Ver código fonte

Add Generator, BinaryData, and function contextualised_select

Billy Barrow 2 anos atrás
pai
commit
829c690d58

+ 215 - 0
src/lib/Concrete/BinaryData.vala

@@ -0,0 +1,215 @@
+namespace Invercargill {
+
+    public class BinaryData : Enumerable<uint8> {
+
+        public enum Endianness {
+            Native,
+            BigEndian,
+            LittleEndian,
+        }
+
+        public Endianness endianness { get; set; }
+
+        private Enumerable<Enumerable<uint8>> chunks;
+
+        public override Tracker<uint8> get_tracker () {
+            return chunks.select_many<uint8>(s => s).get_tracker();
+        }
+
+        public BinaryData() {
+            chunks = new Sequence<Enumerable<uint8>>();
+            endianness = Endianness.Native;
+        }
+
+        public BinaryData.from_enumerable(Enumerable<uint8> data) {
+            chunks = Invercargill.single(data.to_sequence());
+            endianness = Endianness.Native;
+        }
+
+        public void append(Enumerable<uint8> data) {
+            lock(chunks) {
+                chunks = chunks.with(data);
+            }
+        }
+
+        public void prepend(Enumerable<uint8> data) {
+            lock(chunks) {
+                chunks = Invercargill.single(data).concat(chunks);
+            }
+        }
+
+        public void append_byte_array(uint8[] data) {
+            append(ate(data.copy()));
+        }
+
+        public void append_bytes(Bytes data) {
+            append_byte_array(data.get_data());
+        }
+
+        public void append_string(string str, bool remove_null_termination = true) {
+            append_byte_array(get_string_data(str, remove_null_termination));
+        }
+
+        public void prepend_byte_array(uint8[] data) {
+            prepend(ate(data.copy()));
+        }
+
+        public void prepend_bytes(Bytes data) {
+            prepend_byte_array(data.get_data());
+        }
+
+        public void prepend_string(string str, bool remove_null_termination = true) {
+            prepend_byte_array(get_string_data(str, remove_null_termination));
+        }
+        
+        private uint8[] get_string_data(string str, bool remove_null_termination) {
+            var data = (uint8[])str;
+            if(remove_null_termination) {
+                data = data[0:-1];
+            }
+            return data;
+        }
+
+        public void push_int64(int64 value) {
+            var chunk = new uint8[sizeof(int64)];
+            int64 val;
+            switch (endianness) {
+                case Endianness.Native:
+                    val = value;
+                    break;
+                case Endianness.BigEndian:
+                    val = value.to_big_endian();
+                    break;
+                case Endianness.LittleEndian:
+                    val = value.to_little_endian();
+                    break;
+            }            
+            Memory.copy(chunk, &val, sizeof(int64));
+            append(ate(chunk));
+        }
+
+        public void push_uint64(uint64 value) {
+            var chunk = new uint8[sizeof(uint64)];
+            uint64 val;
+            switch (endianness) {
+                case Endianness.Native:
+                    val = value;
+                    break;
+                case Endianness.BigEndian:
+                    val = value.to_big_endian();
+                    break;
+                case Endianness.LittleEndian:
+                    val = value.to_little_endian();
+                    break;
+            }            
+            Memory.copy(chunk, &val, sizeof(uint64));
+            append(ate(chunk));
+        }
+
+        public void push_int32(int32 value) {
+            var chunk = new uint8[sizeof(int32)];
+            int32 val;
+            switch (endianness) {
+                case Endianness.Native:
+                    val = value;
+                    break;
+                case Endianness.BigEndian:
+                    val = value.to_big_endian();
+                    break;
+                case Endianness.LittleEndian:
+                    val = value.to_little_endian();
+                    break;
+            }            
+            Memory.copy(chunk, &val, sizeof(int32));
+            append(ate(chunk));
+        }
+
+        public void push_uint32(uint32 value) {
+            var chunk = new uint8[sizeof(uint32)];
+            uint32 val;
+            switch (endianness) {
+                case Endianness.Native:
+                    val = value;
+                    break;
+                case Endianness.BigEndian:
+                    val = value.to_big_endian();
+                    break;
+                case Endianness.LittleEndian:
+                    val = value.to_little_endian();
+                    break;
+            }            
+            Memory.copy(chunk, &val, sizeof(uint32));
+            append(ate(chunk));
+        }
+
+        public void push_int16(int16 value) {
+            var chunk = new uint8[sizeof(int16)];
+            int16 val;
+            switch (endianness) {
+                case Endianness.Native:
+                    val = value;
+                    break;
+                case Endianness.BigEndian:
+                    val = value.to_big_endian();
+                    break;
+                case Endianness.LittleEndian:
+                    val = value.to_little_endian();
+                    break;
+            }            
+            Memory.copy(chunk, &val, sizeof(int16));
+            append(ate(chunk));
+        }
+
+        public void push_uint16(uint16 value) {
+            var chunk = new uint8[sizeof(uint16)];
+            uint16 val;
+            switch (endianness) {
+                case Endianness.Native:
+                    val = value;
+                    break;
+                case Endianness.BigEndian:
+                    val = value.to_big_endian();
+                    break;
+                case Endianness.LittleEndian:
+                    val = value.to_little_endian();
+                    break;
+            }            
+            Memory.copy(chunk, &val, sizeof(uint16));
+            append(ate(chunk));
+        }
+
+        public void push_int8(int8 value) {
+            var chunk = new uint8[sizeof(int8)];    
+            Memory.copy(chunk, &value, sizeof(int8));
+            append(ate(chunk));
+        }
+
+        public void push_uint8(uint8 value) {
+            var chunk = new uint8[] { value };
+            append(ate(chunk));
+        }
+
+        public string to_escaped_string() {
+            var builder = new StringBuilder();
+            foreach (var byte in this) {
+                if(byte >= 32 && byte <= 126) {
+                    builder.append_unichar((unichar)byte);
+                }
+                else {
+                    builder.append(@"[$(byte)d]");
+                }
+            }
+            return builder.str;
+        }
+
+        public string to_base64() {
+            return Base64.encode(to_array());
+        }
+
+        public BinaryData slice(int start, int end) {
+            return new BinaryData.from_enumerable(skip(start).take(end-start));
+        }
+
+    }
+
+}

