-
Notifications
You must be signed in to change notification settings - Fork 17
/
CreationRules.h
78 lines (67 loc) · 2.31 KB
/
CreationRules.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
#pragma once
#include "autowiring_error.h"
#include "ContextMember.h"
#include "has_simple_constructor.h"
#include "has_static_new.h"
#include "SlotInformation.h"
#include TYPE_TRAITS_HEADER
#include RVALUE_HEADER
#include <new>
template<typename T>
struct is_injectable
{
static const bool value = has_simple_constructor<T>::value || has_static_new<T>::value;
};
/// <summary>
/// Simple structure to centralize knowledge about how to create types with various declarations
/// </summary>
struct CreationRules {
template<typename U, typename... Args>
static typename std::enable_if<has_static_new<U, Args...>::value, U*>::type New(Args&&... args) {
auto retVal = U::New(std::forward<Args>(args)...);
static_assert(
std::is_convertible<decltype(retVal), U*>::value,
"Attempted to create T using T::New, but the type of T::New() is not derived from T"
);
return retVal;
}
template<typename U, typename... Args>
static typename std::enable_if<!has_static_new<U, Args...>::value, U*>::type New(Args&&... args) {
static_assert(!std::is_abstract<U>::value, "Cannot create a type which is abstract");
static_assert(!has_static_new<U, Args...>::value, "Can't inject member with arguments if it has a static New");
// Allocate slot first before registration
auto* pSpace = Allocate<U>(nullptr);
try {
// Stack location and placement new in one expression
return
SlotInformationStackLocation::PushStackLocation<U>(pSpace),
::new (pSpace) U(std::forward<Args>(args)...);
}
catch(...) {
// Don't want memory leaks--but we also want to avoid calling the destructor, here, so we cast to void before freeing
Free<U>(pSpace, nullptr);
throw;
}
}
template<void* (*)(size_t)>
struct alloc_fn {};
template<typename U>
static U* Allocate(alloc_fn<&U::operator new>*) {
return (U*) U::operator new(sizeof(U));
}
template<typename U>
static U* Allocate(...) {
return (U*) ::operator new(sizeof(U));
}
template<void(*)(void*)>
struct free_fn {};
template<typename U>
static void Free(void* ptr, free_fn<&U::operator delete>*) {
U::operator delete(ptr);
}
template<typename U>
static void Free(void* ptr, ...) {
::operator delete(ptr);
}
};