void lm::write_pairs(fs::path fpath, const std::vector<pair>& pairs) { | void lm::write_pairs(fs::path fpath, const std::vector<pair>& pairs) { | ||||
auto fstream = dds::open(fpath, std::ios::out | std::ios::binary); | auto fstream = dds::open(fpath, std::ios::out | std::ios::binary); | ||||
for (auto& pair : pairs) { | for (auto& pair : pairs) { | ||||
fstream << pair.key() << ": " << pair.value() << '\n'; | |||||
fstream << pair.key << ": " << pair.value << '\n'; | |||||
} | } | ||||
} | } |
namespace lm { | namespace lm { | ||||
class pair { | class pair { | ||||
std::string _key; | |||||
std::string _value; | |||||
public: | public: | ||||
std::string key; | |||||
std::string value; | |||||
pair(std::string_view k, std::string_view v) | pair(std::string_view k, std::string_view v) | ||||
: _key(k) | |||||
, _value(v) {} | |||||
auto& key() const noexcept { return _key; } | |||||
auto& value() const noexcept { return _value; } | |||||
template <std::size_t I> | |||||
std::string_view get() const { | |||||
if constexpr (I == 0) { | |||||
return key(); | |||||
} else if constexpr (I == 1) { | |||||
return value(); | |||||
} | |||||
} | |||||
: key(k) | |||||
, value(v) {} | |||||
}; | }; | ||||
class pair_iterator { | class pair_iterator { | ||||
pair_iterator& operator++() & noexcept { | pair_iterator& operator++() & noexcept { | ||||
assert(_iter != _end); | assert(_iter != _end); | ||||
++_iter; | ++_iter; | ||||
while (_iter != _end && _iter->key() != _key) { | |||||
while (_iter != _end && _iter->key != _key) { | |||||
++_iter; | ++_iter; | ||||
} | } | ||||
return *this; | return *this; | ||||
const pair* find(const std::string_view& key) const noexcept { | const pair* find(const std::string_view& key) const noexcept { | ||||
for (auto&& item : items()) { | for (auto&& item : items()) { | ||||
if (item.key() == key) { | |||||
if (item.key == key) { | |||||
return &item; | return &item; | ||||
} | } | ||||
} | } | ||||
pair_iterator iter(std::string_view key) const noexcept { | pair_iterator iter(std::string_view key) const noexcept { | ||||
auto iter = items().begin(); | auto iter = items().begin(); | ||||
const auto end = items().end(); | const auto end = items().end(); | ||||
while (iter != end && iter->key() != key) { | |||||
while (iter != end && iter->key != key) { | |||||
++iter; | ++iter; | ||||
} | } | ||||
return pair_iterator{iter, end, key}; | return pair_iterator{iter, end, key}; | ||||
} | } | ||||
} // namespace lm | } // namespace lm | ||||
namespace std { | |||||
template <> | |||||
struct tuple_size<lm::pair> : std::integral_constant<int, 2> {}; | |||||
template <std::size_t N> | |||||
struct tuple_element<N, lm::pair> { | |||||
using type = std::string_view; | |||||
}; | |||||
} // namespace std |
kvs = parse_string(lm_src); | kvs = parse_string(lm_src); | ||||
CHECK(kvs.size() == 1); | CHECK(kvs.size() == 1); | ||||
REQUIRE(kvs.find("foo")); | REQUIRE(kvs.find("foo")); | ||||
CHECK(kvs.find("foo")->value() == "bar"); | |||||
CHECK(kvs.find("foo")->value == "bar"); | |||||
lm_src = "foo:bar: baz"; | lm_src = "foo:bar: baz"; | ||||
kvs = parse_string(lm_src); | kvs = parse_string(lm_src); | ||||
CHECK(kvs.size() == 1); | CHECK(kvs.size() == 1); | ||||
REQUIRE(kvs.find("foo:bar")); | REQUIRE(kvs.find("foo:bar")); | ||||
CHECK(kvs.find("foo:bar")->value() == "baz"); | |||||
CHECK(kvs.find("foo:bar")->value == "baz"); | |||||
CHECK(parse_string("#comment").size() == 0); | CHECK(parse_string("#comment").size() == 0); | ||||
CHECK(parse_string("\n\n").size() == 0); | CHECK(parse_string("\n\n").size() == 0); | ||||
kvs = parse_string(s); | kvs = parse_string(s); | ||||
CHECK(kvs.size() == 1); | CHECK(kvs.size() == 1); | ||||
REQUIRE(kvs.find("Foo")); | REQUIRE(kvs.find("Foo")); | ||||
CHECK(kvs.find("Foo")->value() == ""); | |||||
CHECK(kvs.find("Foo")->value == ""); | |||||
} | } | ||||
kvs = parse_string("foo: # Not a comment"); | kvs = parse_string("foo: # Not a comment"); | ||||
CHECK(kvs.size() == 1); | CHECK(kvs.size() == 1); | ||||
REQUIRE(kvs.find("foo")); | REQUIRE(kvs.find("foo")); | ||||
CHECK(kvs.find("foo")->value() == "# Not a comment"); | |||||
CHECK(kvs.find("foo")->value == "# Not a comment"); | |||||
} | } | ||||
void test_multi() { | void test_multi() { | ||||
auto kvs = parse_string("Foo: bar\nbaz: qux"); | auto kvs = parse_string("Foo: bar\nbaz: qux"); | ||||
CHECK(kvs.size() == 2); | CHECK(kvs.size() == 2); | ||||
REQUIRE(kvs.find("Foo")); | REQUIRE(kvs.find("Foo")); | ||||
CHECK(kvs.find("Foo")->value() == "bar"); | |||||
CHECK(kvs.find("Foo")->value == "bar"); | |||||
REQUIRE(kvs.find("baz")); | REQUIRE(kvs.find("baz")); | ||||
CHECK(kvs.find("baz")->value() == "qux"); | |||||
CHECK(kvs.find("baz")->value == "qux"); | |||||
kvs = parse_string("foo: first\nfoo: second\n"); | kvs = parse_string("foo: first\nfoo: second\n"); | ||||
CHECK(kvs.size() == 2); | CHECK(kvs.size() == 2); | ||||
auto iter = kvs.iter("foo"); | auto iter = kvs.iter("foo"); | ||||
REQUIRE(iter); | REQUIRE(iter); | ||||
CHECK(iter->key() == "foo"); | |||||
CHECK(iter->value() == "first"); | |||||
CHECK(iter->key == "foo"); | |||||
CHECK(iter->value == "first"); | |||||
++iter; | ++iter; | ||||
REQUIRE(iter); | REQUIRE(iter); | ||||
CHECK(iter->key() == "foo"); | |||||
CHECK(iter->value() == "second"); | |||||
CHECK(iter->key == "foo"); | |||||
CHECK(iter->value == "second"); | |||||
++iter; | ++iter; | ||||
CHECK(!iter); | CHECK(!iter); | ||||