2 * Copyright 2015 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <folly/Format.h>
22 extern const FormatArg::Align formatAlignTable[];
23 extern const FormatArg::Sign formatSignTable[];
27 using namespace folly::detail;
29 void FormatArg::initSlow() {
30 auto b = fullArgString.begin();
31 auto end = fullArgString.end();
34 auto p = static_cast<const char*>(memchr(b, ':', end - b));
36 key_ = StringPiece(b, end);
39 key_ = StringPiece(b, p);
43 if (++p == end) return;
45 // fill/align, or just align
48 (a = formatAlignTable[static_cast<unsigned char>(p[1])]) !=
54 } else if ((a = formatAlignTable[static_cast<unsigned char>(*p)]) !=
57 if (++p == end) return;
61 unsigned char uSign = static_cast<unsigned char>(*p);
62 if ((s = formatSignTable[uSign]) != Sign::INVALID) {
64 if (++p == end) return;
69 if (++p == end) return;
73 enforce(align == Align::DEFAULT, "alignment specified twice");
75 align = Align::PAD_AFTER_SIGN;
76 if (++p == end) return;
79 if (*p >= '0' && *p <= '9') {
83 } while (p != end && *p >= '0' && *p <= '9');
84 width = to<int>(StringPiece(b, p));
90 thousandsSeparator = true;
91 if (++p == end) return;
96 while (p != end && *p >= '0' && *p <= '9') {
100 precision = to<int>(StringPiece(b, p));
101 if (p != end && *p == '.') {
109 if (p == end) return;
113 if (++p == end) return;
116 error("extra characters in format string");
119 void FormatArg::validate(Type type) const {
120 enforce(keyEmpty(), "index not allowed");
123 enforce(precision == kDefaultPrecision,
124 "precision not allowed on integers");
128 "base prefix ('#') specifier only allowed on integers");
129 enforce(!thousandsSeparator,
130 "thousands separator (',') only allowed on integers");
133 enforce(align != Align::PAD_AFTER_SIGN,
134 "'='alignment only allowed on numbers");
135 enforce(sign == Sign::DEFAULT,
136 "sign specifier only allowed on numbers");
138 "base prefix ('#') specifier only allowed on integers");
139 enforce(!thousandsSeparator,
140 "thousands separator (',') only allowed on integers");
146 void insertThousandsGroupingUnsafe(char* start_buffer, char** end_buffer) {
147 uint32_t remaining_digits = *end_buffer - start_buffer;
148 uint32_t separator_size = (remaining_digits - 1) / 3;
149 uint32_t result_size = remaining_digits + separator_size;
150 *end_buffer = *end_buffer + separator_size;
152 // get the end of the new string with the separators
153 uint32_t buffer_write_index = result_size - 1;
154 uint32_t buffer_read_index = remaining_digits - 1;
155 start_buffer[buffer_write_index + 1] = 0;
159 uint32_t next_group_size = 3;
162 uint32_t current_group_size = std::max<uint32_t>(1,
163 std::min<uint32_t>(remaining_digits, next_group_size));
165 // write out the current group's digits to the buffer index
166 for (uint32_t i = 0; i < current_group_size; i++) {
167 start_buffer[buffer_write_index--] = start_buffer[buffer_read_index--];
170 // if not finished, write the separator before the next group
171 if (buffer_write_index < buffer_write_index + 1) {
172 start_buffer[buffer_write_index--] = ',';
177 remaining_digits -= current_group_size;