Skip to content

Commit 865ef12

Browse files
committed
- Renamed Nat literal from _uarb to _nat
- Put literals in their own sub-namespace with usage instructions
1 parent 6e705b1 commit 865ef12

File tree

4 files changed

+88
-75
lines changed

4 files changed

+88
-75
lines changed

arby/include/arby/Nat.hpp

Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -646,47 +646,59 @@ namespace com::saxbophone::arby {
646646
};
647647

648648
/**
649-
* @brief raw user-defined-literal for Nat class
650-
* @param literal the literal
651-
* @returns Corresponding arby::Nat value
652-
* @note we use a raw literal in this case because as the Nat type is
653-
* unbounded, we want to support a potentially infinite number of digits,
654-
* or certainly more than can be stored in unsigned long long...
649+
* @brief Various custom user-defined-literals for creating arby objects
650+
* @note You need to introduce this namespace into global scope with
651+
* `using namespace com::saxbophone::arby::literals` in order to be able
652+
* to use these literals in your code e.g. `arby::Nat f = 12345_nat`
653+
* This can be done without bringing the whole of arby into global scope
654+
* and these literals are provided in a sub-namespace for this exact reason
655+
* @todo Maybe we should also import this namespace into arby's so that
656+
* users get literals in global scope when they put arby into global scope
655657
*/
656-
constexpr Nat operator "" _uarb(const char* literal) {
657-
// detect number base
658-
std::uint8_t base = 10; // base-10 is the fallback base
659-
if (literal[0] == '0' and literal[1] != 0) { // first digit 0, second non-null, maybe a 0x/0b prefix?
660-
switch (literal[1]) {
661-
case 'X': // hexadecimal
662-
case 'x':
663-
base = 16;
664-
// advance string pointer to skip the prefix
665-
literal = literal + 2;
666-
break;
667-
case 'B': // binary
668-
case 'b':
669-
base = 2;
670-
literal = literal + 2;
671-
break;
672-
default: // not allowed --we don't support 0-prefixed octal literals or anything else
673-
throw std::invalid_argument("invalid arby::Nat literal");
658+
namespace literals {
659+
/**
660+
* @brief raw user-defined-literal for Nat class
661+
* @param literal the literal
662+
* @returns Corresponding arby::Nat value
663+
* @note we use a raw literal in this case because as the Nat type is
664+
* unbounded, we want to support a potentially infinite number of digits,
665+
* or certainly more than can be stored in unsigned long long...
666+
*/
667+
constexpr Nat operator "" _nat(const char* literal) {
668+
// detect number base
669+
std::uint8_t base = 10; // base-10 is the fallback base
670+
if (literal[0] == '0' and literal[1] != 0) { // first digit 0, second non-null, maybe a 0x/0b prefix?
671+
switch (literal[1]) {
672+
case 'X': // hexadecimal
673+
case 'x':
674+
base = 16;
675+
// advance string pointer to skip the prefix
676+
literal = literal + 2;
677+
break;
678+
case 'B': // binary
679+
case 'b':
680+
base = 2;
681+
literal = literal + 2;
682+
break;
683+
default: // not allowed --we don't support 0-prefixed octal literals or anything else
684+
throw std::invalid_argument("invalid arby::Nat literal");
685+
}
674686
}
687+
Nat value; // accumulator
688+
// consume digits
689+
while (*literal != 0) { // until null-terminator is found
690+
std::uint8_t digit = (std::uint8_t)*literal; // get character
691+
// when dealing with digits, subtract 32 from any after 'Z' to convert lowercase to upper
692+
if (digit > 'Z') { digit -= 32; }
693+
// calculate digit's value, handling the two contiguous ranges of 0-9 and A-F
694+
std::uint8_t digit_value = digit >= 'A' ? (digit - 'A') + 10 : digit - '0';
695+
// add to accumulator and then shift it up
696+
value *= base;
697+
value += digit_value;
698+
literal++; // next character
699+
}
700+
return value;
675701
}
676-
Nat value; // accumulator
677-
// consume digits
678-
while (*literal != 0) { // until null-terminator is found
679-
std::uint8_t digit = (std::uint8_t)*literal; // get character
680-
// when dealing with digits, subtract 32 from any after 'Z' to convert lowercase to upper
681-
if (digit > 'Z') { digit -= 32; }
682-
// calculate digit's value, handling the two contiguous ranges of 0-9 and A-F
683-
std::uint8_t digit_value = digit >= 'A' ? (digit - 'A') + 10 : digit - '0';
684-
// add to accumulator and then shift it up
685-
value *= base;
686-
value += digit_value;
687-
literal++; // next character
688-
}
689-
return value;
690702
}
691703
}
692704

arby/src/Nat.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
namespace com::saxbophone::arby {
1717
Nat::Nat(std::string digits)
1818
// use user-defined-literal to convert the digits in the string
19-
: _digits(operator "" _uarb(digits.c_str())._digits)
19+
: _digits(literals::operator "" _nat(digits.c_str())._digits)
2020
{}
2121

2222
std::string Nat::_stringify_for_base(std::uint8_t base) const {

tests/stringification.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include <arby/Nat.hpp>
88

99
using namespace com::saxbophone;
10-
using namespace com::saxbophone::arby;
10+
using namespace com::saxbophone::arby::literals;
1111

1212
TEST_CASE("Using std::ostream << arby::Nat generates decimal string of value", "[stringification]") {
1313
auto values = GENERATE(
@@ -45,11 +45,11 @@ TEST_CASE("Using std::ostream << std::hex << arby::Nat generates hexadecimal str
4545
auto values = GENERATE(
4646
table<arby::Nat, std::string>(
4747
{
48-
{0_uarb, "0"},
49-
{0x123456789_uarb, "123456789"},
48+
{0_nat, "0"},
49+
{0x123456789_nat, "123456789"},
5050
{0xcafebabe3362, "cafebabe3362"},
51-
{0x100f32a8d1_uarb, "100f32a8d1"},
52-
{0x900100390_uarb, "900100390"},
51+
{0x100f32a8d1_nat, "100f32a8d1"},
52+
{0x900100390_nat, "900100390"},
5353
{0xf503, "f503"},
5454
}
5555
)

tests/user_defined_literals.cpp

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,63 +7,64 @@
77

88
#include <arby/Nat.hpp>
99

10-
using namespace com::saxbophone::arby;
10+
using namespace com::saxbophone;
11+
using namespace com::saxbophone::arby::literals;
1112

12-
TEST_CASE("Initialising arby::Nat objects with decimal _uarb user-defined-literal", "[user-defined-literal]") {
13+
TEST_CASE("Initialising arby::Nat objects with decimal _nat user-defined-literal", "[user-defined-literal]") {
1314
auto [literal, object] = GENERATE(
14-
table<Nat, Nat>(
15+
table<arby::Nat, arby::Nat>(
1516
{
16-
{0_uarb, 0},
17-
{10_uarb, 10},
18-
{123_uarb, 123},
19-
{1234_uarb, 1234},
20-
{10000_uarb, 10000},
21-
{100000_uarb, 100000},
22-
{123456_uarb, 123456},
23-
{9999999_uarb, 9999999},
24-
{56213870_uarb, 56213870},
17+
{0_nat, 0},
18+
{10_nat, 10},
19+
{123_nat, 123},
20+
{1234_nat, 1234},
21+
{10000_nat, 10000},
22+
{100000_nat, 100000},
23+
{123456_nat, 123456},
24+
{9999999_nat, 9999999},
25+
{56213870_nat, 56213870},
2526
}
2627
)
2728
);
2829

2930
CHECK(literal == object);
3031
}
3132

32-
TEST_CASE("Initialising arby::Nat objects with hexadecimal _uarb user-defined-literal", "[user-defined-literal]") {
33+
TEST_CASE("Initialising arby::Nat objects with hexadecimal _nat user-defined-literal", "[user-defined-literal]") {
3334
auto [literal, object] = GENERATE(
34-
table<Nat, Nat>(
35+
table<arby::Nat, arby::Nat>(
3536
{
36-
{0x1172443_uarb, 0x1172443},
37-
{0x19721871_uarb, 0x19721871},
38-
{0x0_uarb, 0x0},
39-
{0xf3c1d28a_uarb, 0xf3c1d28a},
40-
{0x01234567_uarb, 0x01234567},
41-
{0x89abcdef_uarb, 0x89abcdef},
42-
{0xffffffff_uarb, 0xffffffff},
43-
{0xf00000e1_uarb, 0xf00000e1},
37+
{0x1172443_nat, 0x1172443},
38+
{0x19721871_nat, 0x19721871},
39+
{0x0_nat, 0x0},
40+
{0xf3c1d28a_nat, 0xf3c1d28a},
41+
{0x01234567_nat, 0x01234567},
42+
{0x89abcdef_nat, 0x89abcdef},
43+
{0xffffffff_nat, 0xffffffff},
44+
{0xf00000e1_nat, 0xf00000e1},
4445
}
4546
)
4647
);
4748

4849
CHECK(literal == object);
4950
}
5051

51-
TEST_CASE("Initialising arby::Nat objects with binary _uarb user-defined-literal", "[user-defined-literal]") {
52+
TEST_CASE("Initialising arby::Nat objects with binary _nat user-defined-literal", "[user-defined-literal]") {
5253
auto [literal, object] = GENERATE(
53-
table<Nat, Nat>(
54+
table<arby::Nat, arby::Nat>(
5455
{
55-
{0b0_uarb, 0b0},
56-
{0b1_uarb, 0b1},
57-
{0b11010010_uarb, 0b11010010},
58-
{0b1111111111111111111111111111_uarb, 0b1111111111111111111111111111},
59-
{0b1010011010100011110101110101_uarb, 0b1010011010100011110101110101},
56+
{0b0_nat, 0b0},
57+
{0b1_nat, 0b1},
58+
{0b11010010_nat, 0b11010010},
59+
{0b1111111111111111111111111111_nat, 0b1111111111111111111111111111},
60+
{0b1010011010100011110101110101_nat, 0b1010011010100011110101110101},
6061
}
6162
)
6263
);
6364

6465
CHECK(literal == object);
6566
}
6667

67-
TEST_CASE("Malformed octal _uarb literal throws std::invalid_argument") {
68-
CHECK_THROWS_AS(01234_uarb, std::invalid_argument);
68+
TEST_CASE("Malformed octal _nat literal throws std::invalid_argument") {
69+
CHECK_THROWS_AS(01234_nat, std::invalid_argument);
6970
}

0 commit comments

Comments
 (0)