diff --git a/src/WireEncoder.cpp b/src/WireEncoder.cpp index 102c6ae88f..610a53f5b5 100644 --- a/src/WireEncoder.cpp +++ b/src/WireEncoder.cpp @@ -18,92 +18,70 @@ using namespace nt; WireEncoder::WireEncoder(unsigned int proto_rev) { - // Start with a 1024-byte buffer. Use malloc instead of new so we can - // realloc. - m_start = m_cur = static_cast(std::malloc(1024)); - m_end = m_start + 1024; m_proto_rev = proto_rev; m_error = nullptr; } -WireEncoder::~WireEncoder() { std::free(m_start); } - void WireEncoder::WriteDouble(double val) { - Reserve(8); // The highest performance way to do this, albeit non-portable. std::uint64_t v = llvm::DoubleToBits(val); - m_cur[7] = (char)(v & 0xff); v >>= 8; - m_cur[6] = (char)(v & 0xff); v >>= 8; - m_cur[5] = (char)(v & 0xff); v >>= 8; - m_cur[4] = (char)(v & 0xff); v >>= 8; - m_cur[3] = (char)(v & 0xff); v >>= 8; - m_cur[2] = (char)(v & 0xff); v >>= 8; - m_cur[1] = (char)(v & 0xff); v >>= 8; - m_cur[0] = (char)(v & 0xff); - m_cur += 8; -} - -void WireEncoder::ReserveSlow(std::size_t len) { - assert(m_end >= m_cur); - // should never happen due to checks in Reserve(), but check anyway - if (static_cast(m_end - m_cur) >= len) return; - - // Double current buffer size until we have enough space. Since we're - // reserving space, it's likely more will be required soon in any case. - std::size_t pos = m_cur - m_start; - std::size_t newlen = (m_end - m_start) * 2; - while (newlen < (pos + len)) newlen *= 2; - m_start = static_cast(std::realloc(m_start, newlen)); - m_cur = m_start + pos; - m_end = m_start + newlen; + m_data.append({ + (char)((v >> 56) & 0xff), + (char)((v >> 48) & 0xff), + (char)((v >> 40) & 0xff), + (char)((v >> 32) & 0xff), + (char)((v >> 24) & 0xff), + (char)((v >> 16) & 0xff), + (char)((v >> 8) & 0xff), + (char)(v & 0xff) + }); } void WireEncoder::WriteUleb128(unsigned long val) { - Reserve(SizeUleb128(val)); - m_cur += nt::WriteUleb128(m_cur, val); + nt::WriteUleb128(m_data, val); } void WireEncoder::WriteType(NT_Type type) { - Reserve(1); + char ch; // Convert from enum to actual byte value. switch (type) { case NT_BOOLEAN: - *m_cur = 0x00; + ch = 0x00; break; case NT_DOUBLE: - *m_cur = 0x01; + ch = 0x01; break; case NT_STRING: - *m_cur = 0x02; + ch = 0x02; break; case NT_RAW: if (m_proto_rev < 0x0300u) { m_error = "raw type not supported in protocol < 3.0"; return; } - *m_cur = 0x03; + ch = 0x03; break; case NT_BOOLEAN_ARRAY: - *m_cur = 0x10; + ch = 0x10; break; case NT_DOUBLE_ARRAY: - *m_cur = 0x11; + ch = 0x11; break; case NT_STRING_ARRAY: - *m_cur = 0x12; + ch = 0x12; break; case NT_RPC: if (m_proto_rev < 0x0300u) { m_error = "RPC type not supported in protocol < 3.0"; return; } - *m_cur = 0x20; + ch = 0x20; break; default: m_error = "unrecognized type"; return; } - ++m_cur; + m_data.push_back(ch); } std::size_t WireEncoder::GetValueSize(const Value& value) const { @@ -175,7 +153,6 @@ void WireEncoder::WriteValue(const Value& value) { auto v = value.GetBooleanArray(); std::size_t size = v.size(); if (size > 0xff) size = 0xff; // size is only 1 byte, truncate - Reserve(1 + size); Write8(size); for (std::size_t i = 0; i < size; ++i) @@ -186,7 +163,6 @@ void WireEncoder::WriteValue(const Value& value) { auto v = value.GetDoubleArray(); std::size_t size = v.size(); if (size > 0xff) size = 0xff; // size is only 1 byte, truncate - Reserve(1 + size * 8); Write8(size); for (std::size_t i = 0; i < size; ++i) @@ -228,7 +204,5 @@ void WireEncoder::WriteString(llvm::StringRef str) { WriteUleb128(len); // contents - Reserve(len); - std::memcpy(m_cur, str.data(), len); - m_cur += len; + m_data.append(str.data(), str.data() + len); } diff --git a/src/WireEncoder.h b/src/WireEncoder.h index c74a87178d..40a4ca070b 100644 --- a/src/WireEncoder.h +++ b/src/WireEncoder.h @@ -11,6 +11,7 @@ #include #include +#include "llvm/SmallVector.h" #include "llvm/StringRef.h" #include "nt_Value.h" @@ -24,7 +25,6 @@ namespace nt { class WireEncoder { public: explicit WireEncoder(unsigned int proto_rev); - ~WireEncoder(); /* Change the protocol revision (mostly affects value encoding). */ void set_proto_rev(unsigned int proto_rev) { m_proto_rev = proto_rev; } @@ -34,7 +34,7 @@ class WireEncoder { /* Clears buffer and error indicator. */ void Reset() { - m_cur = m_start; + m_data.clear(); m_error = nullptr; } @@ -44,46 +44,29 @@ class WireEncoder { const char* error() const { return m_error; } /* Returns pointer to start of memory buffer with written data. */ - const char* data() const { return m_start; } + const char* data() const { return m_data.data(); } /* Returns number of bytes written to memory buffer. */ - std::size_t size() const { return m_cur - m_start; } + std::size_t size() const { return m_data.size(); } llvm::StringRef ToStringRef() const { - return llvm::StringRef(m_start, m_cur - m_start); - } - - /* Ensures the buffer has sufficient space to write len bytes. Reallocates - * the buffer if necessary. - */ - void Reserve(std::size_t len) { - // assert(m_end > m_cur); - if (static_cast(m_end - m_cur) < len) - ReserveSlow(len); // Need to reallocate memory + return llvm::StringRef(m_data.data(), m_data.size()); } /* Writes a single byte. */ - void Write8(unsigned int val) { - Reserve(1); - *m_cur++ = (char)(val & 0xff); - } + void Write8(unsigned int val) { m_data.push_back((char)(val & 0xff)); } /* Writes a 16-bit word. */ void Write16(unsigned int val) { - Reserve(2); - m_cur[1] = (char)(val & 0xff); val >>= 8; - m_cur[0] = (char)(val & 0xff); - m_cur += 2; + m_data.append({(char)((val >> 8) & 0xff), (char)(val & 0xff)}); } /* Writes a 32-bit word. */ void Write32(unsigned long val) { - Reserve(4); - m_cur[3] = (char)(val & 0xff); val >>= 8; - m_cur[2] = (char)(val & 0xff); val >>= 8; - m_cur[1] = (char)(val & 0xff); val >>= 8; - m_cur[0] = (char)(val & 0xff); - m_cur += 4; + m_data.append({(char)((val >> 24) & 0xff), + (char)((val >> 16) & 0xff), + (char)((val >> 8) & 0xff), + (char)(val & 0xff)}); } /* Writes a double. */ @@ -106,9 +89,6 @@ class WireEncoder { */ std::size_t GetStringSize(llvm::StringRef str) const; - WireEncoder(const WireEncoder&) = delete; - WireEncoder& operator=(const WireEncoder&) = delete; - protected: /* The protocol revision. E.g. 0x0200 for version 2.0. */ unsigned int m_proto_rev; @@ -117,17 +97,7 @@ class WireEncoder { const char* m_error; private: - /* The slow path for Reserve() when we need to reallocate memory. */ - void ReserveSlow(std::size_t len); - - /* The start of the memory buffer. */ - char* m_start; - - /* Where to write the next byte. */ - char* m_cur; - - /* The end of the allocated buffer. */ - char* m_end; + llvm::SmallVector m_data; }; } // namespace nt diff --git a/src/leb128.cpp b/src/leb128.cpp index d8f3408e9f..a79c3bfa6c 100644 --- a/src/leb128.cpp +++ b/src/leb128.cpp @@ -39,7 +39,7 @@ std::size_t SizeUleb128(unsigned long val) { * encodings refer to section "7.6 - Variable Length Data". Return * the number of bytes written. */ -std::size_t WriteUleb128(char* addr, unsigned long val) { +std::size_t WriteUleb128(llvm::SmallVectorImpl& dest, unsigned long val) { std::size_t count = 0; do { @@ -49,8 +49,7 @@ std::size_t WriteUleb128(char* addr, unsigned long val) { if (val != 0) byte |= 0x80; // mark this byte to show that more bytes will follow - *((unsigned char*)addr) = byte; - addr++; + dest.push_back(byte); count++; } while (val != 0); diff --git a/src/leb128.h b/src/leb128.h index 8a2863d551..73ca24526d 100644 --- a/src/leb128.h +++ b/src/leb128.h @@ -10,12 +10,14 @@ #include +#include "llvm/SmallVector.h" + namespace nt { class raw_istream; std::size_t SizeUleb128(unsigned long val); -std::size_t WriteUleb128(char* addr, unsigned long val); +std::size_t WriteUleb128(llvm::SmallVectorImpl& dest, unsigned long val); std::size_t ReadUleb128(const char* addr, unsigned long* ret); bool ReadUleb128(raw_istream& is, unsigned long* ret); diff --git a/test/unit/leb128Test.cpp b/test/unit/leb128Test.cpp index 7019eb7713..27734df486 100644 --- a/test/unit/leb128Test.cpp +++ b/test/unit/leb128Test.cpp @@ -21,6 +21,7 @@ #include #include +#include "llvm/SmallString.h" #include "llvm/StringRef.h" #include "raw_istream.h" @@ -31,10 +32,10 @@ TEST(LEB128Test, WriteUleb128) { #define EXPECT_ULEB128_EQ(EXPECTED, VALUE, PAD) \ do { \ llvm::StringRef expected(EXPECTED, sizeof(EXPECTED)-1); \ - char buf[32]; \ + llvm::SmallString<32> buf; \ std::size_t size = WriteUleb128(buf, VALUE); \ - llvm::StringRef actual(buf, size); \ - EXPECT_EQ(expected, actual); \ + EXPECT_EQ(size, buf.size()); \ + EXPECT_EQ(expected, buf.str()); \ } while (0) // Write ULEB128