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