1 #ifndef LIBFILEZILLA_UTIL_HEADER
2 #define LIBFILEZILLA_UTIL_HEADER
3
4 #include "libfilezilla.hpp"
5 #include "time.hpp"
6
7 #include <cstdint>
8
9 /** \file
10 * \brief Various utility functions
11 */
12
13 namespace fz {
14
15 /** \brief Sleep current thread for the specified \ref duration.
16 *
17 * Alternative to \c std::this_thread::sleep_for which unfortunately isn't implemented on
18 * MinGW.
19 *
20 * \note May wake up early, e.g. due to a signal. You can use \ref monotonic_clock
21 * to check elapsed time and sleep again if needed.
22 */
23 void FZ_PUBLIC_SYMBOL sleep(duration const& d);
24
25 /** \brief Relinquish control for a brief amount of time.
26 *
27 * The exact duration is unspecified.
28 */
29 void FZ_PUBLIC_SYMBOL yield();
30
31 /** \brief Get a secure random integer uniformly distributed in the closed interval [min, max]
32 */
33 int64_t FZ_PUBLIC_SYMBOL random_number(int64_t min, int64_t max);
34
35 /** \brief Get random uniformly distributed bytes
36 */
37 std::vector<uint8_t> FZ_PUBLIC_SYMBOL random_bytes(size_t size);
38
39 void FZ_PUBLIC_SYMBOL random_bytes(size_t size, uint8_t* destination);
40
41 /** \brief Returns index of the least-significant set bit
42 *
43 * For example \c bitscan(12) returns 2
44 *
45 * Undefined if called with 0
46 */
47 uint64_t FZ_PUBLIC_SYMBOL bitscan(uint64_t v);
48
49 /** \brief Returns index of the most-significant set bit
50 *
51 * For example \c bitscan_reverse(12) returns 3
52 *
53 * Undefined if called with 0
54 */
55 uint64_t FZ_PUBLIC_SYMBOL bitscan_reverse(uint64_t v);
56
57 /** \brief Secure equality test in constant time
58 *
59 * As long as both inputs are of the same size, comparison is done in constant
60 * time to prevent timing attacks.
61 */
62 bool FZ_PUBLIC_SYMBOL equal_consttime(std::basic_string_view<uint8_t> const& lhs, std::basic_string_view<uint8_t> const& rhs);
63
64 template <typename First, typename Second,
65 std::enable_if_t<sizeof(typename First::value_type) == sizeof(uint8_t) &&
66 sizeof(typename Second::value_type) == sizeof(uint8_t)>* = nullptr>
equal_consttime(First const & lhs,Second const & rhs)67 inline bool equal_consttime(First const& lhs, Second const& rhs)
68 {
69 return equal_consttime(std::basic_string_view<uint8_t>(reinterpret_cast<uint8_t const*>(lhs.data()), lhs.size()),
70 std::basic_string_view<uint8_t>(reinterpret_cast<uint8_t const*>(rhs.data()), rhs.size()));
71 }
72
73 /**
74 * /brief Helper to move-assign guaranteeing same member destruction order as the destructor.
75 *
76 * The implicity-defined move operator performs a member-wise move
77 * (class.copy.assign 15.8.2.12 in the C++17 standard), which can lead to members
78 * being destroyed in construction order, e.g. if moving a std::unique_ptr
79 *
80 * If the members depend on being destroyed in destruction order, by default the
81 * reverse default construction order, the implicitly-defined move operator cannot
82 * be used.
83 *
84 * By first explicitly destructing the moved-to instance and then placement
85 * move-constructing it from the moved-from instance, correct destruction order is guaranteed.
86 */
87 template<typename T, typename std::enable_if_t<std::is_final_v<T>>* = nullptr>
88 T& move_assign_through_move_constructor(T* p, T&& op) noexcept
89 {
90 p->~T();
91 new (p)T(std::move(op));
92 return *p;
93 }
94
95 }
96
97 #endif
98