Skip to content

Commit 9099b20

Browse files
authored
Merge b9b7b87 into 4c2af07
2 parents 4c2af07 + b9b7b87 commit 9099b20

File tree

8 files changed

+271
-7
lines changed

8 files changed

+271
-7
lines changed

src/complexity.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace benchmark {
2626

2727
// Internal function to calculate the different scalability forms
2828
BigOFunc* FittingCurve(BigO complexity) {
29+
static const double kLog2E = 1.44269504088896340736;
2930
switch (complexity) {
3031
case oN:
3132
return [](int64_t n) -> double { return static_cast<double>(n); };
@@ -34,9 +35,11 @@ BigOFunc* FittingCurve(BigO complexity) {
3435
case oNCubed:
3536
return [](int64_t n) -> double { return std::pow(n, 3); };
3637
case oLogN:
37-
return [](int64_t n) { return log2(n); };
38+
/* Note: can't use log2 because Android's GNU STL lacks it */
39+
return [](int64_t n) { return kLog2E * log(n); };
3840
case oNLogN:
39-
return [](int64_t n) { return n * log2(n); };
41+
/* Note: can't use log2 because Android's GNU STL lacks it */
42+
return [](int64_t n) { return kLog2E * n * log(n); };
4043
case o1:
4144
default:
4245
return [](int64_t) { return 1.0; };

src/internal_macros.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
#include "benchmark/benchmark.h"
55

6+
/* Needed to detect STL */
7+
#include <cstdlib>
8+
69
// clang-format off
710

811
#ifndef __has_feature
@@ -69,6 +72,10 @@
6972
#define BENCHMARK_OS_SOLARIS 1
7073
#endif
7174

75+
#if defined(__ANDROID__) && defined(__GLIBCXX__)
76+
#define BENCHMARK_STL_ANDROID_GNUSTL 1
77+
#endif
78+
7279
#if !__has_feature(cxx_exceptions) && !defined(__cpp_exceptions) \
7380
&& !defined(__EXCEPTIONS)
7481
#define BENCHMARK_HAS_NO_EXCEPTIONS

src/string_util.cc

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,93 @@ void ReplaceAll(std::string* str, const std::string& from,
169169
}
170170
}
171171

172+
#ifdef BENCHMARK_STL_ANDROID_GNUSTL
173+
/*
174+
* GNU STL in Android NDK lacks support for some C++11 functions, including
175+
* stoul, stoi, stod. We reimplement them here using C functions strtoul,
176+
* strtol, strtod. Note that reimplemented functions are in benchmark::
177+
* namespace, not std:: namespace.
178+
*/
179+
unsigned long stoul(const std::string& str, size_t* pos, int base) {
180+
/* Record previous errno */
181+
const int oldErrno = errno;
182+
errno = 0;
183+
184+
const char* strStart = str.c_str();
185+
char* strEnd = const_cast<char*>(strStart);
186+
const unsigned long result = strtoul(strStart, &strEnd, base);
187+
188+
const int strtoulErrno = errno;
189+
/* Restore previous errno */
190+
errno = oldErrno;
191+
192+
/* Check for errors and return */
193+
if (strtoulErrno == ERANGE) {
194+
throw std::out_of_range(
195+
"stoul failed: " + str + " is outside of range of unsigned long");
196+
} else if (strEnd == strStart || strtoulErrno != 0) {
197+
throw std::invalid_argument(
198+
"stoul failed: " + str + " is not an integer");
199+
}
200+
if (pos != nullptr) {
201+
*pos = static_cast<size_t>(strEnd - strStart);
202+
}
203+
return result;
204+
}
205+
206+
int stoi(const std::string& str, size_t* pos, int base) {
207+
/* Record previous errno */
208+
const int oldErrno = errno;
209+
errno = 0;
210+
211+
const char* strStart = str.c_str();
212+
char* strEnd = const_cast<char*>(strStart);
213+
const long result = strtol(strStart, &strEnd, base);
214+
215+
const int strtolErrno = errno;
216+
/* Restore previous errno */
217+
errno = oldErrno;
218+
219+
/* Check for errors and return */
220+
if (strtolErrno == ERANGE || long(int(result)) != result) {
221+
throw std::out_of_range(
222+
"stoul failed: " + str + " is outside of range of int");
223+
} else if (strEnd == strStart || strtolErrno != 0) {
224+
throw std::invalid_argument(
225+
"stoul failed: " + str + " is not an integer");
226+
}
227+
if (pos != nullptr) {
228+
*pos = static_cast<size_t>(strEnd - strStart);
229+
}
230+
return int(result);
231+
}
232+
233+
double stod(const std::string& str, size_t* pos) {
234+
/* Record previous errno */
235+
const int oldErrno = errno;
236+
errno = 0;
237+
238+
const char* strStart = str.c_str();
239+
char* strEnd = const_cast<char*>(strStart);
240+
const double result = strtod(strStart, &strEnd);
241+
242+
/* Restore previous errno */
243+
const int strtodErrno = errno;
244+
errno = oldErrno;
245+
246+
/* Check for errors and return */
247+
if (strtodErrno == ERANGE) {
248+
throw std::out_of_range(
249+
"stoul failed: " + str + " is outside of range of int");
250+
} else if (strEnd == strStart || strtodErrno != 0) {
251+
throw std::invalid_argument(
252+
"stoul failed: " + str + " is not an integer");
253+
}
254+
if (pos != nullptr) {
255+
*pos = static_cast<size_t>(strEnd - strStart);
256+
}
257+
return result;
258+
}
259+
#endif
260+
172261
} // end namespace benchmark

src/string_util.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,23 @@ inline std::string StrCat(Args&&... args) {
3434
void ReplaceAll(std::string* str, const std::string& from,
3535
const std::string& to);
3636

37+
#ifdef BENCHMARK_STL_ANDROID_GNUSTL
38+
/*
39+
* GNU STL in Android NDK lacks support for some C++11 functions, including
40+
* stoul, stoi, stod. We reimplement them here using C functions strtoul,
41+
* strtol, strtod. Note that reimplemented functions are in benchmark::
42+
* namespace, not std:: namespace.
43+
*/
44+
unsigned long stoul(const std::string& str, size_t* pos = nullptr,
45+
int base = 10);
46+
int stoi(const std::string& str, size_t* pos = nullptr, int base = 10);
47+
double stod(const std::string& str, size_t* pos = nullptr);
48+
#else
49+
using std::stoul;
50+
using std::stoi;
51+
using std::stod;
52+
#endif
53+
3754
} // end namespace benchmark
3855

3956
#endif // BENCHMARK_STRING_UTIL_H_

src/sysinfo.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ int CountSetBitsInCPUMap(std::string Val) {
225225
auto CountBits = [](std::string Part) {
226226
using CPUMask = std::bitset<sizeof(std::uintptr_t) * CHAR_BIT>;
227227
Part = "0x" + Part;
228-
CPUMask Mask(std::stoul(Part, nullptr, 16));
228+
CPUMask Mask(benchmark::stoul(Part, nullptr, 16));
229229
return static_cast<int>(Mask.count());
230230
};
231231
size_t Pos;
@@ -408,7 +408,7 @@ int GetNumCPUs() {
408408
if (ln.size() >= Key.size() && ln.compare(0, Key.size(), Key) == 0) {
409409
NumCPUs++;
410410
if (!value.empty()) {
411-
int CurID = std::stoi(value);
411+
int CurID = benchmark::stoi(value);
412412
MaxID = std::max(CurID, MaxID);
413413
}
414414
}
@@ -481,12 +481,12 @@ double GetCPUCyclesPerSecond() {
481481
// which would cause infinite looping in WallTime_Init.
482482
if (startsWithKey(ln, "cpu MHz")) {
483483
if (!value.empty()) {
484-
double cycles_per_second = std::stod(value) * 1000000.0;
484+
double cycles_per_second = benchmark::stod(value) * 1000000.0;
485485
if (cycles_per_second > 0) return cycles_per_second;
486486
}
487487
} else if (startsWithKey(ln, "bogomips")) {
488488
if (!value.empty()) {
489-
bogo_clock = std::stod(value) * 1000000.0;
489+
bogo_clock = benchmark::stod(value) * 1000000.0;
490490
if (bogo_clock < 0.0) bogo_clock = error_value;
491491
}
492492
}

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ if (BENCHMARK_ENABLE_GTEST_TESTS)
180180

181181
add_gtest(benchmark_gtest)
182182
add_gtest(statistics_gtest)
183+
add_gtest(string_util_gtest)
183184
endif(BENCHMARK_ENABLE_GTEST_TESTS)
184185

185186
###############################################################################

test/complexity_test.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,14 +134,15 @@ static void BM_Complexity_O_N_log_N(benchmark::State& state) {
134134
}
135135
state.SetComplexityN(state.range(0));
136136
}
137+
static const double kLog2E = 1.44269504088896340736;
137138
BENCHMARK(BM_Complexity_O_N_log_N)
138139
->RangeMultiplier(2)
139140
->Range(1 << 10, 1 << 16)
140141
->Complexity(benchmark::oNLogN);
141142
BENCHMARK(BM_Complexity_O_N_log_N)
142143
->RangeMultiplier(2)
143144
->Range(1 << 10, 1 << 16)
144-
->Complexity([](int64_t n) { return n * log2(n); });
145+
->Complexity([](int64_t n) { return kLog2E * n * log(n); });
145146
BENCHMARK(BM_Complexity_O_N_log_N)
146147
->RangeMultiplier(2)
147148
->Range(1 << 10, 1 << 16)

test/string_util_gtest.cc

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
//===---------------------------------------------------------------------===//
2+
// statistics_test - Unit tests for src/statistics.cc
3+
//===---------------------------------------------------------------------===//
4+
5+
#include "../src/string_util.h"
6+
#include "gtest/gtest.h"
7+
8+
namespace {
9+
TEST(StringUtilTest, stoul) {
10+
{
11+
size_t pos = 0;
12+
EXPECT_EQ(0, benchmark::stoul("0", &pos));
13+
EXPECT_EQ(1, pos);
14+
}
15+
{
16+
size_t pos = 0;
17+
EXPECT_EQ(7, benchmark::stoul("7", &pos));
18+
EXPECT_EQ(1, pos);
19+
}
20+
{
21+
size_t pos = 0;
22+
EXPECT_EQ(135, benchmark::stoul("135", &pos));
23+
EXPECT_EQ(3, pos);
24+
}
25+
#if ULONG_MAX == 0xFFFFFFFFul
26+
{
27+
size_t pos = 0;
28+
EXPECT_EQ(0xFFFFFFFFul, benchmark::stoul("4294967295", &pos));
29+
EXPECT_EQ(10, pos);
30+
}
31+
#elif ULONG_MAX == 0xFFFFFFFFFFFFFFFFul
32+
{
33+
size_t pos = 0;
34+
EXPECT_EQ(0xFFFFFFFFFFFFFFFFul, benchmark::stoul("18446744073709551615", &pos));
35+
EXPECT_EQ(20, pos);
36+
}
37+
#endif
38+
{
39+
size_t pos = 0;
40+
EXPECT_EQ(10, benchmark::stoul("1010", &pos, 2));
41+
EXPECT_EQ(4, pos);
42+
}
43+
{
44+
size_t pos = 0;
45+
EXPECT_EQ(520, benchmark::stoul("1010", &pos, 8));
46+
EXPECT_EQ(4, pos);
47+
}
48+
{
49+
size_t pos = 0;
50+
EXPECT_EQ(1010, benchmark::stoul("1010", &pos, 10));
51+
EXPECT_EQ(4, pos);
52+
}
53+
{
54+
size_t pos = 0;
55+
EXPECT_EQ(4112, benchmark::stoul("1010", &pos, 16));
56+
EXPECT_EQ(4, pos);
57+
}
58+
{
59+
size_t pos = 0;
60+
EXPECT_EQ(0xBEEF, benchmark::stoul("BEEF", &pos, 16));
61+
EXPECT_EQ(4, pos);
62+
}
63+
{
64+
ASSERT_THROW(benchmark::stoul("this is a test"), std::invalid_argument);
65+
}
66+
}
67+
68+
TEST(StringUtilTest, stoi) {
69+
{
70+
size_t pos = 0;
71+
EXPECT_EQ(0, benchmark::stoi("0", &pos));
72+
EXPECT_EQ(1, pos);
73+
}
74+
{
75+
size_t pos = 0;
76+
EXPECT_EQ(-17, benchmark::stoi("-17", &pos));
77+
EXPECT_EQ(3, pos);
78+
}
79+
{
80+
size_t pos = 0;
81+
EXPECT_EQ(1357, benchmark::stoi("1357", &pos));
82+
EXPECT_EQ(4, pos);
83+
}
84+
{
85+
size_t pos = 0;
86+
EXPECT_EQ(10, benchmark::stoi("1010", &pos, 2));
87+
EXPECT_EQ(4, pos);
88+
}
89+
{
90+
size_t pos = 0;
91+
EXPECT_EQ(520, benchmark::stoi("1010", &pos, 8));
92+
EXPECT_EQ(4, pos);
93+
}
94+
{
95+
size_t pos = 0;
96+
EXPECT_EQ(1010, benchmark::stoi("1010", &pos, 10));
97+
EXPECT_EQ(4, pos);
98+
}
99+
{
100+
size_t pos = 0;
101+
EXPECT_EQ(4112, benchmark::stoi("1010", &pos, 16));
102+
EXPECT_EQ(4, pos);
103+
}
104+
{
105+
size_t pos = 0;
106+
EXPECT_EQ(0xBEEF, benchmark::stoi("BEEF", &pos, 16));
107+
EXPECT_EQ(4, pos);
108+
}
109+
{
110+
ASSERT_THROW(benchmark::stoi("this is a test"), std::invalid_argument);
111+
}
112+
}
113+
114+
TEST(StringUtilTest, stod) {
115+
{
116+
size_t pos = 0;
117+
EXPECT_EQ(0.0, benchmark::stod("0", &pos));
118+
EXPECT_EQ(1, pos);
119+
}
120+
{
121+
size_t pos = 0;
122+
EXPECT_EQ(-84.0, benchmark::stod("-84", &pos));
123+
EXPECT_EQ(3, pos);
124+
}
125+
{
126+
size_t pos = 0;
127+
EXPECT_EQ(1234.0, benchmark::stod("1234", &pos));
128+
EXPECT_EQ(4, pos);
129+
}
130+
{
131+
size_t pos = 0;
132+
EXPECT_EQ(1.5, benchmark::stod("1.5", &pos));
133+
EXPECT_EQ(3, pos);
134+
}
135+
{
136+
size_t pos = 0;
137+
/* Note: exactly representable as double */
138+
EXPECT_EQ(-1.25e+9, benchmark::stod("-1.25e+9", &pos));
139+
EXPECT_EQ(8, pos);
140+
}
141+
{
142+
ASSERT_THROW(benchmark::stod("this is a test"), std::invalid_argument);
143+
}
144+
}
145+
146+
} // end namespace

0 commit comments

Comments
 (0)