/root/doris/be/src/gutil/strings/substitute.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2008 Google Inc. All rights reserved. |
2 | | |
3 | | #include "gutil/strings/substitute.h" |
4 | | |
5 | | #include "common/logging.h" |
6 | | #include <stdint.h> |
7 | | #include <ostream> |
8 | | |
9 | | // IWYU pragma: no_include <butil/macros.h> |
10 | | #include "gutil/macros.h" // IWYU pragma: keep |
11 | | #include "gutil/stl_util.h" |
12 | | #include "gutil/strings/ascii_ctype.h" |
13 | | #include "gutil/strings/escaping.h" |
14 | | |
15 | | namespace strings { |
16 | | |
17 | | using internal::SubstituteArg; |
18 | | |
19 | | const SubstituteArg SubstituteArg::NoArg; |
20 | | |
21 | | // Returns the number of args in arg_array which were passed explicitly |
22 | | // to Substitute(). |
23 | 0 | static int CountSubstituteArgs(const SubstituteArg* const* args_array) { |
24 | 0 | int count = 0; |
25 | 0 | while (args_array[count] != &SubstituteArg::NoArg) { |
26 | 0 | ++count; |
27 | 0 | } |
28 | 0 | return count; |
29 | 0 | } |
30 | | |
31 | | namespace internal { |
32 | 116k | int SubstitutedSize(StringPiece format, const SubstituteArg* const* args_array) { |
33 | 116k | int size = 0; |
34 | 1.26M | for (int i = 0; i < format.size(); i++) { |
35 | 1.15M | if (format[i] == '$') { |
36 | 345k | if (i + 1 >= format.size()) { |
37 | 0 | LOG(DFATAL) << "Invalid strings::Substitute() format string: \"" << CEscape(format) |
38 | 0 | << "\"."; |
39 | 0 | return 0; |
40 | 345k | } else if (ascii_isdigit(format[i + 1])) { |
41 | 345k | int index = format[i + 1] - '0'; |
42 | 345k | if (args_array[index]->size() == -1) { |
43 | 0 | LOG(DFATAL) << "strings::Substitute format string invalid: asked for \"$" |
44 | 0 | << index << "\", but only " << CountSubstituteArgs(args_array) |
45 | 0 | << " args were given. Full format string was: \"" |
46 | 0 | << CEscape(format) << "\"."; |
47 | 0 | return 0; |
48 | 0 | } |
49 | 345k | size += args_array[index]->size(); |
50 | 345k | ++i; // Skip next char. |
51 | 345k | } else if (format[i + 1] == '$') { |
52 | 0 | ++size; |
53 | 0 | ++i; // Skip next char. |
54 | 0 | } else { |
55 | 0 | LOG(DFATAL) << "Invalid strings::Substitute() format string: \"" << CEscape(format) |
56 | 0 | << "\"."; |
57 | 0 | return 0; |
58 | 0 | } |
59 | 806k | } else { |
60 | 806k | ++size; |
61 | 806k | } |
62 | 1.15M | } |
63 | 116k | return size; |
64 | 116k | } |
65 | | |
66 | 116k | char* SubstituteToBuffer(StringPiece format, const SubstituteArg* const* args_array, char* target) { |
67 | 1.26M | for (int i = 0; i < format.size(); i++) { |
68 | 1.15M | if (format[i] == '$') { |
69 | 345k | if (ascii_isdigit(format[i + 1])) { |
70 | 345k | const SubstituteArg* src = args_array[format[i + 1] - '0']; |
71 | 345k | memcpy(target, src->data(), src->size()); |
72 | 345k | target += src->size(); |
73 | 345k | ++i; // Skip next char. |
74 | 345k | } else if (format[i + 1] == '$') { |
75 | 0 | *target++ = '$'; |
76 | 0 | ++i; // Skip next char. |
77 | 0 | } |
78 | 806k | } else { |
79 | 806k | *target++ = format[i]; |
80 | 806k | } |
81 | 1.15M | } |
82 | 116k | return target; |
83 | 116k | } |
84 | | |
85 | | } // namespace internal |
86 | | |
87 | | void SubstituteAndAppend(string* output, StringPiece format, const SubstituteArg& arg0, |
88 | | const SubstituteArg& arg1, const SubstituteArg& arg2, |
89 | | const SubstituteArg& arg3, const SubstituteArg& arg4, |
90 | | const SubstituteArg& arg5, const SubstituteArg& arg6, |
91 | | const SubstituteArg& arg7, const SubstituteArg& arg8, |
92 | 116k | const SubstituteArg& arg9) { |
93 | 116k | const SubstituteArg* const args_array[] = {&arg0, &arg1, &arg2, &arg3, &arg4, &arg5, |
94 | 116k | &arg6, &arg7, &arg8, &arg9, nullptr}; |
95 | | |
96 | | // Determine total size needed. |
97 | 116k | int size = SubstitutedSize(format, args_array); |
98 | 116k | if (size == 0) return; |
99 | | |
100 | | // Build the string. |
101 | 116k | int original_size = output->size(); |
102 | 116k | STLStringResizeUninitialized(output, original_size + size); |
103 | 116k | char* target = string_as_array(output) + original_size; |
104 | | |
105 | 116k | target = SubstituteToBuffer(format, args_array, target); |
106 | 116k | DCHECK_EQ(target - output->data(), output->size()); |
107 | 116k | } |
108 | | |
109 | 0 | SubstituteArg::SubstituteArg(const void* value) { |
110 | 0 | COMPILE_ASSERT(sizeof(scratch_) >= sizeof(value) * 2 + 2, fix_sizeof_scratch_); |
111 | 0 | if (value == nullptr) { |
112 | 0 | text_ = "NULL"; |
113 | 0 | size_ = strlen(text_); |
114 | 0 | } else { |
115 | 0 | char* ptr = scratch_ + sizeof(scratch_); |
116 | 0 | uintptr_t num = reinterpret_cast<uintptr_t>(value); |
117 | 0 | static const char kHexDigits[] = "0123456789abcdef"; |
118 | 0 | do { |
119 | 0 | *--ptr = kHexDigits[num & 0xf]; |
120 | 0 | num >>= 4; |
121 | 0 | } while (num != 0); |
122 | 0 | *--ptr = 'x'; |
123 | 0 | *--ptr = '0'; |
124 | 0 | text_ = ptr; |
125 | 0 | size_ = scratch_ + sizeof(scratch_) - ptr; |
126 | 0 | } |
127 | 0 | } |
128 | | |
129 | | } // namespace strings |