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

Use uint16_t instead of uint8_t for semver tokens #39

Merged
merged 7 commits into from
May 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading