File indexing completed on 2025-01-31 10:12:02
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef GOOGLE_PROTOBUF_IO_PRINTER_H__
0015 #define GOOGLE_PROTOBUF_IO_PRINTER_H__
0016
0017 #include <cstddef>
0018 #include <functional>
0019 #include <initializer_list>
0020 #include <string>
0021 #include <type_traits>
0022 #include <utility>
0023 #include <vector>
0024
0025 #include "absl/cleanup/cleanup.h"
0026 #include "absl/container/flat_hash_map.h"
0027 #include "absl/functional/any_invocable.h"
0028 #include "absl/functional/function_ref.h"
0029 #include "absl/log/absl_check.h"
0030 #include "absl/meta/type_traits.h"
0031 #include "absl/strings/str_cat.h"
0032 #include "absl/strings/str_format.h"
0033 #include "absl/strings/string_view.h"
0034 #include "absl/types/optional.h"
0035 #include "absl/types/variant.h"
0036 #include "google/protobuf/io/zero_copy_sink.h"
0037
0038
0039
0040 #include "google/protobuf/port_def.inc"
0041
0042 namespace google {
0043 namespace protobuf {
0044 namespace io {
0045
0046
0047 class PROTOBUF_EXPORT AnnotationCollector {
0048 public:
0049
0050
0051 using Annotation = std::pair<std::pair<size_t, size_t>, std::string>;
0052
0053
0054
0055
0056 enum Semantic {
0057 kNone = 0,
0058 kSet = 1,
0059 kAlias = 2,
0060 };
0061
0062 virtual ~AnnotationCollector() = default;
0063
0064
0065
0066 virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
0067 const std::string& file_path,
0068 const std::vector<int>& path) = 0;
0069
0070 virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
0071 const std::string& file_path,
0072 const std::vector<int>& path,
0073 absl::optional<Semantic> semantic) {
0074 AddAnnotation(begin_offset, end_offset, file_path, path);
0075 }
0076
0077
0078
0079 virtual void AddAnnotationNew(Annotation&) {}
0080 };
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093 template <typename AnnotationProto>
0094 class AnnotationProtoCollector : public AnnotationCollector {
0095 private:
0096
0097
0098
0099
0100 struct Rank0 {};
0101 struct Rank1 : Rank0 {};
0102
0103 template <typename Proto>
0104 static auto SetSemantic(Proto* p, int semantic, Rank1)
0105 -> decltype(p->set_semantic(
0106 static_cast<typename Proto::Semantic>(semantic))) {
0107 return p->set_semantic(static_cast<typename Proto::Semantic>(semantic));
0108 }
0109
0110 template <typename Proto>
0111 static void SetSemantic(Proto*, int, Rank0) {}
0112
0113 public:
0114 explicit AnnotationProtoCollector(AnnotationProto* annotation_proto)
0115 : annotation_proto_(annotation_proto) {}
0116
0117 void AddAnnotation(size_t begin_offset, size_t end_offset,
0118 const std::string& file_path,
0119 const std::vector<int>& path) override {
0120 AddAnnotation(begin_offset, end_offset, file_path, path, absl::nullopt);
0121 }
0122
0123 void AddAnnotation(size_t begin_offset, size_t end_offset,
0124 const std::string& file_path, const std::vector<int>& path,
0125 absl::optional<Semantic> semantic) override {
0126 auto* annotation = annotation_proto_->add_annotation();
0127 for (int i = 0; i < path.size(); ++i) {
0128 annotation->add_path(path[i]);
0129 }
0130 annotation->set_source_file(file_path);
0131 annotation->set_begin(begin_offset);
0132 annotation->set_end(end_offset);
0133
0134 if (semantic.has_value()) {
0135 SetSemantic(annotation, *semantic, Rank1{});
0136 }
0137 }
0138
0139 void AddAnnotationNew(Annotation& a) override {
0140 auto* annotation = annotation_proto_->add_annotation();
0141 annotation->ParseFromString(a.second);
0142 annotation->set_begin(a.first.first);
0143 annotation->set_end(a.first.second);
0144 }
0145
0146 private:
0147 AnnotationProto* annotation_proto_;
0148 };
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456 class PROTOBUF_EXPORT Printer {
0457 private:
0458 struct AnnotationRecord;
0459
0460 public:
0461
0462
0463 struct SourceLocation {
0464 static SourceLocation current() { return {}; }
0465 absl::string_view file_name() const { return "<unknown>"; }
0466 int line() const { return 0; }
0467 };
0468
0469 static constexpr char kDefaultVariableDelimiter = '$';
0470 static constexpr absl::string_view kProtocCodegenTrace =
0471 "PROTOC_CODEGEN_TRACE";
0472
0473
0474 class Sub;
0475
0476
0477 struct Options {
0478 Options() = default;
0479 Options(const Options&) = default;
0480 Options(Options&&) = default;
0481 Options(char variable_delimiter, AnnotationCollector* annotation_collector)
0482 : variable_delimiter(variable_delimiter),
0483 annotation_collector(annotation_collector) {}
0484
0485
0486 char variable_delimiter = kDefaultVariableDelimiter;
0487
0488
0489 AnnotationCollector* annotation_collector = nullptr;
0490
0491
0492
0493 absl::string_view comment_start = "//";
0494
0495
0496 absl::string_view ignored_comment_start = "//~";
0497
0498
0499 size_t spaces_per_indent = 2;
0500
0501
0502
0503
0504
0505
0506 absl::optional<bool> enable_codegen_trace = absl::nullopt;
0507 };
0508
0509
0510
0511 explicit Printer(ZeroCopyOutputStream* output);
0512
0513
0514
0515 Printer(ZeroCopyOutputStream* output, Options options);
0516
0517
0518
0519
0520 Printer(ZeroCopyOutputStream* output, char variable_delimiter,
0521 AnnotationCollector* annotation_collector = nullptr);
0522
0523 Printer(const Printer&) = delete;
0524 Printer& operator=(const Printer&) = delete;
0525
0526
0527
0528
0529 template <typename Map>
0530 auto WithVars(const Map* vars);
0531
0532
0533
0534
0535 template <typename Map = absl::flat_hash_map<std::string, std::string>,
0536 typename = std::enable_if_t<!std::is_pointer<Map>::value>,
0537
0538
0539 typename = std::enable_if_t<
0540 !std::is_convertible<Map, absl::Span<const Sub>>::value>>
0541 auto WithVars(Map&& vars);
0542
0543
0544
0545
0546 auto WithVars(absl::Span<const Sub> vars);
0547
0548
0549
0550
0551
0552
0553 absl::string_view LookupVar(absl::string_view var);
0554
0555
0556
0557
0558 template <typename Map>
0559 auto WithAnnotations(const Map* vars);
0560
0561
0562
0563
0564
0565
0566
0567 template <typename Map = absl::flat_hash_map<std::string, AnnotationRecord>>
0568 auto WithAnnotations(Map&& vars);
0569
0570
0571
0572
0573
0574 auto WithIndent(absl::optional<size_t> indent = absl::nullopt) {
0575 size_t delta = indent.value_or(options_.spaces_per_indent);
0576 indent_ += delta;
0577 return absl::MakeCleanup([this, delta] { indent_ -= delta; });
0578 }
0579
0580
0581
0582
0583
0584 void Emit(absl::string_view format,
0585 SourceLocation loc = SourceLocation::current());
0586
0587
0588
0589
0590
0591
0592 void Emit(absl::Span<const Sub> vars, absl::string_view format,
0593 SourceLocation loc = SourceLocation::current());
0594
0595
0596
0597 void PrintRaw(absl::string_view data) { WriteRaw(data.data(), data.size()); }
0598
0599
0600
0601 void WriteRaw(const char* data, size_t size);
0602
0603
0604
0605
0606 bool failed() const { return failed_; }
0607
0608
0609
0610
0611 template <typename Map = absl::flat_hash_map<std::string, std::string>>
0612 void Print(const Map& vars, absl::string_view text);
0613
0614 template <typename... Args>
0615 void Print(absl::string_view text, const Args&... args);
0616
0617
0618
0619 template <typename SomeDescriptor>
0620 void Annotate(
0621 absl::string_view varname, const SomeDescriptor* descriptor,
0622 absl::optional<AnnotationCollector::Semantic> semantic = absl::nullopt) {
0623 Annotate(varname, varname, descriptor, semantic);
0624 }
0625
0626
0627
0628
0629
0630 template <typename Desc>
0631 void Annotate(
0632 absl::string_view begin_varname, absl::string_view end_varname,
0633 const Desc* descriptor,
0634 absl::optional<AnnotationCollector::Semantic> semantic = absl::nullopt);
0635
0636
0637
0638 void Annotate(
0639 absl::string_view varname, absl::string_view file_name,
0640 absl::optional<AnnotationCollector::Semantic> semantic = absl::nullopt) {
0641 Annotate(varname, varname, file_name, semantic);
0642 }
0643
0644
0645
0646
0647
0648 void Annotate(
0649 absl::string_view begin_varname, absl::string_view end_varname,
0650 absl::string_view file_name,
0651 absl::optional<AnnotationCollector::Semantic> semantic = absl::nullopt) {
0652 if (options_.annotation_collector == nullptr) {
0653 return;
0654 }
0655
0656 Annotate(begin_varname, end_varname, file_name, {}, semantic);
0657 }
0658
0659
0660 void Indent() { indent_ += options_.spaces_per_indent; }
0661
0662
0663 void Outdent();
0664
0665
0666
0667 template <typename Map = absl::flat_hash_map<std::string, std::string>>
0668 void FormatInternal(absl::Span<const std::string> args, const Map& vars,
0669 absl::string_view format);
0670
0671
0672
0673
0674
0675
0676 auto WithSubstitutionListener(
0677 absl::AnyInvocable<void(absl::string_view, SourceLocation)> listener) {
0678 ABSL_CHECK(substitution_listener_ == nullptr);
0679 substitution_listener_ = std::move(listener);
0680 return absl::MakeCleanup([this] { substitution_listener_ = nullptr; });
0681 }
0682
0683 private:
0684 struct PrintOptions;
0685 struct Format;
0686
0687
0688 template <bool owned>
0689 struct ValueImpl;
0690
0691 using ValueView = ValueImpl<false>;
0692 using Value = ValueImpl<true>;
0693
0694
0695 template <typename...>
0696 using Void = void;
0697
0698 template <typename Map, typename = void>
0699 struct HasHeteroLookup : std::false_type {};
0700 template <typename Map>
0701 struct HasHeteroLookup<Map, Void<decltype(std::declval<Map>().find(
0702 std::declval<absl::string_view>()))>>
0703 : std::true_type {};
0704
0705 template <typename Map,
0706 typename = std::enable_if_t<HasHeteroLookup<Map>::value>>
0707 static absl::string_view ToStringKey(absl::string_view x) {
0708 return x;
0709 }
0710
0711 template <typename Map,
0712 typename = std::enable_if_t<!HasHeteroLookup<Map>::value>>
0713 static std::string ToStringKey(absl::string_view x) {
0714 return std::string(x);
0715 }
0716
0717 Format TokenizeFormat(absl::string_view format_string,
0718 const PrintOptions& options);
0719
0720
0721
0722
0723
0724
0725
0726
0727
0728 void Annotate(absl::string_view begin_varname, absl::string_view end_varname,
0729 absl::string_view file_path, const std::vector<int>& path,
0730 absl::optional<AnnotationCollector::Semantic> semantic);
0731
0732
0733
0734
0735 void PrintImpl(absl::string_view format, absl::Span<const std::string> args,
0736 PrintOptions opts);
0737
0738
0739 static bool Validate(bool cond, PrintOptions opts,
0740 absl::FunctionRef<std::string()> message);
0741 static bool Validate(bool cond, PrintOptions opts, absl::string_view message);
0742
0743
0744
0745
0746 bool ValidateIndexLookupInBounds(size_t index, size_t current_arg_index,
0747 size_t args_len, PrintOptions opts);
0748
0749
0750 void IndentIfAtStart();
0751
0752
0753 void PrintCodegenTrace(absl::optional<SourceLocation> loc);
0754
0755
0756 auto WithDefs(absl::Span<const Sub> vars, bool allow_callbacks);
0757
0758
0759
0760
0761
0762 absl::optional<std::pair<size_t, size_t>> GetSubstitutionRange(
0763 absl::string_view varname, PrintOptions opts);
0764
0765 google::protobuf::io::zc_sink_internal::ZeroCopyStreamByteSink sink_;
0766 Options options_;
0767 size_t indent_ = 0;
0768 bool at_start_of_line_ = true;
0769 bool failed_ = false;
0770
0771 size_t paren_depth_ = 0;
0772 std::vector<size_t> paren_depth_to_omit_;
0773
0774 std::vector<std::function<absl::optional<ValueView>(absl::string_view)>>
0775 var_lookups_;
0776
0777 std::vector<
0778 std::function<absl::optional<AnnotationRecord>(absl::string_view)>>
0779 annotation_lookups_;
0780
0781
0782
0783 absl::AnyInvocable<void(absl::string_view, SourceLocation)>
0784 substitution_listener_;
0785
0786
0787
0788
0789 absl::flat_hash_map<std::string, std::pair<size_t, size_t>> substitutions_;
0790
0791
0792
0793 std::vector<std::string> line_start_variables_;
0794 };
0795
0796
0797 struct Printer::PrintOptions {
0798
0799 absl::optional<SourceLocation> loc;
0800
0801 bool checks_are_debug_only = false;
0802
0803
0804 bool use_substitution_map = false;
0805
0806
0807
0808 bool use_curly_brace_substitutions = false;
0809
0810
0811 bool allow_digit_substitutions = true;
0812
0813
0814
0815
0816
0817
0818 bool strip_spaces_around_vars = true;
0819
0820
0821
0822
0823
0824 bool strip_raw_string_indentation = false;
0825
0826
0827 bool use_annotation_frames = true;
0828 };
0829
0830
0831 template <bool owned>
0832 struct Printer::ValueImpl {
0833 private:
0834 template <typename T>
0835 struct IsSubImpl : std::false_type {};
0836 template <bool a>
0837 struct IsSubImpl<ValueImpl<a>> : std::true_type {};
0838
0839 public:
0840 using StringType = std::conditional_t<owned, std::string, absl::string_view>;
0841
0842 using Callback = std::function<bool()>;
0843 using StringOrCallback = absl::variant<StringType, Callback>;
0844
0845 ValueImpl() = default;
0846
0847
0848 template <typename Value,
0849 typename = std::enable_if_t<
0850 !IsSubImpl<absl::remove_cvref_t<Value>>::value>>
0851 ValueImpl(Value&& value)
0852 : value(ToStringOrCallback(std::forward<Value>(value), Rank2{})) {
0853 if (absl::holds_alternative<Callback>(this->value)) {
0854 consume_after = ";,";
0855 }
0856 }
0857
0858
0859 template <bool that_owned>
0860 ValueImpl(const ValueImpl<that_owned>& that) {
0861 *this = that;
0862 }
0863
0864 template <bool that_owned>
0865 ValueImpl& operator=(const ValueImpl<that_owned>& that);
0866
0867 const StringType* AsString() const {
0868 return absl::get_if<StringType>(&value);
0869 }
0870
0871 const Callback* AsCallback() const { return absl::get_if<Callback>(&value); }
0872
0873 StringOrCallback value;
0874 std::string consume_after;
0875 bool consume_parens_if_empty = false;
0876
0877 private:
0878
0879 struct Rank0 {};
0880 struct Rank1 : Rank0 {};
0881 struct Rank2 : Rank1 {};
0882
0883
0884
0885
0886
0887
0888
0889 template <typename Cb, typename = decltype(std::declval<Cb&&>()())>
0890 StringOrCallback ToStringOrCallback(Cb&& cb, Rank2);
0891
0892
0893
0894 StringOrCallback ToStringOrCallback(StringType s, Rank1) { return s; }
0895
0896 StringOrCallback ToStringOrCallback(const absl::AlphaNum& s, Rank0) {
0897 return StringType(s.Piece());
0898 }
0899 };
0900
0901 template <bool owned>
0902 template <bool that_owned>
0903 Printer::ValueImpl<owned>& Printer::ValueImpl<owned>::operator=(
0904 const ValueImpl<that_owned>& that) {
0905
0906
0907 if (static_cast<const void*>(this) == static_cast<const void*>(&that)) {
0908 return *this;
0909 }
0910
0911 using ThatStringType = typename ValueImpl<that_owned>::StringType;
0912
0913 if (auto* str = absl::get_if<ThatStringType>(&that.value)) {
0914 value = StringType(*str);
0915 } else {
0916 value = absl::get<Callback>(that.value);
0917 }
0918
0919 consume_after = that.consume_after;
0920 consume_parens_if_empty = that.consume_parens_if_empty;
0921 return *this;
0922 }
0923
0924 template <bool owned>
0925 template <typename Cb, typename >
0926 auto Printer::ValueImpl<owned>::ToStringOrCallback(Cb&& cb, Rank2)
0927 -> StringOrCallback {
0928 return Callback(
0929 [cb = std::forward<Cb>(cb), is_called = false]() mutable -> bool {
0930 if (is_called) {
0931
0932 return false;
0933 }
0934 is_called = true;
0935 cb();
0936 is_called = false;
0937 return true;
0938 });
0939 }
0940
0941 struct Printer::AnnotationRecord {
0942 std::vector<int> path;
0943 std::string file_path;
0944 absl::optional<AnnotationCollector::Semantic> semantic;
0945
0946
0947
0948
0949
0950
0951
0952 template <
0953 typename String,
0954 std::enable_if_t<std::is_convertible<const String&, std::string>::value,
0955 int> = 0>
0956 AnnotationRecord(
0957 const String& file_path,
0958 absl::optional<AnnotationCollector::Semantic> semantic = absl::nullopt)
0959 : file_path(file_path), semantic(semantic) {}
0960
0961 template <typename Desc,
0962
0963
0964 std::enable_if_t<std::is_class<Desc>::value, int> = 0>
0965 AnnotationRecord(
0966 const Desc* desc,
0967 absl::optional<AnnotationCollector::Semantic> semantic = absl::nullopt)
0968 : file_path(desc->file()->name()), semantic(semantic) {
0969 desc->GetLocationPath(&path);
0970 }
0971 };
0972
0973 class Printer::Sub {
0974 public:
0975 template <typename Value>
0976 Sub(std::string key, Value&& value)
0977 : key_(std::move(key)),
0978 value_(std::forward<Value>(value)),
0979 annotation_(absl::nullopt) {}
0980
0981 Sub AnnotatedAs(AnnotationRecord annotation) && {
0982 annotation_ = std::move(annotation);
0983 return std::move(*this);
0984 }
0985
0986 Sub WithSuffix(std::string sub_suffix) && {
0987 value_.consume_after = std::move(sub_suffix);
0988 return std::move(*this);
0989 }
0990
0991 Sub ConditionalFunctionCall() && {
0992 value_.consume_parens_if_empty = true;
0993 return std::move(*this);
0994 }
0995
0996 absl::string_view key() const { return key_; }
0997
0998 absl::string_view value() const {
0999 const auto* str = value_.AsString();
1000 ABSL_CHECK(str != nullptr)
1001 << "could not find " << key() << "; found callback instead";
1002 return *str;
1003 }
1004
1005 private:
1006 friend class Printer;
1007
1008 std::string key_;
1009 Value value_;
1010 absl::optional<AnnotationRecord> annotation_;
1011 };
1012
1013 template <typename Map>
1014 auto Printer::WithVars(const Map* vars) {
1015 var_lookups_.emplace_back(
1016 [vars](absl::string_view var) -> absl::optional<ValueView> {
1017 auto it = vars->find(ToStringKey<Map>(var));
1018 if (it == vars->end()) {
1019 return absl::nullopt;
1020 }
1021 return ValueView(it->second);
1022 });
1023 return absl::MakeCleanup([this] { var_lookups_.pop_back(); });
1024 }
1025
1026 template <typename Map, typename, typename >
1027 auto Printer::WithVars(Map&& vars) {
1028 var_lookups_.emplace_back(
1029 [vars = std::forward<Map>(vars)](
1030 absl::string_view var) -> absl::optional<ValueView> {
1031 auto it = vars.find(ToStringKey<Map>(var));
1032 if (it == vars.end()) {
1033 return absl::nullopt;
1034 }
1035 return ValueView(it->second);
1036 });
1037 return absl::MakeCleanup([this] { var_lookups_.pop_back(); });
1038 }
1039
1040 template <typename Map>
1041 auto Printer::WithAnnotations(const Map* vars) {
1042 annotation_lookups_.emplace_back(
1043 [vars](absl::string_view var) -> absl::optional<AnnotationRecord> {
1044 auto it = vars->find(ToStringKey<Map>(var));
1045 if (it == vars->end()) {
1046 return absl::nullopt;
1047 }
1048 return AnnotationRecord(it->second);
1049 });
1050 return absl::MakeCleanup([this] { annotation_lookups_.pop_back(); });
1051 }
1052
1053 template <typename Map>
1054 auto Printer::WithAnnotations(Map&& vars) {
1055 annotation_lookups_.emplace_back(
1056 [vars = std::forward<Map>(vars)](
1057 absl::string_view var) -> absl::optional<AnnotationRecord> {
1058 auto it = vars.find(ToStringKey<Map>(var));
1059 if (it == vars.end()) {
1060 return absl::nullopt;
1061 }
1062 return AnnotationRecord(it->second);
1063 });
1064 return absl::MakeCleanup([this] { annotation_lookups_.pop_back(); });
1065 }
1066
1067 inline void Printer::Emit(absl::string_view format, SourceLocation loc) {
1068 Emit({}, format, loc);
1069 }
1070
1071 template <typename Map>
1072 void Printer::Print(const Map& vars, absl::string_view text) {
1073 PrintOptions opts;
1074 opts.checks_are_debug_only = true;
1075 opts.use_substitution_map = true;
1076 opts.allow_digit_substitutions = false;
1077
1078 auto pop = WithVars(&vars);
1079 PrintImpl(text, {}, opts);
1080 }
1081
1082 template <typename... Args>
1083 void Printer::Print(absl::string_view text, const Args&... args) {
1084 static_assert(sizeof...(args) % 2 == 0, "");
1085
1086
1087
1088 absl::string_view vars[] = {args..., ""};
1089 absl::flat_hash_map<absl::string_view, absl::string_view> map;
1090 map.reserve(sizeof...(args) / 2);
1091 for (size_t i = 0; i < sizeof...(args); i += 2) {
1092 map.emplace(vars[i], vars[i + 1]);
1093 }
1094
1095 Print(map, text);
1096 }
1097
1098 template <typename Desc>
1099 void Printer::Annotate(absl::string_view begin_varname,
1100 absl::string_view end_varname, const Desc* descriptor,
1101 absl::optional<AnnotationCollector::Semantic> semantic) {
1102 if (options_.annotation_collector == nullptr) {
1103 return;
1104 }
1105
1106 std::vector<int> path;
1107 descriptor->GetLocationPath(&path);
1108 Annotate(begin_varname, end_varname, descriptor->file()->name(), path,
1109 semantic);
1110 }
1111
1112 template <typename Map>
1113 void Printer::FormatInternal(absl::Span<const std::string> args,
1114 const Map& vars, absl::string_view format) {
1115 PrintOptions opts;
1116 opts.use_curly_brace_substitutions = true;
1117 opts.strip_spaces_around_vars = true;
1118
1119 auto pop = WithVars(&vars);
1120 PrintImpl(format, args, opts);
1121 }
1122
1123 inline auto Printer::WithDefs(absl::Span<const Sub> vars,
1124 bool allow_callbacks) {
1125 absl::flat_hash_map<std::string, Value> var_map;
1126 var_map.reserve(vars.size());
1127
1128 absl::flat_hash_map<std::string, AnnotationRecord> annotation_map;
1129
1130 for (const auto& var : vars) {
1131 ABSL_CHECK(allow_callbacks || var.value_.AsCallback() == nullptr)
1132 << "callback arguments are not permitted in this position";
1133 auto result = var_map.insert({var.key_, var.value_});
1134 ABSL_CHECK(result.second)
1135 << "repeated variable in Emit() or WithVars() call: \"" << var.key_
1136 << "\"";
1137 if (var.annotation_.has_value()) {
1138 annotation_map.insert({var.key_, *var.annotation_});
1139 }
1140 }
1141
1142 var_lookups_.emplace_back([map = std::move(var_map)](absl::string_view var)
1143 -> absl::optional<ValueView> {
1144 auto it = map.find(var);
1145 if (it == map.end()) {
1146 return absl::nullopt;
1147 }
1148 return ValueView(it->second);
1149 });
1150
1151 bool has_annotations = !annotation_map.empty();
1152 if (has_annotations) {
1153 annotation_lookups_.emplace_back(
1154 [map = std::move(annotation_map)](
1155 absl::string_view var) -> absl::optional<AnnotationRecord> {
1156 auto it = map.find(var);
1157 if (it == map.end()) {
1158 return absl::nullopt;
1159 }
1160 return it->second;
1161 });
1162 }
1163
1164 return absl::MakeCleanup([this, has_annotations] {
1165 var_lookups_.pop_back();
1166 if (has_annotations) {
1167 annotation_lookups_.pop_back();
1168 }
1169 });
1170 }
1171
1172 inline auto Printer::WithVars(absl::Span<const Sub> vars) {
1173 return WithDefs(vars, false);
1174 }
1175 }
1176 }
1177 }
1178
1179 #include "google/protobuf/port_undef.inc"
1180
1181 #endif