• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

libbitcoin / libbitcoin-system / 14979692795

12 May 2025 06:24PM UTC coverage: 82.118% (-0.002%) from 82.12%
14979692795

push

github

web-flow
Merge pull request #1662 from evoskuil/master

Factor stack.ipp into stack/stack_variant, comments, style.

69 of 91 new or added lines in 1 file covered. (75.82%)

10319 of 12566 relevant lines covered (82.12%)

3834313.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.82
/include/bitcoin/system/impl/machine/stack_variant.ipp
1
/**
2
 * Copyright (c) 2011-2025 libbitcoin developers (see AUTHORS)
3
 *
4
 * This file is part of libbitcoin.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU Affero General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Affero General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
#ifndef LIBBITCOIN_SYSTEM_MACHINE_STACK_VARIANT_IPP
20
#define LIBBITCOIN_SYSTEM_MACHINE_STACK_VARIANT_IPP
21

22
#include <tuple>
23
#include <utility>
24
#include <variant>
25
#include <bitcoin/system/data/data.hpp>
26
#include <bitcoin/system/define.hpp>
27
#include <bitcoin/system/math/math.hpp>
28

29
namespace libbitcoin {
30
namespace system {
31
namespace machine {
32

33
// private
34
// Generalized integer peek for varying bit widths up to 8 bytes.
35
// Chunk to integer conversions are constrained by caller (4 or 5 bytes).
36
// False result implies value overflow, from integer or chunk conversion.
37
TEMPLATE
38
template<size_t Bytes, typename Integer,
39
    if_not_lesser<sizeof(Integer), Bytes>,
40
    if_signed_integral_integer<Integer>>
41
inline bool CLASS::
4,750✔
42
peek_signed(Integer& value) const NOEXCEPT
43
{
44
    using namespace number;
45
    auto result{ true };
4,750✔
46

47
    std::visit(overload
4,750✔
48
    {
49
        [&](bool vary) NOEXCEPT
80✔
50
        {
51
            // This is never executed in standard scripts.
52
            value = to_int(vary);
40✔
53
        },
54
        [&](int64_t vary) NOEXCEPT
8,838✔
55
        {
56
            // This is the canonical use case.
57
            result = integer<Bytes>::from_integer(value, vary);
4,419✔
58
        },
59
        [&](const chunk_xptr& vary) NOEXCEPT
291✔
60
        {
61
            // This is never executed in standard scripts.
62
            result = integer<Bytes>::from_chunk(value, *vary);
291✔
63
        }
64
    }, top());
65

66
    return result;
4,750✔
67
}
68

69
/// Variant data conversions.
70
/// ---------------------------------------------------------------------------
71
/// P2SH and P2WSH redeem scripts and P2TR tapscripts are not subjectable to
72
/// standardness and are therefore not considered "stadnard" in comments below.
73

74
TEMPLATE
75
inline bool CLASS::
1,593✔
76
peek_bool() const NOEXCEPT
77
{
78
    using namespace number;
79
    bool value{};
1,593✔
80

81
    std::visit(overload
1,593✔
82
    {
83
        [&](bool vary) NOEXCEPT
713✔
84
        {
85
            // This is the canonical use case.
86
            value = vary;
713✔
87
        },
88
        [&](int64_t vary) NOEXCEPT
828✔
89
        {
90
            // This is never executed in standard scripts.
91
            value = boolean::from_integer(vary);
828✔
92
        },
93
        [&](const chunk_xptr& vary) NOEXCEPT
52✔
94
        {
95
            // This is never executed in standard scripts.
96
            value = boolean::from_chunk(*vary);
52✔
97
        }
98
    }, top());
99

100
    return value;
1,593✔
101
}
102

103
// Differs from peek_bool in that a chunk false must be empty [].
104
TEMPLATE
105
inline bool CLASS::
2,050✔
106
peek_strict_bool() const NOEXCEPT
107
{
108
    using namespace number;
109
    bool value{};
2,050✔
110

111
    std::visit(overload
2,050✔
112
    {
113
        [&](bool vary) NOEXCEPT
1,200✔
114
        {
115
            // This is the canonical use case (with bip147).
116
            value = vary;
1,200✔
117
        },
118
        [&](int64_t vary) NOEXCEPT
848✔
119
        {
120
            // This may be executed in standard scripts (without bip147).
121
            value = boolean::from_integer(vary);
848✔
122
        },
123
        [&](const chunk_xptr& vary) NOEXCEPT
2✔
124
        {
125
            // This may be executed in standard scripts (without bip147).
126
            value = boolean::from_chunk_strict(*vary);
2✔
127
        }
128
    }, top());
129

130
    return value;
2,050✔
131
}
132

133
// This is the only convertor with both a return value and a result.
134
// A chunk false must be [] and chunk true must be [0x01], otherwise fails.
135
TEMPLATE
NEW
136
inline bool CLASS::
×
137
peek_minimal_bool(bool& value) const NOEXCEPT
138
{
139
    using namespace number;
NEW
140
    auto result{ true };
×
141

NEW
142
    std::visit(overload
×
143
    {
NEW
144
        [&](bool vary) NOEXCEPT
×
145
        {
146
            // This is the canonical use case (tapscript).
NEW
147
            value = vary;
×
148
        },
NEW
149
        [&](int64_t vary) NOEXCEPT
×
150
        {
151
            // This may be executed in tapscripts.
NEW
152
            result = boolean::from_integer(value, vary);
×
153
        },
NEW
154
        [&](const chunk_xptr& vary) NOEXCEPT
×
155
        {
156
            // This may be executed in tapscripts.
NEW
157
            result = boolean::from_chunk(value, *vary);
×
158
        }
159
    }, top());
160

NEW
161
    return result;
×
162
}
163

164
// Could use peek_chunk but this overload skips allocation and tethering.
165
TEMPLATE
166
inline size_t CLASS::
58✔
167
peek_size() const NOEXCEPT
168
{
169
    using namespace number;
170
    size_t value{};
58✔
171

172
    std::visit(overload
58✔
173
    {
174
        [&](bool vary) NOEXCEPT
4✔
175
        {
176
            // This is never executed in standard scripts.
177
            value = chunk::from_bool(vary).size();
2✔
178
        },
179
        [&](int64_t vary) NOEXCEPT
20✔
180
        {
181
            // This is never executed in standard scripts.
182
            value = chunk::from_integer(vary).size();
10✔
183
        },
184
        [&](const chunk_xptr& vary) NOEXCEPT
46✔
185
        {
186
            // This is never executed in standard scripts.
187
            value = vary->size();
46✔
188
        }
189
    }, top());
190

191
    return value;
58✔
192
}
193

194
// This is the only source of peek/pop (read) tethering.
195
TEMPLATE
196
inline chunk_xptr CLASS::
3,578✔
197
peek_chunk() const NOEXCEPT
198
{
199
    using namespace number;
200
    chunk_xptr value{};
3,578✔
201

202
    std::visit(overload
3,578✔
203
    {
NEW
204
        [&](bool vary) NOEXCEPT
×
205
        {
206
            // This is never executed in standard scripts.
NEW
207
            value = make_external(chunk::from_bool(vary), tether_);
×
208
        },
209
        [&](int64_t vary) NOEXCEPT
76✔
210
        {
211
            // This is never executed in standard scripts.
212
            value = make_external(chunk::from_integer(vary), tether_);
38✔
213
        },
214
        [&](const chunk_xptr& vary) NOEXCEPT
3,540✔
215
        {
216
            // This is the canonical use case.
217
            value = vary;
3,540✔
218
        }
219
    }, top());
220

221
    return value;
3,578✔
222
}
223

224
// Static variant compare with conversion.
225
// Methods bound at compile time (free).
226
// One runtime switch on variant index (cheap).
227
// bool/int conversions are compile-time (free).
228
// chunk conversions reduce to conventional bitcoin design.
229
// Integers are unconstrained as these are stack chunk equality comparisons.
230
TEMPLATE
231
inline bool CLASS::
560✔
232
equal_chunks(const stack_variant& left, const stack_variant& right) NOEXCEPT
233
{
234
    using namespace number;
235
    auto same{ true };
560✔
236

237
    std::visit(overload
560✔
238
    {
239
        // This is never executed in standard scripts.
240
        [&](bool vary) NOEXCEPT
24✔
241
        {
242
            switch (right.index())
12✔
243
            {
NEW
244
                case stack_type::bool_:
×
NEW
245
                    same = std::get<bool>(right) == vary;
×
NEW
246
                    break;
×
247
                case stack_type::int64_:
12✔
248
                    same = std::get<int64_t>(right) == to_int(vary);
12✔
249
                    break;
12✔
NEW
250
                case stack_type::pchunk_:
×
NEW
251
                    same = *std::get<chunk_xptr>(right) == chunk::from_bool(vary);
×
252
            }
253
        },
254

255
        // This is never executed in standard scripts.
256
        [&](int64_t vary) NOEXCEPT
700✔
257
        {
258
            switch (right.index())
350✔
259
            {
NEW
260
                case stack_type::bool_:
×
NEW
261
                    same = to_int(std::get<bool>(right)) == vary;
×
NEW
262
                    break;
×
263
                case stack_type::int64_:
322✔
264
                    same = std::get<int64_t>(right) == vary;
322✔
265
                    break;
322✔
266
                case stack_type::pchunk_:
28✔
267
                    same = *std::get<chunk_xptr>(right) == chunk::from_integer(vary);
28✔
268
            }
269
        },
270

271
        // This is the canonical use case.
272
        [&](chunk_xptr vary) NOEXCEPT
396✔
273
        {
274
            switch (right.index())
198✔
275
            {
276
                case stack_type::bool_:
277
                    // This is never executed in standard scripts.
NEW
278
                    same = chunk::from_bool(std::get<bool>(right)) == *vary;
×
NEW
279
                    break;
×
280
                case stack_type::int64_:
281
                    // This is never executed in standard scripts.
282
                    same = chunk::from_integer(std::get<int64_t>(right)) == *vary;
14✔
283
                    break;
14✔
284
                case stack_type::pchunk_:
285
                    // This is the canonical use case.
286
                    same = *std::get<chunk_xptr>(right) == *vary;
184✔
287
            }
288
        }
289
    }, left);
290

291
    return same;
560✔
292
}
293

294
} // namespace machine
295
} // namespace system
296
} // namespace libbitcoin
297

298
#endif
299

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc