summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2018-09-16 18:15:35 +0200
committerEugen Wissner <belka@caraus.de>2018-09-16 19:07:55 +0200
commiteb796e0ddf49312e01fcf2cab42b93d40c1c61eb (patch)
tree1777af0a6271989c6cb6284f85b596f3990a7c83 /source
parente5569e5feafdc2ca4b7f33471c9073a9645cf670 (diff)
downloadtanya-eb796e0ddf49312e01fcf2cab42b93d40c1c61eb.tar.gz
Add bitmanip.BitFlags
Diffstat (limited to 'source')
-rw-r--r--source/tanya/async/event/iocp.d4
-rw-r--r--source/tanya/async/event/selector.d6
-rw-r--r--source/tanya/async/loop.d2
-rw-r--r--source/tanya/bitmanip.d359
4 files changed, 367 insertions, 4 deletions
diff --git a/source/tanya/async/event/iocp.d b/source/tanya/async/event/iocp.d
index 9d09dcd..acd37a5 100644
--- a/source/tanya/async/event/iocp.d
+++ b/source/tanya/async/event/iocp.d
@@ -318,7 +318,9 @@ final class IOCPLoop : Loop
connection.incoming.insertBack(transport);
- reify(transport, EventMask(Event.none), EventMask(Event.read, Event.write));
+ reify(transport,
+ EventMask(Event.none),
+ EventMask(Event.read | Event.write));
pendings.insertBack(connection);
listener.beginAccept(overlapped);
diff --git a/source/tanya/async/event/selector.d b/source/tanya/async/event/selector.d
index f8149cf..9e83261 100644
--- a/source/tanya/async/event/selector.d
+++ b/source/tanya/async/event/selector.d
@@ -140,7 +140,7 @@ package class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{
closing = true;
loop.reify(this,
- EventMask(Event.read, Event.write),
+ EventMask(Event.read | Event.write),
EventMask(Event.write));
}
@@ -393,7 +393,9 @@ abstract class SelectorLoop : Loop
transport.socket = client;
}
- reify(transport, EventMask(Event.none), EventMask(Event.read, Event.write));
+ reify(transport,
+ EventMask(Event.none),
+ EventMask(Event.read | Event.write));
connection.incoming.insertBack(transport);
}
diff --git a/source/tanya/async/loop.d b/source/tanya/async/loop.d
index f5c7dae..b706ff3 100644
--- a/source/tanya/async/loop.d
+++ b/source/tanya/async/loop.d
@@ -72,9 +72,9 @@
module tanya.async.loop;
import core.time;
-import std.typecons;
import tanya.async.transport;
import tanya.async.watcher;
+import tanya.bitmanip;
import tanya.container.buffer;
import tanya.container.list;
import tanya.memory;
diff --git a/source/tanya/bitmanip.d b/source/tanya/bitmanip.d
new file mode 100644
index 0000000..98e7042
--- /dev/null
+++ b/source/tanya/bitmanip.d
@@ -0,0 +1,359 @@
+/* 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/. */
+
+/**
+ * Bit manipulation.
+ *
+ * Copyright: Eugene Wissner 2018.
+ * 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/bitmanip.d,
+ * tanya/bitmanip.d)
+ */
+module tanya.bitmanip;
+
+import tanya.meta.metafunction;
+import tanya.meta.trait;
+import tanya.meta.transform;
+
+/**
+ * Determines whether $(D_PARAM E) is a $(D_KEYWORD enum), whose members can be
+ * used as bit flags.
+ *
+ * This is the case if all members of $(D_PARAM E) are integral numbers that
+ * are either 0 or positive integral powers of 2.
+ *
+ * Params:
+ * E = Some $(D_KEYWORD enum).
+ *
+ * Returns: $(D_KEYWORD true) if $(D_PARAM E) contains only bit flags,
+ * $(D_KEYWORD false) otherwise.
+ */
+template isBitFlagEnum(E)
+{
+ enum bool isValid(OriginalType!E x) = x == 0
+ || (x > 0 && ((x & (x - 1)) == 0));
+ static if (isIntegral!E)
+ {
+ enum bool isBitFlagEnum = allSatisfy!(isValid, EnumMembers!E);
+ }
+ else
+ {
+ enum bool isBitFlagEnum = false;
+ }
+}
+
+///
+@nogc nothrow pure @safe unittest
+{
+ enum Valid
+ {
+ none = 0,
+ one = 1 << 0,
+ two = 1 << 1,
+ }
+ static assert(isBitFlagEnum!Valid);
+
+ enum Invalid
+ {
+ one,
+ two,
+ three,
+ four,
+ }
+ static assert(!isBitFlagEnum!Invalid);
+
+ enum Negative
+ {
+ one = -1,
+ two = -2,
+ }
+ static assert(!isBitFlagEnum!Negative);
+}
+
+/**
+ * Validates that $(D_PARAM field) contains only bits from $(D_PARAM E).
+ *
+ * Params:
+ * E = Some $(D_KEYWORD enum).
+ * field = Bit field.
+ *
+ * Returns: $(D_KEYWORD true) if $(D_PARAM field) is valid, $(D_KEYWORD false)
+ * otherwise.
+ */
+bool containsBitFlags(E)(E field)
+if (isBitFlagEnum!E)
+{
+ OriginalType!E fillField()
+ {
+ typeof(return) full;
+ static foreach (member; EnumMembers!E)
+ {
+ full |= member;
+ }
+ return full;
+ }
+ enum OriginalType!E full = fillField();
+ return (field & ~full) == OriginalType!E.init;
+}
+
+///
+@nogc nothrow pure @safe unittest
+{
+ enum E
+ {
+ one,
+ two,
+ three,
+ }
+ assert(containsBitFlags(E.one | E.two));
+ assert(!containsBitFlags(cast(E) 0x8));
+}
+
+/**
+ * Allows to use $(D_KEYWORD enum) values as a set of bit flags.
+ *
+ * $(D_PSYMBOL BitFlags) behaves the same as a bit field of type $(D_PARAM E),
+ * but does additional cheks to ensure that the bit field contains only valid
+ * values, this is only values from $(D_PARAM E).
+ *
+ * Params:
+ * E = Some $(D_KEYWORD enum).
+ */
+struct BitFlags(E)
+if (isBitFlagEnum!E)
+{
+ private OriginalType!E field;
+
+ /**
+ * Constructs $(D_PSYMBOL BitFlags) from $(D_PARAM field).
+ *
+ * Params:
+ * field = Bits to be set.
+ */
+ this(E field)
+ {
+ this.field = field;
+ }
+
+ /**
+ * Converts $(D_PSYMBOL BitFlags) to a boolean.
+ *
+ * It is $(D_KEYWORD true) if any bit is set, $(D_KEYWORD false) otherwise.
+ *
+ * Returns: $(D_KEYWORD true) if this $(D_PSYMBOL BitFlags) contains any
+ * set bits, $(D_KEYWORD false) otherwise.
+ */
+ bool opCast(T : bool)()
+ {
+ return this.field != 0;
+ }
+
+ /**
+ * Converts to the original type of $(D_PARAM E) ($(D_KEYWORD int) by
+ * default).
+ *
+ * Returns: $(D_KEYWORD this) as $(D_INLINECODE OriginalType!T).
+ */
+ OriginalType!E opCast(T : OriginalType!E)() const
+ {
+ return this.field;
+ }
+
+ /**
+ * Tests (&), sets (|) or toggles (^) bits.
+ *
+ * Params:
+ * op = Operation.
+ * that = 0 or more bit flags.
+ *
+ * Returns: New $(D_PSYMBOL BitFlags) object.
+ */
+ BitFlags opBinary(string op)(E that) const
+ if (op == "&" || op == "|" || op == "^")
+ {
+ BitFlags result = this;
+ mixin("return result " ~ op ~ "= that;");
+ }
+
+ /// ditto
+ BitFlags opBinary(string op)(BitFlags that) const
+ if (op == "&" || op == "|" || op == "^")
+ {
+ BitFlags result = this;
+ mixin("return result " ~ op ~ "= that;");
+ }
+
+ /// ditto
+ BitFlags opBinaryRight(string op)(E that) const
+ if (op == "&" || op == "|" || op == "^")
+ {
+ BitFlags result = this;
+ mixin("return result " ~ op ~ "= that;");
+ }
+
+ /**
+ * Tests (&), sets (|) or toggles (^) bits.
+ *
+ * Params:
+ * op = Operation.
+ * that = 0 or more bit flags.
+ *
+ * Returns: $(D_KEYWORD this).
+ */
+ ref BitFlags opOpAssign(string op)(E that)
+ if (op == "&" || op == "|" || op == "^")
+ {
+ mixin("this.field " ~ op ~ "= that;");
+ return this;
+ }
+
+ /// ditto
+ ref BitFlags opOpAssign(string op)(BitFlags that)
+ if (op == "&" || op == "|" || op == "^")
+ {
+ mixin("this.field " ~ op ~ "= that.field;");
+ return this;
+ }
+
+ /**
+ * Inverts all bit flags.
+ *
+ * Returns: New $(D_PSYMBOL BitFlags) object with all bits inverted.
+ */
+ BitFlags opUnary(string op : "~")() const
+ {
+ BitFlags result;
+ result.field = ~this.field;
+ return result;
+ }
+
+ /**
+ * Assigns a bit field.
+ *
+ * Params:
+ * that = Bit field of type $(D_PARAM E).
+ *
+ * Returns: $(D_KEYWORD this).
+ */
+ ref BitFlags opAssign(E that)
+ {
+ this.field = that;
+ return this;
+ }
+
+ /**
+ * Compares this $(D_PSYMBOL BitFlags) object to another bit field.
+ *
+ * Params:
+ * that = $(D_PSYMBOL BitFlags) object or a bit field of type
+ * $(D_PARAM E).
+ *
+ * Returns: $(D_KEYWORD true) if $(D_KEYWORD this) and $(D_PARAM that)
+ * contain the same bits ,$(D_KEYWORD false) otherwise.
+ */
+ bool opEquals(E that) const
+ {
+ return this.field == that;
+ }
+
+ /// ditto
+ bool opEquals(BitFlags that) const
+ {
+ return this.field == that.field;
+ }
+
+ /**
+ * Generates a hash value of this object.
+ *
+ * Returns: Hash value.
+ */
+ size_t toHash() const
+ {
+ return cast(size_t) this.field;
+ }
+}
+
+@nogc nothrow pure @safe unittest
+{
+ enum E : int
+ {
+ one = 1,
+ }
+
+ // Casts to a boolean
+ assert(BitFlags!E(E.one));
+ assert(!BitFlags!E());
+
+ // Assigns to and compares with a single value
+ {
+ BitFlags!E bitFlags;
+ bitFlags = E.one;
+ assert(bitFlags == E.one);
+ }
+ // Assigns to and compares with the same type
+ {
+ auto bitFlags1 = BitFlags!E(E.one);
+ BitFlags!E bitFlags2;
+ bitFlags2 = bitFlags1;
+ assert(bitFlags1 == bitFlags2);
+ }
+ assert((BitFlags!E() | E.one) == BitFlags!E(E.one));
+ assert((BitFlags!E() | BitFlags!E(E.one)) == BitFlags!E(E.one));
+
+ assert(!(BitFlags!E() & BitFlags!E(E.one)));
+
+ assert(!(BitFlags!E(E.one) ^ E.one));
+ assert(BitFlags!E() ^ BitFlags!E(E.one));
+
+ assert(~BitFlags!E());
+
+ assert(BitFlags!E().toHash() == 0);
+ assert(BitFlags!E(E.one).toHash() != 0);
+
+ // opBinaryRight is allowed
+ static assert(is(typeof({ E.one | BitFlags!E(); })));
+}
+
+/**
+ * Creates a $(D_PSYMBOL BitFlags) object initialized with $(D_PARAM field).
+ *
+ * Params:
+ * E = Some $(D_KEYWORD enum).
+ * field = Bits to be set.
+ */
+BitFlags!E bitFlags(E)(E field)
+if (isBitFlagEnum!E)
+{
+ return BitFlags!E(field);
+}
+
+///
+@nogc nothrow pure @safe unittest
+{
+ enum E
+ {
+ one = 1 << 0,
+ two = 1 << 1,
+ three = 1 << 2,
+ }
+ // Construct with E.one and E.two set
+ auto flags = bitFlags(E.one | E.two);
+
+ // Test wheter E.one is set
+ assert(flags & E.one);
+
+ // Toggle E.one
+ flags ^= E.one;
+ assert(!(flags & E.one));
+
+ // Set E.three
+ flags |= E.three;
+ assert(flags & E.three);
+
+ // Clear E.three
+ flags &= ~E.three;
+ assert(!(flags & E.three));
+}