aaaaaa123456789 icon

IntegerSerializer C# implementation (uses UnlimitedMatrix)

aaaaaa123456789 | PRO | 07/17/15 02:10:08 AM UTC | 0 ⭐ | 579 👁️ | Never ⏰ | []
C# |

8.01 KB

|

None

|

0 👍

/

0 👎

/*
   This code is hereby released to the public domain.
   ~aaaaaa123456789, 2015-07-16
*/
 
using System;
using System.Collections.Generic;
 
public static class IntegerSerializer<T> {
  public static byte[] serialize (UnlimitedMatrix<T> data) {
    List<byte[]> contents = new List<byte[]>();
    ulong size = 0;
    long value;
    long current_value = 0;
    List<long[]> current_stack = new List<long[]>();
    long[] previous = new long[] {64, 64};
    foreach (long[] coords in data) {
      value = convert_from(data[coords[0], coords[1]]);
      if (value == current_value) {
        current_stack.Add(coords);
        continue;
      }
      if (current_value != 0) write_stack(contents, ref size, current_stack, current_value, ref previous);
      current_value = value;
      current_stack = new List<long[]>();
      current_stack.Add(coords);
    }
    if (current_value != 0) write_stack(contents, ref size, current_stack, current_value, ref previous);
    current_stack = null;
    byte[] result = new byte[size + 1];
    ulong current, pointer = 0;
    for (current = 0; current < (ulong) contents.Count; current ++) {
      Array.Copy(contents[(int) current], 0L, result, (long) pointer, contents[(int) current].LongLength);
      pointer += (ulong) contents[(int) current].LongLength;
    }
    result[pointer] = 0;
    return result;
  }
 
 
  private static void write_stack (List<byte[]> contents, ref ulong size, List<long[]> stack, long value, ref long[] prev) {
    if (stack.Count < 4)
      write_stack_single(contents, ref size, stack, value, ref prev);
    else
      write_stack_run(contents, ref size, stack, value, ref prev);
  }
 
  private static void write_stack_single (List<byte[]> contents, ref ulong size, List<long[]> stack, long value, ref long[] prev) {
    byte[] serialized_value = encode_number(value, false);
    foreach(long[] coords in stack) {
      push(contents, ref size, serialized_value);
      push_coordinates(contents, ref size, coords, ref prev);
    }
  }
 
  private static void write_stack_run (List<byte[]> contents, ref ulong size, List<long[]> stack, long value, ref long[] prev) {
    push(contents, ref size, encode_number(value, true));
    foreach (long[] coords in stack) push_coordinates(contents, ref size, coords, ref prev);
    push(contents, ref size, new byte[] {0x40, 0x40});
  }
 
  private static void push_coordinates (List<byte[]> contents, ref ulong size, long[] coordinates, ref long[] previous) {
    push(contents, ref size, create_coordinate(coordinates[0], ref previous[0]));
    push(contents, ref size, create_coordinate(coordinates[1], ref previous[1]));
  }
 
  private static byte[] create_coordinate (long coordinate, ref long reference) {
    byte[] absolute = encode_number(coordinate);
    byte[] relative = encode_number(coordinate, reference);
    reference = coordinate;
    if (relative.Length < absolute.Length) return relative;
    return absolute;
  }
 
  private static void push (List<byte[]> contents, ref ulong size, byte[] item) {
    contents.Add(item);
    size += (ulong) item.LongLength;
  }
 
  public static UnlimitedMatrix<T> unserialize (byte[] data, ref ulong pointer) {
    UnlimitedMatrix<T> result = new UnlimitedMatrix<T>();
    long[] previous_coordinates = new long[] {64, 64};
    while (data[pointer] != 0)
      if ((data[pointer] & 0x40) != 0)
        read_run(result, data, ref pointer, ref previous_coordinates);
      else
        read_single(result, data, ref pointer, ref previous_coordinates);
    pointer ++;
    return result;
  }
 
  private static void read_single (UnlimitedMatrix<T> dst, byte[] src, ref ulong pointer, ref long[] previous) {
    bool kind;
    int advance;
    long value = decode_number(src, pointer, out kind, out advance);
    if (kind) throw new InvalidOperationException();
    pointer += (ulong) advance;
    long[] coordinates = read_coordinates(src, ref pointer, ref previous);
    dst[coordinates[0], coordinates[1]] = convert_to(value);
  }
 
