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

libbitcoin / libbitcoin-system / 13069453084

31 Jan 2025 08:55AM UTC coverage: 82.728% (-0.007%) from 82.735%
13069453084

push

github

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

Set _CRTDBG_MAP_ALLOC for vc++ debug mode leak tracking.

2 of 2 new or added lines in 1 file covered. (100.0%)

15 existing lines in 11 files now uncovered.

10039 of 12135 relevant lines covered (82.73%)

3871639.49 hits per line

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

86.72
/include/bitcoin/system/impl/machine/stack.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_IPP
20
#define LIBBITCOIN_SYSTEM_MACHINE_STACK_IPP
21

22
#include <iterator>
23
#include <type_traits>
24
#include <utility>
25
#include <variant>
26
#include <bitcoin/system/data/data.hpp>
27
#include <bitcoin/system/define.hpp>
28
#include <bitcoin/system/machine/number.hpp>
29
#include <bitcoin/system/math/math.hpp>
30

31
namespace libbitcoin {
32
namespace system {
33
namespace machine {
34

35
template <typename Container>
36
INLINE stack<Container>::stack() NOEXCEPT
1,561✔
37
  : container_{}, tether_{}
1,562✔
38
{
UNCOV
39
}
×
40

41
template <typename Container>
42
INLINE stack<Container>::stack(Container&& container) NOEXCEPT
23✔
43
  : container_(std::move(container)), tether_{}
23✔
44
{
45
}
46

47
// Pure stack abstraction.
48
// ----------------------------------------------------------------------------
49

50
template <typename Container>
51
INLINE const stack_variant& stack<Container>::top() const NOEXCEPT
3,578✔
52
{
53
    BC_ASSERT(!empty());
54
    return container_.back();
35✔
55
}
56

57
template <typename Container>
58
INLINE stack_variant stack<Container>::pop() NOEXCEPT
1,141✔
59
{
60
    BC_ASSERT(!empty());
61
    stack_variant temporary{ std::move(container_.back()) };
1,141✔
62
    container_.pop_back();
1,141✔
63
    return temporary;
1,141✔
64
}
65

66
template <typename Container>
67
INLINE void stack<Container>::drop() NOEXCEPT
10,182✔
68
{
69
    BC_ASSERT(!empty());
70
    container_.pop_back();
745✔
71
}
72

73
template <typename Container>
74
INLINE bool stack<Container>::empty() const NOEXCEPT
7,201✔
75
{
76
    return container_.empty();
1,088✔
77
}
78

79
template <typename Container>
80
INLINE size_t stack<Container>::size() const NOEXCEPT
33,670✔
81
{
82
    return container_.size();
76✔
83
}
84

85
template <typename Container>
86
INLINE void stack<Container>::push(data_chunk&& value) NOEXCEPT
168✔
87
{
88
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
89
    container_.push_back(make_external(std::move(value), tether_));
169✔
90
    BC_POP_WARNING()
91
}
92

93
template <typename Container>
94
INLINE void stack<Container>::push(stack_variant&& value) NOEXCEPT
2✔
95
{
96
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
97
    container_.push_back(std::move(value));
2✔
98
    BC_POP_WARNING()
99
}
2✔
100

101
template <typename Container>
102
INLINE void stack<Container>::push(const stack_variant& value) NOEXCEPT
9,957✔
103
{
104
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
105
    container_.push_back(value);
9,957✔
106
    BC_POP_WARNING()
107
}
108

109
template <typename Container>
110
INLINE void stack<Container>::emplace_boolean(bool value) NOEXCEPT
2,018✔
111
{
112
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
113
    container_.emplace_back(value);
2,018✔
114
    BC_POP_WARNING()
115
}
116

117
template <typename Container>
118
INLINE void stack<Container>::emplace_integer(int64_t value) NOEXCEPT
7,256✔
119
{
120
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
121
    container_.emplace_back(value);
7,256✔
122
    BC_POP_WARNING()
123
}
124

125
template <typename Container>
126
INLINE void stack<Container>::emplace_chunk(const chunk_xptr& value) NOEXCEPT
4,474✔
127
{
128
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
129
    container_.emplace_back(value.get());
4,474✔
130
    BC_POP_WARNING()
131
}
132

133
// Positional (stack cheats).
134
// ----------------------------------------------------------------------------
135
// These optimizations prevent used of std::stack.
136

137
template <typename Container>
138
INLINE void stack<Container>::erase(size_t index) NOEXCEPT
16✔
139
{
140
    BC_ASSERT(index < size());
141
    container_.erase(std::prev(container_.end(), add1(index)));
16✔
142
}
143

144
template <typename Container>
145
INLINE void stack<Container>::swap(size_t left_index,
174✔
146
    size_t right_index) NOEXCEPT
147
{
148
    BC_ASSERT(left_index < size() && right_index < size());
149

150
    if constexpr (vector_)
151
    {
152
        const auto back = sub1(size());
153
        std::swap(
174✔
154
            container_[back - left_index],
174✔
155
            container_[back - right_index]);
174✔
156
    }
157

158
    if constexpr (linked_)
159
    {
160
        const auto end = container_.end();
161
        std::swap(
×
162
            *std::prev(end, add1(left_index)),
×
163
            *std::prev(end, add1(right_index)));
×
164
    }
165
}
166

167
template <typename Container>
168
INLINE const stack_variant& stack<Container>::peek(size_t index) const NOEXCEPT
6,616✔
169
{
170
    BC_ASSERT(index < size());
171

172
    if constexpr (vector_)
173
        return container_[sub1(size()) - index];
9,916✔
174

175
    if constexpr (linked_)
176
        return *std::prev(container_.end(), add1(index));
×
177
}
178

179
// Aliases.
180
// ----------------------------------------------------------------------------
181

182
template <typename Container>
183
INLINE bool stack<Container>::peek_signed4(int32_t& value) const NOEXCEPT
4,738✔
184
{
185
    return peek_signed<4>(value);
4,738✔
186
}
187

188
template <typename Container>
189
INLINE bool stack<Container>::peek_signed5(int64_t& value) const NOEXCEPT
12✔
190
{
191
    return peek_signed<5>(value);
12✔
192
}
193

194
/// Variant data conversions.
195
// ----------------------------------------------------------------------------
196

197
// Generalized integer peek for varying bit widths up to 8 bytes.
198
// Chunk to integer conversions are constrained by caller (4 or 5 bytes).
199
template <typename Container>
200
template<size_t Bytes, typename Integer,
201
    if_not_lesser<sizeof(Integer), Bytes>,
202
    if_signed_integral_integer<Integer>>
203
inline bool stack<Container>::peek_signed(Integer& value) const NOEXCEPT
4,750✔
204
{
205
    using namespace number;
206
    auto result{ true };
4,750✔
207

208
    std::visit(overload
4,750✔
209
    {
210
        [&](bool vary) NOEXCEPT
80✔
211
        {
212
            // This is never executed in standard scripts.
213
            value = boolean::to_integer<Bytes>(vary);
40✔
214
        },
215
        [&](int64_t vary) NOEXCEPT
8,838✔
216
        {
217
            // This is the canonical use case (bounds check only).
218
            result = integer<Bytes>::from_integer(value, vary);
4,419✔
219
        },
220
        [&](const chunk_xptr& vary) NOEXCEPT
291✔
221
        {
222
            // This is never executed in standard scripts.
223
            result = integer<Bytes>::from_chunk(value, *vary);
291✔
224
        }
225
    }, top());
226

227
    return result;
4,750✔
228
}
229

230
template <typename Container>
231
inline bool stack<Container>::peek_bool() const NOEXCEPT
1,593✔
232
{
233
    using namespace number;
234
    bool value{};
1,593✔
235

236
    std::visit(overload
1,593✔
237
    {
238
        [&](bool vary) NOEXCEPT
713✔
239
        {
240
            // This is the canonical use case.
241
            value = vary;
713✔
242
        },
243
        [&](int64_t vary) NOEXCEPT
828✔
244
        {
245
            // This is never executed in standard scripts.
246
            value = boolean::to_bool(vary);
828✔
247
        },
248
        [&](const chunk_xptr& vary) NOEXCEPT
52✔
249
        {
250
            // This is never executed in standard scripts.
251
            value = boolean::from_chunk(*vary);
52✔
252
        }
253
    }, top());
254

255
    return value;
1,593✔
256
}
257

258
// This differs from peek_bool in that a stack chunk must be empty.
259
template <typename Container>
260
inline bool stack<Container>::peek_strict_bool() const NOEXCEPT
2,050✔
261
{
262
    using namespace number;
263
    bool value{};
2,050✔
264

265
    std::visit(overload
2,050✔
266
    {
267
        [&](bool vary) NOEXCEPT
1,200✔
268
        {
269
            // This is the canonical use case (after bip147).
270
            value = vary;
1,200✔
271
        },
272
        [&](int64_t vary) NOEXCEPT
848✔
273
        {
274
            // This may be executed in standard scripts (before bip147).
275
            value = boolean::to_bool(vary);
848✔
276
        },
277
        [&](const chunk_xptr& vary) NOEXCEPT
2✔
278
        {
279
            // This may be executed in standard scripts (before bip147).
280
            value = boolean::strict_from_chunk(*vary);
2✔
281
        }
282
    }, top());
283

284
    return value;
2,050✔
285
}
286

287
// This is the only source of peek/pop (read) tethering.
288
template <typename Container>
289
inline chunk_xptr stack<Container>::peek_chunk() const NOEXCEPT
3,578✔
290
{
291
    using namespace number;
292
    chunk_xptr value{};
3,578✔
293

294
    std::visit(overload
3,578✔
295
    {
296
        [&, this](bool vary) NOEXCEPT
×
297
        {
298
            // This is never executed in standard scripts.
299
            value = make_external(chunk::from_bool(vary), tether_);
×
300
        },
301
        [&](int64_t vary) NOEXCEPT
76✔
302
        {
303
            // This is never executed in standard scripts.
304
            value = make_external(chunk::from_integer(vary), tether_);
76✔
305
        },
306
        [&](const chunk_xptr& vary) NOEXCEPT
3,540✔
307
        {
308
            // This is the canonical use case.
309
            value = vary;
3,540✔
310
        }
311
    }, top());
312

313
    return value;
3,578✔
314
}
315

316
// Could use peek_chunk but this overload skips allocation and tethering.
317
template <typename Container>
318
inline size_t stack<Container>::peek_size() const NOEXCEPT
58✔
319
{
320
    using namespace number;
321
    size_t value{};
58✔
322

323
    std::visit(overload
58✔
324
    {
325
        [&](bool vary) NOEXCEPT
4✔
326
        {
327
            // This is never executed in standard scripts.
328
            value = chunk::from_bool(vary).size();
2✔
329
        },
330
        [&](int64_t vary) NOEXCEPT
20✔
331
        {
332
            // This is never executed in standard scripts.
333
            value = chunk::from_integer(vary).size();
10✔
334
        },
335
        [&](const chunk_xptr& vary) NOEXCEPT
46✔
336
        {
337
            // This is never executed in standard scripts.
338
            value = vary->size();
46✔
339
        }
340
    }, top());
341

342
    return value;
58✔
343
}
344

345
/// Static variant compare with conversion.
346
/// Integers are unconstrained as these are stack chunk equality comparisons.
347
template <typename Container>
348
inline bool stack<Container>::equal_chunks(const stack_variant& left,
560✔
349
    const stack_variant& right) NOEXCEPT
350
{
351
    enum stack_type { bool_, int64_, pchunk_ };
352
    static_assert(std::variant_size<stack_variant>::value == 3u);
353
    const auto right_type = static_cast<stack_type>(right.index());
560✔
354

355
    using namespace number;
356
    auto same{ true };
560✔
357

358
    // Methods bound at compile time (free).
359
    // One runtime switch on variant index (cheap).
360
    // bool/int conversions are compile-time (free).
361
    // chunk conversions reduce to conventional bitcoin design.
362
    std::visit(overload
560✔
363
    {
364
        // This is never executed in standard scripts.
365
        [&](bool vary) NOEXCEPT
12✔
366
        {
367
            switch (right_type)
12✔
368
            {
369
                case bool_:
×
370
                    same = std::get<bool>(right) == vary;
×
371
                    break;
×
372
                case int64_:
12✔
373
                    same = std::get<int64_t>(right) == boolean::to_integer(vary);
12✔
374
                    break;
12✔
375
                case pchunk_:
×
376
                    same = *std::get<chunk_xptr>(right) == chunk::from_bool(vary);
×
377
            }
378
        },
379

380
        // This is never executed in standard scripts.
381
        [&](int64_t vary) NOEXCEPT
350✔
382
        {
383
            switch (right_type)
350✔
384
            {
385
                case bool_:
×
386
                    same = boolean::to_integer(std::get<bool>(right)) == vary;
×
387
                    break;
×
388
                case int64_:
322✔
389
                    same = std::get<int64_t>(right) == vary;
322✔
390
                    break;
322✔
391
                case pchunk_:
28✔
392
                    same = *std::get<chunk_xptr>(right) == chunk::from_integer(vary);
28✔
393
            }
394
        },
395

396
        // This is the canonical use case.
397
        [&](chunk_xptr vary) NOEXCEPT
396✔
398
        {
399
            switch (right_type)
198✔
400
            {
401
                case bool_:
402
                    // This is never executed in standard scripts.
403
                    same = chunk::from_bool(std::get<bool>(right)) == *vary;
×
404
                    break;
×
405
                case int64_:
406
                    // This is never executed in standard scripts.
407
                    same = chunk::from_integer(std::get<int64_t>(right)) == *vary;
14✔
408
                    break;
14✔
409
                case pchunk_:
410
                    // This is the canonical use case.
411
                    same = *std::get<chunk_xptr>(right) == *vary;
184✔
412
            }
413
        }
414
    }, left);
415

416
    return same;
560✔
417
}
418

419
} // namespace machine
420
} // namespace system
421
} // namespace libbitcoin
422

423
#endif
424

425
// Tethering Considerations
426
//
427
// Hash results and int/bool->chunks are saved using a shared_ptr vector.
428
// The tether is not garbage-collected (until destruct) as this is a space-
429
// time performance tradeoff. The maximum number of constructable chunks is
430
// bound by the script size limit. A standard in/out script pair tethers
431
// only one chunk, the computed hash.
432
//
433
// The following script operations will ALWAYS tether chunks, as the result
434
// of a computed hash is *pushed* to the weak pointer (xptr) variant stack.
435
//
436
// op_ripemd160         (1)
437
// op_sha1              (1)
438
// op_sha256            (1)
439
// op_hash160           (1)
440
// op_hash256           (1)
441
//
442
// The following script operations will ONLY tether chunks in the case where
443
// the *popped* element was originally bool/int64_t but required as chunk.
444
// This is never the case in standard scripts.
445
//
446
// op_ripemd160         (0..1)
447
// op_sha1              (0..1)
448
// op_sha256            (0..1)
449
// op_hash160           (0..1)
450
// op_hash256           (0..1)
451
// op_size              (0..1)
452
// op_check_sig         (0..2, and m (endorsements) + n (keys))
453
// op_check_sig_verify  (0..2, and m (endorsements) + n (keys))
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc