#ifndef _UCI_CXX_HPP #define _UCI_CXX_HPP #include #include #include #include #include #include namespace uci { template class iterator { // like uci_foreach_element_safe. private: const uci_ptr& _ptr; uci_element* _it = nullptr; uci_element* _next = nullptr; // wrapper for clang-tidy inline auto _list_to_element(const uci_list* cur) -> uci_element* { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-type-cstyle-cast) return list_to_element(cur); // macro casting container=pointer-offset. } public: inline explicit iterator(const uci_ptr& ptr, const uci_list* cur) : _ptr{ptr}, _it{_list_to_element(cur)} { _next = _list_to_element(_it->list.next); } inline iterator(iterator&&) noexcept = default; inline iterator(const iterator&) = delete; inline auto operator=(const iterator&) -> iterator& = delete; inline auto operator=(iterator &&) -> iterator& = delete; auto operator*() -> T { return T{_ptr, _it}; } inline auto operator!=(const iterator& rhs) -> bool { return (&_it->list != &rhs._it->list); } inline auto operator++() -> iterator& { _it = _next; _next = _list_to_element(_next->list.next); return *this; } inline ~iterator() = default; }; class locked_context { private: static std::mutex inuse; public: inline locked_context() { inuse.lock(); } inline locked_context(locked_context&&) noexcept = default; inline locked_context(const locked_context&) = delete; inline auto operator=(const locked_context&) -> locked_context& = delete; inline auto operator=(locked_context &&) -> locked_context& = delete; // NOLINTNEXTLINE(readability-convert-member-functions-to-static) inline auto get() -> uci_context* // is member to enforce inuse { static auto free_ctx = [](uci_context* ctx) { uci_free_context(ctx); }; static std::unique_ptr lazy_ctx{uci_alloc_context(), free_ctx}; if (!lazy_ctx) { // it could be available on a later call: lazy_ctx.reset(uci_alloc_context()); if (!lazy_ctx) { throw std::runtime_error("uci error: cannot allocate context"); } } return lazy_ctx.get(); } inline ~locked_context() { inuse.unlock(); } }; template class element { private: uci_list* _begin = nullptr; uci_list* _end = nullptr; uci_ptr _ptr{}; protected: [[nodiscard]] inline auto ptr() -> uci_ptr& { return _ptr; } [[nodiscard]] inline auto ptr() const -> const uci_ptr& { return _ptr; } void init_begin_end(uci_list* begin, uci_list* end) { _begin = begin; _end = end; } inline explicit element(const uci_ptr& pre, uci_element* last) : _ptr{pre} { _ptr.last = last; } inline explicit element() = default; public: inline element(element&&) noexcept = default; inline element(const element&) = delete; inline auto operator=(const element&) -> element& = delete; inline auto operator=(element &&) -> element& = delete; auto operator[](std::string_view key) const -> T; [[nodiscard]] inline auto name() const -> std::string { return _ptr.last->name; } void rename(const char* value) const; void commit() const; [[nodiscard]] inline auto begin() const -> iterator { return iterator{_ptr, _begin}; } [[nodiscard]] inline auto end() const -> iterator { return iterator{_ptr, _end}; } inline ~element() = default; }; class section; class option; class item; class package : public element
{ public: inline package(const uci_ptr& pre, uci_element* last) : element{pre, last} { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-type-cstyle-cast) ptr().p = uci_to_package(ptr().last); // macro casting pointer-offset. ptr().package = ptr().last->name; auto* end = &ptr().p->sections; auto* begin = end->next; init_begin_end(begin, end); } explicit package(const char* name); auto set(const char* key, const char* type) const -> section; }; class section : public element