summaryrefslogtreecommitdiff
path: root/docs/handbook/tomlplusplus/tables.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/handbook/tomlplusplus/tables.md')
-rw-r--r--docs/handbook/tomlplusplus/tables.md551
1 files changed, 551 insertions, 0 deletions
diff --git a/docs/handbook/tomlplusplus/tables.md b/docs/handbook/tomlplusplus/tables.md
new file mode 100644
index 0000000000..d573ec0da2
--- /dev/null
+++ b/docs/handbook/tomlplusplus/tables.md
@@ -0,0 +1,551 @@
+# toml++ — Tables
+
+## Overview
+
+`toml::table` is the primary container in toml++. It extends `toml::node` and models an ordered map from `toml::key` objects to child `toml::node` pointers. Every parsed TOML document has a `table` as its root.
+
+Declared in `include/toml++/impl/table.hpp` with implementation in `table.inl`.
+
+---
+
+## Internal Storage
+
+```cpp
+class table : public node
+{
+ private:
+ using map_type = std::map<toml::key, impl::node_ptr, std::less<>>;
+ map_type map_;
+ bool inline_ = false;
+};
+```
+
+- **`map_type`** = `std::map<toml::key, std::unique_ptr<node>, std::less<>>`
+- **`std::less<>`** enables heterogeneous lookup — you can search by `std::string_view` without constructing a `toml::key`
+- **`inline_`** controls whether the table serializes as `{ a = 1, b = 2 }` (inline) or with `[section]` headers (non-inline)
+- Ownership: the table owns all child nodes via `unique_ptr`
+
+---
+
+## Construction
+
+### Default Construction
+
+```cpp
+toml::table tbl; // empty table
+```
+
+### Initializer List Construction
+
+```cpp
+auto tbl = toml::table{
+ { "name", "toml++" },
+ { "version", 3 },
+ { "features", toml::array{ "parsing", "serialization" } },
+ { "metadata", toml::table{
+ { "author", "Mark Gillard" },
+ { "license", "MIT" }
+ }}
+};
+```
+
+This uses `impl::table_init_pair`:
+```cpp
+struct table_init_pair
+{
+ mutable toml::key key;
+ mutable node_ptr value;
+
+ template <typename K, typename V>
+ table_init_pair(K&& k, V&& v, value_flags flags = preserve_source_value_flags);
+};
+```
+
+Values are converted to nodes via `impl::make_node()`, which handles:
+- Native types (`int`, `double`, `const char*`, etc.) → `value<T>`
+- `toml::array` → `array` (moved)
+- `toml::table` → `table` (moved)
+
+### Copy and Move
+
+```cpp
+toml::table copy(original_table); // deep copy — all child nodes are cloned
+toml::table moved(std::move(tbl)); // move — no allocation, transfers ownership
+```
+
+Copy is deep: every child node in the tree is recursively copied.
+
+---
+
+## Iterators
+
+### Types
+
+```cpp
+using table_iterator = impl::table_iterator<false>;
+using const_table_iterator = impl::table_iterator<true>;
+```
+
+`table_iterator` is a **BidirectionalIterator**. Dereferencing yields `table_proxy_pair`:
+
+```cpp
+template <bool IsConst>
+struct table_proxy_pair
+{
+ using value_type = std::conditional_t<IsConst, const node, node>;
+ const toml::key& first;
+ value_type& second;
+};
+```
+
+The `unique_ptr` layer is hidden — you get `(const key&, node&)` pairs.
+
+### Iterator Methods
+
+```cpp
+iterator begin() noexcept;
+iterator end() noexcept;
+const_iterator begin() const noexcept;
+const_iterator end() const noexcept;
+const_iterator cbegin() const noexcept;
+const_iterator cend() const noexcept;
+```
+
+### Range-Based For
+
+```cpp
+for (auto&& [key, value] : tbl)
+{
+ std::cout << key << " = " << value << "\n";
+}
+```
+
+Structured bindings work because `table_proxy_pair` has public `first` and `second` members.
+
+### Iterator to Key String
+
+```cpp
+for (auto it = tbl.begin(); it != tbl.end(); ++it)
+{
+ const toml::key& k = it->first;
+ toml::node& v = it->second;
+ std::cout << k.str() << ": " << v.type() << "\n";
+}
+```
+
+---
+
+## Capacity
+
+```cpp
+size_t size() const noexcept; // number of key-value pairs
+bool empty() const noexcept; // true if size() == 0
+```
+
+---
+
+## Element Access
+
+### `operator[]` — Returns `node_view`
+
+```cpp
+node_view<node> operator[](std::string_view key) noexcept;
+node_view<const node> operator[](std::string_view key) const noexcept;
+```
+
+Returns a `node_view` that wraps the node at that key, or an empty view if the key doesn't exist. This is the safe, chainable accessor:
+
+```cpp
+auto val = tbl["section"]["subsection"]["key"].value_or(42);
+```
+
+### `at()` — Bounds-Checked Access
+
+```cpp
+node& at(std::string_view key);
+const node& at(std::string_view key) const;
+```
+
+Returns a reference to the node at the key. Throws `std::out_of_range` if the key doesn't exist.
+
+### `get()` — Raw Pointer Access
+
+```cpp
+node* get(std::string_view key) noexcept;
+const node* get(std::string_view key) const noexcept;
+```
+
+Returns a pointer to the node, or `nullptr` if not found:
+
+```cpp
+if (auto* n = tbl.get("name"))
+{
+ std::cout << "Found: " << *n << "\n";
+}
+```
+
+### `get_as<T>()` — Typed Pointer Access
+
+```cpp
+template <typename T>
+impl::wrap_node<T>* get_as(std::string_view key) noexcept;
+
+template <typename T>
+const impl::wrap_node<T>* get_as(std::string_view key) const noexcept;
+```
+
+Combines `get()` and `as<T>()`:
+
+```cpp
+if (auto* val = tbl.get_as<std::string>("name"))
+ std::cout << "Name: " << val->get() << "\n";
+
+if (auto* sub = tbl.get_as<toml::table>("database"))
+ std::cout << "Database has " << sub->size() << " keys\n";
+```
+
+### `contains()` — Key Existence Check
+
+```cpp
+bool contains(std::string_view key) const noexcept;
+```
+
+```cpp
+if (tbl.contains("database"))
+ std::cout << "Has database config\n";
+```
+
+---
+
+## Insertion
+
+### `insert()` — Insert If Not Present
+
+```cpp
+template <typename KeyType, typename ValueType>
+std::pair<iterator, bool> insert(KeyType&& key, ValueType&& val,
+ value_flags flags = preserve_source_value_flags);
+```
+
+Inserts a new key-value pair only if the key doesn't already exist. Returns `(iterator, true)` on success, `(iterator_to_existing, false)` if the key was already present:
+
+```cpp
+auto [it, inserted] = tbl.insert("name", "toml++");
+if (inserted)
+ std::cout << "Inserted: " << it->second << "\n";
+else
+ std::cout << "Key already exists\n";
+```
+
+### `insert_or_assign()` — Insert or Replace
+
+```cpp
+template <typename KeyType, typename ValueType>
+std::pair<iterator, bool> insert_or_assign(KeyType&& key, ValueType&& val,
+ value_flags flags = preserve_source_value_flags);
+```
+
+Always succeeds — inserts if new, replaces if existing:
+
+```cpp
+tbl.insert_or_assign("version", 4); // replaces any existing "version"
+```
+
+### `emplace<T>()` — Construct In Place
+
+```cpp
+template <typename ValueType, typename KeyType, typename... Args>
+std::pair<iterator, bool> emplace(KeyType&& key, Args&&... args);
+```
+
+Constructs a new node in place if the key doesn't exist:
+
+```cpp
+tbl.emplace<std::string>("greeting", "Hello, World!");
+tbl.emplace<toml::array>("empty_list");
+tbl.emplace<toml::table>("empty_section");
+```
+
+---
+
+## Removal
+
+### `erase()` — By Key
+
+```cpp
+size_t erase(std::string_view key) noexcept;
+```
+
+Returns 1 if the key was found and removed, 0 otherwise:
+
+```cpp
+tbl.erase("deprecated_key");
+```
+
+### `erase()` — By Iterator
+
+```cpp
+iterator erase(iterator pos) noexcept;
+iterator erase(const_iterator pos) noexcept;
+iterator erase(const_iterator first, const_iterator last) noexcept;
+```
+
+```cpp
+auto it = tbl.find("old_key");
+if (it != tbl.end())
+ tbl.erase(it);
+```
+
+### `clear()`
+
+```cpp
+void clear() noexcept;
+```
+
+Removes all key-value pairs.
+
+---
+
+## Search
+
+### `find()`
+
+```cpp
+iterator find(std::string_view key) noexcept;
+const_iterator find(std::string_view key) const noexcept;
+```
+
+Returns an iterator to the key-value pair, or `end()` if not found.
+
+### `lower_bound()` / `upper_bound()` / `equal_range()`
+
+These operate on the underlying `std::map` with heterogeneous lookup:
+
+```cpp
+iterator lower_bound(std::string_view key) noexcept;
+iterator upper_bound(std::string_view key) noexcept;
+std::pair<iterator, iterator> equal_range(std::string_view key) noexcept;
+// + const overloads
+```
+
+---
+
+## Metadata
+
+### `is_inline()`
+
+```cpp
+bool is_inline() const noexcept;
+void is_inline(bool val) noexcept;
+```
+
+Controls inline serialization. When `true`, the table formats as `{ a = 1, b = 2 }` instead of using `[section]` headers:
+
+```cpp
+auto tbl = toml::table{
+ { "a", 1 },
+ { "b", 2 },
+ { "nested", toml::table{ { "c", 3 } } }
+};
+
+std::cout << tbl << "\n";
+// Output:
+// a = 1
+// b = 2
+//
+// [nested]
+// c = 3
+
+tbl.is_inline(true);
+std::cout << tbl << "\n";
+// Output:
+// { a = 1, b = 2, nested = { c = 3 } }
+```
+
+Runtime-constructed tables default to non-inline. The parser sets `is_inline(true)` for tables parsed from inline syntax.
+
+---
+
+## `for_each()` — Type-Safe Iteration
+
+```cpp
+template <typename Func>
+table& for_each(Func&& visitor) &;
+```
+
+Visits each key-value pair, passing the value as its concrete type:
+
+```cpp
+tbl.for_each([](const toml::key& key, auto& value)
+{
+ std::cout << key << ": ";
+
+ using value_type = std::remove_cvref_t<decltype(value)>;
+ if constexpr (std::is_same_v<value_type, toml::table>)
+ std::cout << "table (" << value.size() << " entries)\n";
+ else if constexpr (std::is_same_v<value_type, toml::array>)
+ std::cout << "array (" << value.size() << " elements)\n";
+ else
+ std::cout << value.get() << "\n";
+});
+```
+
+The visitor is instantiated for all 9 possible value types (table, array, + 7 value types).
+
+---
+
+## Path-Based Access
+
+### `at_path()` Member
+
+```cpp
+node_view<node> at_path(std::string_view path) noexcept;
+node_view<const node> at_path(std::string_view path) const noexcept;
+node_view<node> at_path(const toml::path& path) noexcept;
+```
+
+Resolves dot-separated paths with array indices:
+
+```cpp
+auto tbl = toml::parse(R"(
+ [database]
+ servers = [
+ { host = "alpha", port = 5432 },
+ { host = "beta", port = 5433 }
+ ]
+)");
+
+std::cout << tbl.at_path("database.servers[0].host") << "\n"; // "alpha"
+std::cout << tbl.at_path("database.servers[1].port") << "\n"; // 5433
+```
+
+### `operator[]` with `toml::path`
+
+```cpp
+node_view<node> operator[](const toml::path& path) noexcept;
+```
+
+```cpp
+toml::path p("database.servers[0].host");
+std::cout << tbl[p] << "\n"; // "alpha"
+```
+
+---
+
+## Comparison
+
+### Equality
+
+```cpp
+friend bool operator==(const table& lhs, const table& rhs) noexcept;
+friend bool operator!=(const table& lhs, const table& rhs) noexcept;
+```
+
+Deep structural equality: two tables are equal if they have the same keys with equal values. Source regions and inline-ness are not compared.
+
+---
+
+## Printing
+
+Tables are streamable via the default `toml_formatter`:
+
+```cpp
+std::cout << tbl << "\n";
+```
+
+Equivalent to:
+```cpp
+std::cout << toml::toml_formatter{ tbl } << "\n";
+```
+
+---
+
+## Type Identity
+
+`table` overrides all type-check virtuals from `node`:
+
+```cpp
+node_type type() const noexcept final; // returns node_type::table
+bool is_table() const noexcept final; // returns true
+bool is_array() const noexcept final; // returns false
+bool is_value() const noexcept final; // returns false
+bool is_string() const noexcept final; // returns false
+// ... all other is_*() return false
+
+table* as_table() noexcept final; // returns this
+const table* as_table() const noexcept final; // returns this
+// ... all other as_*() return nullptr
+```
+
+---
+
+## Windows Compatibility
+
+When `TOML_ENABLE_WINDOWS_COMPAT` is enabled, additional overloads accept `std::wstring_view` for key parameters:
+
+```cpp
+node* get(std::wstring_view key);
+bool contains(std::wstring_view key) const;
+node_view<node> operator[](std::wstring_view key) noexcept;
+// etc.
+```
+
+Wide strings are internally narrowed via `impl::narrow()`.
+
+---
+
+## Complete Example
+
+```cpp
+#include <toml++/toml.hpp>
+#include <iostream>
+
+int main()
+{
+ // Build a table programmatically
+ auto config = toml::table{
+ { "app", toml::table{
+ { "name", "MyApp" },
+ { "version", 2 }
+ }},
+ { "features", toml::array{ "auth", "logging" } }
+ };
+
+ // Navigate
+ std::cout << "App: " << config["app"]["name"].value_or("?"sv) << "\n";
+
+ // Insert
+ config["app"].as_table()->insert("debug", false);
+
+ // Modify
+ config.insert_or_assign("features",
+ toml::array{ "auth", "logging", "metrics" });
+
+ // Check
+ if (config.contains("app"))
+ {
+ auto* app = config.get_as<toml::table>("app");
+ std::cout << "App table has " << app->size() << " keys\n";
+ }
+
+ // Iterate
+ for (auto&& [key, value] : config)
+ {
+ std::cout << key << " (" << value.type() << ")\n";
+ }
+
+ // Serialize
+ std::cout << "\n" << config << "\n";
+
+ return 0;
+}
+```
+
+---
+
+## Related Documentation
+
+- [node-system.md](node-system.md) — Base node interface
+- [arrays.md](arrays.md) — Array container details
+- [values.md](values.md) — Value node details
+- [path-system.md](path-system.md) — Path-based navigation