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

Side by Side Diff: mojo/edk/util/string_number_conversions.cc

Issue 1492623002: EDK: Add functions for converting between strings and numbers. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years 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 2015 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 "mojo/edk/util/string_number_conversions.h"
6
7 #include <assert.h>
8 #include <stdint.h>
9
10 #include <limits>
11 #include <type_traits>
12
13 namespace mojo {
14 namespace util {
15 namespace {
16
17 // Helper for |StringToNumberWithError()|. Note that this may modify |*number|
18 // even on failure.
19 template <typename NumberType>
20 bool StringToPositiveNumberWithError(const char* s,
21 size_t length,
22 NumberType* number) {
23 constexpr NumberType kBase = static_cast<NumberType>(10);
24 constexpr NumberType kMaxAllowed = std::numeric_limits<NumberType>::max();
25
26 assert(s);
27 assert(length > 0u);
28 assert(number);
29
30 *number = 0;
31 for (size_t i = 0; i < length; i++) {
32 if (s[i] < '0' || s[i] > '9')
33 return false;
34 NumberType new_digit = static_cast<NumberType>(s[i] - '0');
35 // This is really a check of "*number * kBase + new_digit > kMaxAllowed":
36 if (*number > kMaxAllowed / kBase ||
37 (*number == kMaxAllowed / kBase && new_digit > kMaxAllowed % kBase))
38 return false;
39 *number = *number * kBase + new_digit;
40 }
41
42 return true;
43 }
44
45 // Helper for |StringToNumberWithError()|. Note that this may modify |*number|
46 // even on failure.
47 template <typename NumberType>
48 bool StringToNegativeNumberWithError(const char* s,
49 size_t length,
50 NumberType* number) {
51 constexpr NumberType kBase = static_cast<NumberType>(10);
52 constexpr NumberType kMinAllowed = std::numeric_limits<NumberType>::min();
53
54 assert(s);
55 assert(length > 0u);
56 assert(number);
57
58 *number = 0;
59 for (size_t i = 0; i < length; i++) {
60 if (s[i] < '0' || s[i] > '9')
61 return false;
62 NumberType new_digit = static_cast<NumberType>(s[i] - '0');
63 // This is really a check of "*number * kBase - new_digit > kMinAllowed":
64 if (*number < kMinAllowed / kBase ||
65 (kMinAllowed / kBase == *number && new_digit > -(kMinAllowed % kBase)))
66 return false;
67 *number = *number * kBase - new_digit;
68 }
69
70 return true;
71 }
72
73 } // namespace
74
75 template <typename NumberType>
76 std::string NumberToString(NumberType number) {
77 // Special-case zero (since nonzero cases naturally produce digits).
78 if (!number)
79 return std::string("0");
80
81 using UnsignedNumberType = typename std::make_unsigned<NumberType>::type;
82 // Note: The negative case is safe, since the standard requires that, e.g.,
83 // for n a negative int32_t, |static_cast<uint32_t>(n)| = 2^32 - n and for a
84 // uint32_t m, |-m| = 2^32 - m.
85 bool number_is_negative = (number < static_cast<NumberType>(0));
86 UnsignedNumberType abs_number = number_is_negative
87 ? -static_cast<UnsignedNumberType>(number)
88 : static_cast<UnsignedNumberType>(number);
89
90 char buf[50]; // Big enough to hold the result from even a 128-bit number.
91 size_t i = sizeof(buf);
92 while (abs_number) {
93 i--;
94 buf[i] = '0' + abs_number % 10u;
95 abs_number /= 10u;
96 }
97 if (number_is_negative) {
98 i--;
99 buf[i] = '-';
100 }
101
102 return std::string(buf + i, buf + sizeof(buf));
103 }
104
105 template <typename NumberType>
106 bool StringToNumberWithError(const std::string& string, NumberType* number) {
107 assert(number);
108
109 if (string.empty())
110 return false;
111
112 const char* s = &string[0];
113 size_t length = string.length();
114 NumberType result = 0;
115 if (std::is_signed<NumberType>::value && string[0] == '-') {
116 if (length < 2)
117 return false;
118 if (!StringToNegativeNumberWithError<NumberType>(s + 1, length - 1u,
119 &result))
120 return false;
121 } else {
122 if (!StringToPositiveNumberWithError<NumberType>(s, length, &result))
123 return false;
124 }
125
126 *number = result;
127 return true;
128 }
129
130 // Explicit instantiatiations for (u)intN_t; count on (unsigned) int being one
131 // of these:
132 template std::string NumberToString<int8_t>(int8_t number);
133 template std::string NumberToString<uint8_t>(uint8_t number);
134 template std::string NumberToString<int16_t>(int16_t number);
135 template std::string NumberToString<uint16_t>(uint16_t number);
136 template std::string NumberToString<int32_t>(int32_t number);
137 template std::string NumberToString<uint32_t>(uint32_t number);
138 template std::string NumberToString<int64_t>(int64_t number);
139 template std::string NumberToString<uint64_t>(uint64_t number);
140 template bool StringToNumberWithError<int8_t>(const std::string& string,
141 int8_t* number);
142 template bool StringToNumberWithError<uint8_t>(const std::string& string,
143 uint8_t* number);
144 template bool StringToNumberWithError<int16_t>(const std::string& string,
145 int16_t* number);
146 template bool StringToNumberWithError<uint16_t>(const std::string& string,
147 uint16_t* number);
148 template bool StringToNumberWithError<int32_t>(const std::string& string,
149 int32_t* number);
150 template bool StringToNumberWithError<uint32_t>(const std::string& string,
151 uint32_t* number);
152 template bool StringToNumberWithError<int64_t>(const std::string& string,
153 int64_t* number);
154 template bool StringToNumberWithError<uint64_t>(const std::string& string,
155 uint64_t* number);
156
157 } // namespace util
158 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698