blob: fad038043172a699680083a34a6f494830969015 [file] [log] [blame]
Tao Bao8f237572017-03-26 13:36:49 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <stddef.h>
20
21#include <string>
Tao Baobf5b77d2017-03-30 16:57:29 -070022#include <utility>
Tao Bao8f237572017-03-26 13:36:49 -070023#include <vector>
24
25#include <android-base/logging.h>
26#include <android-base/parseint.h>
27#include <android-base/strings.h>
28
Tao Baobf5b77d2017-03-30 16:57:29 -070029using Range = std::pair<size_t, size_t>;
30
31class RangeSet {
32 public:
33 RangeSet() : blocks_(0) {}
34
35 explicit RangeSet(std::vector<Range>&& pairs) {
36 CHECK_NE(pairs.size(), static_cast<size_t>(0)) << "Invalid number of tokens";
37
38 // Sanity check the input.
39 size_t result = 0;
40 for (const auto& range : pairs) {
41 CHECK_LT(range.first, range.second)
42 << "Empty or negative range: " << range.first << ", " << range.second;
43 size_t sz = range.second - range.first;
44 CHECK_LE(result, SIZE_MAX - sz) << "RangeSet size overflow";
45 result += sz;
46 }
47
48 ranges_ = pairs;
49 blocks_ = result;
50 }
Tao Bao8f237572017-03-26 13:36:49 -070051
52 static RangeSet Parse(const std::string& range_text) {
53 std::vector<std::string> pieces = android::base::Split(range_text, ",");
54 CHECK_GE(pieces.size(), static_cast<size_t>(3)) << "Invalid range text: " << range_text;
55
56 size_t num;
57 CHECK(android::base::ParseUint(pieces[0], &num, static_cast<size_t>(INT_MAX)))
58 << "Failed to parse the number of tokens: " << range_text;
59
60 CHECK_NE(num, static_cast<size_t>(0)) << "Invalid number of tokens: " << range_text;
61 CHECK_EQ(num % 2, static_cast<size_t>(0)) << "Number of tokens must be even: " << range_text;
62 CHECK_EQ(num, pieces.size() - 1) << "Mismatching number of tokens: " << range_text;
63
Tao Baobf5b77d2017-03-30 16:57:29 -070064 std::vector<Range> pairs;
Tao Bao8f237572017-03-26 13:36:49 -070065 for (size_t i = 0; i < num; i += 2) {
Tao Baobf5b77d2017-03-30 16:57:29 -070066 size_t first;
67 CHECK(android::base::ParseUint(pieces[i + 1], &first, static_cast<size_t>(INT_MAX)));
68 size_t second;
69 CHECK(android::base::ParseUint(pieces[i + 2], &second, static_cast<size_t>(INT_MAX)));
Tao Bao8f237572017-03-26 13:36:49 -070070
Tao Baobf5b77d2017-03-30 16:57:29 -070071 pairs.emplace_back(first, second);
Tao Bao8f237572017-03-26 13:36:49 -070072 }
73
Tao Baobf5b77d2017-03-30 16:57:29 -070074 return RangeSet(std::move(pairs));
Tao Bao8f237572017-03-26 13:36:49 -070075 }
76
77 // Get the block number for the i-th (starting from 0) block in the RangeSet.
78 size_t GetBlockNumber(size_t idx) const {
Tao Baobf5b77d2017-03-30 16:57:29 -070079 CHECK_LT(idx, blocks_) << "Out of bound index " << idx << " (total blocks: " << blocks_ << ")";
80
81 for (const auto& range : ranges_) {
82 if (idx < range.second - range.first) {
83 return range.first + idx;
Tao Bao8f237572017-03-26 13:36:49 -070084 }
Tao Baobf5b77d2017-03-30 16:57:29 -070085 idx -= (range.second - range.first);
Tao Bao8f237572017-03-26 13:36:49 -070086 }
Tao Baobf5b77d2017-03-30 16:57:29 -070087
88 CHECK(false) << "Failed to find block number for index " << idx;
Tao Bao8f237572017-03-26 13:36:49 -070089 return 0; // Unreachable, but to make compiler happy.
90 }
91
92 // RangeSet has half-closed half-open bounds. For example, "3,5" contains blocks 3 and 4. So "3,5"
93 // and "5,7" are not overlapped.
94 bool Overlaps(const RangeSet& other) const {
Tao Baobf5b77d2017-03-30 16:57:29 -070095 for (const auto& range : ranges_) {
96 size_t start = range.first;
97 size_t end = range.second;
98 for (const auto& other_range : other.ranges_) {
99 size_t other_start = other_range.first;
100 size_t other_end = other_range.second;
Tao Bao8f237572017-03-26 13:36:49 -0700101 // [start, end) vs [other_start, other_end)
102 if (!(other_start >= end || start >= other_end)) {
103 return true;
104 }
105 }
106 }
107 return false;
108 }
109
Tao Baobf5b77d2017-03-30 16:57:29 -0700110 // size() gives the number of Range's in this RangeSet.
111 size_t size() const {
112 return ranges_.size();
Tao Bao8f237572017-03-26 13:36:49 -0700113 }
Tao Baobf5b77d2017-03-30 16:57:29 -0700114
115 // blocks() gives the number of all blocks in this RangeSet.
116 size_t blocks() const {
117 return blocks_;
118 }
119
120 // We provide const iterators only.
121 std::vector<Range>::const_iterator cbegin() const {
122 return ranges_.cbegin();
123 }
124
125 std::vector<Range>::const_iterator cend() const {
126 return ranges_.cend();
127 }
128
129 // Need to provide begin()/end() since range-based loop expects begin()/end().
130 std::vector<Range>::const_iterator begin() const {
131 return ranges_.cbegin();
132 }
133
134 std::vector<Range>::const_iterator end() const {
135 return ranges_.cend();
136 }
137
138 // Reverse const iterators for MoveRange().
139 std::vector<Range>::const_reverse_iterator crbegin() const {
140 return ranges_.crbegin();
141 }
142
143 std::vector<Range>::const_reverse_iterator crend() const {
144 return ranges_.crend();
145 }
146
147 const Range& operator[](size_t i) const {
148 return ranges_[i];
149 }
150
151 bool operator==(const RangeSet& other) const {
152 // The orders of Range's matter. "4,1,5,8,10" != "4,8,10,1,5".
153 return (ranges_ == other.ranges_);
154 }
155
156 bool operator!=(const RangeSet& other) const {
157 return ranges_ != other.ranges_;
158 }
159
160 private:
161 // Actual limit for each value and the total number are both INT_MAX.
162 std::vector<Range> ranges_;
163 size_t blocks_;
Tao Bao8f237572017-03-26 13:36:49 -0700164};