Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
semantic_version.hpp
Go to the documentation of this file.
1// Copyright 2024, Toyota Motor Corporation
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_SEMANTIC_VERSION_SEMANTIC_VERSION_HPP_
6#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_SEMANTIC_VERSION_SEMANTIC_VERSION_HPP_
7
8// IWYU pragma: private, include "arene/base/semantic_version.hpp"
9// IWYU pragma: friend "(arene/base(?!/tests)|stdlib/include/stdlib_detail)/.*"
10
11// parasoft-begin-suppress AUTOSAR-A16_2_2-a "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
12#include "arene/base/compare/compare_three_way.hpp"
13#include "arene/base/compare/operators.hpp"
14#include "arene/base/compare/strong_ordering.hpp"
15#include "arene/base/compiler_support/attributes.hpp"
16#include "arene/base/stdlib_choice/cstdint.hpp"
17#include "arene/base/utility/to_underlying.hpp"
18// parasoft-end-suppress AUTOSAR-A16_2_2-a
19
20// parasoft-begin-suppress AUTOSAR-A7_1_5-a-2 "Trailing return syntax permitted by A7-1-5 Permit #1 v1.0.0"
21// parasoft-begin-suppress AUTOSAR-M2_10_1-a "Similar identifiers permitted by M2-10-1 Permit #1 v1.0.0"
22
23// parasoft-begin-suppress AUTOSAR-A16_0_1-e "Undefines macros for configuration"
24#undef major
25#undef minor
26// parasoft-end-suppress AUTOSAR-A16_0_1-e
27
28namespace arene {
29namespace base {
30
31/// @brief A class representing semantic versions (https://semver.org/). Does not include build metadata or prerelease
32/// comparisons.
33///
34/// @remarks Pre-releases and Build metadata are effectively (ASCII) strings, and therefore do not fit into compile-time
35/// computation. Should there be significant enough demand, an @c extended_semantic_version with prerelease and build
36/// metadata can be considered, but this class does not retain or track such information.
38 public:
39 // parasoft-begin-suppress AUTOSAR-A12_1_1-a "False positive: This constructor delegates to another, which does
40 // initialize the base class"
41 /// @brief Default ctor, creates a semver of all 0's.
42 /// @post <c> major() == 0 </c>
43 /// @post <c> minor() == 0 </c>
44 /// @post <c> patch() == 0 </c>
45 constexpr semantic_version() noexcept
46 : semantic_version(0U, 0U, 0U) {}
47 // parasoft-end-suppress AUTOSAR-A12_1_1-a
48
49 /// @brief Constructs a semantic_version with the given major, minor, and patch version.
50 ///
51 /// @param major_version The major version number.
52 /// @param minor_version The minor version number.
53 /// @param patch_version The patch version number.
54 /// @post <c> major() == major_version </c>
55 /// @post <c> minor() == minor_version </c>
56 /// @post <c> patch() == patch_version </c>
57 // NOLINTBEGIN(bugprone-easily-swappable-parameters)
58 constexpr explicit semantic_version(
59 std::uint16_t const major_version,
60 std::uint16_t const minor_version = 0U,
61 std::uint32_t const patch_version = 0U
62 ) noexcept
67 // NOLINTEND(bugprone-easily-swappable-parameters)
68
69 /// @brief Tests whether this semantic version represents an "unstable" entity, which is one with a major of 0.
70 /// @return true iff <c> major() == 0 </c>
71 /// @return false otherwise
72 ARENE_NODISCARD constexpr auto is_unstable() const noexcept -> bool { return this->major_ < 1U; }
73
74 /// @brief Get the major version component.
75 /// @return major version number
76 ///
77 ARENE_NODISCARD constexpr auto major() const noexcept -> std::uint16_t { return this->major_; }
78
79 /// @brief Get the minor version component.
80 /// @return minor version number
81 ///
82 ARENE_NODISCARD constexpr auto minor() const noexcept -> std::uint16_t { return this->minor_; }
83
84 /// @brief Get the patch version component.
85 /// @return patch version number
86 ///
87 ARENE_NODISCARD constexpr auto patch() const noexcept -> std::uint32_t { return this->patch_; }
88
89 /// @brief Implements a strong lexicographic sort order based on <c>[major, minor, path]</c>, in that order.
90 ///
91 /// @param left The left hand side of the comparison.
92 /// @param right The right hand side of the comparison.
93 /// @return strong_ordering::less if lhs lexicographically precedes rhs.
94 /// @return strong_ordering::equal if lhs and rhs are equal across major, minor, and patch.
95 /// @return strong_ordering::less if lhs lexicographically follows rhs.
96 // NOLINTBEGIN(readability-avoid-const-params-in-decls) : AUTOSAR M3-9-1 requires this to match
98 static constexpr auto three_way_compare(semantic_version const left, semantic_version const right) noexcept
100 // NOLINTEND(readability-avoid-const-params-in-decls)
101
102 private:
103 /// @brief The major change version
104 std::uint16_t major_;
105 /// @brief The minor change version
106 std::uint16_t minor_;
107 /// @brief The patch change version
108 std::uint32_t patch_;
109};
110
111/// @brief Implements a strong lexicographic sort order based on <c>[major, minor, path]</c>, in that order.
112///
113/// @param left The left hand side of the comparison.
114/// @param right The right hand side of the comparison.
115/// @return strong_ordering::less if lhs lexicographically precedes rhs.
116/// @return strong_ordering::equal if lhs and rhs are equal across major, minor, and patch.
117/// @return strong_ordering::less if lhs lexicographically follows rhs.
118ARENE_NODISCARD
119constexpr auto semantic_version::three_way_compare(semantic_version const left, semantic_version const right) noexcept
120 -> arene::base::strong_ordering {
121 constexpr auto cmp = compare_three_way{};
122 auto order = cmp(left.major_, right.major_);
123 if (order == arene::base::strong_ordering::equal) {
124 order = cmp(left.minor_, right.minor_);
125 }
126 if (order == arene::base::strong_ordering::equal) {
127 order = cmp(left.patch_, right.patch_);
128 }
129 return order;
130}
131
132/// @brief Compares ONLY the major part of two semantic versions, to see if
133/// there's a major change between the two.
134///
135/// @param left The first version value.
136/// @param right The second version value.
137/// @return @c true if there is a major change, otherwise @c false
138///
140inline constexpr auto contains_major_change(semantic_version const left, semantic_version const right) noexcept
141 -> bool {
142 return left.major() != right.major();
143}
144
145/// @brief Compares ONLY the minor part of two semantic versions, to see if
146/// there's a minor change between the two.
147///
148/// @param left The first version value.
149/// @param right The second version value.
150/// @return @c true if there is a minor change, otherwise @c false
151///
153inline constexpr auto contains_minor_change(semantic_version const left, semantic_version const right) noexcept
154 -> bool {
155 return left.minor() != right.minor();
156}
157
158/// @brief Compares ONLY the patch part of two semantic versions, to see if
159/// there's a patch change between the two.
160///
161/// @param left The first version value.
162/// @param right The second version value.
163/// @return @c true if there is a patch change, otherwise @c false
164///
166inline constexpr auto contains_patch_change(semantic_version const left, semantic_version const right) noexcept
167 -> bool {
168 return left.patch() != right.patch();
169}
170
171/// @brief The set of differences between two @c semantic_version s, encoded as a bitfield of @c [patch.minor.major].
172/// @see compute_difference to create a @c sem_ver_diff from two @c semantic_version instances.
173enum class sem_ver_diff : std::uint8_t {
174 /// @brief No changes. 0b000
175 none = 0b000,
176 /// @brief A major change. 0b001
177 major = 0b001,
178 /// @brief A minor change. 0b010
179 minor = 0b010,
180 /// @brief A patch change. 0b100
181 patch = 0b100,
182
183 /// @brief A change to both the major and minor versions.
184 major_minor = 0b011,
185 /// @brief A change to both the major and patch versions.
186 major_patch = 0b101,
187 /// @brief A change to both the minor and patch versions.
188 minor_patch = 0b110,
189 /// @brief A change to major, minor, and patch versions.
191};
192
193/// @brief Computes the set of the potential changes between two different semantic versions.
194///
195/// @param left The first version value.
196/// @param right The second version value.
197/// @return A sem_ver_diff with the following properties:
198/// * The major bit will be set if <c>contains_major_change(left, right) == true</c>
199/// * The minor bit will be set if <c>contains_minor_change(left, right) == true</c>
200/// * The patch bit will be set if <c>contains_patch_change(left, right) == true</c>
201ARENE_NODISCARD inline constexpr auto
203 std::uint8_t diff{to_underlying(sem_ver_diff::none)};
204 if (contains_major_change(left, right)) {
205 diff = static_cast<std::uint8_t>(diff | to_underlying(sem_ver_diff::major));
206 }
207 if (contains_minor_change(left, right)) {
208 diff = static_cast<std::uint8_t>(diff | to_underlying(sem_ver_diff::minor));
209 }
210 if (contains_patch_change(left, right)) {
211 diff = static_cast<std::uint8_t>(diff | to_underlying(sem_ver_diff::patch));
212 }
213 // parasoft-begin-suppress AUTOSAR-A7_2_1-a "False positive: values correspond to enumerators in the enum"
214 // parasoft-begin-suppress CERT_CPP-INT50-a "False positive: values correspond to enumerators in the enum"
215 return static_cast<sem_ver_diff>(diff);
216 // parasoft-end-suppress CERT_CPP-INT50-a
217 // parasoft-end-suppress AUTOSAR-A7_2_1-a
218}
219
220///
221/// @brief Predicate to test if a sem_ver_diff contains a major change
222///
223/// @param diff The computed difference between two versions
224/// @return true if the major bit is set.
225/// @return false otherwise.
226///
227ARENE_NODISCARD inline constexpr auto contains_major_change(sem_ver_diff const diff) noexcept -> bool {
228 return (to_underlying(diff) & to_underlying(sem_ver_diff::major)) == to_underlying(sem_ver_diff::major);
229}
230
231///
232/// @brief Predicate to test if a sem_ver_diff contains a minor change
233///
234/// @param diff The computed difference between two versions
235/// @return true if the minor bit is set.
236/// @return false otherwise.
237///
238ARENE_NODISCARD inline constexpr auto contains_minor_change(sem_ver_diff const diff) noexcept -> bool {
239 return (to_underlying(diff) & to_underlying(sem_ver_diff::minor)) == to_underlying(sem_ver_diff::minor);
240}
241
242///
243/// @brief Predicate to test if a sem_ver_diff contains a patch change
244///
245/// @param diff The computed difference between two versions
246/// @return true if the patch bit is set.
247/// @return false otherwise.
248///
249ARENE_NODISCARD inline constexpr auto contains_patch_change(sem_ver_diff const diff) noexcept -> bool {
250 return (to_underlying(diff) & to_underlying(sem_ver_diff::patch)) == to_underlying(sem_ver_diff::patch);
251}
252
253///
254/// @brief Predicate to test if a sem_ver_diff represents a change of at least one major version.
255///
256/// @param diff The computed difference between two versions.
257/// @return true if the major bit is set.
258/// @return false otherwise.
259///
260ARENE_NODISCARD inline constexpr auto is_major_change(sem_ver_diff const diff) noexcept -> bool {
261 return contains_major_change(diff);
262}
263
264///
265/// @brief Binary predicate to test if two semantic_versions differ by major versions.
266///
267/// @param left The left hand operand.
268/// @param right The right hand operand.
269/// @return true if @c major() is different between @c left and @c right .
270/// @return false otherwise.
271///
273inline constexpr auto is_major_change(semantic_version const left, semantic_version const right) noexcept -> bool {
274 return is_major_change(compute_difference(left, right));
275}
276
277///
278/// @brief Predicate to test if a sem_ver_diff represents a change of minor versions, ignoring patch versions.
279///
280/// @param diff The computed difference between two versions.
281/// @return true if the minor bit is set, and the major bit is not.
282/// @return false if the major bit is set, or the minor bit is not.
283///
284ARENE_NODISCARD inline constexpr auto is_minor_change(sem_ver_diff const diff) noexcept -> bool {
285 return (!is_major_change(diff)) && contains_minor_change(diff);
286}
287
288///
289/// @brief Binary predicate to test if two semantic_versions differ by minor versions, ignoring patch versions.
290///
291/// @param left The left hand operand.
292/// @param right The right hand operand.
293/// @return true if @c minor() is different between @c left and @c right, but @c major() is equivalent.
294/// @return false if either @c major() varies between the operands, or @c minor() is equal.
295///
297inline constexpr auto is_minor_change(semantic_version const left, semantic_version const right) noexcept -> bool {
298 return is_minor_change(compute_difference(left, right));
299}
300
301///
302/// @brief Predicate to test if a sem_ver_diff represents a change of exclusively patch versions.
303///
304/// @param diff The computed difference between two versions.
305/// @return true if exclusively the patch bit is set.
306/// @return false if either the major or minor bits are set.
307///
308ARENE_NODISCARD inline constexpr auto is_patch_change(sem_ver_diff const diff) noexcept -> bool {
309 return diff == sem_ver_diff::patch;
310}
311
312///
313/// @brief Binary predicate to test if two semantic_versions differ by exclusively patch versions.
314///
315/// @param left The left hand operand.
316/// @param right The right hand operand.
317/// @return true if the difference between @c left and @c right is exclusively in @c patch() .
318/// @return false if either @c major() or @c minor() vary between the operands, or @c patch() is equal.
319///
321inline constexpr auto is_patch_change(semantic_version const left, semantic_version const right) noexcept -> bool {
322 return is_patch_change(compute_difference(left, right));
323}
324
325} // namespace base
326} // namespace arene
327
328#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_SEMANTIC_VERSION_SEMANTIC_VERSION_HPP_
A class representing semantic versions (https://semver.org/). Does not include build metadata or prer...
Definition semantic_version.hpp:37
constexpr semantic_version() noexcept
Default ctor, creates a semver of all 0's.
Definition semantic_version.hpp:45
constexpr semantic_version(std::uint16_t const major_version, std::uint16_t const minor_version=0U, std::uint32_t const patch_version=0U) noexcept
Constructs a semantic_version with the given major, minor, and patch version.
Definition semantic_version.hpp:58
ARENE_NODISCARD constexpr auto minor() const noexcept -> std::uint16_t
Get the minor version component.
Definition semantic_version.hpp:82
ARENE_NODISCARD constexpr auto major() const noexcept -> std::uint16_t
Get the major version component.
Definition semantic_version.hpp:77
ARENE_NODISCARD constexpr auto patch() const noexcept -> std::uint32_t
Get the patch version component.
Definition semantic_version.hpp:87
static ARENE_NODISCARD constexpr auto three_way_compare(semantic_version const left, semantic_version const right) noexcept -> arene::base::strong_ordering
Implements a strong lexicographic sort order based on [major, minor, path], in that order.
Definition semantic_version.hpp:119
ARENE_NODISCARD constexpr auto is_unstable() const noexcept -> bool
Tests whether this semantic version represents an "unstable" entity, which is one with a major of 0.
Definition semantic_version.hpp:72
Definition array_exceptions_disabled.cpp:11
ARENE_NODISCARD constexpr auto is_major_change(semantic_version const left, semantic_version const right) noexcept -> bool
Binary predicate to test if two semantic_versions differ by major versions.
Definition semantic_version.hpp:273
ARENE_NODISCARD constexpr auto is_minor_change(sem_ver_diff const diff) noexcept -> bool
Predicate to test if a sem_ver_diff represents a change of minor versions, ignoring patch versions.
Definition semantic_version.hpp:284
ARENE_NODISCARD constexpr auto contains_major_change(sem_ver_diff const diff) noexcept -> bool
Predicate to test if a sem_ver_diff contains a major change.
Definition semantic_version.hpp:227
ARENE_NODISCARD constexpr auto contains_major_change(semantic_version const left, semantic_version const right) noexcept -> bool
Compares ONLY the major part of two semantic versions, to see if there's a major change between the t...
Definition semantic_version.hpp:140
ARENE_NODISCARD constexpr auto contains_minor_change(sem_ver_diff const diff) noexcept -> bool
Predicate to test if a sem_ver_diff contains a minor change.
Definition semantic_version.hpp:238
ARENE_NODISCARD constexpr auto is_patch_change(semantic_version const left, semantic_version const right) noexcept -> bool
Binary predicate to test if two semantic_versions differ by exclusively patch versions.
Definition semantic_version.hpp:321
ARENE_NODISCARD constexpr auto is_patch_change(sem_ver_diff const diff) noexcept -> bool
Predicate to test if a sem_ver_diff represents a change of exclusively patch versions.
Definition semantic_version.hpp:308
ARENE_NODISCARD constexpr auto is_major_change(sem_ver_diff const diff) noexcept -> bool
Predicate to test if a sem_ver_diff represents a change of at least one major version.
Definition semantic_version.hpp:260
ARENE_NODISCARD constexpr auto compute_difference(semantic_version const left, semantic_version const right) noexcept -> sem_ver_diff
Computes the set of the potential changes between two different semantic versions.
Definition semantic_version.hpp:202
ARENE_NODISCARD constexpr auto is_minor_change(semantic_version const left, semantic_version const right) noexcept -> bool
Binary predicate to test if two semantic_versions differ by minor versions, ignoring patch versions.
Definition semantic_version.hpp:297
ARENE_NODISCARD constexpr auto contains_patch_change(sem_ver_diff const diff) noexcept -> bool
Predicate to test if a sem_ver_diff contains a patch change.
Definition semantic_version.hpp:249
ARENE_NODISCARD constexpr auto contains_minor_change(semantic_version const left, semantic_version const right) noexcept -> bool
Compares ONLY the minor part of two semantic versions, to see if there's a minor change between the t...
Definition semantic_version.hpp:153
ARENE_NODISCARD constexpr auto contains_patch_change(semantic_version const left, semantic_version const right) noexcept -> bool
Compares ONLY the patch part of two semantic versions, to see if there's a patch change between the t...
Definition semantic_version.hpp:166
sem_ver_diff
The set of differences between two semantic_version s, encoded as a bitfield of [patch....
Definition semantic_version.hpp:173
@ major_minor_patch
A change to major, minor, and patch versions.
Definition semantic_version.hpp:190
@ none
No changes. 0b000.
Definition semantic_version.hpp:175
@ major_patch
A change to both the major and patch versions.
Definition semantic_version.hpp:186
@ minor_patch
A change to both the minor and patch versions.
Definition semantic_version.hpp:188
@ minor
A minor change. 0b010.
Definition semantic_version.hpp:179
@ major_minor
A change to both the major and minor versions.
Definition semantic_version.hpp:184
@ patch
A patch change. 0b100.
Definition semantic_version.hpp:181
@ major
A major change. 0b001.
Definition semantic_version.hpp:177
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10