CommonLibSSE NG
Version.h
Go to the documentation of this file.
1 #pragma once
2 
3 namespace REL
4 {
5  class Version
6  {
7  public:
8  using value_type = std::uint16_t;
9  using reference = value_type &;
10  using const_reference = const value_type &;
11 
12  constexpr Version() noexcept = default;
13 
14  explicit constexpr Version(std::array<value_type, 4> a_version) noexcept:
15  _impl(a_version)
16  {}
17 
18  constexpr Version(value_type a_v1, value_type a_v2 = 0, value_type a_v3 = 0, value_type a_v4 = 0) noexcept:
19  _impl{a_v1, a_v2, a_v3, a_v4}
20  {}
21 
22  explicit constexpr Version(std::string_view a_version) {
23  std::array<value_type, 4> powers{1, 1, 1, 1};
24  std::size_t position = 0;
25  for (std::size_t i = 0; i < a_version.size(); ++i) {
26  if (a_version[i] == '.') {
27  if (++position == powers.size()) {
28  throw std::invalid_argument("Too many parts in version number.");
29  }
30  } else {
31  powers[position] *= 10;
32  }
33  }
34  position = 0;
35  for (std::size_t i = 0; i < a_version.size(); ++i) {
36  if (a_version[i] == '.') {
37  ++position;
38  } else if (a_version[i] < '0' || a_version[i] > '9') {
39  throw std::invalid_argument("Invalid character in version number.");
40  } else {
41  powers[position] /= 10;
42  _impl[position] += static_cast<value_type>((a_version[i] - '0') * powers[position]);
43  }
44  }
45  }
46 
47  [[nodiscard]] constexpr reference operator[](std::size_t a_idx) noexcept { return _impl[a_idx]; }
48 
49  [[nodiscard]] constexpr const_reference operator[](std::size_t a_idx) const noexcept { return _impl[a_idx]; }
50 
51  [[nodiscard]] constexpr decltype(auto) begin() const noexcept { return _impl.begin(); }
52 
53  [[nodiscard]] constexpr decltype(auto) cbegin() const noexcept { return _impl.cbegin(); }
54 
55  [[nodiscard]] constexpr decltype(auto) end() const noexcept { return _impl.end(); }
56 
57  [[nodiscard]] constexpr decltype(auto) cend() const noexcept { return _impl.cend(); }
58 
59  [[nodiscard]] std::strong_ordering constexpr compare(const Version &a_rhs) const noexcept {
60  for (std::size_t i = 0; i < _impl.size(); ++i) {
61  if ((*this)[i] != a_rhs[i]) {
62  return (*this)[i] < a_rhs[i] ? std::strong_ordering::less : std::strong_ordering::greater;
63  }
64  }
65  return std::strong_ordering::equal;
66  }
67 
68  [[nodiscard]] constexpr std::uint32_t pack() const noexcept {
69  return static_cast<std::uint32_t>(
70  (_impl[0] & 0x0FF) << 24u |
71  (_impl[1] & 0x0FF) << 16u |
72  (_impl[2] & 0xFFF) << 4u |
73  (_impl[3] & 0x00F) << 0u);
74  }
75 
76  [[nodiscard]] constexpr value_type major() const noexcept {
77  return _impl[0];
78  }
79 
80  [[nodiscard]] constexpr value_type minor() const noexcept {
81  return _impl[1];
82  }
83 
84  [[nodiscard]] constexpr value_type patch() const noexcept {
85  return _impl[2];
86  }
87 
88  [[nodiscard]] constexpr value_type build() const noexcept {
89  return _impl[3];
90  }
91 
92  [[nodiscard]] std::string string(std::string_view a_separator = "-"sv) const {
93  std::string result;
94  for (auto &&ver: _impl) {
95  result += std::to_string(ver);
96  result.append(a_separator.data(), a_separator.size());
97  }
98  result.erase(result.size() - a_separator.size(), a_separator.size());
99  return result;
100  }
101 
102  [[nodiscard]] std::wstring wstring(std::wstring_view a_separator = L"-"sv) const {
103  std::wstring result;
104  for (auto &&ver: _impl) {
105  result += std::to_wstring(ver);
106  result.append(a_separator.data(), a_separator.size());
107  }
108  result.erase(result.size() - a_separator.size(), a_separator.size());
109  return result;
110  }
111 
112  [[nodiscard]] static constexpr Version unpack(std::uint32_t a_packedVersion) noexcept {
113  return REL::Version{
114  static_cast<value_type>((a_packedVersion >> 24) & 0x0FF),
115  static_cast<value_type>((a_packedVersion >> 16) & 0x0FF),
116  static_cast<value_type>((a_packedVersion >> 4) & 0xFFF),
117  static_cast<value_type>(a_packedVersion & 0x0F)
118  };
119  }
120 
121  private:
122  std::array<value_type, 4> _impl{0, 0, 0, 0};
123  };
124 
125  [[nodiscard]] constexpr bool operator==(const Version &a_lhs, const Version &a_rhs) noexcept {
126  return a_lhs.compare(a_rhs) == std::strong_ordering::equal;
127  }
128 
129  [[nodiscard]] constexpr std::strong_ordering
130  operator<=>(const Version &a_lhs, const Version &a_rhs) noexcept { return a_lhs.compare(a_rhs); }
131 
132  namespace literals
133  {
134  namespace detail
135  {
136  template<std::size_t Index, char C>
137  constexpr uint8_t read_version(std::array<typename REL::Version::value_type, 4> &result) {
138  static_assert(C >= '0' && C <= '9', "Invalid character in semantic version literal.");
139  static_assert(Index < 4, "Too many components in semantic version literal.");
140  result[Index] += (C - '0');
141  return 10;
142  }
143 
144  template<std::size_t Index, char C, char... Rest>
145  requires (sizeof...(Rest) > 0)
146  constexpr uint8_t read_version(std::array<typename REL::Version::value_type, 4> &result) {
147  static_assert(C == '.' || (C >= '0' && C <= '9'), "Invalid character in semantic version literal.");
148  static_assert(Index < 4, "Too many components in semantic version literal.");
149  if constexpr (C == '.') {
150  read_version<Index + 1, Rest...>(result);
151  return 1;
152  } else {
153  auto position = read_version<Index, Rest...>(result);
154  result[Index] += (C - '0') * position;
155  return position * 10;
156  }
157  }
158  }
159 
160  template<char... C>
161  [[nodiscard]] constexpr REL::Version operator ""_v() noexcept {
162  std::array<typename REL::Version::value_type, 4> result{0, 0, 0, 0};
163  detail::read_version<0, C...>(result);
164  return REL::Version(result);
165  }
166 
167  [[nodiscard]] constexpr REL::Version operator ""_v(const char *str, std::size_t len) {
168  return Version(std::string_view(str, len));
169  }
170  }
171 
172  [[nodiscard]] std::optional<Version> GetFileVersion(stl::zwstring a_filename);
173 }
174 
175 namespace std
176 {
177  [[nodiscard]] inline std::string to_string(REL::Version a_version)
178  {
179  return a_version.string("."sv);
180  }
181 }
182 
183 #ifdef __cpp_lib_format
184 template<class CharT>
185 struct std::formatter<REL::Version, CharT> : formatter<std::string, CharT>
186 {
187  template<class FormatContext>
188  auto format(const REL::Version& a_version, FormatContext& a_ctx) const
189  {
190  return formatter<std::string, CharT>::format(a_version.string("."), a_ctx);
191  }
192 };
193 #endif
194 
195 #ifdef FMT_VERSION
196 template<class CharT>
197 struct fmt::formatter<REL::Version, CharT> : formatter<std::string, CharT>
198 {
199  template<class FormatContext>
200  auto format(const REL::Version& a_version, FormatContext& a_ctx)
201  {
202  return formatter<std::string, CharT>::format(a_version.string("."), a_ctx);
203  }
204 };
205 #endif
Definition: Version.h:6
const value_type & const_reference
Definition: Version.h:10
constexpr value_type build() const noexcept
Definition: Version.h:88
constexpr decltype(auto) end() const noexcept
Definition: Version.h:55
constexpr Version(value_type a_v1, value_type a_v2=0, value_type a_v3=0, value_type a_v4=0) noexcept
Definition: Version.h:18
constexpr value_type patch() const noexcept
Definition: Version.h:84
constexpr reference operator[](std::size_t a_idx) noexcept
Definition: Version.h:47
constexpr decltype(auto) cbegin() const noexcept
Definition: Version.h:53
std::string string(std::string_view a_separator="-"sv) const
Definition: Version.h:92
std::wstring wstring(std::wstring_view a_separator=L"-"sv) const
Definition: Version.h:102
constexpr value_type minor() const noexcept
Definition: Version.h:80
constexpr std::uint32_t pack() const noexcept
Definition: Version.h:68
constexpr Version(std::string_view a_version)
Definition: Version.h:22
constexpr const_reference operator[](std::size_t a_idx) const noexcept
Definition: Version.h:49
static constexpr Version unpack(std::uint32_t a_packedVersion) noexcept
Definition: Version.h:112
std::uint16_t value_type
Definition: Version.h:8
constexpr decltype(auto) cend() const noexcept
Definition: Version.h:57
value_type & reference
Definition: Version.h:9
constexpr Version() noexcept=default
constexpr std::strong_ordering compare(const Version &a_rhs) const noexcept
Definition: Version.h:59
constexpr decltype(auto) begin() const noexcept
Definition: Version.h:51
constexpr value_type major() const noexcept
Definition: Version.h:76
requires(sizeof...(Rest) > 0) const expr uint8_t read_version(std
Definition: Version.h:145
constexpr uint8_t read_version(std::array< typename REL::Version::value_type, 4 > &result)
Definition: Version.h:137
Definition: ID.h:6
constexpr std::strong_ordering operator<=>(const Version &a_lhs, const Version &a_rhs) noexcept
Definition: Version.h:130
constexpr bool operator==(const Version &a_lhs, const Version &a_rhs) noexcept
Definition: Version.h:125
std::optional< Version > GetFileVersion(stl::zwstring a_filename)
string(const CharT(&)[N]) -> string< CharT, N - 1 >
basic_zstring< wchar_t > zwstring
Definition: PCH.h:78
Definition: ActorValueList.h:28
std::string to_string(RE::ActorValue a_actorValue)
Definition: ActorValueList.h:29