bind.cc
Go to the documentation of this file.
00001 #include "absl/strings/internal/str_format/bind.h"
00002 
00003 #include <cerrno>
00004 #include <limits>
00005 #include <sstream>
00006 #include <string>
00007 
00008 namespace absl {
00009 namespace str_format_internal {
00010 
00011 namespace {
00012 
00013 inline bool BindFromPosition(int position, int* value,
00014                              absl::Span<const FormatArgImpl> pack) {
00015   assert(position > 0);
00016   if (static_cast<size_t>(position) > pack.size()) {
00017     return false;
00018   }
00019   // -1 because positions are 1-based
00020   return FormatArgImplFriend::ToInt(pack[position - 1], value);
00021 }
00022 
00023 class ArgContext {
00024  public:
00025   explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {}
00026 
00027   // Fill 'bound' with the results of applying the context's argument pack
00028   // to the specified 'unbound'. We synthesize a BoundConversion by
00029   // lining up a UnboundConversion with a user argument. We also
00030   // resolve any '*' specifiers for width and precision, so after
00031   // this call, 'bound' has all the information it needs to be formatted.
00032   // Returns false on failure.
00033   bool Bind(const UnboundConversion* unbound, BoundConversion* bound);
00034 
00035  private:
00036   absl::Span<const FormatArgImpl> pack_;
00037 };
00038 
00039 inline bool ArgContext::Bind(const UnboundConversion* unbound,
00040                              BoundConversion* bound) {
00041   const FormatArgImpl* arg = nullptr;
00042   int arg_position = unbound->arg_position;
00043   if (static_cast<size_t>(arg_position - 1) >= pack_.size()) return false;
00044   arg = &pack_[arg_position - 1];  // 1-based
00045 
00046   if (!unbound->flags.basic) {
00047     int width = unbound->width.value();
00048     bool force_left = false;
00049     if (unbound->width.is_from_arg()) {
00050       if (!BindFromPosition(unbound->width.get_from_arg(), &width, pack_))
00051         return false;
00052       if (width < 0) {
00053         // "A negative field width is taken as a '-' flag followed by a
00054         // positive field width."
00055         force_left = true;
00056         // Make sure we don't overflow the width when negating it.
00057         width = -std::max(width, -std::numeric_limits<int>::max());
00058       }
00059     }
00060 
00061     int precision = unbound->precision.value();
00062     if (unbound->precision.is_from_arg()) {
00063       if (!BindFromPosition(unbound->precision.get_from_arg(), &precision,
00064                             pack_))
00065         return false;
00066     }
00067 
00068     bound->set_width(width);
00069     bound->set_precision(precision);
00070     bound->set_flags(unbound->flags);
00071     if (force_left)
00072       bound->set_left(true);
00073   } else {
00074     bound->set_flags(unbound->flags);
00075     bound->set_width(-1);
00076     bound->set_precision(-1);
00077   }
00078 
00079   bound->set_length_mod(unbound->length_mod);
00080   bound->set_conv(unbound->conv);
00081   bound->set_arg(arg);
00082   return true;
00083 }
00084 
00085 template <typename Converter>
00086 class ConverterConsumer {
00087  public:
00088   ConverterConsumer(Converter converter, absl::Span<const FormatArgImpl> pack)
00089       : converter_(converter), arg_context_(pack) {}
00090 
00091   bool Append(string_view s) {
00092     converter_.Append(s);
00093     return true;
00094   }
00095   bool ConvertOne(const UnboundConversion& conv, string_view conv_string) {
00096     BoundConversion bound;
00097     if (!arg_context_.Bind(&conv, &bound)) return false;
00098     return converter_.ConvertOne(bound, conv_string);
00099   }
00100 
00101  private:
00102   Converter converter_;
00103   ArgContext arg_context_;
00104 };
00105 
00106 template <typename Converter>
00107 bool ConvertAll(const UntypedFormatSpecImpl format,
00108                 absl::Span<const FormatArgImpl> args, Converter converter) {
00109   if (format.has_parsed_conversion()) {
00110     return format.parsed_conversion()->ProcessFormat(
00111         ConverterConsumer<Converter>(converter, args));
00112   } else {
00113     return ParseFormatString(format.str(),
00114                              ConverterConsumer<Converter>(converter, args));
00115   }
00116 }
00117 
00118 class DefaultConverter {
00119  public:
00120   explicit DefaultConverter(FormatSinkImpl* sink) : sink_(sink) {}
00121 
00122   void Append(string_view s) const { sink_->Append(s); }
00123 
00124   bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
00125     return FormatArgImplFriend::Convert(*bound.arg(), bound, sink_);
00126   }
00127 
00128  private:
00129   FormatSinkImpl* sink_;
00130 };
00131 
00132 class SummarizingConverter {
00133  public:
00134   explicit SummarizingConverter(FormatSinkImpl* sink) : sink_(sink) {}
00135 
00136   void Append(string_view s) const { sink_->Append(s); }
00137 
00138   bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
00139     UntypedFormatSpecImpl spec("%d");
00140 
00141     std::ostringstream ss;
00142     ss << "{" << Streamable(spec, {*bound.arg()}) << ":" << bound.flags();
00143     if (bound.width() >= 0) ss << bound.width();
00144     if (bound.precision() >= 0) ss << "." << bound.precision();
00145     ss << bound.length_mod() << bound.conv() << "}";
00146     Append(ss.str());
00147     return true;
00148   }
00149 
00150  private:
00151   FormatSinkImpl* sink_;
00152 };
00153 
00154 }  // namespace
00155 
00156 bool BindWithPack(const UnboundConversion* props,
00157                   absl::Span<const FormatArgImpl> pack,
00158                   BoundConversion* bound) {
00159   return ArgContext(pack).Bind(props, bound);
00160 }
00161 
00162 std::string Summarize(const UntypedFormatSpecImpl format,
00163                       absl::Span<const FormatArgImpl> args) {
00164   typedef SummarizingConverter Converter;
00165   std::string out;
00166   {
00167     // inner block to destroy sink before returning out. It ensures a last
00168     // flush.
00169     FormatSinkImpl sink(&out);
00170     if (!ConvertAll(format, args, Converter(&sink))) {
00171       return "";
00172     }
00173   }
00174   return out;
00175 }
00176 
00177 bool FormatUntyped(FormatRawSinkImpl raw_sink,
00178                    const UntypedFormatSpecImpl format,
00179                    absl::Span<const FormatArgImpl> args) {
00180   FormatSinkImpl sink(raw_sink);
00181   using Converter = DefaultConverter;
00182   return ConvertAll(format, args, Converter(&sink));
00183 }
00184 
00185 std::ostream& Streamable::Print(std::ostream& os) const {
00186   if (!FormatUntyped(&os, format_, args_)) os.setstate(std::ios::failbit);
00187   return os;
00188 }
00189 
00190 std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl format,
00191                         absl::Span<const FormatArgImpl> args) {
00192   size_t orig = out->size();
00193   if (ABSL_PREDICT_FALSE(!FormatUntyped(out, format, args))) {
00194     out->erase(orig);
00195   }
00196   return *out;
00197 }
00198 
00199 int FprintF(std::FILE* output, const UntypedFormatSpecImpl format,
00200             absl::Span<const FormatArgImpl> args) {
00201   FILERawSink sink(output);
00202   if (!FormatUntyped(&sink, format, args)) {
00203     errno = EINVAL;
00204     return -1;
00205   }
00206   if (sink.error()) {
00207     errno = sink.error();
00208     return -1;
00209   }
00210   if (sink.count() > std::numeric_limits<int>::max()) {
00211     errno = EFBIG;
00212     return -1;
00213   }
00214   return static_cast<int>(sink.count());
00215 }
00216 
00217 int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl format,
00218              absl::Span<const FormatArgImpl> args) {
00219   BufferRawSink sink(output, size ? size - 1 : 0);
00220   if (!FormatUntyped(&sink, format, args)) {
00221     errno = EINVAL;
00222     return -1;
00223   }
00224   size_t total = sink.total_written();
00225   if (size) output[std::min(total, size - 1)] = 0;
00226   return static_cast<int>(total);
00227 }
00228 
00229 }  // namespace str_format_internal
00230 }  // namespace absl


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:14