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

Side by Side Diff: components/enhanced_bookmarks/item_position.cc

Issue 510543002: Introduce ItemPosition class for enhanced bookmarks. (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Rename to ItemPosition Created 6 years, 3 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
OLDNEW
(Empty)
1 // Copyright 2014 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 "components/enhanced_bookmarks/item_position.h"
6
7 #include "base/logging.h"
8
9 namespace {
10 const unsigned kPositionBase = 64;
11 const char kPositionAlphabet[] =
12 ".0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
13 } // namespace
14
15 namespace enhanced_bookmarks {
16
17 ItemPosition::ItemPosition() {
18 }
19
20 ItemPosition::ItemPosition(const PositionVector& position)
21 : position_(position) {
22 }
23
24 ItemPosition::~ItemPosition() {
25 }
26
27 // static
28 ItemPosition ItemPosition::CreateInitialPosition() {
29 PositionVector position(1, kPositionBase / 2);
30 return ItemPosition(position);
31 }
32
33 // static
34 ItemPosition ItemPosition::CreateBefore(const ItemPosition& other) {
35 DCHECK(other.IsValid());
36 return ItemPosition(CreateBeforeImpl(other.position_, 0));
37 }
38
39 // static
40 ItemPosition::PositionVector ItemPosition::CreateBeforeImpl(
41 const PositionVector& other,
42 size_t from_index) {
43 DCHECK_LT(from_index, other.size());
44 PositionVector before(other.begin() + from_index, other.end());
45
46 // Decrement the last character instead of going half-way to 0 in order to
47 // make sure chaining CreateBefore calls result in logarithmic rather than
48 // linear length growth.
49 before[before.size() - 1] /= 2;
50 if (before[before.size() - 1] != 0) {
51 // If the last digit didn't change to 0, we're done!
52 return before;
53 }
54
55 // Reset trailing zeros, then decrement the last non-zero digit.
56 int index = before.size() - 1;
57 while (index >= 0 && before[index] == 0) {
58 before[index--] = kPositionBase / 2;
59 }
60
61 // Negative index means all digits were zeros. Put that many zeros to the
62 // front of the string to get one that is comes before the input given.
63 // This will cause the returned string to be twice as long as the input one,
64 // (and about twice as long as needed for a valid return value), however that
65 // means this function can be called many times more before we need to
66 // increase the string size again. Increasing it with the minimum length
67 // would result in a linear string size growth.
68 if (index < 0) {
69 before.insert(before.begin(), before.size(), 0);
70 } else {
71 before[index] /= 2;
72 }
73 return before;
74 }
75
76 // static
77 ItemPosition ItemPosition::CreateAfter(const ItemPosition& other) {
78 DCHECK(other.IsValid());
79 return ItemPosition(CreateAfterImpl(other.position_, 0));
80 }
81
82 // static
83 ItemPosition::PositionVector ItemPosition::CreateAfterImpl(
84 const PositionVector& other,
85 size_t from_index) {
86 DCHECK_LE(from_index, other.size());
87 if (from_index == other.size()) {
88 return PositionVector(1, kPositionBase / 2);
89 }
90
91 PositionVector after(other.begin() + from_index, other.end());
92
93 // Instead of splitting the position with infinity, increment the last digit
94 // possible, and reset all digits after. This makes sure chaining createAfter
95 // will result in a logarithmic rather than linear length growth.
96 size_t index = after.size() - 1;
97 do {
98 after[index] += (kPositionBase - after[index] + 1) / 2;
99 if (after[index] != kPositionBase)
100 return after;
101 after[index] = kPositionBase / 2;
102 } while (index-- > 0);
103
104 // All digits must have been at the maximal value already, so the string
105 // length has to increase. Double it's size to ensure CreateAfter can be
106 // called exponentially more times every time this needs to happen.
107 after.insert(after.begin(), after.size(), kPositionBase - 1);
108
109 return after;
110 }
111
112 // static
113 ItemPosition ItemPosition::CreateBetween(const ItemPosition& before,
114 const ItemPosition& after) {
115 DCHECK(before.IsValid() && after.IsValid());
116 return ItemPosition(CreateBetweenImpl(before.position_, after.position_));
117 }
118
119 // static
120 ItemPosition::PositionVector ItemPosition::CreateBetweenImpl(
121 const PositionVector& before,
122 const PositionVector& after) {
123 DCHECK(before < after);
124
125 PositionVector between;
126 for (size_t i = 0; i < before.size(); i++) {
127 if (before[i] == after[i]) {
128 // Add the common prefix to the return value.
129 between.push_back(before[i]);
130 continue;
131 }
132 if (before[i] < after[i] - 1) {
133 // Split the difference between the two characters.
134 between.push_back((before[i] + after[i]) / 2);
135 return between;
136 }
137 // The difference between before[i] and after[i] is one character. A valid
138 // return is that character, plus something that comes after the remaining
139 // characters of before.
140 between.push_back(before[i]);
141 PositionVector suffix = CreateAfterImpl(before, i + 1);
142 between.insert(between.end(), suffix.begin(), suffix.end());
143 return between;
144 }
145
146 // |before| must be a prefix of |after|, so return that prefix followed by
147 // something that comes before the remaining digits of |after|.
148 PositionVector suffix = CreateBeforeImpl(after, before.size());
149 between.insert(between.end(), suffix.begin(), suffix.end());
150 return between;
151 }
152
153 std::string ItemPosition::ToString() const {
154 DCHECK_GT(arraysize(kPositionAlphabet), kPositionBase);
155
156 std::string str;
157 str.reserve(position_.size());
158 for (size_t i = 0; i < position_.size(); i++) {
159 unsigned char val = position_[i];
160 CHECK_LT(val, kPositionBase);
161 str.push_back(kPositionAlphabet[position_[i]]);
162 }
163 return str;
164 }
165
166 bool ItemPosition::IsValid() const {
167 return !position_.empty() && position_[position_.size() - 1] != 0;
168 }
169
170 bool ItemPosition::Equals(const ItemPosition& other) const {
171 return position_ == other.position_;
172 }
173
174 bool ItemPosition::LessThan(const ItemPosition& other) const {
175 return position_ < other.position_;
176 }
177
178 } // namespace enhanced_bookmarks
OLDNEW
« no previous file with comments | « components/enhanced_bookmarks/item_position.h ('k') | components/enhanced_bookmarks/item_position_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698