root/trunk/whisperlib/common/base/third-party/string_util.cc

Revision 7, 6.8 kB (checked in by whispercastorg, 2 years ago)

version 0.2.0

Line 
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // This file defines utility functions for working with strings.
6
7
8 //////////////////////////////////////////////////////////////////////
9
10 // WhisperSoft note: Picked from chromium/src/base/string_util.cc
11
12 //////////////////////////////////////////////////////////////////////
13
14 #include <stdio.h>
15
16 #include "common/base/third-party/string_util.h"
17 #include "common/base/errno.h"
18 #include "common/base/log.h"
19
20 namespace strutil {
21
22 // Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter
23 // is the size of the buffer. These return the number of characters in the
24 // formatted string excluding the NUL terminator. If the buffer is not
25 // large enough to accommodate the formatted string without truncation, they
26 // return the number of characters that would be in the fully-formatted string
27 // (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms).
28 inline int vsnprintfT(char* buffer,
29                       size_t buf_size,
30                       const char* format,
31                       va_list argptr) {
32   return ::vsnprintf(buffer, buf_size, format, argptr);
33 }
34
35
36 // Templatized backend for StringPrintF/StringAppendF. This does not finalize
37 // the va_list, the caller is expected to do that.
38 template <class char_type>
39 static void StringAppendVT(
40     std::basic_string<char_type, std::char_traits<char_type> >* dst,
41     const char_type* format,
42     va_list ap) {
43
44   // First try with a small fixed size buffer.
45   // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
46   // and StringUtilTest.StringPrintfBounds.
47   char_type stack_buf[1024];
48
49   va_list backup_ap;
50   ::va_copy(backup_ap, ap);
51
52 #if !defined(OS_WIN)
53   errno = 0;
54 #endif
55   int result = vsnprintfT(stack_buf, NUMBEROF(stack_buf), format, backup_ap);
56   va_end(backup_ap);
57
58   if (result >= 0 && result < static_cast<int>(NUMBEROF(stack_buf))) {
59     // It fit.
60     dst->append(stack_buf, result);
61     return;
62   }
63
64   // Repeatedly increase buffer size until it fits.
65   int mem_length = NUMBEROF(stack_buf);
66   while (true) {
67     if (result < 0) {
68 #if !defined(OS_WIN)
69       // On Windows, vsnprintfT always returns the number of characters in a
70       // fully-formatted string, so if we reach this point, something else is
71       // wrong and no amount of buffer-doubling is going to fix it.
72       if (errno != 0 && errno != EOVERFLOW)
73 #endif
74       {
75         // If an error other than overflow occurred, it's never going to work.
76         DLOG_WARNING << "Unable to printf the requested string due to error.";
77         return;
78       }
79       // Try doubling the buffer size.
80       mem_length *= 2;
81     } else {
82       // We need exactly "result + 1" characters.
83       mem_length = result + 1;
84     }
85
86     if (mem_length > 32 * 1024 * 1024) {
87       // That should be plenty, don't try anything larger.  This protects
88       // against huge allocations when using vsnprintfT implementations that
89       // return -1 for reasons other than overflow without setting errno.
90       DLOG_WARNING << "Unable to printf the requested string due to size: "
91                    << mem_length;
92       return;
93     }
94
95     std::vector<char_type> mem_buf(mem_length);
96
97     // Restore the va_list before we use it again.
98     ::va_copy(backup_ap, ap);
99
100     result = vsnprintfT(&mem_buf[0], mem_length, format, ap);
101     va_end(backup_ap);
102
103     if ((result >= 0) && (result < mem_length)) {
104       // It fit.
105       dst->append(&mem_buf[0], result);
106       return;
107     }
108   }
109 }
110
111 namespace {
112
113 template <typename STR, typename INT, typename UINT, bool NEG>
114 struct IntToStringT {
115
116   // This is to avoid a compiler warning about unary minus on unsigned type.
117   // For example, say you had the following code:
118   //   template <typename INT>
119   //   INT abs(INT value) { return value < 0 ? -value : value; }
120   // Even though if INT is unsigned, it's impossible for value < 0, so the
121   // unary minus will never be taken, the compiler will still generate a
122   // warning.  We do a little specialization dance...
123   template <typename INT2, typename UINT2, bool NEG2>
124   struct ToUnsignedT { };
125
126   template <typename INT2, typename UINT2>
127   struct ToUnsignedT<INT2, UINT2, false> {
128     static UINT2 ToUnsigned(INT2 value) {
129       return static_cast<UINT2>(value);
130     }
131   };
132
133   template <typename INT2, typename UINT2>
134   struct ToUnsignedT<INT2, UINT2, true> {
135     static UINT2 ToUnsigned(INT2 value) {
136       return static_cast<UINT2>(value < 0 ? -value : value);
137     }
138   };
139
140   static STR IntToString(INT value) {
141     // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
142     // So round up to allocate 3 output characters per byte, plus 1 for '-'.
143     const int kOutputBufSize = 3 * sizeof(INT) + 1;
144
145     // Allocate the whole string right away, we will right back to front, and
146     // then return the substr of what we ended up using.
147     STR outbuf(kOutputBufSize, 0);
148
149     bool is_neg = value < 0;
150     // Even though is_neg will never be true when INT is parameterized as
151     // unsigned, even the presence of the unary operation causes a warning.
152     UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);
153
154     for (typename STR::iterator it = outbuf.end();;) {
155       --it;
156       DCHECK(it != outbuf.begin());
157       *it = static_cast<typename STR::value_type>((res % 10) + '0');
158       res /= 10;
159
160       // We're done..
161       if (res == 0) {
162         if (is_neg) {
163           --it;
164           DCHECK(it != outbuf.begin());
165           *it = static_cast<typename STR::value_type>('-');
166         }
167         return STR(it, outbuf.end());
168       }
169     }
170     // NOTREACHED();
171     return STR();
172   }
173 };
174
175 }
176
177 std::string IntToString(int value) {
178   return IntToStringT<std::string, int, unsigned int, true>::
179       IntToString(value);
180 }
181 std::string UintToString(unsigned int value) {
182   return IntToStringT<std::string, unsigned int, unsigned int, false>::
183       IntToString(value);
184 }
185 std::string Int64ToString(int64 value) {
186   return IntToStringT<std::string, int64, uint64, true>::
187       IntToString(value);
188 }
189 std::string Uint64ToString(uint64 value) {
190   return IntToStringT<std::string, uint64, uint64, false>::
191       IntToString(value);
192 }
193
194 inline void StringAppendV(std::string* dst, const char* format, va_list ap) {
195   StringAppendVT<char>(dst, format, ap);
196 }
197
198
199 std::string StringPrintf(const char* format, ...) {
200   va_list ap;
201   va_start(ap, format);
202   std::string result;
203   StringAppendV(&result, format, ap);
204   va_end(ap);
205   return result;
206 }
207
208 const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
209   va_list ap;
210   va_start(ap, format);
211   dst->clear();
212   StringAppendV(dst, format, ap);
213   va_end(ap);
214   return *dst;
215 }
216
217 void StringAppendF(std::string* dst, const char* format, ...) {
218   va_list ap;
219   va_start(ap, format);
220   StringAppendV(dst, format, ap);
221   va_end(ap);
222 }
223
224 }
Note: See TracBrowser for help on using the browser.