Home | History | Annotate | Download | only in strings
      1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
      2 
      3 Licensed under the Apache License, Version 2.0 (the "License");
      4 you may not use this file except in compliance with the License.
      5 You may obtain a copy of the License at
      6 
      7     http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 Unless required by applicable law or agreed to in writing, software
     10 distributed under the License is distributed on an "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 See the License for the specific language governing permissions and
     13 limitations under the License.
     14 ==============================================================================*/
     15 
     16 #include "tensorflow/core/lib/strings/strcat.h"
     17 
     18 #include <stdarg.h>
     19 #include <stdint.h>
     20 #include <stdio.h>
     21 #include <string.h>
     22 
     23 #include "third_party/eigen3/Eigen/Core"
     24 #include "tensorflow/core/lib/gtl/stl_util.h"
     25 #include "tensorflow/core/platform/logging.h"
     26 
     27 namespace tensorflow {
     28 namespace strings {
     29 
     30 AlphaNum::AlphaNum(const Eigen::half &f)
     31     : piece_(digits_, strlen(FloatToBuffer(static_cast<float>(f), digits_))) {}
     32 
     33 AlphaNum::AlphaNum(Hex hex) {
     34   char *const end = &digits_[kFastToBufferSize];
     35   char *writer = end;
     36   uint64 value = hex.value;
     37   uint64 width = hex.spec;
     38   // We accomplish minimum width by OR'ing in 0x10000 to the user's value,
     39   // where 0x10000 is the smallest hex number that is as wide as the user
     40   // asked for.
     41   uint64 mask = (static_cast<uint64>(1) << (width - 1) * 4) | value;
     42   static const char hexdigits[] = "0123456789abcdef";
     43   do {
     44     *--writer = hexdigits[value & 0xF];
     45     value >>= 4;
     46     mask >>= 4;
     47   } while (mask != 0);
     48   piece_ = StringPiece(writer, end - writer);
     49 }
     50 
     51 // ----------------------------------------------------------------------
     52 // StrCat()
     53 //    This merges the given strings or integers, with no delimiter.  This
     54 //    is designed to be the fastest possible way to construct a string out
     55 //    of a mix of raw C strings, StringPieces, strings, and integer values.
     56 // ----------------------------------------------------------------------
     57 
     58 // Append is merely a version of memcpy that returns the address of the byte
     59 // after the area just overwritten.  It comes in multiple flavors to minimize
     60 // call overhead.
     61 static char *Append1(char *out, const AlphaNum &x) {
     62   memcpy(out, x.data(), x.size());
     63   return out + x.size();
     64 }
     65 
     66 static char *Append2(char *out, const AlphaNum &x1, const AlphaNum &x2) {
     67   memcpy(out, x1.data(), x1.size());
     68   out += x1.size();
     69 
     70   memcpy(out, x2.data(), x2.size());
     71   return out + x2.size();
     72 }
     73 
     74 static char *Append4(char *out, const AlphaNum &x1, const AlphaNum &x2,
     75                      const AlphaNum &x3, const AlphaNum &x4) {
     76   memcpy(out, x1.data(), x1.size());
     77   out += x1.size();
     78 
     79   memcpy(out, x2.data(), x2.size());
     80   out += x2.size();
     81 
     82   memcpy(out, x3.data(), x3.size());
     83   out += x3.size();
     84 
     85   memcpy(out, x4.data(), x4.size());
     86   return out + x4.size();
     87 }
     88 
     89 string StrCat(const AlphaNum &a) { return string(a.data(), a.size()); }
     90 
     91 string StrCat(const AlphaNum &a, const AlphaNum &b) {
     92   string result;
     93   gtl::STLStringResizeUninitialized(&result, a.size() + b.size());
     94   char *const begin = &*result.begin();
     95   char *out = Append2(begin, a, b);
     96   DCHECK_EQ(out, begin + result.size());
     97   return result;
     98 }
     99 
    100 string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c) {
    101   string result;
    102   gtl::STLStringResizeUninitialized(&result, a.size() + b.size() + c.size());
    103   char *const begin = &*result.begin();
    104   char *out = Append2(begin, a, b);
    105   out = Append1(out, c);
    106   DCHECK_EQ(out, begin + result.size());
    107   return result;
    108 }
    109 
    110 string StrCat(const AlphaNum &a, const AlphaNum &b, const AlphaNum &c,
    111               const AlphaNum &d) {
    112   string result;
    113   gtl::STLStringResizeUninitialized(&result,
    114                                     a.size() + b.size() + c.size() + d.size());
    115   char *const begin = &*result.begin();
    116   char *out = Append4(begin, a, b, c, d);
    117   DCHECK_EQ(out, begin + result.size());
    118   return result;
    119 }
    120 
    121 namespace internal {
    122 
    123 // Do not call directly - these are not part of the public API.
    124 string CatPieces(std::initializer_list<StringPiece> pieces) {
    125   string result;
    126   size_t total_size = 0;
    127   for (const StringPiece piece : pieces) total_size += piece.size();
    128   gtl::STLStringResizeUninitialized(&result, total_size);
    129 
    130   char *const begin = &*result.begin();
    131   char *out = begin;
    132   for (const StringPiece piece : pieces) {
    133     const size_t this_size = piece.size();
    134     memcpy(out, piece.data(), this_size);
    135     out += this_size;
    136   }
    137   DCHECK_EQ(out, begin + result.size());
    138   return result;
    139 }
    140 
    141 // It's possible to call StrAppend with a StringPiece that is itself a fragment
    142 // of the string we're appending to.  However the results of this are random.
    143 // Therefore, check for this in debug mode.  Use unsigned math so we only have
    144 // to do one comparison.
    145 #define DCHECK_NO_OVERLAP(dest, src) \
    146   DCHECK_GE(uintptr_t((src).data() - (dest).data()), uintptr_t((dest).size()))
    147 
    148 void AppendPieces(string *result, std::initializer_list<StringPiece> pieces) {
    149   size_t old_size = result->size();
    150   size_t total_size = old_size;
    151   for (const StringPiece piece : pieces) {
    152     DCHECK_NO_OVERLAP(*result, piece);
    153     total_size += piece.size();
    154   }
    155   gtl::STLStringResizeUninitialized(result, total_size);
    156 
    157   char *const begin = &*result->begin();
    158   char *out = begin + old_size;
    159   for (const StringPiece piece : pieces) {
    160     const size_t this_size = piece.size();
    161     memcpy(out, piece.data(), this_size);
    162     out += this_size;
    163   }
    164   DCHECK_EQ(out, begin + result->size());
    165 }
    166 
    167 }  // namespace internal
    168 
    169 void StrAppend(string *result, const AlphaNum &a) {
    170   DCHECK_NO_OVERLAP(*result, a);
    171   result->append(a.data(), a.size());
    172 }
    173 
    174 void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b) {
    175   DCHECK_NO_OVERLAP(*result, a);
    176   DCHECK_NO_OVERLAP(*result, b);
    177   string::size_type old_size = result->size();
    178   gtl::STLStringResizeUninitialized(result, old_size + a.size() + b.size());
    179   char *const begin = &*result->begin();
    180   char *out = Append2(begin + old_size, a, b);
    181   DCHECK_EQ(out, begin + result->size());
    182 }
    183 
    184 void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b,
    185                const AlphaNum &c) {
    186   DCHECK_NO_OVERLAP(*result, a);
    187   DCHECK_NO_OVERLAP(*result, b);
    188   DCHECK_NO_OVERLAP(*result, c);
    189   string::size_type old_size = result->size();
    190   gtl::STLStringResizeUninitialized(result,
    191                                     old_size + a.size() + b.size() + c.size());
    192   char *const begin = &*result->begin();
    193   char *out = Append2(begin + old_size, a, b);
    194   out = Append1(out, c);
    195   DCHECK_EQ(out, begin + result->size());
    196 }
    197 
    198 void StrAppend(string *result, const AlphaNum &a, const AlphaNum &b,
    199                const AlphaNum &c, const AlphaNum &d) {
    200   DCHECK_NO_OVERLAP(*result, a);
    201   DCHECK_NO_OVERLAP(*result, b);
    202   DCHECK_NO_OVERLAP(*result, c);
    203   DCHECK_NO_OVERLAP(*result, d);
    204   string::size_type old_size = result->size();
    205   gtl::STLStringResizeUninitialized(
    206       result, old_size + a.size() + b.size() + c.size() + d.size());
    207   char *const begin = &*result->begin();
    208   char *out = Append4(begin + old_size, a, b, c, d);
    209   DCHECK_EQ(out, begin + result->size());
    210 }
    211 
    212 }  // namespace strings
    213 }  // namespace tensorflow
    214