1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
#pragma once
#include <chrono>
#include <command.h>
#include <filesystem>
#include <scn/scan.h>
#include <shared_mutex>
#include <tuple>
namespace WebStat {
template<auto Deleter> struct DeleteWith {
auto
operator()(auto obj)
{
return Deleter(obj);
}
};
template<typename... T>
auto
visit(auto && visitor, std::tuple<T...> & values)
{
std::apply(
[&](auto &&... value) {
(visitor(value), ...);
},
values);
}
using FilePtr = std::unique_ptr<std::FILE, DeleteWith<&fclose>>;
template<typename... T>
void
bindMany(const DB::CommandPtr & cmd, unsigned int firstParam, T &&... param)
{
(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;
}
template<typename Clock, typename Dur, typename Rep, typename Period>
bool
expired(const std::chrono::time_point<Clock, Dur> lastRun, const std::chrono::duration<Rep, Period> freq,
const typename Clock::time_point now = Clock::now())
{
return lastRun + freq < now;
}
template<typename Clock, typename Dur, typename Rep, typename Period>
bool
expiredThenSet(std::chrono::time_point<Clock, Dur> & lastRun, const std::chrono::duration<Rep, Period> freq,
const typename Clock::time_point now = Clock::now())
{
if (expired(lastRun, freq, now)) {
lastRun = now;
return true;
}
return false;
}
template<typename ValueType, typename MutexType = std::shared_mutex> class ThreadSafeT {
public:
template<typename... P> ThreadSafeT(P &&... params) : value {std::forward<P>(params)...} { }
template<typename LockedValueType, typename LockType> class Locked {
public:
Locked(LockedValueType & valueRef, MutexType & mutex) : value {valueRef}, lock {mutex} { }
LockedValueType *
operator->()
{
return &value;
}
private:
LockedValueType & value;
LockType lock;
};
Locked<const ValueType, std::shared_lock<MutexType>>
shared() const
{
return {value, mutex};
}
Locked<ValueType, std::lock_guard<MutexType>>
unique()
{
return {value, mutex};
}
Locked<const ValueType, std::shared_lock<MutexType>>
operator->() const
{
return shared();
}
Locked<ValueType, std::lock_guard<MutexType>>
operator()()
{
return unique();
}
private:
ValueType value;
mutable MutexType mutex;
};
std::error_code renameNoExcept(
const std::filesystem::path & path, const std::filesystem::path & finalPath) noexcept;
}
|