1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2018, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "TypeHandlerRoster.h"
9
10#include <new>
11
12#include <AutoDeleter.h>
13#include <AutoLocker.h>
14
15#include "AddressValueNode.h"
16#include "ArrayValueNode.h"
17#include "CompoundValueNode.h"
18#include "BListTypeHandler.h"
19#include "BMessageTypeHandler.h"
20#include "CStringTypeHandler.h"
21#include "EnumerationValueNode.h"
22#include "PointerToMemberValueNode.h"
23#include "PrimitiveValueNode.h"
24#include "Type.h"
25#include "TypeHandler.h"
26
27
28static int CompareTypeHandlers(const TypeHandler* a, const TypeHandler* b,
29	void* state)
30{
31	Type* type = (Type*)state;
32	return a->SupportsType(type) > b->SupportsType(type) ? 1 : -1;
33}
34
35
36// #pragma mark - BasicTypeHandler
37
38
39namespace {
40
41
42template<typename TypeClass, typename NodeClass>
43class BasicTypeHandler : public TypeHandler {
44public:
45	virtual const char* Name() const
46	{
47		return "Raw";
48	}
49
50	virtual float SupportsType(Type* type) const
51	{
52		return dynamic_cast<TypeClass*>(type) != NULL ? 0.5f : 0;
53	}
54
55	virtual status_t CreateValueNode(ValueNodeChild* nodeChild,
56		Type* type, ValueNode*& _node)
57	{
58		TypeClass* supportedType = dynamic_cast<TypeClass*>(type);
59		if (supportedType == NULL)
60			return B_BAD_VALUE;
61
62		ValueNode* node = new(std::nothrow) NodeClass(nodeChild, supportedType);
63		if (node == NULL)
64			return B_NO_MEMORY;
65
66		_node = node;
67		return B_OK;
68	}
69};
70
71
72}	// unnamed namespace
73
74
75// #pragma mark - TypeHandlerRoster
76
77
78/*static*/ TypeHandlerRoster* TypeHandlerRoster::sDefaultInstance = NULL;
79
80
81TypeHandlerRoster::TypeHandlerRoster()
82	:
83	fLock("type handler roster")
84{
85}
86
87
88TypeHandlerRoster::~TypeHandlerRoster()
89{
90	for (int32 i = 0; TypeHandler* handler = fTypeHandlers.ItemAt(i); i++)
91		handler->ReleaseReference();
92}
93
94/*static*/ TypeHandlerRoster*
95TypeHandlerRoster::Default()
96{
97	return sDefaultInstance;
98}
99
100
101/*static*/ status_t
102TypeHandlerRoster::CreateDefault()
103{
104	if (sDefaultInstance != NULL)
105		return B_OK;
106
107	TypeHandlerRoster* roster = new(std::nothrow) TypeHandlerRoster;
108	if (roster == NULL)
109		return B_NO_MEMORY;
110	ObjectDeleter<TypeHandlerRoster> rosterDeleter(roster);
111
112	status_t error = roster->Init();
113	if (error != B_OK)
114		return error;
115
116	error = roster->RegisterDefaultHandlers();
117	if (error != B_OK)
118		return error;
119
120	sDefaultInstance = rosterDeleter.Detach();
121	return B_OK;
122}
123
124
125/*static*/ void
126TypeHandlerRoster::DeleteDefault()
127{
128	TypeHandlerRoster* roster = sDefaultInstance;
129	sDefaultInstance = NULL;
130	delete roster;
131}
132
133
134status_t
135TypeHandlerRoster::Init()
136{
137	return fLock.InitCheck();
138}
139
140
141status_t
142TypeHandlerRoster::RegisterDefaultHandlers()
143{
144	TypeHandler* handler;
145	BReference<TypeHandler> handlerReference;
146
147	#undef REGISTER_BASIC_HANDLER
148	#define REGISTER_BASIC_HANDLER(name)						\
149		handler = new(std::nothrow)								\
150			BasicTypeHandler<name##Type, name##ValueNode>();	\
151		handlerReference.SetTo(handler, true);					\
152		if (handler == NULL || !RegisterHandler(handler))		\
153			return B_NO_MEMORY;
154
155	REGISTER_BASIC_HANDLER(Address);
156	REGISTER_BASIC_HANDLER(Array);
157	REGISTER_BASIC_HANDLER(Compound);
158	REGISTER_BASIC_HANDLER(Enumeration);
159	REGISTER_BASIC_HANDLER(PointerToMember);
160	REGISTER_BASIC_HANDLER(Primitive);
161
162	#undef REGISTER_SPECIALIZED_HANDLER
163	#define REGISTER_SPECIALIZED_HANDLER(name)					\
164		handler = new(std::nothrow)								\
165			name##TypeHandler();								\
166		handlerReference.SetTo(handler, true);					\
167		if (handler == NULL || !RegisterHandler(handler))		\
168			return B_NO_MEMORY;
169
170	REGISTER_SPECIALIZED_HANDLER(CString);
171	REGISTER_SPECIALIZED_HANDLER(BMessage);
172	REGISTER_SPECIALIZED_HANDLER(BList);
173
174	return B_OK;
175}
176
177
178int32
179TypeHandlerRoster::CountTypeHandlers(Type* type)
180{
181	AutoLocker<BLocker>  locker(fLock);
182
183	int32 count = 0;
184	for (int32 i = 0; TypeHandler* handler = fTypeHandlers.ItemAt(i); i++) {
185		if (handler->SupportsType(type) > 0)
186			++count;
187	}
188
189	return count;
190}
191
192
193status_t
194TypeHandlerRoster::FindBestTypeHandler(ValueNodeChild* nodeChild, Type* type,
195	TypeHandler*& _handler)
196{
197	// find the best-supporting handler
198	AutoLocker<BLocker> locker(fLock);
199
200	TypeHandler* bestHandler = NULL;
201	float bestSupport = 0;
202
203	for (int32 i = 0; TypeHandler* handler = fTypeHandlers.ItemAt(i); i++) {
204		float support = handler->SupportsType(type);
205		if (support > 0 && support > bestSupport) {
206			bestHandler = handler;
207			bestSupport = support;
208		}
209	}
210
211	if (bestHandler == NULL)
212		return B_ENTRY_NOT_FOUND;
213
214	bestHandler->AcquireReference();
215	_handler = bestHandler;
216	return B_OK;
217}
218
219
220status_t
221TypeHandlerRoster::FindTypeHandlers(ValueNodeChild* nodeChild, Type* type,
222	TypeHandlerList*& _handlers)
223{
224	// find the best-supporting handler
225	AutoLocker<BLocker> locker(fLock);
226
227	TypeHandlerList* handlers = new(std::nothrow) TypeHandlerList(10, false);
228	ObjectDeleter<TypeHandlerList> listDeleter(handlers);
229	if (handlers == NULL)
230		return B_NO_MEMORY;
231
232	for (int32 i = 0; TypeHandler* handler = fTypeHandlers.ItemAt(i); i++) {
233		if (handler->SupportsType(type) > 0) {
234			if (!handlers->AddItem(handler))
235				return B_NO_MEMORY;
236		}
237	}
238
239	if (handlers->CountItems() == 0)
240		return B_ENTRY_NOT_FOUND;
241
242	for (int32 i = 0; TypeHandler* handler = handlers->ItemAt(i); i++)
243		handler->AcquireReference();
244
245	handlers->SortItems(CompareTypeHandlers, type);
246
247	_handlers = handlers;
248	listDeleter.Detach();
249
250	return B_OK;
251}
252
253
254status_t
255TypeHandlerRoster::CreateValueNode(ValueNodeChild* nodeChild, Type* type,
256	TypeHandler* handler, ValueNode*& _node)
257{
258	BReference<TypeHandler> handlerReference;
259
260	// if the caller doesn't supply us with a handler to use, try to find
261	// the best match.
262	if (handler == NULL) {
263		// find the best-supporting handler
264		while (true) {
265			status_t error = FindBestTypeHandler(nodeChild, type, handler);
266			if (error == B_OK) {
267				handlerReference.SetTo(handler, true);
268				break;
269			}
270
271			// not found yet -- try to strip a modifier/typedef from the type
272			Type* nextType = type->ResolveRawType(true);
273			if (nextType == NULL || nextType == type)
274				return B_UNSUPPORTED;
275
276			type = nextType;
277		}
278	}
279
280	return handler->CreateValueNode(nodeChild, type, _node);
281}
282
283
284bool
285TypeHandlerRoster::RegisterHandler(TypeHandler* handler)
286{
287	if (!fTypeHandlers.AddItem(handler))
288		return false;
289
290	handler->AcquireReference();
291	return true;
292}
293
294
295void
296TypeHandlerRoster::UnregisterHandler(TypeHandler* handler)
297{
298	if (fTypeHandlers.RemoveItem(handler))
299		handler->ReleaseReference();
300}
301