backend/datamodel/key_set.cc (86 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_set.h" #include <algorithm> #include <ostream> #include <sstream> #include <string> #include <vector> namespace google { namespace spanner { namespace emulator { namespace backend { KeySet::KeySet() = default; KeySet::KeySet(const Key& key) { AddKey(key); } KeySet::KeySet(const KeyRange& key_range) { AddRange(key_range); } void KeySet::AddKey(const Key& key) { keys_.push_back(key); } void KeySet::AddRange(const KeyRange& range) { ranges_.push_back(range); } // static KeySet KeySet::All() { return KeySet(KeyRange::All()); } std::string KeySet::DebugString() const { std::stringstream out; out << (*this); return out.str(); } std::ostream& operator<<(std::ostream& out, const KeySet& set) { const std::vector<Key>& keys = set.keys(); const std::vector<KeyRange>& ranges = set.ranges(); if (keys.empty() && ranges.empty()) { out << "<none>"; } for (int i = 0; i < keys.size(); ++i) { if (i > 0) { out << ", "; } out << "Key" << keys[i]; } for (int i = 0; i < ranges.size(); ++i) { if (!keys.empty() || i > 0) { out << ", "; } out << "Range" << ranges[i]; } return out; } void MakeDisjointKeyRanges(const KeySet& set, std::vector<KeyRange>* ranges) { // Clear output. ranges->clear(); // First convert all keys and ranges to closed-open ranges. for (const Key& key : set.keys()) { ranges->push_back(KeyRange::Point(key)); } for (const KeyRange& range : set.ranges()) { ranges->push_back(range.ToClosedOpen()); } // Early exit if we have nothing to do. if (ranges->empty()) { return; } // Now sort the ranges by start key. std::sort(ranges->begin(), ranges->end(), [](const KeyRange& kr1, const KeyRange& kr2) { return kr1.start_key() < kr2.start_key(); }); // Finally, walk through the ranges, merging them as we go. // Invariants: // - All ranges before last are disjoint // - All ranges in [last, next) have been merged into last // - next moves forward in every iteration auto last = ranges->begin(); auto next = last + 1; while (next != ranges->end()) { // Skip invalid or empty ranges. if (next->start_key() >= next->limit_key()) { ++next; continue; } // Consider merging the next range into the last disjoint range. switch (next->start_key().Compare(last->limit_key())) { case 1: { // The next range's start key is after the last range's limit key. // Everything before next is now disjoint, so make next the new last. ++last; *last = *next; break; } case 0: { // The next range's start key coincides with the last range's limit key. // The two ranges are contiguous, make last extend to cover both ranges. last->limit_key() = next->limit_key(); break; } case -1: { // The next range's start key is before the last range's limit key. // The two ranges overlap, extend last to the greater of the two ranges. last->limit_key() = std::max(next->limit_key(), last->limit_key()); break; } } // Now consider the next un-merged range. ++next; } // Clear any ranges after last (they have already been merged into last). ranges->erase(last + 1, next); } } // namespace backend } // namespace emulator } // namespace spanner } // namespace google