Coverage Report

Created: 2022-08-24 06:39

/src/solidity/libsolutil/FixedHash.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
  This file is part of solidity.
3
4
  solidity is free software: you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation, either version 3 of the License, or
7
  (at your option) any later version.
8
9
  solidity is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
// SPDX-License-Identifier: GPL-3.0
18
/** @file FixedHash.h
19
 * @author Gav Wood <i@gavwood.com>
20
 * @date 2014
21
 *
22
 * The FixedHash fixed-size "hash" container type.
23
 */
24
25
#pragma once
26
27
#include <libsolutil/CommonData.h>
28
#include <libsolutil/Numeric.h>
29
30
#include <boost/functional/hash.hpp>
31
#include <boost/io/ios_state.hpp>
32
33
#include <array>
34
#include <cstdint>
35
#include <algorithm>
36
37
namespace solidity::util
38
{
39
40
/// Fixed-size raw-byte array container type, with an API optimised for storing hashes.
41
/// Transparently converts to/from the corresponding arithmetic type; this will
42
/// assume the data contained in the hash is big-endian.
43
template <unsigned N>
44
class FixedHash
45
{
46
public:
47
  /// The corresponding arithmetic type.
48
  using Arith = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
49
50
  /// The size of the container.
51
  enum { size = N };
52
  static_assert(N != 0);
53
54
  /// Method to convert from a string.
55
  enum ConstructFromStringType { FromHex, FromBinary };
56
57
  /// Method to convert from a string.
58
  enum ConstructFromHashType { AlignLeft, AlignRight, FailIfDifferent };
59
60
  /// Construct an empty hash.
61
11.0k
  explicit FixedHash() { m_data.fill(0); }
62
63
  /// Construct from another hash, filling with zeroes or cropping as necessary.
64
  template <unsigned M> explicit FixedHash(FixedHash<M> const& _h, ConstructFromHashType _t = AlignLeft)
65
5.48k
  {
66
5.48k
    m_data.fill(0);
67
5.48k
    unsigned c = std::min(M, N);
68
115k
    for (unsigned i = 0; i < c; ++i)
69
109k
      m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i];
70
5.48k
  }
71
72
  /// Convert from the corresponding arithmetic type.
73
514
  FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
74
75
  /// Explicitly construct, copying from a byte array.
76
  explicit FixedHash(bytes const& _array, ConstructFromHashType _sizeMismatchBehavior = FailIfDifferent)
77
86.2k
  {
78
86.2k
    if (_array.size() == N)
79
63.1k
      memcpy(m_data.data(), _array.data(), _array.size());
80
23.1k
    else
81
23.1k
    {
82
23.1k
      m_data.fill(0);
83
23.1k
      if (_sizeMismatchBehavior != FailIfDifferent)
84
23.1k
      {
85
23.1k
        auto bytesToCopy = std::min<size_t>(_array.size(), N);
86
54.5k
        for (size_t i = 0; i < bytesToCopy; ++i)
87
31.3k
          if (_sizeMismatchBehavior == AlignRight)
88
0
            m_data[N - 1 - i] = _array[_array.size() - 1 - i];
89
31.3k
          else
90
31.3k
            m_data[i] = _array[i];
91
23.1k
      }
92
23.1k
    }
93
86.2k
  }
solidity::util::FixedHash<32u>::FixedHash(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&, solidity::util::FixedHash<32u>::ConstructFromHashType)
Line
Count
Source
77
86.1k
  {
78
86.1k
    if (_array.size() == N)
79
62.9k
      memcpy(m_data.data(), _array.data(), _array.size());
80
23.1k
    else
81
23.1k
    {
82
23.1k
      m_data.fill(0);
83
23.1k
      if (_sizeMismatchBehavior != FailIfDifferent)
84
23.1k
      {
85
23.1k
        auto bytesToCopy = std::min<size_t>(_array.size(), N);
86
54.5k
        for (size_t i = 0; i < bytesToCopy; ++i)
87
31.3k
          if (_sizeMismatchBehavior == AlignRight)
88
0
            m_data[N - 1 - i] = _array[_array.size() - 1 - i];
89
31.3k
          else
90
31.3k
            m_data[i] = _array[i];
91
23.1k
      }
92
23.1k
    }
93
86.1k
  }
solidity::util::FixedHash<20u>::FixedHash(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&, solidity::util::FixedHash<20u>::ConstructFromHashType)
Line
Count
Source
77
128
  {
78
128
    if (_array.size() == N)
79
128
      memcpy(m_data.data(), _array.data(), _array.size());
80
0
    else
81
0
    {
82
0
      m_data.fill(0);
83
0
      if (_sizeMismatchBehavior != FailIfDifferent)
84
0
      {
85
0
        auto bytesToCopy = std::min<size_t>(_array.size(), N);
86
0
        for (size_t i = 0; i < bytesToCopy; ++i)
87
0
          if (_sizeMismatchBehavior == AlignRight)
88
0
            m_data[N - 1 - i] = _array[_array.size() - 1 - i];
89
0
          else
90
0
            m_data[i] = _array[i];
91
0
      }
92
0
    }
93
128
  }
94
95
  /// Explicitly construct, copying from a byte array.
96
  explicit FixedHash(bytesConstRef _b, ConstructFromHashType _t = FailIfDifferent)
97
0
  {
98
0
    if (_b.size() == N)
99
0
      memcpy(m_data.data(), _b.data(), std::min<size_t>(_b.size(), N));
100
0
    else
101
0
    {
102
0
      m_data.fill(0);
103
0
      if (_t != FailIfDifferent)
104
0
      {
105
0
        auto c = std::min<size_t>(_b.size(), N);
106
0
        for (size_t i = 0; i < c; ++i)
107
0
          if (_t == AlignRight)
108
0
            m_data[N - 1 - i] = _b[_b.size() - 1 - i];
109
0
          else
110
0
            m_data[i] = _b[i];
111
0
      }
112
0
    }
113
0
  }
114
115
  /// Explicitly construct, copying from a string.
116
  explicit FixedHash(std::string const& _s, ConstructFromStringType _t = FromHex, ConstructFromHashType _ht = FailIfDifferent):
117
    FixedHash(_t == FromHex ? fromHex(_s, WhenError::Throw) : solidity::util::asBytes(_s), _ht)
118
24.0k
  {}
119
120
  /// Convert to arithmetic type.
121
48.0k
  operator Arith() const { return fromBigEndian<Arith>(m_data); }
122
123
  // The obvious comparison operators.
124
  bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; }
