aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/core/src/firebase/firestore/util/string_format.h
blob: 3d7a1dc350793812ea490183a1182f2e15f8b4be (plain)
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
/*
 * Copyright 2018 Google
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_FORMAT_H_
#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_FORMAT_H_

#include <initializer_list>
#include <string>
#include <utility>

#include "absl/base/attributes.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"

namespace firebase {
namespace firestore {
namespace util {

namespace internal {

std::string StringFormatPieces(const char* format,
                               std::initializer_list<absl::string_view> pieces);

/**
 * Explicit ranking for formatting choices. Only useful as an implementation
 * detail of `FormatArg`.
 */
template <int I>
struct FormatChoice : FormatChoice<I + 1> {};

template <>
struct FormatChoice<4> {};

}  // namespace internal

/**
 * Acts as the main value parameter to StringFormat and related functions.
 *
 * Chooses a conversion to a text form in this order:
 *   * If the value is exactly of `bool` type (without implicit conversions)
 *     the text will the "true" or "false".
 *   * If the value is of type `const char*`, the text will be the value
 *     interpreted as a C string. To show the address of a single char or to
 *     show the `const char*` as an address, cast to `void*`.
 *   * If the value is any other pointer type, the text will be the hexidecimal
 *     formatting of the value as an unsigned integer.
 *   * Otherwise the value is interpreted as anything absl::AlphaNum accepts.
 */
class FormatArg : public absl::AlphaNum {
 public:
  template <typename T>
  FormatArg(T&& value)  // NOLINT(runtime/explicit)
      : FormatArg{std::forward<T>(value), internal::FormatChoice<0>{}} {
  }

 private:
  /**
   * Creates a FormatArg from a boolean value, representing the string
   * "true" or "false".
   *
   * This overload only applies if the type of the argument is exactly `bool`.
   * No implicit conversions to bool are accepted.
   */
  template <typename T,
            typename = typename std::enable_if<std::is_same<bool, T>{}>::type>
  FormatArg(T bool_value, internal::FormatChoice<0>)
      : AlphaNum{bool_value ? "true" : "false"} {
  }

  /**
   * Creates a FormatArg from a character string literal. This is
   * handled specially to avoid ambiguity with generic pointers, which are
   * handled differently.
   */
  FormatArg(std::nullptr_t, internal::FormatChoice<1>) : AlphaNum{"null"} {
  }

  /**
   * Creates a FormatArg from a character string literal. This is
   * handled specially to avoid ambiguity with generic pointers, which are
   * handled differently.
   */
  FormatArg(const char* string_value, internal::FormatChoice<2>)
      : AlphaNum{string_value == nullptr ? "null" : string_value} {
  }

  /**
   * Creates a FormatArg from an arbitrary pointer, represented as a
   * hexidecimal integer literal.
   */
  template <typename T>
  FormatArg(T* pointer_value, internal::FormatChoice<3>)
      : AlphaNum{absl::Hex{reinterpret_cast<uintptr_t>(pointer_value)}} {
  }

  /**
   * As a final fallback, creates a FormatArg from any type of value that
   * absl::AlphaNum accepts.
   */
  template <typename T>
  FormatArg(T&& value, internal::FormatChoice<4>)
      : AlphaNum{std::forward<T>(value)} {
  }
};

/**
 * Formats a string using a simplified printf-like formatting mechanism that
 * does not rely on C varargs.
 *
 * The following format specifiers are recognized:
 *   * "%%" - A literal "%"
 *   * "%s" - The next parameter is copied through
 *
 * Note:
 *   * If you pass fewer arguments than the format requires, StringFormat will
 *     insert "<missing>".
 *   * If you pass more arguments than the format requires, any excess arguments
 *     are ignored.
 *   * If you use an invalid format specifier, StringFormat will insert
 *     <invalid>.
 */
template <typename... FA>
std::string StringFormat(const char* format, const FA&... args) {
  return internal::StringFormatPieces(
      format, {static_cast<const FormatArg&>(args).Piece()...});
}

inline std::string StringFormat() {
  return {};
}

}  // namespace util
}  // namespace firestore
}  // namespace firebase

#endif  // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_UTIL_STRING_FORMAT_H_