backend/datamodel/key_range.cc (113 lines of code) (raw):
//
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "backend/datamodel/key_range.h"
#include <ostream>
#include <sstream>
#include <string>
namespace google {
namespace spanner {
namespace emulator {
namespace backend {
KeyRange::KeyRange()
: KeyRange(EndpointType::kClosed, Key(), EndpointType::kOpen, Key()) {}
KeyRange::KeyRange(EndpointType start_type, const Key& start_key,
EndpointType limit_type, const Key& limit_key)
: start_type_(start_type),
start_key_(start_key),
limit_type_(limit_type),
limit_key_(limit_key) {}
// static
KeyRange KeyRange::Empty() {
return KeyRange::ClosedOpen(Key::Empty(), Key::Empty());
}
// static
KeyRange KeyRange::All() {
return KeyRange::ClosedOpen(Key::Empty(), Key::Infinity());
}
// static
KeyRange KeyRange::Point(const Key& key) {
return KeyRange::ClosedOpen(key, key.ToPrefixLimit());
}
// static
KeyRange KeyRange::Prefix(const Key& key) {
return KeyRange::ClosedOpen(key, key.ToPrefixLimit());
}
// static
KeyRange KeyRange::ClosedOpen(const Key& start_key, const Key& limit_key) {
return KeyRange(EndpointType::kClosed, start_key, EndpointType::kOpen,
limit_key);
}
// static
KeyRange KeyRange::ClosedClosed(const Key& start_key, const Key& limit_key) {
return KeyRange(EndpointType::kClosed, start_key, EndpointType::kClosed,
limit_key);
}
// static
KeyRange KeyRange::OpenOpen(const Key& start_key, const Key& limit_key) {
return KeyRange(EndpointType::kOpen, start_key, EndpointType::kOpen,
limit_key);
}
// static
KeyRange KeyRange::OpenClosed(const Key& start_key, const Key& limit_key) {
return KeyRange(EndpointType::kOpen, start_key, EndpointType::kClosed,
limit_key);
}
bool KeyRange::operator==(const KeyRange& other) const {
return start_key_ == other.start_key_ && limit_key_ == other.limit_key_ &&
start_type_ == other.start_type_ && limit_type_ == other.limit_type_;
}
bool KeyRange::IsClosedOpen() const {
return start_type_ == EndpointType::kClosed &&
limit_type_ == EndpointType::kOpen;
}
bool KeyRange::Contains(const Key& k) const {
// Note that, based on the interval endpoint type, we could have converted
// keys at construction time using Key::ToPrefixLimit which would allow us to
// the natural operator overloads to test for inclusion, but we want to
// preserve the keys given to us in the constructor.
switch (start_type_) {
case EndpointType::kOpen:
if (k <= start_key_ || start_key_.IsPrefixOf(k)) {
return false;
}
break;
case EndpointType::kClosed:
if (k < start_key_) {
return false;
}
break;
}
switch (limit_type_) {
case EndpointType::kOpen:
if (k >= limit_key_) {
return false;
}
break;
case EndpointType::kClosed:
if (k > limit_key_ && !limit_key_.IsPrefixOf(k)) {
return false;
}
break;
}
return true;
}
KeyRange KeyRange::ToClosedOpen() const {
// For Open intervals, we want to exclude all keys with the given prefix. This
// is (by definition) equivalent to a closed interval starting at the prefix
// limit key.
Key start_key = start_type_ == EndpointType::kClosed
? start_key_
: start_key_.ToPrefixLimit();
// For Closed intervals, we want to include all keys with the given prefix.
// This is (by definition) equivalent to a open interval ending in the prefix
// limit key.
Key limit_key = limit_type_ == EndpointType::kOpen
? limit_key_
: limit_key_.ToPrefixLimit();
return KeyRange::ClosedOpen(start_key, limit_key);
}
std::string KeyRange::DebugString() const {
std::stringstream out;
out << (*this);
return out.str();
}
std::ostream& operator<<(std::ostream& out, const KeyRange& range) {
if (range.start_type() == EndpointType::kClosed) {
out << "[";
} else {
out << "(";
}
out << range.start_key();
out << " ... ";
out << range.limit_key();
if (range.limit_type() == EndpointType::kClosed) {
out << "]";
} else {
out << ")";
}
return out;
}
} // namespace backend
} // namespace emulator
} // namespace spanner
} // namespace google