The Perl Toolchain Summit 2025 Needs You: You can help 🙏 Learn more

#pragma once
#include <panda/string.h>
namespace panda {
inline string varint_encode(uint32_t i) {
string res;
while (i > 127) {
res += 0x80 | uint8_t(i & 0x7F);
i >>= 7;
}
res += uint8_t(i);
return res;
}
inline uint32_t _varint_decode(const char*& ptr, const char* end) {
size_t i = 0;
uint32_t r = 0;
while (ptr != end && (*ptr & 0x80)) {
r |= (*ptr & 0x7f) << 7*i;
++i;
ptr++;
}
r |= (*ptr & 0x7f) << 7*i;
++ptr;
return r;
}
inline uint32_t varint_decode(const string& str, size_t start = 0) {
auto begin = str.data() + start;
return _varint_decode(begin, str.data() + str.length());
}
inline string varint_encode_s(int32_t i) {
//ZigZag encoding, x86 (both 32,64) only, uses signed bit shift
return varint_encode((i << 1) ^ (i >> 31));
}
inline int32_t _varint_decode_s(const char*& ptr, const char* end) {
//ZigZag decoding
uint32_t i = _varint_decode(ptr, end);
return ((i >> 1) ^ -(i & 1));
}
inline int32_t varint_decode_s(const string& str) {
auto begin = str.data();
return _varint_decode_s(begin, str.data() + str.length());
}
struct VarIntStack {
string storage;
struct const_iterator {
const char* ptr;
using size_type = size_t;
using value_type = int;
using reference = int&;
using pointer = int*;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
int operator*() const {
auto copy = ptr; // to prevent ptr from moving
return _varint_decode_s(copy, nullptr); // unsafe end
}
const_iterator& operator++ () {
_varint_decode_s(ptr, nullptr);
return *this;
}
const_iterator operator++ (int) {
auto res = *this;
_varint_decode_s(ptr, nullptr);
return res;
}
bool operator== (const const_iterator& oth) const {return ptr == oth.ptr;}
bool operator!= (const const_iterator& oth) const {return !operator ==(oth);}
};
VarIntStack() = default;
VarIntStack(const VarIntStack&) = default;
VarIntStack(VarIntStack&&) = default;
~VarIntStack() = default;
VarIntStack& operator=(const VarIntStack&) = default;
VarIntStack& operator=(VarIntStack&&) = default;
void push(int32_t val) {
storage.insert(0, varint_encode_s(val));
}
void pop() {
storage.offset(size_of_first());
}
int32_t top() const {
return varint_decode_s(storage.substr(0, size_of_first()));
}
size_t size() const {
size_t res = 0;
for (char c : storage) {
if (!(c&0x80)) {
res += 1;
}
}
return res;
}
void clear () {
storage.clear();
}
bool empty() const {
return storage.empty();
}
const_iterator begin() const {
return const_iterator{storage.data()};
}
const_iterator end() const {
return const_iterator{storage.data() + storage.length()};
}
private:
size_t size_of_first() const {
size_t pos = 0;
for (; pos < storage.size(); ++pos) {
if (!(storage[pos] & 0x80)) {
break;
}
}
return pos + 1;
}
};
}