Skip to content

Commit cac846c

Browse files
l0rincryanofskyhodlinator
committed
Allow CScript's operator<< to accept spans, not just vectors
Extracted existing serialization to append size & data in separate private methods to clarify that it does more than just a simple data insertion. * the C style casts were changed to static_cast * `unsigned char` and `uint8_t` were changed to value_type for forward compatibility * `data + sizeof(data)` was changed to `std::cend` * data insertion (in AppendData) relies on pointer arithmetic now to enable both `std::span<const value_type>` and `std::span<const std::byte>` operators * use uint32_t for data size instead of size_t * used span instead of raw pointers in the new methods Co-authored-by: Ryan Ofsky <ryan@ofsky.org> Co-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>
1 parent c78d8ff commit cac846c

File tree

1 file changed

+36
-25
lines changed

1 file changed

+36
-25
lines changed

src/script/script.h

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <cstdint>
1818
#include <cstring>
1919
#include <limits>
20+
#include <span>
2021
#include <stdexcept>
2122
#include <string>
2223
#include <type_traits>
@@ -412,6 +413,32 @@ bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator en
412413
/** Serialized script, used inside transaction inputs and outputs */
413414
class CScript : public CScriptBase
414415
{
416+
private:
417+
inline void AppendDataSize(const uint32_t size)
418+
{
419+
if (size < OP_PUSHDATA1) {
420+
insert(end(), static_cast<value_type>(size));
421+
} else if (size <= 0xff) {
422+
insert(end(), OP_PUSHDATA1);
423+
insert(end(), static_cast<value_type>(size));
424+
} else if (size <= 0xffff) {
425+
insert(end(), OP_PUSHDATA2);
426+
value_type data[2];
427+
WriteLE16(data, size);
428+
insert(end(), std::cbegin(data), std::cend(data));
429+
} else {
430+
insert(end(), OP_PUSHDATA4);
431+
value_type data[4];
432+
WriteLE32(data, size);
433+
insert(end(), std::cbegin(data), std::cend(data));
434+
}
435+
}
436+
437+
void AppendData(std::span<const value_type> data)
438+
{
439+
insert(end(), data.begin(), data.end());
440+
}
441+
415442
protected:
416443
CScript& push_int64(int64_t n)
417444
{
@@ -463,35 +490,19 @@ class CScript : public CScriptBase
463490
return *this;
464491
}
465492

466-
CScript& operator<<(const std::vector<unsigned char>& b) LIFETIMEBOUND
493+
CScript& operator<<(std::span<const std::byte> b) LIFETIMEBOUND
467494
{
468-
if (b.size() < OP_PUSHDATA1)
469-
{
470-
insert(end(), (unsigned char)b.size());
471-
}
472-
else if (b.size() <= 0xff)
473-
{
474-
insert(end(), OP_PUSHDATA1);
475-
insert(end(), (unsigned char)b.size());
476-
}
477-
else if (b.size() <= 0xffff)
478-
{
479-
insert(end(), OP_PUSHDATA2);
480-
uint8_t _data[2];
481-
WriteLE16(_data, b.size());
482-
insert(end(), _data, _data + sizeof(_data));
483-
}
484-
else
485-
{
486-
insert(end(), OP_PUSHDATA4);
487-
uint8_t _data[4];
488-
WriteLE32(_data, b.size());
489-
insert(end(), _data, _data + sizeof(_data));
490-
}
491-
insert(end(), b.begin(), b.end());
495+
AppendDataSize(b.size());
496+
AppendData({reinterpret_cast<const value_type*>(b.data()), b.size()});
492497
return *this;
493498
}
494499

500+
// For compatibility reasons. In new code, prefer using std::byte instead of uint8_t.
501+
CScript& operator<<(std::span<const value_type> b) LIFETIMEBOUND
502+
{
503+
return *this << std::as_bytes(b);
504+
}
505+
495506
bool GetOp(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet) const
496507
{
497508
return GetScriptOp(pc, end(), opcodeRet, &vchRet);

0 commit comments

Comments
 (0)