File indexing completed on 2026-09-22 08:53:15
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 <optional>
0021 #include <string>
0022 #include <type_traits>
0023 #include <utility>
0024 #include <variant>
0025 #include <vector>
0026
0027 #include "absl/cleanup/cleanup.h"
0028 #include "absl/container/flat_hash_map.h"
0029 #include "absl/functional/any_invocable.h"
0030 #include "absl/functional/function_ref.h"
0031 #include "absl/log/absl_check.h"
0032 #include "absl/meta/type_traits.h"
0033 #include "absl/strings/str_cat.h"
0034 #include "absl/strings/str_format.h"
0035 #include "absl/strings/string_view.h"
0036 #include "absl/types/span.h"
0037 #include "google/protobuf/io/zero_copy_sink.h"
0038 #include "google/protobuf/io/zero_copy_stream.h"
0039
0040
0041
0042 #include "google/protobuf/port_def.inc"
0043
0044 namespace google {
0045 namespace protobuf {
0046 namespace io {
0047
0048
0049 class PROTOBUF_EXPORT AnnotationCollector {
0050 public:
0051
0052
0053 using Annotation = std::pair<std::pair<size_t, size_t>, std::string>;
0054
0055
0056
0057
0058 enum Semantic {
0059 kNone = 0,
0060 kSet = 1,
0061 kAlias = 2,
0062 };
0063
0064 virtual ~AnnotationCollector() = default;
0065
0066
0067
0068 virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
0069 const std::string& file_path,
0070 const std::vector<int>& path) = 0;
0071
0072 virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
0073 const std::string& file_path,
0074 const std::vector<int>& path,
0075 std::optional<Semantic> semantic) {
0076 AddAnnotation(begin_offset, end_offset, file_path, path);
0077 }
0078
0079
0080
0081 virtual void AddAnnotationNew(Annotation&) {}
0082 };
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095 template <typename AnnotationProto>
0096 class AnnotationProtoCollector : public AnnotationCollector {
0097 private:
0098
0099
0100
0101
0102 struct Rank0 {};
0103 struct Rank1 : Rank0 {};
0104
0105 template <typename Proto>
0106 static auto SetSemantic(Proto* p, int semantic, Rank1)
0107 -> decltype(p->set_semantic(
0108 static_cast<typename Proto::Semantic>(semantic))) {
0109 return p->set_semantic(static_cast<typename Proto::Semantic>(semantic));
0110 }
0111
0112 template <typename Proto>
0113 static void SetSemantic(Proto*, int, Rank0) {}
0114
0115 public:
0116 explicit AnnotationProtoCollector(AnnotationProto* annotation_proto)
0117 : annotation_proto_(annotation_proto) {}
0118
0119 void AddAnnotation(size_t begin_offset, size_t end_offset,
0120 const std::string& file_path,
0121 const std::vector<int>& path) override {
0122 AddAnnotation(begin_offset, end_offset, file_path, path, std::nullopt);
0123 }
0124
0125 void AddAnnotation(size_t begin_offset, size_t end_offset,
0126 const std::string& file_path, const std::vector<int>& path,
0127 std::optional<Semantic> semantic) override {
0128 auto* annotation = annotation_proto_->add_annotation();
0129 for (const int segment : path) {
0130 annotation->add_path(segment);
0131 }
0132 annotation->set_source_file(file_path);
0133 annotation->set_begin(begin_offset);
0134 annotation->set_end(end_offset);
0135
0136 if (semantic.has_value()) {
0137 SetSemantic(annotation, *semantic, Rank1{});
0138 }
0139 }
0140
0141 void AddAnnotationNew(Annotation& a) override {
0142 auto* annotation = annotation_proto_->add_annotation();
0143 annotation->ParseFromString(a.second);
0144 annotation->set_begin(a.first.first);
0145 annotation->set_end(a.first.second);
0146 }
0147
0148 private:
0149 AnnotationProto* annotation_proto_;
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
0457
0458 class PROTOBUF_EXPORT Printer {
0459 private:
0460 struct AnnotationRecord;
0461
0462 public:
0463
0464
0465 struct SourceLocation {
0466 static SourceLocation current() { return {}; }
0467 absl::string_view file_name() const { return "<unknown>"; }
0468 int line() const { return 0; }
0469 };
0470
0471 static constexpr char kDefaultVariableDelimiter = '$';
0472 static constexpr absl::string_view kProtocCodegenTrace =
0473 "PROTOC_CODEGEN_TRACE";
0474
0475
0476 class Sub;
0477
0478
0479 struct Options {
0480 Options() = default;
0481 Options(const Options&) = default;
0482 Options(Options&&) = default;
0483 Options(char variable_delimiter, AnnotationCollector* annotation_collector)
0484 : variable_delimiter(variable_delimiter),
0485 annotation_collector(annotation_collector) {}
0486
0487
0488 char variable_delimiter = kDefaultVariableDelimiter;
0489
0490
0491 AnnotationCollector* annotation_collector = nullptr;
0492
0493
0494
0495 absl::string_view comment_start = "//";
0496
0497
0498 absl::string_view ignored_comment_start = "//~";
0499
0500
0501 size_t spaces_per_indent = 2;
0502
0503
0504
0505
0506
0507
0508 std::optional<bool> enable_codegen_trace = std::nullopt;
0509 };
0510
0511
0512
0513 explicit Printer(ZeroCopyOutputStream* output);
0514
0515
0516
0517 Printer(ZeroCopyOutputStream* output, Options options);
0518
0519
0520
0521
0522 Printer(ZeroCopyOutputStream* output, char variable_delimiter,
0523 AnnotationCollector* annotation_collector = nullptr);
0524
0525 Printer(const Printer&) = delete;
0526 Printer& operator=(const Printer&) = delete;
0527
0528
0529
0530
0531 template <typename Map>
0532 auto WithVars(const Map* vars);
0533
0534
0535
0536
0537 template <
0538 typename Map = absl::flat_hash_map<absl::string_view, absl::string_view>,
0539 typename = std::enable_if_t<!std::is_pointer<Map>::value>,
0540
0541
0542 typename = std::enable_if_t<
0543 !std::is_convertible<Map, absl::Span<const Sub>>::value>>
0544 auto WithVars(Map&& vars);
0545
0546
0547
0548
0549 auto WithVars(absl::Span<const Sub> vars);
0550
0551
0552
0553
0554
0555
0556 absl::string_view LookupVar(absl::string_view var);
0557
0558
0559
0560
0561 template <typename Map>
0562 auto WithAnnotations(const Map* vars);
0563
0564
0565
0566
0567
0568
0569
0570 template <typename Map = absl::flat_hash_map<std::string, AnnotationRecord>>
0571 auto WithAnnotations(Map&& vars);
0572
0573
0574
0575
0576
0577 auto WithIndent(std::optional<size_t> indent = std::nullopt) {
0578 size_t delta = indent.value_or(options_.spaces_per_indent);
0579 indent_ += delta;
0580 return absl::MakeCleanup([this, delta] { indent_ -= delta; });
0581 }
0582
0583
0584
0585
0586
0587 void Emit(absl::string_view format,
0588 SourceLocation loc = SourceLocation::current());
0589
0590
0591
0592
0593
0594
0595 void Emit(absl::Span<const Sub> vars, absl::string_view format,
0596 SourceLocation loc = SourceLocation::current());
0597
0598
0599
0600 void PrintRaw(absl::string_view data) { WriteRaw(data.data(), data.size()); }
0601
0602
0603
0604 void WriteRaw(const char* data, size_t size);
0605
0606
0607
0608
0609 bool failed() const { return failed_; }
0610
0611
0612
0613
0614 template <
0615 typename Map = absl::flat_hash_map<absl::string_view, absl::string_view>>
0616 void Print(const Map& vars, absl::string_view text);
0617
0618 template <typename... Args>
0619 void Print(absl::string_view text, const Args&... args);
0620
0621
0622
0623 template <typename SomeDescriptor>
0624 void Annotate(
0625 absl::string_view varname, const SomeDescriptor* descriptor,
0626 std::optional<AnnotationCollector::Semantic> semantic = std::nullopt) {
0627 Annotate(varname, varname, descriptor, semantic);
0628 }
0629
0630
0631
0632
0633
0634 template <typename Desc>
0635 void Annotate(
0636 absl::string_view begin_varname, absl::string_view end_varname,
0637 const Desc* descriptor,
0638 std::optional<AnnotationCollector::Semantic> semantic = std::nullopt);
0639
0640
0641
0642 void Annotate(
0643 absl::string_view varname, absl::string_view file_name,
0644 std::optional<AnnotationCollector::Semantic> semantic = std::nullopt) {
0645 Annotate(varname, varname, file_name, semantic);
0646 }
0647
0648
0649
0650
0651
0652 void Annotate(
0653 absl::string_view begin_varname, absl::string_view end_varname,
0654 absl::string_view file_name,
0655 std::optional<AnnotationCollector::Semantic> semantic = std::nullopt) {
0656 if (options_.annotation_collector == nullptr) {
0657 return;
0658 }
0659
0660 Annotate(begin_varname, end_varname, file_name, {}, semantic);
0661 }
0662
0663
0664 void Indent() { indent_ += options_.spaces_per_indent; }
0665
0666
0667 void Outdent(SourceLocation loc = SourceLocation::current());
0668
0669
0670
0671 template <typename Map = absl::flat_hash_map<std::string, std::string>>
0672 void FormatInternal(absl::Span<const std::string> args, const Map& vars,
0673 absl::string_view format);
0674
0675
0676
0677
0678
0679
0680 auto WithSubstitutionListener(
0681 absl::AnyInvocable<void(absl::string_view, SourceLocation)> listener) {
0682 ABSL_CHECK(substitution_listener_ == nullptr);
0683 substitution_listener_ = std::move(listener);
0684 return absl::MakeCleanup([this] { substitution_listener_ = nullptr; });
0685 }
0686
0687 private:
0688 struct PrintOptions;
0689 struct Format;
0690
0691
0692 template <bool owned>
0693 struct ValueImpl;
0694
0695 using ValueView = ValueImpl<false>;
0696 using Value = ValueImpl<true>;
0697
0698
0699 template <typename...>
0700 using Void = void;
0701
0702 template <typename Map, typename = void>
0703 struct HasHeteroLookup : std::false_type {};
0704 template <typename Map>
0705 struct HasHeteroLookup<Map, Void<decltype(std::declval<Map>().find(
0706 std::declval<absl::string_view>()))>>
0707 : std::true_type {};
0708
0709 template <typename Map,
0710 typename = std::enable_if_t<HasHeteroLookup<Map>::value>>
0711 static absl::string_view ToStringKey(absl::string_view x) {
0712 return x;
0713 }
0714
0715 template <typename Map,
0716 typename = std::enable_if_t<!HasHeteroLookup<Map>::value>>
0717 static std::string ToStringKey(absl::string_view x) {
0718 return std::string(x);
0719 }
0720
0721 Format TokenizeFormat(absl::string_view format_string,
0722 const PrintOptions& options);
0723
0724
0725
0726
0727
0728
0729
0730
0731
0732 void Annotate(absl::string_view begin_varname, absl::string_view end_varname,
0733 absl::string_view file_path, const std::vector<int>& path,
0734 std::optional<AnnotationCollector::Semantic> semantic);
0735
0736
0737
0738
0739 void PrintImpl(absl::string_view format, absl::Span<const std::string> args,
0740 PrintOptions opts);
0741
0742
0743 static bool Validate(bool cond, PrintOptions opts,
0744 absl::FunctionRef<std::string()> message);
0745 static bool Validate(bool cond, PrintOptions opts, absl::string_view message);
0746
0747
0748
0749
0750 bool ValidateIndexLookupInBounds(size_t index, size_t current_arg_index,
0751 size_t args_len, PrintOptions opts);
0752
0753
0754 void IndentIfAtStart();
0755
0756
0757 void PrintCodegenTrace(std::optional<SourceLocation> loc);
0758
0759
0760 auto WithDefs(absl::Span<const Sub> vars, bool allow_callbacks);
0761
0762
0763
0764
0765
0766 std::optional<std::pair<size_t, size_t>> GetSubstitutionRange(
0767 absl::string_view varname, PrintOptions opts);
0768
0769 google::protobuf::io::zc_sink_internal::ZeroCopyStreamByteSink sink_;
0770 Options options_;
0771 size_t indent_ = 0;
0772 bool at_start_of_line_ = true;
0773 bool failed_ = false;
0774
0775 size_t paren_depth_ = 0;
0776 std::vector<size_t> paren_depth_to_omit_;
0777
0778 std::vector<std::function<std::optional<ValueView>(absl::string_view)>>
0779 var_lookups_;
0780
0781 std::vector<std::function<std::optional<AnnotationRecord>(absl::string_view)>>
0782 annotation_lookups_;
0783
0784
0785
0786 absl::AnyInvocable<void(absl::string_view, SourceLocation)>
0787 substitution_listener_;
0788
0789
0790
0791
0792 absl::flat_hash_map<std::string, std::pair<size_t, size_t>> substitutions_;
0793
0794
0795
0796 std::vector<std::string> line_start_variables_;
0797 };
0798
0799
0800 struct Printer::PrintOptions {
0801
0802 std::optional<SourceLocation> loc;
0803
0804 bool checks_are_debug_only = false;
0805
0806
0807 bool use_substitution_map = false;
0808
0809
0810
0811 bool use_curly_brace_substitutions = false;
0812
0813
0814 bool allow_digit_substitutions = true;
0815
0816
0817
0818
0819
0820
0821 bool strip_spaces_around_vars = true;
0822
0823
0824
0825
0826
0827 bool strip_raw_string_indentation = false;
0828
0829
0830 bool use_annotation_frames = true;
0831 };
0832
0833
0834 template <bool owned>
0835 struct Printer::ValueImpl {
0836 private:
0837 template <typename T>
0838 struct IsSubImpl : std::false_type {};
0839 template <bool a>
0840 struct IsSubImpl<ValueImpl<a>> : std::true_type {};
0841
0842 public:
0843 using StringType = std::conditional_t<owned, std::string, absl::string_view>;
0844
0845 using Callback = std::function<bool()>;
0846 using StringOrCallback = std::variant<StringType, Callback>;
0847
0848 ValueImpl() = default;
0849
0850
0851 template <typename Value,
0852 typename = std::enable_if_t<
0853 !IsSubImpl<absl::remove_cvref_t<Value>>::value>>
0854 ValueImpl(Value&& value)
0855 : value(ToStringOrCallback(std::forward<Value>(value), Rank2{})) {
0856 if (std::holds_alternative<Callback>(this->value)) {
0857 consume_after = ";,";
0858 }
0859 }
0860
0861
0862 template <bool that_owned>
0863 ValueImpl(const ValueImpl<that_owned>& that) {
0864 *this = that;
0865 }
0866
0867 template <bool that_owned>
0868 ValueImpl& operator=(const ValueImpl<that_owned>& that);
0869
0870 const StringType* AsString() const { return std::get_if<StringType>(&value); }
0871
0872 const Callback* AsCallback() const { return std::get_if<Callback>(&value); }
0873
0874 StringOrCallback value;
0875 std::string consume_after;
0876 bool consume_parens_if_empty = false;
0877
0878 private:
0879
0880 struct Rank0 {};
0881 struct Rank1 : Rank0 {};
0882 struct Rank2 : Rank1 {};
0883
0884
0885
0886
0887
0888
0889
0890 template <typename Cb, typename = decltype(std::declval<Cb&&>()())>
0891 StringOrCallback ToStringOrCallback(Cb&& cb, Rank2);
0892
0893
0894
0895 StringOrCallback ToStringOrCallback(StringType s, Rank1) { return s; }
0896
0897 StringOrCallback ToStringOrCallback(const absl::AlphaNum& s, Rank0) {
0898 return StringType(s.Piece());
0899 }
0900 };
0901
0902 template <bool owned>
0903 template <bool that_owned>
0904 Printer::ValueImpl<owned>& Printer::ValueImpl<owned>::operator=(
0905 const ValueImpl<that_owned>& that) {
0906
0907
0908 if (static_cast<const void*>(this) == static_cast<const void*>(&that)) {
0909 return *this;
0910 }
0911
0912 using ThatStringType = typename ValueImpl<that_owned>::StringType;
0913
0914 if (auto* str = std::get_if<ThatStringType>(&that.value)) {
0915 value = StringType(*str);
0916 } else {
0917 value = std::get<Callback>(that.value);
0918 }
0919
0920 consume_after = that.consume_after;
0921 consume_parens_if_empty = that.consume_parens_if_empty;
0922 return *this;
0923 }
0924
0925 template <bool owned>
0926 template <typename Cb, typename >
0927 auto Printer::ValueImpl<owned>::ToStringOrCallback(Cb&& cb, Rank2)
0928 -> StringOrCallback {
0929 return Callback(
0930 [cb = std::forward<Cb>(cb), is_called = false]() mutable -> bool {
0931 if (is_called) {
0932
0933 return false;
0934 }
0935 is_called = true;
0936 cb();
0937 is_called = false;
0938 return true;
0939 });
0940 }
0941
0942 struct Printer::AnnotationRecord {
0943 std::vector<int> path;
0944 std::string file_path;
0945 std::optional<AnnotationCollector::Semantic> semantic;
0946
0947
0948
0949
0950
0951
0952
0953 template <
0954 typename String,
0955 std::enable_if_t<std::is_convertible<const String&, std::string>::value,
0956 int> = 0>
0957 AnnotationRecord(
0958 const String& file_path,
0959 std::optional<AnnotationCollector::Semantic> semantic = std::nullopt)
0960 : file_path(file_path), semantic(semantic) {}
0961
0962 template <typename Desc,
0963
0964
0965 std::enable_if_t<std::is_class<Desc>::value, int> = 0>
0966 AnnotationRecord(
0967 const Desc* desc,
0968 std::optional<AnnotationCollector::Semantic> semantic = std::nullopt)
0969 : file_path(desc->file()->name()), semantic(semantic) {
0970 desc->GetLocationPath(&path);
0971 }
0972 };
0973
0974 class Printer::Sub {
0975 public:
0976 template <typename Value>
0977 Sub(std::string key, Value&& value)
0978 : key_(std::move(key)),
0979 value_(std::forward<Value>(value)),
0980 annotation_(std::nullopt) {}
0981
0982 Sub AnnotatedAs(AnnotationRecord annotation) && {
0983 annotation_ = std::move(annotation);
0984 return std::move(*this);
0985 }
0986
0987 Sub WithSuffix(std::string sub_suffix) && {
0988 value_.consume_after = std::move(sub_suffix);
0989 return std::move(*this);
0990 }
0991
0992 Sub ConditionalFunctionCall() && {
0993 value_.consume_parens_if_empty = true;
0994 return std::move(*this);
0995 }
0996
0997 absl::string_view key() const { return key_; }
0998
0999 absl::string_view value() const {
1000 const auto* str = value_.AsString();
1001 ABSL_CHECK(str != nullptr)
1002 << "could not find " << key() << "; found callback instead";
1003 return *str;
1004 }
1005
1006 private:
1007 friend class Printer;
1008
1009 std::string key_;
1010 Value value_;
1011 std::optional<AnnotationRecord> annotation_;
1012 };
1013
1014 template <typename Map>
1015 auto Printer::WithVars(const Map* vars) {
1016 var_lookups_.emplace_back(
1017 [vars](absl::string_view var) -> std::optional<ValueView> {
1018 auto it = vars->find(ToStringKey<Map>(var));
1019 if (it == vars->end()) {
1020 return std::nullopt;
1021 }
1022 return ValueView(it->second);
1023 });
1024 return absl::MakeCleanup([this] { var_lookups_.pop_back(); });
1025 }
1026
1027 template <typename Map, typename, typename >
1028 auto Printer::WithVars(Map&& vars) {
1029 var_lookups_.emplace_back(
1030 [vars = std::forward<Map>(vars)](
1031 absl::string_view var) -> std::optional<ValueView> {
1032 auto it = vars.find(ToStringKey<Map>(var));
1033 if (it == vars.end()) {
1034 return std::nullopt;
1035 }
1036 return ValueView(it->second);
1037 });
1038 return absl::MakeCleanup([this] { var_lookups_.pop_back(); });
1039 }
1040
1041 template <typename Map>
1042 auto Printer::WithAnnotations(const Map* vars) {
1043 annotation_lookups_.emplace_back(
1044 [vars](absl::string_view var) -> std::optional<AnnotationRecord> {
1045 auto it = vars->find(ToStringKey<Map>(var));
1046 if (it == vars->end()) {
1047 return std::nullopt;
1048 }
1049 return AnnotationRecord(it->second);
1050 });
1051 return absl::MakeCleanup([this] { annotation_lookups_.pop_back(); });
1052 }
1053
1054 template <typename Map>
1055 auto Printer::WithAnnotations(Map&& vars) {
1056 annotation_lookups_.emplace_back(
1057 [vars = std::forward<Map>(vars)](
1058 absl::string_view var) -> std::optional<AnnotationRecord> {
1059 auto it = vars.find(ToStringKey<Map>(var));
1060 if (it == vars.end()) {
1061 return std::nullopt;
1062 }
1063 return AnnotationRecord(it->second);
1064 });
1065 return absl::MakeCleanup([this] { annotation_lookups_.pop_back(); });
1066 }
1067
1068 inline void Printer::Emit(absl::string_view format, SourceLocation loc) {
1069 Emit({}, format, loc);
1070 }
1071
1072 template <typename Map>
1073 void Printer::Print(const Map& vars, absl::string_view text) {
1074 PrintOptions opts;
1075 opts.checks_are_debug_only = true;
1076 opts.use_substitution_map = true;
1077 opts.allow_digit_substitutions = false;
1078
1079 auto pop = WithVars(&vars);
1080 PrintImpl(text, {}, opts);
1081 }
1082
1083 template <typename... Args>
1084 void Printer::Print(absl::string_view text, const Args&... args) {
1085 static_assert(sizeof...(args) % 2 == 0, "");
1086
1087
1088
1089 absl::string_view vars[] = {args..., ""};
1090 absl::flat_hash_map<absl::string_view, absl::string_view> map;
1091 map.reserve(sizeof...(args) / 2);
1092 for (size_t i = 0; i < sizeof...(args); i += 2) {
1093 map.emplace(vars[i], vars[i + 1]);
1094 }
1095
1096 Print(map, text);
1097 }
1098
1099 template <typename Desc>
1100 void Printer::Annotate(absl::string_view begin_varname,
1101 absl::string_view end_varname, const Desc* descriptor,
1102 std::optional<AnnotationCollector::Semantic> semantic) {
1103 if (options_.annotation_collector == nullptr) {
1104 return;
1105 }
1106
1107 std::vector<int> path;
1108 descriptor->GetLocationPath(&path);
1109 Annotate(begin_varname, end_varname, descriptor->file()->name(), path,
1110 semantic);
1111 }
1112
1113 template <typename Map>
1114 void Printer::FormatInternal(absl::Span<const std::string> args,
1115 const Map& vars, absl::string_view format) {
1116 PrintOptions opts;
1117 opts.use_curly_brace_substitutions = true;
1118 opts.strip_spaces_around_vars = true;
1119
1120 auto pop = WithVars(&vars);
1121 PrintImpl(format, args, opts);
1122 }
1123
1124 inline auto Printer::WithDefs(absl::Span<const Sub> vars,
1125 bool allow_callbacks) {
1126 absl::flat_hash_map<std::string, Value> var_map;
1127 var_map.reserve(vars.size());
1128
1129 absl::flat_hash_map<std::string, AnnotationRecord> annotation_map;
1130
1131 for (const auto& var : vars) {
1132 ABSL_CHECK(allow_callbacks || var.value_.AsCallback() == nullptr)
1133 << "callback arguments are not permitted in this position";
1134 auto result = var_map.insert({var.key_, var.value_});
1135 ABSL_CHECK(result.second)
1136 << "repeated variable in Emit() or WithVars() call: \"" << var.key_
1137 << "\"";
1138 if (var.annotation_.has_value()) {
1139 annotation_map.insert({var.key_, *var.annotation_});
1140 }
1141 }
1142
1143 var_lookups_.emplace_back([map = std::move(var_map)](absl::string_view var)
1144 -> std::optional<ValueView> {
1145 auto it = map.find(var);
1146 if (it == map.end()) {
1147 return std::nullopt;
1148 }
1149 return ValueView(it->second);
1150 });
1151
1152 bool has_annotations = !annotation_map.empty();
1153 if (has_annotations) {
1154 annotation_lookups_.emplace_back(
1155 [map = std::move(annotation_map)](
1156 absl::string_view var) -> std::optional<AnnotationRecord> {
1157 auto it = map.find(var);
1158 if (it == map.end()) {
1159 return std::nullopt;
1160 }
1161 return it->second;
1162 });
1163 }
1164
1165 return absl::MakeCleanup([this, has_annotations] {
1166 var_lookups_.pop_back();
1167 if (has_annotations) {
1168 annotation_lookups_.pop_back();
1169 }
1170 });
1171 }
1172
1173 inline auto Printer::WithVars(absl::Span<const Sub> vars) {
1174 return WithDefs(vars, false);
1175 }
1176 }
1177 }
1178 }
1179
1180 #include "google/protobuf/port_undef.inc"
1181
1182 #endif