diff --git a/meta/tanya/meta/metafunction.d b/meta/tanya/meta/metafunction.d index eaa5111..eeb0d56 100644 --- a/meta/tanya/meta/metafunction.d +++ b/meta/tanya/meta/metafunction.d @@ -9,7 +9,7 @@ * It contains different algorithms for iterating, searching and modifying * template arguments. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) @@ -34,7 +34,7 @@ import tanya.meta.transform; * $(D_INLINECODE Args[0] < Args[1]), a positive number that * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) * ) - * + * * Params: * pred = Template predicate. * Args = Elements for which you want to find the minimum value. @@ -81,7 +81,7 @@ if (Args.length > 0 && __traits(isTemplate, pred)) * $(D_INLINECODE Args[0] < Args[1]), a positive number that * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) * ) - * + * * Params: * pred = Template predicate. * Args = Elements for which you want to find the maximum value. @@ -792,7 +792,7 @@ alias AliasSeq(Args...) = Args; * so $(D_INLINECODE F!([0]) && F!([1])) and so on, can be called. * * Params: - * F = Template predicate. + * F = Template predicate. * L = List of items to test. * * Returns: $(D_KEYWORD true) if all the items of $(D_PARAM L) satisfy @@ -815,7 +815,7 @@ enum bool allSatisfy(alias F, L...) = Filter!(templateNot!F, L).length == 0; * so $(D_INLINECODE F!([0]) && F!([1])) and so on, can be called. * * Params: - * F = Template predicate. + * F = Template predicate. * L = List of items to test. * * Returns: $(D_KEYWORD true) if any of the items of $(D_PARAM L) satisfy diff --git a/meta/tanya/meta/package.d b/meta/tanya/meta/package.d index 377626d..d962b12 100644 --- a/meta/tanya/meta/package.d +++ b/meta/tanya/meta/package.d @@ -9,7 +9,7 @@ * to transform from one type to another. It has also different algorithms for * iterating, searching and modifying template arguments. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/meta/tanya/meta/trait.d b/meta/tanya/meta/trait.d index 2d81a9e..b91d673 100644 --- a/meta/tanya/meta/trait.d +++ b/meta/tanya/meta/trait.d @@ -8,7 +8,7 @@ * Templates in this module are used to obtain type information at compile * time. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/meta/tanya/meta/transform.d b/meta/tanya/meta/transform.d index 08b1b34..2bef67f 100644 --- a/meta/tanya/meta/transform.d +++ b/meta/tanya/meta/transform.d @@ -9,7 +9,7 @@ * types. They take some type as argument and return a different type after * perfoming the specified transformation. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/middle/middle-test-library b/middle/middle-test-library deleted file mode 100755 index b8c40ab..0000000 Binary files a/middle/middle-test-library and /dev/null differ diff --git a/middle/tanya/memory/allocator.d b/middle/tanya/memory/allocator.d index 064ab37..188eff9 100644 --- a/middle/tanya/memory/allocator.d +++ b/middle/tanya/memory/allocator.d @@ -6,9 +6,9 @@ * This module contains the interface for implementing custom allocators. * * Allocators are classes encapsulating memory allocation strategy. This allows - * to decouple memory management from the algorithms and the data. + * to decouple memory management from the algorithms and the data. * - * Copyright: Eugene Wissner 2016-2020. + * Copyright: Eugene Wissner 2016-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/middle/tanya/memory/lifetime.d b/middle/tanya/memory/lifetime.d index 8a8cfe9..606086f 100644 --- a/middle/tanya/memory/lifetime.d +++ b/middle/tanya/memory/lifetime.d @@ -5,7 +5,7 @@ /** * Lifetime management functions, types and related exceptions. * - * Copyright: Eugene Wissner 2019-2020. + * Copyright: Eugene Wissner 2019-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/middle/tanya/memory/mallocator.d b/middle/tanya/memory/mallocator.d index 69a2876..49eb424 100644 --- a/middle/tanya/memory/mallocator.d +++ b/middle/tanya/memory/mallocator.d @@ -6,7 +6,7 @@ * Allocator based on $(D_PSYMBOL malloc), $(D_PSYMBOL realloc) and * $(D_PSYMBOL free). * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/middle/tanya/memory/mmappool.d b/middle/tanya/memory/mmappool.d index 3ce49d5..1986c97 100644 --- a/middle/tanya/memory/mmappool.d +++ b/middle/tanya/memory/mmappool.d @@ -5,7 +5,7 @@ /* * Native allocator. * - * Copyright: Eugene Wissner 2016-2020. + * Copyright: Eugene Wissner 2016-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/middle/tanya/memory/op.d b/middle/tanya/memory/op.d index a41149b..a266140 100644 --- a/middle/tanya/memory/op.d +++ b/middle/tanya/memory/op.d @@ -1,11 +1,11 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public +/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** * Set of operations on memory blocks. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/middle/tanya/memory/package.d b/middle/tanya/memory/package.d index 61e98d2..e3c20d6 100644 --- a/middle/tanya/memory/package.d +++ b/middle/tanya/memory/package.d @@ -5,7 +5,7 @@ /** * Dynamic memory management. * - * Copyright: Eugene Wissner 2016-2020. + * Copyright: Eugene Wissner 2016-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/middle/tanya/memory/smartref.d b/middle/tanya/memory/smartref.d index b6ec374..01a90e1 100644 --- a/middle/tanya/memory/smartref.d +++ b/middle/tanya/memory/smartref.d @@ -14,7 +14,7 @@ * $(LI Unique ownership) * ) * - * Copyright: Eugene Wissner 2016-2020. + * Copyright: Eugene Wissner 2016-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/os/tanya/os/error.d b/os/tanya/os/error.d index b271517..3268a8a 100644 --- a/os/tanya/os/error.d +++ b/os/tanya/os/error.d @@ -5,7 +5,7 @@ /** * This module provides a portable way of using operating system error codes. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/os/tanya/os/package.d b/os/tanya/os/package.d index 399e975..9b81c18 100644 --- a/os/tanya/os/package.d +++ b/os/tanya/os/package.d @@ -6,7 +6,7 @@ * This package provides platform-independent interfaces to operating system * functionality. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/algorithm/iteration.d b/source/tanya/algorithm/iteration.d index 5efc676..469699c 100644 --- a/source/tanya/algorithm/iteration.d +++ b/source/tanya/algorithm/iteration.d @@ -11,7 +11,7 @@ * All algorithms in this module are lazy, they request the next element of the * original range on demand. * - * Copyright: Eugene Wissner 2018-2021. + * Copyright: Eugene Wissner 2018-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/algorithm/mutation.d b/source/tanya/algorithm/mutation.d index 6a6edd6..da5ed96 100644 --- a/source/tanya/algorithm/mutation.d +++ b/source/tanya/algorithm/mutation.d @@ -5,7 +5,7 @@ /** * Algorithms that modify its arguments. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/algorithm/package.d b/source/tanya/algorithm/package.d index 90e9a8a..b15564d 100644 --- a/source/tanya/algorithm/package.d +++ b/source/tanya/algorithm/package.d @@ -5,7 +5,7 @@ /** * Collection of generic algorithms. * - * Copyright: Eugene Wissner 2017-2021. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/container/array.d b/source/tanya/container/array.d index f5aabcf..7027641 100644 --- a/source/tanya/container/array.d +++ b/source/tanya/container/array.d @@ -5,7 +5,7 @@ /** * Single-dimensioned array. * - * Copyright: Eugene Wissner 2016-2021. + * Copyright: Eugene Wissner 2016-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/container/buffer.d b/source/tanya/container/buffer.d index 6c8a1e2..35d83a5 100644 --- a/source/tanya/container/buffer.d +++ b/source/tanya/container/buffer.d @@ -1,681 +1,681 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * This module contains buffers designed for C-style input/output APIs. - * - * Copyright: Eugene Wissner 2016-2020. - * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, - * Mozilla Public License, v. 2.0). - * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) - * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/container/buffer.d, - * tanya/container/buffer.d) - */ -module tanya.container.buffer; - -import std.traits : isScalarType; -import tanya.memory.allocator; -import tanya.meta.trait; - -version (unittest) -{ - private int fillBuffer(ubyte[] buffer, - int start = 0, - int end = 10) @nogc pure nothrow - in - { - assert(start < end); - } - do - { - auto numberRead = end - start; - for (ubyte i; i < numberRead; ++i) - { - buffer[i] = cast(ubyte) (start + i); - } - return numberRead; - } -} - -/** - * Self-expanding buffer, that can be used with functions returning the number - * of the read bytes. - * - * This buffer supports asynchronous reading. It means you can pass a new chunk - * to an asynchronous read function during you are working with already - * available data. But only one asynchronous call at a time is supported. Be - * sure to call $(D_PSYMBOL ReadBuffer.clear()) before you append the result - * of the pended asynchronous call. - * - * Params: - * T = Buffer type. - */ -struct ReadBuffer(T = ubyte) -if (isScalarType!T) -{ - /// Internal buffer. - private T[] buffer_; - - /// Filled buffer length. - private size_t length_; - - /// Start of available data. - private size_t start; - - /// Last position returned with $(D_KEYWORD []). - private size_t ring; - - /// Available space. - private size_t minAvailable = 1024; - - /// Size by which the buffer will grow. - private size_t blockSize = 8192; - - invariant - { - assert(this.length_ <= this.buffer_.length); - assert(this.blockSize > 0); - assert(this.minAvailable > 0); - } - - /** - * Creates a new read buffer. - * - * Params: - * size = Initial buffer size and the size by which the buffer - * will grow. - * minAvailable = minimal size should be always available to fill. - * So it will reallocate if $(D_INLINECODE - * $(D_PSYMBOL free) < $(D_PARAM minAvailable)). - * allocator = Allocator. - */ - this(size_t size, - size_t minAvailable = 1024, - shared Allocator allocator = defaultAllocator) @trusted - { - this(allocator); - this.minAvailable = minAvailable; - this.blockSize = size; - this.buffer_ = cast(T[]) allocator_.allocate(size * T.sizeof); - } - - /// ditto - this(shared Allocator allocator) - in - { - assert(allocator_ is null); - } - do - { - allocator_ = allocator; - } - - /** - * Deallocates the internal buffer. - */ - ~this() @trusted - { - allocator.deallocate(this.buffer_); - } - - /// - @nogc nothrow pure @safe unittest - { - ReadBuffer!ubyte b; - assert(b.capacity == 0); - assert(b.length == 0); - } - - /** - * Returns: The size of the internal buffer. - */ - @property size_t capacity() const - { - return this.buffer_.length; - } - - /** - * Returns: Data size. - */ - @property size_t length() const - { - return this.length_ - start; - } - - /// ditto - alias opDollar = length; - - /** - * Clears the buffer. - * - * Returns: $(D_KEYWORD this). - */ - void clear() - { - start = this.length_ = ring; - } - - /** - * Returns: Available space. - */ - @property size_t free() const - { - return length > ring ? capacity - length : capacity - ring; - } - - /// - @nogc nothrow pure @system unittest - { - ReadBuffer!ubyte b; - size_t numberRead; - - assert(b.free == 0); - - // Fills the buffer with values 0..10 - numberRead = fillBuffer(b[], 0, 10); - b += numberRead; - assert(b.free == b.blockSize - numberRead); - b.clear(); - assert(b.free == b.blockSize); - } - - /** - * Appends some data to the buffer. - * - * Params: - * length = Number of the bytes read. - * - * Returns: $(D_KEYWORD this). - */ - ref ReadBuffer opOpAssign(string op)(size_t length) - if (op == "+") - { - this.length_ += length; - ring = start; - return this; - } - - /// - @nogc nothrow pure @system unittest - { - ReadBuffer!ubyte b; - size_t numberRead; - ubyte[] result; - - // Fills the buffer with values 0..10 - numberRead = fillBuffer(b[], 0, 10); - b += numberRead; - - result = b[0 .. $]; - assert(result[0] == 0); - assert(result[1] == 1); - assert(result[9] == 9); - b.clear(); - - // It shouldn't overwrite, but append another 5 bytes to the buffer - numberRead = fillBuffer(b[], 0, 10); - b += numberRead; - - numberRead = fillBuffer(b[], 20, 25); - b += numberRead; - - result = b[0..$]; - assert(result[0] == 0); - assert(result[1] == 1); - assert(result[9] == 9); - assert(result[10] == 20); - assert(result[14] == 24); - } - - /** - * Params: - * start = Start position. - * end = End position. - * - * Returns: Array between $(D_PARAM start) and $(D_PARAM end). - */ - T[] opSlice(size_t start, size_t end) - { - return this.buffer_[this.start + start .. this.start + end]; - } - - /** - * Returns a free chunk of the buffer. - * - * Add ($(D_KEYWORD +=)) the number of the read bytes after using it. - * - * Returns: A free chunk of the buffer. - */ - T[] opIndex() - { - if (start > 0) - { - auto ret = this.buffer_[0 .. start]; - ring = 0; - return ret; - } - else - { - if (capacity - length < this.minAvailable) - { - void[] buf = this.buffer_; - const cap = capacity; - () @trusted { - allocator.reallocate(buf, - (cap + this.blockSize) * T.sizeof); - this.buffer_ = cast(T[]) buf; - }(); - } - ring = this.length_; - return this.buffer_[this.length_ .. $]; - } - } - - /// - @nogc nothrow pure @system unittest - { - ReadBuffer!ubyte b; - size_t numberRead; - ubyte[] result; - - // Fills the buffer with values 0..10 - numberRead = fillBuffer(b[], 0, 10); - b += numberRead; - - assert(b.length == 10); - result = b[0 .. $]; - assert(result[0] == 0); - assert(result[9] == 9); - b.clear(); - assert(b.length == 0); - } - - mixin DefaultAllocator; -} - -/** - * Circular, self-expanding buffer with overflow support. Can be used with - * functions returning the number of the transferred bytes. - * - * The buffer is optimized for situations where you read all the data from it - * at once (without writing to it occasionally). It can become ineffective if - * you permanently keep some data in the buffer and alternate writing and - * reading, because it may allocate and move elements. - * - * Params: - * T = Buffer type. - */ -struct WriteBuffer(T = ubyte) -if (isScalarType!T) -{ - /// Internal buffer. - private T[] buffer_; - - /// Buffer start position. - private size_t start; - - /// Buffer ring area size. After this position begins buffer overflow area. - private size_t ring; - - /// Size by which the buffer will grow. - private const size_t blockSize; - - /// The position of the free area in the buffer. - private size_t position; - - invariant - { - assert(this.blockSize > 0); - // Position can refer to an element outside the buffer if the buffer is - // full. - assert(this.position <= this.buffer_.length); - } - - /** - * Params: - * size = Initial buffer size and the size by which the buffer will - * grow. - * allocator = Allocator. - * - * Precondition: $(D_INLINECODE size > 0 && allocator !is null) - */ - this(size_t size, shared Allocator allocator = defaultAllocator) @trusted - in - { - assert(size > 0); - assert(allocator !is null); - } - do - { - this.blockSize = size; - ring = size - 1; - allocator_ = allocator; - this.buffer_ = cast(T[]) allocator_.allocate(size * T.sizeof); - } - - @disable this(); - - /** - * Deallocates the internal buffer. - */ - ~this() - { - allocator.deallocate(this.buffer_); - } - - /** - * Returns: The size of the internal buffer. - */ - @property size_t capacity() const - { - return this.buffer_.length; - } - - /** - * Note that $(D_PSYMBOL length) doesn't return the real length of the data, - * but only the array length that will be returned with $(D_PSYMBOL opIndex) - * next time. Be sure to call $(D_PSYMBOL opIndex) and set $(D_KEYWORD +=) - * until $(D_PSYMBOL length) returns 0. - * - * Returns: Data size. - */ - @property size_t length() const - { - if (this.position > ring || this.position < start) // Buffer overflowed - { - return ring - start + 1; - } - else - { - return this.position - start; - } - } - - /// ditto - alias opDollar = length; - - /// - @nogc nothrow pure @system unittest - { - auto b = WriteBuffer!ubyte(4); - ubyte[3] buf = [48, 23, 255]; - - b ~= buf; - assert(b.length == 3); - b += 2; - assert(b.length == 1); - - b ~= buf; - assert(b.length == 2); - b += 2; - assert(b.length == 2); - - b ~= buf; - assert(b.length == 5); - b += b.length; - assert(b.length == 0); - } - - /** - * Returns: Available space. - */ - @property size_t free() const - { - return capacity - length; - } - - /** - * Appends data to the buffer. - * - * Params: - * buffer = Buffer chunk got with $(D_PSYMBOL opIndex). - */ - ref WriteBuffer opOpAssign(string op)(const T[] buffer) - if (op == "~") - { - size_t end, start; - - if (this.position >= this.start && this.position <= ring) - { - auto afterRing = ring + 1; - - end = this.position + buffer.length; - if (end > afterRing) - { - end = afterRing; - } - start = end - this.position; - this.buffer_[this.position .. end] = buffer[0 .. start]; - if (end == afterRing) - { - this.position = this.start == 0 ? afterRing : 0; - } - else - { - this.position = end; - } - } - - // Check if we have some free space at the beginning - if (start < buffer.length && this.position < this.start) - { - end = this.position + buffer.length - start; - if (end > this.start) - { - end = this.start; - } - auto areaEnd = end - this.position + start; - this.buffer_[this.position .. end] = buffer[start .. areaEnd]; - this.position = end == this.start ? ring + 1 : end - this.position; - start = areaEnd; - } - - // And if we still haven't found any place, save the rest in the overflow area - if (start < buffer.length) - { - end = this.position + buffer.length - start; - if (end > capacity) - { - const newSize = end / this.blockSize * this.blockSize - + this.blockSize; - () @trusted { - void[] buf = this.buffer_; - allocator.reallocate(buf, newSize * T.sizeof); - this.buffer_ = cast(T[]) buf; - }(); - } - this.buffer_[this.position .. end] = buffer[start .. $]; - this.position = end; - if (this.start == 0) - { - ring = capacity - 1; - } - } - - return this; - } - - /** - * Sets how many bytes were written. It will shrink the buffer - * appropriately. Always call it after $(D_PSYMBOL opIndex). - * - * Params: - * length = Length of the written data. - * - * Returns: $(D_KEYWORD this). - */ - ref WriteBuffer opOpAssign(string op)(size_t length) - if (op == "+") - in - { - assert(length <= this.length); - } - do - { - auto afterRing = ring + 1; - auto oldStart = start; - - if (length <= 0) - { - return this; - } - else if (this.position <= afterRing) - { - start += length; - if (start > 0 && this.position == afterRing) - { - this.position = oldStart; - } - } - else - { - auto overflow = this.position - afterRing; - - if (overflow > length) - { - const afterLength = afterRing + length; - this.buffer_[start .. start + length] = this.buffer_[afterRing .. afterLength]; - this.buffer_[afterRing .. afterLength] = this.buffer_[afterLength .. this.position]; - this.position -= length; - } - else if (overflow == length) - { - this.buffer_[start .. start + overflow] = this.buffer_[afterRing .. this.position]; - this.position -= overflow; - } - else - { - this.buffer_[start .. start + overflow] = this.buffer_[afterRing .. this.position]; - this.position = overflow; - } - start += length; - - if (start == this.position) - { - if (this.position != afterRing) - { - this.position = 0; - } - start = 0; - ring = capacity - 1; - } - } - if (start > ring) - { - start = 0; - } - return this; - } - - /// - @nogc nothrow pure @system unittest - { - auto b = WriteBuffer!ubyte(6); - ubyte[6] buf = [23, 23, 255, 128, 127, 9]; - - b ~= buf; - assert(b.length == 6); - b += 2; - assert(b.length == 4); - b += 4; - assert(b.length == 0); - } - - /** - * Returns a chunk with data. - * - * After calling it, set $(D_KEYWORD +=) to the length could be - * written. - * - * $(D_PSYMBOL opIndex) may return only part of the data. You may need - * to call it and set $(D_KEYWORD +=) several times until - * $(D_PSYMBOL length) is 0. If all the data can be written, - * maximally 3 calls are required. - * - * Returns: A chunk of data buffer. - */ - T[] opSlice(size_t start, size_t end) - { - if (this.position > ring || this.position < start) // Buffer overflowed - { - return this.buffer_[this.start .. ring + 1 - length + end]; - } - else - { - return this.buffer_[this.start .. this.start + end]; - } - } - - /// - @nogc nothrow pure @system unittest - { - auto b = WriteBuffer!ubyte(6); - ubyte[6] buf = [23, 23, 255, 128, 127, 9]; - - b ~= buf; - assert(b[0 .. $] == buf[0 .. 6]); - b += 2; - - assert(b[0 .. $] == buf[2 .. 6]); - - b ~= buf; - assert(b[0 .. $] == buf[2 .. 6]); - b += b.length; - - assert(b[0 .. $] == buf[0 .. 6]); - b += b.length; - } - - /** - * After calling it, set $(D_KEYWORD +=) to the length could be - * written. - * - * $(D_PSYMBOL opIndex) may return only part of the data. You may need - * to call it and set $(D_KEYWORD +=) several times until - * $(D_PSYMBOL length) is 0. If all the data can be written, - * maximally 3 calls are required. - * - * Returns: A chunk of data buffer. - */ - T[] opIndex() - { - return opSlice(0, length); - } - - mixin DefaultAllocator; -} - -@nogc nothrow pure @system unittest -{ - auto b = WriteBuffer!ubyte(4); - ubyte[3] buf = [48, 23, 255]; - - b ~= buf; - assert(b.capacity == 4); - assert(b.buffer_[0] == 48 && b.buffer_[1] == 23 && b.buffer_[2] == 255); - - b += 2; - b ~= buf; - assert(b.capacity == 4); - assert(b.buffer_[0] == 23 && b.buffer_[1] == 255 - && b.buffer_[2] == 255 && b.buffer_[3] == 48); - - b += 2; - b ~= buf; - assert(b.capacity == 8); - assert(b.buffer_[0] == 23 && b.buffer_[1] == 255 - && b.buffer_[2] == 48 && b.buffer_[3] == 23 && b.buffer_[4] == 255); -} - -@nogc nothrow pure @system unittest -{ - auto b = WriteBuffer!ubyte(2); - ubyte[3] buf = [48, 23, 255]; - - b ~= buf; - assert(b.start == 0); - assert(b.capacity == 4); - assert(b.ring == 3); - assert(b.position == 3); -} +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This module contains buffers designed for C-style input/output APIs. + * + * Copyright: Eugene Wissner 2016-2025. + * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, + * Mozilla Public License, v. 2.0). + * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) + * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/container/buffer.d, + * tanya/container/buffer.d) + */ +module tanya.container.buffer; + +import std.traits : isScalarType; +import tanya.memory.allocator; +import tanya.meta.trait; + +version (unittest) +{ + private int fillBuffer(ubyte[] buffer, + int start = 0, + int end = 10) @nogc pure nothrow + in + { + assert(start < end); + } + do + { + auto numberRead = end - start; + for (ubyte i; i < numberRead; ++i) + { + buffer[i] = cast(ubyte) (start + i); + } + return numberRead; + } +} + +/** + * Self-expanding buffer, that can be used with functions returning the number + * of the read bytes. + * + * This buffer supports asynchronous reading. It means you can pass a new chunk + * to an asynchronous read function during you are working with already + * available data. But only one asynchronous call at a time is supported. Be + * sure to call $(D_PSYMBOL ReadBuffer.clear()) before you append the result + * of the pended asynchronous call. + * + * Params: + * T = Buffer type. + */ +struct ReadBuffer(T = ubyte) +if (isScalarType!T) +{ + /// Internal buffer. + private T[] buffer_; + + /// Filled buffer length. + private size_t length_; + + /// Start of available data. + private size_t start; + + /// Last position returned with $(D_KEYWORD []). + private size_t ring; + + /// Available space. + private size_t minAvailable = 1024; + + /// Size by which the buffer will grow. + private size_t blockSize = 8192; + + invariant + { + assert(this.length_ <= this.buffer_.length); + assert(this.blockSize > 0); + assert(this.minAvailable > 0); + } + + /** + * Creates a new read buffer. + * + * Params: + * size = Initial buffer size and the size by which the buffer + * will grow. + * minAvailable = minimal size should be always available to fill. + * So it will reallocate if $(D_INLINECODE + * $(D_PSYMBOL free) < $(D_PARAM minAvailable)). + * allocator = Allocator. + */ + this(size_t size, + size_t minAvailable = 1024, + shared Allocator allocator = defaultAllocator) @trusted + { + this(allocator); + this.minAvailable = minAvailable; + this.blockSize = size; + this.buffer_ = cast(T[]) allocator_.allocate(size * T.sizeof); + } + + /// ditto + this(shared Allocator allocator) + in + { + assert(allocator_ is null); + } + do + { + allocator_ = allocator; + } + + /** + * Deallocates the internal buffer. + */ + ~this() @trusted + { + allocator.deallocate(this.buffer_); + } + + /// + @nogc nothrow pure @safe unittest + { + ReadBuffer!ubyte b; + assert(b.capacity == 0); + assert(b.length == 0); + } + + /** + * Returns: The size of the internal buffer. + */ + @property size_t capacity() const + { + return this.buffer_.length; + } + + /** + * Returns: Data size. + */ + @property size_t length() const + { + return this.length_ - start; + } + + /// ditto + alias opDollar = length; + + /** + * Clears the buffer. + * + * Returns: $(D_KEYWORD this). + */ + void clear() + { + start = this.length_ = ring; + } + + /** + * Returns: Available space. + */ + @property size_t free() const + { + return length > ring ? capacity - length : capacity - ring; + } + + /// + @nogc nothrow pure @system unittest + { + ReadBuffer!ubyte b; + size_t numberRead; + + assert(b.free == 0); + + // Fills the buffer with values 0..10 + numberRead = fillBuffer(b[], 0, 10); + b += numberRead; + assert(b.free == b.blockSize - numberRead); + b.clear(); + assert(b.free == b.blockSize); + } + + /** + * Appends some data to the buffer. + * + * Params: + * length = Number of the bytes read. + * + * Returns: $(D_KEYWORD this). + */ + ref ReadBuffer opOpAssign(string op)(size_t length) + if (op == "+") + { + this.length_ += length; + ring = start; + return this; + } + + /// + @nogc nothrow pure @system unittest + { + ReadBuffer!ubyte b; + size_t numberRead; + ubyte[] result; + + // Fills the buffer with values 0..10 + numberRead = fillBuffer(b[], 0, 10); + b += numberRead; + + result = b[0 .. $]; + assert(result[0] == 0); + assert(result[1] == 1); + assert(result[9] == 9); + b.clear(); + + // It shouldn't overwrite, but append another 5 bytes to the buffer + numberRead = fillBuffer(b[], 0, 10); + b += numberRead; + + numberRead = fillBuffer(b[], 20, 25); + b += numberRead; + + result = b[0..$]; + assert(result[0] == 0); + assert(result[1] == 1); + assert(result[9] == 9); + assert(result[10] == 20); + assert(result[14] == 24); + } + + /** + * Params: + * start = Start position. + * end = End position. + * + * Returns: Array between $(D_PARAM start) and $(D_PARAM end). + */ + T[] opSlice(size_t start, size_t end) + { + return this.buffer_[this.start + start .. this.start + end]; + } + + /** + * Returns a free chunk of the buffer. + * + * Add ($(D_KEYWORD +=)) the number of the read bytes after using it. + * + * Returns: A free chunk of the buffer. + */ + T[] opIndex() + { + if (start > 0) + { + auto ret = this.buffer_[0 .. start]; + ring = 0; + return ret; + } + else + { + if (capacity - length < this.minAvailable) + { + void[] buf = this.buffer_; + const cap = capacity; + () @trusted { + allocator.reallocate(buf, + (cap + this.blockSize) * T.sizeof); + this.buffer_ = cast(T[]) buf; + }(); + } + ring = this.length_; + return this.buffer_[this.length_ .. $]; + } + } + + /// + @nogc nothrow pure @system unittest + { + ReadBuffer!ubyte b; + size_t numberRead; + ubyte[] result; + + // Fills the buffer with values 0..10 + numberRead = fillBuffer(b[], 0, 10); + b += numberRead; + + assert(b.length == 10); + result = b[0 .. $]; + assert(result[0] == 0); + assert(result[9] == 9); + b.clear(); + assert(b.length == 0); + } + + mixin DefaultAllocator; +} + +/** + * Circular, self-expanding buffer with overflow support. Can be used with + * functions returning the number of the transferred bytes. + * + * The buffer is optimized for situations where you read all the data from it + * at once (without writing to it occasionally). It can become ineffective if + * you permanently keep some data in the buffer and alternate writing and + * reading, because it may allocate and move elements. + * + * Params: + * T = Buffer type. + */ +struct WriteBuffer(T = ubyte) +if (isScalarType!T) +{ + /// Internal buffer. + private T[] buffer_; + + /// Buffer start position. + private size_t start; + + /// Buffer ring area size. After this position begins buffer overflow area. + private size_t ring; + + /// Size by which the buffer will grow. + private const size_t blockSize; + + /// The position of the free area in the buffer. + private size_t position; + + invariant + { + assert(this.blockSize > 0); + // Position can refer to an element outside the buffer if the buffer is + // full. + assert(this.position <= this.buffer_.length); + } + + /** + * Params: + * size = Initial buffer size and the size by which the buffer will + * grow. + * allocator = Allocator. + * + * Precondition: $(D_INLINECODE size > 0 && allocator !is null) + */ + this(size_t size, shared Allocator allocator = defaultAllocator) @trusted + in + { + assert(size > 0); + assert(allocator !is null); + } + do + { + this.blockSize = size; + ring = size - 1; + allocator_ = allocator; + this.buffer_ = cast(T[]) allocator_.allocate(size * T.sizeof); + } + + @disable this(); + + /** + * Deallocates the internal buffer. + */ + ~this() + { + allocator.deallocate(this.buffer_); + } + + /** + * Returns: The size of the internal buffer. + */ + @property size_t capacity() const + { + return this.buffer_.length; + } + + /** + * Note that $(D_PSYMBOL length) doesn't return the real length of the data, + * but only the array length that will be returned with $(D_PSYMBOL opIndex) + * next time. Be sure to call $(D_PSYMBOL opIndex) and set $(D_KEYWORD +=) + * until $(D_PSYMBOL length) returns 0. + * + * Returns: Data size. + */ + @property size_t length() const + { + if (this.position > ring || this.position < start) // Buffer overflowed + { + return ring - start + 1; + } + else + { + return this.position - start; + } + } + + /// ditto + alias opDollar = length; + + /// + @nogc nothrow pure @system unittest + { + auto b = WriteBuffer!ubyte(4); + ubyte[3] buf = [48, 23, 255]; + + b ~= buf; + assert(b.length == 3); + b += 2; + assert(b.length == 1); + + b ~= buf; + assert(b.length == 2); + b += 2; + assert(b.length == 2); + + b ~= buf; + assert(b.length == 5); + b += b.length; + assert(b.length == 0); + } + + /** + * Returns: Available space. + */ + @property size_t free() const + { + return capacity - length; + } + + /** + * Appends data to the buffer. + * + * Params: + * buffer = Buffer chunk got with $(D_PSYMBOL opIndex). + */ + ref WriteBuffer opOpAssign(string op)(const T[] buffer) + if (op == "~") + { + size_t end, start; + + if (this.position >= this.start && this.position <= ring) + { + auto afterRing = ring + 1; + + end = this.position + buffer.length; + if (end > afterRing) + { + end = afterRing; + } + start = end - this.position; + this.buffer_[this.position .. end] = buffer[0 .. start]; + if (end == afterRing) + { + this.position = this.start == 0 ? afterRing : 0; + } + else + { + this.position = end; + } + } + + // Check if we have some free space at the beginning + if (start < buffer.length && this.position < this.start) + { + end = this.position + buffer.length - start; + if (end > this.start) + { + end = this.start; + } + auto areaEnd = end - this.position + start; + this.buffer_[this.position .. end] = buffer[start .. areaEnd]; + this.position = end == this.start ? ring + 1 : end - this.position; + start = areaEnd; + } + + // And if we still haven't found any place, save the rest in the overflow area + if (start < buffer.length) + { + end = this.position + buffer.length - start; + if (end > capacity) + { + const newSize = end / this.blockSize * this.blockSize + + this.blockSize; + () @trusted { + void[] buf = this.buffer_; + allocator.reallocate(buf, newSize * T.sizeof); + this.buffer_ = cast(T[]) buf; + }(); + } + this.buffer_[this.position .. end] = buffer[start .. $]; + this.position = end; + if (this.start == 0) + { + ring = capacity - 1; + } + } + + return this; + } + + /** + * Sets how many bytes were written. It will shrink the buffer + * appropriately. Always call it after $(D_PSYMBOL opIndex). + * + * Params: + * length = Length of the written data. + * + * Returns: $(D_KEYWORD this). + */ + ref WriteBuffer opOpAssign(string op)(size_t length) + if (op == "+") + in + { + assert(length <= this.length); + } + do + { + auto afterRing = ring + 1; + auto oldStart = start; + + if (length <= 0) + { + return this; + } + else if (this.position <= afterRing) + { + start += length; + if (start > 0 && this.position == afterRing) + { + this.position = oldStart; + } + } + else + { + auto overflow = this.position - afterRing; + + if (overflow > length) + { + const afterLength = afterRing + length; + this.buffer_[start .. start + length] = this.buffer_[afterRing .. afterLength]; + this.buffer_[afterRing .. afterLength] = this.buffer_[afterLength .. this.position]; + this.position -= length; + } + else if (overflow == length) + { + this.buffer_[start .. start + overflow] = this.buffer_[afterRing .. this.position]; + this.position -= overflow; + } + else + { + this.buffer_[start .. start + overflow] = this.buffer_[afterRing .. this.position]; + this.position = overflow; + } + start += length; + + if (start == this.position) + { + if (this.position != afterRing) + { + this.position = 0; + } + start = 0; + ring = capacity - 1; + } + } + if (start > ring) + { + start = 0; + } + return this; + } + + /// + @nogc nothrow pure @system unittest + { + auto b = WriteBuffer!ubyte(6); + ubyte[6] buf = [23, 23, 255, 128, 127, 9]; + + b ~= buf; + assert(b.length == 6); + b += 2; + assert(b.length == 4); + b += 4; + assert(b.length == 0); + } + + /** + * Returns a chunk with data. + * + * After calling it, set $(D_KEYWORD +=) to the length could be + * written. + * + * $(D_PSYMBOL opIndex) may return only part of the data. You may need + * to call it and set $(D_KEYWORD +=) several times until + * $(D_PSYMBOL length) is 0. If all the data can be written, + * maximally 3 calls are required. + * + * Returns: A chunk of data buffer. + */ + T[] opSlice(size_t start, size_t end) + { + if (this.position > ring || this.position < start) // Buffer overflowed + { + return this.buffer_[this.start .. ring + 1 - length + end]; + } + else + { + return this.buffer_[this.start .. this.start + end]; + } + } + + /// + @nogc nothrow pure @system unittest + { + auto b = WriteBuffer!ubyte(6); + ubyte[6] buf = [23, 23, 255, 128, 127, 9]; + + b ~= buf; + assert(b[0 .. $] == buf[0 .. 6]); + b += 2; + + assert(b[0 .. $] == buf[2 .. 6]); + + b ~= buf; + assert(b[0 .. $] == buf[2 .. 6]); + b += b.length; + + assert(b[0 .. $] == buf[0 .. 6]); + b += b.length; + } + + /** + * After calling it, set $(D_KEYWORD +=) to the length could be + * written. + * + * $(D_PSYMBOL opIndex) may return only part of the data. You may need + * to call it and set $(D_KEYWORD +=) several times until + * $(D_PSYMBOL length) is 0. If all the data can be written, + * maximally 3 calls are required. + * + * Returns: A chunk of data buffer. + */ + T[] opIndex() + { + return opSlice(0, length); + } + + mixin DefaultAllocator; +} + +@nogc nothrow pure @system unittest +{ + auto b = WriteBuffer!ubyte(4); + ubyte[3] buf = [48, 23, 255]; + + b ~= buf; + assert(b.capacity == 4); + assert(b.buffer_[0] == 48 && b.buffer_[1] == 23 && b.buffer_[2] == 255); + + b += 2; + b ~= buf; + assert(b.capacity == 4); + assert(b.buffer_[0] == 23 && b.buffer_[1] == 255 + && b.buffer_[2] == 255 && b.buffer_[3] == 48); + + b += 2; + b ~= buf; + assert(b.capacity == 8); + assert(b.buffer_[0] == 23 && b.buffer_[1] == 255 + && b.buffer_[2] == 48 && b.buffer_[3] == 23 && b.buffer_[4] == 255); +} + +@nogc nothrow pure @system unittest +{ + auto b = WriteBuffer!ubyte(2); + ubyte[3] buf = [48, 23, 255]; + + b ~= buf; + assert(b.start == 0); + assert(b.capacity == 4); + assert(b.ring == 3); + assert(b.position == 3); +} diff --git a/source/tanya/container/entry.d b/source/tanya/container/entry.d index 7ea5ff6..f8414e0 100644 --- a/source/tanya/container/entry.d +++ b/source/tanya/container/entry.d @@ -5,7 +5,7 @@ /* * Internal package used by containers that rely on entries/nodes. * - * Copyright: Eugene Wissner 2016-2022. + * Copyright: Eugene Wissner 2016-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/container/hashtable.d b/source/tanya/container/hashtable.d index 723855e..119cc3c 100644 --- a/source/tanya/container/hashtable.d +++ b/source/tanya/container/hashtable.d @@ -5,7 +5,7 @@ /** * Hash table. * - * Copyright: Eugene Wissner 2018-2021. + * Copyright: Eugene Wissner 2018-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) @@ -210,7 +210,7 @@ struct ByKey(T) assert(!empty); assert(this.dataRange.back.status == BucketStatus.used); } - out + out { assert(empty || this.dataRange.back.status == BucketStatus.used); } diff --git a/source/tanya/container/list.d b/source/tanya/container/list.d index 90a834b..0c924ec 100644 --- a/source/tanya/container/list.d +++ b/source/tanya/container/list.d @@ -6,7 +6,7 @@ * This module contains singly-linked ($(D_PSYMBOL SList)) and doubly-linked * ($(D_PSYMBOL DList)) lists. * - * Copyright: Eugene Wissner 2016-2021. + * Copyright: Eugene Wissner 2016-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/container/package.d b/source/tanya/container/package.d index 5edd72e..ae308d0 100644 --- a/source/tanya/container/package.d +++ b/source/tanya/container/package.d @@ -5,7 +5,7 @@ /** * Abstract data types whose instances are collections of other objects. * - * Copyright: Eugene Wissner 2016-2020. + * Copyright: Eugene Wissner 2016-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/container/set.d b/source/tanya/container/set.d index ea95bc8..1b7c1db 100644 --- a/source/tanya/container/set.d +++ b/source/tanya/container/set.d @@ -6,7 +6,7 @@ * This module implements a $(D_PSYMBOL Set) container that stores unique * values without any particular order. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/container/string.d b/source/tanya/container/string.d index 88c82d2..a2cd2f2 100644 --- a/source/tanya/container/string.d +++ b/source/tanya/container/string.d @@ -17,7 +17,7 @@ * Internally $(D_PSYMBOL String) is represented by a sequence of * $(D_KEYWORD char)s. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/conv.d b/source/tanya/conv.d index 6d6dfdd..7d5a264 100644 --- a/source/tanya/conv.d +++ b/source/tanya/conv.d @@ -5,7 +5,7 @@ /** * This module provides functions for converting between different types. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/format.d b/source/tanya/format.d index 8f43cf6..ebe3354 100644 --- a/source/tanya/format.d +++ b/source/tanya/format.d @@ -38,7 +38,7 @@ * * More advanced formatting is currently not implemented. * - * Copyright: Eugene Wissner 2017-2022. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/hash/lookup.d b/source/tanya/hash/lookup.d index 536904d..62faf89 100644 --- a/source/tanya/hash/lookup.d +++ b/source/tanya/hash/lookup.d @@ -5,7 +5,7 @@ /** * Non-cryptographic, lookup hash functions. * - * Copyright: Eugene Wissner 2018-2020. + * Copyright: Eugene Wissner 2018-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/hash/package.d b/source/tanya/hash/package.d index b109f48..89f6440 100644 --- a/source/tanya/hash/package.d +++ b/source/tanya/hash/package.d @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** - * Copyright: Eugene Wissner 2018-2020. + * Copyright: Eugene Wissner 2018-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/math/package.d b/source/tanya/math/package.d index c632bba..0d10238 100644 --- a/source/tanya/math/package.d +++ b/source/tanya/math/package.d @@ -12,7 +12,7 @@ * be found in its submodules. $(D_PSYMBOL tanya.math) doesn't import any * submodules publically, they should be imported explicitly. * - * Copyright: Eugene Wissner 2016-2022. + * Copyright: Eugene Wissner 2016-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/math/random.d b/source/tanya/math/random.d index 646dd59..6146788 100644 --- a/source/tanya/math/random.d +++ b/source/tanya/math/random.d @@ -5,7 +5,7 @@ /** * Random number generator. * - * Copyright: Eugene Wissner 2016-2022. + * Copyright: Eugene Wissner 2016-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/net/iface.d b/source/tanya/net/iface.d index 3bc165a..699d09d 100644 --- a/source/tanya/net/iface.d +++ b/source/tanya/net/iface.d @@ -1,178 +1,178 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Network interfaces. - * - * Copyright: Eugene Wissner 2018-2020. - * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, - * Mozilla Public License, v. 2.0). - * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) - * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/net/iface.d, - * tanya/net/iface.d) - */ -module tanya.net.iface; - -import tanya.algorithm.mutation; -import tanya.container.string; -import tanya.meta.trait; -import tanya.meta.transform; -import tanya.range; - -version (Windows) -{ - private union NET_LUID_LH { ulong Value, Info; } - private alias NET_LUID = NET_LUID_LH; - private alias NET_IFINDEX = uint; - private enum IF_MAX_STRING_SIZE = 256; - extern(Windows) @nogc nothrow private @system - { - uint ConvertInterfaceNameToLuidA(const(char)* InterfaceName, - NET_LUID* InterfaceLuid); - uint ConvertInterfaceLuidToIndex(const(NET_LUID)* InterfaceLuid, - NET_IFINDEX* InterfaceIndex); - uint ConvertInterfaceIndexToLuid(NET_IFINDEX InterfaceIndex, - NET_LUID* InterfaceLuid); - uint ConvertInterfaceLuidToNameA(const(NET_LUID)* InterfaceLuid, - char* InterfaceName, - size_t Length); - } -} -else version (Posix) -{ - import core.sys.posix.net.if_; -} - -/** - * Converts the name of a network interface to its index. - * - * If an interface with the name $(D_PARAM name) cannot be found or another - * error occurres, returns 0. - * - * Params: - * name = Interface name. - * - * Returns: Returns interface index or 0. - */ -uint nameToIndex(R)(R name) @trusted -if (isInputRange!R && is(Unqual!(ElementType!R) == char) && hasLength!R) -{ - version (Windows) - { - if (name.length > IF_MAX_STRING_SIZE) - { - return 0; - } - char[IF_MAX_STRING_SIZE + 1] buffer; - NET_LUID luid; - - copy(name, buffer[]); - buffer[name.length] = '\0'; - - if (ConvertInterfaceNameToLuidA(buffer.ptr, &luid) != 0) - { - return 0; - } - NET_IFINDEX index; - if (ConvertInterfaceLuidToIndex(&luid, &index) == 0) - { - return index; - } - return 0; - } - else version (Posix) - { - if (name.length >= IF_NAMESIZE) - { - return 0; - } - char[IF_NAMESIZE] buffer; - - copy(name, buffer[]); - buffer[name.length] = '\0'; - - return if_nametoindex(buffer.ptr); - } -} - -/// -@nogc nothrow @safe unittest -{ - version (linux) - { - assert(nameToIndex("lo") == 1); - } - else version (Windows) - { - assert(nameToIndex("loopback_0") == 1); - } - else - { - assert(nameToIndex("lo0") == 1); - } - assert(nameToIndex("ecafretni") == 0); -} - -/** - * Converts the index of a network interface to its name. - * - * If an interface with the $(D_PARAM index) cannot be found or another - * error occurres, returns an empty $(D_PSYMBOL String). - * - * Params: - * index = Interface index. - * - * Returns: Returns interface name or an empty $(D_PSYMBOL String). - */ -String indexToName(uint index) @nogc nothrow @trusted -{ - import tanya.memory.op : findNullTerminated; - - version (Windows) - { - NET_LUID luid; - if (ConvertInterfaceIndexToLuid(index, &luid) != 0) - { - return String(); - } - - char[IF_MAX_STRING_SIZE + 1] buffer; - if (ConvertInterfaceLuidToNameA(&luid, - buffer.ptr, - IF_MAX_STRING_SIZE + 1) != 0) - { - return String(); - } - return String(findNullTerminated(buffer)); - } - else version (Posix) - { - char[IF_NAMESIZE] buffer; - if (if_indextoname(index, buffer.ptr) is null) - { - return String(); - } - return String(findNullTerminated(buffer)); - } -} - -/** - * $(D_PSYMBOL AddressFamily) specifies a communication domain; this selects - * the protocol family which will be used for communication. - */ -enum AddressFamily : int -{ - unspec = 0, /// Unspecified. - local = 1, /// Local to host (pipes and file-domain). - unix = local, /// POSIX name for PF_LOCAL. - inet = 2, /// IP protocol family. - ax25 = 3, /// Amateur Radio AX.25. - ipx = 4, /// Novell Internet Protocol. - appletalk = 5, /// Appletalk DDP. - netrom = 6, /// Amateur radio NetROM. - bridge = 7, /// Multiprotocol bridge. - atmpvc = 8, /// ATM PVCs. - x25 = 9, /// Reserved for X.25 project. - inet6 = 10, /// IP version 6. -} +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Network interfaces. + * + * Copyright: Eugene Wissner 2018-2025. + * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, + * Mozilla Public License, v. 2.0). + * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) + * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/net/iface.d, + * tanya/net/iface.d) + */ +module tanya.net.iface; + +import tanya.algorithm.mutation; +import tanya.container.string; +import tanya.meta.trait; +import tanya.meta.transform; +import tanya.range; + +version (Windows) +{ + private union NET_LUID_LH { ulong Value, Info; } + private alias NET_LUID = NET_LUID_LH; + private alias NET_IFINDEX = uint; + private enum IF_MAX_STRING_SIZE = 256; + extern(Windows) @nogc nothrow private @system + { + uint ConvertInterfaceNameToLuidA(const(char)* InterfaceName, + NET_LUID* InterfaceLuid); + uint ConvertInterfaceLuidToIndex(const(NET_LUID)* InterfaceLuid, + NET_IFINDEX* InterfaceIndex); + uint ConvertInterfaceIndexToLuid(NET_IFINDEX InterfaceIndex, + NET_LUID* InterfaceLuid); + uint ConvertInterfaceLuidToNameA(const(NET_LUID)* InterfaceLuid, + char* InterfaceName, + size_t Length); + } +} +else version (Posix) +{ + import core.sys.posix.net.if_; +} + +/** + * Converts the name of a network interface to its index. + * + * If an interface with the name $(D_PARAM name) cannot be found or another + * error occurres, returns 0. + * + * Params: + * name = Interface name. + * + * Returns: Returns interface index or 0. + */ +uint nameToIndex(R)(R name) @trusted +if (isInputRange!R && is(Unqual!(ElementType!R) == char) && hasLength!R) +{ + version (Windows) + { + if (name.length > IF_MAX_STRING_SIZE) + { + return 0; + } + char[IF_MAX_STRING_SIZE + 1] buffer; + NET_LUID luid; + + copy(name, buffer[]); + buffer[name.length] = '\0'; + + if (ConvertInterfaceNameToLuidA(buffer.ptr, &luid) != 0) + { + return 0; + } + NET_IFINDEX index; + if (ConvertInterfaceLuidToIndex(&luid, &index) == 0) + { + return index; + } + return 0; + } + else version (Posix) + { + if (name.length >= IF_NAMESIZE) + { + return 0; + } + char[IF_NAMESIZE] buffer; + + copy(name, buffer[]); + buffer[name.length] = '\0'; + + return if_nametoindex(buffer.ptr); + } +} + +/// +@nogc nothrow @safe unittest +{ + version (linux) + { + assert(nameToIndex("lo") == 1); + } + else version (Windows) + { + assert(nameToIndex("loopback_0") == 1); + } + else + { + assert(nameToIndex("lo0") == 1); + } + assert(nameToIndex("ecafretni") == 0); +} + +/** + * Converts the index of a network interface to its name. + * + * If an interface with the $(D_PARAM index) cannot be found or another + * error occurres, returns an empty $(D_PSYMBOL String). + * + * Params: + * index = Interface index. + * + * Returns: Returns interface name or an empty $(D_PSYMBOL String). + */ +String indexToName(uint index) @nogc nothrow @trusted +{ + import tanya.memory.op : findNullTerminated; + + version (Windows) + { + NET_LUID luid; + if (ConvertInterfaceIndexToLuid(index, &luid) != 0) + { + return String(); + } + + char[IF_MAX_STRING_SIZE + 1] buffer; + if (ConvertInterfaceLuidToNameA(&luid, + buffer.ptr, + IF_MAX_STRING_SIZE + 1) != 0) + { + return String(); + } + return String(findNullTerminated(buffer)); + } + else version (Posix) + { + char[IF_NAMESIZE] buffer; + if (if_indextoname(index, buffer.ptr) is null) + { + return String(); + } + return String(findNullTerminated(buffer)); + } +} + +/** + * $(D_PSYMBOL AddressFamily) specifies a communication domain; this selects + * the protocol family which will be used for communication. + */ +enum AddressFamily : int +{ + unspec = 0, /// Unspecified. + local = 1, /// Local to host (pipes and file-domain). + unix = local, /// POSIX name for PF_LOCAL. + inet = 2, /// IP protocol family. + ax25 = 3, /// Amateur Radio AX.25. + ipx = 4, /// Novell Internet Protocol. + appletalk = 5, /// Appletalk DDP. + netrom = 6, /// Amateur radio NetROM. + bridge = 7, /// Multiprotocol bridge. + atmpvc = 8, /// ATM PVCs. + x25 = 9, /// Reserved for X.25 project. + inet6 = 10, /// IP version 6. +} diff --git a/source/tanya/net/inet.d b/source/tanya/net/inet.d index 65146b6..7199a3c 100644 --- a/source/tanya/net/inet.d +++ b/source/tanya/net/inet.d @@ -5,7 +5,7 @@ /** * Internet utilities. * - * Copyright: Eugene Wissner 2016-2020. + * Copyright: Eugene Wissner 2016-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/net/ip.d b/source/tanya/net/ip.d index 73e7f84..4b6d2f7 100644 --- a/source/tanya/net/ip.d +++ b/source/tanya/net/ip.d @@ -5,7 +5,7 @@ /** * Internet Protocol implementation. * - * Copyright: Eugene Wissner 2018-2020. + * Copyright: Eugene Wissner 2018-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/net/package.d b/source/tanya/net/package.d index 9626b9e..f8762a7 100644 --- a/source/tanya/net/package.d +++ b/source/tanya/net/package.d @@ -5,7 +5,7 @@ /** * Network programming. * - * Copyright: Eugene Wissner 2017-2022. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/net/uri.d b/source/tanya/net/uri.d index 419b486..d164724 100644 --- a/source/tanya/net/uri.d +++ b/source/tanya/net/uri.d @@ -5,7 +5,7 @@ /** * URL parser. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) @@ -193,7 +193,7 @@ struct URL if (this.user is null) { this.user = source[start .. start + i]; - this.pass = source[start + i + 1 .. pos]; + this.pass = source[start + i + 1 .. pos]; } } else if (!c.isAlpha() && @@ -315,10 +315,10 @@ struct URL @nogc pure @system unittest { auto u = URL("example.org"); - assert(u.path == "example.org"); + assert(u.path == "example.org"); u = URL("relative/path"); - assert(u.path == "relative/path"); + assert(u.path == "relative/path"); // Host and scheme u = URL("https://example.org"); diff --git a/source/tanya/range/adapter.d b/source/tanya/range/adapter.d index 60d4c67..9dfe2f2 100644 --- a/source/tanya/range/adapter.d +++ b/source/tanya/range/adapter.d @@ -5,7 +5,7 @@ /** * Range adapters transform some data structures into ranges. * - * Copyright: Eugene Wissner 2018-2020. + * Copyright: Eugene Wissner 2018-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/range/array.d b/source/tanya/range/array.d index bd47fb9..fb0895d 100644 --- a/source/tanya/range/array.d +++ b/source/tanya/range/array.d @@ -31,7 +31,7 @@ * (D_INLINECODE dchar[])) are treated as any other normal array, they aren't * auto-decoded. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/range/package.d b/source/tanya/range/package.d index 16ffe8c..e2debfc 100644 --- a/source/tanya/range/package.d +++ b/source/tanya/range/package.d @@ -6,7 +6,7 @@ * This package contains generic functions and templates to be used with D * ranges. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/source/tanya/range/primitive.d b/source/tanya/range/primitive.d index 54646a6..3cc45e0 100644 --- a/source/tanya/range/primitive.d +++ b/source/tanya/range/primitive.d @@ -5,7 +5,7 @@ /** * This module defines primitives for working with ranges. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/test/tanya/test/assertion.d b/test/tanya/test/assertion.d index ae24fad..5fd9831 100644 --- a/test/tanya/test/assertion.d +++ b/test/tanya/test/assertion.d @@ -13,7 +13,7 @@ * The functions can cause segmentation fault if the module is compiled * in production mode and the condition fails. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/test/tanya/test/package.d b/test/tanya/test/package.d index a444a88..f316ddf 100644 --- a/test/tanya/test/package.d +++ b/test/tanya/test/package.d @@ -5,7 +5,7 @@ /** * Test suite for $(D_KEYWORD unittest)-blocks. * - * Copyright: Eugene Wissner 2017-2020. + * Copyright: Eugene Wissner 2017-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) diff --git a/test/tanya/test/stub.d b/test/tanya/test/stub.d index 99630e6..a83cf01 100644 --- a/test/tanya/test/stub.d +++ b/test/tanya/test/stub.d @@ -5,7 +5,7 @@ /** * Range and generic type generators. * - * Copyright: Eugene Wissner 2018-2020. + * Copyright: Eugene Wissner 2018-2025. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)