folly/folly/Format-inl.h

/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * 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 FOLLY_FORMAT_H_
#error This file may only be included from Format.h.
#endif

#include <array>
#include <cinttypes>
#include <deque>
#include <map>
#include <unordered_map>
#include <vector>

#include <folly/Exception.h>
#include <folly/FormatTraits.h>
#include <folly/MapUtil.h>
#include <folly/Portability.h>
#include <folly/Traits.h>
#include <folly/lang/Exception.h>
#include <folly/lang/ToAscii.h>
#include <folly/portability/Windows.h>

// Ignore -Wformat-nonliteral and -Wconversion warnings within this file
FOLLY_PUSH_WARNING
FOLLY_GNU_DISABLE_WARNING()
FOLLY_GNU_DISABLE_WARNING()

namespace folly {

namespace detail {

// Updates the end of the buffer after the comma separators have been added.
void insertThousandsGroupingUnsafe(char* start_buffer, char** end_buffer);

extern const std::array<std::array<char, 2>, 256> formatHexUpper;
extern const std::array<std::array<char, 2>, 256> formatHexLower;
extern const std::array<std::array<char, 3>, 512> formatOctal;
extern const std::array<std::array<char, 8>, 256> formatBinary;

const size_t kMaxHexLength =;
const size_t kMaxOctalLength =;
const size_t kMaxBinaryLength =;

/**
 * Convert an unsigned to hex, using repr (which maps from each possible
 * 2-hex-bytes value to the 2-character representation).
 *
 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
 * the supplied buffer and returns the offset of the beginning of the string
 * from the start of the buffer.  The formatted string will be in range
 * [buf+begin, buf+bufLen).
 */
template <class Uint>
size_t uintToHex(
    char* buffer,
    size_t bufLen,
    Uint v,
    std::array<std::array<char, 2>, 256> const& repr) {}

/**
 * Convert an unsigned to hex, using lower-case letters for the digits
 * above 9.  See the comments for uintToHex.
 */
template <class Uint>
inline size_t uintToHexLower(char* buffer, size_t bufLen, Uint v) {}

/**
 * Convert an unsigned to hex, using upper-case letters for the digits
 * above 9.  See the comments for uintToHex.
 */
template <class Uint>
inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) {}

/**
 * Convert an unsigned to octal.
 *
 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
 * the supplied buffer and returns the offset of the beginning of the string
 * from the start of the buffer.  The formatted string will be in range
 * [buf+begin, buf+bufLen).
 */
template <class Uint>
size_t uintToOctal(char* buffer, size_t bufLen, Uint v) {}

/**
 * Convert an unsigned to binary.
 *
 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
 * the supplied buffer and returns the offset of the beginning of the string
 * from the start of the buffer.  The formatted string will be in range
 * [buf+begin, buf+bufLen).
 */
template <class Uint>
size_t uintToBinary(char* buffer, size_t bufLen, Uint v) {}

template <bool containerMode, bool RecordUsedArg, class Output>
void baseFormatterCallImpl(
    Output& out,
    size_t nargs,
    const int widths[],
    std::bool_constant<RecordUsedArg>(used)(const BaseFormatterBase&, size_t),
    BaseFormatterBase::DoFormatFn<Output>* const funs[],
    const BaseFormatterBase& base) {}

} // namespace detail

template <class Derived, bool containerMode, size_t... I, class... Args>
template <class Output>
void BaseFormatterImpl<
    Derived,
    containerMode,
    std::index_sequence<I...>,
    Args...>::operator()(Output& out) const {}

namespace format_value {

template <class FormatCallback>
void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {}

template <class FormatCallback>
void formatNumber(
    StringPiece val, int prefixLen, FormatArg& arg, FormatCallback& cb) {}

template <typename FormatCallback>
struct FormatFormatterFn {};

template <class FormatCallback, bool containerMode, class... Args>
void formatFormatter(
    const Formatter<containerMode, Args...>& formatter,
    FormatArg& arg,
    FormatCallback& cb) {}

} // namespace format_value

