2 * Copyright 2014 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 #ifndef FOLLY_FORMATARG_H_
18 #define FOLLY_FORMATARG_H_
21 #include "folly/Conv.h"
22 #include "folly/Likely.h"
23 #include "folly/Portability.h"
24 #include "folly/Range.h"
29 * Parsed format argument.
33 * Parse a format argument from a string. Keeps a reference to the
34 * passed-in string -- does not copy the given characters.
36 explicit FormatArg(StringPiece sp)
39 align(Align::DEFAULT),
42 thousandsSeparator(false),
44 precision(kDefaultPrecision),
45 presentation(kDefaultPresentation),
46 nextKeyMode_(NextKeyMode::NONE) {
58 * Validate the argument for the given type; throws on error.
60 void validate(Type type) const;
63 * Throw an exception if the first argument is false. The exception
64 * message will contain the argument string as well as any passed-in
65 * arguments to enforce, formatted using folly::to<std::string>.
67 template <typename... Args>
68 void enforce(bool v, Args&&... args) const {
70 error(std::forward<Args>(args)...);
74 template <typename... Args>
75 std::string errorStr(Args&&... args) const;
76 template <typename... Args>
77 void error(Args&&... args) const FOLLY_NORETURN;
80 * Full argument string, as passed in to the constructor.
82 StringPiece fullArgString;
87 static constexpr char kDefaultFill = '\0';
93 enum class Align : uint8_t {
106 enum class Sign : uint8_t {
116 * Output base prefix (0 for octal, 0x for hex)
121 * Output thousands separator (comma)
123 bool thousandsSeparator;
128 static constexpr int kDefaultWidth = -1;
134 static constexpr int kDefaultPrecision = -1;
140 static constexpr char kDefaultPresentation = '\0';
144 * Split a key component from "key", which must be non-empty (an exception
145 * is thrown otherwise).
147 template <bool emptyOk=false>
148 StringPiece splitKey();
151 * Is the entire key empty?
153 bool keyEmpty() const {
154 return nextKeyMode_ == NextKeyMode::NONE && key_.empty();
158 * Split an key component from "key", which must be non-empty and a valid
159 * integer (an exception is thrown otherwise).
163 void setNextIntKey(int val) {
164 assert(nextKeyMode_ == NextKeyMode::NONE);
165 nextKeyMode_ = NextKeyMode::INT;
169 void setNextKey(StringPiece val) {
170 assert(nextKeyMode_ == NextKeyMode::NONE);
171 nextKeyMode_ = NextKeyMode::STRING;
177 template <bool emptyOk>
178 StringPiece doSplitKey();
182 StringPiece nextKey_;
183 enum class NextKeyMode {
188 NextKeyMode nextKeyMode_;
191 template <typename... Args>
192 inline std::string FormatArg::errorStr(Args&&... args) const {
193 return to<std::string>(
194 "invalid format argument {", fullArgString, "}: ",
195 std::forward<Args>(args)...);
198 template <typename... Args>
199 inline void FormatArg::error(Args&&... args) const {
200 throw std::invalid_argument(errorStr(std::forward<Args>(args)...));
203 template <bool emptyOk>
204 inline StringPiece FormatArg::splitKey() {
205 enforce(nextKeyMode_ != NextKeyMode::INT, "integer key expected");
206 return doSplitKey<emptyOk>();
209 template <bool emptyOk>
210 inline StringPiece FormatArg::doSplitKey() {
211 if (nextKeyMode_ == NextKeyMode::STRING) {
212 nextKeyMode_ = NextKeyMode::NONE;
213 if (!emptyOk) { // static
214 enforce(!nextKey_.empty(), "non-empty key required");
220 if (!emptyOk) { // static
221 error("non-empty key required");
223 return StringPiece();
226 const char* b = key_.begin();
227 const char* e = key_.end();
231 p = static_cast<const char*>(memchr(b, '[', e - b));
232 enforce(p, "unmatched ']'");
234 p = static_cast<const char*>(memchr(b, '.', e - b));
237 key_.assign(p + 1, e);
242 if (!emptyOk) { // static
243 enforce(b != p, "non-empty key required");
245 return StringPiece(b, p);
248 inline int FormatArg::splitIntKey() {
249 if (nextKeyMode_ == NextKeyMode::INT) {
250 nextKeyMode_ = NextKeyMode::NONE;
254 return to<int>(doSplitKey<true>());
255 } catch (const std::out_of_range& e) {
256 error("integer key required");
257 return 0; // unreached
263 #endif /* FOLLY_FORMATARG_H_ */