From aeebf57ccbd7e79efe1ce9a9314224e9abb8d5e6 Mon Sep 17 00:00:00 2001 From: Luna Date: Thu, 19 Sep 2024 03:43:28 +0200 Subject: [PATCH] Major overhaul --- source/numem/all.d | 20 +- .../{mem => collections}/internal/btree.d | 4 +- source/numem/collections/internal/package.d | 7 + source/numem/{mem => collections}/map.d | 6 +- source/numem/collections/package.d | 15 ++ source/numem/{mem => collections}/set.d | 6 +- source/numem/{mem => collections}/vector.d | 13 +- source/numem/conv.d | 9 +- source/numem/{mem => core}/exception.d | 16 +- source/numem/{mem => core/memory}/package.d | 9 +- .../{mem/ptr.d => core/memory/smartptr.d} | 7 +- source/numem/core/package.d | 3 + source/numem/core/random.d | 247 ++++++++++++++++++ source/numem/{mem/internal => core}/trace.d | 2 +- source/numem/{mem => core}/utils.d | 12 +- source/numem/core/uuid.d | 154 +++++++++++ source/numem/io/endian.d | 25 +- source/numem/io/file.d | 6 +- source/numem/io/stdio.d | 2 +- source/numem/io/stream/filestream.d | 7 +- source/numem/io/stream/memstream.d | 7 +- source/numem/io/stream/package.d | 9 +- source/numem/io/stream/reader.d | 9 +- source/numem/io/stream/writer.d | 9 +- source/numem/mem.d | 11 + source/numem/mem/internal/package.d | 26 -- source/numem/{mem => }/string.d | 105 +++++--- source/numem/text/ascii.d | 63 +++++ source/numem/text/package.d | 11 + source/numem/{ => text}/unicode/package.d | 9 +- source/numem/{ => text}/unicode/utf16.d | 11 +- source/numem/{ => text}/unicode/utf8.d | 11 +- 32 files changed, 721 insertions(+), 130 deletions(-) rename source/numem/{mem => collections}/internal/btree.d (99%) create mode 100644 source/numem/collections/internal/package.d rename source/numem/{mem => collections}/map.d (98%) create mode 100644 source/numem/collections/package.d rename source/numem/{mem => collections}/set.d (97%) rename source/numem/{mem => collections}/vector.d (98%) rename source/numem/{mem => core}/exception.d (86%) rename source/numem/{mem => core/memory}/package.d (98%) rename source/numem/{mem/ptr.d => core/memory/smartptr.d} (99%) create mode 100644 source/numem/core/package.d create mode 100644 source/numem/core/random.d rename source/numem/{mem/internal => core}/trace.d (96%) rename source/numem/{mem => core}/utils.d (81%) create mode 100644 source/numem/core/uuid.d create mode 100644 source/numem/mem.d delete mode 100644 source/numem/mem/internal/package.d rename source/numem/{mem => }/string.d (83%) create mode 100644 source/numem/text/ascii.d create mode 100644 source/numem/text/package.d rename source/numem/{ => text}/unicode/package.d (85%) rename source/numem/{ => text}/unicode/utf16.d (95%) rename source/numem/{ => text}/unicode/utf8.d (98%) diff --git a/source/numem/all.d b/source/numem/all.d index faa0183..b6ed8dd 100644 --- a/source/numem/all.d +++ b/source/numem/all.d @@ -1,13 +1,19 @@ +/* + Copyright © 2024, Inochi2D Project + Distributed under the 2-Clause BSD License, see LICENSE file. + + Authors: Luna the Foxgirl +*/ + /** Automatically imports all of the numem types. */ module numem.all; -public import numem.mem; -public import numem.mem.ptr; -public import numem.mem.string; -public import numem.mem.vector; -public import numem.mem.map; -public import numem.mem.set; -public import numem.mem.exception; +public import numem.core; +public import numem.core.memory; +public import numem.collections; +public import numem.core.exception; public import numem.io; +public import numem.string; +public import numem.conv; diff --git a/source/numem/mem/internal/btree.d b/source/numem/collections/internal/btree.d similarity index 99% rename from source/numem/mem/internal/btree.d rename to source/numem/collections/internal/btree.d index ea9b044..bbae527 100644 --- a/source/numem/mem/internal/btree.d +++ b/source/numem/collections/internal/btree.d @@ -6,8 +6,8 @@ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Guillaume Piolat */ -module numem.mem.internal.btree; -import numem.mem; +module numem.collections.internal.btree; +import numem.core; import std.functional : binaryFun; diff --git a/source/numem/collections/internal/package.d b/source/numem/collections/internal/package.d new file mode 100644 index 0000000..a45dea4 --- /dev/null +++ b/source/numem/collections/internal/package.d @@ -0,0 +1,7 @@ +/* + Copyright © 2023, Inochi2D Project + Distributed under the 2-Clause BSD License, see LICENSE file. + + Authors: Luna Nielsen +*/ +module numem.core.internal; \ No newline at end of file diff --git a/source/numem/mem/map.d b/source/numem/collections/map.d similarity index 98% rename from source/numem/mem/map.d rename to source/numem/collections/map.d index d1cf0bc..e500b53 100644 --- a/source/numem/mem/map.d +++ b/source/numem/collections/map.d @@ -13,9 +13,9 @@ License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) Authors: Authors: Steven Schveighoffer, $(HTTP erdani.com, Andrei Alexandrescu), Guillaume Piolat */ -module numem.mem.map; -import numem.mem.internal.btree; -import numem.mem; +module numem.collections.map; +import numem.collections.internal.btree; +import numem.core; import std.functional : binaryFun; @nogc: diff --git a/source/numem/collections/package.d b/source/numem/collections/package.d new file mode 100644 index 0000000..ce3cbc1 --- /dev/null +++ b/source/numem/collections/package.d @@ -0,0 +1,15 @@ +/* + Copyright © 2023, Inochi2D Project + Distributed under the 2-Clause BSD License, see LICENSE file. + + Authors: Luna Nielsen +*/ + +/** + Standard numem collection types. +*/ +module numem.collections; + +public import numem.collections.vector; +public import numem.collections.set; +public import numem.collections.map; diff --git a/source/numem/mem/set.d b/source/numem/collections/set.d similarity index 97% rename from source/numem/mem/set.d rename to source/numem/collections/set.d index 22583f9..ed52474 100644 --- a/source/numem/mem/set.d +++ b/source/numem/collections/set.d @@ -13,9 +13,9 @@ License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) Authors: Authors: Steven Schveighoffer, $(HTTP erdani.com, Andrei Alexandrescu), Guillaume Piolat */ -module numem.mem.set; -import numem.mem.internal.btree; -import numem.mem; +module numem.collections.set; +import numem.collections.internal.btree; +import numem.core; import std.functional : binaryFun; diff --git a/source/numem/mem/vector.d b/source/numem/collections/vector.d similarity index 98% rename from source/numem/mem/vector.d rename to source/numem/collections/vector.d index 2ccd8e7..6c4ae50 100644 --- a/source/numem/mem/vector.d +++ b/source/numem/collections/vector.d @@ -1,12 +1,13 @@ /* - Copyright © 2023, Inochi2D Project + Copyright © 2024, Inochi2D Project Distributed under the 2-Clause BSD License, see LICENSE file. - - Authors: Luna Nielsen + + Authors: Luna the Foxgirl */ -module numem.mem.vector; -import numem.mem.ptr; -import numem.mem; + +module numem.collections.vector; +import numem.core.memory.smartptr; +import numem.core; import core.stdc.stdlib : malloc, realloc, free; import core.stdc.string : memcpy, memmove; import core.atomic : atomicFetchAdd, atomicFetchSub, atomicStore, atomicLoad; diff --git a/source/numem/conv.d b/source/numem/conv.d index 9bbc940..d139c94 100644 --- a/source/numem/conv.d +++ b/source/numem/conv.d @@ -1,3 +1,10 @@ +/* + Copyright © 2024, Inochi2D Project + Distributed under the 2-Clause BSD License, see LICENSE file. + + Authors: Luna the Foxgirl +*/ + /** Utilities for converting between some basic types */ @@ -11,7 +18,7 @@ version(NoC) { import core.stdc.stdlib; import core.stdc.stdio : snprintf; import std.traits; - import numem.mem.exception; + import numem.core.exception; @nogc: diff --git a/source/numem/mem/exception.d b/source/numem/core/exception.d similarity index 86% rename from source/numem/mem/exception.d rename to source/numem/core/exception.d index b0c94a9..12516e5 100644 --- a/source/numem/mem/exception.d +++ b/source/numem/core/exception.d @@ -1,11 +1,19 @@ +/* + Copyright © 2024, Inochi2D Project + Distributed under the 2-Clause BSD License, see LICENSE file. + + Authors: Luna the Foxgirl +*/ + /** Numem Exception support */ -module numem.mem.exception; -import numem.mem.string; -import numem.mem; +module numem.core.exception; +import numem.string; +import numem.core; + import core.stdc.stdio; -import numem.mem.internal.trace; +import numem.core.trace; @nogc: diff --git a/source/numem/mem/package.d b/source/numem/core/memory/package.d similarity index 98% rename from source/numem/mem/package.d rename to source/numem/core/memory/package.d index dfae947..7232850 100644 --- a/source/numem/mem/package.d +++ b/source/numem/core/memory/package.d @@ -4,11 +4,14 @@ Authors: Luna Nielsen */ -module numem.mem; + +module numem.core.memory; import core.stdc.stdlib : free, exit, malloc; import std.traits; -import numem.mem.utils; -import numem.mem.internal.trace; +import numem.core.utils; +import numem.core.trace; + +public import numem.core.memory.smartptr; version(Have_tinyd_rt) { private __gshared diff --git a/source/numem/mem/ptr.d b/source/numem/core/memory/smartptr.d similarity index 99% rename from source/numem/mem/ptr.d rename to source/numem/core/memory/smartptr.d index a2a9a84..8f13c25 100644 --- a/source/numem/mem/ptr.d +++ b/source/numem/core/memory/smartptr.d @@ -4,10 +4,11 @@ Authors: Luna Nielsen */ -module numem.mem.ptr; + +module numem.core.memory.smartptr; import core.atomic : atomicFetchAdd, atomicFetchSub, atomicStore, atomicLoad; import std.traits; -import numem.mem; +import numem.core; // // SMART POINTERS @@ -600,7 +601,7 @@ unittest { @("unique_ptr: move to array") unittest { - import numem.mem.vector; + import numem.collections.vector; struct A { int b; } vector!(unique_ptr!A) uniques; diff --git a/source/numem/core/package.d b/source/numem/core/package.d new file mode 100644 index 0000000..7d6798d --- /dev/null +++ b/source/numem/core/package.d @@ -0,0 +1,3 @@ +module numem.core; + +public import numem.core.memory; \ No newline at end of file diff --git a/source/numem/core/random.d b/source/numem/core/random.d new file mode 100644 index 0000000..2838e3f --- /dev/null +++ b/source/numem/core/random.d @@ -0,0 +1,247 @@ +module numem.core.random; +import numem.core; +import std.traits; + +/** + Base class of all random number generators +*/ +abstract +class RandomBase { +@nogc nothrow: + + /** + Resets the random number generator to its initial state. + */ + abstract void reset(); + + /** + Gets the next value in the random stream + */ + abstract size_t next(); + + /** + Gets the next value in the random stream + */ + abstract double nextUniform(); + + /** + Gets the next bytes in the random stream + */ + abstract void next(ref ubyte[] destination); +} + +/** + A psuedo-random number generator +*/ +class Random : RandomBase { +@nogc nothrow: +private: + + enum mtWordSize = (size_t.sizeof*8); + static if (mtWordSize == 32) { + enum mtRecurrence = 624; + enum mtMiddleWord = 397; + enum mtSeperationPoint = 31; + enum mtMagicNumber = 1_812_433_253; + enum mtTwistCoefficient = 0x9908B0DF; + + enum mtU = 11; + enum mtD = 0xFFFFFFFF; + enum mtS = 7; + enum mtB = 0x9D2C5680; + enum mtT = 15; + enum mtC = 0xEFC60000; + enum mtL = 18; + + } else { + enum mtRecurrence = 312; + enum mtMiddleWord = 156; + enum mtSeperationPoint = 31; + enum mtMagicNumber = 6_364_136_223_846_793_005; + enum mtTwistCoefficient = 0xB5026F5AA96619E9; + + enum mtU = 29; + enum mtD = 0x5555555555555555; + enum mtS = 17; + enum mtB = 0x71D67FFFEDA60000; + enum mtT = 37; + enum mtC = 0xFFF7EEE000000000; + enum mtL = 43; + } + + enum mtUpperMask = (size_t.max << mtSeperationPoint); + enum mtLowerMask = (size_t.max >> (mtWordSize-mtSeperationPoint)); + + + size_t[mtRecurrence] state; + size_t idx; + size_t seed; + + /// Resets the mersenne twister algorithm. + void initialize() { + state[0] = seed; + + // NOTE: Local seed iteration. + // This is to allow calling reset() + size_t nseed = seed; + foreach(i; 1..state.length) { + nseed = mtMagicNumber * (nseed ^ (nseed >> (mtWordSize-2))) + i; + state[i] = nseed; + } + + idx = 0; + } +public: + + /** + Constructs a random number generator with a set seed. + */ + this(size_t seed) { + this.seed = seed; + this.initialize(); + } + + /** + Constructs a random number generator with a set seed. + */ + override + void reset() { + this.initialize(); + } + + /** + Gets the next value in the random stream + */ + override + size_t next() { + + // Get current index and at the opposite end of the circular buffer. + ptrdiff_t k = idx; + ptrdiff_t j = k - (mtRecurrence-1); + if (j < 0) + j += mtRecurrence; + + size_t x = (state[k] & mtUpperMask) | (state[j] & mtLowerMask); + + + size_t xA = x >> 1; + if (x & 1) xA ^= mtTwistCoefficient; + + // Point to state recurrange - magic number + // modulo if need be. + j = k - (mtRecurrence-mtMiddleWord); + if (j < 0) + j += mtRecurrence; + + // Compute and set next state value + x = state[j] ^ xA; + state[k++] = x; + + // Wrap around + if (k >= mtRecurrence) + k = 0; + idx = k; + + // Tempering algorithm + size_t y = x ^ (x >> mtU); + y = y ^ ((y << mtS) & mtB); + y = y ^ ((y << mtT) & mtC); + + return y ^ (y >> 1); + } + + /** + Gets the next value in the random stream + */ + override + double nextUniform() { + size_t nrandom = this.next(); + return cast(double)nrandom/cast(double)size_t.max; + } + + /** + Gets the next bytes in the random stream + */ + override + void next(ref ubyte[] destination) { + + // State of random number generator + union tmp { + ubyte[size_t.sizeof] buffer; + size_t nrandom; + } + tmp _tmp; + + // Algorithm for filling buffer + size_t i = 0; + while (i < destination.length) { + _tmp.nrandom = next(); + + // Figre out how many bytes to copy over + size_t count = size_t.sizeof; + if (i+size_t.sizeof > destination.length) + count = (i+size_t.sizeof) - destination.length; + + // Write to destination + destination[i..i+count] = _tmp.buffer[0..count]; + i += count; + } + } +} + +@("Random") +unittest { + // Mersenne Twister is deterministic, so this should always give the same result + // (on 64-bit systems) + static if (size_t.sizeof == 8) { + const ubyte[128] verification = [ + 155, 16, 179, 137, 163, 208, 254, 167, 182, 56, 19, 183, 127, 46, + 4, 165, 24, 95, 218, 132, 62, 197, 42, 151, 145, 200, 45, 143, 88, + 166, 19, 52, 93, 142, 195, 160, 49, 12, 35, 123, 216, 164, 13, 106, + 204, 45, 231, 157, 109, 165, 89, 86, 236, 142, 4, 245, 84, 188, 235, + 162, 184, 89, 247, 17, 72, 92, 160, 219, 113, 83, 43, 44, 180, 191, + 109, 53, 245, 47, 125, 196, 234, 11, 19, 92, 185, 161, 167, 76, 114, + 113, 255, 64, 83, 191, 254, 194, 169, 61, 243, 22, 54, 232, 196, 110, + 82, 208, 110, 80, 6, 188, 68, 101, 60, 116, 47, 210, 79, 186, 138, 122, + 205, 191, 62, 59, 194, 137, 117, 5 + ]; + + ubyte[128] buffer; + ubyte[] dest = buffer[0..$]; + + Random random = nogc_new!Random(42); + random.next(dest); + + assert(dest == verification[0..$]); + } + + // Test skipped on 32 bit. +} + +@("Random (seed reset)") +unittest { + + ubyte[128] buffer1; + ubyte[] dest1 = buffer1[0..$]; + + ubyte[128] buffer2; + ubyte[] dest2 = buffer2[0..$]; + + Random random = nogc_new!Random(42); + + // These should not match + random.next(dest1); + random.next(dest2); + assert(dest1 != dest2, "Randomness is diminished?"); + + + // These should not match + random.reset(); + random.next(dest1); + random.reset(); + random.next(dest2); + + assert(dest1 == dest2, "Randomness is not deterministic?"); +} + +// TODO: optional crypto rng? \ No newline at end of file diff --git a/source/numem/mem/internal/trace.d b/source/numem/core/trace.d similarity index 96% rename from source/numem/mem/internal/trace.d rename to source/numem/core/trace.d index 2b2776c..cd88f22 100644 --- a/source/numem/mem/internal/trace.d +++ b/source/numem/core/trace.d @@ -8,7 +8,7 @@ /** Debug tracing module */ -module numem.mem.internal.trace; +module numem.core.trace; import core.stdc.stdio; pragma(inline, true) diff --git a/source/numem/mem/utils.d b/source/numem/core/utils.d similarity index 81% rename from source/numem/mem/utils.d rename to source/numem/core/utils.d index ea43712..de498c5 100644 --- a/source/numem/mem/utils.d +++ b/source/numem/core/utils.d @@ -1,8 +1,12 @@ -module numem.mem.utils; -import std.traits; +/* + Copyright © 2024, Inochi2D Project + Distributed under the 2-Clause BSD License, see LICENSE file. + + Authors: Luna the Foxgirl +*/ -// Based on code from dplug:core -// which is released under the Boost license. +module numem.core.utils; +import std.traits; /** Forces a function to assume that it's nogc compatible. diff --git a/source/numem/core/uuid.d b/source/numem/core/uuid.d new file mode 100644 index 0000000..9c02903 --- /dev/null +++ b/source/numem/core/uuid.d @@ -0,0 +1,154 @@ +/* + Copyright © 2024, Inochi2D Project + Distributed under the 2-Clause BSD License, see LICENSE file. + + Authors: Luna the Foxgirl +*/ + +/** + RFC4122 compliant UUIDs +*/ +module numem.core.uuid; +import numem.string; +import numem.io.endian; + +enum UUIDVariant { + invalid, + ncs, + rfc4122, + microsoft, + reserved +} + +/** + RFC4122 compliant UUIDs +*/ +struct UUID { +@nogc nothrow: +private: + enum VERSION_BITMASK = 0b11110000; + enum VARIANT_BITMASK = 0b11100000; + + union { + struct { + uint time_low; + ushort time_mid; + ushort time_hi_and_version; + ubyte clk_seq_hi_reserved; + ubyte clk_seq_low; + ubyte[6] node; + } + ubyte[16] data; + ulong[2] ldata; + } + + this(ulong[2] data) inout { + this.ldata = data; + } + +public: + this(ubyte[16] bytes) { + this.data = bytes; + this.time_low = ntoh(this.time_low); + this.time_mid = ntoh(this.time_mid); + this.time_hi_and_version = ntoh(this.time_hi_and_version); + } + + this(string str) { + this(nstring(str)); + } + + this(nstring str) { + + } + + /** + Special "nil" UUID + */ + static UUID nil() { + UUID uuid; + return uuid; + } + + /** + Special "max" UUID + */ + static UUID max() { + UUID uuid; + uuid.ldata[0] = ulong.max; + uuid.ldata[1] = ulong.max; + return uuid; + } + + /** + Creates a new UUID + */ + static UUID createRandom() { + UUID uuid; + uuid.clk_seq_hi_reserved = 0;//ntoh(uuid.data.clk_seq_hi_reserved); + + return uuid; + } + + /** + Gets the version of the UUID structure + */ + int getVersion() { + return cast(int)(time_hi_and_version | VERSION_BITMASK); + } + + /** + Gets the variant of the UUID structure + */ + UUIDVariant getVariant() { + return cast(UUIDVariant)(clk_seq_hi_reserved | VARIANT_BITMASK); + } + + /** + Returns byte stream from UUID with data in network order. + */ + ubyte[16] toBytes() { + UUID datacopy; + datacopy.data[0..$] = data[0..$]; + + datacopy.time_low = ntoh(this.time_low); + datacopy.time_mid = ntoh(this.time_mid); + datacopy.time_hi_and_version = ntoh(this.time_hi_and_version); + return datacopy.data; + } + + + /** + Checks equality between 2 UUIDs. + */ + bool opEquals(const UUID other) const { + return this.ldata[0] == other.ldata[0] && this.ldata[1] == other.ldata[1]; + } + + /** + Compares 2 UUIDs lexically. + + Lexical order is NOT temporal! + */ + int opCmp(const UUID other) const { + + // First check things which are endian dependent. + if (this.time_low != other.time_low) + return this.time_low < other.time_low; + + if (this.time_mid != other.time_mid) + return this.time_mid < other.time_mid; + + if (this.time_hi_and_version != other.time_hi_and_version) + return this.time_hi_and_version < other.time_hi_and_version; + + // Then check all the nodes + static foreach(i; 0..6) { + if (this.node[i] < other.node[i]) return -1; + if (this.node[i] > other.node[i]) return 1; + } + + // They're the same. + return 0; + } +} \ No newline at end of file diff --git a/source/numem/io/endian.d b/source/numem/io/endian.d index eb2bc94..8b33564 100644 --- a/source/numem/io/endian.d +++ b/source/numem/io/endian.d @@ -5,9 +5,9 @@ Authors: Luna Nielsen */ module numem.io.endian; -import numem.mem; -import numem.mem.vector; -import std.traits : isNumeric; +import numem.core; +import numem.collections.vector; +import std.traits : isNumeric, isIntegral; @nogc nothrow: @@ -129,4 +129,23 @@ unittest { assert(vec[0..4] == cast(ubyte[])[4, 3, 2, 1], "Endianness swap failed!"); nogc_delete(vec); +} + +/** + Converts values from network order to host order + + Calling this on a converted value flips the operation. +*/ +T ntoh(T)(T in_) if (isIntegral!T && T.sizeof > 1) { + static if (NATIVE_ENDIAN == Endianess.bigEndian) return in_; + else { + union tmp { + T value; + ubyte[T.sizeof] bytes; + } + + tmp toConvert; + toConvert.value = in_; + return fromEndian!(T)(toConvert.bytes, Endianess.bigEndian); + } } \ No newline at end of file diff --git a/source/numem/io/file.d b/source/numem/io/file.d index 921f11f..35deefb 100644 --- a/source/numem/io/file.d +++ b/source/numem/io/file.d @@ -5,9 +5,9 @@ Authors: Luna Nielsen */ module numem.io.file; -import numem.mem.string; -import numem.mem; -import numem.mem.ptr; +import numem.string; +import numem.core; +import numem.core.memory; import numem.io.stream.filestream; import c = core.stdc.stdio; diff --git a/source/numem/io/stdio.d b/source/numem/io/stdio.d index 1a7bed7..fa3b557 100644 --- a/source/numem/io/stdio.d +++ b/source/numem/io/stdio.d @@ -7,7 +7,7 @@ version(NoC) { // If there's no C this should be disabled. } else { - import numem.mem.string; + import numem.string; import numem.conv; import core.stdc.stdio : printf, puts; diff --git a/source/numem/io/stream/filestream.d b/source/numem/io/stream/filestream.d index 6a62778..29bf952 100644 --- a/source/numem/io/stream/filestream.d +++ b/source/numem/io/stream/filestream.d @@ -1,12 +1,13 @@ /* Copyright © 2024, Inochi2D Project Distributed under the 2-Clause BSD License, see LICENSE file. - - Authors: Luna Nielsen + + Authors: Luna the Foxgirl */ + module numem.io.stream.filestream; import numem.io.stream; -import numem.mem.vector; +import numem.collections.vector; import core.stdc.stdio; diff --git a/source/numem/io/stream/memstream.d b/source/numem/io/stream/memstream.d index ab49488..6f312a9 100644 --- a/source/numem/io/stream/memstream.d +++ b/source/numem/io/stream/memstream.d @@ -1,12 +1,13 @@ /* Copyright © 2024, Inochi2D Project Distributed under the 2-Clause BSD License, see LICENSE file. - - Authors: Luna Nielsen + + Authors: Luna the Foxgirl */ + module numem.io.stream.memstream; import numem.io.stream; -import numem.mem.vector; +import numem.collections.vector; /** A memory stream. diff --git a/source/numem/io/stream/package.d b/source/numem/io/stream/package.d index 13bf991..cb54dbd 100644 --- a/source/numem/io/stream/package.d +++ b/source/numem/io/stream/package.d @@ -1,11 +1,12 @@ /* - Copyright © 2023, Inochi2D Project + Copyright © 2024, Inochi2D Project Distributed under the 2-Clause BSD License, see LICENSE file. - - Authors: Luna Nielsen + + Authors: Luna the Foxgirl */ + module numem.io.stream; -import numem.mem.vector; +import numem.collections.vector; import core.stdc.stdio : SEEK_CUR, SEEK_END, SEEK_SET; public import numem.io.stream.filestream; diff --git a/source/numem/io/stream/reader.d b/source/numem/io/stream/reader.d index 8357c8b..e4447c1 100644 --- a/source/numem/io/stream/reader.d +++ b/source/numem/io/stream/reader.d @@ -1,14 +1,15 @@ /* Copyright © 2024, Inochi2D Project Distributed under the 2-Clause BSD License, see LICENSE file. - - Authors: Luna Nielsen + + Authors: Luna the Foxgirl */ + module numem.io.stream.reader; import numem.io.stream; import numem.io.endian; -import numem.mem.string; -import numem.mem.vector; +import numem.string; +import numem.collections.vector; import std.traits; /** diff --git a/source/numem/io/stream/writer.d b/source/numem/io/stream/writer.d index 5872c11..85894dd 100644 --- a/source/numem/io/stream/writer.d +++ b/source/numem/io/stream/writer.d @@ -1,14 +1,15 @@ /* Copyright © 2024, Inochi2D Project Distributed under the 2-Clause BSD License, see LICENSE file. - - Authors: Luna Nielsen + + Authors: Luna the Foxgirl */ + module numem.io.stream.writer; import numem.io.stream; import numem.io.endian; -import numem.mem.string; -import numem.mem.vector; +import numem.string; +import numem.collections.vector; import std.traits; /** diff --git a/source/numem/mem.d b/source/numem/mem.d new file mode 100644 index 0000000..c79df8b --- /dev/null +++ b/source/numem/mem.d @@ -0,0 +1,11 @@ +/* + Copyright © 2024, Inochi2D Project + Distributed under the 2-Clause BSD License, see LICENSE file. + + Authors: Luna the Foxgirl +*/ + +deprecated("This module has been moved to numem.core") +module numem.mem; + +public import numem.core; \ No newline at end of file diff --git a/source/numem/mem/internal/package.d b/source/numem/mem/internal/package.d deleted file mode 100644 index d10dcbd..0000000 --- a/source/numem/mem/internal/package.d +++ /dev/null @@ -1,26 +0,0 @@ -/* - Copyright © 2023, Inochi2D Project - Distributed under the 2-Clause BSD License, see LICENSE file. - - Authors: Luna Nielsen -*/ -module numem.mem.internal; - -const(T)[] fromStringz(T)(return scope const(T)* cString) @nogc @system pure nothrow { - import core.stdc.string: strlen; - - static if (is(T == char)) - import core.stdc.string : cstrlen = strlen; - else static if (is(T == wchar) || is(T == dchar)) { - static size_t cstrlen(scope const T* s) { - const(T)* p = s; - while (*p) - ++p; - return p - s; - } - } - else - static assert(0); - - return cString ? cString[0 .. cstrlen(cString)] : null; -} \ No newline at end of file diff --git a/source/numem/mem/string.d b/source/numem/string.d similarity index 83% rename from source/numem/mem/string.d rename to source/numem/string.d index a386c7a..44a4cb9 100644 --- a/source/numem/mem/string.d +++ b/source/numem/string.d @@ -4,15 +4,27 @@ Authors: Luna Nielsen */ -module numem.mem.string; -import numem.mem.vector; -import numem.mem.internal; -import numem.mem; +module numem.string; +import numem.collections.vector; +import numem.core; +import std.string; /// Gets whether the provided type is some type of nstring. enum isSomeNString(T) = is(T == nstring) || is (T == nwstring) || is(T == ndstring); +/// Gets whether the provided type is some type of null terminated C string. +enum isSomeCString(T) = + is(T : inout(char)*) || is(T : inout(wchar)*)|| is(T : inout(dchar)*); + +/// Gets whether the provided type is some type of D string slice. +enum isSomeDString(T) = + is(T : inout(char)[]) || is(T : inout(wchar)[])|| is(T : inout(dchar)[]); + +/// Gets whether the provided type is a character +enum isSomeChar(T) = + is(T == char) || is(T == wchar) || is(T == dchar); + /** Basic string type. @@ -56,6 +68,16 @@ public: } } + /** + Creates a string from a C string + + This is considered unsafe. + */ + @system + this(inout(T)* text) { + this.set_(text.fromStringz()); + } + /** Creates a string with specified text */ @@ -64,23 +86,6 @@ public: this.set_(text); } - // Handle creation from C string - version(NoC) { } - else { - static if (is(T == char)) { - - /** - Creates a string with specified text - */ - @system - this(ref const(char)* text) { - import core.stdc.string : strlen; - size_t len = strlen(text); - this.set_(text[0..len]); - } - } - } - /** Makes a copy of a string */ @@ -259,18 +264,7 @@ public: */ @system ref auto opOpAssign(string op = "~")(const(T)* cString) { - return this.appendCString(cString); - } - - /** - Appends a zero-terminated C string to string - */ - @system - ref auto appendCString(const(T)* cString) { - const(T)[] s = numem.mem.internal.fromStringz(cString); - if (s != null) - this.append_(s); - return this; + return this.opOpAssign(cString.fromStringz()); } /** @@ -372,24 +366,28 @@ unittest { @("nstring: append") unittest { + const(char)* cstr1 = "a zero-terminated string"; + const(wchar)* cstr2 = "hey"; + const(dchar)* cstr3 = "ho"; + nstring s; s ~= cast(string)null; s ~= ""; - s.appendCString("a zero-terminated string".ptr); + s ~= cstr1; assert(s.toDString() == "a zero-terminated string"); nwstring ws; - ws.appendCString("hey"w.ptr); + ws ~= cstr2; assert(ws.length == 3); ndstring wd; - wd.appendCString("ho"d.ptr); + wd ~= cstr3; assert(wd.toDString() == "ho"d); } @("nstring: string in map") unittest { - import numem.mem.map : map; + import numem.collections.map : map; map!(nstring, int) kv; kv[nstring("uwu")] = 42; @@ -414,4 +412,37 @@ unittest { str.clear(); assert(str.empty); assert(str.realLength == 1 && str[0] == '\0'); +} + +// +// C and D string handling utilities +// + +@nogc pure nothrow { + + /** + Gets a slice from a C string + */ + inout(T)[] fromStringz(T)(inout(T)* cString) if (isSomeChar!T) { + return cString ? cString[0 .. cstrlen!T(cString)] : null; + } + + /** + Gets the length of a C-style string + */ + size_t cstrlen(T)(inout(T)* s) if (isSomeChar!T) { + const(T)* p = s; + while (*p) + ++p; + + return p - s; + } +} + +@("string: cstrlen") +unittest { + const(char)* cstr1 = "A"; + const(char)* cstr2 = "ABCD"; + assert(cstrlen(cstr1) == 1); + assert(cstrlen(cstr2) == 4); } \ No newline at end of file diff --git a/source/numem/text/ascii.d b/source/numem/text/ascii.d new file mode 100644 index 0000000..b5ff931 --- /dev/null +++ b/source/numem/text/ascii.d @@ -0,0 +1,63 @@ +/* + Copyright © 2024, Inochi2D Project + Distributed under the 2-Clause BSD License, see LICENSE file. + + Authors: Luna the Foxgirl +*/ + +/** + Numem ascii utility functions +*/ +module numem.text.ascii; + +/** + Gets whether the character is ascii +*/ +bool isASCII(char c) { + return c < 128; +} + +/** + Gets whether the character is a hexidedcimal digit +*/ +bool isHex(char c) { + return + (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F') || + (c >= '0' && c <= '9'); +} + +/** + Gets whether the character is alphabetic. +*/ +bool isAlpha(char c) { + return + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z'); +} + +/** + Gets whether the character is alphabetic. +*/ +bool isAlphaNumeric(char c) { + return + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9'); +} + +/** + Gets whether the character is printable +*/ +bool isPrintable(char c) { + return (c >= 32 && c < 126); +} + +/** + Gets whether the character is an ASCII non-printable escape character +*/ +bool isEscapeCharacter(char c) { + return + (c >= 0 && c <= 31) || + (c == 127); +} \ No newline at end of file diff --git a/source/numem/text/package.d b/source/numem/text/package.d new file mode 100644 index 0000000..a7bf380 --- /dev/null +++ b/source/numem/text/package.d @@ -0,0 +1,11 @@ +/* + Copyright © 2024, Inochi2D Project + Distributed under the 2-Clause BSD License, see LICENSE file. + + Authors: Luna the Foxgirl +*/ + +/** + Numem text transformation utilities +*/ +module numem.text; \ No newline at end of file diff --git a/source/numem/unicode/package.d b/source/numem/text/unicode/package.d similarity index 85% rename from source/numem/unicode/package.d rename to source/numem/text/unicode/package.d index 3e09e82..96f9b48 100644 --- a/source/numem/unicode/package.d +++ b/source/numem/text/unicode/package.d @@ -1,5 +1,12 @@ +/* + Copyright © 2024, Inochi2D Project + Distributed under the 2-Clause BSD License, see LICENSE file. + + Authors: Luna the Foxgirl +*/ + module numem.unicode; -import numem.mem.vector; +import numem.collections.vector; @nogc nothrow: diff --git a/source/numem/unicode/utf16.d b/source/numem/text/unicode/utf16.d similarity index 95% rename from source/numem/unicode/utf16.d rename to source/numem/text/unicode/utf16.d index 22ed84b..0740545 100644 --- a/source/numem/unicode/utf16.d +++ b/source/numem/text/unicode/utf16.d @@ -1,7 +1,14 @@ +/* + Copyright © 2024, Inochi2D Project + Distributed under the 2-Clause BSD License, see LICENSE file. + + Authors: Luna the Foxgirl +*/ + module numem.unicode.utf16; import numem.unicode; -import numem.mem.string; -import numem.mem.vector; +import numem.collections.vector; +import numem.string; nothrow @nogc: diff --git a/source/numem/unicode/utf8.d b/source/numem/text/unicode/utf8.d similarity index 98% rename from source/numem/unicode/utf8.d rename to source/numem/text/unicode/utf8.d index 24d477c..fadc298 100644 --- a/source/numem/unicode/utf8.d +++ b/source/numem/text/unicode/utf8.d @@ -1,7 +1,14 @@ +/* + Copyright © 2024, Inochi2D Project + Distributed under the 2-Clause BSD License, see LICENSE file. + + Authors: Luna the Foxgirl +*/ + module numem.unicode.utf8; import numem.unicode; -import numem.mem.string; -import numem.mem.vector; +import numem.collections.vector; +import numem.string; // For some reason D really wants this import. import numem.unicode : validate;