diff --git a/include/duckhandy/version_bt.hpp b/include/duckhandy/version_bt.hpp
new file mode 100644
index 0000000..5b7f80d
--- /dev/null
+++ b/include/duckhandy/version_bt.hpp
@@ -0,0 +1,101 @@
+/* Copyright 2016-2021 Michele Santullo
+ * This file is part of "duckhandy".
+ *
+ * "duckhandy" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * "duckhandy" is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with "duckhandy". If not, see .
+ */
+
+#ifndef id5594416333AA4792BFEC94E863E03B08
+#define id5594416333AA4792BFEC94E863E03B08
+
+#include "int_conv.hpp"
+#include
+#include
+
+namespace dhandy {
+
+template
+class Version {
+public:
+ constexpr static std::size_t Count = N;
+
+ constexpr Version (const char* const ver, bool accept_less=false);
+
+ constexpr unsigned int operator[] (std::size_t idx) const;
+ constexpr unsigned int major() const;
+ constexpr unsigned int minor() const;
+ constexpr unsigned int revision() const;
+
+private:
+ unsigned int m_versions[N];
+};
+
+template
+inline constexpr Version::Version (const char* const ver, bool accept_less) :
+ m_versions{0}
+{
+ std::size_t z = 0;
+ std::size_t s = 0;
+ std::size_t idx = 0;
+ bool commit = false;
+
+ do {
+ if (ver[z] >= '0' and ver[z] <= '9') {
+ commit = true;
+ }
+ else if (commit) {
+ commit = false;
+ m_versions[idx++] = dhandy::ary_to_int(ver + s, ver + z);
+ s = z + 1;
+ }
+ else {
+ s = z + 1;
+ }
+ } while(ver[z++] and idx < N);
+
+ if (not accept_less and idx < N)
+ throw std::invalid_argument("Input version doesn't contain enough version numbers");
+}
+
+template
+inline constexpr unsigned int Version::operator[] (std::size_t idx) const {
+ if (idx < N)
+ return m_versions[idx];
+ else
+ throw std::out_of_range("Index is out of range");
+}
+
+template
+inline constexpr unsigned int Version::major() const {
+ return m_versions[0];
+}
+
+template
+inline constexpr unsigned int Version::minor() const {
+ if constexpr (N > 1)
+ return m_versions[1];
+ else
+ throw std::out_of_range("Not enough version entries, there is no minor number");
+}
+
+template
+inline constexpr unsigned int Version::revision() const {
+ if constexpr (N > 2)
+ return m_versions[2];
+ else
+ throw std::out_of_range("Not enough version entries, there is no revision number");
+}
+
+} //namespace dhandy
+
+#endif
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index eaae1f8..16efbcf 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -7,6 +7,7 @@ add_executable(${PROJECT_NAME}
reversed_sized_array_test.cpp
bitfield_pack_test.cpp
resource_pool_test.cpp
+ version_test.cpp
)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 17)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
diff --git a/test/unit/version_test.cpp b/test/unit/version_test.cpp
new file mode 100644
index 0000000..60b8cb0
--- /dev/null
+++ b/test/unit/version_test.cpp
@@ -0,0 +1,94 @@
+/* Copyright 2016-2021 Michele Santullo
+ * This file is part of "duckhandy".
+ *
+ * "duckhandy" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * "duckhandy" is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with "duckhandy". If not, see .
+ */
+
+#include "catch2/catch.hpp"
+#include "duckhandy/version_bt.hpp"
+
+TEST_CASE ("Version class tests", "[version][bt]") {
+ using dhandy::Version;
+
+ {
+ constexpr Version<1> ver{"102"};
+ static_assert(ver.major() == 102, "Version error");
+ static_assert(ver.Count == 1, "Version error");
+ CHECK(ver[0] == 102);
+ CHECK_THROWS(ver[1]);
+ CHECK_THROWS(ver[2]);
+ CHECK_THROWS(ver[3]);
+ CHECK_THROWS(ver[4]);
+ }
+
+ {
+ constexpr Version<3> ver{".aheud15,a.ud22,cu.sh81,.nuad.h44"};
+ static_assert(ver.Count == 3, "Version error");
+ static_assert(ver.major() == 15, "Version error");
+ static_assert(ver.minor() == 22, "Version error");
+ static_assert(ver.revision() == 81, "Version error");
+ CHECK(ver[0] == 15);
+ CHECK(ver[1] == 22);
+ CHECK(ver[2] == 81);
+ CHECK_THROWS(ver[3]);
+ CHECK_THROWS(ver[4]);
+ }
+
+ {
+ constexpr Version<10> ver{"1.2.3.44.55.66.777.888.999.101010"};
+ static_assert(ver.Count == 10, "Version error");
+ static_assert(ver.major() == 1, "Version error");
+ static_assert(ver.minor() == 2, "Version error");
+ static_assert(ver.revision() == 3, "Version error");
+ CHECK(ver[0] == 1);
+ CHECK(ver[1] == 2);
+ CHECK(ver[2] == 3);
+ CHECK(ver[3] == 44);
+ CHECK(ver[4] == 55);
+ CHECK(ver[5] == 66);
+ CHECK(ver[6] == 777);
+ CHECK(ver[7] == 888);
+ CHECK(ver[8] == 999);
+ CHECK(ver[9] == 101010);
+ CHECK_THROWS(ver[10]);
+ }
+
+ {
+ constexpr Version<4> ver{"1.2.3.", true};
+ static_assert(ver.Count == 4, "Version error");
+ static_assert(ver.major() == 1, "Version error");
+ static_assert(ver.minor() == 2, "Version error");
+ static_assert(ver.revision() == 3, "Version error");
+ CHECK(ver[0] == 1);
+ CHECK(ver[1] == 2);
+ CHECK(ver[2] == 3);
+ CHECK(ver[3] == 0);
+ CHECK_THROWS(ver[10]);
+ }
+
+ {
+ constexpr Version<4> ver{"6.7.2-r1"};
+ static_assert(ver.Count == 4, "Version error");
+ static_assert(ver.major() == 6, "Version error");
+ static_assert(ver.minor() == 7, "Version error");
+ static_assert(ver.revision() == 2, "Version error");
+ CHECK(ver[0] == 6);
+ CHECK(ver[1] == 7);
+ CHECK(ver[2] == 2);
+ CHECK(ver[3] == 1);
+ CHECK_THROWS(ver[10]);
+ }
+
+ CHECK_THROWS(Version<4>{"4.5"});
+}