Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/common/string_index.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 | |
| 11 namespace { | |
| 12 // Constants | |
| 13 static const char kZeroDigit = 'A'; | |
|
akalin
2011/10/17 22:25:25
no need for static since we're in anon namespace
| |
| 14 static const char kMinDigit = 'B'; | |
| 15 static const char kMidDigit = 'N'; | |
| 16 static const char kMaxDigit = 'Z'; | |
| 17 static const int kMaxDigitValue = kMaxDigit - kZeroDigit; | |
| 18 static const int kMidDigitValue = kMidDigit - kZeroDigit; | |
| 19 static const int kFullDigitValue = (kMaxDigit + 1) - kZeroDigit; | |
| 20 | |
| 21 // Helper Functions | |
| 22 | |
| 23 // Remove all trailing zeros from a value as they provide no value. | |
| 24 std::string RemoveTrailingZeros(const std::string& value) { | |
| 25 DCHECK(!value.empty()); | |
| 26 | |
| 27 int end_position = value.length() - 1; | |
| 28 while (value[end_position] == kZeroDigit) { | |
| 29 --end_position; | |
| 30 } | |
| 31 | |
| 32 return value.substr(0, end_position + 1); | |
| 33 } | |
| 34 | |
| 35 // Add kMidDigitValue to the value at position index because | |
| 36 // the previous index values had an odd difference, so their correct | |
| 37 // middle value is x and a half, so the half is now inserted. | |
| 38 void AddHalf(size_t position, std::string& value) { | |
| 39 DCHECK_GT(position, static_cast<size_t>(0)); | |
| 40 value[position] += kMidDigitValue; | |
| 41 | |
| 42 for (size_t i = position; value[i] > kMaxDigit; --i) { | |
| 43 CHECK_GT(i, static_cast<size_t>(0)); | |
| 44 value[i] -= kFullDigitValue; | |
| 45 ++value[i - 1]; | |
| 46 } | |
| 47 } | |
| 48 | |
| 49 // Return the digit value at position i, padding with kZeroDigit if required. | |
| 50 int GetPositionValue(std::string str, size_t i) { | |
| 51 return (i < str.length()) ? (str[i] - kZeroDigit) : 0; | |
| 52 } | |
| 53 | |
| 54 // Compute the midpoint string that is between start and end. | |
|
akalin
2011/10/17 22:25:25
This is what I want, basically:
// Given strings
| |
| 55 std::string ComputeMidpoint(const std::string& start, | |
| 56 const std::string& end) { | |
| 57 size_t max_size = std::max(start.length(), | |
| 58 end.length()); | |
| 59 std::string middle_string(max_size, kZeroDigit); | |
| 60 | |
| 61 bool add_half = false; | |
| 62 for (size_t i = 0; i < max_size; ++i) { | |
| 63 int char_value = GetPositionValue(start, i); | |
| 64 char_value += GetPositionValue(end, i); | |
| 65 | |
| 66 middle_string[i] += (char_value / 2); | |
| 67 if (add_half) { | |
| 68 AddHalf(i, middle_string); | |
| 69 } | |
| 70 add_half = (char_value % 2 == 1); | |
| 71 } | |
| 72 | |
| 73 return middle_string; | |
| 74 } | |
| 75 | |
| 76 // Create a StringIndex that is lexigraphically greater than start and | |
| 77 // lexigraphically less than end, ideally the StringIndex will be a | |
| 78 // middle value between the two StringIndexs. | |
| 79 StringIndex CreateStringIndexBetween(const StringIndex& start, | |
| 80 const StringIndex& end) { | |
| 81 CHECK(start.IsValid()); | |
| 82 CHECK(end.IsValid()); | |
| 83 std::string start_string = start.ToString(); | |
| 84 std::string end_string = end.ToString(); | |
| 85 DCHECK_LT(start_string, end_string); | |
| 86 | |
| 87 std::string middle_string = ComputeMidpoint(start_string, end_string); | |
| 88 | |
| 89 // We only add an extra digit if it is required for uniqueness, otherwise | |
|
akalin
2011/10/17 22:25:25
Although you can decomp this logic (which will tur
| |
| 90 // we accept a close to middle placement. | |
| 91 if (RemoveTrailingZeros(middle_string) == start_string) { | |
| 92 middle_string += kMidDigit; | |
| 93 } | |
| 94 middle_string = RemoveTrailingZeros(middle_string); | |
| 95 | |
| 96 DCHECK_GT(middle_string, start_string); | |
| 97 DCHECK_LT(middle_string, end_string); | |
| 98 | |
| 99 return StringIndex(middle_string); | |
| 100 } | |
| 101 } // namespace | |
| 102 | |
| 103 StringIndex::StringIndex(const std::string& str) : string_index_(str), | |
| 104 is_valid_(true) { | |
| 105 if (string_index_.empty()) { | |
| 106 is_valid_ = false; | |
|
akalin
2011/10/17 22:25:25
decomp this into a function. That is, have:
bool
| |
| 107 } | |
| 108 | |
| 109 for (size_t i = 0; i < string_index_.length(); ++i) { | |
| 110 if (string_index_[i] < kZeroDigit || string_index_[i] > kMaxDigit) { | |
| 111 is_valid_ = false; | |
| 112 } | |
| 113 } | |
| 114 | |
| 115 if (string_index_[string_index_.length() - 1] == kZeroDigit) { | |
| 116 is_valid_ = false; | |
| 117 } | |
| 118 } | |
| 119 | |
| 120 StringIndex::StringIndex() : string_index_(""), is_valid_(false) { | |
|
akalin
2011/10/17 22:25:25
omit string_index_ (it's already default-initializ
| |
| 121 } | |
| 122 | |
| 123 bool StringIndex::IsValid() const { | |
| 124 return is_valid_; | |
| 125 } | |
| 126 | |
| 127 bool StringIndex::LessThan(const StringIndex& other) const { | |
| 128 CHECK(other.IsValid()); | |
|
akalin
2011/10/17 22:25:25
nit: prefer CHECK(IsValid()) before CHECK(other.Is
| |
| 129 CHECK(IsValid()); | |
| 130 return string_index_ < other.string_index_; | |
| 131 } | |
| 132 | |
| 133 bool StringIndex::Equal(const StringIndex& other) const { | |
| 134 CHECK(other.IsValid()); | |
|
akalin
2011/10/17 22:25:25
here too
| |
| 135 CHECK(IsValid()); | |
| 136 | |
|
akalin
2011/10/17 22:25:25
omit extra line
| |
| 137 return string_index_ == other.string_index_; | |
| 138 } | |
| 139 | |
| 140 StringIndex StringIndex::CreateBetween(const StringIndex& other) const { | |
| 141 CHECK(other.IsValid()); | |
|
akalin
2011/10/17 22:25:25
here too
| |
| 142 CHECK(IsValid()); | |
| 143 CHECK(LessThan(other)); | |
| 144 | |
| 145 return CreateStringIndexBetween(*this, other); | |
| 146 } | |
| 147 | |
| 148 StringIndex StringIndex::CreateBefore() const { | |
| 149 CHECK(IsValid()); | |
|
akalin
2011/10/17 22:25:25
I think the following would be clearer:
const siz
| |
| 150 // Create the smallest, valid StringIndex to be the minimum boundary. | |
| 151 std::string start_string = std::string(string_index_.length(), | |
| 152 kZeroDigit); | |
| 153 *(start_string.rbegin()) = kMinDigit; | |
| 154 if (start_string == string_index_) { | |
| 155 *(start_string.rbegin()) = kZeroDigit; | |
| 156 start_string += kMinDigit; | |
| 157 } | |
| 158 | |
| 159 return CreateStringIndexBetween(StringIndex(start_string), *this); | |
|
akalin
2011/10/17 22:25:25
return StringIndex(start_string).CreateBetween(*th
akalin
2011/10/17 22:25:25
Add comment saying that, even though start_string
| |
| 160 } | |
| 161 | |
| 162 StringIndex StringIndex::CreateAfter() const { | |
| 163 CHECK(IsValid()); | |
| 164 std::string end = std::string(string_index_.length(), kMaxDigit); | |
| 165 if (end == string_index_) { | |
| 166 end += kMaxDigit; | |
| 167 } | |
| 168 | |
|
akalin
2011/10/17 22:25:25
return CreateBetween(StringIndex(end))
| |
| 169 return CreateStringIndexBetween(*this, StringIndex(end)); | |
|
akalin
2011/10/17 22:25:25
Add comment similar to CreateBefore
| |
| 170 } | |
| 171 | |
| 172 std::string StringIndex::ToString() const { | |
| 173 return string_index_; | |
| 174 } | |
| OLD | NEW |