base_path.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * Copyright 2018 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #ifndef FIRESTORE_CORE_SRC_MODEL_BASE_PATH_H_
  17. #define FIRESTORE_CORE_SRC_MODEL_BASE_PATH_H_
  18. #include <algorithm>
  19. #include <cctype>
  20. #include <initializer_list>
  21. #include <string>
  22. #include <utility>
  23. #include <vector>
  24. #include "Firestore/core/src/util/comparison.h"
  25. #include "Firestore/core/src/util/hard_assert.h"
  26. #include "Firestore/core/src/util/hashing.h"
  27. namespace firebase {
  28. namespace firestore {
  29. namespace model {
  30. namespace impl {
  31. /**
  32. * BasePath represents a path sequence in the Firestore database. It is composed
  33. * of an ordered sequence of string segments.
  34. *
  35. * BasePath is reassignable and movable. Apart from those, all other mutating
  36. * operations return new independent instances.
  37. *
  38. * ## Subclassing Notes
  39. *
  40. * BasePath is strictly meant as a base class for concrete implementations. It
  41. * doesn't contain a single virtual method, can't be instantiated, and should
  42. * never be used in any polymorphic way. BasePath is templated to allow static
  43. * factory methods to return objects of the derived class (the expected
  44. * inheritance would use CRTP: struct Derived : BasePath<Derived>).
  45. */
  46. template <typename T>
  47. class BasePath {
  48. protected:
  49. using SegmentsT = std::vector<std::string>;
  50. public:
  51. using const_iterator = SegmentsT::const_iterator;
  52. /** Returns i-th segment of the path. */
  53. const std::string& operator[](const size_t i) const {
  54. HARD_ASSERT(i < segments_.size(), "index %s out of range", i);
  55. return segments_[i];
  56. }
  57. /** Returns the first segment of the path. */
  58. const std::string& first_segment() const {
  59. HARD_ASSERT(!empty(), "Cannot call first_segment on empty path");
  60. return segments_[0];
  61. }
  62. /** Returns the last segment of the path. */
  63. const std::string& last_segment() const {
  64. HARD_ASSERT(!empty(), "Cannot call last_segment on empty path");
  65. return segments_[size() - 1];
  66. }
  67. size_t size() const {
  68. return segments_.size();
  69. }
  70. bool empty() const {
  71. return segments_.empty();
  72. }
  73. const_iterator begin() const {
  74. return segments_.begin();
  75. }
  76. const_iterator end() const {
  77. return segments_.end();
  78. }
  79. /**
  80. * Returns a new path which is the result of concatenating this path with an
  81. * additional segment.
  82. */
  83. T Append(const std::string& segment) const {
  84. auto appended = segments_;
  85. appended.push_back(segment);
  86. return T{std::move(appended)};
  87. }
  88. T Append(std::string&& segment) const {
  89. auto appended = segments_;
  90. appended.push_back(std::move(segment));
  91. return T{std::move(appended)};
  92. }
  93. /**
  94. * Returns a new path which is the result of concatenating this path with an
  95. * another path.
  96. */
  97. T Append(const T& path) const {
  98. auto appended = segments_;
  99. appended.insert(appended.end(), path.begin(), path.end());
  100. return T{std::move(appended)};
  101. }
  102. /**
  103. * Returns a new path which is the result of omitting the first n segments of
  104. * this path.
  105. */
  106. T PopFirst(const size_t n = 1) const {
  107. HARD_ASSERT(n <= size(), "Cannot call PopFirst(%s) on path of length %s", n,
  108. size());
  109. return T{begin() + n, end()};
  110. }
  111. /**
  112. * Returns a new path which is the result of omitting the last segment of
  113. * this path.
  114. */
  115. T PopLast() const {
  116. HARD_ASSERT(!empty(), "Cannot call PopLast() on empty path");
  117. return T{begin(), end() - 1};
  118. }
  119. /**
  120. * Returns true if this path is a prefix of the given path.
  121. *
  122. * Empty path is a prefix of any path. Any path is a prefix of itself.
  123. */
  124. bool IsPrefixOf(const T& rhs) const {
  125. return size() <= rhs.size() && std::equal(begin(), end(), rhs.begin());
  126. }
  127. /**
  128. * Returns true if the given argument is a direct child of this path.
  129. *
  130. * Empty path is a parent of any path that consists of a single segment.
  131. */
  132. bool IsImmediateParentOf(const T& potential_child) const {
  133. return size() + 1 == potential_child.size() &&
  134. std::equal(begin(), end(), potential_child.begin());
  135. }
  136. util::ComparisonResult CompareTo(const T& rhs) const {
  137. return util::CompareContainer(segments_, rhs.segments_);
  138. }
  139. friend bool operator==(const BasePath& lhs, const BasePath& rhs) {
  140. return lhs.segments_ == rhs.segments_;
  141. }
  142. size_t Hash() const {
  143. return util::Hash(segments_);
  144. }
  145. protected:
  146. BasePath() = default;
  147. template <typename IterT>
  148. BasePath(const IterT begin, const IterT end) : segments_{begin, end} {
  149. }
  150. BasePath(std::initializer_list<std::string> list) : segments_{list} {
  151. }
  152. explicit BasePath(SegmentsT&& segments) : segments_{std::move(segments)} {
  153. }
  154. private:
  155. SegmentsT segments_;
  156. };
  157. } // namespace impl
  158. } // namespace model
  159. } // namespace firestore
  160. } // namespace firebase
  161. #endif // FIRESTORE_CORE_SRC_MODEL_BASE_PATH_H_