1 /// Assorted helpers 2 module mecca.reactor.utils; 3 4 // Licensed under the Boost license. Full copyright information in the AUTHORS file 5 6 import std.range; 7 8 import mecca.log; 9 import mecca.reactor; 10 11 /** 12 * Pointer to data on another Fiber's stack 13 * 14 * This is a pointer to data that reside on another fiber's stack. It is assumed that the other fiber knows not 15 * to exit the function while the pointer is in effect. 16 * 17 * This construct protects against the case that the other fiber is killed while the pointer is still live. 18 * 19 * Params: 20 * T = The pointer type to use 21 */ 22 struct FiberPointer(T) { 23 private: 24 FiberHandle fibHandle; 25 T* ptr; 26 27 public: 28 /** 29 * Construct a FiberPointer. 30 */ 31 this(T* ptr) nothrow @safe @nogc { 32 this.fibHandle = theReactor.currentFiberHandle(); 33 this.ptr = ptr; 34 } 35 36 /// Reports whether the pointer is currently valid 37 @property bool isValid() const nothrow @safe @nogc { 38 return fibHandle.isValid; 39 } 40 41 /** 42 * Returns the pointer. 43 * 44 * Returns: 45 * Returns the pointer or `null` if the fiber quit 46 */ 47 @property T* get() nothrow @safe @nogc { 48 return fibHandle.isValid ? ptr : null; 49 } 50 51 /// Return a handle to the owning fiber, if valid 52 @property 53 auto ownerFiber() const nothrow @safe @nogc { 54 assert(this.isValid); 55 return this.fibHandle; 56 } 57 58 /// Reset the pointer 59 @notrace void reset() nothrow @safe @nogc { 60 this = FiberPointer.init; 61 } 62 63 /// The `FiberPointer` acts as the pointer itself 64 alias get this; 65 } 66 67 /// Create a FiberPointer from a pointer 68 auto makeFiberPointer(T)(T* ptr) { 69 return FiberPointer!T(ptr); 70 } 71 72 /** 73 "Play nice" input range filter 74 75 Injecting this into an input range processing chain will make sure that an occasional context switch happens during 76 long processing. 77 78 Each call to `popFront` may result in a context switch 79 */ 80 auto contextSwitchingRange(R)(R range) if( isInputRange!R ) { 81 static struct ContextSwitchingRange(R) { 82 R range; 83 alias range this; 84 ref auto popFront() { 85 theReactor.considerYield(); 86 return range.popFront; 87 } 88 } 89 return ContextSwitchingRange!R(range); 90 }