Skip to content

Commit

Permalink
Use uint16_t instead of uint8_t for semver tokens (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
TylerJang27 committed May 27, 2023
1 parent 5b5e542 commit 02f52e9
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 43 deletions.
4 changes: 2 additions & 2 deletions example/basic_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ using namespace semver;

int main() {
constexpr version v_default;
static_assert(v_default == version(0, 1, 0, prerelease::none, 0));
static_assert(v_default == version(0, 1, 0, prerelease::none, std::nullopt));
std::cout << v_default << std::endl; // 0.1.0

constexpr version v1{1, 4, 3};
Expand All @@ -47,7 +47,7 @@ int main() {
v_s.from_string("1.2.3-rc.1");
std::string s1 = v_s.to_string();
std::cout << s1 << std::endl; // 1.2.3-rc.1
v_s.prerelease_number = 0;
v_s.prerelease_number = std::nullopt;
std::string s2 = v_s.to_string();
std::cout << s2 << std::endl; // 1.2.3-rc

Expand Down
81 changes: 52 additions & 29 deletions include/semver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ struct to_chars_result {
};
#endif

// Max version string length = 3(<major>) + 1(.) + 3(<minor>) + 1(.) + 3(<patch>) + 1(-) + 5(<prerelease>) + 1(.) + 3(<prereleaseversion>) = 21.
inline constexpr auto max_version_string_length = std::size_t{21};
// Max version string length = 5(<major>) + 1(.) + 5(<minor>) + 1(.) + 5(<patch>) + 1(-) + 5(<prerelease>) + 1(.) + 5(<prereleaseversion>) = 29.
inline constexpr auto max_version_string_length = std::size_t{29};

namespace detail {

Expand Down Expand Up @@ -153,12 +153,24 @@ constexpr bool is_letter(char c) noexcept {
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}

constexpr std::uint8_t to_digit(char c) noexcept {
return static_cast<std::uint8_t>(c - '0');
constexpr std::uint16_t to_digit(char c) noexcept {
return static_cast<std::uint16_t>(c - '0');
}

constexpr std::uint8_t length(std::uint8_t x) noexcept {
return x < 10 ? 1 : (x < 100 ? 2 : 3);
constexpr std::uint8_t length(std::uint16_t x) noexcept {
if (x < 10) {
return 1;
}
if (x < 100) {
return 2;
}
if (x < 1000) {
return 3;
}
if (x < 10000) {
return 4;
}
return 5;
}

constexpr std::uint8_t length(prerelease t) noexcept {
Expand All @@ -183,7 +195,7 @@ constexpr bool equals(const char* first, const char* last, std::string_view str)
return true;
}

constexpr char* to_chars(char* str, std::uint8_t x, bool dot = true) noexcept {
constexpr char* to_chars(char* str, std::uint16_t x, bool dot = true) noexcept {
do {
*(--str) = static_cast<char>('0' + (x % 10));
x /= 10;
Expand Down Expand Up @@ -215,29 +227,29 @@ constexpr char* to_chars(char* str, prerelease t) noexcept {
return str;
}

constexpr const char* from_chars(const char* first, const char* last, std::uint8_t& d) noexcept {
constexpr const char* from_chars(const char* first, const char* last, std::uint16_t& d) noexcept {
if (first != last && is_digit(*first)) {
std::int32_t t = 0;
for (; first != last && is_digit(*first); ++first) {
t = t * 10 + to_digit(*first);
}
if (t <= (std::numeric_limits<std::uint8_t>::max)()) {
d = static_cast<std::uint8_t>(t);
if (t <= (std::numeric_limits<std::uint16_t>::max)()) {
d = static_cast<std::uint16_t>(t);
return first;
}
}

return nullptr;
}

constexpr const char* from_chars(const char* first, const char* last, std::optional<std::uint8_t>& d) noexcept {
constexpr const char* from_chars(const char* first, const char* last, std::optional<std::uint16_t>& d) noexcept {
if (first != last && is_digit(*first)) {
std::int32_t t = 0;
for (; first != last && is_digit(*first); ++first) {
t = t * 10 + to_digit(*first);
}
if (t <= (std::numeric_limits<std::uint8_t>::max)()) {
d = static_cast<std::uint8_t>(t);
if (t <= (std::numeric_limits<std::uint16_t>::max)()) {
d = static_cast<std::uint16_t>(t);
return first;
}
}
Expand Down Expand Up @@ -285,26 +297,37 @@ struct resize_uninitialized<T, std::void_t<decltype(std::declval<T>().__resize_d
} // namespace semver::detail

struct version {
std::uint8_t major = 0;
std::uint8_t minor = 1;
std::uint8_t patch = 0;
prerelease prerelease_type = prerelease::none;
std::optional<std::uint8_t> prerelease_number = std::nullopt;

constexpr version(std::uint8_t mj,
std::uint8_t mn,
std::uint8_t pt,
std::uint16_t major = 0;
std::uint16_t minor = 1;
std::uint16_t patch = 0;
prerelease prerelease_type = prerelease::none;
std::optional<std::uint16_t> prerelease_number = std::nullopt;

constexpr version(std::uint16_t mj,
std::uint16_t mn,
std::uint16_t pt,
prerelease prt = prerelease::none,
std::optional<std::uint8_t> prn = std::nullopt) noexcept
std::optional<std::uint16_t> prn = std::nullopt) noexcept
: major{mj},
minor{mn},
patch{pt},
prerelease_type{prt},
prerelease_number{prt == prerelease::none ? std::nullopt : prn} {
}

constexpr version(std::uint16_t mj,
std::uint16_t mn,
std::uint16_t pt,
prerelease prt,
std::uint16_t prn) noexcept
: major{mj},
minor{mn},
patch{pt},
prerelease_type{prt},
prerelease_number{prt == prerelease::none ? std::nullopt : std::make_optional<std::uint16_t>(prn)} {
}

explicit constexpr version(std::string_view str) : version(0, 0, 0, prerelease::none, 0) {
explicit constexpr version(std::string_view str) : version(0, 0, 0, prerelease::none, std::nullopt) {
from_string(str);
}

Expand Down Expand Up @@ -632,7 +655,7 @@ class range {

struct range_token {
range_token_type type = range_token_type::none;
std::uint8_t number = 0;
std::uint16_t number = 0;
range_operator op = range_operator::equal;
prerelease prerelease_type = prerelease::none;
};
Expand Down Expand Up @@ -714,10 +737,10 @@ class range {
return range_operator::equal;
}

constexpr std::uint8_t get_number() noexcept {
constexpr std::uint16_t get_number() noexcept {
const auto first = text.data() + pos;
const auto last = text.data() + text.length();
if (std::uint8_t n{}; from_chars(first, last, n) != nullptr) {
if (std::uint16_t n{}; from_chars(first, last, n) != nullptr) {
advance(length(n));
return n;
}
Expand Down Expand Up @@ -783,7 +806,7 @@ class range {
const auto patch = parse_number();

prerelease prerelease = prerelease::none;
std::optional<std::uint8_t> prerelease_number = std::nullopt;
std::optional<std::uint16_t> prerelease_number = std::nullopt;

if (current_token.type == range_token_type::hyphen) {
advance_token(range_token_type::hyphen);
Expand All @@ -797,7 +820,7 @@ class range {
return {major, minor, patch, prerelease, prerelease_number};
}

constexpr std::uint8_t parse_number() {
constexpr std::uint16_t parse_number() {
const auto token = current_token;
advance_token(range_token_type::number);

Expand Down
24 changes: 12 additions & 12 deletions test/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ static_assert(semver_version.major == SEMVER_VERSION_MAJOR);
static_assert(semver_version.minor == SEMVER_VERSION_MINOR);
static_assert(semver_version.patch == SEMVER_VERSION_PATCH);

static_assert(alignof(version) == 1);
static_assert(alignof(version) == 2);
static_assert(alignof(prerelease) == 1);
static_assert(sizeof(version) == 6);
static_assert(sizeof(version) == 12);
static_assert(sizeof(prerelease) == 1);

#define STATIC_CHECK_OP_AND_REVERSE(v1, op, v2) \
Expand Down Expand Up @@ -415,59 +415,59 @@ TEST_CASE("operators") {
TEST_CASE("from/to string") {
constexpr std::array<version, 22> versions = {{
version{1, 2, 3},
version{255, 255, 255},
version{65535, 65535, 65535},
version{0, 0, 0},
//
version{1, 2, 3, prerelease::none, std::nullopt},
version{1, 2, 3, prerelease::none, 4},
version{255, 255, 255, prerelease::none, 255},
version{65535, 65535, 65535, prerelease::none, 65535},
version{0, 0, 0, prerelease::none, std::nullopt},
//
version{1, 2, 3, prerelease::alpha, std::nullopt},
version{1, 2, 3, prerelease::alpha, 0},
version{1, 2, 3, prerelease::alpha, 4},
version{255, 255, 255, prerelease::alpha, 255},
version{65535, 65535, 65535, prerelease::alpha, 65535},
version{0, 0, 0, prerelease::alpha, std::nullopt},
//
version{1, 2, 3, prerelease::beta, std::nullopt},
version{1, 2, 3, prerelease::beta, 0},
version{1, 2, 3, prerelease::beta, 4},
version{255, 255, 255, prerelease::beta, 255},
version{65535, 65535, 65535, prerelease::beta, 65535},
version{0, 0, 0, prerelease::beta, std::nullopt},
//
version{1, 2, 3, prerelease::rc, std::nullopt},
version{1, 2, 3, prerelease::rc, 0},
version{1, 2, 3, prerelease::rc, 4},
version{255, 255, 255, prerelease::rc, 255},
version{65535, 65535, 65535, prerelease::rc, 65535},
version{0, 0, 0, prerelease::rc, std::nullopt},
}};

constexpr std::array<std::string_view, 22> versions_strings = {{
"1.2.3",
"255.255.255",
"65535.65535.65535",
"0.0.0",
//
"1.2.3",
"1.2.3",
"255.255.255",
"65535.65535.65535",
"0.0.0",
//
"1.2.3-alpha",
"1.2.3-alpha.0",
"1.2.3-alpha.4",
"255.255.255-alpha.255",
"65535.65535.65535-alpha.65535",
"0.0.0-alpha",
//
"1.2.3-beta",
"1.2.3-beta.0",
"1.2.3-beta.4",
"255.255.255-beta.255",
"65535.65535.65535-beta.65535",
"0.0.0-beta",
//
"1.2.3-rc",
"1.2.3-rc.0",
"1.2.3-rc.4",
"255.255.255-rc.255",
"65535.65535.65535-rc.65535",
"0.0.0-rc",
}};

Expand Down

0 comments on commit 02f52e9

Please sign in to comment.