substitute.cc
Go to the documentation of this file.
00001 // Copyright 2017 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include "absl/strings/substitute.h"
00016 
00017 #include <algorithm>
00018 
00019 #include "absl/base/internal/raw_logging.h"
00020 #include "absl/strings/ascii.h"
00021 #include "absl/strings/escaping.h"
00022 #include "absl/strings/internal/resize_uninitialized.h"
00023 #include "absl/strings/string_view.h"
00024 
00025 namespace absl {
00026 namespace substitute_internal {
00027 
00028 void SubstituteAndAppendArray(std::string* output, absl::string_view format,
00029                               const absl::string_view* args_array,
00030                               size_t num_args) {
00031   // Determine total size needed.
00032   size_t size = 0;
00033   for (size_t i = 0; i < format.size(); i++) {
00034     if (format[i] == '$') {
00035       if (i + 1 >= format.size()) {
00036 #ifndef NDEBUG
00037         ABSL_RAW_LOG(FATAL,
00038                      "Invalid strings::Substitute() format std::string: \"%s\".",
00039                      absl::CEscape(format).c_str());
00040 #endif
00041         return;
00042       } else if (absl::ascii_isdigit(format[i + 1])) {
00043         int index = format[i + 1] - '0';
00044         if (static_cast<size_t>(index) >= num_args) {
00045 #ifndef NDEBUG
00046           ABSL_RAW_LOG(
00047               FATAL,
00048               "Invalid strings::Substitute() format std::string: asked for \"$"
00049               "%d\", but only %d args were given.  Full format std::string was: "
00050               "\"%s\".",
00051               index, static_cast<int>(num_args), absl::CEscape(format).c_str());
00052 #endif
00053           return;
00054         }
00055         size += args_array[index].size();
00056         ++i;  // Skip next char.
00057       } else if (format[i + 1] == '$') {
00058         ++size;
00059         ++i;  // Skip next char.
00060       } else {
00061 #ifndef NDEBUG
00062         ABSL_RAW_LOG(FATAL,
00063                      "Invalid strings::Substitute() format std::string: \"%s\".",
00064                      absl::CEscape(format).c_str());
00065 #endif
00066         return;
00067       }
00068     } else {
00069       ++size;
00070     }
00071   }
00072 
00073   if (size == 0) return;
00074 
00075   // Build the std::string.
00076   size_t original_size = output->size();
00077   strings_internal::STLStringResizeUninitialized(output, original_size + size);
00078   char* target = &(*output)[original_size];
00079   for (size_t i = 0; i < format.size(); i++) {
00080     if (format[i] == '$') {
00081       if (absl::ascii_isdigit(format[i + 1])) {
00082         const absl::string_view src = args_array[format[i + 1] - '0'];
00083         target = std::copy(src.begin(), src.end(), target);
00084         ++i;  // Skip next char.
00085       } else if (format[i + 1] == '$') {
00086         *target++ = '$';
00087         ++i;  // Skip next char.
00088       }
00089     } else {
00090       *target++ = format[i];
00091     }
00092   }
00093 
00094   assert(target == output->data() + output->size());
00095 }
00096 
00097 static const char kHexDigits[] = "0123456789abcdef";
00098 Arg::Arg(const void* value) {
00099   static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2,
00100                 "fix sizeof(scratch_)");
00101   if (value == nullptr) {
00102     piece_ = "NULL";
00103   } else {
00104     char* ptr = scratch_ + sizeof(scratch_);
00105     uintptr_t num = reinterpret_cast<uintptr_t>(value);
00106     do {
00107       *--ptr = kHexDigits[num & 0xf];
00108       num >>= 4;
00109     } while (num != 0);
00110     *--ptr = 'x';
00111     *--ptr = '0';
00112     piece_ = absl::string_view(ptr, scratch_ + sizeof(scratch_) - ptr);
00113   }
00114 }
00115 
00116 // TODO(jorg): Don't duplicate so much code between here and str_cat.cc
00117 Arg::Arg(Hex hex) {
00118   char* const end = &scratch_[numbers_internal::kFastToBufferSize];
00119   char* writer = end;
00120   uint64_t value = hex.value;
00121   do {
00122     *--writer = kHexDigits[value & 0xF];
00123     value >>= 4;
00124   } while (value != 0);
00125 
00126   char* beg;
00127   if (end - writer < hex.width) {
00128     beg = end - hex.width;
00129     std::fill_n(beg, writer - beg, hex.fill);
00130   } else {
00131     beg = writer;
00132   }
00133 
00134   piece_ = absl::string_view(beg, end - beg);
00135 }
00136 
00137 // TODO(jorg): Don't duplicate so much code between here and str_cat.cc
00138 Arg::Arg(Dec dec) {
00139   assert(dec.width <= numbers_internal::kFastToBufferSize);
00140   char* const end = &scratch_[numbers_internal::kFastToBufferSize];
00141   char* const minfill = end - dec.width;
00142   char* writer = end;
00143   uint64_t value = dec.value;
00144   bool neg = dec.neg;
00145   while (value > 9) {
00146     *--writer = '0' + (value % 10);
00147     value /= 10;
00148   }
00149   *--writer = '0' + value;
00150   if (neg) *--writer = '-';
00151 
00152   ptrdiff_t fillers = writer - minfill;
00153   if (fillers > 0) {
00154     // Tricky: if the fill character is ' ', then it's <fill><+/-><digits>
00155     // But...: if the fill character is '0', then it's <+/-><fill><digits>
00156     bool add_sign_again = false;
00157     if (neg && dec.fill == '0') {  // If filling with '0',
00158       ++writer;                    // ignore the sign we just added
00159       add_sign_again = true;       // and re-add the sign later.
00160     }
00161     writer -= fillers;
00162     std::fill_n(writer, fillers, dec.fill);
00163     if (add_sign_again) *--writer = '-';
00164   }
00165 
00166   piece_ = absl::string_view(writer, end - writer);
00167 }
00168 
00169 }  // namespace substitute_internal
00170 }  // namespace absl


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