Line data Source code
1 : #pragma once 2 : 3 : #include <cstring> 4 : #include <cassert> 5 : #include <type_traits> 6 : #include <vector> 7 : #include <string> 8 : #include <atomic> 9 : 10 : #ifdef __INTEL_COMPILER 11 : #pragma warning(disable : 597) // will not be called for implicit or explicit conversions 12 : #endif 13 : 14 : namespace dev { 15 : 16 : /** 17 : * A modifiable reference to an existing object or vector in memory. 18 : */ 19 : template<class _T> 20 : class vector_ref 21 : { 22 : public: 23 : using value_type = _T; 24 : using element_type = _T; 25 : using mutable_value_type = typename std:: 26 : conditional<std::is_const<_T>::value, typename std::remove_const<_T>::type, _T>::type; 27 : 28 : static_assert(std::is_pod<value_type>::value, 29 : "vector_ref can only be used with PODs due to its low-level treatment of data."); 30 : 31 44 : vector_ref() 32 44 : : m_data(nullptr) 33 44 : , m_count(0) 34 44 : {} 35 : /// Creates a new vector_ref to point to @a _count elements starting at @a _data. 36 7659 : vector_ref(_T* _data, size_t _count) 37 7659 : : m_data(_data) 38 7659 : , m_count(_count) 39 7659 : {} 40 : /// Creates a new vector_ref pointing to the data part of a string (given as pointer). 41 : vector_ref( 42 : typename std::conditional<std::is_const<_T>::value, std::string const*, std::string*>::type 43 : _data) 44 : : m_data(reinterpret_cast<_T*>(_data->data())) 45 : , m_count(_data->size() / sizeof(_T)) 46 : {} 47 : /// Creates a new vector_ref pointing to the data part of a vector (given as pointer). 48 : vector_ref(typename std::conditional<std::is_const<_T>::value, 49 : std::vector<typename std::remove_const<_T>::type> const*, 50 : std::vector<_T>*>::type _data) 51 : : m_data(_data->data()) 52 : , m_count(_data->size()) 53 : {} 54 : /// Creates a new vector_ref pointing to the data part of a string (given as reference). 55 : vector_ref( 56 : typename std::conditional<std::is_const<_T>::value, std::string const&, std::string&>::type 57 : _data) 58 : : m_data(reinterpret_cast<_T*>(_data.data())) 59 : , m_count(_data.size() / sizeof(_T)) 60 : {} 61 : explicit operator bool() const { return m_data && m_count; } 62 : 63 : bool contentsEqual(std::vector<mutable_value_type> const& _c) const 64 : { 65 : if (!m_data || m_count == 0) 66 : return _c.empty(); 67 : else 68 : return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count * sizeof(_T)); 69 : } 70 : std::vector<mutable_value_type> toVector() const 71 : { 72 : return std::vector<mutable_value_type>(m_data, m_data + m_count); 73 : } 74 : std::vector<unsigned char> toBytes() const 75 : { 76 : return std::vector<unsigned char>(reinterpret_cast<unsigned char const*>(m_data), 77 : reinterpret_cast<unsigned char const*>(m_data) 78 : + m_count * sizeof(_T)); 79 : } 80 : std::string toString() const 81 : { 82 : return std::string((char const*) m_data, ((char const*) m_data) + m_count * sizeof(_T)); 83 : } 84 : 85 : template<class _T2> 86 : explicit operator vector_ref<_T2>() const 87 : { 88 : assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); 89 : return vector_ref<_T2>(reinterpret_cast<_T2*>(m_data), m_count * sizeof(_T) / sizeof(_T2)); 90 : } 91 : operator vector_ref<_T const>() const { return vector_ref<_T const>(m_data, m_count); } 92 : 93 3134 : _T* data() const { return m_data; } 94 : /// @returns the number of elements referenced (not necessarily number of bytes). 95 : size_t count() const { return m_count; } 96 : /// @returns the number of elements referenced (not necessarily number of bytes). 97 3134 : size_t size() const { return m_count; } 98 : bool empty() const { return !m_count; } 99 : /// @returns a new vector_ref pointing at the next chunk of @a size() elements. 100 : vector_ref<_T> next() const 101 : { 102 : if (!m_data) 103 : return *this; 104 : else 105 : return vector_ref<_T>(m_data + m_count, m_count); 106 : } 107 : /// @returns a new vector_ref which is a shifted and shortened view of the original data. 108 : /// If this goes out of bounds in any way, returns an empty vector_ref. 109 : /// If @a _count is ~size_t(0), extends the view to the end of the data. 110 : vector_ref<_T> cropped(size_t _begin, size_t _count) const 111 : { 112 : if (m_data && _begin <= m_count && _count <= m_count && _begin + _count <= m_count) 113 : return vector_ref<_T>(m_data + _begin, _count == ~size_t(0) ? m_count - _begin : _count); 114 : else 115 : return vector_ref<_T>(); 116 : } 117 : /// @returns a new vector_ref which is a shifted view of the original data (not going beyond it). 118 : vector_ref<_T> cropped(size_t _begin) const 119 : { 120 : if (m_data && _begin <= m_count) 121 : return vector_ref<_T>(m_data + _begin, m_count - _begin); 122 : else 123 : return vector_ref<_T>(); 124 : } 125 : void retarget(_T* _d, size_t _s) 126 : { 127 : m_data = _d; 128 : m_count = _s; 129 : } 130 : void retarget(std::vector<_T> const& _t) 131 : { 132 : m_data = _t.data(); 133 : m_count = _t.size(); 134 : } 135 : /// Securely overwrite the memory. 136 : /// @note adapted from OpenSSL's implementation. 137 3785 : void cleanse() 138 : { 139 : static std::atomic<unsigned char> s_cleanseCounter {0u}; 140 3785 : uint8_t* p = (uint8_t*) begin(); 141 3785 : size_t const len = (uint8_t*) end() - p; 142 3785 : size_t loop = len; 143 3785 : size_t count = s_cleanseCounter; 144 124905 : while (loop--) { 145 121120 : *(p++) = (uint8_t) count; 146 121120 : count += (17 + ((size_t) p & 0xf)); 147 : } 148 3785 : p = (uint8_t*) memchr((uint8_t*) begin(), (uint8_t) count, len); 149 3785 : if (p) 150 0 : count += (63 + (size_t) p); 151 3785 : s_cleanseCounter = (uint8_t) count; 152 3785 : memset((uint8_t*) begin(), 0, len); 153 3785 : } 154 : 155 11355 : _T* begin() { return m_data; } 156 3785 : _T* end() { return m_data + m_count; } 157 784 : _T const* begin() const { return m_data; } 158 784 : _T const* end() const { return m_data + m_count; } 159 : 160 : _T& operator[](size_t _i) 161 : { 162 : assert(m_data); 163 : assert(_i < m_count); 164 : return m_data[_i]; 165 : } 166 : _T const& operator[](size_t _i) const 167 : { 168 : assert(m_data); 169 : assert(_i < m_count); 170 : return m_data[_i]; 171 : } 172 : 173 : bool operator==(vector_ref<_T> const& _cmp) const 174 : { 175 : return m_data == _cmp.m_data && m_count == _cmp.m_count; 176 : } 177 : bool operator!=(vector_ref<_T> const& _cmp) const { return !operator==(_cmp); } 178 : 179 : void reset() 180 : { 181 : m_data = nullptr; 182 : m_count = 0; 183 : } 184 : 185 : private: 186 : _T* m_data; 187 : size_t m_count; 188 : }; 189 : 190 : template<class _T> 191 : vector_ref<_T const> 192 : ref(_T const& _t) 193 : { 194 : return vector_ref<_T const>(&_t, 1); 195 : } 196 : template<class _T> 197 : vector_ref<_T> 198 : ref(_T& _t) 199 : { 200 : return vector_ref<_T>(&_t, 1); 201 : } 202 : template<class _T> 203 : vector_ref<_T const> 204 : ref(std::vector<_T> const& _t) 205 : { 206 : return vector_ref<_T const>(&_t); 207 : } 208 : template<class _T> 209 : vector_ref<_T> 210 : ref(std::vector<_T>& _t) 211 : { 212 : return vector_ref<_T>(&_t); 213 : } 214 : 215 : } // namespace dev