summaryrefslogtreecommitdiff
path: root/docs/handbook/tomlplusplus/values.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/handbook/tomlplusplus/values.md')
-rw-r--r--docs/handbook/tomlplusplus/values.md547
1 files changed, 547 insertions, 0 deletions
diff --git a/docs/handbook/tomlplusplus/values.md b/docs/handbook/tomlplusplus/values.md
new file mode 100644
index 0000000000..453140df89
--- /dev/null
+++ b/docs/handbook/tomlplusplus/values.md
@@ -0,0 +1,547 @@
+# toml++ — Values
+
+## Overview
+
+`toml::value<T>` represents leaf TOML values — the concrete data in a TOML document. Each `value` wraps one of seven native C++ types corresponding to the TOML data types.
+
+Declared in `include/toml++/impl/value.hpp` with supporting types in `forward_declarations.hpp` and `date_time.hpp`.
+
+---
+
+## Native Types
+
+The seven supported value types map to TOML types via `toml::value_type_of<T>`:
+
+| TOML Type | C++ Storage Type | `node_type` Enum | Alias |
+|-------------------|---------------------|---------------------------|--------------------|
+| String | `std::string` | `node_type::string` | `value<std::string>` |
+| Integer | `int64_t` | `node_type::integer` | `value<int64_t>` |
+| Float | `double` | `node_type::floating_point` | `value<double>` |
+| Boolean | `bool` | `node_type::boolean` | `value<bool>` |
+| Date | `toml::date` | `node_type::date` | `value<date>` |
+| Time | `toml::time` | `node_type::time` | `value<time>` |
+| Date-Time | `toml::date_time` | `node_type::date_time` | `value<date_time>` |
+
+Only these seven instantiations of `value<T>` exist. The template is constrained:
+
+```cpp
+template <typename T>
+class value : public node
+{
+ static_assert(
+ impl::is_native<T>,
+ "Template parameter must be one of the TOML native value types"
+ );
+
+ private:
+ value_type val_;
+ value_flags flags_ = value_flags::none;
+};
+```
+
+Where `value_type` is the `impl::native_type_of<T>` alias.
+
+---
+
+## Type Traits
+
+```cpp
+// Check at compile time
+toml::is_string<value<std::string>> // true
+toml::is_integer<value<int64_t>> // true
+toml::is_floating_point<value<double>> // true
+toml::is_boolean<value<bool>> // true
+toml::is_date<value<date>> // true
+toml::is_time<value<time>> // true
+toml::is_date_time<value<date_time>> // true
+
+// Works on the raw types too
+toml::is_integer<int64_t> // true
+toml::is_number<int64_t> // true (integer or float)
+toml::is_number<double> // true
+
+// Supertype checks
+toml::is_value<value<int64_t>> // true (any value<T>)
+toml::is_chronological<value<date>> // true (date, time, or date_time)
+```
+
+---
+
+## Construction
+
+### From Compatible Types
+
+```cpp
+toml::value<int64_t> i{ 42 };
+toml::value<double> f{ 3.14 };
+toml::value<std::string> s{ "hello" };
+toml::value<bool> b{ true };
+
+// Implicit promotion from smaller integer types
+toml::value<int64_t> from_int{ 42 }; // int → int64_t
+toml::value<int64_t> from_short{ short(5) }; // short → int64_t
+
+// Implicit promotion from float → double
+toml::value<double> from_float{ 1.5f }; // float → double
+```
+
+The `native_value_maker` mechanism handles promotions:
+
+```cpp
+// In impl namespace:
+template <typename T>
+struct native_value_maker;
+
+// For integer types (int, unsigned, short, etc.):
+// Promotes to int64_t
+
+// For floating-point (float):
+// Promotes to double
+
+// For string types (const char*, string_view, etc.):
+// Converts to std::string
+
+// For char8_t strings (u8"..."):
+// Transcodes to std::string
+```
+
+### Copy and Move
+
+```cpp
+toml::value<std::string> original{ "hello" };
+toml::value<std::string> copy{ original }; // deep copy
+toml::value<std::string> moved{ std::move(original) }; // move
+```
+
+### Assignment
+
+```cpp
+auto v = toml::value<int64_t>{ 10 };
+v = 42; // assign from raw value (operator=(ValueType))
+v = copy; // assign from another value (operator=(const value&))
+v = std::move(other); // move assign
+```
+
+---
+
+## Retrieving Values
+
+### `get()` — Direct Access
+
+```cpp
+ValueType& get() & noexcept;
+ValueType&& get() && noexcept;
+const ValueType& get() const& noexcept;
+```
+
+Returns a direct reference to the stored value:
+
+```cpp
+auto v = toml::value<std::string>{ "hello" };
+std::string& s = v.get();
+s += " world";
+std::cout << v.get() << "\n"; // "hello world"
+```
+
+### `operator ValueType&()` — Implicit Conversion
+
+```cpp
+explicit operator ValueType&() noexcept;
+explicit operator const ValueType&() const noexcept;
+```
+
+```cpp
+auto v = toml::value<int64_t>{ 42 };
+int64_t x = static_cast<int64_t>(v);
+```
+
+### `operator*()` / `operator->()`
+
+```cpp
+ValueType& operator*() & noexcept;
+const ValueType& operator*() const& noexcept;
+ValueType* operator->() noexcept;
+const ValueType* operator->() const noexcept;
+```
+
+Dereference-style access:
+
+```cpp
+auto v = toml::value<std::string>{ "hello" };
+std::cout << v->length() << "\n"; // 5
+std::cout << (*v).size() << "\n"; // 5
+```
+
+---
+
+## Value Flags
+
+`value_flags` is a bitmask controlling how values are formatted when serialized:
+
+```cpp
+enum class value_flags : uint16_t
+{
+ none = 0,
+ format_as_binary = 1, // 0b10101
+ format_as_octal = 2, // 0o755
+ format_as_hexadecimal = 4, // 0xFF
+
+ // Special sentinel (default behavior):
+ // preserve_source_value_flags
+};
+```
+
+### Getting / Setting Flags
+
+```cpp
+value_flags flags() const noexcept;
+value<T>& flags(value_flags new_flags) noexcept;
+```
+
+```cpp
+auto v = toml::value<int64_t>{ 255 };
+v.flags(toml::value_flags::format_as_hexadecimal);
+
+std::cout << toml::toml_formatter{ toml::table{ { "val", v } } };
+// Output: val = 0xFF
+```
+
+### Source Format Preservation
+
+When parsing, the library records the source format in the flags. When printing, if `preserve_source_value_flags` is used (the default), the original format is retained:
+
+```toml
+port = 0xFF
+mask = 0o777
+bits = 0b1010
+```
+
+After parsing and re-serializing, these retain their hex/octal/binary format.
+
+---
+
+## Date and Time Types
+
+Defined in `include/toml++/impl/date_time.hpp`.
+
+### `toml::date`
+
+```cpp
+struct date
+{
+ uint16_t year;
+ uint8_t month; // 1-12
+ uint8_t day; // 1-31
+
+ // Comparison operators
+ friend bool operator==(const date&, const date&) noexcept;
+ friend bool operator!=(const date&, const date&) noexcept;
+ friend bool operator< (const date&, const date&) noexcept;
+ friend bool operator<=(const date&, const date&) noexcept;
+ friend bool operator> (const date&, const date&) noexcept;
+ friend bool operator>=(const date&, const date&) noexcept;
+
+ // Streaming
+ friend std::ostream& operator<<(std::ostream&, const date&);
+};
+```
+
+```cpp
+auto d = toml::date{ 2024, 1, 15 };
+auto v = toml::value<toml::date>{ d };
+std::cout << v << "\n"; // 2024-01-15
+```
+
+### `toml::time`
+
+```cpp
+struct time
+{
+ uint8_t hour; // 0-23
+ uint8_t minute; // 0-59
+ uint8_t second; // 0-59 (0-60 for leap second)
+ uint32_t nanosecond; // 0-999999999
+
+ // Comparison and streaming operators
+};
+```
+
+```cpp
+auto t = toml::time{ 14, 30, 0 };
+auto v = toml::value<toml::time>{ t };
+std::cout << v << "\n"; // 14:30:00
+```
+
+### `toml::time_offset`
+
+```cpp
+struct time_offset
+{
+ int16_t minutes; // UTC offset: -720 to +840
+
+ // Convenience for UTC:
+ static constexpr time_offset utc() noexcept { return { 0 }; }
+
+ // Comparison operators
+};
+```
+
+### `toml::date_time`
+
+```cpp
+struct date_time
+{
+ toml::date date;
+ toml::time time;
+ optional<time_offset> offset; // nullopt = local date-time
+
+ // Constructor overloads:
+ constexpr date_time(const toml::date& d, const toml::time& t) noexcept;
+ constexpr date_time(const toml::date& d, const toml::time& t,
+ const toml::time_offset& off) noexcept;
+
+ bool is_local() const noexcept; // true if no offset
+
+ // Comparison and streaming operators
+};
+```
+
+#### TOML Date-Time Variants
+
+```toml
+# Offset date-time (has time zone)
+odt = 2024-01-15T14:30:00+05:30
+odt_utc = 2024-01-15T09:00:00Z
+
+# Local date-time (no time zone)
+ldt = 2024-01-15T14:30:00
+
+# Local date
+ld = 2024-01-15
+
+# Local time
+lt = 14:30:00
+```
+
+```cpp
+auto tbl = toml::parse(R"(
+ odt = 2024-01-15T14:30:00+05:30
+ ldt = 2024-01-15T14:30:00
+ ld = 2024-01-15
+ lt = 14:30:00
+)");
+
+auto odt = tbl["odt"].value<toml::date_time>();
+// odt->offset has value, odt->is_local() == false
+
+auto ldt = tbl["ldt"].value<toml::date_time>();
+// ldt->offset is nullopt, ldt->is_local() == true
+
+auto ld = tbl["ld"].value<toml::date>();
+// ld->year == 2024, month == 1, day == 15
+
+auto lt = tbl["lt"].value<toml::time>();
+// lt->hour == 14, minute == 30, second == 0
+```
+
+---
+
+## Type Identity
+
+```cpp
+// For value<int64_t>:
+node_type type() const noexcept final; // node_type::integer
+bool is_integer() const noexcept final; // true
+bool is_number() const noexcept final; // true
+bool is_value() const noexcept final; // true
+// All other is_*() return false
+
+value<int64_t>* as_integer() noexcept final; // returns this
+// All other as_*() return nullptr
+```
+
+---
+
+## Retrieving Values from Nodes
+
+From the base `node` or `node_view`, there are multiple retrieval patterns:
+
+### `value<T>()` — Get with Type Coercion
+
+```cpp
+// As node method:
+optional<T> value() const noexcept;
+```
+
+Attempts to return the value as `T`, with permitted coercions:
+- `int64_t` → `int`, `unsigned`, `size_t`, etc. (bounds-checked)
+- `double` → `float` (precision loss allowed)
+- `double` ↔ `int64_t` (within representable range)
+
+```cpp
+auto tbl = toml::parse("x = 42");
+
+auto as_int = tbl["x"].value<int64_t>(); // optional(42)
+auto as_double = tbl["x"].value<double>(); // optional(42.0)
+auto as_int32 = tbl["x"].value<int>(); // optional(42)
+auto as_string = tbl["x"].value<std::string>(); // nullopt (type mismatch)
+```
+
+### `value_exact<T>()` — No Coercion
+
+```cpp
+optional<T> value_exact() const noexcept;
+```
+
+Only succeeds if the stored type exactly matches `T` (no int→double or similar coercions):
+
+```cpp
+auto tbl = toml::parse("x = 42");
+
+auto exact_int = tbl["x"].value_exact<int64_t>(); // optional(42)
+auto exact_dbl = tbl["x"].value_exact<double>(); // nullopt (it's an int)
+```
+
+### `value_or()` — With Default
+
+```cpp
+template <typename T>
+auto value_or(T&& default_value) const noexcept;
+```
+
+Returns the value or a default:
+
+```cpp
+auto tbl = toml::parse("name = \"Alice\"");
+
+auto name = tbl["name"].value_or("unknown"sv); // "Alice"
+auto age = tbl["age"].value_or(int64_t{ 0 }); // 0 (key missing)
+```
+
+---
+
+## Comparison
+
+```cpp
+// Between values of same type
+friend bool operator==(const value& lhs, const value& rhs) noexcept;
+
+// Between value and raw type
+friend bool operator==(const value<T>& lhs, const T& rhs) noexcept;
+```
+
+```cpp
+auto a = toml::value<int64_t>{ 42 };
+auto b = toml::value<int64_t>{ 42 };
+
+std::cout << (a == b) << "\n"; // true
+std::cout << (a == 42) << "\n"; // true
+std::cout << (a != 99) << "\n"; // true
+```
+
+For `value<std::string>`, comparison also works with `std::string_view` and `const char*`:
+
+```cpp
+auto s = toml::value<std::string>{ "hello" };
+std::cout << (s == "hello") << "\n"; // true
+std::cout << (s == "world"sv) << "\n"; // false
+```
+
+---
+
+## `make_value<T>`
+
+Utility function in `make_node.hpp` for constructing values:
+
+```cpp
+template <typename T, typename... Args>
+auto make_value(Args&&... args)
+ -> decltype(std::make_unique<impl::wrap_node<T>>(std::forward<Args>(args)...));
+```
+
+Returns `std::unique_ptr<value<T>>`:
+
+```cpp
+auto v = toml::make_value<int64_t>(42);
+// v is std::unique_ptr<toml::value<int64_t>>
+```
+
+---
+
+## Printing
+
+Values stream via the default formatter:
+
+```cpp
+auto v = toml::value<std::string>{ "hello world" };
+std::cout << v << "\n"; // "hello world"
+
+auto d = toml::value<toml::date>{ toml::date{ 2024, 6, 15 } };
+std::cout << d << "\n"; // 2024-06-15
+
+auto i = toml::value<int64_t>{ 255 };
+i.flags(toml::value_flags::format_as_hexadecimal);
+std::cout << i << "\n"; // 0xFF
+```
+
+---
+
+## Complete Example
+
+```cpp
+#include <toml++/toml.hpp>
+#include <iostream>
+
+int main()
+{
+ auto config = toml::parse(R"(
+ title = "My App"
+ version = 3
+ debug = true
+ pi = 3.14159
+ created = 2024-01-15T10:30:00Z
+ expires = 2025-12-31
+ check_time = 08:00:00
+ )");
+
+ // Type-safe retrieval with defaults
+ auto title = config["title"].value_or("Untitled"sv);
+ auto version = config["version"].value_or(int64_t{ 1 });
+ auto debug = config["debug"].value_or(false);
+ auto pi = config["pi"].value_or(0.0);
+
+ std::cout << "Title: " << title << "\n";
+ std::cout << "Version: " << version << "\n";
+ std::cout << "Debug: " << debug << "\n";
+ std::cout << "Pi: " << pi << "\n";
+
+ // Date-time access
+ if (auto dt = config["created"].value<toml::date_time>())
+ {
+ std::cout << "Created: " << dt->date.year
+ << "-" << (int)dt->date.month
+ << "-" << (int)dt->date.day << "\n";
+
+ if (!dt->is_local())
+ std::cout << " Offset: " << dt->offset->minutes << " min\n";
+ }
+
+ // Modify and re-serialize
+ auto* v = config["version"].as_integer();
+ if (v) *v = 4;
+
+ std::cout << "\n" << config << "\n";
+
+ return 0;
+}
+```
+
+---
+
+## Related Documentation
+
+- [node-system.md](node-system.md) — Base node class and type dispatch
+- [arrays.md](arrays.md) — Array container
+- [tables.md](tables.md) — Table container
+- [parsing.md](parsing.md) — Parsing values from TOML text
+- [formatting.md](formatting.md) — Formatting values for output