1 // Copyright 2017 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_ROW_RANGE_H 16 #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_ROW_RANGE_H 17 18 #include "google/cloud/bigtable/internal/prefix_range_end.h" 19 #include "google/cloud/bigtable/row_key.h" 20 #include "google/cloud/bigtable/version.h" 21 #include <google/bigtable/v2/data.pb.h> 22 #include <chrono> 23 #include <utility> 24 25 namespace google { 26 namespace cloud { 27 namespace bigtable { 28 inline namespace BIGTABLE_CLIENT_NS { 29 /** 30 * Define the interfaces to create row key ranges. 31 * 32 * Example: 33 * @code 34 * // Create a range for the keys starting with the given prefix. 35 * auto range = bigtable::RowRange("foo/"); 36 * @endcode 37 */ 38 class RowRange { 39 public: RowRange(::google::bigtable::v2::RowRange rhs)40 explicit RowRange(::google::bigtable::v2::RowRange rhs) 41 : row_range_(std::move(rhs)) {} 42 43 RowRange(RowRange&&) noexcept = default; 44 RowRange& operator=(RowRange&&) noexcept = default; 45 RowRange(RowRange const&) = default; 46 RowRange& operator=(RowRange const&) = default; 47 48 /// Return the infinite range, i.e., a range including all possible keys. InfiniteRange()49 static RowRange InfiniteRange() { return RowRange(); } 50 51 /// Return the range starting at @p begin (included), with no upper limit. 52 template <typename T> StartingAt(T && begin)53 static RowRange StartingAt(T&& begin) { 54 RowRange result; 55 result.row_range_.set_start_key_closed(std::forward<T>(begin)); 56 return result; 57 } 58 59 /// Return the range ending at @p end (included), with no lower limit. 60 template <typename T> EndingAt(T && end)61 static RowRange EndingAt(T&& end) { 62 RowRange result; 63 result.row_range_.set_end_key_closed(std::forward<T>(end)); 64 return result; 65 } 66 67 /// Return an empty range. Empty()68 static RowRange Empty() { 69 RowRange result; 70 // Return an open interval that contains no key, using "\0" for the end key. 71 // We can't use "", because when appearing as the end it means 'infinity'. 72 result.row_range_.set_start_key_open(""); 73 result.row_range_.set_end_key_open(std::string("\0", 1)); 74 return result; 75 } 76 77 /// Return the range representing the interval [@p begin, @p end). 78 template <typename T, typename U> Range(T && begin,U && end)79 static RowRange Range(T&& begin, U&& end) { 80 return RightOpen(std::forward<T>(begin), std::forward<U>(end)); 81 } 82 83 /// Return a range that contains all the keys starting with @p prefix. 84 template <typename T> Prefix(T && prefix)85 static RowRange Prefix(T&& prefix) { 86 auto end = internal::PrefixRangeEnd(prefix); 87 return RightOpen(std::forward<T>(prefix), std::move(end)); 88 } 89 90 //@{ 91 /// @name Less common, yet sometimes useful, ranges. 92 /// Return a range representing the interval [@p begin, @p end). 93 template <typename T, typename U> RightOpen(T && begin,U && end)94 static RowRange RightOpen(T&& begin, U&& end) { 95 RowRange result; 96 result.row_range_.set_start_key_closed(std::forward<T>(begin)); 97 if (!internal::IsEmptyRowKey(end)) { 98 result.row_range_.set_end_key_open(std::forward<U>(end)); 99 } 100 return result; 101 } 102 103 /// Return a range representing the interval (@p begin, @p end]. 104 template <typename T, typename U> LeftOpen(T && begin,U && end)105 static RowRange LeftOpen(T&& begin, U&& end) { 106 RowRange result; 107 result.row_range_.set_start_key_open(std::forward<T>(begin)); 108 if (!internal::IsEmptyRowKey(end)) { 109 result.row_range_.set_end_key_closed(std::forward<U>(end)); 110 } 111 return result; 112 } 113 114 /// Return a range representing the interval (@p begin, @p end). 115 template <typename T, typename U> Open(T && begin,U && end)116 static RowRange Open(T&& begin, U&& end) { 117 RowRange result; 118 result.row_range_.set_start_key_open(std::forward<T>(begin)); 119 if (!internal::IsEmptyRowKey(end)) { 120 result.row_range_.set_end_key_open(std::forward<U>(end)); 121 } 122 return result; 123 } 124 125 /// Return a range representing the interval [@p begin, @p end]. 126 template <typename T, typename U> Closed(T && begin,U && end)127 static RowRange Closed(T&& begin, U&& end) { 128 RowRange result; 129 result.row_range_.set_start_key_closed(std::forward<T>(begin)); 130 if (!internal::IsEmptyRowKey(end)) { 131 result.row_range_.set_end_key_closed(std::forward<U>(end)); 132 } 133 return result; 134 } 135 //@} 136 137 /** 138 * Return true if the range is empty. 139 * 140 * Note that some ranges (such as `["", ""]`) are not empty but only include 141 * invalid row keys. 142 */ 143 bool IsEmpty() const; 144 145 /// Return true if @p key is in the range. 146 template <typename T> Contains(T const & key)147 bool Contains(T const& key) const { 148 return !BelowStart(key) && !AboveEnd(key); 149 } 150 151 /** 152 * Compute the intersection against another RowRange. 153 * 154 * @return a 2-tuple, the first element is a boolean, with value `true` if 155 * there is some intersection, the second element is the intersection. 156 * If there is no intersection the first element is `false` and the second 157 * element has a valid, but unspecified value. 158 */ 159 std::pair<bool, RowRange> Intersect(RowRange const& range) const; 160 161 /// Return the filter expression as a protobuf. as_proto()162 ::google::bigtable::v2::RowRange const& as_proto() const& { 163 return row_range_; 164 } 165 166 /// Move out the underlying protobuf value. as_proto()167 ::google::bigtable::v2::RowRange&& as_proto() && { 168 return std::move(row_range_); 169 } 170 171 private: 172 /// Private to avoid mistaken creation of uninitialized ranges. 173 RowRange() = default; 174 175 /// Return true if @p key is below the start. 176 bool BelowStart(RowKeyType const& key) const; 177 178 /// Return true if @p key is above the end. 179 bool AboveEnd(RowKeyType const& key) const; 180 181 /// Overloads for types != RowKeyType. 182 template <typename T> BelowStart(T const & key)183 bool BelowStart(T const& key) const { 184 return BelowStart(RowKeyType(key)); 185 } 186 187 /// Overloads for types != RowKeyType. 188 template <typename T> AboveEnd(T const & key)189 bool AboveEnd(T const& key) const { 190 return AboveEnd(RowKeyType(key)); 191 } 192 193 ::google::bigtable::v2::RowRange row_range_; 194 }; 195 196 bool operator==(RowRange const& lhs, RowRange const& rhs); 197 198 inline bool operator!=(RowRange const& lhs, RowRange const& rhs) { 199 return std::rel_ops::operator!=(lhs, rhs); 200 } 201 202 /// Print a human-readable representation of the range, mostly for testing. 203 std::ostream& operator<<(std::ostream& os, RowRange const& x); 204 } // namespace BIGTABLE_CLIENT_NS 205 } // namespace bigtable 206 } // namespace cloud 207 } // namespace google 208 209 #endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_ROW_RANGE_H 210