Coverage Report

Created: 2025-06-24 07:59

/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
3.37M
  explicit FixedHash() { m_data.fill(0); }
Unexecuted instantiation: solidity::util::FixedHash<20u>::FixedHash()
solidity::util::FixedHash<32u>::FixedHash()
Line
Count
Source
61
3.37M
  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)
65
194k
  {
66
194k
    m_data.fill(0);
67
194k
    unsigned c = std::min(M, N);
68
2.84M
    for (unsigned i = 0; i < c; ++i)
69
2.65M
      m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i];
70
194k
  }
solidity::util::FixedHash<20u>::FixedHash<32u>(solidity::util::FixedHash<32u> const&, solidity::util::FixedHash<20u>::ConstructFromHashType)
Line
Count
Source
65
33.1k
  {
66
33.1k
    m_data.fill(0);
67
33.1k
    unsigned c = std::min(M, N);
68
695k
    for (unsigned i = 0; i < c; ++i)
69
662k
      m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i];
70
33.1k
  }
solidity::util::FixedHash<4u>::FixedHash<32u>(solidity::util::FixedHash<32u> const&, solidity::util::FixedHash<4u>::ConstructFromHashType)
Line
Count
Source
65
76.9k
  {
66
76.9k
    m_data.fill(0);
67
76.9k
    unsigned c = std::min(M, N);
68
384k
    for (unsigned i = 0; i < c; ++i)
69
307k
      m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i];
70
76.9k
  }
solidity::util::FixedHash<32u>::FixedHash<20u>(solidity::util::FixedHash<20u> const&, solidity::util::FixedHash<32u>::ConstructFromHashType)
Line
Count
Source
65
83.9k
  {
66
83.9k
    m_data.fill(0);
67
83.9k
    unsigned c = std::min(M, N);
68
1.76M
    for (unsigned i = 0; i < c; ++i)
69
1.67M
      m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i];
70
83.9k
  }
71
72
  /// Convert from the corresponding arithmetic type.
73
1.16M
  FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
solidity::util::FixedHash<32u>::FixedHash(boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<256ul, 256ul, (boost::multiprecision::cpp_integer_type)0, (boost::multiprecision::cpp_int_check_type)0, void>, (boost::multiprecision::expression_template_option)0> const&)
Line
Count
Source
73
856k
  FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
solidity::util::FixedHash<1u>::FixedHash(boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<8ul, 8ul, (boost::multiprecision::cpp_integer_type)0, (boost::multiprecision::cpp_int_check_type)0, void>, (boost::multiprecision::expression_template_option)0> const&)
Line
Count
Source
73
313k
  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
1.20M
  {
78
1.20M
    if (_array.size() == N)
79
993k
      memcpy(m_data.data(), _array.data(), _array.size());
80
210k
    else
81
210k
    {
82
210k
      m_data.fill(0);
83
210k
      if (_sizeMismatchBehavior != FailIfDifferent)
84
210k
      {
85
210k
        auto bytesToCopy = std::min<size_t>(_array.size(), N);
86
1.18M
        for (size_t i = 0; i < bytesToCopy; ++i)
87
971k
          if (_sizeMismatchBehavior == AlignRight)
88
0
            m_data[N - 1 - i] = _array[_array.size() - 1 - i];
89
971k
          else
90
971k
            m_data[i] = _array[i];
91
210k
      }
92
210k
    }
93
1.20M
  }
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
440k
  {
78
440k
    if (_array.size() == N)
79
440k
      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
440k
  }
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
762k
  {
78
762k
    if (_array.size() == N)
79
552k
      memcpy(m_data.data(), _array.data(), _array.size());
80
210k
    else
81
210k
    {
82
210k
      m_data.fill(0);
83
210k
      if (_sizeMismatchBehavior != FailIfDifferent)
84
210k
      {
85
210k
        auto bytesToCopy = std::min<size_t>(_array.size(), N);
86
1.18M
        for (size_t i = 0; i < bytesToCopy; ++i)
87
971k
          if (_sizeMismatchBehavior == AlignRight)
88
0
            m_data[N - 1 - i] = _array[_array.size() - 1 - i];
89
971k
          else
90
971k
            m_data[i] = _array[i];
91
210k
      }
92
210k
    }
93
762k
  }