+ 86 - 0
src/lib/Concrete/Generator.vala

@@ -0,0 +1,86 @@
+namespace Invercargill {
+
+    public delegate GeneratorResult<T> GeneratorFunc<T>();
+
+    public class Generator<T> : Enumerable<T> {
+
+        private GeneratorFunc<T> func;
+        private bool completed = false;
+        private GeneratorResult<T>? next_result = null;
+
+        private bool has_next() {
+            lock(func) {
+                if(completed) {
+                    return false;
+                }
+                if(next_result == null) {
+                    next_result = func();
+                }
+                while(next_result.result == GeneratorResultType.SKIP) {
+                    next_result = func();
+                }
+                if(next_result.result == GeneratorResultType.END) {
+                    completed = true;
+                    return false;
+                }
+                return true;
+            }
+        }
+
+        private T get_next() {
+            lock(func) {
+                var res = next_result;
+                next_result = null;
+                return res.value;
+            }
+        }
+
+        public Generator(owned GeneratorFunc<T> generator) {
+            func = (owned)generator;
+        }
+
+        public override Tracker<T> get_tracker () {
+            return new LambdaTracker<T>(
+                () => has_next(),
+                () => get_next());
+        }
+    }
+
+    public class GeneratorResult<T> {
+        public GeneratorResultType result { get; private set; }
+        public T? value { get; private set; }
+
+        public GeneratorResult(T? item, GeneratorResultType type) {
+            this.value = item;
+            result = type;
+        }
+
+        public static GeneratorResult<T> item<T>(T item) {
+            return new GeneratorResult<T>(item, GeneratorResultType.VALUE);
+        }
+
+        public static GeneratorResult<T> end_if_null<T>(T? item) {
+            var result = item == null ? GeneratorResultType.END : GeneratorResultType.VALUE;
+            return new GeneratorResult<T>(item, result);
+        }
+
+        public static GeneratorResult<T> skip_if_null<T>(T? item) {
+            var result = item == null ? GeneratorResultType.SKIP : GeneratorResultType.VALUE;
+            return new GeneratorResult<T>(item, result);
+        }
+        
+        public static GeneratorResult<T> end<T>() {
+            return new GeneratorResult<T>(null, GeneratorResultType.END);
+        }
+
+        public static GeneratorResult<T> skip<T>() {
+            return new GeneratorResult<T>(null, GeneratorResultType.SKIP);
+        }
+    }
+
+    public enum GeneratorResultType {
+        VALUE,
+        SKIP,
+        END
+    }
+}

+ 7 - 0
src/lib/Enumerable.vala

@@ -119,6 +119,13 @@ namespace Invercargill {
             .count();
         }
 
