pointer.h 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #pragma once
  2. #include <cstdint>
  3. #include <iostream>
  4. #include <string>
  5. #include <string_view>
  6. #include <variant>
  7. #include <vector>
  8. #include <jvalidate/detail/compare.h>
  9. #include <jvalidate/forward.h>
  10. namespace jvalidate::detail {
  11. class Pointer {
  12. public:
  13. Pointer() = default;
  14. Pointer(std::vector<std::variant<std::string, size_t>> const & tokens) : tokens_(tokens) {}
  15. Pointer(std::string_view path) {
  16. if (path.empty()) {
  17. return;
  18. }
  19. auto append_with_parse = [this](std::string in) {
  20. if (not in.empty() && in.find_first_not_of("0123456789") == std::string::npos) {
  21. return tokens_.push_back(std::stoull(in));
  22. }
  23. for (size_t i = 0; i < in.size(); ++i) {
  24. if (in[i] == '%') {
  25. char const enc[3] = {in[i + 1], in[i + 2]};
  26. in.replace(i, 3, 1, char(std::stoi(enc, nullptr, 16)));
  27. } else if (in[i] != '~') {
  28. continue;
  29. }
  30. if (in[i + 1] == '0') {
  31. in.replace(i, 2, 1, '~');
  32. } else if (in[i + 1] == '1') {
  33. in.replace(i, 2, 1, '/');
  34. }
  35. }
  36. tokens_.push_back(std::move(in));
  37. };
  38. path.remove_prefix(1);
  39. size_t p = path.find('/');
  40. for (; p != std::string::npos; path.remove_prefix(p + 1), p = path.find('/')) {
  41. append_with_parse(std::string(path.substr(0, p)));
  42. }
  43. append_with_parse(std::string(path));
  44. }
  45. template <Adapter A> A walk(A document) const {
  46. for (auto const & token : tokens_) {
  47. document = std::visit([&document](auto const & next) { return document[next]; }, token);
  48. }
  49. return document;
  50. }
  51. Pointer parent() const { return Pointer({tokens_.begin(), tokens_.end() - 1}); }
  52. Pointer & operator/=(Pointer const & relative) {
  53. tokens_.insert(tokens_.end(), relative.tokens_.begin(), relative.tokens_.end());
  54. return *this;
  55. }
  56. Pointer operator/(Pointer const & relative) const { return Pointer(*this) /= relative; }
  57. Pointer & operator/=(std::string_view key) {
  58. tokens_.emplace_back(std::string(key));
  59. return *this;
  60. }
  61. Pointer operator/(std::string_view key) const { return Pointer(*this) /= key; }
  62. Pointer & operator/=(size_t index) {
  63. tokens_.emplace_back(index);
  64. return *this;
  65. }
  66. Pointer operator/(size_t index) const { return Pointer(*this) /= index; }
  67. friend std::ostream & operator<<(std::ostream & os, Pointer const & self) {
  68. for (auto const & elem : self.tokens_) {
  69. std::visit([&os](auto const & v) { os << '/' << v; }, elem);
  70. }
  71. return os;
  72. }
  73. auto operator<=>(Pointer const &) const = default;
  74. private:
  75. std::vector<std::variant<std::string, size_t>> tokens_{};
  76. };
  77. }