xref: /haiku/src/kits/shared/Variant.cpp (revision c9ad965c81b08802fed0827fd1dd16f45297928a)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <Variant.h>
8 
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include <ByteOrder.h>
13 
14 
15 template<typename NumberType>
16 inline NumberType
17 BVariant::_ToNumber() const
18 {
19 	switch (fType) {
20 		case B_BOOL_TYPE:
21 			return fBool ? 1 : 0;
22 		case B_INT8_TYPE:
23 			return (NumberType)fInt8;
24 		case B_UINT8_TYPE:
25 			return (NumberType)fUInt8;
26 		case B_INT16_TYPE:
27 			return (NumberType)fInt16;
28 		case B_UINT16_TYPE:
29 			return (NumberType)fUInt16;
30 		case B_INT32_TYPE:
31 			return (NumberType)fInt32;
32 		case B_UINT32_TYPE:
33 			return (NumberType)fUInt32;
34 		case B_INT64_TYPE:
35 			return (NumberType)fInt64;
36 		case B_UINT64_TYPE:
37 			return (NumberType)fUInt64;
38 		case B_FLOAT_TYPE:
39 			return (NumberType)fFloat;
40 		case B_DOUBLE_TYPE:
41 			return (NumberType)fDouble;
42 		default:
43 			return 0;
44 	}
45 }
46 
47 
48 BVariant::~BVariant()
49 {
50 	Unset();
51 }
52 
53 
54 status_t
55 BVariant::SetToTypedData(const void* data, type_code type)
56 {
57 	Unset();
58 
59 	switch (type) {
60 		case B_BOOL_TYPE:
61 			fBool = *(bool*)data;
62 			break;
63 		case B_INT8_TYPE:
64 			fInt8 = *(int8*)data;
65 			break;
66 		case B_UINT8_TYPE:
67 			fUInt8 = *(uint8*)data;
68 			break;
69 		case B_INT16_TYPE:
70 			fInt16 = *(int16*)data;
71 			break;
72 		case B_UINT16_TYPE:
73 			fUInt16 = *(uint16*)data;
74 			break;
75 		case B_INT32_TYPE:
76 			fInt32 = *(int32*)data;
77 			break;
78 		case B_UINT32_TYPE:
79 			fUInt32 = *(uint32*)data;
80 			break;
81 		case B_INT64_TYPE:
82 			fInt64 = *(int64*)data;
83 			break;
84 		case B_UINT64_TYPE:
85 			fUInt64 = *(uint64*)data;
86 			break;
87 		case B_FLOAT_TYPE:
88 			fFloat = *(float*)data;
89 			break;
90 		case B_DOUBLE_TYPE:
91 			fDouble = *(double*)data;
92 			break;
93 		case B_POINTER_TYPE:
94 			fPointer = *(void**)data;
95 			break;
96 		case B_STRING_TYPE:
97 			return _SetTo((const char*)data, 0) ? B_OK : B_NO_MEMORY;
98 		default:
99 			return B_BAD_TYPE;
100 	}
101 
102 	fType = type;
103 	return B_OK;
104 }
105 
106 
107 void
108 BVariant::Unset()
109 {
110 	if ((fFlags & B_VARIANT_OWNS_DATA) != 0) {
111 		switch (fType) {
112 			case B_STRING_TYPE:
113 				free(fString);
114 				break;
115 			default:
116 				break;
117 		}
118 	} else if ((fFlags & B_VARIANT_REFERENCEABLE_DATA) != 0) {
119 		if (fReferenceable != NULL)
120 			fReferenceable->ReleaseReference();
121 	}
122 
123 	fType = 0;
124 	fFlags = 0;
125 }
126 
127 
128 bool
129 BVariant::operator==(const BVariant& other) const
130 {
131 	if (fType == 0)
132 		return other.fType == 0;
133 	if (other.fType == 0)
134 		return false;
135 
136 	// TODO: The number comparisons are not really accurate. Particularly a
137 	// conversion between signed and unsigned integers might actually change the
138 	// value.
139 
140 	switch (fType) {
141 		case B_BOOL_TYPE:
142 			return fBool == other.ToBool();
143 		case B_INT8_TYPE:
144 		case B_INT16_TYPE:
145 		case B_INT32_TYPE:
146 		case B_INT64_TYPE:
147 			if (!other.IsNumber())
148 				return false;
149 			return ToInt64() == other.ToInt64();
150 		case B_UINT8_TYPE:
151 		case B_UINT16_TYPE:
152 		case B_UINT32_TYPE:
153 		case B_UINT64_TYPE:
154 			if (!other.IsNumber())
155 				return false;
156 			return ToUInt64() == other.ToUInt64();
157 		case B_FLOAT_TYPE:
158 		case B_DOUBLE_TYPE:
159 			if (!other.IsNumber())
160 				return false;
161 			return ToDouble() == other.ToDouble();
162 		case B_POINTER_TYPE:
163 			return other.fType == B_POINTER_TYPE
164 				&& fPointer == other.fPointer;
165 		case B_STRING_TYPE:
166 			if (other.fType != B_STRING_TYPE)
167 				return false;
168 			if (fString == NULL || other.fString == NULL)
169 				return fString == other.fString;
170 			return strcmp(fString, other.fString) == 0;
171 		default:
172 			return false;
173 	}
174 }
175 
176 
177 size_t
178 BVariant::Size() const
179 {
180 	if (fType == B_STRING_TYPE)
181 		return fString != NULL ? strlen(fString) + 1 : 0;
182 	if ((fFlags & B_VARIANT_REFERENCEABLE_DATA) != 0)
183 		return sizeof(this->fReferenceable);
184 	return SizeOfType(fType);
185 }
186 
187 
188 const uint8*
189 BVariant::Bytes() const
190 {
191 	if (fType == B_STRING_TYPE)
192 		return (const uint8*)fString;
193 	return fBytes;
194 }
195 
196 
197 bool
198 BVariant::ToBool() const
199 {
200 	switch (fType) {
201 		case B_BOOL_TYPE:
202 			return fBool;
203 		case B_INT8_TYPE:
204 			return fInt8 != 0;
205 		case B_UINT8_TYPE:
206 			return fUInt8 != 0;
207 		case B_INT16_TYPE:
208 			return fInt16 != 0;
209 		case B_UINT16_TYPE:
210 			return fUInt16 != 0;
211 		case B_INT32_TYPE:
212 			return fInt32 != 0;
213 		case B_UINT32_TYPE:
214 			return fUInt32 != 0;
215 		case B_INT64_TYPE:
216 			return fInt64 != 0;
217 		case B_UINT64_TYPE:
218 			return fUInt64 != 0;
219 		case B_FLOAT_TYPE:
220 			return fFloat != 0;
221 		case B_DOUBLE_TYPE:
222 			return fDouble != 0;
223 		case B_POINTER_TYPE:
224 			return fPointer != NULL;
225 		case B_STRING_TYPE:
226 			return fString != NULL;
227 				// TODO: We should probably check for actual values like "true",
228 				// "false", "on", "off", etc.
229 		default:
230 			return false;
231 	}
232 }
233 
234 
235 int8
236 BVariant::ToInt8() const
237 {
238 	return _ToNumber<int8>();
239 }
240 
241 
242 uint8
243 BVariant::ToUInt8() const
244 {
245 	return _ToNumber<uint8>();
246 }
247 
248 
249 int16
250 BVariant::ToInt16() const
251 {
252 	return _ToNumber<int16>();
253 }
254 
255 
256 uint16
257 BVariant::ToUInt16() const
258 {
259 	return _ToNumber<uint16>();
260 }
261 
262 
263 int32
264 BVariant::ToInt32() const
265 {
266 	return _ToNumber<int32>();
267 }
268 
269 
270 uint32
271 BVariant::ToUInt32() const
272 {
273 	return _ToNumber<uint32>();
274 }
275 
276 
277 int64
278 BVariant::ToInt64() const
279 {
280 	return _ToNumber<int64>();
281 }
282 
283 
284 uint64
285 BVariant::ToUInt64() const
286 {
287 	return _ToNumber<uint64>();
288 }
289 
290 
291 float
292 BVariant::ToFloat() const
293 {
294 	return _ToNumber<float>();
295 }
296 
297 
298 double
299 BVariant::ToDouble() const
300 {
301 	return _ToNumber<double>();
302 }
303 
304 
305 void*
306 BVariant::ToPointer() const
307 {
308 	return fType == B_POINTER_TYPE ? fString : NULL;
309 }
310 
311 
312 const char*
313 BVariant::ToString() const
314 {
315 	return fType == B_STRING_TYPE ? fString : NULL;
316 }
317 
318 
319 void
320 BVariant::_SetTo(const BVariant& other)
321 {
322 	if ((other.fFlags & B_VARIANT_OWNS_DATA) != 0) {
323 		switch (other.fType) {
324 			case B_STRING_TYPE:
325 				fType = B_STRING_TYPE;
326 				fString = strdup(other.fString);
327 				fFlags = B_VARIANT_OWNS_DATA;
328 				return;
329 			default:
330 				break;
331 		}
332 	} else if ((other.fFlags & B_VARIANT_REFERENCEABLE_DATA) != 0) {
333 		if (other.fReferenceable != NULL)
334 			other.fReferenceable->AcquireReference();
335 	}
336 
337 	memcpy(this, &other, sizeof(BVariant));
338 }
339 
340 
341 BReferenceable*
342 BVariant::ToReferenceable() const
343 {
344 	return (fFlags & B_VARIANT_REFERENCEABLE_DATA) != 0
345 		? fReferenceable : NULL;
346 }
347 
348 
349 void
350 BVariant::SwapEndianess()
351 {
352 	if (!IsNumber() || fType == B_POINTER_TYPE)
353 		return;
354 
355 	swap_data(fType, fBytes, Size(), B_SWAP_ALWAYS);
356 }
357 
358 
359 /*static*/ size_t
360 BVariant::SizeOfType(type_code type)
361 {
362 	switch (type) {
363 		case B_BOOL_TYPE:
364 			return 1;
365 		case B_INT8_TYPE:
366 			return 1;
367 		case B_UINT8_TYPE:
368 			return 1;
369 		case B_INT16_TYPE:
370 			return 2;
371 		case B_UINT16_TYPE:
372 			return 2;
373 		case B_INT32_TYPE:
374 			return 4;
375 		case B_UINT32_TYPE:
376 			return 4;
377 		case B_INT64_TYPE:
378 			return 8;
379 		case B_UINT64_TYPE:
380 			return 8;
381 		case B_FLOAT_TYPE:
382 			return sizeof(float);
383 		case B_DOUBLE_TYPE:
384 			return sizeof(double);
385 		case B_POINTER_TYPE:
386 			return sizeof(void*);
387 		default:
388 			return 0;
389 	}
390 }
391 
392 
393 /*static*/ bool
394 BVariant::TypeIsNumber(type_code type)
395 {
396 	switch (type) {
397 		case B_INT8_TYPE:
398 		case B_UINT8_TYPE:
399 		case B_INT16_TYPE:
400 		case B_UINT16_TYPE:
401 		case B_INT32_TYPE:
402 		case B_UINT32_TYPE:
403 		case B_INT64_TYPE:
404 		case B_UINT64_TYPE:
405 		case B_FLOAT_TYPE:
406 		case B_DOUBLE_TYPE:
407 			return true;
408 		default:
409 			return false;
410 	}
411 }
412 
413 
414 /*static*/ bool
415 BVariant::TypeIsInteger(type_code type, bool* _isSigned)
416 {
417 	switch (type) {
418 		case B_INT8_TYPE:
419 		case B_INT16_TYPE:
420 		case B_INT32_TYPE:
421 		case B_INT64_TYPE:
422 			if (_isSigned != NULL)
423 				*_isSigned = true;
424 			return true;
425 		case B_UINT8_TYPE:
426 		case B_UINT16_TYPE:
427 		case B_UINT32_TYPE:
428 		case B_UINT64_TYPE:
429 			if (_isSigned != NULL)
430 				*_isSigned = false;
431 			return true;
432 		default:
433 			return false;
434 	}
435 }
436 
437 
438 /*static*/ bool
439 BVariant::TypeIsFloat(type_code type)
440 {
441 	switch (type) {
442 		case B_FLOAT_TYPE:
443 		case B_DOUBLE_TYPE:
444 			return true;
445 		default:
446 			return false;
447 	}
448 }
449 
450 
451 void
452 BVariant::_SetTo(bool value)
453 {
454 	fType = B_BOOL_TYPE;
455 	fFlags = 0;
456 	fBool = value;
457 }
458 
459 
460 void
461 BVariant::_SetTo(int8 value)
462 {
463 	fType = B_INT8_TYPE;
464 	fFlags = 0;
465 	fInt8 = value;
466 }
467 
468 
469 void
470 BVariant::_SetTo(uint8 value)
471 {
472 	fType = B_UINT8_TYPE;
473 	fFlags = 0;
474 	fUInt8 = value;
475 }
476 
477 
478 void
479 BVariant::_SetTo(int16 value)
480 {
481 	fType = B_INT16_TYPE;
482 	fFlags = 0;
483 	fInt16 = value;
484 }
485 
486 
487 void
488 BVariant::_SetTo(uint16 value)
489 {
490 	fType = B_UINT16_TYPE;
491 	fFlags = 0;
492 	fUInt16 = value;
493 }
494 
495 
496 void
497 BVariant::_SetTo(int32 value)
498 {
499 	fType = B_INT32_TYPE;
500 	fFlags = 0;
501 	fInt32 = value;
502 }
503 
504 
505 void
506 BVariant::_SetTo(uint32 value)
507 {
508 	fType = B_UINT32_TYPE;
509 	fFlags = 0;
510 	fUInt32 = value;
511 }
512 
513 
514 void
515 BVariant::_SetTo(int64 value)
516 {
517 	fType = B_INT64_TYPE;
518 	fFlags = 0;
519 	fInt64 = value;
520 }
521 
522 
523 void
524 BVariant::_SetTo(uint64 value)
525 {
526 	fType = B_UINT64_TYPE;
527 	fFlags = 0;
528 	fUInt64 = value;
529 }
530 
531 
532 void
533 BVariant::_SetTo(float value)
534 {
535 	fType = B_FLOAT_TYPE;
536 	fFlags = 0;
537 	fFloat = value;
538 }
539 
540 
541 void
542 BVariant::_SetTo(double value)
543 {
544 	fType = B_DOUBLE_TYPE;
545 	fFlags = 0;
546 	fDouble = value;
547 }
548 
549 
550 void
551 BVariant::_SetTo(const void* value)
552 {
553 	fType = B_POINTER_TYPE;
554 	fFlags = 0;
555 	fPointer = (void*)value;
556 }
557 
558 
559 bool
560 BVariant::_SetTo(const char* value, uint32 flags)
561 {
562 	fType = B_STRING_TYPE;
563 	fFlags = 0;
564 
565 	if (value != NULL) {
566 		if ((flags & B_VARIANT_DONT_COPY_DATA) == 0) {
567 			fString = strdup(value);
568 			fFlags |= B_VARIANT_OWNS_DATA;
569 			if (fString == NULL)
570 				return false;
571 		} else {
572 			fString = (char*)value;
573 			fFlags |= flags & B_VARIANT_OWNS_DATA;
574 		}
575 	} else
576 		fString = NULL;
577 
578 	return true;
579 }
580 
581 
582 void
583 BVariant::_SetTo(BReferenceable* value, type_code type)
584 {
585 	fType = type;
586 	fFlags = B_VARIANT_REFERENCEABLE_DATA;
587 	fReferenceable = value;
588 
589 	if (fReferenceable != NULL)
590 		fReferenceable->AcquireReference();
591 }
592