1 /**
2  * Reference-counted objects for handling large amounts of raw _data.
3  *
4  * Using the `Data` type will only place a small object in managed
5  * memory, keeping the actual bytes in unmanaged memory.
6  *
7  * A proxy class (`Memory`) is used to safely allow multiple
8  * references to the same block of unmanaged memory.
9  *
10  * When the `Memory` object is destroyed, the unmanaged memory is
11  * deallocated.
12  *
13  * This has the following advantage over using managed memory (regular
14  * D arrays):
15  *
16  * - Faster allocation and deallocation, since memory is requested from
17  *   the OS directly as whole pages.
18  *
19  * - Greatly reduced chance of memory leaks (on 32-bit platforms) due to
20  *   stray pointers.
21  *
22  * - Overall improved GC performance due to reduced size of managed heap.
23  *
24  * - Memory is immediately returned to the OS when no more references
25  *   remain.
26  *
27  * - Unlike D arrays, `Data` objects know their reference count,
28  *   enabling things like copy-on-write or safely casting away constness.
29  *
30  * License:
31  *   This Source Code Form is subject to the terms of
32  *   the Mozilla Public License, v. 2.0. If a copy of
33  *   the MPL was not distributed with this file, You
34  *   can obtain one at http://mozilla.org/MPL/2.0/.
35  *
36  * Authors:
37  *   Vladimir Panteleev <ae@cy.md>
38  */
39 
40 module ae.sys.data;
41 
42 import core.exception : OutOfMemoryError, onOutOfMemoryError;
43 
44 import std.algorithm.mutation : move;
45 import std.traits : hasIndirections, Unqual, isSomeChar;
46 
47 // https://issues.dlang.org/show_bug.cgi?id=23961
48 //import ae.utils.array : emptySlice, sliceIndex, bytes, fromBytes;
49 
50 debug(DATA) import core.stdc.stdio;
51 
52 version (ae_data_nogc)
53 	private enum useGC = false;
54 else
55 	private enum useGC = true;
56 
57 static if (useGC)
58 	import core.memory : GC;
59 
60 /**
61  * A reference to a reference-counted block of memory.
62  * Represents a slice of data, which may be backed by managed memory,
63  * unmanaged memory, memory-mapped files, etc.
64  *
65  * Params:
66  *  T = the element type. "void" has a special meaning in that memory
67  *      will not be default-initialized.
68  */
69 struct TData(T)
70 if (!hasIndirections!T)
71 {
72 private:
73 	// https://issues.dlang.org/show_bug.cgi?id=23961
74 	import ae.utils.array : emptySlice, sliceIndex, as, asBytes;
75 
76 	/// Wrapped data
77 	T[] data;
78 
79 	/// Reference to the memory of the actual data - may be null to
80 	/// indicate wrapped data in managed memory.
81 	/// Used to maintain the reference count to unmanaged data, and
82 	/// for in-place expands (for appends).
83 	Memory memory;
84 
85 	// --- Typed Memory construction helpers
86 
87 	// No pure due to https://issues.dlang.org/show_bug.cgi?id=23959
88 	static T[] allocateMemory(U)(out Memory memory, size_t initialSize, size_t capacity, scope void delegate(Unqual!U[] contents) /*pure*/ @safe nothrow @nogc fill)
89 	{
90 		if (capacity * T.sizeof < OSAllocator.pageSize)
91 			memory = unmanagedNew!CMemory(initialSize * T.sizeof, capacity * T.sizeof);
92 		else
93 			memory = unmanagedNew!OSMemory(initialSize * T.sizeof, capacity * T.sizeof);
94 		fill(cast(Unqual!U[])memory.contents);
95 		return cast(T[])memory.contents;
96 	}
97 
98 	static T[] allocateMemory(U)(out Memory memory, U[] initialData)
99 	{
100 		assert(initialData.length * U.sizeof % T.sizeof == 0, "Unaligned allocation size");
101 		auto initialSize = initialData.length * U.sizeof / T.sizeof;
102 		// @trusted to allow copying void[] to void[]
103 		return allocateMemory!U(memory, initialSize, initialSize, (contents) @trusted { contents[] = initialData[]; });
104 	}
105 
106 	static T[] allocateMemory(out Memory memory, size_t initialSize, size_t capacity)
107 	{
108 		return allocateMemory!T(memory, initialSize, capacity, (contents) {
109 			static if (!is(Unqual!T == void))
110 				contents[] = T.init;
111 		});
112 	}
113 
114 	// --- Concatenation / appending helpers
115 
116 	// No pure due to https://issues.dlang.org/show_bug.cgi?id=23959
117 	void reallocate(size_t size, size_t capacity, scope void delegate(Unqual!T[] contents) /*pure*/ @safe nothrow @nogc fill)
118 	{
119 		Memory newMemory;
120 		// @trusted to allow copying void[] to void[]
121 		auto newData = allocateMemory!T(newMemory, size, capacity, (contents) @trusted {
122 			contents[0 .. this.data.length] = this.data;
123 			fill(contents[this.data.length .. $]);
124 		});
125 
126 		clear();
127 		this.memory = newMemory;
128 		this.memory.referenceCount++;
129 		this.data = newData;
130 	}
131 
132 	// No pure due to https://issues.dlang.org/show_bug.cgi?id=23959
133 	void expand(size_t newSize, size_t newCapacity, scope void delegate(Unqual!T[] contents) /*pure*/ @safe nothrow @nogc fill)
134 	@trusted // Allow slicing data.ptr
135 	in
136 	{
137 		assert(length < newSize);
138 		assert(newSize <= newCapacity);
139 	}
140 	out
141 	{
142 		assert(length == newSize);
143 	}
144 	do
145 	{
146 		if (newCapacity <= capacity)
147 		{
148 			auto dataBytes = this.data.asBytes;
149 			auto pos = memory.contents.sliceIndex(dataBytes); // start position in memory data in bytes
150 			memory.setSize(pos + newSize * T.sizeof);
151 			auto oldSize = data.length;
152 			data = data.ptr[0..newSize];
153 			fill(cast(Unqual!T[])data[oldSize .. $]);
154 		}
155 		else
156 			reallocate(newSize, newCapacity, fill);
157 	}
158 
159 	// Maximum preallocation for append operations.
160 	enum maxPrealloc = 4*1024*1024; // must be power of 2
161 
162 	alias Appendable = const(Unqual!T)[];
163 	static assert(is(typeof((T[]).init ~ Appendable.init)));
164 
165 	static TData createConcatenation(Appendable left, Appendable right)
166 	{
167 		auto newSize = left.length + right.length;
168 		Memory newMemory;
169 		// @trusted to allow copying void[] to void[]
170 		allocateMemory!T(newMemory, newSize, newSize, (contents) @trusted {
171 			contents[0 .. left.length] = left[];
172 			contents[left.length .. $] = right[];
173 		});
174 		return TData(newMemory);
175 	}
176 
177 	TData concat(Appendable right)
178 	{
179 		if (right.length == 0)
180 			return this;
181 		return createConcatenation(this.data, right);
182 	}
183 
184 	TData prepend(Appendable left)
185 	{
186 		if (left.length == 0)
187 			return this;
188 		return createConcatenation(left, this.data);
189 	}
190 
191 	static size_t getPreallocSize(size_t length)
192 	{
193 		import ae.utils.math : isPowerOfTwo, nextPowerOfTwo;
194 		static assert(isPowerOfTwo(maxPrealloc));
195 
196 		if (length < maxPrealloc)
197 			return nextPowerOfTwo(length);
198 		else
199 			return ((length-1) | (maxPrealloc-1)) + 1;
200 	}
201 
202 	TData append(Appendable right)
203 	{
204 		if (right.length == 0)
205 			return this;
206 		size_t newLength = length + right.length;
207 		// @trusted to allow copying void[] to void[]
208 		expand(newLength, getPreallocSize(newLength), (contents) @trusted {
209 			contents[] = right[];
210 		});
211 		return this;
212 	}
213 
214 	// --- Conversion helpers
215 
216 	void assertUnique() const
217 	{
218 		assert(
219 			(data is null)
220 			||
221 			(memory && memory.referenceCount == 1)
222 		);
223 	}
224 
225 	void becomeUnique()
226 	out
227 	{
228 		assertUnique();
229 	}
230 	do
231 	{
232 		if (!memory) // null, empty, or GC-owned data
233 			this = TData(data);
234 		else
235 		if (memory.referenceCount > 1)
236 			this = TData(data);
237 	}
238 
239 	debug invariant
240 	{
241 		if (data.length == 0)
242 			assert(memory is null, "Zero-length Data pinning Memory");
243 		if (memory)
244 			assert(memory.referenceCount > 0, "Data referencing Memory with bad reference count");
245 	}
246 
247 public:
248 	// --- Lifetime - construction
249 
250 	// TODO: overload the constructor on scope/non-scope to detect when to reallocate?
251 	// https://issues.dlang.org/show_bug.cgi?id=23941
252 
253 	/**
254 	 * DWIM constructor for creating a new instance wrapping the given data.
255 	 *
256 	 * In the current implementation, `data` is always copied into the
257 	 * new instance, however past and future implementations may not
258 	 * guarantee this (`wrapGC`-like construction may be used
259 	 * opportunistically instead).
260 	 */
261 	this(U)(U[] data)
262 	if (is(typeof({ U[] u; T[] t = u.dup; })))
263 	{
264 		if (data is null)
265 			this.data = null;
266 		else
267 		if (data.length == 0)
268 			this.data = emptySlice!T;
269 		else
270 		// if (forceReallocation || GC.addrOf(data.ptr) is null)
271 		{
272 			// copy (emplace) into unmanaged memory
273 			this.data = allocateMemory(this.memory, data);
274 			this.memory.referenceCount++;
275 		}
276 		// else
277 		// {
278 		// 	// just save a reference
279 		// 	this.data = data;
280 		// }
281 
282 		assert(this.length * T.sizeof == data.length * U.sizeof);
283 	}
284 
285 	/// Create a new null-like instance.
286 	this(typeof(null) n)
287 	{
288 	}
289 
290 	deprecated this(U)(U[] data)
291 	if (is(T == ubyte) &&
292 		!is(typeof({ U[] u; T[] t = u.dup; })) &&
293 		is(typeof({ U[] u; void[] t = u.dup; })))
294 	{
295 		const(void)[] v = data;
296 		this(cast(const(ubyte)[])v);
297 	}
298 
299 	/// Create a new instance with given size/capacity. Capacity defaults to size.
300 	this(size_t size, size_t capacity = 0)
301 	in
302 	{
303 		assert(capacity == 0 || size <= capacity);
304 	}
305 	do
306 	{
307 		if (!capacity)
308 			capacity = size;
309 
310 		if (capacity)
311 		{
312 			this.data = allocateMemory(this.memory, size, capacity);
313 			this.memory.referenceCount++;
314 		}
315 		else
316 		{
317 			memory = null;
318 			this.data = null;
319 		}
320 
321 		assert(this.length == size);
322 	}
323 
324 	/// Allow assigning null to clear.
325 	void opAssign(typeof(null))
326 	{
327 		clear();
328 	}
329 
330 	/// Create a new instance which slices some range of managed (GC-owned) memory.
331 	/// Does not copy the data.
332 	static if (useGC)
333 	static TData wrapGC(T[] data)
334 	{
335 		assert(data.length == 0 || GC.addrOf(data.ptr) !is null, "wrapGC data must be GC-owned");
336 		TData result;
337 		result.data = data;
338 		return result;
339 	}
340 
341 	/// Create a new instance slicing all of the given memory's contents.
342 	this(Memory memory)
343 	{
344 		this.memory = memory;
345 		this.memory.referenceCount++;
346 		this.data = cast(T[])memory.contents;
347 	}
348 
349 	this(this) @safe
350 	{
351 		if (memory)
352 		{
353 			memory.referenceCount++;
354 			debug (DATA_REFCOUNT) debugLog("%p -> %p: Incrementing refcount to %d", cast(void*)&this, cast(void*)memory, memory.referenceCount);
355 		}
356 		else
357 			debug (DATA_REFCOUNT) debugLog("%p -> %p: this(this) with no memory", cast(void*)&this, cast(void*)memory);
358 	}
359 
360 	// --- Lifetime - destruction
361 
362 	// No pure due to https://issues.dlang.org/show_bug.cgi?id=23959
363 	~this() /*pure*/ @trusted nothrow @nogc
364 	{
365 		clear();
366 		// https://issues.dlang.org/show_bug.cgi?id=13809
367 		// (cast(void delegate() pure nothrow @nogc)&clear)();
368 	}
369 
370 	/// Unreference contents, freeing it if this was the last reference.
371 	void clear() nothrow @nogc
372 	{
373 		if (memory)
374 		{
375 			assert(memory.referenceCount > 0, "Dangling pointer to Memory");
376 			memory.referenceCount--;
377 			debug (DATA_REFCOUNT) debugLog("%p -> %p: Decrementing refcount to %d", cast(void*)&this, cast(void*)memory, memory.referenceCount);
378 			if (memory.referenceCount == 0)
379 				unmanagedDelete(memory);
380 
381 			memory = null;
382 		}
383 
384 		this.data = null;
385 	}
386 
387 	// This used to be an unsafe method which deleted the wrapped data.
388 	// Now that Data is refcounted, this simply calls clear() and
389 	// additionally asserts that this Data is the only Data holding
390 	// a reference to the memory.
391 	deprecated void deleteContents()
392 	out
393 	{
394 		assert(memory is null);
395 	}
396 	do
397 	{
398 		if (memory)
399 		{
400 			assert(memory.referenceCount == 1, "Attempting to call deleteContents with more than one reference");
401 			clear();
402 		}
403 	}
404 
405 	// --- Lifetime - conversion
406 
407 	/// Returns an instance with the same data as the current instance, and a reference count of 1.
408 	/// The current instance is cleared.
409 	/// If the current instance already has a reference count of 1, no copying is done.
410 	TData ensureUnique()
411 	{
412 		becomeUnique();
413 		return move(this);
414 	}
415 
416 	/// Soft (memory-safe) cast:
417 	/// Cast contents to another type, and returns an instance with that contents.
418 	/// Constness is preserved. No copying is done.
419 	auto asDataOf(U)()
420 	if (is(typeof(this.data.asBytes.as!(U[])) == U[]))
421 	{
422 		TData!U result;
423 		result.data = this.data.asBytes.as!(U[]);
424 		result.memory = this.memory;
425 		if (result.memory)
426 			result.memory.referenceCount++;
427 		return result;
428 	}
429 
430 	/// Hard (normally memory-unsafe) cast:
431 	/// Cast contents to another type, and returns an instance with that contents.
432 	/// The current instance is cleared. U may have an incompatible constness.
433 	/// To enforce memory safety, the current instance must be the only one
434 	/// holding a reference to the data (call `ensureUnique` first).
435 	/// No copying is done.
436 	TData!U castTo(U)()
437 	if (!hasIndirections!U)
438 	{
439 		assertUnique();
440 
441 		TData!U result;
442 		result.data = cast(U[])data;
443 		result.memory = this.memory;
444 		this.data = null;
445 		this.memory = null;
446 		return result;
447 	}
448 
449 	// --- Contents access
450 
451 	private enum enterImpl = q{
452 		// We must make a copy of ourselves to ensure that, should
453 		// `fn` overwrite the `this` instance, the passed contents
454 		// slice remains valid.
455 		auto self = this;
456 		scope data = self.data; // Add `scope` attribute
457 		return fn(data);
458 	};
459 
460 	/// Get temporary access to the data referenced by this Data instance.
461 	// This non-templated overload set exists to allow
462 	// lambda functions (anonymous function templates).
463 	void enter(scope void delegate(scope T[])                          fn)                          { mixin(enterImpl); }
464 	void enter(scope void delegate(scope T[]) @safe                    fn) @safe                    { mixin(enterImpl); } /// ditto
465 	// No pure due to https://issues.dlang.org/show_bug.cgi?id=23959
466 	// void enter(scope void delegate(scope T[])       pure               fn)       pure               { mixin(enterImpl); } /// ditto
467 	// void enter(scope void delegate(scope T[]) @safe pure               fn) @safe pure               { mixin(enterImpl); } /// ditto
468 	void enter(scope void delegate(scope T[])            nothrow       fn)            nothrow       { mixin(enterImpl); } /// ditto
469 	void enter(scope void delegate(scope T[]) @safe      nothrow       fn) @safe      nothrow       { mixin(enterImpl); } /// ditto
470 	// void enter(scope void delegate(scope T[])       pure nothrow       fn)       pure nothrow       { mixin(enterImpl); } /// ditto
471 	// void enter(scope void delegate(scope T[]) @safe pure nothrow       fn) @safe pure nothrow       { mixin(enterImpl); } /// ditto
472 	void enter(scope void delegate(scope T[])                    @nogc fn)                    @nogc { mixin(enterImpl); } /// ditto
473 	void enter(scope void delegate(scope T[]) @safe              @nogc fn) @safe              @nogc { mixin(enterImpl); } /// ditto
474 	// void enter(scope void delegate(scope T[])       pure         @nogc fn)       pure         @nogc { mixin(enterImpl); } /// ditto
475 	// void enter(scope void delegate(scope T[]) @safe pure         @nogc fn) @safe pure         @nogc { mixin(enterImpl); } /// ditto
476 	void enter(scope void delegate(scope T[])            nothrow @nogc fn)            nothrow @nogc { mixin(enterImpl); } /// ditto
477 	void enter(scope void delegate(scope T[]) @safe      nothrow @nogc fn) @safe      nothrow @nogc { mixin(enterImpl); } /// ditto
478 	// void enter(scope void delegate(scope T[])       pure nothrow @nogc fn)       pure nothrow @nogc { mixin(enterImpl); } /// ditto
479 	// void enter(scope void delegate(scope T[]) @safe pure nothrow @nogc fn) @safe pure nothrow @nogc { mixin(enterImpl); } /// ditto
480 
481 	// https://issues.dlang.org/show_bug.cgi?id=23956
482 	// void enter(scope void delegate(scope const(T)[])                          fn) const                          { mixin(enterImpl); }
483 	// void enter(scope void delegate(scope const(T)[]) @safe                    fn) const @safe                    { mixin(enterImpl); }
484 	// void enter(scope void delegate(scope const(T)[])       pure               fn) const       pure               { mixin(enterImpl); }
485 	// void enter(scope void delegate(scope const(T)[]) @safe pure               fn) const @safe pure               { mixin(enterImpl); }
486 	// void enter(scope void delegate(scope const(T)[])            nothrow       fn) const            nothrow       { mixin(enterImpl); }
487 	// void enter(scope void delegate(scope const(T)[]) @safe      nothrow       fn) const @safe      nothrow       { mixin(enterImpl); }
488 	// void enter(scope void delegate(scope const(T)[])       pure nothrow       fn) const       pure nothrow       { mixin(enterImpl); }
489 	// void enter(scope void delegate(scope const(T)[]) @safe pure nothrow       fn) const @safe pure nothrow       { mixin(enterImpl); }
490 	// void enter(scope void delegate(scope const(T)[])                    @nogc fn) const                    @nogc { mixin(enterImpl); }
491 	// void enter(scope void delegate(scope const(T)[]) @safe              @nogc fn) const @safe              @nogc { mixin(enterImpl); }
492 	// void enter(scope void delegate(scope const(T)[])       pure         @nogc fn) const       pure         @nogc { mixin(enterImpl); }
493 	// void enter(scope void delegate(scope const(T)[]) @safe pure         @nogc fn) const @safe pure         @nogc { mixin(enterImpl); }
494 	// void enter(scope void delegate(scope const(T)[])            nothrow @nogc fn) const            nothrow @nogc { mixin(enterImpl); }
495 	// void enter(scope void delegate(scope const(T)[]) @safe      nothrow @nogc fn) const @safe      nothrow @nogc { mixin(enterImpl); }
496 	// void enter(scope void delegate(scope const(T)[])       pure nothrow @nogc fn) const       pure nothrow @nogc { mixin(enterImpl); }
497 	// void enter(scope void delegate(scope const(T)[]) @safe pure nothrow @nogc fn) const @safe pure nothrow @nogc { mixin(enterImpl); }
498 
499 	// For everything else, there is a template overload.
500 	// Note: Dg is a IFTI-inferred parameter due to
501 	// https://issues.dlang.org/show_bug.cgi?id=23955
502 	auto enter(this This, Dg)(scope Dg fn) { mixin(enterImpl); }
503 
504 	/// Put a copy of the data on D's managed heap, and return it.
505 	T[] toGC() const
506 	{
507 		return data.dup;
508 	}
509 
510 	// deprecated alias toHeap = toGC;
511 	// https://issues.dlang.org/show_bug.cgi?id=23954
512 	deprecated T[] toHeap() const { return toGC(); }
513 
514 	/**
515 	   Get the referenced data. Unsafe!
516 
517 	   All operations on the returned contents must be accompanied by
518 	   a live reference to the `Data` object, in order to keep a
519 	   reference towards the Memory owning the contents.
520 
521 	   Be sure not to lose `Data` references while using their contents!
522 	   For example, avoid code like this:
523 	   ----
524 	   getSomeData()        // returns Data
525 		   .unsafeContents  // returns ubyte[]
526 		   .useContents();  // uses the ubyte[] ... while there is no Data to reference it
527 	   ----
528 	   The `Data` return value may be unreachable once `.unsafeContents` is evaluated.
529 	   Use `.toGC` instead of `.unsafeContents` in such cases to safely get a GC-owned copy,
530 	   or use `.enter(contents => ...)` to safely get a temporary reference.
531 	*/
532 	@property inout(T)[] unsafeContents() inout @system { return this.data; }
533 
534 	// deprecated alias contents = unsafeContents;
535 	// https://issues.dlang.org/show_bug.cgi?id=23954
536 	deprecated @property inout(T)[] contents() inout @system { return this.data; }
537 
538 	deprecated @property Unqual!T[] mcontents() @system
539 	{
540 		becomeUnique();
541 		return cast(Unqual!T[])data;
542 	}
543 
544 	// --- Array-like operations
545 
546 	/// 
547 	@property size_t length() const
548 	{
549 		return data.length;
550 	}
551 	alias opDollar = length; /// ditto
552 
553 	deprecated @property inout(T)* ptr() inout { return unsafeContents.ptr; }
554 
555 	deprecated @property Unqual!T* mptr() @system { return mcontents.ptr; }
556 
557 	bool opCast(T)() const
558 		if (is(T == bool))
559 	{
560 		return data !is null;
561 	} ///
562 
563 	/// Return the maximum value that can be set to `length` without causing a reallocation
564 	@property size_t capacity() const
565 	{
566 		if (memory is null)
567 			return length;
568 		// We can only safely expand if the memory slice is at the end of the used unmanaged memory block,
569 		// or, if we are the only reference.
570 		auto dataBytes = this.data.asBytes;
571 		auto pos = memory.contents.sliceIndex(dataBytes); // start position in memory data in bytes
572 		auto end = pos + dataBytes.length;                // end   position in memory data in bytes
573 		assert(end <= memory.size);
574 		if ((end == memory.size || memory.referenceCount == 1) && end < memory.capacity)
575 			return (memory.capacity - pos) / T.sizeof; // integer division truncating towards zero
576 		else
577 			return length;
578 	}
579 
580 	/// Resize contents
581 	@property void length(size_t newLength)
582 	{
583 		if (newLength == length) // no change
584 			return;
585 		if (newLength < length)  // shorten
586 		{
587 			if (!newLength)
588 				this = TData(emptySlice!T);
589 			else
590 				data = data[0..newLength];
591 		}
592 		else                 // lengthen
593 			expand(newLength, newLength, (contents) {
594 				static if (!is(Unqual!T == void))
595 					contents[] = T.init;
596 			});
597 	}
598 
599 	/// Create a copy of the data
600 	@property This dup(this This)()
601 	{
602 		return This(this.data);
603 	}
604 
605 	/// Create a new `Data` containing the concatenation of `this` and `data`.
606 	/// Does not preallocate for successive appends.
607 	template opBinary(string op) if (op == "~")
608 	{
609 		TData opBinary(Appendable data)
610 		{
611 			return concat(data);
612 		} ///
613 
614 		TData opBinary(TData data)
615 		{
616 			return concat(data.data);
617 		} ///
618 
619 		static if (!is(Unqual!T == void))
620 		TData opBinary(T value)
621 		{
622 			return concat((&value)[0..1]);
623 		} ///
624 
625 		static if (is(T == ubyte))
626 		deprecated TData opBinary(const(void)[] data)
627 		{
628 			return concat(cast(Appendable)data);
629 		}
630 	}
631 
632 	/// Create a new `Data` containing the concatenation of `data` and `this`.
633 	/// Does not preallocate for successive appends.
634 	template opBinaryRight(string op) if (op == "~")
635 	{
636 		TData opBinaryRight(Appendable data)
637 		{
638 			return prepend(data);
639 		} ///
640 
641 		static if (!is(Unqual!T == void))
642 		TData opBinaryRight(T value)
643 		{
644 			return prepend((&value)[0..1]);
645 		} ///
646 
647 		static if (is(T == ubyte))
648 		deprecated TData opBinaryRight(const(void)[] data)
649 		{
650 			return prepend(cast(Appendable)data);
651 		}
652 	}
653 
654 	/// Append data to this `Data`.
655 	/// Unlike concatenation (`a ~ b`), appending (`a ~= b`) will preallocate.
656 	template opOpAssign(string op) if (op == "~")
657 	{
658 		TData opOpAssign(Appendable data)
659 		{
660 			return append(data);
661 		} ///
662 
663 		TData opOpAssign(TData data)
664 		{
665 			return append(data.data);
666 		} ///
667 
668 		static if (!is(Unqual!T == void))
669 		TData opOpAssign(T value)
670 		{
671 			return append((&value)[0..1]);
672 		} ///
673 
674 		static if (is(T == ubyte))
675 		deprecated TData opOpAssign(const(void)[] data)
676 		{
677 			return append(cast(Appendable)data);
678 		}
679 	}
680 
681 	/// Access an individual item.
682 	static if (!is(Unqual!T == void))
683 	T opIndex(size_t index)
684 	{
685 		return data[index];
686 	}
687 
688 	/// Write an individual item.
689 	static if (is(typeof(data[0] = T.init)))
690 	T opIndexAssign(T value, size_t index)
691 	{
692 		return data[index] = value;
693 	}
694 
695 	/// Returns a `Data` pointing at a slice of this `Data`'s contents.
696 	TData opSlice()
697 	{
698 		return this;
699 	}
700 
701 	/// ditto
702 	TData opSlice(size_t x, size_t y)
703 	in
704 	{
705 		assert(x <= y);
706 		assert(y <= length);
707 	}
708 	out(result)
709 	{
710 		assert(result.length == y-x);
711 	}
712 	do
713 	{
714 		if (x == y)
715 			return TData(emptySlice!T);
716 		else
717 		{
718 			TData result = this;
719 			result.data = result.data[x .. y];
720 			return result;
721 		}
722 	}
723 
724 	package(ae) // TODO: is this a good API?
725 	sizediff_t indexOf(const(T)[] needle) const
726 	{
727 		static if (is(typeof(imported!q{ae.utils.array}.indexOf(this.data, needle))))
728 			return imported!q{ae.utils.array}.indexOf(this.data, needle);
729 		else
730 		static if (is(typeof(imported!q{std..string}.indexOf(this.data, needle))))
731 			return imported!q{std..string}.indexOf(this.data, needle);
732 		else
733 		{
734 			if (this.data.length >= needle.length)
735 				foreach (i; 0 .. this.data.length - needle.length + 1)
736 					if (this.data[i .. i + needle.length] == needle)
737 						return i;
738 			return -1;
739 		}
740 	}
741 
742 	package(ae) // ditto
743 	static if (is(T == ubyte))
744 	deprecated sizediff_t indexOf(const(void)[] needle) const
745 	{
746 		return indexOf(cast(const(ubyte)[])needle);
747 	}
748 
749 	// --- Range operations
750 
751 	/// Range primitive.
752 	@property bool empty() const { return length == 0; }
753 	static if (!is(Unqual!T == void))
754 	T front() { return data[0]; } ///
755 	void popFront() { data = data[1 .. $]; } ///
756 
757 	// /// Return a new `Data` for the first `size` bytes, and slice this instance from size to end.
758 	// Data popFront(size_t size)
759 	// in
760 	// {
761 	// 	assert(size <= length);
762 	// }
763 	// do
764 	// {
765 	// 	Data result = this;
766 	// 	result.contents = contents[0..size];
767 	// 	this  .contents = contents[size..$];
768 	// 	return result;
769 	// }
770 }
771 
772 unittest
773 {
774 	import core.exception : AssertError;
775 	import core.memory : GC;
776 	import std.exception : assertThrown;
777 	import ae.utils.array : emptySlice;
778 
779 	alias AliasSeq(TList...) = TList;
780 	foreach (B; AliasSeq!(ubyte, uint, char, void))
781 	{
782 		alias Ts = AliasSeq!(B, const(B), immutable(B));
783 		foreach (T; Ts)
784 		{
785 			// Template instantiation
786 			{
787 				TData!T d;
788 				cast(void) d;
789 			}
790 			// .enter type
791 			{
792 				TData!T d;
793 				d.enter((scope contents) { T[] _ = contents; });
794 			}
795 			// .enter with functors
796 			{
797 				import ae.utils.functor.primitives : functor;
798 				TData!T d;
799 				d.enter(functor!((contents) {
800 					assert(contents == d.unsafeContents);
801 				}));
802 			}
803 			// // .enter with const
804 			// {
805 			// 	const TData!T d;
806 			// 	d.enter((scope contents) { const T[] _ = contents; });
807 			// }
808 			// .enter with return value
809 			{
810 				TData!T d;
811 				auto l = d.enter((T[] contents) => contents.length);
812 				assert(l == d.length);
813 			}
814 			// Construction from typeof(null)
815 			{
816 				auto d = TData!T(null);
817 				assert(d.length == 0);
818 				assert(d.unsafeContents.ptr is null);
819 			}
820 			// Construction from null slice
821 			{
822 				T[] arr = null;
823 				auto d = TData!T(arr);
824 				assert(d.length == 0);
825 				assert(d.unsafeContents.ptr is null);
826 			}
827 			// Construction from non-null empty
828 			{
829 				auto d = TData!T(emptySlice!T());
830 				assert(d.length == 0);
831 				assert(d.unsafeContents.ptr !is null);
832 			}
833 			// Construction from non-empty non-GC slice
834 			{
835 				T[5] arr = void;
836 				assert(GC.addrOf(arr.ptr) is null);
837 				auto d = TData!T(arr[]);
838 				assert(d.length == 5);
839 				assert(d.unsafeContents.ptr !is null);
840 				assert(GC.addrOf(d.unsafeContents.ptr) is null);
841 			}
842 			// Construction from non-empty GC slice
843 			{
844 				T[] arr = new T[5];
845 				assert(GC.addrOf(arr.ptr) !is null);
846 				auto d = TData!T(arr);
847 				assert(d.length == 5);
848 				assert(d.unsafeContents.ptr !is null);
849 				assert(GC.addrOf(d.unsafeContents.ptr) is null);
850 			}
851 			// wrapGC from GC slice
852 			static if (useGC)
853 			{{
854 				T[] arr = new T[5];
855 				auto d = TData!T.wrapGC(arr);
856 				assert(d.length == 5);
857 				assert(d.unsafeContents.ptr is arr.ptr);
858 			}}
859 			// wrapGC from non-GC slice
860 			static if (useGC)
861 			{{
862 				static T[5] arr = void;
863 				assertThrown!AssertError(TData!T.wrapGC(arr[]));
864 			}}
865 			// .capacity
866 			{
867 				T[] arr = new T[5];
868 				auto d = TData!T(arr);
869 				assert(d.capacity >= 5);
870 				auto d2 = d[0 .. 3];
871 				assert(d2.capacity == 3);
872 				d = null;
873 				assert(d2.capacity >= 5); // Sole reference; safe to expand over old data
874 			}
875 
876 			// Try a bunch of operations with different kinds of instances
877 			static T[5] arr = void;
878 			TData!T delegate()[] generators = [
879 				delegate () => TData!T(),
880 				delegate () => TData!T(null),
881 				delegate () => TData!T(T[].init),
882 				delegate () => TData!T(arr[]),
883 				delegate () => TData!T(arr[0 .. 0]),
884 				delegate () => TData!T(arr[].dup),
885 				delegate () => TData!T(arr[].dup[0 .. 0]),
886 			];
887 			static if (useGC)
888 				generators ~= [
889 					delegate () => TData!T.wrapGC(arr[].dup),
890 					delegate () => TData!T.wrapGC(arr[].dup[0 .. 0]),
891 				];
892 			static if (is(B == void))
893 				foreach (B2; AliasSeq!(ubyte, uint, char, void))
894 					foreach (T2; AliasSeq!(B2, const(B2), immutable(B2)))
895 						static if (is(typeof({ T2[] u; T[] t = u; })))
896 						{
897 							static T2[5] arr2 = void;
898 							generators ~= [
899 								delegate () => TData!T(T2[].init),
900 								delegate () => TData!T(arr2[]),
901 								delegate () => TData!T(arr2[0 .. 0]),
902 								delegate () => TData!T(arr2[].dup),
903 								delegate () => TData!T(arr2[].dup[0 .. 0]),
904 							];
905 							static if (useGC)
906 								generators ~= [
907 									delegate () => TData!T.wrapGC(arr2[].dup),
908 								//	delegate () => TData!T.wrapGC(arr2[].dup[0 .. 0]), // TODO: why not?
909 								];
910 						}
911 			foreach (generator; generators)
912 			{
913 				// General coherency
914 				{
915 					auto d = generator();
916 					auto length = d.length;
917 					auto contents = d.unsafeContents;
918 					assert(contents.length == length);
919 					size_t entered;
920 					d.enter((enteredContents) {
921 						assert(enteredContents is contents);
922 						entered++;
923 					});
924 					assert(entered == 1);
925 					assert(d.dup.unsafeContents == contents);
926 				}
927 				// Lifetime with .enter
928 				{
929 					auto d = generator();
930 					d.enter((contents) {
931 						d = typeof(d)(null);
932 						(cast(ubyte[])contents)[] = 42;
933 					});
934 				}
935 				// toGC
936 				{
937 					auto d = generator();
938 					auto contents = d.unsafeContents;
939 					assert(d.toGC() == contents);
940 				}
941 				// In-place expansion (resize to capacity)
942 				{
943 					auto d = generator();
944 					auto oldContents = d.unsafeContents;
945 					d.length = d.capacity;
946 					assert(d.unsafeContents.ptr == oldContents.ptr);
947 				}
948 				// Copying expansion (resize past capacity)
949 				{
950 					auto d = generator();
951 					auto oldContents = d.unsafeContents;
952 					d.length = d.capacity + 1;
953 					assert(d.unsafeContents.ptr != oldContents.ptr);
954 				}
955 				// Concatenation
956 				{
957 					void test(L, R)(L left, R right)
958 					{
959 						{
960 							auto result = left ~ right;
961 							assert(result.length == left.length + right.length);
962 							// TODO: test contents, need opEquals?
963 						}
964 						static if (!is(Unqual!T == void))
965 						{
966 							if (left.length)
967 							{
968 								auto result = left[0] ~ right;
969 								assert(result.length == 1 + right.length);
970 							}
971 							if (right.length)
972 							{
973 								auto result = left ~ right[0];
974 								assert(result.length == left.length + 1);
975 							}
976 						}
977 					}
978 
979 					foreach (generator2; generators)
980 					{
981 						test(generator(), generator2());
982 						test(generator().toGC, generator2());
983 						test(generator(), generator2().toGC);
984 					}
985 				}
986 				// Appending
987 				{
988 					void test(L, R)(L left, R right)
989 					{
990 						{
991 							auto result = left;
992 							result ~= right;
993 							assert(result.length == left.length + right.length);
994 							// TODO: test contents, need opEquals?
995 						}
996 						static if (!is(Unqual!T == void))
997 						{
998 							if (right.length)
999 							{
1000 								auto result = left;
1001 								result ~= right[0];
1002 								assert(result.length == left.length + 1);
1003 							}
1004 						}
1005 					}
1006 
1007 					foreach (generator2; generators)
1008 					{
1009 						test(generator(), generator2());
1010 						// test(generator().toGC, generator2());
1011 						test(generator(), generator2().toGC);
1012 					}
1013 				}
1014 				// Slicing to zero
1015 				{
1016 					auto l = generator().length;
1017 					foreach (n; [0, l/2, l])
1018 					{
1019 						auto d = generator();
1020 						d = d[n .. n];
1021 						assert(d == d);
1022 					}
1023 				}
1024 				// Shrinking to zero
1025 				{
1026 					auto d = generator();
1027 					d.length = 0;
1028 					assert(d == d);
1029 				}
1030 				// Reference count
1031 				{
1032 					auto d = generator();
1033 					if (d.memory)
1034 					{
1035 						assert(d.memory.referenceCount == 1);
1036 						{
1037 							auto s = d[1..4];
1038 							assert(d.memory.referenceCount == 2);
1039 							cast(void) s;
1040 						}
1041 						assert(d.memory.referenceCount == 1);
1042 					}
1043 				}
1044 			}
1045 
1046 			// Test effects of construction from various sources
1047 			{
1048 				void testSource(S)(S s)
1049 				{
1050 					void testData(TData!T d)
1051 					{
1052 						// Test true-ish-ness
1053 						assert(!! s == !! d);
1054 						// Test length
1055 						static if (is(typeof(s.length)))
1056 							assert(s.length * s[0].sizeof == d.length * T.sizeof);
1057 						// Test content
1058 						assert(s == d.unsafeContents);
1059 					}
1060 					// Construction
1061 					testData(TData!T(s));
1062 					// wrapGC
1063 					static if (useGC)
1064 						static if (is(typeof(*s.ptr) == T))
1065 							if (GC.addrOf(s.ptr))
1066 								testData(TData!T.wrapGC(s));
1067 					// Appending
1068 					{
1069 						TData!T d;
1070 						d ~= s;
1071 					}
1072 				}
1073 				testSource(null);
1074 				testSource(T[].init);
1075 				testSource(arr[]);
1076 				testSource(arr[0 .. 0]);
1077 				testSource(arr[].dup);
1078 				testSource(arr[].dup[0 .. 0]);
1079 				testSource(arr[].idup);
1080 				testSource(arr[].idup[0 .. 0]);
1081 				static if (is(B == void))
1082 					foreach (B2; AliasSeq!(ubyte, uint, char, void))
1083 						foreach (T2; AliasSeq!(B2, const(B2), immutable(B2)))
1084 							static if (is(typeof({ T2[] u; T[] t = u; })))
1085 							{
1086 								static T2[5] arr2 = void;
1087 								testSource(T2[].init);
1088 								testSource(arr2[]);
1089 								testSource(arr2[0 .. 0]);
1090 								testSource(arr2[].dup);
1091 								testSource(arr2[].dup[0 .. 0]);
1092 							}
1093 			}
1094 
1095 			foreach (U; Ts)
1096 			{
1097 				// Construction from compatible slice
1098 				{
1099 					U[] u;
1100 					TData!T(u);
1101 					static if (useGC)
1102 						static if (is(typeof({ T[] t = u; })))
1103 							cast(void) TData!T.wrapGC(u);
1104 				}
1105 			}
1106 		}
1107 	}
1108 }
1109 
1110 // pure/@safe/nothrow/@nogc compilation test
1111 // No pure due to https://issues.dlang.org/show_bug.cgi?id=23959
1112 /*pure*/ @safe nothrow @nogc unittest
1113 {
1114 	TData!ubyte d;
1115 	d.enter((scope contents) { ubyte[] _ = contents; });
1116 	d = TData!ubyte(null);
1117 	assert(d.length == 0);
1118 
1119 	ubyte[] arr1 = null;
1120 	d = TData!ubyte(arr1);
1121 
1122 	ubyte[0] arr2;
1123 	d = TData!ubyte(arr2[]);
1124 
1125 	ubyte[5] arr3 = void;
1126 	d = TData!ubyte(arr3[]);
1127 
1128 	d.enter((contents) {
1129 		d = typeof(d)(null);
1130 		(cast(ubyte[])contents)[] = 42;
1131 	});
1132 
1133 	d.length = d.length + 1;
1134 	d.length = d.capacity;
1135 
1136 	d = d ~ d;
1137 	d ~= d;
1138 	d.enter((contents) {
1139 		d = d ~ contents;
1140 		d = contents ~ d;
1141 		d ~= contents;
1142 	});
1143 }
1144 
1145 /// Get the underlying type of a `TData`.
1146 /// (For `Data`, this will be `ubyte`.)
1147 template DataElementType(D)
1148 if (is(D == TData!T, T))
1149 {
1150 	static if (is(D == TData!T, T))
1151 		alias DataElementType = T;
1152 }
1153 static assert(is(DataElementType!Data == ubyte));
1154 
1155 /// The most common use case of manipulating unmanaged memory is
1156 /// working with raw bytes, whether they're received from the network,
1157 /// read from a file, or elsewhere.
1158 alias Data = TData!ubyte;
1159 
1160 // ************************************************************************
1161 
1162 deprecated("legacy transitive import - please `import ae.sys.dataset;`.")
1163 public import ae.sys.dataset : copyTo, joinData, joinToHeap, DataVec, shift, bytes, DataSetBytes;
1164 
1165 deprecated alias DataWrapper = Memory;
1166 
1167 package(ae) // TODO: is this a good API?
1168 T as(T)(Data data)
1169 {
1170 	assert(data.length == T.sizeof, "Incorrect data size");
1171 	return data.asDataOf!T.front;
1172 }
1173 
1174 package(ae) // TODO: is this a good API?
1175 T pop(T)(ref Data data)
1176 {
1177 	assert(data.length >= T.sizeof, "Insufficient bytes in data");
1178 	auto result = data[0 .. T.sizeof].asDataOf!T.front;
1179 	data = data[T.sizeof .. $];
1180 	return result;
1181 }
1182 
1183 // ************************************************************************
1184 
1185 /// Base abstract class which owns a block of memory.
1186 abstract class Memory
1187 {
1188 	sizediff_t referenceCount = 0; /// Reference count.
1189 	abstract @property inout(ubyte)[] contents() inout pure @safe nothrow @nogc; /// The owned memory
1190 	abstract @property size_t size() const pure @safe nothrow @nogc;  /// Length of `contents`.
1191 	abstract void setSize(size_t newSize) pure @safe nothrow @nogc; /// Resize `contents` up to `capacity`.
1192 	abstract @property size_t capacity() const pure @safe nothrow @nogc; /// Maximum possible size.
1193 
1194 	debug ~this() nothrow @nogc
1195 	{
1196 		debug(DATA_REFCOUNT) debugLog("%.*s.~this, referenceCount==%d", this.classinfo.name.length, this.classinfo.name.ptr, referenceCount);
1197 		assert(referenceCount == 0, "Deleting Memory with non-zero reference count");
1198 	}
1199 }
1200 
1201 // ************************************************************************
1202 
1203 package:
1204 
1205 /// How many bytes are currently in `Data`-owned memory.
1206 static /*thread-local*/ size_t dataMemory, dataMemoryPeak;
1207 /// How many `Memory` instances there are live currently.
1208 static /*thread-local*/ uint   dataCount;
1209 /// How many allocations have been done so far.
1210 static /*thread-local*/ uint   allocCount;
1211 
1212 /// Set threshold of allocated memory to trigger a garbage collection.
1213 static if (useGC)
1214 void setGCThreshold(size_t value) { collectThreshold = value; }
1215 
1216 /// Allocate and construct a new class in `malloc`'d memory.
1217 C unmanagedNew(C, Args...)(auto ref Args args) @trusted
1218 if (is(C == class))
1219 {
1220 	import std.conv : emplace;
1221 	enum size = __traits(classInstanceSize, C);
1222 	auto p = unmanagedAlloc(size);
1223 	emplace!C(p[0..size], args);
1224 	return cast(C)p;
1225 }
1226 
1227 /// Delete a class instance created with `unmanagedNew`.
1228 void unmanagedDelete(C)(C c) nothrow @nogc
1229 if (is(C == class))
1230 {
1231 	// Add attributes to object.destroy by cast:
1232 	// - Add @nogc.
1233 	//   Object.~this is not @nogc, but allocating in a destructor crashes the GC anyway,
1234 	//   so all class destructors are already effectively @nogc.
1235 	// - Add pure as well.
1236 	//   Memory implementations may have impure destructors,
1237 	//   such as closing file descriptors for memory-mapped files.
1238 	//   However, implementations SHOULD be pure as far as the program's state is concerned.
1239 	static void callDestroy(C c) nothrow { c.destroy(); }
1240 	// No pure due to: https://issues.dlang.org/show_bug.cgi?id=23959
1241 	(cast(void function(C) /*pure*/ nothrow @nogc) &callDestroy)(c);
1242 
1243 	unmanagedFree(cast(void*)c);
1244 }
1245 
1246 void* unmanagedAlloc(size_t sz) pure nothrow @nogc
1247 {
1248 	import core.stdc.stdlib : malloc;
1249 
1250 	// Cast to add `pure` to malloc.
1251 	// Allocating with `new` is pure, and so should be malloc.
1252 	alias PureMalloc = extern (C) void* function(size_t) pure nothrow @nogc @system;
1253 	auto p = (cast(PureMalloc) &malloc)(sz);
1254 
1255 	debug(DATA_REFCOUNT) debugLog("? -> %p: Allocating via malloc (%d bytes)", p, cast(uint)sz);
1256 
1257 	if (!p)
1258 		//throw new OutOfMemoryError();
1259 		onOutOfMemoryError(); // @nogc
1260 
1261 	//GC.addRange(p, sz);
1262 	return p;
1263 }
1264 
1265 void unmanagedFree(void* p) pure nothrow @nogc
1266 {
1267 	import core.stdc.stdlib : free;
1268 
1269 	if (p)
1270 	{
1271 		debug(DATA_REFCOUNT) debugLog("? -> %p: Deleting via free", p);
1272 
1273 		//GC.removeRange(p);
1274 
1275 		// Cast to add `pure` to free.
1276 		// Same rationale as for malloc.
1277 		alias PureFree = extern (C) void function(void* ptr) pure nothrow @nogc @system;
1278 		(cast(PureFree) &free)(p);
1279 	}
1280 }
1281 
1282 version (Windows)
1283 	import core.sys.windows.windows;
1284 else
1285 {
1286 	import core.sys.posix.unistd;
1287 	import core.sys.posix.sys.mman;
1288 }
1289 
1290 static if (useGC)
1291 {
1292 	/// Threshold of allocated memory to trigger a collect.
1293 	__gshared size_t collectThreshold = 8*1024*1024; // 8MB
1294 	/// Counter towards the threshold.
1295 	/*thread-local*/ size_t allocatedThreshold;
1296 }
1297 
1298 /// Some form of dynamically-allocated memory.
1299 /// Implementation is provided by the Allocator parameter.
1300 /*private*/ class DynamicMemory(Allocator) : Memory
1301 {
1302 	/// Pointer to actual data.
1303 	ubyte* data;
1304 	/// Used size. Needed for safe appends.
1305 	size_t _size;
1306 	/// Allocated capacity.
1307 	size_t _capacity;
1308 
1309 	static if (useGC)
1310 	{
1311 		deprecated alias collectThreshold = .collectThreshold;
1312 		deprecated alias allocatedThreshold = .allocatedThreshold;
1313 	}
1314 
1315 	/// Create a new instance with given capacity.
1316 	this(size_t size, size_t capacity) pure @trusted nothrow @nogc
1317 	{
1318 		// Add attributes to the implementation by cast:
1319 		// - Add pure.
1320 		//   - The implementation is "pure" in the same way that the D
1321 		//     garbage collector is "pure", even though it has global state.
1322 		// - Add @nogc.
1323 		//   - There are a few common use cases for the @nogc attribute:
1324 		//     1. The entire program does not use the GC (and probably does not even link to one).
1325 		//     2. The program does use the GC, but some sections should not
1326 		//        (e.g. they perform only performance-sensitive computations
1327 		//        and accidental GC allocations should be caught and avoided).
1328 		//     3. The code is a library which wants to be usable by either GC or @nogc programs.
1329 		//   - The second case is the most common in my personal experience,
1330 		//     so by default we assume that a GC is present but still offer a @nogc interface.
1331 		//   - We do this to offer better memory usage and reclaim memory faster
1332 		//     when Data instances are on the D GC heap, but are unreferenced.
1333 		//   - To actually use this module without the D GC, compile with -version=ae_data_nogc.
1334 		//   - (Ideally, we would offer both a @nogc and non-@nogc interface,
1335 		//     and let the caller's @nogc-ness select which one is used,
1336 		//     in the same way that the compiler can choose between a @nogc and non-@nogc overload,
1337 		//     however this is not currently feasible to implement.)
1338 		(cast(void delegate(size_t size, size_t capacity) pure @trusted nothrow @nogc)&thisImpl)(size, capacity);
1339 	}
1340 
1341 	private final void thisImpl(size_t size, size_t capacity) @trusted nothrow
1342 	{
1343 		data = cast(ubyte*)Allocator.allocate(/*ref*/ capacity);
1344 		static if (useGC)
1345 			if (data is null)
1346 			{
1347 				debug(DATA) fprintf(stderr, "Garbage collect triggered by failed Data allocation of %llu bytes... ", cast(ulong)capacity);
1348 				GC.collect();
1349 				debug(DATA) fprintf(stderr, "Done\n");
1350 				data = cast(ubyte*)Allocator.allocate(/*ref*/ capacity);
1351 				.allocatedThreshold = 0;
1352 			}
1353 		if (data is null)
1354 			onOutOfMemoryError();
1355 
1356 		dataMemory += capacity;
1357 		if (dataMemoryPeak < dataMemory)
1358 			dataMemoryPeak = dataMemory;
1359 		dataCount ++;
1360 		allocCount ++;
1361 
1362 		this._size = size;
1363 		this._capacity = capacity;
1364 
1365 		static if (useGC)
1366 		{
1367 			// also collect
1368 			.allocatedThreshold += capacity;
1369 			if (.allocatedThreshold > .collectThreshold)
1370 			{
1371 				debug(DATA) fprintf(stderr, "Garbage collect triggered by total allocated Data exceeding threshold... ");
1372 				GC.collect();
1373 				debug(DATA) fprintf(stderr, "Done\n");
1374 				.allocatedThreshold = 0;
1375 			}
1376 		}
1377 	}
1378 
1379 	/// Destructor - destroys the wrapped data.
1380 	~this() @nogc
1381 	{
1382 		Allocator.deallocate(data, capacity);
1383 		data = null;
1384 		// If Memory is created and manually deleted, there is no need to cause frequent collections
1385 		static if (useGC)
1386 		{
1387 			if (.allocatedThreshold > capacity)
1388 				.allocatedThreshold -= capacity;
1389 			else
1390 				.allocatedThreshold = 0;
1391 		}
1392 
1393 		dataMemory -= capacity;
1394 		dataCount --;
1395 	}
1396 
1397 	@property override
1398 	size_t size() const pure @safe nothrow @nogc { return _size; }
1399 
1400 	@property override
1401 	size_t capacity() const pure @safe nothrow @nogc { return _capacity; }
1402 
1403 	override void setSize(size_t newSize) pure @safe nothrow @nogc
1404 	{
1405 		assert(newSize <= capacity);
1406 		_size = newSize;
1407 	}
1408 
1409 	@property override
1410 	inout(ubyte)[] contents() inout pure @trusted nothrow @nogc
1411 	{
1412 		return data[0 .. _size];
1413 	}
1414 }
1415 
1416 // TODO: Maybe use std.experimental.allocator, one day.
1417 // One blocker is that it needs to stop pretending the page size is 4096 everywhere.
1418 
1419 private struct OSAllocator
1420 {
1421 	static immutable size_t pageSize;
1422 
1423 	shared static this()
1424 	{
1425 		version (Windows)
1426 		{
1427 			import core.sys.windows.winbase : GetSystemInfo, SYSTEM_INFO;
1428 
1429 			SYSTEM_INFO si;
1430 			GetSystemInfo(&si);
1431 			pageSize = si.dwPageSize;
1432 		}
1433 		else
1434 		{
1435 			pageSize = sysconf(_SC_PAGE_SIZE);
1436 		}
1437 	}
1438 
1439 	static void* allocate(ref size_t size) /*pure*/ nothrow @nogc
1440 	{
1441 		if (is(typeof(pageSize)))
1442 			size = ((size-1) | (pageSize-1))+1;
1443 
1444 		version(Windows)
1445 		{
1446 			return VirtualAlloc(null, size, MEM_COMMIT, PAGE_READWRITE);
1447 		}
1448 		else
1449 		version(Posix)
1450 		{
1451 			version(linux)
1452 				import core.sys.linux.sys.mman : MAP_ANON;
1453 			auto p = mmap(null, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
1454 			return (p == MAP_FAILED) ? null : p;
1455 		}
1456 		else
1457 			return core.stdc.malloc(size);
1458 	}
1459 
1460 	static void deallocate(void* p, size_t size) @nogc
1461 	{
1462 		debug
1463 		{
1464 			(cast(ubyte*)p)[0..size] = 0xDB;
1465 		}
1466 		version(Windows)
1467 			VirtualFree(p, 0, MEM_RELEASE);
1468 		else
1469 		version(Posix)
1470 			munmap(p, size);
1471 		else
1472 			core.stdc.free(size);
1473 	}
1474 }
1475 
1476 /// Wrapper for data in RAM, allocated from the OS.
1477 alias OSMemory = DynamicMemory!OSAllocator;
1478 
1479 private struct CAllocator
1480 {
1481 	static void* allocate(ref size_t size) /*pure*/ nothrow @nogc
1482 	{
1483 		import core.stdc.stdlib : malloc;
1484 		return malloc(size);
1485 	}
1486 
1487 	static void deallocate(void* p, size_t size) @nogc
1488 	{
1489 		import core.stdc.stdlib : free;
1490 		free(p);
1491 	}
1492 }
1493 
1494 /// Wrapper for data in RAM, allocated from the C standard library.
1495 /// Used for small objects.
1496 alias CMemory = DynamicMemory!CAllocator;
1497 
1498 // ************************************************************************
1499 
1500 debug(DATA_REFCOUNT) import ae.utils.exception, ae.sys.memory, core.stdc.stdio;
1501 
1502 debug(DATA_REFCOUNT) void debugLog(Args...)(const char* s, Args args) @nogc
1503 {
1504 	fprintf(stderr, s, args);
1505 	fprintf(stderr, "\n");
1506 	if (inCollect())
1507 		fprintf(stderr, "\t(in GC collect)\n");
1508 	else
1509 		(cast(void function() @nogc)&debugStackTrace)();
1510 	fflush(core.stdc.stdio.stderr);
1511 }
1512 
1513 debug(DATA_REFCOUNT) void debugStackTrace()
1514 {
1515 	try
1516 		foreach (line; getStackTrace())
1517 			fprintf(stderr, "\t%.*s\n", cast(int)line.length, line.ptr);
1518 	catch (Throwable e)
1519 		fprintf(stderr, "\t(stacktrace error: %.*s)", cast(int)e.msg.length, e.msg.ptr);
1520 }