Branch data Line data Source code
1 : : /*
2 : : * Copyright 2006-2009 Savarese Software Research Corporation
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at
7 : : *
8 : : * https://www.savarese.com/software/ApacheLicense-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : /**
18 : : * @file
19 : : * This header defines the ToString class.
20 : : */
21 : :
22 : : #ifndef __SSRC_WSPR_UTILITY_TO_STRING_H
23 : : #define __SSRC_WSPR_UTILITY_TO_STRING_H
24 : :
25 : : #include <ssrc/wispers-packages.h>
26 : :
27 : : // Pull in std::bad_cast.
28 : : #include <typeinfo>
29 : : #include <sstream>
30 : :
31 : : // TODO: Determine if it's possible to use a static buffer in
32 : : // configure.ac based on diagnostic test programs instead of
33 : : // hardcoding a specific compiler and version check.
34 : : #if defined(__GNUC__) && (__GNUC__ >= 4)
35 : : #define __WSPR_LEXICAL_CAST_USE_STATIC_BUFFER
36 : : #endif
37 : :
38 : : #ifdef __WSPR_LEXICAL_CAST_USE_STATIC_BUFFER
39 : : #include <type_traits>
40 : : #endif
41 : :
42 : : __BEGIN_NS_SSRC_WSPR_UTILITY
43 : :
44 : : using std::string;
45 : : using std::ostringstream;
46 : :
47 : : /**
48 : : * ToString is a convenience class for converting non-string types
49 : : * to strings. Even though this functionality (and more) is provided
50 : : * by boost::lexical_cast, that implementation uses a free-function
51 : : * and does not allow you to hold on to a casting object. Therefore,
52 : : * it reinstantiates a stringstream (and possibly other objects) on
53 : : * every use. ToString is meant to be used in situations where
54 : : * you will be repeatedly converting numbers to strings (such as in a
55 : : * loop or in a service call) and would like to avoid the overhead of
56 : : * the reinstantiation performed by boost::lexical_cast.
57 : : */
58 [ + - ]: 114 : class ToString {
59 : : // This is big enough to hold the string representations of a
60 : : // 128-bit integer. If the representation is longer, the buffer
61 : : // will not be overrun, but the output will be truncated.
62 : : #ifdef __WSPR_LEXICAL_CAST_USE_STATIC_BUFFER
63 : : char _buffer[64];
64 : : #endif
65 : : string _str;
66 : : ostringstream _ostream;
67 : :
68 : : #ifdef __WSPR_LEXICAL_CAST_USE_STATIC_BUFFER
69 : 218 : void set_static_buffer() {
70 : 218 : _ostream.rdbuf()->pubsetbuf(_buffer, sizeof(_buffer));
71 : 218 : }
72 : :
73 : 20 : template<typename T> const string & cast_to_string(const T & obj,
74 : : const std::true_type &)
75 : : SSRC_DECL_THROW(std::bad_cast)
76 : : {
77 : 20 : _ostream.seekp(0);
78 : :
79 [ - + - + ]: 20 : if(!(_ostream << obj))
80 : 0 : throw std::bad_cast();
81 : :
82 : 20 : _str.assign(_buffer,
83 : : std::min(static_cast<std::streampos>(sizeof(_buffer)),
84 : : _ostream.tellp()));
85 : 20 : return _str;
86 : : }
87 : :
88 : 1 : template<typename T> const char * cast_to_c_str(const T & obj,
89 : : const std::true_type &)
90 : : SSRC_DECL_THROW(std::bad_cast)
91 : : {
92 : 1 : _ostream.seekp(0);
93 : :
94 [ - + ]: 1 : if(!(_ostream << obj))
95 : 0 : throw std::bad_cast();
96 : :
97 : 1 : _buffer[std::min(static_cast<std::streampos>(sizeof(_buffer) - 1),
98 : : _ostream.tellp())] = 0;
99 : 1 : return _buffer;
100 : : }
101 : : #endif
102 : :
103 : 104 : template<typename T> const string & cast_to_string(const T & obj
104 : : #ifdef __WSPR_LEXICAL_CAST_USE_STATIC_BUFFER
105 : : , const std::false_type &
106 : : #endif
107 : : )
108 : : SSRC_DECL_THROW(std::bad_cast)
109 : : {
110 [ + - + - : 104 : _ostream.str("");
+ - ]
111 : :
112 [ - + ]: 104 : if(!(_ostream << obj))
113 : 0 : throw std::bad_cast();
114 : :
115 [ + - ]: 104 : _str.assign(_ostream.str());
116 : :
117 : : #ifdef __WSPR_LEXICAL_CAST_USE_STATIC_BUFFER
118 : 104 : set_static_buffer();
119 : : #endif
120 : 104 : return _str;
121 : : }
122 : :
123 : : template<typename T> const char * cast_to_c_str(const T & obj
124 : : #ifdef __WSPR_LEXICAL_CAST_USE_STATIC_BUFFER
125 : : , const std::false_type &
126 : : #endif
127 : : )
128 : : SSRC_DECL_THROW(std::bad_cast)
129 : : {
130 : : _ostream.str("");
131 : :
132 : : if(!(_ostream << obj))
133 : : throw std::bad_cast();
134 : :
135 : : _str.assign(_ostream.str());
136 : :
137 : : #ifdef __WSPR_LEXICAL_CAST_USE_STATIC_BUFFER
138 : : set_static_buffer();
139 : : #endif
140 : : return _str.c_str();
141 : : }
142 : :
143 : : public:
144 : : typedef ostringstream::fmtflags fmtflags;
145 : : typedef ostringstream::iostate iostate;
146 : :
147 : : ToString(const ToString &) {
148 : : #ifdef __WSPR_LEXICAL_CAST_USE_STATIC_BUFFER
149 : : set_static_buffer();
150 : : #endif
151 : : }
152 : :
153 [ + - ]: 114 : ToString() {
154 : : #ifdef __WSPR_LEXICAL_CAST_USE_STATIC_BUFFER
155 [ + - ]: 114 : set_static_buffer();
156 : : #endif
157 : 114 : }
158 : :
159 : : /**
160 : : * Converts an object to a string. Be careful of constructs
161 : : * such as foo.append(_string_cast(bar)).append(_string_cast(baz))
162 : : * because the cast returns a reference and the compiler may order
163 : : * calls in such a way that both appends end up with the same value.
164 : : *
165 : : * @param T The type of the object to convert. It must define the
166 : : * << operator for use with an ostream.
167 : : * @param obj The object to convert.
168 : : * @return A string representation of the object.
169 : : */
170 : : #ifdef __WSPR_LEXICAL_CAST_USE_STATIC_BUFFER
171 : 124 : template<typename T> const string & operator()(const T & obj)
172 : : SSRC_DECL_THROW(std::bad_cast)
173 : : {
174 : 124 : return cast_to_string(obj, std::is_fundamental<T>());
175 : : }
176 : :
177 : 1 : template<typename T> const char * c_str(const T & obj)
178 : : SSRC_DECL_THROW(std::bad_cast)
179 : : {
180 : 1 : return cast_to_c_str(obj, std::is_fundamental<T>());
181 : : }
182 : : #else
183 : : template<typename T> const string & operator()(const T & obj)
184 : : SSRC_DECL_THROW(std::bad_cast)
185 : : {
186 : : return cast_to_string(obj);
187 : : }
188 : :
189 : : template<typename T> const char * c_str(const T & obj)
190 : : SSRC_DECL_THROW(std::bad_cast)
191 : : {
192 : : return cast_to_c_str(obj);
193 : : }
194 : : #endif
195 : :
196 : : fmtflags flags() const {
197 : : return _ostream.flags();
198 : : }
199 : :
200 : : fmtflags flags(const fmtflags flags) {
201 : : return _ostream.flags(flags);
202 : : }
203 : :
204 : 1 : fmtflags setf(const fmtflags flags) {
205 : 1 : return _ostream.setf(flags);
206 : : }
207 : :
208 : 1 : fmtflags setf(const fmtflags flags,
209 : : const fmtflags mask)
210 : : {
211 : 1 : return _ostream.setf(flags, mask);
212 : : }
213 : :
214 : : void unsetf(const fmtflags flags) {
215 : : _ostream.unsetf(flags);
216 : : }
217 : :
218 : : iostate rdstate() const {
219 : : return _ostream.rdstate();
220 : : }
221 : :
222 : : void clear(iostate state = ostringstream::goodbit) {
223 : : _ostream.clear(state);
224 : : }
225 : :
226 : : void setstate(iostate state) {
227 : : _ostream.setstate(state);
228 : : }
229 : :
230 : : };
231 : :
232 : : #ifdef __WSPR_LEXICAL_CAST_USE_STATIC_BUFFER
233 : : #undef __WSPR_LEXICAL_CAST_USE_STATIC_BUFFER
234 : : #endif
235 : :
236 : : // Only intended for primitive types, otherwise static buffer may
237 : : // be too small. Should really specialize behavior based on
238 : : // primitive type.
239 : : template<typename T>
240 : 105 : inline string to_string(const T & obj)
241 : : SSRC_DECL_THROW(std::bad_cast)
242 : : {
243 : 210 : ToString string_cast;
244 [ + - + - : 210 : return string_cast(obj);
+ - + - ]
245 : : }
246 : :
247 : : template<>
248 : : inline string to_string<string>(const string & obj)
249 : : SSRC_DECL_THROW(std::bad_cast)
250 : : {
251 : : return obj;
252 : : }
253 : :
254 : : template<>
255 : : inline string to_string<char *>(char * const & obj)
256 : : SSRC_DECL_THROW(std::bad_cast)
257 : : {
258 : : return obj;
259 : : }
260 : :
261 : : __END_NS_SSRC_WSPR_UTILITY
262 : :
263 : : #endif
|