94
95
  /// Explicitly construct, copying from a byte array.
96
  explicit FixedHash(bytesConstRef _b, ConstructFromHashType _t = FailIfDifferent)
97
16.5k
  {
98
16.5k
    if (_b.size() == N)
99
1.71k
      memcpy(m_data.data(), _b.data(), std::min<size_t>(_b.size(), N));
100
14.8k
    else
101
14.8k
    {
102
14.8k
      m_data.fill(0);
103
14.8k
      if (_t != FailIfDifferent)
104
14.8k
      {
105
14.8k
        auto c = std::min<size_t>(_b.size(), N);
106
123k
        for (size_t i = 0; i < c; ++i)
107
108k
          if (_t == AlignRight)
108
0
            m_data[N - 1 - i] = _b[_b.size() - 1 - i];
109
108k
          else
110
108k
            m_data[i] = _b[i];
111
14.8k
      }
112
14.8k
    }
113
16.5k
  }
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
663k
  {}
solidity::util::FixedHash<32u>::FixedHash(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, solidity::util::FixedHash<32u>::ConstructFromStringType, solidity::util::FixedHash<32u>::ConstructFromHashType)
Line
Count
Source
118
222k
  {}
solidity::util::FixedHash<20u>::FixedHash(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, solidity::util::FixedHash<20u>::ConstructFromStringType, solidity::util::FixedHash<20u>::ConstructFromHashType)
Line
Count
Source
118
440k
  {}
119
120
  /// Convert to arithmetic type.
121
1.12M
  operator Arith() const { return fromBigEndian<Arith>(m_data); }
solidity::util::FixedHash<32u>::operator boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<256ul, 256ul, (boost::multiprecision::cpp_integer_type)0, (boost::multiprecision::cpp_int_check_type)0, void>, (boost::multiprecision::expression_template_option)0>() const
Line
Count
Source
121
963k
  operator Arith() const { return fromBigEndian<Arith>(m_data); }
solidity::util::FixedHash<4u>::operator boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<32ul, 32ul, (boost::multiprecision::cpp_integer_type)0, (boost::multiprecision::cpp_int_check_type)0, void>, (boost::multiprecision::expression_template_option)0>() const
Line
Count
Source
121
66.4k
  operator Arith() const { return fromBigEndian<Arith>(m_data); }
solidity::util::FixedHash<20u>::operator boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<160ul, 160ul, (boost::multiprecision::cpp_integer_type)0, (boost::multiprecision::cpp_int_check_type)0, void>, (boost::multiprecision::expression_template_option)0>() const
Line
Count
Source
121
93.4k
  operator Arith() const { return fromBigEndian<Arith>(m_data); }
122
123
  // The obvious comparison operators.
124
33.6k
  bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; }
125
167k
  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.86M
  bool operator<(FixedHash const& _c) const {
128
35.9M
    for (unsigned i = 0; i < N; ++i)
129
35.4M
    {
130
35.4M
      if (m_data[i] < _c.m_data[i])
131
821k
        return true;
132
34.6M
      else if (m_data[i] > _c.m_data[i])
133
517k
        return false;
134
35.4M
    }
135
527k
    return false;
136
1.86M
  }
solidity::util::FixedHash<32u>::operator<(solidity::util::FixedHash<32u> const&) const
Line
Count
Source
127
1.63M
  bool operator<(FixedHash const& _c) const {
128
35.5M
    for (unsigned i = 0; i < N; ++i)
129
35.0M
    {
130
35.0M
      if (m_data[i] < _c.m_data[i])
131
712k
        return true;
132
34.3M
      else if (m_data[i] > _c.m_data[i])
133
454k
        return false;
134
35.0M
    }
135
471k
    return false;
136
1.63M
  }
