From edf49792078609b8b8957fae62b17a77fb931d43 Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Sun, 10 Jun 2018 10:25:34 +0200 Subject: [PATCH] make `@safe`, improve coverage and refresh the style --- source/tinyendian.d | 97 +++++++++++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 34 deletions(-) diff --git a/source/tinyendian.d b/source/tinyendian.d index 205effa..f5bf64d 100644 --- a/source/tinyendian.d +++ b/source/tinyendian.d @@ -6,10 +6,6 @@ /// A minimal library providing functionality for changing the endianness of data. module tinyendian; - -import core.stdc.string; - -import std.algorithm; import std.system; import std.utf; @@ -23,8 +19,8 @@ enum UTFEncoding : ubyte UTF_16, UTF_32 } - -unittest +/// +@safe unittest { const ints = [314, -101]; int[2] intsSwapBuffer = ints; @@ -39,8 +35,6 @@ unittest assert(floats == floatsSwapBuffer, "Lost information when swapping byte order"); } -@nogc @system pure nothrow: - /** Swap byte order of items in an array in place. * * Params: @@ -48,19 +42,20 @@ unittest * T = Item type. Must be either 2 or 4 bytes long. * array = Buffer with values to fix byte order of. */ -void swapByteOrder(T)(T[] array) - if([2, 4].canFind(T.sizeof)) +void swapByteOrder(T)(T[] array) @trusted @nogc pure nothrow +if (T.sizeof == 2 || T.sizeof == 4) { - import core.bitop; // Swap the byte order of all read characters. - foreach(ref item; array) + foreach (ref item; array) { - static if(T.sizeof == 2) + static if (T.sizeof == 2) { + import std.algorithm.mutation : swap; swap(*cast(ubyte*)&item, *(cast(ubyte*)&item + 1)); } - else static if(T.sizeof == 4) + else static if (T.sizeof == 4) { + import core.bitop : bswap; const swapped = bswap(*cast(uint*)&item); item = *cast(const(T)*)&swapped; } @@ -68,6 +63,15 @@ void swapByteOrder(T)(T[] array) } } +/// See fixUTFByteOrder. +struct FixUTFByteOrderResult +{ + ubyte[] array; + UTFEncoding encoding; + Endian endian; + uint bytesStripped = 0; +} + /** Convert byte order of an array encoded in UTF(8/16/32) to system endianness in place. * * Uses the UTF byte-order-mark (BOM) to determine UTF encoding. If there is no BOM @@ -100,7 +104,7 @@ void swapByteOrder(T)(T[] array) * * Complexity: (BIGOH array.length) */ -auto fixUTFByteOrder(ubyte[] array) +auto fixUTFByteOrder(ubyte[] array) @safe @nogc pure nothrow { // Enumerates UTF BOMs, matching indices to byteOrderMarks/bomEndian. enum BOM: ubyte @@ -126,23 +130,17 @@ auto fixUTFByteOrder(ubyte[] array) Endian.bigEndian ]; // Documented in function ddoc. - struct Result - { - ubyte[] array; - UTFEncoding encoding; - Endian endian; - uint bytesStripped = 0; - } - Result result; + + FixUTFByteOrderResult result; // Detect BOM, if any, in the bytes we've read. -1 means no BOM. // Need the last match: First 2 bytes of UTF-32LE BOM match the UTF-16LE BOM. If we // used the first match, UTF-16LE would be detected when we have a UTF-32LE BOM. + import std.algorithm.searching : startsWith; BOM bomId = BOM.None; - foreach(i, bom; byteOrderMarks) if(array.startsWith(bom)) - { - bomId = cast(BOM)i; - } + foreach (i, bom; byteOrderMarks) + if (array.startsWith(bom)) + bomId = cast(BOM)i; result.endian = (bomId != BOM.None) ? bomEndian[bomId] : Endian.init; @@ -168,21 +166,52 @@ auto fixUTFByteOrder(ubyte[] array) break; } - array = array[0 .. $ - result.bytesStripped]; // If there's a BOM, we need to move data back to ensure it starts at array[0] - if(start != 0) + if (start != 0) { - core.stdc.string.memmove(array.ptr, array.ptr + start, array.length - start); - array = array[0 .. $ - start]; + array = array[start .. $ - result.bytesStripped]; } // We enforce above that array.length is divisible by 2/4 for UTF-16/32 - if(std.system.endian != result.endian) + if (std.system.endian != result.endian) { - if(result.encoding == UTFEncoding.UTF_16) { swapByteOrder(cast(wchar[])array); } - else if(result.encoding == UTFEncoding.UTF_32) { swapByteOrder(cast(dchar[])array); } + if (result.encoding == UTFEncoding.UTF_16) + swapByteOrder(cast(wchar[])array); + else if (result.encoding == UTFEncoding.UTF_32) + swapByteOrder(cast(dchar[])array); } result.array = array; return result; } +/// +@safe unittest +{ + { + ubyte[] s = [0xEF, 0xBB, 0xBF, 'a']; + FixUTFByteOrderResult r = fixUTFByteOrder(s); + assert(r.encoding == UTFEncoding.UTF_8); + assert(r.array.length == 1); + assert(r.array == ['a']); + assert(r.endian == Endian.littleEndian); + } + + { + ubyte[] s = ['a']; + FixUTFByteOrderResult r = fixUTFByteOrder(s); + assert(r.encoding == UTFEncoding.UTF_8); + assert(r.array.length == 1); + assert(r.array == ['a']); + assert(r.endian == Endian.bigEndian); + } + + { + // strip 'a' b/c not complete unit + ubyte[] s = [0xFE, 0xFF, 'a']; + FixUTFByteOrderResult r = fixUTFByteOrder(s); + assert(r.encoding == UTFEncoding.UTF_16); + assert(r.array.length == 0); + assert(r.endian == Endian.bigEndian); + } + +}