Timestamping callback interface in folly::AsyncSocket
[folly.git] / folly / FormatArg.h
index d48aad7a05b277f5b3c1866d7399a49f71b83e8a..48311e3d4e7cd18a77aeacb553dd0d4c98fc7ee9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * limitations under the License.
  */
 
-#ifndef FOLLY_FORMATARG_H_
-#define FOLLY_FORMATARG_H_
+#pragma once
 
 #include <stdexcept>
-#include "folly/Conv.h"
-#include "folly/Likely.h"
-#include "folly/Portability.h"
-#include "folly/Range.h"
+#include <folly/Conv.h>
+#include <folly/Likely.h>
+#include <folly/Portability.h>
+#include <folly/Range.h>
 
 namespace folly {
 
+class BadFormatArg : public std::invalid_argument {
+ public:
+  explicit BadFormatArg(const std::string& msg)
+    : std::invalid_argument(msg) {}
+};
+
 /**
  * Parsed format argument.
  */
@@ -40,7 +45,9 @@ struct FormatArg {
       sign(Sign::DEFAULT),
       basePrefix(false),
       thousandsSeparator(false),
+      trailingDot(false),
       width(kDefaultWidth),
+      widthIndex(kNoIndex),
       precision(kDefaultPrecision),
       presentation(kDefaultPresentation),
       nextKeyMode_(NextKeyMode::NONE) {
@@ -74,7 +81,7 @@ struct FormatArg {
   template <typename... Args>
   std::string errorStr(Args&&... args) const;
   template <typename... Args>
-  void error(Args&&... args) const FOLLY_NORETURN;
+  [[noreturn]] void error(Args&&... args) const;
 
   /**
    * Full argument string, as passed in to the constructor.
@@ -123,10 +130,18 @@ struct FormatArg {
   bool thousandsSeparator;
 
   /**
-   * Field width
+   * Force a trailing decimal on doubles which could be rendered as ints
+   */
+  bool trailingDot;
+
+  /**
+   * Field width and optional argument index
    */
   static constexpr int kDefaultWidth = -1;
+  static constexpr int kDynamicWidth = -2;
+  static constexpr int kNoIndex = -1;
   int width;
+  int widthIndex;
 
   /**
    * Precision
@@ -196,13 +211,13 @@ inline std::string FormatArg::errorStr(Args&&... args) const {
 }
 
 template <typename... Args>
-inline void FormatArg::error(Args&&... args) const {
-  throw std::invalid_argument(errorStr(std::forward<Args>(args)...));
+[[noreturn]] inline void FormatArg::error(Args&&... args) const {
+  throw BadFormatArg(errorStr(std::forward<Args>(args)...));
 }
 
 template <bool emptyOk>
 inline StringPiece FormatArg::splitKey() {
-  CHECK(nextKeyMode_ != NextKeyMode::INT) << errorStr("integer key expected");
+  enforce(nextKeyMode_ != NextKeyMode::INT, "integer key expected");
   return doSplitKey<emptyOk>();
 }
 
@@ -210,12 +225,16 @@ template <bool emptyOk>
 inline StringPiece FormatArg::doSplitKey() {
   if (nextKeyMode_ == NextKeyMode::STRING) {
     nextKeyMode_ = NextKeyMode::NONE;
-    CHECK(emptyOk || !nextKey_.empty()) << errorStr("non-empty key required");
+    if (!emptyOk) {  // static
+      enforce(!nextKey_.empty(), "non-empty key required");
+    }
     return nextKey_;
   }
 
   if (key_.empty()) {
-    CHECK(emptyOk) << errorStr("non-empty key required");
+    if (!emptyOk) {  // static
+      error("non-empty key required");
+    }
     return StringPiece();
   }
 
@@ -224,10 +243,10 @@ inline StringPiece FormatArg::doSplitKey() {
   const char* p;
   if (e[-1] == ']') {
     --e;
-    p = static_cast<const char*>(memchr(b, '[', e - b));
-    CHECK(p) << errorStr("unmatched ']'");
+    p = static_cast<const char*>(memchr(b, '[', size_t(e - b)));
+    enforce(p != nullptr, "unmatched ']'");
   } else {
-    p = static_cast<const char*>(memchr(b, '.', e - b));
+    p = static_cast<const char*>(memchr(b, '.', size_t(e - b)));
   }
   if (p) {
     key_.assign(p + 1, e);
@@ -235,8 +254,9 @@ inline StringPiece FormatArg::doSplitKey() {
     p = e;
     key_.clear();
   }
-  CHECK(emptyOk || b != p) << errorStr("non-empty key required");
-
+  if (!emptyOk) {  // static
+    enforce(b != p, "non-empty key required");
+  }
   return StringPiece(b, p);
 }
 
@@ -247,13 +267,10 @@ inline int FormatArg::splitIntKey() {
   }
   try {
     return to<int>(doSplitKey<true>());
-  } catch (const std::out_of_range& e) {
-    LOG(FATAL) << errorStr("integer key required");
+  } catch (const std::out_of_range&) {
+    error("integer key required");
     return 0;  // unreached
   }
 }
 
 }  // namespace folly
-
-#endif /* FOLLY_FORMATARG_H_ */
-