Google Cloud Bigtable C++ Client  1.1.0
A C++ Client Library for Google Cloud Bigtable
row_range.cc
Go to the documentation of this file.
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 #include "google/cloud/bigtable/row_range.h"
16 
17 namespace google {
18 namespace cloud {
19 namespace bigtable {
20 inline namespace BIGTABLE_CLIENT_NS {
21 namespace btproto = ::google::bigtable::v2;
22 
23 bool RowRange::IsEmpty() const {
24  RowKeyType unused;
25  // We do not want to copy the strings unnecessarily, so initialize a reference
26  // pointing to *_key_closed() or *_key_open(), as needed.
27  auto const* start = &unused;
28  bool start_open = false;
29  switch (row_range_.start_key_case()) {
30  case btproto::RowRange::kStartKeyClosed:
31  start = &row_range_.start_key_closed();
32  break;
33  case btproto::RowRange::kStartKeyOpen:
34  start = &row_range_.start_key_open();
35  start_open = true;
36  break;
37  case btproto::RowRange::START_KEY_NOT_SET:
38  break;
39  }
40  // We need to initialize this to something to make g++ happy, but it cannot
41  // be a value that is discarded in all switch() cases to make Clang happy.
42  auto const* end = &row_range_.end_key_closed();
43  bool end_open = false;
44  switch (row_range_.end_key_case()) {
45  case btproto::RowRange::kEndKeyClosed:
46  // Already initialized.
47  break;
48  case btproto::RowRange::kEndKeyOpen:
49  end = &row_range_.end_key_open();
50  end_open = true;
51  break;
52  case btproto::RowRange::END_KEY_NOT_SET:
53  // A range ending at +infinity is never empty.
54  return false;
55  }
56 
57  // Special case of an open interval of two consecutive strings.
58  if (start_open && end_open && internal::ConsecutiveRowKeys(*start, *end)) {
59  return true;
60  }
61 
62  // Compare the strings as byte vectors (careful with unsigned chars).
63  int cmp = internal::CompareRowKey(*start, *end);
64  if (cmp == 0) {
65  return start_open || end_open;
66  }
67  return cmp > 0;
68 }
69 
70 bool RowRange::BelowStart(RowKeyType const& key) const {
71  switch (row_range_.start_key_case()) {
72  case btproto::RowRange::START_KEY_NOT_SET:
73  break;
74  case btproto::RowRange::kStartKeyClosed:
75  return key < row_range_.start_key_closed();
76  case btproto::RowRange::kStartKeyOpen:
77  return key <= row_range_.start_key_open();
78  }
79  return false;
80 }
81 
82 bool RowRange::AboveEnd(RowKeyType const& key) const {
83  switch (row_range_.end_key_case()) {
84  case btproto::RowRange::END_KEY_NOT_SET:
85  break;
86  case btproto::RowRange::kEndKeyClosed:
87  return key > row_range_.end_key_closed();
88  case btproto::RowRange::kEndKeyOpen:
89  return key >= row_range_.end_key_open();
90  }
91  return false;
92 }
93 
94 std::pair<bool, RowRange> RowRange::Intersect(RowRange const& range) const {
95  if (range.IsEmpty()) {
96  return std::make_pair(false, RowRange::Empty());
97  }
98  std::string empty;
99 
100  // The algorithm is simple: start with *this as a the resulting range. Update
101  // both endpoints based on the value of @p range. If the resulting range is
102  // empty there is no intersection.
103  RowRange intersection(*this);
104 
105  switch (range.row_range_.start_key_case()) {
106  case btproto::RowRange::START_KEY_NOT_SET:
107  break;
108  case btproto::RowRange::kStartKeyClosed: {
109  auto const& start = range.row_range_.start_key_closed();
110  // If `range` starts above the current range then there is no
111  // intersection.
112  if (intersection.AboveEnd(start)) {
113  return std::make_pair(false, Empty());
114  }
115  // If `start` is inside the intersection (as computed so far), then the
116  // intersection must start at `start`, and it would be closed if `range`
117  // is closed at the start.
118  if (intersection.Contains(start)) {
119  intersection.row_range_.set_start_key_closed(start);
120  }
121  } break;
122  case btproto::RowRange::kStartKeyOpen: {
123  // The case where `range` is open on the start point is analogous.
124  auto const& start = range.row_range_.start_key_open();
125  if (intersection.AboveEnd(start)) {
126  return std::make_pair(false, Empty());
127  }
128  if (intersection.Contains(start)) {
129  intersection.row_range_.set_start_key_open(start);
130  }
131  } break;
132  }
133 
134  // Then check if the end limit of @p range is below *this.
135  switch (range.row_range_.end_key_case()) {
136  case btproto::RowRange::END_KEY_NOT_SET:
137  break;
138  case btproto::RowRange::kEndKeyClosed: {
139  // If `range` ends before the start of the intersection there is no
140  // intersection and we can return immediately.
141  auto const& end = range.row_range_.end_key_closed();
142  if (intersection.BelowStart(end)) {
143  return std::make_pair(false, Empty());
144  }
145  // If `end` is inside the intersection as computed so far, then the
146  // intersection must end at `end` and it is closed if `range` is closed
147  // at the end.
148  if (intersection.Contains(end)) {
149  intersection.row_range_.set_end_key_closed(end);
150  }
151  } break;
152  case btproto::RowRange::kEndKeyOpen: {
153  // Do the analogous thing for `end` being a open endpoint.
154  auto const& end = range.row_range_.end_key_open();
155  if (intersection.BelowStart(end)) {
156  return std::make_pair(false, Empty());
157  }
158  if (intersection.Contains(end)) {
159  intersection.row_range_.set_end_key_open(end);
160  }
161  } break;
162  }
163 
164  bool is_empty = intersection.IsEmpty();
165  return std::make_pair(!is_empty, std::move(intersection));
166 }
167 
168 bool operator==(RowRange const& lhs, RowRange const& rhs) {
169  if (lhs.as_proto().start_key_case() != rhs.as_proto().start_key_case()) {
170  return false;
171  }
172  switch (lhs.as_proto().start_key_case()) {
173  case btproto::RowRange::START_KEY_NOT_SET:
174  break;
175  case btproto::RowRange::kStartKeyClosed:
176  if (lhs.as_proto().start_key_closed() !=
177  rhs.as_proto().start_key_closed()) {
178  return false;
179  }
180  break;
181  case btproto::RowRange::kStartKeyOpen:
182  if (lhs.as_proto().start_key_open() != rhs.as_proto().start_key_open()) {
183  return false;
184  }
185  break;
186  }
187 
188  if (lhs.as_proto().end_key_case() != rhs.as_proto().end_key_case()) {
189  return false;
190  }
191  switch (lhs.as_proto().end_key_case()) {
192  case btproto::RowRange::END_KEY_NOT_SET:
193  break;
194  case btproto::RowRange::kEndKeyClosed:
195  if (lhs.as_proto().end_key_closed() != rhs.as_proto().end_key_closed()) {
196  return false;
197  }
198  break;
199  case btproto::RowRange::kEndKeyOpen:
200  if (lhs.as_proto().end_key_open() != rhs.as_proto().end_key_open()) {
201  return false;
202  }
203  break;
204  }
205 
206  return true;
207 }
208 
209 std::ostream& operator<<(std::ostream& os, RowRange const& x) {
210  switch (x.as_proto().start_key_case()) {
211  case btproto::RowRange::START_KEY_NOT_SET:
212  os << "['', ";
213  break;
214  case btproto::RowRange::kStartKeyClosed:
215  os << "['" << x.as_proto().start_key_closed() << "', ";
216  break;
217  case btproto::RowRange::kStartKeyOpen:
218  os << "('" << x.as_proto().start_key_open() << "', ";
219  }
220 
221  switch (x.as_proto().end_key_case()) {
222  case btproto::RowRange::END_KEY_NOT_SET:
223  os << "'')";
224  break;
225  case btproto::RowRange::kEndKeyClosed:
226  os << "'" << x.as_proto().end_key_closed() << "']";
227  break;
228  case btproto::RowRange::kEndKeyOpen:
229  os << "'" << x.as_proto().end_key_open() << "')";
230  break;
231  }
232  return os;
233 }
234 
235 } // namespace BIGTABLE_CLIENT_NS
236 } // namespace bigtable
237 } // namespace cloud
238 } // namespace google
#define BIGTABLE_CLIENT_NS
Definition: version.h:22
Contains all the Cloud Bigtable C++ client APIs.