User:Shimmy/Variable-length quantity

From Rosetta Code
Revision as of 00:23, 30 October 2014 by rosettacode>Shimmy (Created page with "<lang csharp>namespace Vlq { using System; using System.Collections.Generic; using System.Linq; public static class VarLenQuantity { public static ulong ToVlq(u...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

<lang csharp>namespace Vlq {

 using System;
 using System.Collections.Generic;
 using System.Linq;
 public static class VarLenQuantity
 {
   public static ulong ToVlq(ulong integer)
   {
     var array = new byte[8];
     var buffer = ToVlqCollection(integer)
       .SkipWhile(b => b == 0)
       .Reverse()
       .ToArray();
     Array.Copy(buffer, array, buffer.Length);
     return BitConverter.ToUInt64(array, 0);
   }
   public static ulong FromVlq(ulong integer)
   {
     var collection = BitConverter.GetBytes(integer).Reverse();
     return FromVlqCollection(collection);
   }
   public static IEnumerable<byte> ToVlqCollection(ulong integer)
   {
     if (integer > Math.Pow(2, 56))
       throw new OverflowException("Integer exceeds max value.");
     var index = 7;
     var significantBitReached = false;
     var mask = 0x7fUL << (index * 7);
     while (index >= 0)
     {
       var buffer = (mask & integer);
       if (buffer > 0 || significantBitReached)
       {
         significantBitReached = true;
         buffer >>= index * 7;
         if (index > 0)
           buffer |= 0x80;
         yield return (byte)buffer;
       }
       mask >>= 7;
       index--;
     }
   }


   public static ulong FromVlqCollection(IEnumerable<byte> vlq)
   {
     ulong integer = 0;
     var significantBitReached = false;
     using (var enumerator = vlq.GetEnumerator())
     {
       int index = 0;
       while (enumerator.MoveNext())
       {
         var buffer = enumerator.Current;
         if (buffer > 0 || significantBitReached)
         {
           significantBitReached = true;
           integer <<= 7;
           integer |= (buffer & 0x7fUL);
         }
         if (++index == 8 || (significantBitReached && (buffer & 0x80) != 0x80))
           break;
       }
     }
     return integer;
   }
   public static void Main()
   {
     var integers = new ulong[] { 0x7fUL << 7 * 7, 0x80, 0x2000, 0x3FFF, 0x4000, 0x200000, 0x1fffff };
     foreach (var original in integers)
     {
       Console.WriteLine("Original: 0x{0:X}", original);
       //collection
       var seq = ToVlqCollection(original);
       Console.WriteLine("Sequence: 0x{0}", seq.Select(b => b.ToString("X2")).Aggregate(string.Concat));
       var decoded = FromVlqCollection(seq);
       Console.WriteLine("Decoded: 0x{0:X}", decoded);
       //ints
       var encoded = ToVlq(original);
       Console.WriteLine("Encoded: 0x{0:X}", encoded);
       decoded = FromVlq(encoded);
       Console.WriteLine("Decoded: 0x{0:X}", decoded);
       Console.WriteLine();
     }
     Console.WriteLine("Press any key to continue...");
     Console.ReadKey();
   }
 }

}</lang>output<lang>Original: 0xFE000000000000 Sequence: 0xFF80808080808000 Decoded: 0xFE000000000000 Encoded: 0xFF80808080808000 Decoded: 0xFE000000000000

Original: 0x80 Sequence: 0x8100 Decoded: 0x80 Encoded: 0x8100 Decoded: 0x80

Original: 0x2000 Sequence: 0xC000 Decoded: 0x2000 Encoded: 0xC000 Decoded: 0x2000

Original: 0x3FFF Sequence: 0xFF7F Decoded: 0x3FFF Encoded: 0xFF7F Decoded: 0x3FFF

Original: 0x4000 Sequence: 0x818000 Decoded: 0x4000 Encoded: 0x818000 Decoded: 0x4000

Original: 0x200000 Sequence: 0x81808000 Decoded: 0x200000 Encoded: 0x81808000 Decoded: 0x200000

Original: 0x1FFFFF Sequence: 0xFFFF7F Decoded: 0x1FFFFF Encoded: 0xFFFF7F Decoded: 0x1FFFFF

Press any key to continue...</lang>