+        public virtual Enumerable<SelectionContext<T, Tout>> contextualised_select<Tout>(owned TransformDelegate<T, Tout> transform) {
+            return new TransformQuery<T, SelectionContext<T, Tout>>(this, (i) => new SelectionContext<T, Tout>() {
+                origin = i,
+                result = transform(i)
+            });
+        }
+
         public virtual Tout aggrigate<Tout>(Tout initial, AggrigateDelegate<Tout, T> aggrigate_func) {
             var aggrigate = initial;
             iterate(i => {

+ 9 - 0
src/lib/SelectionContext.vala

@@ -0,0 +1,9 @@
+
+namespace Invercargill {
+
+    public class SelectionContext<TOrigin, TResult> {
+        public TOrigin origin {get; set;}
+        public TResult result {get; set;}
+    }
+
+}

+ 3 - 0
src/lib/meson.build

@@ -12,6 +12,7 @@ sources += files('Delegates.vala')
 sources += files('Pair.vala')
 sources += files('Tracker.vala')
 sources += files('SequenceError.vala')
+sources += files('SelectionContext.vala')
 
 sources += files('Queries/Query.vala')
 sources += files('Queries/Transform.vala')
@@ -34,6 +35,8 @@ sources += files('Concrete/ZipperEnumerable.vala')
 sources += files('Concrete/EmptyEnumerable.vala')
 sources += files('Concrete/Sequence.vala')
 sources += files('Concrete/Fifo.vala')
+sources += files('Concrete/Generator.vala')
+sources += files('Concrete/BinaryData.vala')
 
 invercargill = shared_library('invercargill', sources,
     dependencies: dependencies,

+ 66 - 0
src/tests/Integration/BinaryData.vala

@@ -0,0 +1,66 @@
+using Invercargill;
+
+void binary_data_tests() {
+
+    Test.add_func("/invercargill/structure/binary_data/endian_test", () => {
+
+        uint64 u64 = 3292849078942343;
+        int64 i64 = 637292174;
+        uint32 u32 = 43782989;
+        int32 i32 = 32898762;
+        uint16 u16 = 47839;
+        int16 i16 = 3892;
+        uint8 u8 = 253;
+        int8 i8 = 121;
+
+        var expected_le = ate(new uint8[] { 
+            0x87, 0x3A, 0xA6, 0x2B, 0xD4, 0xB2, 0x0B, 0x00, // u64
+            0x8E, 0x4E, 0xFC, 0x25, 0x00, 0x00, 0x00, 0x00, // i64
+            0x4D, 0x13, 0x9C, 0x02, // u32
+            0xCA, 0xFE, 0xF5, 0x01, // i32
+            0xDF, 0xBA, // u16
+            0x34, 0x0F, // i16
+            0xFD, // u8
+            0x79  // i8
+        });
+
+        var bin_le = new BinaryData();
+        bin_le.endianness = BinaryData.Endianness.LittleEndian;
+        bin_le.push_uint64(u64);
+        bin_le.push_int64(i64);
+        bin_le.push_uint32(u32);
+        bin_le.push_int32(i32);
+        bin_le.push_uint16(u16);
+        bin_le.push_int16(i16);
+        bin_le.push_uint8(u8);
+        bin_le.push_int8(i8);
+
+        var expected_be = ate(new uint8[] { 
+            0x00, 0x0B, 0xB2, 0xD4, 0x2B, 0xA6, 0x3A, 0x87, // u64
+            0x00, 0x00, 0x00, 0x00, 0x25, 0xFC, 0x4E, 0x8E, // i64
+            0x02, 0x9C, 0x13, 0x4D, // u32
+            0x01, 0xF5, 0xFE, 0xCA, // i32
+            0xBA, 0xDF, // u16
+            0x0F, 0x34, // i16
+            0xFD, // u8
+            0x79  // i8
+        });
+
+        var bin_be = new BinaryData();
+        bin_be.endianness = BinaryData.Endianness.BigEndian;
+        bin_be.push_uint64(u64);
+        bin_be.push_int64(i64);
+        bin_be.push_uint32(u32);
+        bin_be.push_int32(i32);
+        bin_be.push_uint16(u16);
+        bin_be.push_int16(i16);
+        bin_be.push_uint8(u8);
+        bin_be.push_int8(i8);
+
+        assert_true(bin_le.matches(expected_le, (b1, b2) => b1 == b2));
+        assert_true(bin_be.matches(expected_be, (b1, b2) => b1 == b2));
+
+    });
+
+
+}

+ 1 - 0
src/tests/TestRunner.vala

@@ -10,6 +10,7 @@ public static int main(string[] args) {
     tracker_tests();
     parallel_tests();
     first_tests();
+    binary_data_tests();
 
     Test.run();
 

+ 1 - 0
src/tests/meson.build

@@ -10,5 +10,6 @@ sources += files('Integration/Gee.vala')
 sources += files('Integration/Tracker.vala')
 sources += files('Integration/Parallel.vala')
 sources += files('Integration/Firsts.vala')
+sources += files('Integration/BinaryData.vala')
 
 executable('invercargill-test-suite', sources, dependencies: dependencies, install: true)