//# This file is a part of toml++ and is subject to the the terms of the MIT license. //# Copyright (c) Mark Gillard //# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. // SPDX-License-Identifier: MIT #pragma once //# {{ #include "preprocessor.h" #if !TOML_IMPLEMENTATION #error This is an implementation-only header. #endif //# }} #include "path.h" #include "at_path.h" #include "print_to_stream.h" TOML_DISABLE_WARNINGS; #if TOML_INT_CHARCONV #include #endif #include TOML_ENABLE_WARNINGS; #include "header_start.h" //#===================================================================================================================== //# toml::path_component //#===================================================================================================================== TOML_NAMESPACE_START { TOML_EXTERNAL_LINKAGE path_component::path_component() // : type_{ path_component_type::key } { store_key("", value_storage_); } TOML_EXTERNAL_LINKAGE path_component::path_component(size_t index) noexcept // : type_(path_component_type::array_index) { store_index(index, value_storage_); } TOML_EXTERNAL_LINKAGE path_component::path_component(std::string_view key) // : type_(path_component_type::key) { store_key(key, value_storage_); } #if TOML_ENABLE_WINDOWS_COMPAT TOML_EXTERNAL_LINKAGE path_component::path_component(std::wstring_view key) // : path_component(impl::narrow(key)) {} #endif TOML_EXTERNAL_LINKAGE path_component::path_component(const path_component& pc) // : type_{ pc.type_ } { if (type_ == path_component_type::array_index) store_index(pc.index(), value_storage_); else store_key(pc.key(), value_storage_); } TOML_EXTERNAL_LINKAGE path_component::path_component(path_component && pc) noexcept // : type_{ pc.type_ } { if (type_ == path_component_type::array_index) store_index(pc.index_ref(), value_storage_); else store_key(std::move(pc.key_ref()), value_storage_); } TOML_EXTERNAL_LINKAGE path_component& path_component::operator=(const path_component& rhs) { if (type_ != rhs.type_) { destroy(); type_ = rhs.type_; if (type_ == path_component_type::array_index) store_index(rhs.index(), value_storage_); else store_key(rhs.key(), value_storage_); } else { if (type_ == path_component_type::array_index) index_ref() = rhs.index(); else key_ref() = rhs.key(); } return *this; } TOML_EXTERNAL_LINKAGE path_component& path_component::operator=(path_component&& rhs) noexcept { if (type_ != rhs.type_) { destroy(); type_ = rhs.type_; if (type_ == path_component_type::array_index) store_index(rhs.index(), value_storage_); else store_key(std::move(rhs.key_ref()), value_storage_); } else { if (type_ == path_component_type::array_index) index_ref() = rhs.index(); else key_ref() = std::move(rhs.key_ref()); } return *this; } TOML_PURE_GETTER TOML_EXTERNAL_LINKAGE bool TOML_CALLCONV path_component::equal(const path_component& lhs, const path_component& rhs) noexcept { // Different comparison depending on contents if (lhs.type_ != rhs.type_) return false; if (lhs.type_ == path_component_type::array_index) return lhs.index() == rhs.index(); else // path_component_type::key return lhs.key() == rhs.key(); } TOML_EXTERNAL_LINKAGE path_component& path_component::operator=(size_t new_index) noexcept { // If currently a key, string will need to be destroyed regardless destroy(); type_ = path_component_type::array_index; store_index(new_index, value_storage_); return *this; } TOML_EXTERNAL_LINKAGE path_component& path_component::operator=(std::string_view new_key) { if (type_ == path_component_type::key) key_ref() = new_key; else { type_ = path_component_type::key; store_key(new_key, value_storage_); } return *this; } #if TOML_ENABLE_WINDOWS_COMPAT TOML_EXTERNAL_LINKAGE path_component& path_component::operator=(std::wstring_view new_key) { if (type_ == path_component_type::key) key_ref() = impl::narrow(new_key); else { type_ = path_component_type::key; store_key(impl::narrow(new_key), value_storage_); } return *this; } #endif } TOML_NAMESPACE_END; //#===================================================================================================================== //# toml::path //#===================================================================================================================== TOML_ANON_NAMESPACE_START { TOML_INTERNAL_LINKAGE bool parse_path_into(std::string_view path_str, std::vector & components) { using components_type = std::remove_reference_t; const auto original_size = components.size(); static constexpr auto on_key = [](void* data, std::string_view key) -> bool { auto& comps = *static_cast(data); comps.emplace_back(key); return true; }; static constexpr auto on_index = [](void* data, size_t index) -> bool { auto& comps = *static_cast(data); comps.emplace_back(index); return true; }; if (!impl::parse_path(path_str, &components, on_key, on_index)) { components.resize(original_size); return false; } return true; } } TOML_ANON_NAMESPACE_END; TOML_NAMESPACE_START { TOML_EXTERNAL_LINKAGE void path::print_to(std::ostream & os) const { bool root = true; for (const auto& component : components_) { if (component.type() == path_component_type::key) // key { if (!root) impl::print_to_stream(os, '.'); impl::print_to_stream(os, component.key()); } else if (component.type() == path_component_type::array_index) // array { impl::print_to_stream(os, '['); impl::print_to_stream(os, component.index()); impl::print_to_stream(os, ']'); } root = false; } } TOML_PURE_GETTER TOML_EXTERNAL_LINKAGE bool TOML_CALLCONV path::equal(const path& lhs, const path& rhs) noexcept { return lhs.components_ == rhs.components_; } //#=== constructors ================================================= TOML_EXTERNAL_LINKAGE path::path(std::string_view str) // { TOML_ANON_NAMESPACE::parse_path_into(str, components_); } #if TOML_ENABLE_WINDOWS_COMPAT TOML_EXTERNAL_LINKAGE path::path(std::wstring_view str) // : path(impl::narrow(str)) {} #endif //#=== assignment ================================================= TOML_EXTERNAL_LINKAGE path& path::operator=(std::string_view rhs) { components_.clear(); TOML_ANON_NAMESPACE::parse_path_into(rhs, components_); return *this; } #if TOML_ENABLE_WINDOWS_COMPAT TOML_EXTERNAL_LINKAGE path& path::operator=(std::wstring_view rhs) { return assign(impl::narrow(rhs)); } #endif //#=== appending ================================================= TOML_EXTERNAL_LINKAGE path& path::operator+=(const path& rhs) { components_.insert(components_.cend(), rhs.begin(), rhs.end()); return *this; } TOML_EXTERNAL_LINKAGE path& path::operator+=(path&& rhs) { components_.insert(components_.end(), std::make_move_iterator(rhs.components_.begin()), std::make_move_iterator(rhs.components_.end())); return *this; } TOML_EXTERNAL_LINKAGE path& path::operator+=(std::string_view str) { TOML_ANON_NAMESPACE::parse_path_into(str, components_); return *this; } #if TOML_ENABLE_WINDOWS_COMPAT TOML_EXTERNAL_LINKAGE path& path::operator+=(std::wstring_view str) { return *this += impl::narrow(str); } #endif //#=== prepending ================================================= TOML_EXTERNAL_LINKAGE path& path::prepend(const path& source) { components_.insert(components_.begin(), source.components_.begin(), source.components_.end()); return *this; } TOML_EXTERNAL_LINKAGE path& path::prepend(path && source) { components_.insert(components_.begin(), std::make_move_iterator(source.components_.begin()), std::make_move_iterator(source.components_.end())); return *this; } TOML_EXTERNAL_LINKAGE path& path::prepend(std::string_view source) { return prepend(path{ source }); } #if TOML_ENABLE_WINDOWS_COMPAT TOML_EXTERNAL_LINKAGE path& path::prepend(std::wstring_view source) { return prepend(impl::narrow(source)); } #endif //#=== string conversion ================================================= TOML_EXTERNAL_LINKAGE std::string path::str() const { if (empty()) return ""; std::ostringstream ss; print_to(ss); return std::move(ss).str(); } #if TOML_ENABLE_WINDOWS_COMPAT TOML_EXTERNAL_LINKAGE std::wstring path::wide_str() const { return impl::widen(str()); } #endif //#=== equality and comparison ================================================= TOML_EXTERNAL_LINKAGE void path::clear() noexcept { components_.clear(); } TOML_EXTERNAL_LINKAGE path& path::truncate(size_t n) { n = n > components_.size() ? components_.size() : n; auto it_end = components_.end(); components_.erase(it_end - static_cast(n), it_end); return *this; } TOML_EXTERNAL_LINKAGE path path::truncated(size_t n) const { path truncated_path{}; n = n > components_.size() ? components_.size() : n; // Copy all components except one // Need at least two path components to have a parent, since if there is // only one path component, the parent is the root/null path "" truncated_path.components_.insert(truncated_path.components_.begin(), components_.begin(), components_.end() - static_cast(n)); return truncated_path; } TOML_EXTERNAL_LINKAGE path path::parent() const { return truncated(1); } TOML_EXTERNAL_LINKAGE path path::leaf(size_t n) const { path leaf_path{}; n = n > components_.size() ? components_.size() : n; if (n > 0) { leaf_path.components_.insert(leaf_path.components_.begin(), components_.end() - static_cast(n), components_.end()); } return leaf_path; } TOML_EXTERNAL_LINKAGE path path::subpath(std::vector::const_iterator start, std::vector::const_iterator end) const { if (start >= end) return {}; path subpath; subpath.components_.insert(subpath.components_.begin(), start, end); return subpath; } TOML_EXTERNAL_LINKAGE path path::subpath(size_t start, size_t length) const { return subpath(begin() + static_cast(start), begin() + static_cast(start + length)); } } TOML_NAMESPACE_END; //#===================================================================================================================== //# at_path() overloads for toml::path //#===================================================================================================================== TOML_NAMESPACE_START { TOML_EXTERNAL_LINKAGE node_view TOML_CALLCONV at_path(node & root, const toml::path& path) noexcept { // early-exit sanity-checks if (root.is_value()) return {}; if (auto tbl = root.as_table(); tbl && tbl->empty()) return {}; if (auto arr = root.as_array(); arr && arr->empty()) return {}; node* current = &root; for (const auto& component : path) { auto type = component.type(); if (type == path_component_type::array_index) { const auto current_array = current->as(); if (!current_array) return {}; // not an array, using array index doesn't work current = current_array->get(component.index()); } else if (type == path_component_type::key) { const auto current_table = current->as(); if (!current_table) return {}; current = current_table->get(component.key()); } else { // Error: invalid component return {}; } if (!current) return {}; // not found } return node_view{ current }; } TOML_EXTERNAL_LINKAGE node_view TOML_CALLCONV at_path(const node& root, const toml::path& path) noexcept { return node_view{ at_path(const_cast(root), path).node() }; } } TOML_NAMESPACE_END; #include "header_end.h"