]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
formattable: adjust array access interface
authorYehuda Sadeh <yehuda@redhat.com>
Mon, 8 Jan 2018 09:44:41 +0000 (01:44 -0800)
committerYehuda Sadeh <yehuda@redhat.com>
Thu, 12 Apr 2018 22:38:37 +0000 (15:38 -0700)
appending new entry by providing empty index, setting existing entries
by providing negative index.

Signed-off-by: Yehuda Sadeh <yehuda@redhat.com>
src/common/ceph_json.cc
src/test/common/test_json_formattable.cc

index 262019896aaffc96247d0f0cbb20fd9e35c0daaa..f43fce8bfa81547ed670e3e4458eeb8555f2af9f 100644 (file)
@@ -640,6 +640,7 @@ struct field_entity {
   bool is_obj{false}; /* either obj field or array entity */
   string name; /* if obj */
   int index{0}; /* if array */
+  bool append{false};
 
   field_entity() {}
   field_entity(const string& n) : is_obj(true), name(n) {}
@@ -673,7 +674,13 @@ static int parse_entity(const string& s, vector<field_entity> *result)
 
     ofs = end_arr + 1;
 
-    result->push_back(field_entity(atoi(index_str.c_str())));
+    if (!index_str.empty()) {
+      result->push_back(field_entity(atoi(index_str.c_str())));
+    } else {
+      field_entity f;
+      f.append = true;
+      result->push_back(f);
+    }
   }
   return 0;
 }
@@ -713,10 +720,19 @@ int JSONFormattable::set(const string& name, const string& val)
         if (vi.is_obj) {
           return -EINVAL;
         }
-        if ((size_t)vi.index >= f->arr.size()) {
-          f->arr.resize(vi.index + 1);
+        int index = vi.index;
+        if (vi.append) {
+          index = f->arr.size();
+        } else if (index < 0) {
+          index = f->arr.size() + index;
+          if (index < 0) {
+            return -EINVAL; /* out of bounds */
+          }
         }
-        f = &f->arr[vi.index];
+        if ((size_t)index >= f->arr.size()) {
+          f->arr.resize(index + 1);
+        }
+        f = &f->arr[index];
       }
     }
   }
@@ -757,8 +773,6 @@ int JSONFormattable::erase(const string& name)
 
       parent = f;
 
-      last_entity = vi;
-
       if (f->type == FMT_OBJ) {
         if (!vi.is_obj) {
           return -EINVAL;
@@ -772,11 +786,18 @@ int JSONFormattable::erase(const string& name)
         if (vi.is_obj) {
           return -EINVAL;
         }
+        if (vi.index < 0) {
+          vi.index = f->arr.size() + vi.index;
+          if (vi.index < 0) { /* out of bounds, nothing to remove */
+            return 0;
+          }
+        }
         if ((size_t)vi.index >= f->arr.size()) {
           return 0; /* index beyond array boundaries */
         }
         f = &f->arr[vi.index];
       }
+      last_entity = vi;
     }
   }
 
index 6042a1a55ba8562fde9a0a520cbdce6c1bbf442b..6708506cc9bc6cc2113bdcd6899c9652fb0758ec 100644 (file)
@@ -238,6 +238,12 @@ TEST(formatable, set_array) {
   ASSERT_EQ(f["bbb"][0].array().size(), 2);
   ASSERT_EQ((int)f["bbb"][0][1], 25);
 
+  f.set("bbb[0][]", "26"); /* append operation */
+  ASSERT_EQ((int)f["bbb"][0][2], 26);
+  f.set("bbb[0][-1]", "27"); /* replace last */
+  ASSERT_EQ((int)f["bbb"][0][2], 27);
+  ASSERT_EQ(f["bbb"][0].array().size(), 3);
+
   f.set("foo.asd[0][0]", "{ \"field\": \"xyz\"}");
   ASSERT_EQ((string)f["foo"]["asd"][0][0]["field"], "xyz");
 
@@ -265,5 +271,21 @@ TEST(formatable, erase_array) {
   f.erase("asd");
   ASSERT_FALSE(f["asd"].exists(0));
   ASSERT_FALSE(f.exists("asd"));
+
+  f.set("bbb[]", "10");
+  f.set("bbb[]", "20");
+  f.set("bbb[]", "30");
+  ASSERT_EQ((int)f["bbb"][0], 10);
+  ASSERT_EQ((int)f["bbb"][1], 20);
+  ASSERT_EQ((int)f["bbb"][2], 30);
+  f.erase("bbb[-2]");
+  ASSERT_FALSE(f.exists("bbb[2]"));
+
+  ASSERT_EQ((int)f["bbb"][0], 10);
+  ASSERT_EQ((int)f["bbb"][1], 30);
+
+  if (0) { /* for debugging when needed */
+    dumpf(f);
+  }
 }