aboutsummaryrefslogtreecommitdiffstats
path: root/util/generic/utility.h
blob: bb0534d2971dafc3e43ad1a2cadedaed8c84beee (plain) (blame)
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
#pragma once 

#include "typetraits.h"

#include <cstring>

template <class T>
static constexpr const T& Min(const T& l, const T& r) {
    return r < l ? r : l;
}

template <typename T, typename... Args>
static constexpr const T& Min(const T& a, const T& b, const Args&... args) {
    return Min(a, Min(b, args...));
}

template <class T>
static constexpr const T& Max(const T& l, const T& r) {
    return l < r ? r : l;
}

template <typename T, typename... Args>
static constexpr const T& Max(const T& a, const T& b, const Args&... args) {
    return Max(a, Max(b, args...));
}

// replace with http://en.cppreference.com/w/cpp/algorithm/clamp in c++17
template <class T>
constexpr const T& ClampVal(const T& val, const T& min, const T& max) {
    return val < min ? min : (max < val ? max : val);
}

template <typename T = double, typename... Args>
static T Mean(const Args&... other) noexcept {
    const auto numArgs = sizeof...(other);

    auto sum = T();
    for (const auto& v : {other...}) {
        sum += v;
    }

    return sum / numArgs;
}

template <class T>
static inline void Zero(T& t) noexcept {
    memset((void*)&t, 0, sizeof(t));
}

/**
 * Securely zero memory (compiler does not optimize this out)
 *
 * @param pointer   void pointer to start of memory block to be zeroed
 * @param count     size of memory block to be zeroed (in bytes)
 */
void SecureZero(void* pointer, size_t count) noexcept;

/**
 * Securely zero memory of given object (compiler does not optimize this out)
 *
 * @param t     reference to object, which must be zeroed
 */
template <class T>
static inline void SecureZero(T& t) noexcept {
    SecureZero((void*)&t, sizeof(t));
}

namespace NSwapCheck {
    Y_HAS_MEMBER(swap);
    Y_HAS_MEMBER(Swap);

    template <class T, class = void>
    struct TSwapSelector {
        static inline void Swap(T& l, T& r) noexcept(std::is_nothrow_move_constructible<T>::value&&
                                                         std::is_nothrow_move_assignable<T>::value) {
            T tmp(std::move(l));
            l = std::move(r);
            r = std::move(tmp);
        }
    };

    template <class T>
    struct TSwapSelector<T, std::enable_if_t<THasSwap<T>::value>> {
        static inline void Swap(T& l, T& r) noexcept(noexcept(l.Swap(r))) {
            l.Swap(r);
        }
    };

    template <class T>
    struct TSwapSelector<T, std::enable_if_t<THasswap<T>::value && !THasSwap<T>::value>> {
        static inline void Swap(T& l, T& r) noexcept(noexcept(l.swap(r))) {
            l.swap(r);
        }
    };
}

/*
 * DoSwap better than ::Swap in member functions...
 */
template <class T>
static inline void DoSwap(T& l, T& r) noexcept(noexcept(NSwapCheck::TSwapSelector<T>::Swap(l, r))) {
    NSwapCheck::TSwapSelector<T>::Swap(l, r);
}

template <bool b>
struct TNullTmpl {
    template <class T>
    operator T() const {
        return (T)0;
    }
};

using TNull = TNullTmpl<0>;

/*
 * Class for zero-initialize padding bytes in derived classes
 */
template <typename TDerived>
class TZeroInit {
protected:
    TZeroInit() {
        // Actually, safe because this as TDerived is not initialized yet.
        Zero(*static_cast<TDerived*>(this));
    }
};

struct TIdentity {
    template <class T>
    constexpr decltype(auto) operator()(T&& x) const noexcept {
        return std::forward<T>(x);
    }
};