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 = 26 : typename std::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 40 : vector_ref() 32 40 : : m_data(nullptr) 33 40 : , m_count(0) 34 40 : {} 35 : /// Creates a new vector_ref to point to @a _count elements starting at @a _data. 36 7555 : vector_ref(_T* _data, size_t _count) 37 7555 : : m_data(_data) 38 7555 : , m_count(_count) 39 7555 : {} 40 : /// Creates a new vector_ref pointing to the data part of a string (given as pointer). 41 : vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const*, std::string*>::type _data) 42 : : m_data(reinterpret_cast<_T*>(_data->data())) 43 : , m_count(_data->size() / sizeof(_T)) 44 : {} 45 : /// Creates a new vector_ref pointing to the data part of a vector (given as pointer). 46 : vector_ref(typename std::conditional<std::is_const<_T>::value, 47 : std::vector<typename std::remove_const<_T>::type> const*, 48 : std::vector<_T>*>::type _data) 49 : : m_data(_data->data()) 50 : , m_count(_data->size()) 51 : {} 52 : /// Creates a new vector_ref pointing to the data part of a string (given as reference). 53 : vector_ref(typename std::conditional<std::is_const<_T>::value, std::string const&, std::string&>::type _data) 54 : : m_data(reinterpret_cast<_T*>(_data.data())) 55 : , m_count(_data.size() / sizeof(_T)) 56 : {} 57 : explicit operator bool() const { return m_data && m_count; } 58 : 59 : bool contentsEqual(std::vector<mutable_value_type> const& _c) const 60 : { 61 : if (!m_data || m_count == 0) 62 : return _c.empty(); 63 : else 64 : return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count * sizeof(_T)); 65 : } 66 : std::vector<mutable_value_type> toVector() const 67 : { 68 : return std::vector<mutable_value_type>(m_data, m_data + m_count); 69 : } 70 : std::vector<unsigned char> toBytes() const 71 : { 72 : return std::vector<unsigned char>(reinterpret_cast<unsigned char const*>(m_data), 73 : reinterpret_cast<unsigned char const*>(m_data) + m_count * sizeof(_T)); 74 : } 75 : std::string toString() const 76 : { 77 : return std::string((char const*) m_data, ((char const*) m_data) + m_count * sizeof(_T)); 78 : } 79 : 80 : template<class _T2> 81 : explicit operator vector_ref<_T2>() const 82 : { 83 : assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); 84 : return vector_ref<_T2>(reinterpret_cast<_T2*>(m_data), m_count * sizeof(_T) / sizeof(_T2)); 85 : } 86 : operator vector_ref<_T const>() const { return vector_ref<_T const>(m_data, m_count); } 87 : 88 3086 : _T* data() const { return m_data; } 89 : /// @returns the number of elements referenced (not necessarily number of bytes). 90 : size_t count() const { return m_count; } 91 : /// @returns the number of elements referenced (not necessarily number of bytes). 92 3086 : size_t size() const { return m_count; } 93 : bool empty() const { return !m_count; } 94 : /// @returns a new vector_ref pointing at the next chunk of @a size() elements. 95 : vector_ref<_T> next() const 96 : { 97 : if (!m_data) 98 : return *this; 99 : else 100 : return vector_ref<_T>(m_data + m_count, m_count); 101 : } 102 : /// @returns a new vector_ref which is a shifted and shortened view of the original data. 103 : /// If this goes out of bounds in any way, returns an empty vector_ref. 104 : /// If @a _count is ~size_t(0), extends the view to the end of the data. 105 : vector_ref<_T> cropped(size_t _begin, size_t _count) const 106 : { 107 : if (m_data && _begin <= m_count && _count <= m_count && _begin + _count <= m_count) 108 : return vector_ref<_T>(m_data + _begin, _count == ~size_t(0) ? m_count - _begin : _count); 109 : else 110 : return vector_ref<_T>(); 111 : } 112 : /// @returns a new vector_ref which is a shifted view of the original data (not going beyond it). 113 : vector_ref<_T> cropped(size_t _begin) const 114 : { 115 : if (m_data && _begin <= m_count) 116 : return vector_ref<_T>(m_data + _begin, m_count - _begin); 117 : else 118 : return vector_ref<_T>(); 119 : } 120 : void retarget(_T* _d, size_t _s) 121 : { 122 : m_data = _d; 123 : m_count = _s; 124 : } 125 : void retarget(std::vector<_T> const& _t) 126 : { 127 : m_data = _t.data(); 128 : m_count = _t.size(); 129 : } 130 : /// Securely overwrite the memory. 131 : /// @note adapted from OpenSSL's implementation. 132 3734 : void cleanse() 133 : { 134 : static std::atomic<unsigned char> s_cleanseCounter {0u}; 135 3734 : uint8_t* p = (uint8_t*) begin(); 136 3734 : size_t const len = (uint8_t*) end() - p; 137 3734 : size_t loop = len; 138 3734 : size_t count = s_cleanseCounter; 139 123222 : while (loop--) { 140 119488 : *(p++) = (uint8_t) count; 141 119488 : count += (17 + ((size_t) p & 0xf)); 142 : } 143 3734 : p = (uint8_t*) memchr((uint8_t*) begin(), (uint8_t) count, len); 144 3734 : if (p) 145 0 : count += (63 + (size_t) p); 146 3734 : s_cleanseCounter = (uint8_t) count; 147 3734 : memset((uint8_t*) begin(), 0, len); 148 3734 : } 149 : 150 11202 : _T* begin() { return m_data; } 151 3734 : _T* end() { return m_data + m_count; } 152 775 : _T const* begin() const { return m_data; } 153 775 : _T const* end() const { return m_data + m_count; } 154 : 155 : _T& operator[](size_t _i) 156 : { 157 : assert(m_data); 158 : assert(_i < m_count); 159 : return m_data[_i]; 160 : } 161 : _T const& operator[](size_t _i) const 162 : { 163 : assert(m_data); 164 : assert(_i < m_count); 165 : return m_data[_i]; 166 : } 167 : 168 : bool operator==(vector_ref<_T> const& _cmp) const { return m_data == _cmp.m_data && m_count == _cmp.m_count; } 169 : bool operator!=(vector_ref<_T> const& _cmp) const { return !operator==(_cmp); } 170 : 171 : void reset() 172 : { 173 : m_data = nullptr; 174 : m_count = 0; 175 : } 176 : 177 : private: 178 : _T* m_data; 179 : size_t m_count; 180 : }; 181 : 182 : template<class _T> 183 : vector_ref<_T const> 184 : ref(_T const& _t) 185 : { 186 : return vector_ref<_T const>(&_t, 1); 187 : } 188 : template<class _T> 189 : vector_ref<_T> 190 : ref(_T& _t) 191 : { 192 : return vector_ref<_T>(&_t, 1); 193 : } 194 : template<class _T> 195 : vector_ref<_T const> 196 : ref(std::vector<_T> const& _t) 197 : { 198 : return vector_ref<_T const>(&_t); 199 : } 200 : template<class _T> 201 : vector_ref<_T> 202 : ref(std::vector<_T>& _t) 203 : { 204 : return vector_ref<_T>(&_t); 205 : } 206 : 207 : } // namespace dev