/* This file is part of TON Blockchain Library. TON Blockchain Library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. TON Blockchain Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . Copyright 2017-2019 Telegram Systems LLP */ #pragma once #include "common/refcnt.hpp" #include #include #include #include #include #include "td/utils/bits.h" namespace td { template struct BitPtrGen; typedef BitPtrGen BitPtr; typedef BitPtrGen ConstBitPtr; struct BitstringError {}; namespace bitstring { void bits_memcpy(unsigned char* to, int to_offs, const unsigned char* from, int from_offs, std::size_t bit_count); void bits_memcpy(BitPtr to, ConstBitPtr from, std::size_t bit_count); void bits_memset(unsigned char* to, int to_offs, bool val, std::size_t bit_count); void bits_memset(BitPtr to, bool val, std::size_t bit_count); int bits_memcmp(const unsigned char* bs1, int bs1_offs, const unsigned char* bs2, int bs2_offs, std::size_t bit_count, std::size_t* same_upto = 0); int bits_memcmp(ConstBitPtr bs1, ConstBitPtr bs2, std::size_t bit_count, std::size_t* same_upto = 0); int bits_lexcmp(const unsigned char* bs1, int bs1_offs, std::size_t bs1_bit_count, const unsigned char* bs2, int bs2_offs, std::size_t bs2_bit_count); int bits_lexcmp(ConstBitPtr bs1, std::size_t bs1_bit_count, ConstBitPtr bs2, std::size_t bs2_bit_count); std::size_t bits_memscan(const unsigned char* ptr, int offs, std::size_t bit_count, bool cmp_to); std::size_t bits_memscan_rev(const unsigned char* ptr, int offs, std::size_t bit_count, bool cmp_to); std::size_t bits_memscan(ConstBitPtr bs, std::size_t bit_count, bool cmp_to); std::size_t bits_memscan_rev(ConstBitPtr bs, std::size_t bit_count, bool cmp_to); void bits_store_long_top(unsigned char* to, int to_offs, unsigned long long val, unsigned top_bits); void bits_store_long_top(BitPtr to, unsigned long long val, unsigned top_bits); void bits_store_long(BitPtr to, unsigned long long val, unsigned bits); unsigned long long bits_load_long_top(const unsigned char* from, int from_offs, unsigned top_bits); unsigned long long bits_load_long_top(ConstBitPtr from, unsigned top_bits); long long bits_load_long(ConstBitPtr from, unsigned bits); unsigned long long bits_load_ulong(ConstBitPtr from, unsigned bits); long parse_bitstring_hex_literal(unsigned char* buff, std::size_t buff_size, const char* str, const char* str_end); long parse_bitstring_binary_literal(BitPtr buff, std::size_t buff_size, const char* str, const char* str_end); void bits_sha256(BitPtr to, ConstBitPtr from, std::size_t size); std::string bits_to_binary(const unsigned char* ptr, int offs, std::size_t len); std::string bits_to_binary(ConstBitPtr bs, std::size_t len); std::string bits_to_hex(const unsigned char* ptr, int offs, std::size_t len); std::string bits_to_hex(ConstBitPtr bs, std::size_t len); } // namespace bitstring template struct BitPtrGen { Pt* ptr; int offs; BitPtrGen(Pt* _ptr, int _offs = 0) : ptr(_ptr), offs(_offs) { } template BitPtrGen(BitPtrGen val) : ptr(val.ptr), offs(val.offs) { } BitPtrGen& operator+=(int _offs) { offs += _offs; return *this; } BitPtrGen& operator-=(int _offs) { offs -= _offs; return *this; } void advance(int _offs) { offs += _offs; } bool byte_aligned() const { return !(offs & 7); } Pt* get_byte_ptr() const { return ptr + (offs >> 3); } void copy_from(BitPtrGen from, unsigned size) const { bitstring::bits_memcpy(*this, from, size); } BitPtrGen& concat(BitPtrGen from, unsigned size) { bitstring::bits_memcpy(*this, from, size); offs += size; return *this; } template void copy_from(const T& from) const { copy_from(from.bits(), from.size()); } template BitPtrGen& concat(const T& from) { return concat(from.bits(), from.size()); } void fill(bool bit, unsigned size) { bitstring::bits_memset(*this, bit, size); } BitPtrGen& concat_same(bool bit, unsigned size) { bitstring::bits_memset(*this, bit, size); offs += size; return *this; } int compare(BitPtrGen other, std::size_t size, std::size_t* same_upto = nullptr) const { return bitstring::bits_memcmp(*this, other, size, same_upto); } bool equals(BitPtrGen other, std::size_t size) const { return !bitstring::bits_memcmp(*this, other, size); } std::size_t scan(bool value, std::size_t len) const { return bitstring::bits_memscan(*this, len, value); } long long get_int(unsigned bits) const { return bitstring::bits_load_long(*this, bits); } unsigned long long get_uint(unsigned bits) const { return bitstring::bits_load_ulong(*this, bits); } void store_uint(unsigned long long val, unsigned n) const { bitstring::bits_store_long(*this, val, n); } void store_int(long long val, unsigned n) const { bitstring::bits_store_long(*this, val, n); } BitPtrGen operator+(int _offs) const { return BitPtrGen{ptr, offs + _offs}; } BitPtrGen operator-(int _offs) const { return BitPtrGen{ptr, offs - _offs}; } BitPtrGen operator++() { ++offs; return *this; } BitPtrGen operator--() { --offs; return *this; } BitPtrGen operator++(int) { return BitPtrGen{ptr, offs++}; } BitPtrGen operator--(int) { return BitPtrGen{ptr, offs--}; } bool is_null() const { return !ptr; } bool not_null() const { return ptr; } class BitSelector { Pt* ptr; unsigned char mask; public: BitSelector(Pt* _ptr, int offs) { ptr = _ptr + (offs >> 3); mask = (unsigned char)(0x80 >> (offs & 7)); } bool clear() { *ptr = (unsigned char)(*ptr & ~mask); return false; } bool set() { *ptr = (unsigned char)(*ptr | mask); return true; } bool operator=(bool val) { return val ? set() : clear(); } operator bool() const { return *ptr & mask; } }; BitSelector operator*() const { return BitSelector{ptr, offs}; } BitSelector operator[](int i) const { return BitSelector{ptr, offs + i}; } std::string to_hex(std::size_t len) const { return bitstring::bits_to_hex(*this, len); } std::string to_binary(std::size_t len) const { return bitstring::bits_to_binary(*this, len); } }; template class BitSliceGen { Rf ref; Pt* ptr; unsigned offs, len; public: struct BitSliceError {}; BitSliceGen() : ref(), ptr(0), offs(0), len(0) { } BitSliceGen(Rf _ref, Pt* _ptr, int _offs, unsigned _len) : ref(std::move(_ref)), ptr(_ptr + (_offs >> 3)), offs(_offs & 7), len(_len) { } BitSliceGen(const BitSliceGen& bs, unsigned _offs, unsigned _len); BitSliceGen(BitSliceGen&& bs, unsigned _offs, unsigned _len); BitSliceGen(Pt* _ptr, unsigned _len) : ref(), ptr(_ptr), offs(0), len(_len) { } ~BitSliceGen() { } Pt* get_ptr() const { return ptr; } BitPtrGen bits() const { return BitPtrGen{ptr, (int)offs}; } bool is_valid() const { return ptr != 0; } unsigned char cur_byte() const { return *ptr; } unsigned get_offs() const { return offs; } unsigned size() const { return len; } unsigned byte_size() const { return (offs + len + 7) >> 3; } void ensure_throw(bool cond) const { if (!cond) { throw BitSliceError{}; } } BitSliceGen& assign(Rf _ref, Pt* _ptr, unsigned _offs, unsigned _len); void forget() { ref.clear(); ptr = 0; offs = len = 0; } bool operator[](unsigned i) const { i += offs; return ptr[i >> 3] & (0x80 >> (i & 7)); } bool at(unsigned i) const { ensure_throw(i < len); return operator[](i); } bool advance_bool(unsigned bits); bool set_size_bool(unsigned bits) { if (bits > len) { return false; } len = bits; return true; } BitSliceGen& advance(unsigned bits) { ensure_throw(advance_bool(bits)); return *this; } BitSliceGen& set_size(unsigned bits) { ensure_throw(set_size_bool(bits)); return *this; } BitSliceGen subslice(unsigned from, unsigned bits) const & { return BitSliceGen(*this, from, bits); } BitSliceGen subslice(unsigned from, unsigned bits) && { return BitSliceGen(*this, from, bits); } void copy_to(BitPtr to) const { bitstring::bits_memcpy(to, bits(), size()); } int compare(ConstBitPtr other) const { return bitstring::bits_memcmp(bits(), other, size()); } bool operator==(ConstBitPtr other) const { return !compare(other); } bool operator!=(ConstBitPtr other) const { return compare(other); } std::string to_binary() const { return bitstring::bits_to_binary(ptr, offs, len); } std::string to_hex() const { return bitstring::bits_to_hex(ptr, offs, len); } void dump(std::ostream& stream, bool nocr = false) const { stream << "[" << offs << "," << len << "]"; if (!nocr) { stream << std::endl; } } protected: inline Pt& cur_byte_w() const { return *ptr; } }; template BitSliceGen::BitSliceGen(const BitSliceGen& bs, unsigned from, unsigned bits) : ref() { if (from >= bs.size() || bits > bs.size() - from) { ptr = 0; offs = len = 0; return; } //bs.dump(std::cout, true); //std::cout << ".subslice(" << from << "," << bits << ") = "; ref = bs.ref; offs = bs.offs + from; ptr = bs.ptr + (offs >> 3); offs &= 7; len = bits; //dump(std::cout); } template BitSliceGen::BitSliceGen(BitSliceGen&& bs, unsigned from, unsigned bits) : ref() { if (from >= bs.size() || bits > bs.size() - from) { ptr = 0; offs = len = 0; return; } ref = std::move(bs.ref); offs = bs.offs + from; ptr = bs.ptr + (offs >> 3); offs &= 7; len = bits; } template BitSliceGen& BitSliceGen::assign(Rf _ref, Pt* _ptr, unsigned _offs, unsigned _len) { ref = std::move(_ref); ptr = _ptr + (_offs >> 3); offs = (_offs & 7); len = _len; return *this; } template inline bool BitSliceGen::advance_bool(unsigned bits) { if (len < bits) { return false; } len -= bits; offs += bits; ptr += (offs >> 3); offs &= 7; return true; } typedef BitSliceGen BitSlice; static inline std::string to_hex(const BitSlice& bs) { return bs.to_hex(); } static inline std::string to_binary(const BitSlice& bs) { return bs.to_binary(); } class BitSliceWrite : public BitSliceGen { public: struct LengthMismatch {}; BitSliceWrite(RefAny _ref, unsigned char* _ptr, unsigned _offs, unsigned _len) : BitSliceGen(_ref, _ptr, _offs, _len) { } BitSliceWrite() : BitSliceGen() { } BitSliceWrite(unsigned char* _ptr, unsigned _len) : BitSliceGen(_ptr, _len) { } operator BitSlice&() { return *reinterpret_cast(this); } operator const BitSlice&() const { return *reinterpret_cast(this); } const BitSliceWrite& operator=(const BitSlice& bs) const; const BitSliceWrite& operator=(bool val) const; }; class BitString : public CntObject { unsigned char* ptr; unsigned offs, len, bytes_alloc; public: BitString() : ptr(0), offs(0), len(0), bytes_alloc(0) { } explicit BitString(const BitSlice& bs, unsigned reserve_bits = 0); explicit BitString(unsigned reserve_bits); BitString(const BitString&) = delete; BitString& operator=(const BitString&) = delete; BitString(BitString&&) = delete; BitString& operator=(BitString&&) = delete; ~BitString() { if (ptr) { std::free(ptr); } } operator BitSlice() const; BitString* make_copy() const override; unsigned size() const { return len; } unsigned byte_size() const { return (offs + len + 7) >> 3; } ConstBitPtr cbits() const { return ConstBitPtr{ptr, (int)offs}; } ConstBitPtr bits() const { return ConstBitPtr{ptr, (int)offs}; } BitPtr bits() { return BitPtr{ptr, (int)offs}; } BitString& reserve_bits(unsigned req_bits); BitSliceWrite reserve_bitslice(unsigned req_bits); BitString& append(const BitSlice& bs); BitSlice subslice(unsigned from, unsigned bits) const; BitSliceWrite subslice_write(unsigned from, unsigned bits); std::string to_hex() const { return bitstring::bits_to_hex(cbits(), size()); } std::string to_binary() const { return bitstring::bits_to_binary(cbits(), size()); } }; extern std::ostream& operator<<(std::ostream& stream, const BitString& bs); extern std::ostream& operator<<(std::ostream& stream, Ref bs_ref); extern template class Ref; typedef Ref BitStringRef; template class BitArray { static constexpr unsigned m = (n + 7) >> 3; typedef std::array byte_array_t; typedef unsigned char raw_byte_array_t[m]; byte_array_t bytes; public: const unsigned char* data() const { return bytes.data(); } unsigned char* data() { return bytes.data(); } unsigned size() const { return n; } const byte_array_t& as_array() const { return bytes; } byte_array_t& as_array() { return bytes; } Slice as_slice() const { return Slice{data(), m}; } MutableSlice as_slice() { return MutableSlice{data(), m}; } ConstBitPtr cbits() const { return ConstBitPtr{data()}; } ConstBitPtr bits() const { return ConstBitPtr{data()}; } BitPtr bits() { return BitPtr{data()}; } BitArray() = default; BitArray(const BitArray&) = default; BitArray(const byte_array_t& init_bytes) : bytes(init_bytes) { } explicit BitArray(const raw_byte_array_t init_bytes) { std::memcpy(data(), init_bytes, m); } BitArray(ConstBitPtr from) { bitstring::bits_memcpy(bits(), from, n); } template > explicit BitArray(long long val) { bitstring::bits_store_long(bits(), val, n); } BitArray& operator=(const BitArray&) = default; BitArray& operator=(const byte_array_t& set_bytes) { bytes = set_bytes; return *this; } BitArray& operator=(ConstBitPtr from) { bitstring::bits_memcpy(bits(), from, n); return *this; } BitArray& operator=(const raw_byte_array_t set_byte_array) { std::memcpy(data(), set_byte_array, m); return *this; } BitSliceWrite write_bitslice() { return BitSliceWrite{data(), n}; } BitSlice as_bitslice() const { return BitSlice{data(), n}; } //operator BitString() const { //return BitString{as_bitslice()}; //} Ref make_bitstring_ref() const { return td::make_ref(as_bitslice()); } unsigned long long to_ulong() const { return bitstring::bits_load_ulong(bits(), n); } long long to_long() const { return bitstring::bits_load_long(bits(), n); } void store_ulong(unsigned long long val) { bitstring::bits_store_long(bits(), val, n); } void store_long(long long val) { bitstring::bits_store_long(bits(), val, n); } void set_same(bool v) { bytes.fill(static_cast(v ? -1 : 0)); } void set_zero() { set_same(0); } void set_zero_s() { volatile uint8* p = data(); auto x = m; while (x--) { *p++ = 0; } } void set_ones() { set_same(1); } void clear() { set_zero(); } bool is_zero() const { return bitstring::bits_memscan(cbits(), n, 0) == n; } std::string to_hex() const { return bitstring::bits_to_hex(cbits(), size()); } std::string to_binary() const { return bitstring::bits_to_binary(cbits(), size()); } int compare(const BitArray& other) const { return (n % 8 == 0) ? std::memcmp(data(), other.data(), n / 8) : bitstring::bits_memcmp(bits(), other.bits(), n); } bool operator==(const BitArray& other) const { return (n % 8 == 0) ? (bytes == other.bytes) : !bitstring::bits_memcmp(bits(), other.bits(), n); } bool operator!=(const BitArray& other) const { return (n % 8 == 0) ? (bytes != other.bytes) : bitstring::bits_memcmp(bits(), other.bits(), n); } bool operator<(const BitArray& other) const { return (n % 8 == 0) ? (bytes < other.bytes) : (bitstring::bits_memcmp(bits(), other.bits(), n) < 0); } int compare(ConstBitPtr other) const { return bitstring::bits_memcmp(bits(), other, n); } bool operator==(ConstBitPtr other) const { return !compare(other); } bool operator!=(ConstBitPtr other) const { return compare(other); } BitPtr::BitSelector operator[](int i) { return bits()[i]; } bool operator[](int i) const { return cbits()[i]; } void compute_sha256(BitPtr to) const { bitstring::bits_sha256(to, cbits(), n); } void compute_sha256(BitArray<256>& to) const { bitstring::bits_sha256(to.bits(), cbits(), n); } static inline BitArray zero() { BitArray x; x.set_zero(); return x; } static inline BitArray ones() { BitArray x; x.set_ones(); return x; } BitArray operator^(const BitArray& with) const { BitArray res; for (unsigned i = 0; i < m; i++) { res.bytes[i] = bytes[i] ^ with.bytes[i]; } return res; } unsigned scan(bool value) const { return (unsigned)cbits().scan(value, n); } unsigned count_leading_zeroes() const { return scan(false); } unsigned count_matching(ConstBitPtr other) const { std::size_t cnt; bitstring::bits_memcmp(cbits(), other, n, &cnt); return (unsigned)cnt; } unsigned count_matching(const BitArray& other) const { return count_matching(other.bits()); } }; using Bits256 = BitArray<256>; using Bits128 = BitArray<128>; template std::ostream& operator<<(std::ostream& stream, BitArray bits) { return stream << bits.to_hex(); } template Slice as_slice(const BitArray& value) { return value.as_slice(); } template MutableSlice as_slice(BitArray& value) { return value.as_slice(); } template Ref make_bitstring_ref(const BitArray& value) { return value.make_bitstring_ref(); } } // namespace td