solidity::util::FixedHash<4u>::operator<(solidity::util::FixedHash<4u> const&) const
Line
Count
Source
127
227k
  bool operator<(FixedHash const& _c) const {
128
451k
    for (unsigned i = 0; i < N; ++i)
129
395k
    {
130
395k
      if (m_data[i] < _c.m_data[i])
131
109k
        return true;
132
286k
      else if (m_data[i] > _c.m_data[i])
133
62.7k
        return false;
134
395k
    }
135
55.7k
    return false;
136
227k
  }
137
138
  /// @returns a particular byte from the hash.
139
6.44k
  uint8_t& operator[](unsigned _i) { return m_data[_i]; }
140
  /// @returns a particular byte from the hash.
141
11.6M
  uint8_t operator[](unsigned _i) const { return m_data[_i]; }
solidity::util::FixedHash<20u>::operator[](unsigned int) const
Line
Count
Source
141
2.34M
  uint8_t operator[](unsigned _i) const { return m_data[_i]; }
solidity::util::FixedHash<32u>::operator[](unsigned int) const
Line
Count
Source
141
9.28M
  uint8_t operator[](unsigned _i) const { return m_data[_i]; }
142
143
  /// @returns the hash as a user-readable hex string.
144
200k
  std::string hex() const { return toHex(asBytes()); }
solidity::util::FixedHash<4u>::hex() const
Line
Count
Source
144
6.64k
  std::string hex() const { return toHex(asBytes()); }
solidity::util::FixedHash<32u>::hex() const
Line
Count
Source
144
193k
  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
55.7k
  bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
solidity::util::FixedHash<32u>::ref() const
Line
Count
Source
150
55.6k
  bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
solidity::util::FixedHash<4u>::ref() const
Line
Count
Source
150
57
  bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
151
152
  /// @returns a mutable byte pointer to the object's data.
153
2.91M
  uint8_t* data() { return m_data.data(); }
154
155
  /// @returns a constant byte pointer to the object's data.
156
6.17M
  uint8_t const* data() const { return m_data.data(); }
solidity::util::FixedHash<32u>::data() const
Line
Count
Source
156
5.75M
  uint8_t const* data() const { return m_data.data(); }
solidity::util::FixedHash<4u>::data() const
Line
Count
Source
156
13.2k
  uint8_t const* data() const { return m_data.data(); }
Unexecuted instantiation: solidity::util::FixedHash<20u>::data() const
solidity::util::FixedHash<1u>::data() const
Line
Count
Source
156
408k
  uint8_t const* data() const { return m_data.data(); }
157
158
  /// @returns a copy of the object's data as a byte vector.
159
3.08M
  bytes asBytes() const { return bytes(data(), data() + N); }
solidity::util::FixedHash<32u>::asBytes() const
Line
Count
Source
159
2.87M
  bytes asBytes() const { return bytes(data(), data() + N); }
solidity::util::FixedHash<4u>::asBytes() const
Line
Count
Source
159
6.64k
  bytes asBytes() const { return bytes(data(), data() + N); }
Unexecuted instantiation: solidity::util::FixedHash<20u>::asBytes() const
solidity::util::FixedHash<1u>::asBytes() const
Line
Count
Source
159
202k
  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
224k
{
169
224k
  boost::io::ios_all_saver guard(_out);
170
224k
  _out << std::noshowbase << std::hex << std::setfill('0');
171
7.42M
  for (unsigned i = 0; i < N; ++i)
172
7.19M
    _out << std::setw(2) << (int)_h[i];
173
224k
  _out << std::dec;
174
224k
  return _out;
175
224k
}
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
224k
{
169
224k
  boost::io::ios_all_saver guard(_out);
170
224k
  _out << std::noshowbase << std::hex << std::setfill('0');
171
7.42M
  for (unsigned i = 0; i < N; ++i)
172
7.19M
    _out << std::setw(2) << (int)_h[i];
173
224k
  _out << std::dec;
174
224k
  return _out;
175
224k
}
Unexecuted instantiation: 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&)
176
177
// Common types of FixedHash.
178
using h256 = FixedHash<32>;
179
using h160 = FixedHash<20>;
180
181
}