2009-10-09 Chris Toshok <toshok@ximian.com>
[moon.git] / src / type.cpp
blob7ff8c92419ed0102ab4420e9d8f7eb1f3563516e
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * type.cpp: Our type system
5 * Contact:
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
14 #include <config.h>
15 #include <string.h>
16 #include <stdlib.h>
18 #include "type.h"
19 #include "runtime.h"
20 #include "deployment.h"
21 #include "dependencyproperty.h"
24 * Type implementation
26 Type::Type (Type::Kind type, Type::Kind parent, bool is_value_type, bool is_interface,
27 const char *name,
28 int event_count, int total_event_count, const char **events,
29 int interface_count, const Type::Kind *interfaces, bool ctor_visible,
30 create_inst_func *create_inst, const char *content_property)
32 this->type = type;
33 this->parent = parent;
34 this->is_value_type = is_value_type;
35 this->is_interface = is_interface;
36 this->name = name;
37 this->event_count = event_count;
38 this->total_event_count = total_event_count;
39 this->events = events;
40 this->ctor_visible = ctor_visible;
41 this->create_inst = create_inst;
42 this->content_property = content_property;
43 this->properties = NULL;
44 this->interface_count = interface_count;
45 if (this->interface_count) {
46 this->interfaces = new Type::Kind[interface_count];
47 memcpy (this->interfaces, interfaces, interface_count * sizeof (Type::Kind));
49 else {
50 this->interfaces = NULL;
54 Type::~Type ()
56 if (properties) {
57 g_hash_table_destroy (properties);
58 properties = NULL;
61 delete [] interfaces;
64 const char *
65 Type::LookupEventName (int id)
67 Type *parent_type = Type::Find (parent);
68 int parent_event_count = (parent_type == NULL ? 0 : parent_type->total_event_count);
69 int current_id;
70 const char *result;
72 if (id < 0)
73 return "";
75 if (events != NULL) {
76 for (int i = 0; events [i] != NULL; i++) {
77 current_id = i + parent_event_count;
78 if (current_id == id)
79 return events [i];
83 if (parent == Type::INVALID || parent_type == NULL) {
84 printf ("Event lookup of event id %i in type '%s' failed.\n", id, name);
85 return NULL;
88 result = parent_type->LookupEventName (id);
90 if (result == NULL)
91 printf ("Event lookup of event %i in (more exactly) type '%s' failed.\n", id, name);
93 return result;
96 int
97 Type::LookupEvent (const char *event_name)
99 Type *parent_type = Type::Find (parent);
100 int result;
102 if (events != NULL) {
103 for (int i = 0; events [i] != NULL; i++) {
104 if (!g_ascii_strcasecmp (events [i], event_name))
105 return i + (parent_type == NULL ? 0 : parent_type->total_event_count);
109 if (parent == Type::INVALID || parent_type == NULL) {
110 printf ("Event lookup of event '%s' in type '%s' failed.\n", event_name, name);
111 return -1;
114 result = parent_type->LookupEvent (event_name);
116 if (result == -1)
117 printf ("Event lookup of event '%s' in (more exactly) type '%s' failed.\n", event_name, name);
119 return result;
122 bool
123 Type::IsSubclassOf (Deployment *deployment, Type::Kind type, Type::Kind super)
125 return deployment->GetTypes ()->IsSubclassOf (type, super);
128 bool
129 Type::IsSubclassOf (Type::Kind type, Type::Kind super)
131 return IsSubclassOf (Deployment::GetCurrent (), type, super);
134 bool
135 Type::IsSubclassOf (Deployment *deployment, Type::Kind super)
137 return deployment->GetTypes ()->IsSubclassOf (type, super);
140 bool
141 Type::IsSubclassOf (Type::Kind super)
143 return IsSubclassOf (Deployment::GetCurrent (), type, super);
146 bool
147 Types::IsSubclassOrSuperclassOf (Type::Kind unknown, Type::Kind known)
149 return IsSubclassOf(unknown, known) || IsSubclassOf (known, unknown);
152 bool
153 Types::IsSubclassOrSuperclassOf (Types *arg, Type::Kind unknown, Type::Kind known)
155 Types *types = arg == NULL ? Deployment::GetCurrent ()->GetTypes () : arg;
156 return types->IsSubclassOf(unknown, known) || types->IsSubclassOf (known, unknown);
160 bool
161 Types::IsSubclassOf (Type::Kind type, Type::Kind super)
163 Type *t;
164 Type::Kind parent;
166 if (type == Type::INVALID)
167 return false;
169 if (type == super)
170 return true;
172 t = Find (type);
174 g_return_val_if_fail (t != NULL, false);
176 do {
177 parent = t->GetParent ();
179 if (parent == super)
180 return true;
182 if (parent == Type::INVALID)
183 return false;
185 t = Find (parent);
187 if (t == NULL)
188 return false;
189 } while (true);
191 return false;
194 bool
195 Type::IsAssignableFrom (Type::Kind type)
197 return Deployment::GetCurrent ()->GetTypes ()->IsAssignableFrom (GetKind (), type);
200 bool
201 Type::IsAssignableFrom (Type::Kind destination, Type::Kind type)
203 return Deployment::GetCurrent ()->GetTypes ()->IsAssignableFrom (destination, type);
206 bool
207 Types::IsAssignableFrom (Type::Kind destination, Type::Kind type)
209 if (destination == type)
210 return true;
212 if (IsSubclassOf (type, destination))
213 return true;
215 // more expensive.. interface checks
216 Type *destination_type = Find (destination);
217 if (!destination_type->IsInterface())
218 return false;
220 Type *type_type = Find (type);
221 while (type_type && type_type->GetKind() != Type::INVALID) {
222 for (int i = 0; i < type_type->GetInterfaceCount(); i ++) {
223 // should this be IsAssignableFrom instead of ==? ugh
224 if (type_type->GetInterface(i) == destination)
225 return true;
227 type_type = Find (type_type->GetParent());
230 return false;
233 Type *
234 Type::Find (Deployment *deployment, const char *name)
236 return deployment->GetTypes ()->Find (name);
239 Type *
240 Type::Find (const char *name)
242 return Find (Deployment::GetCurrent (), name);
245 Type *
246 Type::Find (Deployment *deployment, const char *name, bool ignore_case)
248 return deployment->GetTypes ()->Find (name, ignore_case);
251 Type *
252 Type::Find (const char *name, bool ignore_case)
254 return Find (Deployment::GetCurrent (), name, ignore_case);
257 Type *
258 Type::Find (Deployment *deployment, Type::Kind type)
260 if (type < Type::INVALID || type == Type::LASTTYPE)
261 return NULL;
263 return deployment->GetTypes ()->Find (type);
266 Type *
267 Type::Find (Type::Kind type)
269 if (type < Type::INVALID || type == Type::LASTTYPE)
270 return NULL;
272 return Find (Deployment::GetCurrent (), type);
275 DependencyObject *
276 Type::CreateInstance ()
278 if (!create_inst) {
279 g_warning ("Unable to create an instance of type: %s\n", name);
280 return NULL;
283 return create_inst ();
286 const char *
287 Type::GetContentPropertyName ()
289 Type *parent_type;
291 if (type == INVALID)
292 return NULL;
294 if (content_property)
295 return content_property;
297 parent_type = Find (parent);
299 if (parent_type == NULL)
300 return NULL;
302 return parent_type->GetContentPropertyName ();
305 DependencyProperty *
306 Type::LookupProperty (const char *name)
308 DependencyProperty *property = NULL;
310 g_return_val_if_fail (name != NULL, NULL);
312 if (properties != NULL) {
313 char *key = g_ascii_strdown (name, -1);
314 property = (DependencyProperty*) g_hash_table_lookup (properties, key);
315 g_free (key);
317 if (property)
318 return property;
321 return NULL;
324 void
325 Type::AddProperty (DependencyProperty *property)
327 DependencyProperty *existing = NULL;
329 g_return_if_fail (property != NULL);
331 if (properties == NULL) {
332 properties = g_hash_table_new (g_str_hash, g_str_equal);
333 } else {
334 existing = (DependencyProperty *) g_hash_table_lookup (properties, property->GetHashKey ());
337 if (existing == NULL || existing->IsCustom ()) {
338 // Allow overwriting of custom properties
339 g_hash_table_insert (properties, (gpointer) property->GetHashKey (), property);
340 } else {
341 g_warning ("Type::AddProperty (): Trying to register the property '%s' (of type %s) in the owner type '%s', and there already is a property registered on that type with the same name.",
342 property->GetName (), Type::Find (property->GetPropertyType ())->GetName(), GetName());
346 static void
347 property_add (gpointer key, gpointer value, gpointer user_data)
349 g_hash_table_insert ((GHashTable *) user_data, key, value);
352 GHashTable *
353 Type::CopyProperties (bool inherited)
355 GHashTable *props = g_hash_table_new (g_str_hash, g_str_equal);
356 Type *type = this;
358 do {
359 if (type->properties)
360 g_hash_table_foreach (type->properties, property_add, props);
362 if (!inherited || type->GetParent () == Type::INVALID)
363 break;
365 type = Type::Find (type->GetParent ());
366 } while (type);
368 return props;
371 bool
372 type_get_value_type (Type::Kind type)
374 Type *t = Type::Find (type);
376 if (t == NULL)
377 return false;
379 return t->IsValueType ();
382 const char *
383 type_get_name (Type::Kind type)
385 Type *t = Type::Find (type);
387 if (t == NULL)
388 return NULL;
390 return t->GetName ();
393 bool
394 type_is_dependency_object (Type::Kind type)
396 return Type::IsSubclassOf (type, Type::DEPENDENCY_OBJECT);
399 DependencyObject *
400 type_create_instance (Type *type)
402 if (!type) {
403 g_warning ("Unable to create instance of type %p.", type);
404 return NULL;
407 return type->CreateInstance ();
410 DependencyObject *
411 type_create_instance_from_kind (Type::Kind kind)
413 Type *t = Type::Find (kind);
415 if (t == NULL) {
416 g_warning ("Unable to create instance of type %d. Type not found.", kind);
417 return NULL;
420 return t->CreateInstance ();
424 * Types
427 Types::Types ()
429 //printf ("Types::Types (). this: %p\n", this);
430 types.SetCount ((int) Type::LASTTYPE + 1);
431 RegisterNativeTypes ();
434 void
435 Types::Initialize ()
437 RegisterNativeProperties ();
440 void
441 Types::DeleteProperties ()
443 /* this can't be done in the destructor, since deleting the properties might end up accessing the types */
444 for (int i = 0; i < properties.GetCount (); i++)
445 delete (DependencyProperty *) properties [i];
446 properties.SetCount (0);
449 void
450 Types::Dispose ()
452 for (int i = 0; i < properties.GetCount (); i++)
453 ((DependencyProperty *) properties [i])->Dispose ();
456 Types::~Types ()
458 for (int i = 0; i < types.GetCount (); i++)
459 delete (Type *) types [i];
462 void
463 Types::AddProperty (DependencyProperty *property)
465 Type *type;
467 g_return_if_fail (property != NULL);
469 type = Find (property->GetOwnerType ());
471 g_return_if_fail (type != NULL);
473 property->SetId (properties.Add (property));
474 type->AddProperty (property);
477 DependencyProperty *
478 Types::GetProperty (int id)
480 g_return_val_if_fail (properties.GetCount () > id, NULL);
481 return (DependencyProperty *) properties [id];
484 Type *
485 Types::Find (Type::Kind type)
487 if ((int) type + 1 > types.GetCount ())
488 return NULL;
490 return (Type *) types [(int) type];
493 Type *
494 Types::Find (const char *name)
496 return Types::Find (name, true);
499 Type *
500 Types::Find (const char *name, bool ignore_case)
502 Type *t;
504 for (int i = 1; i < types.GetCount (); i++) { // 0 = INVALID, shouldn't compare against that
505 if (i == Type::LASTTYPE)
506 continue;
508 t = (Type *) types [i];
509 if ((ignore_case && !g_ascii_strcasecmp (t->GetName (), name)) || !strcmp (t->GetName (), name))
510 return t;
513 return NULL;
516 Type::Kind
517 Types::RegisterType (const char *name, void *gc_handle, Type::Kind parent, bool is_interface, bool ctor_visible, Type::Kind* interfaces, int interface_count)
519 Type *type = new Type (Type::INVALID, parent, false, is_interface, g_strdup (name), 0, Find (parent)->GetEventCount (), NULL, interface_count, interfaces, ctor_visible, NULL, NULL);
521 // printf ("Types::RegisterType (%s, %p, %i (%s)). this: %p, size: %i, count: %i\n", name, gc_handle, parent, Type::Find (this, parent) ? Type::Find (this, parent)->name : NULL, this, size, count);
523 type->SetKind ((Type::Kind) types.Add (type));
525 return type->GetKind ();