1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_SYNC_MODEL_STRING_ORDINAL_H_
#define COMPONENTS_SYNC_MODEL_STRING_ORDINAL_H_
#include <cstddef>
#include <cstdint>
#include <string>
namespace mojo {
template <typename DataViewType, typename T>
struct StructTraits;
}
namespace syncer {
namespace mojom {
class StringOrdinalDataView;
}
// WARNING, DO NOT USE! Use UniquePosition instead.
//
//
// A StringOrdinal is an object that can be used for ordering. The
// StringOrdinal class has an unbounded dense strict total order, which
// mean for any StringOrdinals a, b and c:
//
// - a < b and b < c implies a < c (transitivity);
// - exactly one of a < b, b < a and a = b holds (trichotomy);
// - if a < b, there is a StringOrdinal x such that a < x < b (density);
// - there are Ordinals<T> x and y such that x < a < y (unboundedness).
//
// This means that when StringOrdinal is used for sorting a list, if any
// item changes its position in the list, only its StringOrdinal value
// has to change to represent the new order, and all the other values
// can stay the same.
//
// A StringOrdinal is internally represented as an array of bytes, so it
// can be serialized to and deserialized from disk.
//
// A StringOrdinal is valid iff its corresponding string has at least
// kMinLength characters, does not contain any characters less than
// kZeroDigit or greater than kMaxDigit, is not all zero digits, and
// does not have any unnecessary trailing zero digits.
//
// Since StringOrdinals contain only printable characters, it is safe
// to store as a string in a protobuf.
class StringOrdinal {
public:
// Functors for use with STL algorithms and containers.
class LessThanFn {
public:
LessThanFn();
bool operator()(const StringOrdinal& lhs, const StringOrdinal& rhs) const;
};
class EqualsFn {
public:
EqualsFn();
bool operator()(const StringOrdinal& lhs, const StringOrdinal& rhs) const;
};
// Creates an StringOrdinal from the given string of bytes. The StringOrdinal
// may be valid or invalid.
explicit StringOrdinal(std::string bytes);
// Creates an invalid StringOrdinal.
StringOrdinal();
// Creates a valid initial StringOrdinal. This is called to create the first
// element of StringOrdinal list (i.e. before we have any other values we can
// generate from).
static StringOrdinal CreateInitialOrdinal();
// Returns true iff this StringOrdinal is valid. This takes constant
// time.
bool IsValid() const;
// Returns true iff `*this` == `other` or `*this` and `other`
// are both invalid.
bool EqualsOrBothInvalid(const StringOrdinal& other) const;
// Returns a printable string representation of the StringOrdinal suitable
// for logging.
std::string ToDebugString() const;
// All remaining functions can only be called if IsValid() holds.
// It is an error to call them if IsValid() is false.
// Order-related functions.
// Returns true iff `*this` < `other`.
bool LessThan(const StringOrdinal& other) const;
// Returns true iff `*this` > `other`.
bool GreaterThan(const StringOrdinal& other) const;
// Returns true iff `*this` == `other` (i.e. `*this` < `other` and
// `other` < `*this` are both false).
bool Equals(const StringOrdinal& other) const;
// Given `*this` != `other`, returns a StringOrdinal x such that
// min(`*this`, `other`) < x < max(`*this`, `other`). It is an error
// to call this function when `*this` == `other`.
StringOrdinal CreateBetween(const StringOrdinal& other) const;
// Returns a StringOrdinal `x` such that `x` < `*this`.
StringOrdinal CreateBefore() const;
// Returns a StringOrdinal `x` such that `*this` < `x`.
StringOrdinal CreateAfter() const;
// Returns the string of bytes representing the StringOrdinal. It is
// guaranteed that an StringOrdinal constructed from the returned string
// will be valid.
std::string ToInternalValue() const;
// Use of copy constructor and default assignment for this class is allowed.
// Constants for StringOrdinal digits.
static const uint8_t kZeroDigit = 'a';
static const uint8_t kMaxDigit = 'z';
static const size_t kMinLength = 1;
static const uint8_t kOneDigit = kZeroDigit + 1;
static const uint8_t kMidDigit = kOneDigit + (kMaxDigit - kOneDigit) / 2;
static const unsigned int kMidDigitValue = kMidDigit - kZeroDigit;
static const unsigned int kMaxDigitValue = kMaxDigit - kZeroDigit;
static const unsigned int kRadix = kMaxDigitValue + 1;
static_assert(kOneDigit > kZeroDigit, "incorrect StringOrdinal one digit");
static_assert(kMidDigit > kOneDigit, "incorrect StringOrdinal mid digit");
static_assert(kMaxDigit > kMidDigit, "incorrect StringOrdinal max digit");
static_assert(kMinLength > 0, "incorrect StringOrdinal min length");
static_assert(kMidDigitValue > 1, "incorrect StringOrdinal mid digit");
static_assert(kMaxDigitValue > kMidDigitValue,
"incorrect StringOrdinal max digit");
static_assert(kRadix == kMaxDigitValue + 1, "incorrect StringOrdinal radix");
private:
friend struct mojo::StructTraits<syncer::mojom::StringOrdinalDataView,
StringOrdinal>;
// Returns true iff the given byte string satisfies the criteria for
// a valid StringOrdinal.
static bool IsValidOrdinalBytes(const std::string& bytes);
// Returns the length that bytes.substr(0, length) would be with
// trailing zero digits removed.
static size_t GetLengthWithoutTrailingZeroDigits(const std::string& bytes,
size_t length);
// Returns the digit at position i, padding with zero digits if
// required.
static uint8_t GetDigit(const std::string& bytes, size_t i);
// Returns the digit value at position i, padding with 0 if required.
static int GetDigitValue(const std::string& bytes, size_t i);
// Adds the given value to `bytes` at position i, carrying when
// necessary. Returns the left-most carry.
static int AddDigitValue(std::string* bytes, size_t i, int digit_value);
// Returns the proper length `bytes` should be resized to, i.e. the
// smallest length such that `bytes` is still greater than
// `lower_bound` and is still valid. `bytes` should be greater than
// `lower_bound`.
static size_t GetProperLength(const std::string& lower_bound,
const std::string& bytes);
// Compute the midpoint StringOrdinal byte string that is between `start`
// and `end`.
static std::string ComputeMidpoint(const std::string& start,
const std::string& end);
// Create a StringOrdinal that is lexicographically greater than `start` and
// lexicographically less than `end`. The returned StringOrdinal will be
// roughly between `start` and `end`.
static StringOrdinal CreateOrdinalBetween(const StringOrdinal& start,
const StringOrdinal& end);
// The internal byte string representation of the StringOrdinal. Never
// changes after construction except for assignment.
std::string bytes_;
// A cache of the result of IsValidOrdinalBytes(bytes_).
bool is_valid_;
};
bool operator==(const StringOrdinal& lhs, const StringOrdinal& rhs);
static_assert(StringOrdinal::kZeroDigit == 'a',
"StringOrdinal has incorrect zero digit");
static_assert(StringOrdinal::kOneDigit == 'b',
"StringOrdinal has incorrect one digit");
static_assert(StringOrdinal::kMidDigit == 'n',
"StringOrdinal has incorrect mid digit");
static_assert(StringOrdinal::kMaxDigit == 'z',
"StringOrdinal has incorrect max digit");
static_assert(StringOrdinal::kMidDigitValue == 13,
"StringOrdinal has incorrect mid digit value");
static_assert(StringOrdinal::kMaxDigitValue == 25,
"StringOrdinal has incorrect max digit value");
static_assert(StringOrdinal::kRadix == 26, "StringOrdinal has incorrect radix");
} // namespace syncer
#endif // COMPONENTS_SYNC_MODEL_STRING_ORDINAL_H_
|