diff --git a/wpiutil/src/main/native/cpp/leb128.cpp b/wpiutil/src/main/native/cpp/leb128.cpp index aa931c0bb9..965788332e 100644 --- a/wpiutil/src/main/native/cpp/leb128.cpp +++ b/wpiutil/src/main/native/cpp/leb128.cpp @@ -4,7 +4,10 @@ #include "wpi/leb128.h" +#include "wpi/SpanExtras.h" #include "wpi/raw_istream.h" +#include "wpi/raw_ostream.h" +#include "wpi/span.h" namespace wpi { @@ -21,7 +24,7 @@ uint64_t WriteUleb128(SmallVectorImpl& dest, uint64_t val) { size_t count = 0; do { - unsigned char byte = val & 0x7f; + uint8_t byte = val & 0x7f; val >>= 7; if (val != 0) { @@ -35,6 +38,19 @@ uint64_t WriteUleb128(SmallVectorImpl& dest, uint64_t val) { return count; } +void WriteUleb128(raw_ostream& os, uint64_t val) { + do { + uint8_t byte = val & 0x7f; + val >>= 7; + + if (val != 0) { + byte |= 0x80; // mark this byte to show that more bytes will follow + } + + os << byte; + } while (val != 0); +} + uint64_t ReadUleb128(const char* addr, uint64_t* ret) { uint64_t result = 0; int shift = 0; @@ -82,4 +98,22 @@ bool ReadUleb128(raw_istream& is, uint64_t* ret) { return true; } +std::optional Uleb128Reader::ReadOne(span* in) { + while (!in->empty()) { + uint8_t byte = in->front(); + *in = wpi::drop_front(*in); + + m_result |= (byte & 0x7fULL) << m_shift; + m_shift += 7; + + if (!(byte & 0x80)) { + uint64_t result = m_result; + m_result = 0; + m_shift = 0; + return result; + } + } + return std::nullopt; +} + } // namespace wpi diff --git a/wpiutil/src/main/native/include/wpi/leb128.h b/wpiutil/src/main/native/include/wpi/leb128.h index 7bcf1ef663..be158fe729 100644 --- a/wpiutil/src/main/native/include/wpi/leb128.h +++ b/wpiutil/src/main/native/include/wpi/leb128.h @@ -5,13 +5,18 @@ #ifndef WPIUTIL_WPI_LEB128_H_ #define WPIUTIL_WPI_LEB128_H_ -#include +#include -#include "wpi/SmallVector.h" +#include + +#include "wpi/span.h" namespace wpi { +template +class SmallVectorImpl; class raw_istream; +class raw_ostream; /** * Get size of unsigned LEB128 data @@ -26,7 +31,7 @@ uint64_t SizeUleb128(uint64_t val); /** * Write unsigned LEB128 data - * @addr: the address where the ULEB128 data is to be stored + * @dest: the address where the ULEB128 data is to be stored * @val: value to be stored * * Encode an unsigned LEB128 encoded datum. The algorithm is taken @@ -36,6 +41,18 @@ uint64_t SizeUleb128(uint64_t val); */ uint64_t WriteUleb128(SmallVectorImpl& dest, uint64_t val); +/** + * Write unsigned LEB128 data. + * + * Encode an unsigned LEB128 encoded datum. The algorithm is taken + * from Appendix C of the DWARF 3 spec. For information on the + * encodings refer to section "7.6 - Variable Length Data". + * + * @param os output stream + * @param val value to be stored + */ +void WriteUleb128(raw_ostream& os, uint64_t val); + /** * Read unsigned LEB128 data * @addr: the address where the ULEB128 data is stored @@ -60,6 +77,32 @@ uint64_t ReadUleb128(const char* addr, uint64_t* ret); */ bool ReadUleb128(raw_istream& is, uint64_t* ret); +/** + * Unsigned LEB128 streaming reader. + * + * Decode an unsigned LEB128 encoded datum. The algorithm is taken + * from Appendix C of the DWARF 3 spec. For information on the + * encodings refer to section "7.6 - Variable Length Data". + */ +class Uleb128Reader { + public: + /** + * Decode a single ULEB128 value. Returns after a single ULEB128 value has + * been read or insufficient input (call in a loop to get multiple values). + * If a value is returned, internal state is reset so it's safe to immediately + * call this function again to decode another value. + * + * @param in input data; modified as data is consumed (any unconsumed data + * is left when function returns) + * @return value (in std::optional) + */ + std::optional ReadOne(span* in); + + private: + uint64_t m_result = 0; + int m_shift = 0; +}; + } // namespace wpi #endif // WPIUTIL_WPI_LEB128_H_