From feb67c9bd56b4e99a099ca0ba7a004aba934cb43 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Mon, 8 Jan 2018 01:44:41 -0800 Subject: [PATCH] formattable: adjust array access interface appending new entry by providing empty index, setting existing entries by providing negative index. Signed-off-by: Yehuda Sadeh --- src/common/ceph_json.cc | 33 +++++++++++++++++++----- src/test/common/test_json_formattable.cc | 22 ++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/common/ceph_json.cc b/src/common/ceph_json.cc index 262019896aaff..f43fce8bfa815 100644 --- a/src/common/ceph_json.cc +++ b/src/common/ceph_json.cc @@ -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 *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; } } diff --git a/src/test/common/test_json_formattable.cc b/src/test/common/test_json_formattable.cc index 6042a1a55ba85..6708506cc9bc6 100644 --- a/src/test/common/test_json_formattable.cc +++ b/src/test/common/test_json_formattable.cc @@ -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); + } } -- 2.39.5