  private static void read_run (UnlimitedMatrix<T> dst, byte[] src, ref ulong pointer, ref long[] previous) {
    bool kind;
    int advance;
    long value = decode_number(src, pointer, out kind, out advance);
    T converted = convert_to(value);
    if (!kind) throw new InvalidOperationException();
    pointer += (ulong) advance;
    long[] coordinates;
    while ((src[pointer] != 0x40) || (src[pointer + 1] != 0x40)) {
      coordinates = read_coordinates(src, ref pointer, ref previous);
      dst[coordinates[0], coordinates[1]] = converted;
    }
    pointer += 2;
  }
 
  private static long[] read_coordinates (byte[] src, ref ulong pointer, ref long[] previous) {
    long[] result = new long[2];
    result[0] = read_coordinate(src, ref pointer, ref previous[0]);
    result[1] = read_coordinate(src, ref pointer, ref previous[1]);
    return result;
  }
 
  private static long read_coordinate (byte[] src, ref ulong pointer, ref long previous) {
    bool relative;
    int advance;
    long coordinate = decode_number(src, pointer, out relative, out advance);
    pointer += (ulong) advance;
    if (relative) coordinate += previous;
    previous = coordinate;
    return coordinate;
  }
 
  public static UnlimitedMatrix<T> unserialize (byte[] data, ulong pointer) {
    return unserialize(data, ref pointer);
  }
 
  public static UnlimitedMatrix<T> unserialize (byte[] data) {
    ulong pointer = 0;
    return unserialize(data, ref pointer);
  }
 
  private static byte[] encode_number (long number, bool kind) {
    bool sign = number < 0;
    if (sign) number = ~number;
    int length;
    if (number < 0x20L)
      length = 1;
    else if (number < 0x1000L)
      length = 2;
    else if (number < 0x80000L)
      length = 3;
    else if (number < 0x4000000L)
      length = 4;
    else if (number < 0x200000000L)
      length = 5;
    else if (number < 0x10000000000L)
      length = 6;
    else if (number < 0x800000000000L)
      length = 7;
    else
      length = 9;
    byte[] result = new byte[length];
    long available_bits = 0x887777775L;
    int current, bits;
    for (current = 0; current < length; current ++) {
      bits = (int) (available_bits & 15);
      available_bits >>= 4;
      result[current] = (byte) ((((bits == 8) || (length == (current + 1))) ? 0 : 0x80) | ((byte) number & ((1 << bits) - 1)));
      number >>= bits;
    }
    if (kind) result[0] |= 0x40;
    if (sign) result[0] |= 0x20;
    return result;
  }
 
  private static byte[] encode_number (long number, long reference) {
    return encode_number(number - reference, true);
  }
 
  private static byte[] encode_number (long number) {
    return encode_number(number, false);
  }
 
  private static long decode_number (byte[] data, ulong position, out bool kind, out int length) {
    for (length = 0; length < 7; length ++) if ((data[position + (ulong) length] & 0x80) == 0) break;
    if (length == 7)
      length = 9;
    else
      length ++;
    if ((ulong) data.Length < (position + (ulong) length)) throw new IndexOutOfRangeException();
    long available_bits = 0x887777775L;
    int current, bits, shift_state = 0;
    long result = 0;
    for (current = 0; current < length; current ++) {
      bits = (int) (available_bits & 15);
      available_bits >>= 4;
      result |= (((long) data[position + (ulong) current]) & ((1L << bits) - 1)) << shift_state;
      shift_state += bits;
    }
    kind = (data[position] & 0x40) != 0;
    if ((data[position] & 0x20) != 0) result = ~result;
    return result;
  }
 
  private static long decode_number (byte[] data, ulong position, long reference, out int length) {
    bool relative;
    long rv = decode_number(data, position, out relative, out length);
    if (relative) rv += reference;
    return rv;
  }
 
  private static long convert_from (T value) {
    return (long) Convert.ChangeType(value, typeof(long));
  }
 
  private static T convert_to (long value) {
    return (T) Convert.ChangeType(value, typeof(T));
  }
}

Comments