#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) {
return
varint_encode((i << 1) ^ (i >> 31));
}
inline
int32_t _varint_decode_s(
const
char
*& ptr,
const
char
* end) {
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;
return
_varint_decode_s(copy,
nullptr
);
}
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;
}
};
}