Last active
March 17, 2016 18:15
-
-
Save JakobOvrum/49e6af2e9034a50c2a91 to your computer and use it in GitHub Desktop.
Factory implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import std.traits : FunctionAttribute; | |
private string faToString(FunctionAttribute fa) | |
{ | |
import std.algorithm, std.traits; | |
string result; | |
foreach (member; __traits(derivedMembers, FunctionAttribute)) | |
{ | |
if (fa & __traits(getMember, FunctionAttribute, member)) | |
result ~= (member.endsWith("_")? member.stripRight('_') : '@' ~ member) ~ " "; | |
} | |
return result; | |
} | |
// TODO: implicit conversion != inheritance | |
// TODO: emplace for classes that can propagate attributes | |
// TODO: Array.insertBack is not @nogc? Exceptions? | |
// TODO: binary search | |
// TODO: ignore subsequent registration attempts | |
// TODO: support shared instances | |
// TODO: parameterized construction | |
struct Factory(Base, Allocator, FunctionAttribute constructionAttributes = FunctionAttribute.none) | |
if (is(Base == class) || is(Base == interface)) | |
{ | |
import std.container.array : Array; | |
import std.meta; | |
import std.typecons : Tuple; | |
import std.traits; | |
private: | |
mixin("alias Constructor = Base function(void[]) " ~ faToString(constructionAttributes) ~ ";"); | |
alias Producer = Tuple!(string, "fqn", size_t, "size", Constructor, "ctor"); | |
Array!Producer producers; | |
public: | |
static if (is(typeof(Allocator.instance))) | |
private alias alloc = Allocator.instance; | |
else | |
{ | |
private Allocator alloc; | |
@disable this(); | |
this(Allocator alloc) | |
{ | |
this.alloc = alloc; | |
} | |
} | |
void register(Ts...)() | |
if (allSatisfy!(applyRight!(isImplicitlyConvertible, Base), Ts)) | |
{ | |
import std.conv, std.meta, std.traits; | |
auto producer(T) = Producer( | |
fullyQualifiedName!T, | |
__traits(classInstanceSize, T), | |
buffer => emplace!T(buffer)); | |
alias Deduplicated = NoDuplicates!Ts; | |
Producer[Deduplicated.length] newEntries = [staticMap!(producer, Deduplicated)]; | |
producers.insertBack(newEntries[]); | |
} | |
Base make()(in char[] fqn) | |
{ | |
import std.algorithm.searching : find; | |
auto search = producers[].find!((producer, fqn) => producer.fqn == fqn)(fqn); | |
if (search.empty) return null; | |
return search.front.ctor(alloc.allocate(search.front.size)); | |
} | |
void dispose(T : Base)(ref T o) | |
{ | |
import std.experimental.allocator : dispose; | |
alloc.dispose(o); | |
o = null; | |
} | |
} | |
unittest | |
{ | |
import std.experimental.allocator.mallocator; | |
import std.traits : fullyQualifiedName; | |
interface Identifiable | |
{ | |
string id(); | |
} | |
Factory!(Identifiable, Mallocator) myFactory; | |
static class A : Identifiable | |
{ | |
string id() { return "foo"; } | |
} | |
static class B : Identifiable | |
{ | |
string id_; | |
this() { this.id_ = "bar"; } | |
string id() { return id_; } | |
} | |
myFactory.register!(A, B); | |
auto a = myFactory.make(fullyQualifiedName!A); | |
assert(a); | |
assert(a.id == "foo"); | |
myFactory.dispose(a); | |
assert(a is null); | |
auto b = myFactory.make(fullyQualifiedName!B); | |
assert(b); | |
assert(b.id == "bar"); | |
myFactory.dispose(b); | |
assert(b is null); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment