#pragma once #include #include #include #include #include #include struct ikv_node_t; namespace ikv { /// Runtime value types exposed by iKv. enum ValueType { nullValue = 0, stringValue, intValue, realValue, booleanValue, objectValue, arrayValue }; /// On-disk iKv format versions supported for explicit writes. enum class Version : unsigned { v1 = 1, v2 = 2 }; /// Error raised for invalid types, unsupported operations, parse failures, /// and I/O failures. class Error : public std::runtime_error { public: using std::runtime_error::runtime_error; }; /// RAII handle to an iKv root or a node owned by an iKv tree. /// /// Copies share ownership of the same tree. Child handles remain valid while their /// node exists, but should be reacquired after replacing that node or refreshing the root. class Value { public: using ArrayIndex = std::uint32_t; /// Creates an object or array root. Scalar roots are not supported by iKv. explicit Value(ValueType type = objectValue, std::string root_name = "root"); Value(const Value&) = default; /// Structural assignment is unavailable because iKv cannot clone arbitrary subtrees. Value& operator=(const Value&) = delete; /// Parses auto-detected iKv1 or iKv2 text. static Value parse(const std::string& text); /// Loads an auto-detected iKv1 or iKv2 text file. static Value load(const std::string& path); /// Parses an iKv binary buffer. The resulting tree owns any required data. static Value fromBinary(const void* data, std::size_t size); /// Loads an auto-detected binary iKv file. static Value loadBinary(const std::string& path); /// Returns the node's runtime type, or nullValue for a missing member. ValueType type() const noexcept; bool isNull() const noexcept; bool isString() const noexcept; bool isInt() const noexcept; bool isDouble() const noexcept; bool isBool() const noexcept; bool isObject() const noexcept; bool isArray() const noexcept; bool empty() const; std::size_t size() const; std::string name() const; bool isMember(const std::string& key) const; /// Looks up an object member. A missing non-const member returns an assignable null Value. Value operator[](const std::string& key); Value operator[](const char* key); Value operator[](const std::string& key) const; Value operator[](const char* key) const; Value operator[](ArrayIndex index); Value operator[](int index); Value operator[](ArrayIndex index) const; Value operator[](int index) const; /// Returns an object member or a shared copy of fallback when the key is absent. Value get(const std::string& key, const Value& fallback) const; /// Assigns a scalar to an object member returned by operator[]. Value& operator=(const std::string& value); Value& operator=(const char* value); Value& operator=(std::int64_t value); Value& operator=(int value); Value& operator=(double value); Value& operator=(bool value); /// Adds or replaces an object member and returns a handle to it. Value makeObject(const std::string& key); /// Adds an array member. nullValue creates an untyped array. Value makeArray(const std::string& key, ValueType element_type = nullValue); /// Appends to an array. Typed arrays reject incompatible values with Error. Value append(const std::string& value); Value append(const char* value); Value append(std::int64_t value); Value append(int value); Value append(double value); Value append(bool value); Value appendObject(); std::string asString() const; std::int64_t asInt64() const; int asInt() const; double asDouble() const; bool asBool() const; /// Writes text or binary output, using iKv2 unless a version is specified. void write(const std::string& path, Version version = Version::v2) const; void writeBinary(const std::string& path, Version version = Version::v2) const; std::vector toBinary(Version version = Version::v2) const; /// Replaces this root in place from a text or binary path while preserving shared handles. /// Only mutable root Values can be refreshed; failure leaves the existing tree unchanged. void refresh(const std::string& path); private: struct Deleter { void operator()(ikv_node_t* node) const noexcept; }; using Owner = std::shared_ptr; Value(Owner owner, ikv_node_t* node, ikv_node_t* parent, std::string key, bool read_only = false); static Value adopt(ikv_node_t* node); void require(ValueType expected, const char* operation) const; void requireMutable(const char* operation) const; void requireObjectParent(const char* operation) const; Value appended(std::size_t old_size); Owner owner_; ikv_node_t* node_ = nullptr; ikv_node_t* parent_ = nullptr; std::string key_; bool read_only_ = false; }; } // namespace ikv