Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(177)

Side by Side Diff: chrome/common/string_ordinal.cc

Issue 8236002: Create StringOrdinal to allow placement of strings in sorted lists (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Changing StringIndex to StringOrdinal and making code review changes. Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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_ordinal.h"
6
7 #include <algorithm>
8 #include <cstddef>
9
10 #include "base/logging.h"
11
12 namespace {
13 // Constants
14 const char kZeroDigit = 'a';
15 const char kMinDigit = 'b';
16 const char kMidDigit = 'n';
17 const char kMaxDigit = 'z';
18 const int kMaxDigitValue = kMaxDigit - kZeroDigit;
19 const int kMidDigitValue = kMidDigit - kZeroDigit;
akalin 2011/10/18 17:59:27 put kMidDigitValue before kMaxDigitValue
20 const int kFullDigitValue = (kMaxDigit + 1) - kZeroDigit;
akalin 2011/10/18 17:59:27 #include base/basictypes.h and use COMPILE_ASSERT
akalin 2011/10/18 17:59:27 a better name would be kRadix, and you can set it
21
22 // Helper Functions
23
24 // Remove all trailing zeros from a value as they provide no value.
25 std::string RemoveTrailingZeros(const std::string& value) {
26 DCHECK(!value.empty());
27
28 int end_position = value.length() - 1;
29 while (value[end_position] == kZeroDigit) {
30 --end_position;
31 }
32
33 return value.substr(0, end_position + 1);
34 }
35
36
37 // Return the digit value at position i, padding with kZeroDigit if required.
38 int GetPositionValue(const std::string& str, size_t i) {
39 return (i < str.length()) ? (str[i] - kZeroDigit) : 0;
40 }
41
42 // Add kMidDigitValue to the value at position index because
43 // the previous index values had an odd difference, so their correct
44 // middle value is x and a half, so the half is now inserted.
45 void AddHalf(size_t position, std::string& value) {
46 DCHECK_GT(position, static_cast<size_t>(0));
47
48 // We can't preform this operation directly on the string because
akalin 2011/10/18 17:59:27 preform -> perform
49 // overflow can occur and mess up the values.
50 int new_position_value = value[position] + kMidDigitValue;
akalin 2011/10/18 17:59:27 do static_cast<int>(value[position]) just to be cl
51
52 if (new_position_value <= kMaxDigit) {
53 value[position] = new_position_value;
54 } else {
55 value[position] = new_position_value - kFullDigitValue;
56 ++value[position - 1];
57
58 for (size_t i = position - 1; value[i] > kMaxDigit; --i) {
59 CHECK_GT(i, static_cast<size_t>(0));
60 value[i] = value[i] - kFullDigitValue;
akalin 2011/10/18 17:59:27 -=
61 ++value[i - 1];
62 }
63 }
64 }
65
66 // Drops off the last digit of value and then all trailing zeros iff that
67 // doesn't change its ordering as greater than start.
68 std::string DropUnneededDigits(std::string value,
akalin 2011/10/18 17:59:27 use const refs to strings instead of passing by va
69 std::string start) {
70 CHECK(value > start);
akalin 2011/10/18 17:59:27 CHECK_GT
71
72 std::string shorter_value = value.substr(0, value.length() - 1);
73 shorter_value = RemoveTrailingZeros(shorter_value);
74
75 if (shorter_value != start) {
76 return shorter_value;
77 }
78 return value;
79 }
80
81 // Compute the midpoint string that is between start and end.
akalin 2011/10/18 17:59:27 start -> |start| end -> |end|
82 std::string ComputeMidpoint(const std::string& start,
83 const std::string& end) {
84 size_t max_size = std::max(start.length(), end.length()) + 1;
85 std::string middle_string(max_size, kZeroDigit);
akalin 2011/10/18 17:59:27 middle_string -> midpoint
86
87 bool add_half = false;
88 for (size_t i = 0; i < max_size; ++i) {
89 int char_value = GetPositionValue(start, i);
90 char_value += GetPositionValue(end, i);
91
92 middle_string[i] += (char_value / 2);
93 if (add_half) {
94 AddHalf(i, middle_string);
95 }
96 add_half = (char_value % 2 == 1);
97 }
98
99 return middle_string;
100 }
101
102 // Create a StringOrdinal that is lexigraphically greater than start and
akalin 2011/10/18 17:59:27 start -> |start| end -> |end|
103 // lexigraphically less than end, ideally the StringOrdinal will be a
akalin 2011/10/18 17:59:27 "end, ideally" -> "end. The returned StringOrdina
104 // middle value between the two StringIndexs.
akalin 2011/10/18 17:59:27 StringOrdinals
105 StringOrdinal CreateStringOrdinalBetween(const StringOrdinal& start,
106 const StringOrdinal& end) {
107 CHECK(start.IsValid());
108 CHECK(end.IsValid());
akalin 2011/10/18 17:59:27 CHECK(start.LessThan(end))
109 std::string start_string = start.ToString();
akalin 2011/10/18 17:59:27 use const refs
110 std::string end_string = end.ToString();
akalin 2011/10/18 17:59:27 here, too
111 DCHECK_LT(start_string, end_string);
112
113 std::string middle_string = ComputeMidpoint(start_string, end_string);
akalin 2011/10/18 17:59:27 middle_string -> midpoint
114
115 middle_string = DropUnneededDigits(middle_string, start_string);
116
117 DCHECK_GT(middle_string, start_string);
118 DCHECK_LT(middle_string, end_string);
119
120 return StringOrdinal(middle_string);
121 }
122
123 // Returns true iff the input string matches the format [a-z]*[b-z].
124 bool IsValidStringOrdinal(const std::string& value) {
125 if (value.empty()) {
126 return false;
127 }
128
129 for (size_t i = 0; i < value.length(); ++i) {
130 if (value[i] < kZeroDigit || value[i] > kMaxDigit) {
131 return false;
132 }
133 }
134
135 return (value[value.length() - 1] != kZeroDigit);
136 }
137 } // namespace
138
139 StringOrdinal::StringOrdinal(const std::string& str)
140 : string_index_(str),
141 is_valid_(IsValidStringOrdinal(string_index_)) {
142
143 }
144
145 StringOrdinal::StringOrdinal() : is_valid_(false) {
146 }
147
148 bool StringOrdinal::IsValid() const {
149 return is_valid_;
150 }
151
152 bool StringOrdinal::LessThan(const StringOrdinal& other) const {
153 CHECK(IsValid());
154 CHECK(other.IsValid());
155 return string_index_ < other.string_index_;
156 }
157
158 bool StringOrdinal::Equal(const StringOrdinal& other) const {
159 CHECK(IsValid());
160 CHECK(other.IsValid());
161 return string_index_ == other.string_index_;
162 }
163
164 StringOrdinal StringOrdinal::CreateBetween(const StringOrdinal& other) const {
165 CHECK(IsValid());
166 CHECK(other.IsValid());
akalin 2011/10/18 17:59:27 CHECK(!Equal(other))
167
168 if (LessThan(other)) {
169 return CreateStringOrdinalBetween(*this, other);
170 } else {
171 return CreateStringOrdinalBetween(other, *this);
172 }
173 }
174
175 StringOrdinal StringOrdinal::CreateBefore() const {
176 CHECK(IsValid());
177 // Create the smallest, valid StringOrdinal to be the minimum boundary.
178 const size_t length = string_index_.length();
179 std::string start_string = std::string(length, kZeroDigit);
akalin 2011/10/18 17:59:27 start_string -> start (to be consistent with Creat
akalin 2011/10/18 17:59:27 don't do std::string foo = std::string(...), just
180 start_string[length - 1] = kMinDigit;
181 if (start_string == string_index_) {
182 start_string[length - 1] = kZeroDigit;
183 start_string += kMinDigit;
184 }
185
186 // Even though start_string is already a valid StringOrdinal that is less
akalin 2011/10/18 17:59:27 |start_string|
187 // than *this, we don't return it because we wouldn't have much space in
akalin 2011/10/18 17:59:27 |*this|
188 // front of it to insert potential future values.
189 return StringOrdinal(start_string).CreateBetween(*this);
akalin 2011/10/18 17:59:27 can actually just do: return CreateBetween(String
190 }
191
192 StringOrdinal StringOrdinal::CreateAfter() const {
193 CHECK(IsValid());
194 std::string end = std::string(string_index_.length(), kMaxDigit);
akalin 2011/10/18 17:59:27 std::string end(...)
195 if (end == string_index_) {
196 end += kMaxDigit;
197 }
198
199 // Even though end is already a valid StringOrdinal that is greater than
akalin 2011/10/18 17:59:27 |end|
200 // *this, we don't return it because we wouldn't have much space after
akalin 2011/10/18 17:59:27 |*this|
201 // it to insert potential future values.
202 return CreateBetween(StringOrdinal(end));
203 }
204
205 std::string StringOrdinal::ToString() const {
akalin 2011/10/18 17:59:27 CHECK(is_valid_)
206 return string_index_;
207 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698