YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/gutil/strings/substitute.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2008 Google Inc.  All rights reserved.
2
//
3
// The following only applies to changes made to this file as part of YugaByte development.
4
//
5
// Portions Copyright (c) YugaByte, Inc.
6
//
7
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
8
// in compliance with the License.  You may obtain a copy of the License at
9
//
10
// http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software distributed under the License
13
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14
// or implied.  See the License for the specific language governing permissions and limitations
15
// under the License.
16
//
17
18
#include "yb/gutil/strings/substitute.h"
19
20
#include <glog/logging.h>
21
22
#include "yb/gutil/macros.h"
23
#include "yb/gutil/stl_util.h"
24
#include "yb/gutil/strings/ascii_ctype.h"
25
#include "yb/gutil/strings/escaping.h"
26
27
namespace strings {
28
29
using internal::SubstituteArg;
30
31
const SubstituteArg SubstituteArg::NoArg;
32
33
// Returns the number of args in arg_array which were passed explicitly
34
// to Substitute().
35
0
static int CountSubstituteArgs(const SubstituteArg* const* args_array) {
36
0
  int count = 0;
37
0
  while (args_array[count] != &SubstituteArg::NoArg) {
38
0
    ++count;
39
0
  }
40
0
  return count;
41
0
}
42
43
namespace internal {
44
int SubstitutedSize(GStringPiece format,
45
62.7M
                    const SubstituteArg* const* args_array) {
46
62.7M
  int size = 0;
47
1.25G
  for (size_t i = 0; i < format.size(); i++) {
48
1.18G
    if (format[i] == '$') {
49
139M
      if (i+1 >= format.size()) {
50
0
        LOG(DFATAL) << "Invalid strings::Substitute() format string: \""
51
0
                    << CEscape(format) << "\".";
52
0
        return 0;
53
139M
      } else if (ascii_isdigit(format[i+1])) {
54
139M
        int index = format[i+1] - '0';
55
139M
        if (args_array[index]->size() == -1) {
56
0
          LOG(DFATAL)
57
0
            << "strings::Substitute format string invalid: asked for \"$"
58
0
            << index << "\", but only " << CountSubstituteArgs(args_array)
59
0
            << " args were given.  Full format string was: \""
60
0
            << CEscape(format) << "\".";
61
0
          return 0;
62
0
        }
63
139M
        size += args_array[index]->size();
64
139M
        ++i;  // Skip next char.
65
18.4E
      } else if (format[i+1] == '$') {
66
15
        ++size;
67
15
        ++i;  // Skip next char.
68
18.4E
      } else {
69
18.4E
        LOG(DFATAL) << "Invalid strings::Substitute() format string: \""
70
18.4E
                    << CEscape(format) << "\".";
71
18.4E
        return 0;
72
18.4E
      }
73
1.04G
    } else {
74
1.04G
      ++size;
75
1.04G
    }
76
1.18G
  }
77
62.7M
  return size;
78
62.7M
}
79
80
char* SubstituteToBuffer(GStringPiece format,
81
                         const SubstituteArg* const* args_array,
82
62.7M
                         char* target) {
83
62.7M
  CHECK_NOTNULL(target);
84
1.25G
  for (size_t i = 0; i < format.size(); i++) {
85
1.18G
    if (format[i] == '$') {
86
139M
      if (ascii_isdigit(format[i+1])) {
87
139M
        const SubstituteArg* src = args_array[format[i+1] - '0'];
88
139M
        memcpy(target, src->data(), src->size());
89
139M
        target += src->size();
90
139M
        ++i;  // Skip next char.
91
847
      } else if (format[i+1] == '$') {
92
15
        *target++ = '$';
93
15
        ++i;  // Skip next char.
94
15
      }
95
1.04G
    } else {
96
1.04G
      *target++ = format[i];
97
1.04G
    }
98
1.18G
  }
99
62.7M
  return target;
100
62.7M
}
101
102
} // namespace internal
103
104
void SubstituteAndAppend(
105
    string* output, GStringPiece format,
106
    const SubstituteArg& arg0, const SubstituteArg& arg1,
107
    const SubstituteArg& arg2, const SubstituteArg& arg3,
108
    const SubstituteArg& arg4, const SubstituteArg& arg5,
109
    const SubstituteArg& arg6, const SubstituteArg& arg7,
110
52.0M
    const SubstituteArg& arg8, const SubstituteArg& arg9) {
111
52.0M
  const SubstituteArg* const args_array[] = {
112
52.0M
    &arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8, &arg9, nullptr
113
52.0M
  };
114
115
  // Determine total size needed.
116
52.0M
  int size = SubstitutedSize(format, args_array);
117
52.0M
  if (size == 0) return;
118
119
  // Build the string.
120
52.0M
  auto original_size = output->size();
121
52.0M
  STLStringResizeUninitialized(output, original_size + size);
122
52.0M
  char* target = string_as_array(output) + original_size;
123
124
52.0M
  target = SubstituteToBuffer(format, args_array, target);
125
52.0M
  DCHECK_EQ(target - output->data(), output->size());
126
52.0M
}
127
128
5.00M
SubstituteArg::SubstituteArg(const void* value) {
129
5.00M
  COMPILE_ASSERT(sizeof(scratch_) >= sizeof(value) * 2 + 2,
130
5.00M
                 fix_sizeof_scratch_);
131
5.00M
  if (value == nullptr) {
132
0
    text_ = "NULL";
133
0
    size_ = strlen(text_);
134
5.00M
  } else {
135
5.00M
    char* ptr = scratch_ + sizeof(scratch_);
136
5.00M
    uintptr_t num = reinterpret_cast<uintptr_t>(value);
137
5.00M
    static const char kHexDigits[] = "0123456789abcdef";
138
60.0M
    do {
139
60.0M
      *--ptr = kHexDigits[num & 0xf];
140
60.0M
      num >>= 4;
141
60.0M
    } while (num != 0);
142
5.00M
    *--ptr = 'x';
143
5.00M
    *--ptr = '0';
144
5.00M
    text_ = ptr;
145
5.00M
    size_ = scratch_ + sizeof(scratch_) - ptr;
146
5.00M
  }
147
5.00M
}
148
149
}  // namespace strings