// Definitions for default FormatValue classes

// Integral types (except bool)
FormatValue<T, typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value>::type>;

// Bool
template <>
class FormatValue<bool> {};

// double
template <>
class FormatValue<double> {};

// float (defer to double)
template <>
class FormatValue<float> {};

// String-y types (implicitly convertible to StringPiece, except char*)
FormatValue<T, typename std::enable_if<(!std::is_pointer<T>::value || !std::is_same<char, typename std::decay<typename std::remove_pointer<T>::type>::type>::value) && std::is_convertible<T, StringPiece>::value>::type>;

// Null
template <>
class FormatValue<std::nullptr_t> {};

// Partial specialization of FormatValue for char*
FormatValue<T *, typename std::enable_if<std::is_same<char, typename std::decay<T>::type>::value>::type>;

// Partial specialization of FormatValue for void*
FormatValue<T *, typename std::enable_if<std::is_same<void, typename std::decay<T>::type>::value>::type>;

template <class T, class = void>
class TryFormatValue {};

TryFormatValue<T, typename std::enable_if<0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>;

// Partial specialization of FormatValue for other pointers
FormatValue<T *, typename std::enable_if<!std::is_same<char, typename std::decay<T>::type>::value && !std::is_same<void, typename std::decay<T>::type>::value>::type>;

namespace detail {

// std::array
IndexableTraits<std::array<T, N>>;

// std::vector
IndexableTraits<std::vector<T, A>>;

// std::deque
IndexableTraits<std::deque<T, A>>;

// std::map with integral keys
IndexableTraits<std::map<K, T, C, A>, typename std::enable_if<std::is_integral<K>::value>::type>;

// std::unordered_map with integral keys
IndexableTraits<std::unordered_map<K, T, H, E, A>, typename std::enable_if<std::is_integral<K>::value>::type>;

} // namespace detail

// Partial specialization of FormatValue for integer-indexable containers
FormatValue<T, typename detail::IndexableTraits<T>::enabled>;

FormatValue<detail::DefaultValueWrapper<Container, Value>, typename detail::IndexableTraits<Container>::enabled>;

namespace detail {

// Define enabled, key_type, convert from StringPiece to the key types
// that we support
template <class T>
struct KeyFromStringPiece;

// std::string
template <>
struct KeyFromStringPiece<std::string> : public FormatTraitsBase {};

// fbstring
template <>
struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {};

// StringPiece
template <>
struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {};

// Base class for associative types keyed by strings
template <class T>
struct KeyableTraitsAssoc : public FormatTraitsBase {};

// Define enabled, key_type, value_type, at() for supported string-keyed
// types
template <class T, class Enabled = void>
struct KeyableTraits;

// std::map with string key
KeyableTraits<std::map<K, T, C, A>, typename KeyFromStringPiece<K>::enabled>;

// std::unordered_map with string key
KeyableTraits<std::unordered_map<K, T, H, E, A>, typename KeyFromStringPiece<K>::enabled>;

} // namespace detail

// Partial specialization of FormatValue for string-keyed containers
FormatValue<T, typename detail::KeyableTraits<T>::enabled>;

FormatValue<detail::DefaultValueWrapper<Container, Value>, typename detail::KeyableTraits<Container>::enabled>;

// Partial specialization of FormatValue for pairs
FormatValue<std::pair<A, B>>;

// Partial specialization of FormatValue for tuples
FormatValue<std::tuple<Args...>>;

// Partial specialization of FormatValue for nested Formatters
FormatValue<F<containerMode, Args...>, typename std::enable_if<detail::IsFormatter<F<containerMode, Args...>>::value>::type>;

/**
 * Formatter objects can be appended to strings, and therefore they're
 * compatible with folly::toAppend and folly::to.
 */
template <class Tgt, bool containerMode, class... Args>
typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
    const Formatter<containerMode, Args...>& value, Tgt* result) {}

} // namespace folly

FOLLY_POP_WARNING