File: Variant.h

package info (click to toggle)
storm-lang 0.7.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,004 kB
  • sloc: ansic: 261,462; cpp: 140,405; sh: 14,891; perl: 9,846; python: 2,525; lisp: 2,504; asm: 860; makefile: 678; pascal: 70; java: 52; xml: 37; awk: 12
file content (154 lines) | stat: -rw-r--r-- 4,757 bytes parent folder | download | duplicates (2)
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
#pragma once
#include "Handle.h"
#include "Utils/Templates.h"
#include "Core/Object.h"
#include "Core/TObject.h"
#include "Core/Exception.h"

namespace storm {
	STORM_PKG(core);

	/**
	 * A class that represents an instance of some type in the system. Similar to "void *" in C.
	 *
	 * The interface to this class in Storm is not yet complete; this class was created as a useful
	 * tool for implementing serialization and other generic facilities in C++.
	 */
	class Variant {
		STORM_VALUE;
	public:
		// Create an empty variant.
		STORM_CTOR Variant();

		// Copy the variant.
		Variant(const Variant &o);
		Variant &operator =(const Variant &o);

		// Create a variant referring to an object.
		explicit Variant(RootObject *t);
		STORM_CAST_CTOR Variant(Object *o);
		STORM_CAST_CTOR Variant(TObject *o);

		// Create a variant referring to some known type known to be a value.
		Variant(const void *value, Type *type);

		// Generic creation. The overloads make sure to act correctly regardless if the contained
		// type is a value or an object. The second parameter is Engine &. Sorry for the template mess...
		template <class T>
		Variant(const T &v, typename EnableIf<!IsPointer<T>::value, Engine &>::t e) {
			init(&v, StormInfo<T>::type(e));
		}

		template <class T>
		Variant(T v, typename EnableIf<IsPointer<T>::value, Engine &>::t) : data(v) {}

		// Destroy. Call the destructor of the contained element, if any.
		~Variant();

		// Deep copy.
		void STORM_FN deepCopy(CloneEnv *env);

		// Is the variant empty?
		Bool STORM_FN empty() const;

		// Does the variant contain any element?
		Bool STORM_FN any() const { return !empty(); }

		// Does this variant contain the type `type`?
		Bool STORM_FN has(Type *type) const;

		// Get the type of the value in the variant. Returns `null` if it is empty.
		MAYBE(Type *) STORM_FN type() const;

		// Output.
		void STORM_FN toS(StrBuf *to) const;

	public:

		/**
		 * Low-level API for C++.
		 *
		 * Make sure to differentiate usage depending on wether the contained type is a value or a
		 * class! This API does no checking of the contents of the variant, and may crash horribly
		 * if care is not taken externally.
		 */

		// Create a uninitialized variant referring to a type. Call 'getValue' and 'valueInitialized'
		// to initialize the value.
		static Variant uninitializedValue(Type *type);

		// Get a pointer to the value stored in here, assuming it is a value.
		void *getValue() const;

		// Note that we have initialized the value.
		void valueInitialized();

		// Note that we have moved the value somewhere else, clearing the variant without calling
		// the destructor. It is possible to call 'valueInitialized' again.
		void valueRemoved();

		// Move the value somewhere else.
		void moveValue(void *to);

		// Get the object stored in here.
		RootObject *getObject() const;

		// Get a pointer to the contained data. If it is an object, get a pointer to the object
		// pointer. If it is a value, get a pointer to the value. This is useful when calling
		// functions through the FnCall interface.
		void *getPointer();


		/**
		 * High-level API for C++.
		 */

		// Templated function for extracting the contained type. Works regardless if the contained
		// type is a value or an object. Assumes that the variant actually contains a value unless T
		// is a pointer, in which case null is returned if the variant is empty. Returns T, sorry
		// for the template mess...
		template <class T>
		typename EnableIf<!IsPointer<T>::value, T>::t get() const {
			if (!data)
				throw new (runtime::someEngine()) InternalError(S("Attempting to get a value from an empty variant."));
			if (!has(StormInfo<T>::type(engine())))
				throw new (engine()) InternalError(S("Attempting to get an incorrect type from a variant."));

			assert(runtime::gcTypeOf(data)->kind == GcType::tArray, L"Should specify a pointer with this type to 'get'.");

			return *(T *)getValue();
		}

		template <class T>
		typename EnableIf<IsPointer<T>::value, T>::t get() const {
			if (data == null)
				return null;

			Type *t = StormInfo<typename BaseType<T>::Type>::type(engine());
			if (!has(t))
				return null;

			const GcType *g = runtime::gcTypeOf(data);
			if (g->kind == GcType::tArray) {
				return (T)getValue();
			} else {
				return (T)getObject();
			}
		}

	private:
		// The stored data. Either an array with one element, or a pointer to an object.
		UNKNOWN(PTR_GC) void *data;

		// Initialize for a value.
		void init(const void *value, Type *type);

		// Find an Engine instance. Assumes we're not empty.
		Engine &engine() const;

		friend wostream &operator <<(wostream &to, const Variant &v);
	};

	// Output.
	wostream &operator <<(wostream &to, const Variant &v);
}