Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- 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));
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement