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