-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathKiwi_Loader.hpp
158 lines (140 loc) · 4.29 KB
/
Kiwi_Loader.hpp
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//
// Kiwi_External.h
// Kiwi_External
//
// Created by Pierre on 04/04/2018.
// Copyright © 2018 Pierre. All rights reserved.
//
#pragma once
#include "Kiwi_External.hpp"
#include <map>
#include <set>
#include <cassert>
#ifdef _WIN32
#include <windows.h>
#include <stdio.h>
#define KIWI_PATH_SEPARATOR "\\"
#else
#include <dlfcn.h>
#define KIWI_PATH_SEPARATOR "/"
#endif
namespace kiwi
{
namespace external
{
class Loader
{
public:
static Object* create(std::string const& path, std::string const& name)
{
const std::string fullpath = path.empty() ? name + ".kiwix" : path + KIWI_PATH_SEPARATOR + name + ".kiwix";
auto& olib = get().libs[fullpath];
if(!olib.lib)
{
#ifdef _WIN32
lib_t lib_handle = LoadLibrary(TEXT(fullpath.c_str()));
#else
lib_t lib_handle = dlopen(fullpath.c_str(), RTLD_LOCAL|RTLD_LAZY);
#endif
if (!lib_handle)
{
throw kerror_t(std::string("Unable to open library: ") + fullpath);
}
else
{
olib.lib = lib_handle;
}
}
if(!olib.ctor)
{
#ifdef _WIN32
object_creator* ctor = (object_creator*)GetProcAddress(olib.lib, "create_object");
#else
object_creator* ctor = (object_creator*)dlsym(olib.lib, "create_object");
#endif
if(!ctor)
{
throw kerror_t(std::string("Unable to find create_object method from: ") + fullpath);
}
else
{
olib.ctor = ctor;
}
}
if(!olib.dspr)
{
#ifdef _WIN32
object_disposer* dspr = (object_disposer*)GetProcAddress(olib.lib, "free_object");
#else
object_disposer* dspr = (object_disposer*)dlsym(olib.lib, "free_object");
#endif
if(!dspr)
{
throw kerror_t(std::string("Unable to find free_object method from: ") + fullpath);
}
else
{
olib.dspr = dspr;
}
}
Object* obj = olib.ctor();
if(obj)
{
olib.objs.insert(obj);
}
return obj;
}
static void dispose(Object* obj)
{
for(auto& olib : get().libs)
{
const size_t n = olib.second.objs.size();
if(olib.second.objs.erase(obj))
{
olib.second.dspr(obj);
assert(olib.second.objs.size() == n-1);
return;
}
}
throw kerror_t("can't find the disposer.");
}
~Loader()
{
for(auto& olib : libs)
{
if(olib.second.lib)
{
#ifdef _WIN32
FreeLibrary(olib.second.lib);
#else
if (dlclose(olib.second.lib) != 0)
{
}
#endif
}
assert(olib.second.objs.empty() && "objects not freed");
}
}
private:
static Loader& get()
{
static Loader singleton;
return singleton;
}
#ifdef _WIN32
typedef HINSTANCE lib_t;
#else
typedef void* lib_t;
#endif
struct object_lib
{
lib_t lib = nullptr;
object_creator* ctor = nullptr;
object_disposer* dspr = nullptr;
std::set<Object*> objs;
};
std::map<std::string, object_lib> libs;
};
}
}
#undef KIWI_PATH_SEPARATOR