summaryrefslogtreecommitdiff
path: root/absl/strings/internal/str_format/bind.h
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2018-06-21 12:55:12 -0700
committerGravatar Shaindel Schwartz <shaindel@google.com>2018-06-22 08:55:41 -0400
commit4491d606df34c44efda47b6d17b605262f17e182 (patch)
tree5c5a2717289760c229fed502a6310d70ca4ed35a /absl/strings/internal/str_format/bind.h
parentd89dba27e35462d7457121b978fd79214205e686 (diff)
Export of internal Abseil changes.
-- 70f43a482d7d4ae4a255f17ca02b0106653dd600 by Shaindel Schwartz <shaindel@google.com>: Internal change PiperOrigin-RevId: 201571193 -- 93e6e9c2e683158be49d9dd1f5cb1a91d0c0f556 by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 201567108 -- fbd8ee94fbe9f2448e5adf5e88706f9c8216048f by Juemin Yang <jueminyang@google.com>: str_format release PiperOrigin-RevId: 201565129 -- 387faa301555a8a888c4429df52734aa806dca46 by Abseil Team <absl-team@google.com>: Adds a defaulted allocator parameter to the size_type constructor of InlinedVector PiperOrigin-RevId: 201558711 -- 39b15ea2c68d7129d70cbde7e71af900032595ec by Matt Calabrese <calabrese@google.com>: Update the variant implementation to eliminate unnecessary checking on alternative access when the index is known or required to be correct. PiperOrigin-RevId: 201529535 -- adab77f1f7bb363aa534297f22aae2b0f08889ea by Abseil Team <absl-team@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 201458388 -- a701dc0ba62e3cadf0de14203415b91df4ee8151 by Greg Falcon <gfalcon@google.com>: Internal cleanup PiperOrigin-RevId: 201394836 -- 8a7191410b8f440fdfa27f722ff05e451502ab61 by Abseil Team <absl-team@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 201369269 GitOrigin-RevId: 70f43a482d7d4ae4a255f17ca02b0106653dd600 Change-Id: I8ab073b30b4e27405a3b6da2c826bb4f3f0b9af6
Diffstat (limited to 'absl/strings/internal/str_format/bind.h')
-rw-r--r--absl/strings/internal/str_format/bind.h189
1 files changed, 189 insertions, 0 deletions
diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h
new file mode 100644
index 00000000..40086112
--- /dev/null
+++ b/absl/strings/internal/str_format/bind.h
@@ -0,0 +1,189 @@
+#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/container/inlined_vector.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) : str_(s), pc_() {}
+ explicit UntypedFormatSpecImpl(
+ const str_format_internal::ParsedFormatBase* pc)
+ : pc_(pc) {}
+ string_view str() const { return str_; }
+ const str_format_internal::ParsedFormatBase* parsed_conversion() const {
+ return pc_;
+ }
+
+ template <typename T>
+ static const UntypedFormatSpecImpl& Extract(const T& s) {
+ return s.spec_;
+ }
+
+ private:
+ string_view str_;
+ const str_format_internal::ParsedFormatBase* pc_;
+};
+
+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:
+#if 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), args_(args.begin(), args.end()) {}
+
+ 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::InlinedVector<FormatArgImpl, 4> args_;
+};
+
+// for testing
+std::string Summarize(const UntypedFormatSpecImpl& format,
+ absl::Span<const FormatArgImpl> args);
+bool BindWithPack(const UnboundConversion* props,
+ absl::Span<const FormatArgImpl> pack, BoundConversion* bound);
+
+bool FormatUntyped(FormatRawSinkImpl raw_sink,
+ const UntypedFormatSpecImpl& format,
+ absl::Span<const FormatArgImpl> args);
+
+std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl& format,
+ absl::Span<const FormatArgImpl> args);
+
+inline std::string FormatPack(const UntypedFormatSpecImpl& format,
+ absl::Span<const FormatArgImpl> args) {
+ std::string out;
+ AppendPack(&out, format, args);
+ return out;
+}
+
+int FprintF(std::FILE* output, const UntypedFormatSpecImpl& format,
+ absl::Span<const FormatArgImpl> args);
+int SnprintF(char* output, size_t size, const 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,
+ const ConversionSpec& conv,
+ FormatSinkImpl* out);
+ const T& v_;
+};
+
+} // namespace str_format_internal
+} // namespace absl
+
+#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_