選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

330 行
9.0KB

  1. #pragma once
  2. #include <libman/parse_fwd.hpp>
  3. #include <cassert>
  4. #include <filesystem>
  5. #include <optional>
  6. #include <string>
  7. #include <tuple>
  8. #include <utility>
  9. #include <vector>
  10. namespace lm {
  11. class pair {
  12. public:
  13. std::string key;
  14. std::string value;
  15. pair(std::string_view k, std::string_view v)
  16. : key(k)
  17. , value(v) {}
  18. };
  19. class pair_iterator {
  20. using vec_type = std::vector<pair>;
  21. using base_iter = vec_type::const_iterator;
  22. base_iter _iter;
  23. base_iter _end;
  24. std::string _key;
  25. public:
  26. using iterator_category = std::forward_iterator_tag;
  27. using difference_type = vec_type::difference_type;
  28. using value_type = vec_type::value_type;
  29. using pointer = vec_type::pointer;
  30. using reference = vec_type::reference;
  31. inline pair_iterator(base_iter, base_iter, std::string_view k);
  32. pair_iterator& operator++() & noexcept {
  33. assert(_iter != _end);
  34. ++_iter;
  35. while (_iter != _end && _iter->key != _key) {
  36. ++_iter;
  37. }
  38. return *this;
  39. }
  40. const pair* operator->() const noexcept {
  41. assert(_iter != _end);
  42. return _iter.operator->();
  43. }
  44. const pair& operator*() const noexcept {
  45. assert(_iter != _end);
  46. return *_iter;
  47. }
  48. inline bool operator!=(const pair_iterator& o) const noexcept { return _iter != o._iter; }
  49. inline bool operator==(const pair_iterator& o) const noexcept { return _iter == o._iter; }
  50. auto begin() const noexcept { return *this; }
  51. auto end() const noexcept { return pair_iterator(_end, _end, _key); }
  52. explicit operator bool() const noexcept { return *this != end(); }
  53. };
  54. class pair_list {
  55. std::vector<pair> _kvs;
  56. public:
  57. explicit pair_list(std::vector<pair> kvs)
  58. : _kvs(kvs) {}
  59. auto& items() const noexcept { return _kvs; }
  60. const pair* find(const std::string_view& key) const noexcept {
  61. for (auto&& item : items()) {
  62. if (item.key == key) {
  63. return &item;
  64. }
  65. }
  66. return nullptr;
  67. }
  68. pair_iterator iter(std::string_view key) const noexcept {
  69. auto iter = items().begin();
  70. const auto end = items().end();
  71. while (iter != end && iter->key != key) {
  72. ++iter;
  73. }
  74. return pair_iterator{iter, end, key};
  75. }
  76. std::vector<pair> all_of(std::string_view key) const noexcept {
  77. auto iter = this->iter(key);
  78. return std::vector<pair>(iter, iter.end());
  79. }
  80. auto size() const noexcept { return _kvs.size(); }
  81. };
  82. inline pair_iterator::pair_iterator(base_iter it, base_iter end, std::string_view k)
  83. : _iter{it}
  84. , _end{end}
  85. , _key{k} {}
  86. pair_list parse_string(std::string_view);
  87. pair_list parse_file(std::filesystem::path);
  88. void write_pairs(std::filesystem::path, const std::vector<pair>&);
  89. inline void write_pairs(const std::filesystem::path& fpath, const pair_list& pairs) {
  90. write_pairs(fpath, pairs.items());
  91. }
  92. struct nested_kvlist {
  93. std::string primary;
  94. pair_list pairs;
  95. static nested_kvlist parse(std::string_view s);
  96. };
  97. struct unchanged {
  98. template <typename Item>
  99. auto operator()(Item&& item) const {
  100. return item;
  101. }
  102. };
  103. template <typename What>
  104. class read_required {
  105. std::string_view _key;
  106. What& _ref;
  107. bool _did_read = false;
  108. public:
  109. read_required(std::string_view key, What& ref)
  110. : _key(key)
  111. , _ref(ref) {}
  112. int operator()(std::string_view context, std::string_view key, std::string_view value) {
  113. if (key != _key) {
  114. return 0;
  115. }
  116. if (_did_read) {
  117. throw std::runtime_error(std::string(context) + ": Duplicated key '" + std::string(key)
  118. + "' is not allowed");
  119. }
  120. _did_read = true;
  121. _ref = What(value);
  122. return 1;
  123. }
  124. void validate(std::string_view context) const {
  125. if (!_did_read) {
  126. throw std::runtime_error(std::string(context) + ": Missing required key '"
  127. + std::string(_key) + "'");
  128. }
  129. }
  130. };
  131. template <typename T, typename Transform = unchanged>
  132. class read_opt {
  133. std::string_view _key;
  134. T& _ref;
  135. bool _did_read = false;
  136. Transform _tr;
  137. public:
  138. read_opt(std::string_view key, T& ref, Transform tr = unchanged())
  139. : _key(key)
  140. , _ref(ref)
  141. , _tr(std::move(tr)) {}
  142. int operator()(std::string_view context, std::string_view key, std::string_view value) {
  143. if (key != _key) {
  144. return 0;
  145. }
  146. if (_did_read) {
  147. throw std::runtime_error(std::string(context) + ": Duplicated key '" + std::string(key)
  148. + "' is not allowed.");
  149. }
  150. _ref = T(_tr(value));
  151. return 1;
  152. }
  153. };
  154. template <typename T>
  155. class read_bool {
  156. std::string_view _key;
  157. T& _ref;
  158. bool _did_read = false;
  159. public:
  160. read_bool(std::string_view key, T& ref)
  161. : _key(key)
  162. , _ref(ref) {}
  163. bool operator()(std::string_view context, std::string_view key, std::string_view value) {
  164. if (key != _key) {
  165. return false;
  166. }
  167. if (_did_read) {
  168. throw std::runtime_error(std::string(context) + ": Duplicate key '" + std::string(key)
  169. + "' is not allowed.");
  170. }
  171. if (value == "true" || value == "True") {
  172. _ref = true;
  173. } else if (value == "false" || value == "False") {
  174. _ref = false;
  175. } else {
  176. throw std::runtime_error(std::string(context) + ": Invalid value '" + std::string(value)
  177. + "' for key '" + std::string(key)
  178. + ".' Expected `true` or `false`.");
  179. }
  180. _did_read = true;
  181. return true;
  182. }
  183. };
  184. struct read_empty_set_true {
  185. std::string_view _key;
  186. bool& _bool;
  187. bool _seen = false;
  188. bool operator()(std::string_view context, std::string_view key, std::string_view value) {
  189. if (key != _key) {
  190. return false;
  191. }
  192. if (value != "") {
  193. throw std::runtime_error(std::string(context) + ": Key '" + std::string(key)
  194. + "' does not expected a value (Got '" + std::string(value)
  195. + "').");
  196. }
  197. if (_seen) {
  198. throw std::runtime_error(std::string(context) + ": Duplicated key '" + std::string(key)
  199. + "'");
  200. }
  201. _bool = true;
  202. _seen = true;
  203. return true;
  204. }
  205. };
  206. class read_check_eq {
  207. std::string_view _key;
  208. std::string_view _expect;
  209. public:
  210. read_check_eq(std::string_view key, std::string_view value)
  211. : _key(key)
  212. , _expect(value) {}
  213. int operator()(std::string_view context, std::string_view key, std::string_view value) const {
  214. if (key != _key) {
  215. return 0;
  216. }
  217. if (value != _expect) {
  218. throw std::runtime_error(std::string(context) + ": Expected key '" + std::string(key)
  219. + "' to have value '" + std::string(_expect) + "' (Got '"
  220. + std::string(value) + "')");
  221. }
  222. return 1;
  223. }
  224. };
  225. template <typename Container, typename Transform = unchanged>
  226. class read_accumulate {
  227. std::string_view _key;
  228. Container& _items;
  229. Transform _tr;
  230. public:
  231. read_accumulate(std::string_view key, Container& c, Transform tr)
  232. : _key(key)
  233. , _items(c)
  234. , _tr(std::move(tr)) {}
  235. read_accumulate(std::string_view key, Container& c)
  236. : _key(key)
  237. , _items(c)
  238. , _tr(unchanged()) {}
  239. int operator()(std::string_view, std::string_view key, std::string_view value) const {
  240. if (key == _key) {
  241. _items.emplace_back(_tr(value));
  242. return 1;
  243. }
  244. return 0;
  245. }
  246. };
  247. class ignore_x_keys {
  248. public:
  249. bool operator()(std::string_view, std::string_view key, std::string_view) const {
  250. return key.find("X-") == 0;
  251. }
  252. };
  253. class reject_unknown {
  254. public:
  255. int operator()(std::string_view context, std::string_view key, std::string_view) const {
  256. throw std::runtime_error(std::string(context) + ": Unknown key '" + std::string(key) + "'");
  257. }
  258. };
  259. template <typename T>
  260. auto validate_reader(T&& t, std::string_view context, int) -> decltype(t.validate(context)) {
  261. t.validate(context);
  262. }
  263. template <typename T>
  264. void validate_reader(T&&, std::string_view, ...) {}
  265. template <typename... Items>
  266. auto read(std::string_view context [[maybe_unused]], const pair_list& pairs, Items... is) {
  267. std::vector<pair> bad_pairs;
  268. for (auto [key, value] : pairs.items()) {
  269. auto did_read = (is(context, key, value) || ...);
  270. if (did_read) {
  271. bad_pairs.emplace_back(key, value);
  272. }
  273. }
  274. (validate_reader(is, context, 0), ...);
  275. return bad_pairs;
  276. }
  277. } // namespace lm