Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ARROW-12657: [C++] Adding String hex to numeric conversion #11064

Closed
wants to merge 94 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
59dcbde
working implementation but lacks case-insensitivity and more unit tests
wmalpica Sep 1, 2021
4cb862b
different algorithm. Added more tests and benchmarks
wmalpica Sep 2, 2021
d03b7eb
uncommented tests
wmalpica Sep 2, 2021
69972dd
ARROW-13792 [Java]: The toString representation is incorrect for unsi…
liyafan82 Sep 2, 2021
b76caf4
ARROW-13544 [Java]: Remove APIs that have been deprecated for long (C…
liyafan82 Sep 2, 2021
111f0c7
ARROW-13823 [Java]: Exclude .factorypath
laurentgo Sep 2, 2021
09497a9
ARROW-13544 [Java]: Remove APIs that have been deprecated for long (C…
liyafan82 Sep 2, 2021
e380c1a
ARROW-13812: [C++] Fix Valgrind error in Grouper.BooleanKey test
lidavidm Sep 2, 2021
bbecb6a
ARROW-13067: [C++][Compute] Implement integer to decimal cast
cyb70289 Sep 2, 2021
495c734
ARROW-13846: [C++] Fix crashes on invalid IPC file
pitrou Sep 2, 2021
425b1cb
ARROW-13850: [C++] Fix crashes on invalid Parquet data
pitrou Sep 2, 2021
f0879a5
ARROW-13164: [R] altrep vectors from Array with nulls
romainfrancois Sep 2, 2021
8c70a5f
ARROW-13459: [C++][Docs]Missing param docs for RecordBatch::SetColumn
zhjwpku Sep 2, 2021
a1d207e
ARROW-13831: [GLib][Ruby] Add support for writing by Arrow Dataset
kou Sep 2, 2021
1440d5a
ARROW-13768: [R] Allow JSON to be an optional component
karldw Sep 3, 2021
a45fc3f
ARROW-13782: [C++] Add skip_nulls/min_count to tdigest/mode/quantile
lidavidm Sep 3, 2021
5ead375
ARROW-13855: [C++][Python] Implement C data interface support for ext…
pitrou Sep 3, 2021
e9251b0
ARROW-13740: [R] summarize() should not eagerly evaluate
nealrichardson Sep 3, 2021
858ac57
ARROW-13874: [R] Implement TrimOptions
thisisnic Sep 3, 2021
a49048b
ARROW-13543: [R] Handle summarize() with 0 arguments or no aggregate …
nealrichardson Sep 3, 2021
f12c18e
ARROW-13899: [Ruby] Implement slicer by compute kernels
kou Sep 4, 2021
882e8b4
MINOR: [Doc][Python] Fix a typo (#11085)
jjyao Sep 4, 2021
5d38723
ARROW-13909: [GLib] Add GArrowVarianceOptions
kou Sep 5, 2021
2588e17
ARROW-13909: [GLib] Add tests for GArrowVarianceOptions
kou Sep 5, 2021
c83db7e
ARROW-13793: [C++] Migrate ORCFileReader to Result<T>
zhjwpku Sep 6, 2021
5c5af6c
ARROW-13871: [C++] JSON reader can fail if a list array key is presen…
westonpace Sep 6, 2021
a8953de
ARROW-13845: [C++] Reconcile RandomArrayGenerator::ArrayOf implementa…
pitrou Sep 6, 2021
4390a64
ARROW-13857: [R][CI] Remove checkbashisms download
nealrichardson Sep 6, 2021
cf0e5e4
ARROW-13803: [C++] Don't read past end of buffer in BitUtil::SetBitmap
cyb70289 Sep 6, 2021
b1cfa7d
ARROW-13912: [R] TrimOptions implementation breaks test-r-minimal-bui…
nealrichardson Sep 6, 2021
303b7f4
ARROW-13915: [R][CI] R UCRT C++ bundles are incomplete
nealrichardson Sep 6, 2021
fd47183
ARROW-13913: [C++] Don't segfault if IndexOptions omitted
lidavidm Sep 6, 2021
02343c8
ARROW-13684: [C++][Compute] Strftime kernel follow-up
rok Sep 6, 2021
5876e3f
ARROW-13403: [R] Update developing.Rmd vignette
thisisnic Sep 6, 2021
4cb77a2
ARROW-13910: [Ruby] Arrow::Table#[]/Arrow::RecordBatch#[] accepts Ran…
kou Sep 6, 2021
67b5bd2
ARROW-13743: [CI] OSX job fails due to incompatible git and libcurl
kszucs Sep 7, 2021
6dc272a
ARROW-13810: [C++][Compute] Predicate IsAsciiCharacter allows invalid…
edponce Sep 7, 2021
6c7c4f0
ARROW-13671: [Dev] Fix conda recipe on Arm 64k page system
cyb70289 Sep 7, 2021
9064fa0
ARROW-12981: [R] Install source package from CRAN alone
karldw Sep 7, 2021
080a86b
Implemented review feedback and added more unit tests
wmalpica Sep 7, 2021
f40856a
ARROW-13925: [R] Remove system installation devdocs jobs
jonkeane Sep 7, 2021
85d8175
ARROW-13919: [GLib] Add GArrowFunctionDoc
kou Sep 7, 2021
e396d4f
ARROW-13872: [Java] ExtensionTypeVector does not work with RangeEqual…
BryanCutler Sep 8, 2021
57e76e8
ARROW-13921: [Python][Packaging] Pin minimum setuptools version for t…
kszucs Sep 8, 2021
97135bc
Docs + lintr fix (#11107)
jonkeane Sep 8, 2021
a081a05
checked for empty hex falues. added scalar tests
wmalpica Sep 8, 2021
170a24f
ARROW-13820: [R] Rename na.min_count to min_count and na.rm to skip_n…
nealrichardson Sep 8, 2021
7a23a07
fixed style with clang-format
wmalpica Sep 8, 2021
e5db0fc
MINOR: [R] Fix broken doc example (#11110)
nealrichardson Sep 8, 2021
9dd8b6a
implemented some improvements
wmalpica Sep 8, 2021
31f80e5
fixed clang format
wmalpica Sep 8, 2021
4666073
fixed unit test
wmalpica Sep 8, 2021
b0d89db
ARROW-13680: [C++] Create an asynchronous nursery to simplify capture…
westonpace Sep 9, 2021
4b5ed4e
ARROW-13138: [C++][R] Implement extract temporal components (year, mo…
aucahuasi Sep 9, 2021
bb1ef85
ARROW-13033: [C++] Kernel to localize naive timestamps to a timezone …
rok Sep 9, 2021
9aee524
ARROW-11885: [R] Turn off some capabilities when LIBARROW_MINIMAL=true
nealrichardson Sep 9, 2021
0c41e0b
ARROW-13842: [C++] Bump vendored date library
pitrou Sep 9, 2021
946bdcf
ARROW-13963: [Go] Minor: Add bitmap reader/writer impl from go Parque…
Sep 9, 2021
4fe6fae
ARROW-13961: [C++] Fix use of non-const references, declaration witho…
lidavidm Sep 9, 2021
66d7dd4
ARROW-13962: [R] Catch up on the NEWS
nealrichardson Sep 9, 2021
04515de
MINOR: [R] Exclude some paths from the cpp rsync
nealrichardson Sep 9, 2021
56411f5
ARROW-13940: [R] Turn on multithreading with Arrow engine queries
nealrichardson Sep 9, 2021
42d10c3
ARROW-13964: MINOR: [Go][Parquet] remove base bitmap reader/writer fr…
Sep 9, 2021
3bbec3f
ARROW-13942: [Dev] Update cmake_format usage in autotune comment bot
kou Sep 10, 2021
3db4854
ARROW-13778: [R] Handle complex summarize expressions
nealrichardson Sep 10, 2021
fa7cff6
ARROW-1565: [C++] Implement TopK/BottomK
aocsa Sep 10, 2021
bae7e2b
MINOR: [Doc][Python] Fix typo ParquetFileForma (#11137)
domoritz Sep 11, 2021
db5b848
ARROW-13979: [Go] Enable -race for go tests
Sep 12, 2021
c091e6d
ARROW-13859: [Java] Add code coverage support
laurentgo Sep 12, 2021
e8ab3ae
ARROW-13733 [Java]: Allow JDBC adapters to reuse vector schema roots
liyafan82 Sep 12, 2021
1049dde
ARROW-13544 [Java]: Remove APIs that have been deprecated for long (C…
liyafan82 Sep 12, 2021
74f020d
ARROW-13974: [C++] Resolve follow-up reviews for TopK/BottomK
aocsa Sep 13, 2021
293f856
ARROW-13966: [C++] Support decimals in comparisons
lidavidm Sep 13, 2021
9122149
ARROW-13937: [C++][Compute] Add explicit output values to sign functi…
edponce Sep 13, 2021
f2cb977
ARROW-13646: [Go][Parquet] adding the parquet metadata package
Sep 13, 2021
dfaa415
ARROW-13983: [C++] Avoid raising error if fadvise() isn't supported
pitrou Sep 13, 2021
0610998
ARROW-13978: [C++] Bump gtest to 1.11 to unbreak builds with recent c…
pitrou Sep 13, 2021
52904d6
ARROW-13958: [Python] Migrate Python ORC bindings to use new Result-b…
jorisvandenbossche Sep 13, 2021
376cb45
ARROW-12744: [C++][Compute] Add rounding kernel
edponce Sep 13, 2021
87b2fcd
ARROW-12087: [C++] Allow sorting durations, timestamps with timezones
lidavidm Sep 13, 2021
1cbc4a2
ARROW-13904: [R] Implement ModeOptions
thisisnic Sep 13, 2021
f3d3c68
ARROW-13905: [R] Implement ReplaceSliceOptions
thisisnic Sep 14, 2021
0b6f531
ARROW-13906: [R] Implement PartitionNthOptions
thisisnic Sep 14, 2021
672149b
ARROW-13869: [R] Implement options for non-bound MatchSubstringOption…
thisisnic Sep 14, 2021
8875d5c
ARROW-13908: [R] Implement ExtractRegexOptions
thisisnic Sep 14, 2021
f1d6811
working implementation but lacks case-insensitivity and more unit tests
wmalpica Sep 1, 2021
925b2a7
different algorithm. Added more tests and benchmarks
wmalpica Sep 2, 2021
68ec4db
Implemented review feedback and added more unit tests
wmalpica Sep 7, 2021
a538072
checked for empty hex falues. added scalar tests
wmalpica Sep 8, 2021
400d886
fixed style with clang-format
wmalpica Sep 8, 2021
9cac060
implemented some improvements
wmalpica Sep 8, 2021
6053936
fixed clang format
wmalpica Sep 8, 2021
68a6844
fixed unit test
wmalpica Sep 8, 2021
7aee4f0
Merge branch 'wmalpica/ARROW-12657' of github.com:wmalpica/arrow into…
wmalpica Sep 14, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
118 changes: 118 additions & 0 deletions cpp/src/arrow/util/value_parsing.h
Expand Up @@ -273,6 +273,96 @@ inline bool ParseUnsigned(const char* s, size_t length, uint64_t* out) {
#undef PARSE_UNSIGNED_ITERATION
#undef PARSE_UNSIGNED_ITERATION_LAST

#define PARSE_HEX_ITERATION(C_TYPE) \
if (length > 0) { \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to make this a function. The use of macros is undesired in the general case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this recommendation. I was following the pattern of how ParseUnsigned and PARSE_UNSIGNED_ITERATION is done in the same file. Since I am new to the codebase I decided to follow the patterns I was seeing.

char val = *s; \
s++; \
result = static_cast<C_TYPE>(result << 4); \
length--; \
if (val >= '0' && val <= '9'){ \
result = static_cast<C_TYPE>(result | (val -'0')); \
} else if (val >= 'A' && val <= 'F'){ \
result = static_cast<C_TYPE>(result | (val -'A' + 10)); \
} else if (val >= 'a' && val <= 'f'){ \
result = static_cast<C_TYPE>(result | (val -'a' + 10)); \
} else { \
/* Non-digit */ \
return false; \
} \
} else { \
break; \
}


inline bool ParseHex(const char* s, size_t length, uint8_t* out) {
uint8_t result = 0;
Copy link
Contributor

@edponce edponce Sep 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of having multiple functions for each type, I suggest to use templates, and, given that each function is conceptually doing the same operation but different number of times based on the output data type width, use a for-loop instead.

template <typename T>
inline bool ParseHex(...) {
   ...
   for (int i = 0; i < sizeof(T) * 2; ++i) {
      ParseHexIteration<T>(result);
   }
   ...
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you prefer, but I would be fine with keeping this a macro in this case. Note there is a control flow inside the macro so you cannot turn it into such a trivial loop.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I turned it into a loop, it works fine


do {
PARSE_HEX_ITERATION(uint8_t);
PARSE_HEX_ITERATION(uint8_t);
} while (false);
*out = result;
return true;
}

inline bool ParseHex(const char* s, size_t length, uint16_t* out) {
uint16_t result = 0;
do {
PARSE_HEX_ITERATION(uint16_t);
PARSE_HEX_ITERATION(uint16_t);
PARSE_HEX_ITERATION(uint16_t);
PARSE_HEX_ITERATION(uint16_t);
} while (false);
*out = result;
return true;
}

inline bool ParseHex(const char* s, size_t length, uint32_t* out) {
uint32_t result = 0;
do {
PARSE_HEX_ITERATION(uint32_t);
PARSE_HEX_ITERATION(uint32_t);
PARSE_HEX_ITERATION(uint32_t);
PARSE_HEX_ITERATION(uint32_t);

PARSE_HEX_ITERATION(uint32_t);
PARSE_HEX_ITERATION(uint32_t);
PARSE_HEX_ITERATION(uint32_t);
PARSE_HEX_ITERATION(uint32_t);
} while (false);
*out = result;
return true;
}

inline bool ParseHex(const char* s, size_t length, uint64_t* out) {
uint64_t result = 0;
do {
PARSE_HEX_ITERATION(uint64_t);
PARSE_HEX_ITERATION(uint64_t);
PARSE_HEX_ITERATION(uint64_t);
PARSE_HEX_ITERATION(uint64_t);

PARSE_HEX_ITERATION(uint64_t);
PARSE_HEX_ITERATION(uint64_t);
PARSE_HEX_ITERATION(uint64_t);
PARSE_HEX_ITERATION(uint64_t);

PARSE_HEX_ITERATION(uint64_t);
PARSE_HEX_ITERATION(uint64_t);
PARSE_HEX_ITERATION(uint64_t);
PARSE_HEX_ITERATION(uint64_t);

PARSE_HEX_ITERATION(uint64_t);
PARSE_HEX_ITERATION(uint64_t);
PARSE_HEX_ITERATION(uint64_t);
PARSE_HEX_ITERATION(uint64_t);
} while (false);
*out = result;
return true;
}

#undef PARSE_HEX_ITERATION

template <class ARROW_TYPE>
struct StringToUnsignedIntConverterMixin {
using value_type = typename ARROW_TYPE::c_type;
Expand All @@ -281,6 +371,19 @@ struct StringToUnsignedIntConverterMixin {
if (ARROW_PREDICT_FALSE(length == 0)) {
return false;
}
// If its starts with 0x then its hex
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"it", "it's"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

if (*s == '0' && *(s + 1) == 'x'){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add support for case-insensitive 0x.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

length -= 2;
s += 2;
// lets make sure that the length of the string is not too big
Copy link
Contributor

@edponce edponce Sep 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: You probably not need to decrease length and consider the offset of s as the difference to consider.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opted not to do this, since length is used both at StringToSignedIntConverterMixin and at ParseHex. Getting rid of length would then involve keeping track of the original pointer of s and the new pointer and comparing that to the original length. It seems more convoluted

if (!ARROW_PREDICT_TRUE(sizeof(value_type)*2 >= length)) {
return false;
}
if (!ARROW_PREDICT_TRUE(ParseHex(s, length, out))) {
return false;
}
return true;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can simplify these checks and boolean result as

return ARROW_PREDICT_TRUE((sizeof(value_type) * 2 >= length) && ParseHex(s, length, out));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// Skip leading zeros
while (length > 0 && *s == '0') {
length--;
Expand Down Expand Up @@ -336,6 +439,21 @@ struct StringToSignedIntConverterMixin {
return false;
}
}

// If its starts with 0x then its hex
if (*s == '0' && *(s + 1) == 'x'){
length -= 2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is a negative sign, then it is not a well-formed hex string.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Fixed this

s += 2;
// lets make sure that the length of the string is not too big
if (!ARROW_PREDICT_TRUE(sizeof(unsigned_value)*2 >= length)) {
return false;
}
if (!ARROW_PREDICT_TRUE(ParseHex(s, length, &unsigned_value))) {
return false;
}
*out = static_cast<value_type>(unsigned_value);
return true;
}
// Skip leading zeros
while (length > 0 && *s == '0') {
length--;
Expand Down
51 changes: 51 additions & 0 deletions cpp/src/arrow/util/value_parsing_benchmark.cc
Expand Up @@ -56,6 +56,29 @@ static std::vector<std::string> MakeIntStrings(int32_t num_items) {
return strings;
}

template <typename c_int>
static std::vector<std::string> MakeHexStrings(int32_t num_items) {
int32_t num_bytes = sizeof(c_int);
const char* kAsciiTable = "0123456789ABCDEF";
std::vector<char> large_hex_chars(num_bytes*2 + 2);
large_hex_chars[0]='0';
large_hex_chars[1]='x';
for (int32_t i = 0; i < num_bytes*2; ++i) {
large_hex_chars[i + 2] = kAsciiTable[i];
}
std::string large_hex(&large_hex_chars[0], large_hex_chars.size());

std::vector<std::string> base_strings = {"0x0",
"0xA5",
"0x5E",
large_hex};
std::vector<std::string> strings;
for (int32_t i = 0; i < num_items; ++i) {
strings.push_back(base_strings[i % base_strings.size()]);
}
return strings;
}

static std::vector<std::string> MakeFloatStrings(int32_t num_items) {
std::vector<std::string> base_strings = {"0.0", "5", "-12.3",
"98765430000", "3456.789", "0.0012345",
Expand Down Expand Up @@ -123,6 +146,25 @@ static void IntegerParsing(benchmark::State& state) { // NOLINT non-const refer
state.SetItemsProcessed(state.iterations() * strings.size());
}

template <typename ARROW_TYPE, typename C_TYPE = typename ARROW_TYPE::c_type>
static void HexParsing(benchmark::State& state) { // NOLINT non-const reference
auto strings = MakeHexStrings<C_TYPE>(1000);

while (state.KeepRunning()) {
C_TYPE total = 0;
for (const auto& s : strings) {
C_TYPE value;
if (!ParseValue<ARROW_TYPE>(s.data(), s.length(), &value)) {
std::cerr << "Conversion failed for '" << s << "'";
std::abort();
}
total = static_cast<C_TYPE>(total + value);
}
benchmark::DoNotOptimize(total);
}
state.SetItemsProcessed(state.iterations() * strings.size());
}

template <typename ARROW_TYPE, typename C_TYPE = typename ARROW_TYPE::c_type>
static void FloatParsing(benchmark::State& state) { // NOLINT non-const reference
auto strings = MakeFloatStrings(1000);
Expand Down Expand Up @@ -230,6 +272,15 @@ BENCHMARK_TEMPLATE(IntegerParsing, UInt16Type);
BENCHMARK_TEMPLATE(IntegerParsing, UInt32Type);
BENCHMARK_TEMPLATE(IntegerParsing, UInt64Type);

BENCHMARK_TEMPLATE(HexParsing, Int8Type);
BENCHMARK_TEMPLATE(HexParsing, Int16Type);
BENCHMARK_TEMPLATE(HexParsing, Int32Type);
BENCHMARK_TEMPLATE(HexParsing, Int64Type);
BENCHMARK_TEMPLATE(HexParsing, UInt8Type);
BENCHMARK_TEMPLATE(HexParsing, UInt16Type);
BENCHMARK_TEMPLATE(HexParsing, UInt32Type);
BENCHMARK_TEMPLATE(HexParsing, UInt64Type);

BENCHMARK_TEMPLATE(FloatParsing, FloatType);
BENCHMARK_TEMPLATE(FloatParsing, DoubleType);

Expand Down
69 changes: 69 additions & 0 deletions cpp/src/arrow/util/value_parsing_test.cc
Expand Up @@ -120,6 +120,14 @@ TEST(StringConversion, ToInt8) {
AssertConversionFails<Int8Type>("-");
AssertConversionFails<Int8Type>("0.0");
AssertConversionFails<Int8Type>("e");

// Hex
AssertConversion<Int8Type>("0x0", 0);
AssertConversion<Int8Type>("0x1A", 26);
AssertConversion<Int8Type>("0xb", 11);
AssertConversion<Int8Type>("0x7F", 127);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if I pass 0x80 or higher? Does it work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added unit test for this case

AssertConversionFails<Int8Type>("0x100");
AssertConversionFails<Int8Type>("0x1g");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you check that 0x is not a valid hex value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added unit test for this case

}

TEST(StringConversion, ToUInt8) {
Expand All @@ -138,6 +146,14 @@ TEST(StringConversion, ToUInt8) {
AssertConversionFails<UInt8Type>("-");
AssertConversionFails<UInt8Type>("0.0");
AssertConversionFails<UInt8Type>("e");

// Hex
AssertConversion<UInt8Type>("0x0", 0);
AssertConversion<UInt8Type>("0x1A", 26);
AssertConversion<UInt8Type>("0xb", 11);
AssertConversion<UInt8Type>("0x7F", 127);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question re. 0x80.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added unit test for this case

AssertConversionFails<UInt8Type>("0x100");
AssertConversionFails<UInt8Type>("0x1g");
}

TEST(StringConversion, ToInt16) {
Expand All @@ -155,6 +171,14 @@ TEST(StringConversion, ToInt16) {
AssertConversionFails<Int16Type>("-");
AssertConversionFails<Int16Type>("0.0");
AssertConversionFails<Int16Type>("e");

// Hex
AssertConversion<Int16Type>("0x0", 0);
AssertConversion<Int16Type>("0x1aA", 426);
AssertConversion<Int16Type>("0xb", 11);
AssertConversion<Int16Type>("0x7ffF", 32767);
AssertConversionFails<Int16Type>("0x10000");
AssertConversionFails<Int16Type>("0x1g");
}

TEST(StringConversion, ToUInt16) {
Expand All @@ -172,6 +196,14 @@ TEST(StringConversion, ToUInt16) {
AssertConversionFails<UInt16Type>("-");
AssertConversionFails<UInt16Type>("0.0");
AssertConversionFails<UInt16Type>("e");

// Hex
AssertConversion<UInt16Type>("0x0", 0);
AssertConversion<UInt16Type>("0x1aA", 426);
AssertConversion<UInt16Type>("0xb", 11);
AssertConversion<UInt16Type>("0x7ffF", 32767);
AssertConversionFails<UInt16Type>("0x10000");
AssertConversionFails<UInt16Type>("0x1g");
}

TEST(StringConversion, ToInt32) {
Expand All @@ -189,6 +221,17 @@ TEST(StringConversion, ToInt32) {
AssertConversionFails<Int32Type>("-");
AssertConversionFails<Int32Type>("0.0");
AssertConversionFails<Int32Type>("e");

// Hex
AssertConversion<Int32Type>("0x0", 0);
AssertConversion<Int32Type>("0x123ABC", 1194684);
AssertConversion<Int32Type>("0xA4B35", 674613);
AssertConversion<Int32Type>("0x7FFFFFFF", 2147483647);
AssertConversion<Int32Type>("0x123abc", 1194684);
AssertConversion<Int32Type>("0xA4b35", 674613);
AssertConversion<Int32Type>("0x7FFFfFfF", 2147483647);
AssertConversionFails<Int32Type>("0x23512ak");

}

TEST(StringConversion, ToUInt32) {
Expand All @@ -206,6 +249,16 @@ TEST(StringConversion, ToUInt32) {
AssertConversionFails<UInt32Type>("-");
AssertConversionFails<UInt32Type>("0.0");
AssertConversionFails<UInt32Type>("e");

// Hex
AssertConversion<UInt32Type>("0x0", 0);
AssertConversion<UInt32Type>("0x123ABC", 1194684);
AssertConversion<UInt32Type>("0xA4B35", 674613);
AssertConversion<UInt32Type>("0x7FFFFFFF", 2147483647);
AssertConversion<UInt32Type>("0x123abc", 1194684);
AssertConversion<UInt32Type>("0xA4b35", 674613);
AssertConversion<UInt32Type>("0x7FFFfFfF", 2147483647);
AssertConversionFails<UInt32Type>("0x23512ak");
}

TEST(StringConversion, ToInt64) {
Expand All @@ -223,6 +276,14 @@ TEST(StringConversion, ToInt64) {
AssertConversionFails<Int64Type>("-");
AssertConversionFails<Int64Type>("0.0");
AssertConversionFails<Int64Type>("e");

// Hex
AssertConversion<Int64Type>("0x0", 0);
AssertConversion<Int64Type>("0x5415a123ABC123cb", 6058926048274359243);
AssertConversion<Int64Type>("0xA4B35", 674613);
AssertConversion<Int64Type>("0x7FFFFFFFFFFFFFFf", 9223372036854775807);
AssertConversionFails<Int64Type>("0x12345678901234567");
AssertConversionFails<Int64Type>("0x23512ak");
}

TEST(StringConversion, ToUInt64) {
Expand All @@ -237,6 +298,14 @@ TEST(StringConversion, ToUInt64) {
AssertConversionFails<UInt64Type>("-");
AssertConversionFails<UInt64Type>("0.0");
AssertConversionFails<UInt64Type>("e");

// Hex
AssertConversion<UInt64Type>("0x0", 0);
AssertConversion<UInt64Type>("0x5415a123ABC123cb", 6058926048274359243);
AssertConversion<UInt64Type>("0xA4B35", 674613);
AssertConversion<UInt64Type>("0x7FFFFFFFFFFFFFFf", 9223372036854775807);
AssertConversionFails<UInt64Type>("0x12345678901234567");
AssertConversionFails<UInt64Type>("0x23512ak");
}

TEST(StringConversion, ToDate32) {
Expand Down