125
  bool operator!=(FixedHash const& _c) const { return m_data != _c.m_data; }
126
  /// Required to sort objects of this type or use them as map keys.
127
1.12k
  bool operator<(FixedHash const& _c) const {
128
30.2k
    for (unsigned i = 0; i < N; ++i)
129
29.3k
    {
130
29.3k
      if (m_data[i] < _c.m_data[i])
131
174
        return true;
132
29.1k
      else if (m_data[i] > _c.m_data[i])
133
41
        return false;
134
29.3k
    }
135
910
    return false;
136
1.12k
  }
137
138
  /// @returns a particular byte from the hash.
139
0
  uint8_t& operator[](unsigned _i) { return m_data[_i]; }
140
  /// @returns a particular byte from the hash.
141
1.62M
  uint8_t operator[](unsigned _i) const { return m_data[_i]; }
solidity::util::FixedHash<20u>::operator[](unsigned int) const
Line
Count
Source
141
112k
  uint8_t operator[](unsigned _i) const { return m_data[_i]; }
solidity::util::FixedHash<32u>::operator[](unsigned int) const
Line
Count
Source
141
1.51M
  uint8_t operator[](unsigned _i) const { return m_data[_i]; }
142
143
  /// @returns the hash as a user-readable hex string.
144
0
  std::string hex() const { return toHex(asBytes()); }
145
146
  /// @returns a mutable byte vector_ref to the object's data.
147
  bytesRef ref() { return bytesRef(m_data.data(), N); }
148
149
  /// @returns a constant byte vector_ref to the object's data.
150
  bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
151
152
  /// @returns a mutable byte pointer to the object's data.
153
11.0k
  uint8_t* data() { return m_data.data(); }
154
155
  /// @returns a constant byte pointer to the object's data.
156
0
  uint8_t const* data() const { return m_data.data(); }
Unexecuted instantiation: solidity::util::FixedHash<32u>::data() const
Unexecuted instantiation: solidity::util::FixedHash<20u>::data() const
157
158
  /// @returns a copy of the object's data as a byte vector.
159
0
  bytes asBytes() const { return bytes(data(), data() + N); }
160
161
private:
162
  std::array<uint8_t, N> m_data;    ///< The binary data.
163
};
164
165
/// Stream I/O for the FixedHash class.
166
template <unsigned N>
167
inline std::ostream& operator<<(std::ostream& _out, FixedHash<N> const& _h)
168
38.3k
{
169
38.3k
  boost::io::ios_all_saver guard(_out);
170
38.3k
  _out << std::noshowbase << std::hex << std::setfill('0');
171
1.26M
  for (unsigned i = 0; i < N; ++i)
172
1.22M
    _out << std::setw(2) << (int)_h[i];
173
38.3k
  _out << std::dec;
174
38.3k
  return _out;
175
38.3k
}
std::__1::basic_ostream<char, std::__1::char_traits<char> >& solidity::util::operator<< <32u>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, solidity::util::FixedHash<32u> const&)
Line
Count
Source
168
38.2k
{
169
38.2k
  boost::io::ios_all_saver guard(_out);
170
38.2k
  _out << std::noshowbase << std::hex << std::setfill('0');
171
1.26M
  for (unsigned i = 0; i < N; ++i)
172
1.22M
    _out << std::setw(2) << (int)_h[i];
173
38.2k
  _out << std::dec;
174
38.2k
  return _out;
175
38.2k
}
std::__1::basic_ostream<char, std::__1::char_traits<char> >& solidity::util::operator<< <20u>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, solidity::util::FixedHash<20u> const&)
Line
Count
Source
168
128
{
169
128
  boost::io::ios_all_saver guard(_out);
170
128
  _out << std::noshowbase << std::hex << std::setfill('0');
171
2.68k
  for (unsigned i = 0; i < N; ++i)
172
2.56k
    _out << std::setw(2) << (int)_h[i];
173
128
  _out << std::dec;
174
128
  return _out;
175
128
}
176
177
// Common types of FixedHash.
178
using h256 = FixedHash<32>;
179
using h160 = FixedHash<20>;
180
181
}