Task: Variable-length quantity


C++: #include <iomanip>
#include <iostream>
#include <vector>

std::ostream &operator<<(std::ostream &os, const std::vector<uint8_t> &v) {
    auto it = v.cbegin();
    auto end = v.cend();

    os << "[ ";
    if (it != end) {
        os << std::setfill('0') << std::setw(2) << (uint32_t)*it;
        it = std::next(it);
    }
    while (it != end) {
        os << ' ' << std::setfill('0') << std::setw(2) << (uint32_t)*it;
        it = std::next(it);
    }
    return os << " ]";
}

std::vector<uint8_t> to_seq(uint64_t x) {
    int i;
    for (i = 9; i > 0; i--) {
        if (x & 127ULL << i * 7) {
            break;
        }
    }

    std::vector<uint8_t> out;
    for (int j = 0; j <= i; j++) {
        out.push_back(((x >> ((i - j) * 7)) & 127) | 128);
    }
    out[i] ^= 128;
    return out;
}

uint64_t from_seq(const std::vector<uint8_t> &seq) {
    uint64_t r = 0;

    for (auto b : seq) {
        r = (r << 7) | (b & 127);
    }

    return r;
}

int main() {
    std::vector<uint64_t> src{ 0x7f, 0x4000, 0, 0x3ffffe, 0x1fffff, 0x200000, 0x3311a1234df31413ULL };

    for (auto x : src) {
        auto s = to_seq(x);
        std::cout << std::hex;
        std::cout << "seq from " << x << ' ' << s << " back: " << from_seq(s) << '\n';
        std::cout << std::dec;
    }

    return 0;
}










Ada: with Ada.Containers.Vectors;
with Ada.Text_IO;
with Ada.Unchecked_Conversion;

procedure VLQ is

   package Nat_IO is new Ada.Text_IO.Integer_IO (Natural);

   type Byte is mod 2**8;

   package Byte_IO is new Ada.Text_IO.Modular_IO (Byte);

   type Int7 is mod 2**7;

   package Int7_IO is new Ada.Text_IO.Modular_IO (Int7);

   type VLQ_Octet is record
      Value : Int7 := 0;
      Next  : Boolean := True;
   end record;
   pragma Pack (VLQ_Octet);
   for VLQ_Octet'Size use 8;

   function VLQ_To_Byte is new Ada.Unchecked_Conversion (VLQ_Octet, Byte);
   function Byte_To_VLQ is new Ada.Unchecked_Conversion (Byte, VLQ_Octet);

   package VLQ_Vectors is new Ada.Containers.Vectors (Natural, VLQ_Octet);

   procedure Hex_Print (Position : in VLQ_Vectors.Cursor) is
      Value : Byte := VLQ_To_Byte (VLQ_Vectors.Element (Position));
   begin
      Ada.Text_IO.Put (':');
      Byte_IO.Put (Item => Value, Width => 6, Base => 16);
   end Hex_Print;

   procedure Print (X : VLQ_Vectors.Vector) is
   begin
      X.Iterate (Hex_Print'Access);
      Ada.Text_IO.New_Line;
   end Print;

   function To_VLQ (From : Natural) return VLQ_Vectors.Vector is
      Result : VLQ_Vectors.Vector;
      Current : Natural := From;
      Element : VLQ_Octet;
   begin
      loop
         Element.Value := Int7 (Current mod 2**7);
         Result.Prepend (Element);
         Current := Current / 2**7;
         exit when Current = 0;
      end loop;
      Element := Result.Last_Element;
      Element.Next := False;
      VLQ_Vectors.Replace_Element (Result, Result.Last, Element);
      return Result;
   end To_VLQ;

   function To_Int (From : VLQ_Vectors.Vector) return Natural is
      use type VLQ_Vectors.Cursor;
      Result : Natural := 0;
      Iterator : VLQ_Vectors.Cursor := From.First;
   begin
      while Iterator /= VLQ_Vectors.No_Element loop
         Result := Result * 2**7;
         Result := Result + Natural(VLQ_Vectors.Element (Iterator).Value);
         VLQ_Vectors.Next (Iterator);
      end loop;
      return Result;
   end To_Int;

   Test : VLQ_Vectors.Vector;
begin
   Test := To_VLQ (16#7f#);
   Nat_IO.Put (To_Int (Test), 10, 16); Ada.Text_IO.Put (" = ");
   Print (Test);
   Test := To_VLQ (16#4000#);
   Nat_IO.Put (To_Int (Test), 10, 16); Ada.Text_IO.Put (" = ");
   Print (Test);
   Test := To_VLQ (16#0#);
   Nat_IO.Put (To_Int (Test), 10, 16); Ada.Text_IO.Put (" = ");
   Print (Test);
   Test := To_VLQ (16#3FFFFE#);
   Nat_IO.Put (To_Int (Test), 10, 16); Ada.Text_IO.Put (" = ");
   Print (Test);
   Test := To_VLQ (16#1FFFFF#);
   Nat_IO.Put (To_Int (Test), 10, 16); Ada.Text_IO.Put (" = ");
   Print (Test);
   Test := To_VLQ (16#200000#);
   Nat_IO.Put (To_Int (Test), 10, 16); Ada.Text_IO.Put (" = ");
   Print (Test);
end VLQ;