| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 | // Copyright 2020 The Abseil Authors.//// 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////      https://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 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 {ABSL_NAMESPACE_BEGINclass UntypedFormatSpec;namespace str_format_internal {class BoundConversion : public FormatConversionSpecImpl { 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, FormatConversionCharSet...>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 <FormatConversionCharSet... 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 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 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<Args...>(s), "bad format trap")))      : Base(s) {}  FormatSpecTemplate(string_view s)  // NOLINT      __attribute__((enable_if(ValidFormatImpl<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 <      FormatConversionCharSet... C,      typename = typename std::enable_if<sizeof...(C) == sizeof...(Args)>::type,      typename = typename std::enable_if<AllOf(Contains(Args,                                                        C)...)>::type>  FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc)  // NOLINT      : Base(&pc) {}};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 testingstd::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 ArgConvertResult<FormatConversionCharSetInternal::s> FormatConvertImpl(      const StreamedWrapper<S>& v, FormatConversionSpecImpl conv,      FormatSinkImpl* out);  const T& v_;};}  // namespace str_format_internalABSL_NAMESPACE_END}  // namespace absl#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
 |