diff options
| author | Dan Goodliffe <dan@randomdan.homeip.net> | 2025-12-20 15:11:51 +0000 |
|---|---|---|
| committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2025-12-20 15:11:51 +0000 |
| commit | a19c28924d28f3633727bf86f92a0aaeb9ed7692 (patch) | |
| tree | 3fc683bc342908d5e3e1d12ac7b836e21a0b6aa9 /src | |
| parent | 0b34bd33d9b74e51adccba4b330b0bd264a7d24c (diff) | |
| download | webstat-a19c28924d28f3633727bf86f92a0aaeb9ed7692.tar.bz2 webstat-a19c28924d28f3633727bf86f92a0aaeb9ed7692.tar.xz webstat-a19c28924d28f3633727bf86f92a0aaeb9ed7692.zip | |
Add utility for parsing an ISO like duration
Diffstat (limited to 'src')
| -rw-r--r-- | src/util.hpp | 44 |
1 files changed, 44 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; + } } |
