a4b757b5d4
-- 693f81830b9f9cc8b24a1f38492b8dfcdd1d0e24 by Abseil Team <absl-team@google.com>: Check that absl::int128 works as a std::chrono::duration::rep. In particular, validate that ... std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<absl::int128, std::atto>> is a superset (range and resolution) of absl::Time. PiperOrigin-RevId: 283370280 -- df6073b686bd44223c6f9070fcceec918c728871 by Gennadiy Rozental <rogeeff@google.com>: Changes thread annotations to use DataGuard() function instead of a specific Mutex. Remove unused declaration of InvokeCallback. PiperOrigin-RevId: 283361188 -- b49eb2dd2ee1a0b4c8a7bb1a94e368b81ce5f861 by Abseil Team <absl-team@google.com>: Rewrite GetNominalCPUFrequency to use advapi32 instead of shlwapi Using shlwapi.dll means that gdi32.dll is loaded which then makes process destruction more expensive, which is unacceptable for some uses. There may be other places that pull in gdi32.dll - this just fixes the one. PiperOrigin-RevId: 282960698 -- b5508afec5099a0fdbb55e39a7cd2993259ed860 by Abseil Team <absl-team@google.com>: Small typo fix in comments: initiazliation -> initialization PiperOrigin-RevId: 282891800 -- 4319cc419584e91ee74f6ae1a32d88a412fc5c01 by Abseil Team <absl-team@google.com>: Update c_find_first_of() comment to remove the mention of an ordered container. PiperOrigin-RevId: 282836540 -- 5fcabc0a834dff39a505d5a5fc5403ddeb96028e by Derek Mauro <dmauro@google.com>: Fix NaCl build, where format checking is broken PiperOrigin-RevId: 282826202 -- aaf9ad3274c056a2f68e9b8ccada45c9802e2f1e by Derek Mauro <dmauro@google.com>: Fix more -Wundef warnings PiperOrigin-RevId: 282799820 -- 1fb06150a70ffe98bf4b2d42b2a39d083bf44f8c by Derek Mauro <dmauro@google.com>: Release support for additional platforms PiperOrigin-RevId: 282793384 -- fa947fc28624a316fa872d7045b3838b88a0d69b by Derek Mauro <dmauro@google.com>: Cleanup inconsistent usage of __has_attribute PiperOrigin-RevId: 282793296 -- 990030ad282263d6303c83b780a55fdec8e90d43 by Gennadiy Rozental <rogeeff@google.com>: Eliminate the pointer in absl::Flag, which points to n space where we were storing flag's default value. We also eliminate additional (now unnecessary) allocation for flag's default value. Instead we'll initialize the flags value directly from the value specified in ABSL_FLAG. If the default value is updated via the call to SetCommandLineOptionWithMode we are replacing pointer to initialization routine to pointer to new default value. PiperOrigin-RevId: 282637616 GitOrigin-RevId: 693f81830b9f9cc8b24a1f38492b8dfcdd1d0e24 Change-Id: I6f2edd8ef844de09aa2c182a7ca3133a22364792
207 lines
6.8 KiB
C++
207 lines
6.8 KiB
C++
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
|
|
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
|
|
|
|
#include <array>
|
|
#include <cstdio>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
#include "absl/base/port.h"
|
|
#include "absl/strings/internal/str_format/arg.h"
|
|
#include "absl/strings/internal/str_format/checker.h"
|
|
#include "absl/strings/internal/str_format/parser.h"
|
|
#include "absl/types/span.h"
|
|
|
|
namespace absl {
|
|
|
|
class UntypedFormatSpec;
|
|
|
|
namespace str_format_internal {
|
|
|
|
class BoundConversion : public ConversionSpec {
|
|
public:
|
|
const FormatArgImpl* arg() const { return arg_; }
|
|
void set_arg(const FormatArgImpl* a) { arg_ = a; }
|
|
|
|
private:
|
|
const FormatArgImpl* arg_;
|
|
};
|
|
|
|
// This is the type-erased class that the implementation uses.
|
|
class UntypedFormatSpecImpl {
|
|
public:
|
|
UntypedFormatSpecImpl() = delete;
|
|
|
|
explicit UntypedFormatSpecImpl(string_view s)
|
|
: data_(s.data()), size_(s.size()) {}
|
|
explicit UntypedFormatSpecImpl(
|
|
const str_format_internal::ParsedFormatBase* pc)
|
|
: data_(pc), size_(~size_t{}) {}
|
|
|
|
bool has_parsed_conversion() const { return size_ == ~size_t{}; }
|
|
|
|
string_view str() const {
|
|
assert(!has_parsed_conversion());
|
|
return string_view(static_cast<const char*>(data_), size_);
|
|
}
|
|
const str_format_internal::ParsedFormatBase* parsed_conversion() const {
|
|
assert(has_parsed_conversion());
|
|
return static_cast<const str_format_internal::ParsedFormatBase*>(data_);
|
|
}
|
|
|
|
template <typename T>
|
|
static const UntypedFormatSpecImpl& Extract(const T& s) {
|
|
return s.spec_;
|
|
}
|
|
|
|
private:
|
|
const void* data_;
|
|
size_t size_;
|
|
};
|
|
|
|
template <typename T, typename...>
|
|
struct MakeDependent {
|
|
using type = T;
|
|
};
|
|
|
|
// Implicitly convertible from `const char*`, `string_view`, and the
|
|
// `ExtendedParsedFormat` type. This abstraction allows all format functions to
|
|
// operate on any without providing too many overloads.
|
|
template <typename... Args>
|
|
class FormatSpecTemplate
|
|
: public MakeDependent<UntypedFormatSpec, Args...>::type {
|
|
using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type;
|
|
|
|
public:
|
|
#ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
|
|
|
|
// Honeypot overload for when the std::string is not constexpr.
|
|
// We use the 'unavailable' attribute to give a better compiler error than
|
|
// just 'method is deleted'.
|
|
FormatSpecTemplate(...) // NOLINT
|
|
__attribute__((unavailable("Format std::string is not constexpr.")));
|
|
|
|
// Honeypot overload for when the format is constexpr and invalid.
|
|
// We use the 'unavailable' attribute to give a better compiler error than
|
|
// just 'method is deleted'.
|
|
// To avoid checking the format twice, we just check that the format is
|
|
// constexpr. If is it valid, then the overload below will kick in.
|
|
// We add the template here to make this overload have lower priority.
|
|
template <typename = void>
|
|
FormatSpecTemplate(const char* s) // NOLINT
|
|
__attribute__((
|
|
enable_if(str_format_internal::EnsureConstexpr(s), "constexpr trap"),
|
|
unavailable(
|
|
"Format specified does not match the arguments passed.")));
|
|
|
|
template <typename T = void>
|
|
FormatSpecTemplate(string_view s) // NOLINT
|
|
__attribute__((enable_if(str_format_internal::EnsureConstexpr(s),
|
|
"constexpr trap"))) {
|
|
static_assert(sizeof(T*) == 0,
|
|
"Format specified does not match the arguments passed.");
|
|
}
|
|
|
|
// Good format overload.
|
|
FormatSpecTemplate(const char* s) // NOLINT
|
|
__attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s),
|
|
"bad format trap")))
|
|
: Base(s) {}
|
|
|
|
FormatSpecTemplate(string_view s) // NOLINT
|
|
__attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s),
|
|
"bad format trap")))
|
|
: Base(s) {}
|
|
|
|
#else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
|
|
|
|
FormatSpecTemplate(const char* s) : Base(s) {} // NOLINT
|
|
FormatSpecTemplate(string_view s) : Base(s) {} // NOLINT
|
|
|
|
#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
|
|
|
|
template <Conv... C, typename = typename std::enable_if<
|
|
sizeof...(C) == sizeof...(Args) &&
|
|
AllOf(Contains(ArgumentToConv<Args>(),
|
|
C)...)>::type>
|
|
FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT
|
|
: Base(&pc) {}
|
|
};
|
|
|
|
template <typename... Args>
|
|
struct FormatSpecDeductionBarrier {
|
|
using type = FormatSpecTemplate<Args...>;
|
|
};
|
|
|
|
class Streamable {
|
|
public:
|
|
Streamable(const UntypedFormatSpecImpl& format,
|
|
absl::Span<const FormatArgImpl> args)
|
|
: format_(format) {
|
|
if (args.size() <= ABSL_ARRAYSIZE(few_args_)) {
|
|
for (size_t i = 0; i < args.size(); ++i) {
|
|
few_args_[i] = args[i];
|
|
}
|
|
args_ = absl::MakeSpan(few_args_, args.size());
|
|
} else {
|
|
many_args_.assign(args.begin(), args.end());
|
|
args_ = many_args_;
|
|
}
|
|
}
|
|
|
|
std::ostream& Print(std::ostream& os) const;
|
|
|
|
friend std::ostream& operator<<(std::ostream& os, const Streamable& l) {
|
|
return l.Print(os);
|
|
}
|
|
|
|
private:
|
|
const UntypedFormatSpecImpl& format_;
|
|
absl::Span<const FormatArgImpl> args_;
|
|
// if args_.size() is 4 or less:
|
|
FormatArgImpl few_args_[4] = {FormatArgImpl(0), FormatArgImpl(0),
|
|
FormatArgImpl(0), FormatArgImpl(0)};
|
|
// if args_.size() is more than 4:
|
|
std::vector<FormatArgImpl> many_args_;
|
|
};
|
|
|
|
// for testing
|
|
std::string Summarize(UntypedFormatSpecImpl format,
|
|
absl::Span<const FormatArgImpl> args);
|
|
bool BindWithPack(const UnboundConversion* props,
|
|
absl::Span<const FormatArgImpl> pack, BoundConversion* bound);
|
|
|
|
bool FormatUntyped(FormatRawSinkImpl raw_sink,
|
|
UntypedFormatSpecImpl format,
|
|
absl::Span<const FormatArgImpl> args);
|
|
|
|
std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format,
|
|
absl::Span<const FormatArgImpl> args);
|
|
|
|
std::string FormatPack(const UntypedFormatSpecImpl format,
|
|
absl::Span<const FormatArgImpl> args);
|
|
|
|
int FprintF(std::FILE* output, UntypedFormatSpecImpl format,
|
|
absl::Span<const FormatArgImpl> args);
|
|
int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format,
|
|
absl::Span<const FormatArgImpl> args);
|
|
|
|
// Returned by Streamed(v). Converts via '%s' to the std::string created
|
|
// by std::ostream << v.
|
|
template <typename T>
|
|
class StreamedWrapper {
|
|
public:
|
|
explicit StreamedWrapper(const T& v) : v_(v) { }
|
|
|
|
private:
|
|
template <typename S>
|
|
friend ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<S>& v,
|
|
ConversionSpec conv,
|
|
FormatSinkImpl* out);
|
|
const T& v_;
|
|
};
|
|
|
|
} // namespace str_format_internal
|
|
} // namespace absl
|
|
|
|
#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
|