summaryrefslogtreecommitdiff
path: root/docs/handbook/json4cpp/element-access.md
diff options
context:
space:
mode:
authorMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-05 17:37:54 +0300
committerMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-05 17:37:54 +0300
commit32f5f761bc8e960293b4f4feaf973dd0da26d0f8 (patch)
tree8d0436fdd093d5255c3b75e45f9741882b22e2e4 /docs/handbook/json4cpp/element-access.md
parent64f4ddfa97c19f371fe1847b20bd26803f0a25d5 (diff)
downloadProject-Tick-32f5f761bc8e960293b4f4feaf973dd0da26d0f8.tar.gz
Project-Tick-32f5f761bc8e960293b4f4feaf973dd0da26d0f8.zip
NOISSUE Project Tick Handbook is Released!
Assisted-by: Claude:Opus-4.6-High Signed-off-by: Mehmet Samet Duman <yongdohyun@projecttick.org>
Diffstat (limited to 'docs/handbook/json4cpp/element-access.md')
-rw-r--r--docs/handbook/json4cpp/element-access.md581
1 files changed, 581 insertions, 0 deletions
diff --git a/docs/handbook/json4cpp/element-access.md b/docs/handbook/json4cpp/element-access.md
new file mode 100644
index 0000000000..73d52126bb
--- /dev/null
+++ b/docs/handbook/json4cpp/element-access.md
@@ -0,0 +1,581 @@
+# json4cpp — Element Access
+
+## Overview
+
+The `basic_json` class provides several ways to access elements:
+
+| Method | Applicable To | Behaviour on Missing |
+|---|---|---|
+| `operator[]` | array, object, null | Inserts default (creates if null) |
+| `at()` | array, object | Throws `out_of_range` |
+| `value()` | object | Returns caller-supplied default |
+| `front()` | array, object, scalar | UB if empty |
+| `back()` | array, object, scalar | UB if empty |
+| `find()` | object | Returns `end()` |
+| `contains()` | object | Returns `false` |
+| `count()` | object | Returns `0` |
+
+## `operator[]`
+
+### Array Access
+
+```cpp
+reference operator[](size_type idx);
+const_reference operator[](size_type idx) const;
+```
+
+Accesses the element at index `idx`. If the JSON value is **null**, it is
+automatically converted to an **array** before accessing:
+
+```cpp
+json j; // null
+j[0] = "first"; // j is now ["first"]
+j[1] = "second"; // j is now ["first", "second"]
+```
+
+If `idx` is beyond the current array size, the array is extended with null
+elements:
+
+```cpp
+json j = {1, 2};
+j[5] = 99;
+// j is now [1, 2, null, null, null, 99]
+```
+
+**Warning:** `const` array access does **not** extend the array and has
+undefined behavior for out-of-bounds access.
+
+### Object Access
+
+```cpp
+reference operator[](const typename object_t::key_type& key);
+const_reference operator[](const typename object_t::key_type& key) const;
+
+// C++14 heterogeneous lookup (KeyType template)
+template<typename KeyType>
+reference operator[](KeyType&& key);
+template<typename KeyType>
+const_reference operator[](KeyType&& key) const;
+```
+
+Accesses the element with key `key`. If the key does not exist in a mutable
+context, it is **inserted** with a null value:
+
+```cpp
+json j = {{"name", "alice"}};
+j["age"] = 30; // inserts "age"
+std::string name = j["name"];
+
+// const access does not insert
+const json& cj = j;
+// cj["missing"]; // undefined behavior if key doesn't exist
+```
+
+If the JSON value is **null**, it is automatically converted to an **object**:
+
+```cpp
+json j; // null
+j["key"] = "value"; // j is now {"key": "value"}
+```
+
+### String Literal vs. Integer Ambiguity
+
+Be careful with `0`:
+
+```cpp
+json j = {{"key", "value"}};
+// j[0] — array access (selects first element of object iteration) — NOT recommended
+// j["key"] — object access
+```
+
+### Using `json::object_t::key_type`
+
+The non-const `operator[]` accepts a `key_type` (default: `std::string`).
+The `KeyType` template overloads accept any type that satisfies these
+constraints via `detail::is_usable_as_key_type`:
+
+- Must be comparable with `object_comparator_t`
+- Not convertible to `basic_json`
+- Not a `value_t`
+- Not a `BasicJsonType`
+
+## `at()`
+
+### Array Access
+
+```cpp
+reference at(size_type idx);
+const_reference at(size_type idx) const;
+```
+
+Returns a reference to the element at index `idx`. Throws
+`json::out_of_range` (id 401) if the index is out of bounds:
+
+```cpp
+json j = {1, 2, 3};
+j.at(0); // 1
+j.at(3); // throws out_of_range::401: "array index 3 is out of range"
+```
+
+When `JSON_DIAGNOSTIC_POSITIONS` is enabled, the exception includes
+byte-offset information.
+
+### Object Access
+
+```cpp
+reference at(const typename object_t::key_type& key);
+const_reference at(const typename object_t::key_type& key) const;
+
+template<typename KeyType>
+reference at(KeyType&& key);
+template<typename KeyType>
+const_reference at(KeyType&& key) const;
+```
+
+Returns a reference to the element with key `key`. Throws
+`json::out_of_range` (id 403) if the key is not found:
+
+```cpp
+json j = {{"name", "alice"}, {"age", 30}};
+j.at("name"); // "alice"
+j.at("missing"); // throws out_of_range::403: "key 'missing' not found"
+```
+
+### Type Mismatch
+
+Both `at()` overloads throw `json::type_error` (id 304) if the JSON value
+is not of the expected type:
+
+```cpp
+json j = 42;
+j.at(0); // throws type_error::304: "cannot use at() with number"
+j.at("key"); // throws type_error::304: "cannot use at() with number"
+```
+
+## `value()`
+
+```cpp
+// With default value
+ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const;
+
+// With JSON pointer
+ValueType value(const json_pointer& ptr, const ValueType& default_value) const;
+
+// KeyType template overloads
+template<typename KeyType>
+ValueType value(KeyType&& key, const ValueType& default_value) const;
+```
+
+Returns the value for a given key or JSON pointer, or `default_value` if
+the key/pointer does not resolve. Unlike `operator[]` and `at()`, this
+method **never modifies** the JSON value.
+
+```cpp
+json j = {{"name", "alice"}, {"age", 30}};
+
+std::string name = j.value("name", "unknown"); // "alice"
+std::string addr = j.value("address", "N/A"); // "N/A"
+int height = j.value("height", 170); // 170
+
+// With JSON pointer
+int age = j.value("/age"_json_pointer, 0); // 30
+int foo = j.value("/foo"_json_pointer, -1); // -1
+```
+
+Throws `json::type_error` (id 306) if the JSON value is not an object (for
+the key overloads) or if the found value cannot be converted to `ValueType`.
+
+### `value()` vs `operator[]`
+
+| Feature | `operator[]` | `value()` |
+|---|---|---|
+| Modifies on miss | Yes (inserts null) | No |
+| Returns | Reference | Value copy |
+| Default on miss | null (always) | Caller-specified |
+| Applicable to arrays | Yes | No (objects only) |
+
+## `front()` and `back()`
+
+```cpp
+reference front();
+const_reference front() const;
+
+reference back();
+const_reference back() const;
+```
+
+Return references to the first/last element. For **arrays**, this is the
+first/last element by index. For **objects**, this is the first/last element
+by iteration order (which depends on the comparator — insertion order for
+`ordered_json`). For **non-compound types**, the value itself is returned
+(the JSON value is treated as a single-element container).
+
+```cpp
+json j = {1, 2, 3};
+j.front(); // 1
+j.back(); // 3
+
+json j2 = 42;
+j2.front(); // 42
+j2.back(); // 42
+```
+
+**Warning:** Calling `front()` or `back()` on an empty container is
+**undefined behavior** (same as STL containers).
+
+## `find()`
+
+```cpp
+iterator find(const typename object_t::key_type& key);
+const_iterator find(const typename object_t::key_type& key) const;
+
+template<typename KeyType>
+iterator find(KeyType&& key);
+template<typename KeyType>
+const_iterator find(KeyType&& key) const;
+```
+
+Returns an iterator to the element with the given key, or `end()` if not
+found. Only works on objects:
+
+```cpp
+json j = {{"name", "alice"}, {"age", 30}};
+
+auto it = j.find("name");
+if (it != j.end()) {
+ std::cout << it.key() << " = " << it.value() << "\n";
+}
+
+auto it2 = j.find("missing");
+assert(it2 == j.end());
+```
+
+For non-objects, `find()` always returns `end()`.
+
+## `contains()`
+
+```cpp
+bool contains(const typename object_t::key_type& key) const;
+
+template<typename KeyType>
+bool contains(KeyType&& key) const;
+
+// JSON pointer overload
+bool contains(const json_pointer& ptr) const;
+```
+
+Returns `true` if the key or pointer exists:
+
+```cpp
+json j = {{"name", "alice"}, {"address", {{"city", "wonderland"}}}};
+
+j.contains("name"); // true
+j.contains("phone"); // false
+
+// JSON pointer — checks nested paths
+j.contains("/address/city"_json_pointer); // true
+j.contains("/address/zip"_json_pointer); // false
+```
+
+## `count()`
+
+```cpp
+size_type count(const typename object_t::key_type& key) const;
+
+template<typename KeyType>
+size_type count(KeyType&& key) const;
+```
+
+Returns the number of elements with the given key. Since JSON objects have
+unique keys, the result is always `0` or `1`:
+
+```cpp
+json j = {{"name", "alice"}};
+j.count("name"); // 1
+j.count("missing"); // 0
+```
+
+## `erase()`
+
+### Erase by Iterator
+
+```cpp
+iterator erase(iterator pos);
+iterator erase(const_iterator pos);
+```
+
+Removes the element at the given iterator position. Returns an iterator to
+the element after the erased one:
+
+```cpp
+json j = {1, 2, 3, 4, 5};
+auto it = j.erase(j.begin() + 2); // removes 3
+// j is now [1, 2, 4, 5], it points to 4
+```
+
+### Erase by Iterator Range
+
+```cpp
+iterator erase(iterator first, iterator last);
+iterator erase(const_iterator first, const_iterator last);
+```
+
+Removes all elements in the range `[first, last)`:
+
+```cpp
+json j = {1, 2, 3, 4, 5};
+j.erase(j.begin() + 1, j.begin() + 3);
+// j is now [1, 4, 5]
+```
+
+### Erase by Key
+
+```cpp
+size_type erase(const typename object_t::key_type& key);
+
+template<typename KeyType>
+size_type erase(KeyType&& key);
+```
+
+Removes the element with the given key from an object. Returns the number
+of elements removed (0 or 1):
+
+```cpp
+json j = {{"name", "alice"}, {"age", 30}};
+j.erase("age");
+// j is now {"name": "alice"}
+```
+
+### Erase by Index
+
+```cpp
+void erase(const size_type idx);
+```
+
+Removes the element at the given index from an array. Throws
+`out_of_range::401` if the index is out of range:
+
+```cpp
+json j = {"a", "b", "c"};
+j.erase(1);
+// j is now ["a", "c"]
+```
+
+### Erase on Primitive Types
+
+Erasing by iterator on primitive types (number, string, boolean) is
+supported only if the iterator points to the single element:
+
+```cpp
+json j = 42;
+j.erase(j.begin()); // j is now null
+```
+
+## `size()`, `empty()`, `max_size()`
+
+```cpp
+size_type size() const noexcept;
+bool empty() const noexcept;
+size_type max_size() const noexcept;
+```
+
+| Type | `size()` | `empty()` |
+|---|---|---|
+| null | 0 | `true` |
+| object | number of key-value pairs | `true` if no pairs |
+| array | number of elements | `true` if no elements |
+| scalar (string, number, boolean, binary) | 1 | `false` |
+
+```cpp
+json j_null;
+j_null.size(); // 0
+j_null.empty(); // true
+
+json j_arr = {1, 2, 3};
+j_arr.size(); // 3
+j_arr.empty(); // false
+
+json j_str = "hello";
+j_str.size(); // 1
+j_str.empty(); // false (primitive → always 1)
+```
+
+`max_size()` returns the maximum number of elements the container can hold
+(delegates to the underlying container's `max_size()` for arrays and
+objects; returns 1 for scalars).
+
+## `clear()`
+
+```cpp
+void clear() noexcept;
+```
+
+Resets the value to a default-constructed value of the same type:
+
+| Type | Result after `clear()` |
+|---|---|
+| null | null |
+| object | `{}` |
+| array | `[]` |
+| string | `""` |
+| boolean | `false` |
+| number_integer | `0` |
+| number_unsigned | `0` |
+| number_float | `0.0` |
+| binary | `[]` (empty, no subtype) |
+
+## `push_back()` and `emplace_back()`
+
+### Array Operations
+
+```cpp
+void push_back(basic_json&& val);
+void push_back(const basic_json& val);
+
+template<typename... Args>
+reference emplace_back(Args&&... args);
+```
+
+Appends an element at the end:
+
+```cpp
+json j = {1, 2, 3};
+j.push_back(4);
+j.emplace_back(5);
+// j is now [1, 2, 3, 4, 5]
+```
+
+If the value is `null`, it's first converted to an empty array.
+
+### Object Operations
+
+```cpp
+void push_back(const typename object_t::value_type& val);
+void push_back(initializer_list_t init);
+```
+
+Inserts a key-value pair:
+
+```cpp
+json j = {{"a", 1}};
+j.push_back({"b", 2}); // initializer_list pair
+j.push_back(json::object_t::value_type("c", 3)); // explicit pair
+// j is now {"a": 1, "b": 2, "c": 3}
+```
+
+### `operator+=`
+
+Alias for `push_back()`:
+
+```cpp
+json j = {1, 2};
+j += 3;
+j += {4, 5}; // pushes an array [4, 5] as a single element
+```
+
+## `emplace()`
+
+```cpp
+template<typename... Args>
+std::pair<iterator, bool> emplace(Args&&... args);
+```
+
+For objects, inserts a key-value pair if the key doesn't already exist.
+Returns a pair of iterator and bool (whether insertion took place):
+
+```cpp
+json j = {{"a", 1}};
+auto [it, inserted] = j.emplace("b", 2);
+// inserted == true, it points to {"b": 2}
+auto [it2, inserted2] = j.emplace("a", 99);
+// inserted2 == false, existing value unchanged
+```
+
+## `insert()`
+
+### Array Insert
+
+```cpp
+iterator insert(const_iterator pos, const basic_json& val);
+iterator insert(const_iterator pos, basic_json&& val);
+iterator insert(const_iterator pos, size_type cnt, const basic_json& val);
+iterator insert(const_iterator pos, const_iterator first, const_iterator last);
+iterator insert(const_iterator pos, initializer_list_t ilist);
+```
+
+Inserts elements at the given position:
+
+```cpp
+json j = {1, 2, 5};
+j.insert(j.begin() + 2, 3);
+j.insert(j.begin() + 3, 4);
+// j is now [1, 2, 3, 4, 5]
+
+// Insert count copies
+j.insert(j.end(), 2, 0);
+// j is now [1, 2, 3, 4, 5, 0, 0]
+```
+
+### Object Insert
+
+```cpp
+void insert(const_iterator first, const_iterator last);
+```
+
+Inserts elements from another object:
+
+```cpp
+json j1 = {{"a", 1}};
+json j2 = {{"b", 2}, {"c", 3}};
+j1.insert(j2.begin(), j2.end());
+// j1 is now {"a": 1, "b": 2, "c": 3}
+```
+
+## `update()`
+
+```cpp
+void update(const_reference j, bool merge_objects = false);
+void update(const_iterator first, const_iterator last, bool merge_objects = false);
+```
+
+Updates an object with keys from another object. Existing keys are
+**overwritten**:
+
+```cpp
+json j1 = {{"a", 1}, {"b", 2}};
+json j2 = {{"b", 99}, {"c", 3}};
+j1.update(j2);
+// j1 is now {"a": 1, "b": 99, "c": 3}
+```
+
+When `merge_objects` is `true`, nested objects are merged recursively
+instead of being overwritten:
+
+```cpp
+json j1 = {{"config", {{"debug", true}, {"port", 8080}}}};
+json j2 = {{"config", {{"port", 9090}, {"host", "localhost"}}}};
+j1.update(j2, true);
+// j1["config"] is now {"debug": true, "port": 9090, "host": "localhost"}
+```
+
+## `swap()`
+
+```cpp
+void swap(reference other) noexcept;
+
+void swap(array_t& other);
+void swap(object_t& other);
+void swap(string_t& other);
+void swap(binary_t& other);
+void swap(typename binary_t::container_type& other);
+```
+
+Swaps contents with another value or with a compatible container.
+The typed overloads throw `type_error::310` if the types don't match:
+
+```cpp
+json j = {1, 2, 3};
+std::vector<json> v = {4, 5, 6};
+j.swap(v);
+// j is now [4, 5, 6], v contains the old j's elements
+```