Skip to content

Commit f4d9406

Browse files
committed
unit_evaluate: accept binary suffixes
+ test
1 parent 5ed4b72 commit f4d9406

File tree

4 files changed

+80
-10
lines changed

4 files changed

+80
-10
lines changed

src/utils/misc.cpp

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ unit_evaluate(const char *str, const char **endptr)
9090
}
9191

9292
/**
93-
* Converts units in format <val>[.<val>][kMG] to floating point representation.
93+
* Converts units in format <val>[.<val>][kMG[i]] to floating point representation.
9494
*
9595
* @param str string to be parsed, suffix following SI suffix is ignored (as in 1ms or 100MB)
9696
* @param case_sensitive if true 'm' will be considered as milli, otherwise mega
@@ -101,6 +101,11 @@ unit_evaluate(const char *str, const char **endptr)
101101
double
102102
unit_evaluate_dbl(const char *str, bool case_sensitive, const char **endptr)
103103
{
104+
enum {
105+
SI = 1000,
106+
BIN = 1024,
107+
};
108+
104109
if (endptr != nullptr) {
105110
*endptr = str;
106111
}
@@ -117,39 +122,52 @@ unit_evaluate_dbl(const char *str, bool case_sensitive, const char **endptr)
117122
return NAN;
118123
}
119124
char unit_prefix = case_sensitive ? *endptr_tmp : toupper(*endptr_tmp);
125+
char *prefix_start = endptr_tmp;
120126
endptr_tmp += 1;
127+
double unit = SI;
128+
double mult = 1;
129+
if (endptr_tmp[0] == 'i' || (!case_sensitive && endptr_tmp[0] == 'I')) {
130+
endptr_tmp += 1;
131+
unit = BIN;
132+
}
121133
switch(unit_prefix) {
122134
case 'n':
123135
case 'N':
124-
ret /= 1000'000'000;
136+
mult = 1 / unit / unit / unit;
125137
break;
126138
case 'u':
127139
case 'U':
128-
ret /= 1000'000;
140+
mult = 1 / unit / unit;
129141
break;
130142
case 'm':
131-
ret /= 1000;
143+
mult = 1 / unit;
132144
break;
133145
case 'k':
134146
case 'K':
135-
ret *= 1000;
147+
mult = unit;
136148
break;
137149
case 'M':
138-
ret *= 1000'000LL;
150+
mult = unit * unit;
139151
break;
140152
case 'g':
141153
case 'G':
142-
ret *= 1000'000'000LL;
154+
mult = unit * unit * unit;
143155
break;
144156
default:
145-
endptr_tmp -= 1;
157+
endptr_tmp = prefix_start;
158+
}
159+
if (unit == BIN) { // sanity chwecks
160+
if ((case_sensitive && isupper(unit_prefix)) // eg. GI
161+
|| mult < 1) { // binary prefixes <1 undefined
162+
mult = 1;
163+
endptr_tmp = prefix_start;
164+
}
146165
}
147-
148166
if (endptr != nullptr) {
149167
*endptr = endptr_tmp;
150168
}
151169

152-
return ret;
170+
return ret * mult;
153171
}
154172

155173
/**

test/misc_test.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <climits>
12
#include <cstring> // for strcmp
23
#include <cmath> // for abs
34
#include <list>
@@ -6,6 +7,7 @@
67

78
#include "color.h"
89
#include "types.h"
10+
#include "utils/misc.h"
911
#include "utils/net.h"
1012
#include "utils/string.h"
1113
#include "unit_common.h"
@@ -18,6 +20,7 @@ int misc_test_net_getsockaddr();
1820
int misc_test_net_sockaddr_compare_v4_mapped();
1921
int misc_test_replace_all();
2022
int misc_test_video_desc_io_op_symmetry();
23+
int misc_test_unit_evaluate();
2124
}
2225

2326
using namespace std;
@@ -134,6 +137,35 @@ int misc_test_replace_all()
134137
return 0;
135138
}
136139

140+
int misc_test_unit_evaluate()
141+
{
142+
struct {
143+
const char *str;
144+
long long exp_val;
145+
const char *exp_endstr; // value, not ptr
146+
} test_cases[] = {
147+
{ "1", 1, "" },
148+
{ "1M", 1000 * 1000, "" },
149+
{ "1.2M", 1200 * 1000, "" },
150+
{ "0.5Gi", 512 * 1024 * 1024, "" },
151+
// partially parsed
152+
{ "1x", 1, "x" },
153+
// errors
154+
{ "x", LLONG_MIN, "x" },
155+
{ "Gi", LLONG_MIN, "Gi" },
156+
};
157+
158+
for (unsigned i = 0; i < sizeof test_cases / sizeof test_cases[0];
159+
++i) {
160+
const char *endptr = nullptr;
161+
long long val = unit_evaluate(test_cases[i].str, &endptr);
162+
ASSERT_EQUAL(test_cases[i].exp_val, val);
163+
ASSERT_EQUAL_STR(test_cases[i].exp_endstr, endptr);
164+
}
165+
166+
return 0;
167+
}
168+
137169
int misc_test_video_desc_io_op_symmetry()
138170
{
139171
const std::list<video_desc> test_desc = {

test/run_tests.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ DECLARE_TEST(misc_test_color_coeff_range);
9090
DECLARE_TEST(misc_test_net_getsockaddr);
9191
DECLARE_TEST(misc_test_net_sockaddr_compare_v4_mapped);
9292
DECLARE_TEST(misc_test_replace_all);
93+
DECLARE_TEST(misc_test_unit_evaluate);
9394
DECLARE_TEST(misc_test_video_desc_io_op_symmetry);
9495

9596
struct {
@@ -126,6 +127,7 @@ struct {
126127
DEFINE_TEST(misc_test_net_getsockaddr),
127128
DEFINE_TEST(misc_test_net_sockaddr_compare_v4_mapped),
128129
DEFINE_TEST(misc_test_replace_all),
130+
DEFINE_TEST(misc_test_unit_evaluate),
129131
DEFINE_TEST(misc_test_video_desc_io_op_symmetry),
130132
};
131133

test/unit_common.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
#include <cinttypes>
66
#include <cstdio>
77
#include <iostream>
8+
#include <string>
89
#else
910
#include <inttypes.h>
1011
#include <stdio.h>
12+
#include <string.h>
1113
#endif
1214

1315
#define ASSERT(expr) \
@@ -38,6 +40,13 @@
3840
<< ", actual : " << (actual) << "\n"; \
3941
return -1; \
4042
}
43+
/// compares cstr or std::string value
44+
#define ASSERT_EQUAL_STR(expected, actual) \
45+
if (std::string(expected) != std::string(actual)) { \
46+
std::cerr << "Assertion failed - expected \"" << (expected) \
47+
<< "\", actual : \"" << (actual) << "\"\n"; \
48+
return -1; \
49+
}
4150
#else
4251
#define ASSERT_EQUAL(expected, actual) \
4352
if ((expected) != (actual)) { \
@@ -47,6 +56,15 @@
4756
(intmax_t) (expected), (intmax_t) (actulal)); \
4857
return -1; \
4958
}
59+
/// compares cstr value
60+
#define ASSERT_EQUAL_STR(expected, actual) \
61+
if (strcmp((expected), (actual)) != 0) { \
62+
fprintf(stderr, \
63+
"Assertion failed - expected \"%s\"" \
64+
", actual \"%s\"\n", \
65+
(expected), (actulal)); \
66+
return -1; \
67+
}
5068
#endif
5169

5270
#ifdef __cplusplus

0 commit comments

Comments
 (0)