summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/util.hpp44
-rw-r--r--test/Jamfile.jam9
-rw-r--r--test/test-util.cpp31
3 files changed, 84 insertions, 0 deletions
diff --git a/src/util.hpp b/src/util.hpp
index ad55604..8f2a585 100644
--- a/src/util.hpp
+++ b/src/util.hpp
@@ -1,6 +1,8 @@
#pragma once
+#include <chrono>
#include <command.h>
+#include <scn/scan.h>
#include <tuple>
namespace WebStat {
@@ -31,4 +33,46 @@ namespace WebStat {
{
(cmd->bindParam(firstParam++, std::forward<T>(param)), ...);
}
+
+ namespace detail {
+ template<typename Rep, typename Period, typename AddPeriod>
+ void
+ add(std::chrono::duration<Rep, Period> & subtotal, Rep value)
+ {
+ if constexpr (requires { subtotal += AddPeriod {value}; }) {
+ subtotal += AddPeriod {value};
+ }
+ }
+ }
+
+ template<typename Rep, typename Period>
+ std::chrono::duration<Rep, Period>
+ parseDuration(std::string_view input)
+ {
+ static constexpr std::initializer_list<
+ std::pair<void (*)(std::chrono::duration<Rep, Period> & subtotal, Rep value), std::string_view>>
+ DURATION_UNITS {
+ {detail::add<Rep, Period, std::chrono::milliseconds>, "ms"},
+ {detail::add<Rep, Period, std::chrono::seconds>, "s"},
+ {detail::add<Rep, Period, std::chrono::minutes>, "m"},
+ {detail::add<Rep, Period, std::chrono::hours>, "h"},
+ {detail::add<Rep, Period, std::chrono::days>, "d"},
+ {detail::add<Rep, Period, std::chrono::weeks>, "w"},
+ };
+
+ std::chrono::duration<Rep, Period> out {};
+ auto inputSubRange = scn::ranges::subrange {input};
+
+ while (auto result = scn::scan<Rep, std::string>(inputSubRange, "{}{:[a-z]}")) {
+ const auto & [count, chars] = result->values();
+ if (auto unit = std::ranges::find(
+ DURATION_UNITS, chars, &std::decay_t<decltype(*DURATION_UNITS.begin())>::second);
+ unit != DURATION_UNITS.end()) {
+ unit->first(out, count);
+ }
+ inputSubRange = result->range();
+ }
+
+ return out;
+ }
}
diff --git a/test/Jamfile.jam b/test/Jamfile.jam
index 6574046..98c0d9a 100644
--- a/test/Jamfile.jam
+++ b/test/Jamfile.jam
@@ -21,6 +21,15 @@ lib testing-util :
<library>..//dbpp-postgresql
;
+run test-util.cpp : : :
+ <define>BOOST_TEST_DYN_LINK
+ <library>testing-util
+ <library>..//dbpp-postgresql
+ <library>boost_unit_test_framework
+ <library>dbpptestcore
+ <library>stdc++fs
+ ;
+
run test-ingest.cpp :
-- :
../src/schema.sql
diff --git a/test/test-util.cpp b/test/test-util.cpp
new file mode 100644
index 0000000..5850411
--- /dev/null
+++ b/test/test-util.cpp
@@ -0,0 +1,31 @@
+#define BOOST_TEST_MODULE ingest
+#include <boost/test/data/test_case.hpp>
+#include <boost/test/unit_test.hpp>
+
+#include <util.hpp>
+
+namespace WebStat {
+}
+
+using DurationParserData = std::tuple<std::string_view, std::chrono::milliseconds>;
+
+BOOST_TEST_DECORATOR(*boost::unit_test::timeout(1))
+
+BOOST_DATA_TEST_CASE(durationParser,
+ boost::unit_test::data::make<DurationParserData>({
+ {"", std::chrono::milliseconds {0}},
+ {"123ms", std::chrono::milliseconds {123}},
+ {"45s", std::chrono::seconds {45}},
+ {"10m", std::chrono::minutes {10}},
+ {"7h", std::chrono::hours {7}},
+ {"2d", std::chrono::days {2}},
+ {"7w", std::chrono::weeks {7}},
+ {"1w4d3h45m10s1ms",
+ std::chrono::weeks {1} + std::chrono::days {4} + std::chrono::hours {3}
+ + std::chrono::minutes {45} + std::chrono::seconds {10}
+ + std::chrono::milliseconds {1}},
+ }),
+ input, expected)
+{
+ BOOST_CHECK_EQUAL(expected, (WebStat::parseDuration<std::intmax_t, std::milli>(input)));
+}