StringHelper.cc Source File

Back to the index.

StringHelper.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010 Anders Gavare. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include "StringHelper.h"
29 
30 
31 // This is basically strtoull(), but it needs to be explicitly implemented
32 // since some systems lack it. (Also, compiling with GNU C++ in ANSI mode
33 // does not work with strtoull.)
34 uint64_t StringHelper::ParseNumber(const char* str, bool& error)
35 {
36  bool baseSet = false;
37  int base = 10;
38  uint64_t result = 0;
39  bool negative = false;
40 
41  error = false;
42 
43  if (str == NULL)
44  return 0;
45 
46  while (*str == ' ')
47  ++str;
48 
49  if (*str == '-') {
50  negative = true;
51  ++str;
52  }
53 
54  while ((*str == 'x' || *str == 'X') || (*str >= '0' && *str <= '9')
55  || (*str >= 'a' && *str <= 'f') || (*str >= 'A' && *str <= 'F')) {
56  char c = *str;
57 
58  if (c == 'x' || c == 'X') {
59  // Multiple base selections are not allowed.
60  if (baseSet)
61  break;
62 
63  // Only 0 prefix before base selection is allowed,
64  // no other values.
65  if (result != 0)
66  break;
67 
68  base = 16;
69  baseSet = true;
70  } else {
71  if (base == 10 && (c < '0' || c > '9'))
72  break;
73 
74  int n = c - '0';
75  if (c >= 'a' && c <= 'f')
76  n = *str - 'a' + 10;
77  if (c >= 'A' && c <= 'F')
78  n = *str - 'A' + 10;
79 
80  if (base == 16 && (n < 0 || n > 15))
81  break;
82 
83  result = result * base + n;
84  }
85 
86  ++str;
87  }
88 
89  if (*str)
90  error = true;
91 
92  if (negative)
93  return -result;
94  else
95  return result;
96 }
97 
98 
99 vector<string> StringHelper::SplitStringIntoVector(const string &str, const char splitter)
100 {
101  // This is slow and hackish, but works.
102  vector<string> strings;
103  string word;
104  bool lastWasSplitter = false;
105 
106  for (size_t i=0, n=str.length(); i<n; i++) {
107  char ch = str[i];
108  if (ch == splitter) {
109  strings.push_back(word);
110  word = "";
111  lastWasSplitter = true;
112  } else {
113  word += ch;
114  lastWasSplitter = false;
115  }
116  }
117 
118  if (word != "" || lastWasSplitter)
119  strings.push_back(word);
120 
121  return strings;
122 }
123 
124 
125 /*****************************************************************************/
126 
127 
128 #ifdef WITHUNITTESTS
129 
130 static void Test_StringHelper_ParseNumber_Simple()
131 {
132  string s = "42";
133  bool error = true;
134 
135  uint64_t value = StringHelper::ParseNumber(s.c_str(), error);
136 
137  UnitTest::Assert("Should have succeeded with no error", error == false);
138  UnitTest::Assert("Unexpected resulting value", value, 42);
139 }
140 
141 static void Test_StringHelper_ParseNumber_SimpleError()
142 {
143  string s = "Q42";
144  bool error = false;
145 
146  StringHelper::ParseNumber(s.c_str(), error);
147 
148  UnitTest::Assert("Should have resulted in error", error == true);
149 }
150 
151 static void Test_StringHelper_ParseNumber_Negative()
152 {
153  string s = "-42";
154  bool error = true;
155 
156  uint64_t value = StringHelper::ParseNumber(s.c_str(), error);
157 
158  UnitTest::Assert("Should have succeeded with no error", error == false);
159  UnitTest::Assert("Unexpected resulting value", value, (uint64_t) -42);
160 }
161 
162 static void Test_StringHelper_ParseNumber_LeadingSpaces()
163 {
164  string s = " 42";
165  bool error = true;
166 
167  uint64_t value = StringHelper::ParseNumber(s.c_str(), error);
168 
169  UnitTest::Assert("Should have succeeded with no error", error == false);
170  UnitTest::Assert("Unexpected resulting value", value, 42);
171 }
172 
173 static void Test_StringHelper_ParseNumber_LeadingSpacesAndNegative()
174 {
175  string s = " -42";
176  bool error = true;
177 
178  uint64_t value = StringHelper::ParseNumber(s.c_str(), error);
179 
180  UnitTest::Assert("Should have succeeded with no error", error == false);
181  UnitTest::Assert("Unexpected resulting value", value, (uint64_t) -42);
182 }
183 
184 static void Test_StringHelper_ParseNumber_LeadingSpacesAndErrorNegative()
185 {
186  string s = " - 42";
187  bool error = false;
188 
189  StringHelper::ParseNumber(s.c_str(), error);
190 
191  UnitTest::Assert("Should have resulted in error", error == true);
192 }
193 
194 static void Test_StringHelper_ParseNumber_SimpleHexLowerCase()
195 {
196  string s = "0x42a";
197  bool error = true;
198 
199  uint64_t value = StringHelper::ParseNumber(s.c_str(), error);
200 
201  UnitTest::Assert("Should have succeeded with no error", error == false);
202  UnitTest::Assert("Unexpected resulting value", value, 0x42a);
203 }
204 
205 static void Test_StringHelper_ParseNumber_SimpleHexUpperCase()
206 {
207  string s = "0X42A";
208  bool error = true;
209 
210  uint64_t value = StringHelper::ParseNumber(s.c_str(), error);
211 
212  UnitTest::Assert("Should have succeeded with no error", error == false);
213  UnitTest::Assert("Unexpected resulting value", value, 0x42a);
214 }
215 
216 static void Test_StringHelper_ParseNumber_HexErrorDoubleX()
217 {
218  string s = "0xx42";
219  bool error = false;
220 
221  StringHelper::ParseNumber(s.c_str(), error);
222 
223  UnitTest::Assert("Should have resulted in error", error == true);
224 }
225 
226 static void Test_StringHelper_ParseNumber_HexErrorNonZeroPrefix()
227 {
228  string s = "04x42";
229  bool error = false;
230 
231  StringHelper::ParseNumber(s.c_str(), error);
232 
233  UnitTest::Assert("Should have resulted in error", error == true);
234 }
235 
236 static void Test_StringHelper_ParseNumber_NumberFollowedByErrorValidHexChar()
237 {
238  string s = "42A"; // Note: A is a valid hex char
239  bool error = false;
240 
241  StringHelper::ParseNumber(s.c_str(), error);
242 
243  UnitTest::Assert("Should have resulted in error", error == true);
244 }
245 
246 static void Test_StringHelper_ParseNumber_NumberFollowedByError()
247 {
248  string s = "42Q";
249  bool error = false;
250 
251  StringHelper::ParseNumber(s.c_str(), error);
252 
253  UnitTest::Assert("Should have resulted in error", error == true);
254 }
255 
256 static void Test_StringHelper_SplitStringIntoVector_Simple()
257 {
258  vector<string> v = StringHelper::SplitStringIntoVector("A:B:C", ':');
259 
260  UnitTest::Assert("Wrong number of strings?", v.size(), 3);
261  UnitTest::Assert("Wrong string contents?", v[0], "A");
262  UnitTest::Assert("Wrong string contents?", v[1], "B");
263  UnitTest::Assert("Wrong string contents?", v[2], "C");
264 }
265 
266 static void Test_StringHelper_SplitStringIntoVector_EmptyInput()
267 {
268  vector<string> v = StringHelper::SplitStringIntoVector("", ':');
269 
270  UnitTest::Assert("Wrong number of strings?", v.size(), 0);
271 }
272 
273 static void Test_StringHelper_SplitStringIntoVector_Simple2()
274 {
275  vector<string> v = StringHelper::SplitStringIntoVector("A:B:C", 'B');
276 
277  UnitTest::Assert("Wrong number of strings?", v.size(), 2);
278  UnitTest::Assert("Wrong string contents?", v[0], "A:");
279  UnitTest::Assert("Wrong string contents?", v[1], ":C");
280 }
281 
282 static void Test_StringHelper_SplitStringIntoVector_WithZeroLengthParts()
283 {
284  vector<string> v = StringHelper::SplitStringIntoVector("A::B:::C", ':');
285 
286  UnitTest::Assert("Wrong number of strings?", v.size(), 6);
287  UnitTest::Assert("Wrong string contents?", v[0], "A");
288  UnitTest::Assert("Wrong string contents?", v[1], "");
289  UnitTest::Assert("Wrong string contents?", v[2], "B");
290  UnitTest::Assert("Wrong string contents?", v[3], "");
291  UnitTest::Assert("Wrong string contents?", v[4], "");
292  UnitTest::Assert("Wrong string contents?", v[5], "C");
293 }
294 
295 static void Test_StringHelper_SplitStringIntoVector_WithTrailingZeroLengthParts()
296 {
297  vector<string> v = StringHelper::SplitStringIntoVector("A::", ':');
298 
299  UnitTest::Assert("Wrong number of strings?", v.size(), 3);
300  UnitTest::Assert("Wrong string contents?", v[0], "A");
301  UnitTest::Assert("Wrong string contents?", v[1], "");
302  UnitTest::Assert("Wrong string contents?", v[2], "");
303 }
304 
305 static void Test_StringHelper_SplitStringIntoVector_WithHeadingZeroLengthParts()
306 {
307  vector<string> v = StringHelper::SplitStringIntoVector("A::", 'A');
308 
309  UnitTest::Assert("Wrong number of strings?", v.size(), 2);
310  UnitTest::Assert("Wrong string contents?", v[0], "");
311  UnitTest::Assert("Wrong string contents?", v[1], "::");
312 }
313 
315 {
316  UNITTEST(Test_StringHelper_ParseNumber_Simple);
317  UNITTEST(Test_StringHelper_ParseNumber_SimpleError);
318  UNITTEST(Test_StringHelper_ParseNumber_Negative);
319  UNITTEST(Test_StringHelper_ParseNumber_LeadingSpaces);
320  UNITTEST(Test_StringHelper_ParseNumber_LeadingSpacesAndNegative);
321  UNITTEST(Test_StringHelper_ParseNumber_LeadingSpacesAndErrorNegative);
322  UNITTEST(Test_StringHelper_ParseNumber_SimpleHexLowerCase);
323  UNITTEST(Test_StringHelper_ParseNumber_SimpleHexUpperCase);
324  UNITTEST(Test_StringHelper_ParseNumber_HexErrorDoubleX);
325  UNITTEST(Test_StringHelper_ParseNumber_HexErrorNonZeroPrefix);
326  UNITTEST(Test_StringHelper_ParseNumber_NumberFollowedByErrorValidHexChar);
327  UNITTEST(Test_StringHelper_ParseNumber_NumberFollowedByError);
328 
329  UNITTEST(Test_StringHelper_SplitStringIntoVector_Simple);
330  UNITTEST(Test_StringHelper_SplitStringIntoVector_EmptyInput);
331  UNITTEST(Test_StringHelper_SplitStringIntoVector_Simple2);
332  UNITTEST(Test_StringHelper_SplitStringIntoVector_WithZeroLengthParts);
333  UNITTEST(Test_StringHelper_SplitStringIntoVector_WithTrailingZeroLengthParts);
334  UNITTEST(Test_StringHelper_SplitStringIntoVector_WithHeadingZeroLengthParts);
335 }
336 
337 #endif
338 
StringHelper::SplitStringIntoVector
static vector< string > SplitStringIntoVector(const string &str, const char splitter)
Splits a string with a certain delimiter into a vector of strings.
Definition: StringHelper.cc:99
UNITTESTS
#define UNITTESTS(class)
Helper for unit test case execution.
Definition: UnitTest.h:184
UNITTEST
#define UNITTEST(functionname)
Helper for unit test case execution.
Definition: UnitTest.h:217
UnitTest::Assert
static void Assert(const string &strFailMessage, bool condition)
Asserts that a boolean condition is correct.
Definition: UnitTest.cc:40
StringHelper
A helper class, with static functions for common string operations.
Definition: StringHelper.h:41
StringHelper.h
StringHelper::ParseNumber
static uint64_t ParseNumber(const char *str, bool &error)
Parses a string into a 64-bit number.
Definition: StringHelper.cc:34

Generated on Tue Aug 25 2020 19:25:06 for GXemul by doxygen 1.8.18