diff options
Diffstat (limited to 'include/openvic-dataloader')
-rw-r--r-- | include/openvic-dataloader/csv/LineObject.hpp | 53 | ||||
-rw-r--r-- | include/openvic-dataloader/csv/ValueNode.hpp | 81 |
2 files changed, 120 insertions, 14 deletions
diff --git a/include/openvic-dataloader/csv/LineObject.hpp b/include/openvic-dataloader/csv/LineObject.hpp index c6d8e2a..b9ee9a5 100644 --- a/include/openvic-dataloader/csv/LineObject.hpp +++ b/include/openvic-dataloader/csv/LineObject.hpp @@ -4,7 +4,6 @@ #include <cctype> #include <cstddef> #include <cstdint> -#include <functional> #include <initializer_list> #include <optional> #include <ostream> @@ -14,6 +13,7 @@ #include <utility> #include <vector> +#include <openvic-dataloader/csv/ValueNode.hpp> #include <openvic-dataloader/detail/VectorConstexpr.hpp> namespace ovdl::csv { @@ -28,13 +28,13 @@ namespace ovdl::csv { /// ;a;b;c -> 0,4+ == "" /// /// If this is incorrect, please report an issue. - class LineObject final : public std::vector<std::pair<std::uint32_t, std::string>> { + class LineObject final : public std::vector<ValueNode> { public: // Stored position of value - using position_type = std::uint32_t; + using position_type = ValueNode::position_type; // Value - using inner_value_type = std::string; - using container_type = std::vector<std::pair<position_type, inner_value_type>>; + using inner_value_type = ValueNode; + using container_type = std::vector<ValueNode>; OVDL_VECTOR_CONSTEXPR LineObject() = default; OVDL_VECTOR_CONSTEXPR LineObject(LineObject&) = default; @@ -57,18 +57,42 @@ namespace ovdl::csv { /// Special Functionality /// Retrieves value, produces "" for empty values - constexpr std::string_view get_value_for(std::size_t position) const { + constexpr std::string get_value_for(std::size_t position) const { if (position < _prefix_end || position >= _suffix_end) return ""; - for (const auto& [pos, val] : *this) { - if (pos == position) return val; + for (const auto& object : *this) { + if (object.get_position() == position) return object.make(); } return ""; } - /// Tries to retrieve reference, produces nullopt for empty values - constexpr std::optional<const std::reference_wrapper<const std::string>> try_get_string_at(std::size_t position) const { + /// Tries to retrieve string, produces nullopt for empty values + constexpr std::optional<const std::string> try_get_string_at(std::size_t position) const { if (position < _prefix_end || position >= _suffix_end) return std::nullopt; - for (const auto& [pos, val] : *this) { - if (pos == position) return std::cref(val); + for (const auto& object : *this) { + if (object.get_position() == position) return object.make(); + } + return std::nullopt; + } + constexpr std::optional<const std::reference_wrapper<const ValueNode>> try_get_object_at(std::size_t position) const { + if (position < _prefix_end || position >= _suffix_end) return std::nullopt; + for (const auto& object : *this) { + if (object.get_position() == position) return object; + } + return std::nullopt; + } + + /// Retrieves value, produces "" for empty values + constexpr std::string_view get_value_for(std::size_t position, const IsMap<std::string> auto& map) const { + if (position < _prefix_end || position >= _suffix_end) return ""; + for (const auto& object : *this) { + if (object.get_position() == position) return object.make_from_map(map); + } + return ""; + } + /// Tries to retrieve string, produces nullopt for empty values + constexpr std::optional<const std::string> try_get_string_at(std::size_t position, const IsMap<std::string> auto& map) const { + if (position < _prefix_end || position >= _suffix_end) return std::nullopt; + for (const auto& object : *this) { + if (object.get_position() == position) return object.make_from_map(map); } return std::nullopt; } @@ -91,8 +115,9 @@ namespace ovdl::csv { inline std::ostream& operator<<(std::ostream& stream, const LineObject& line) { static const char SEP = ';'; LineObject::position_type sep_index = 0; - for (const auto& [pos, val] : line) { - while (sep_index < pos) { + for (const auto& object : line) { + const std::string& val = object.make(); + while (sep_index < object.get_position()) { stream << SEP; sep_index++; } diff --git a/include/openvic-dataloader/csv/ValueNode.hpp b/include/openvic-dataloader/csv/ValueNode.hpp new file mode 100644 index 0000000..e66dac0 --- /dev/null +++ b/include/openvic-dataloader/csv/ValueNode.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include <concepts> +#include <cstdint> +#include <initializer_list> +#include <optional> +#include <string> +#include <string_view> +#include <type_traits> +#include <variant> +#include <vector> + +#include <fmt/compile.h> +#include <fmt/core.h> +#include <fmt/format.h> + +namespace ovdl::csv { + template<typename T, typename Value> + concept IsMap = + requires(T t) { + { t.begin() } -> std::same_as<typename T::const_iterator>; + { t.end() } -> std::same_as<typename T::const_iterator>; + { t.empty() } -> std::same_as<bool>; + { t.size() } -> std::same_as<typename T::size_type>; + { t.at("") } -> std::same_as<const Value&>; + { t.find("") } -> std::same_as<typename T::const_iterator>; + { t[""] } -> std::same_as<const Value&>; + }; + + class ValueNode { + public: + struct Placeholder { + static constexpr char ESCAPE_CHAR = '$'; + static constexpr std::string_view ESCAPE_STR = std::string_view { &ESCAPE_CHAR, 1 }; + + std::string value; + inline std::string as_string(std::string_view prefix = ESCAPE_STR, std::optional<std::string_view> suffix = std::nullopt) const { + return fmt::format(FMT_COMPILE("{}{}{}"), prefix, value, suffix.value_or(prefix)); + } + }; + + using internal_value_type = std::variant<std::string, Placeholder>; + using position_type = std::uint32_t; + + ValueNode(); + ValueNode(std::string_view string, position_type position = 0); + ValueNode(std::vector<internal_value_type> value_list, position_type position = 0); + ValueNode(std::initializer_list<internal_value_type> value_list, position_type position = 0); + + void set_position(position_type position); + position_type get_position() const; + + void set_as_list(internal_value_type value); + void add_to_list(internal_value_type value); + bool list_is_empty() const; + + inline std::string make_from_map(const IsMap<std::string> auto& map) const { + std::vector<std::string_view> pre_joined(_value_list.size()); + + for (auto&& value : _value_list) { + pre_joined.push_back(std::visit([&](auto&& arg) -> std::string_view { + using T = std::decay_t<decltype(arg)>; + if constexpr (std::is_same_v<T, std::string>) { + return arg; + } else if constexpr (std::is_same_v<T, Placeholder>) { + return map[arg.value]; + } + }, + value)); + } + + return fmt::format(FMT_COMPILE("{}"), fmt::join(pre_joined, "")); + } + + std::string make(std::string_view prefix = Placeholder::ESCAPE_STR, std::optional<std::string_view> suffix = std::nullopt) const; + + private: + position_type _position; + std::vector<internal_value_type> _value_list; + }; +}
\ No newline at end of file |