1 /******************************************************************************
2 3 Wraps any type in a struct that also contains boolean field indicating if
4 value is in defined state.
5 6 If T is a value type, `Optional!(T)` is value type too.
7 8 Copyright:
9 Copyright (c) 2009-2017 dunnhumby Germany GmbH. All rights reserved.
10 11 License:
12 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
13 Alternatively, this file may be distributed under the terms of the Tango
14 3-Clause BSD License (see LICENSE_BSD.txt for details).
15 16 17 *******************************************************************************/18 19 moduleocean.core.Optional;
20 21 version (unittest)
22 {
23 importocean.core.Test;
24 }
25 26 /// ditto27 structOptional ( T )
28 {
29 /// Alias to make code working with undefined state more readable30 publicenumundefined = Optional!(T).init;
31 32 /// wrapped arbitrary value33 privateTvalue;
34 35 /// flag indicating if stored value is in defined state36 privatebooldefined = false;
37 38 /**************************************************************************
39 40 Puts `this` into defined state
41 42 Params:
43 rhs = value to assign
44 45 **************************************************************************/46 47 publicvoidopAssign ( Trhs )
48 {
49 this.defined = true;
50 this.value = rhs;
51 }
52 53 /**************************************************************************
54 55 Puts `this` into undefined state
56 57 **************************************************************************/58 59 publicvoidreset()
60 {
61 this.tupleof[] = Optional.undefined.tupleof[];
62 }
63 64 /**************************************************************************
65 66 Interface to retrieve stored value. It is intentionally designed in a
67 way that forces you to handle "undefined" state to avoid issues akin
68 to "null pointer".
69 70 This will become more convenient with D2 when lambda type inference
71 will happen, as well as shorter notation:
72 73 ---
74 value.visit(
75 () => { },
76 (x) => { }
77 );
78 ---
79 80 Parameters:
81 cb_undefined = action to take if value is not defined
82 cb_defined = ditto for defined. May modify internal value via
83 reference
84 85 **************************************************************************/86 87 publicvoidvisit ( scopevoiddelegate() cb_undefined,
88 scopevoiddelegate(refT) cb_defined )
89 {
90 if (this.defined)
91 cb_defined(this.value);
92 else93 cb_undefined();
94 }
95 96 /**************************************************************************
97 98 A more "old-school" version of `visit`. Provided both to conform style
99 of existing code and avoid delegate bugs in dmd1.
100 101 Discouraged by default as more error-prone than `visit`.
102 103 Parameters:
104 value = will be set to content of `this` if defined, will remain
105 unchanged otherwise
106 107 Return:
108 `true` if this is defined and `value` was updated.
109 110 **************************************************************************/111 112 publicboolget ( refTvalue )
113 {
114 if (this.defined)
115 value = this.value;
116 returnthis.defined;
117 }
118 119 /**************************************************************************
120 121 Returns:
122 `true` if this is defined.
123 124 **************************************************************************/125 126 publicboolisDefined ( )
127 {
128 returnthis.defined;
129 }
130 }
131 132 ///133 unittest134 {
135 aliasOptional!(bool) Maybe;
136 137 Maybex, y, z;
138 x = true;
139 y = false;
140 z = Maybe.undefined;
141 142 x.visit(
143 () { test(false); },
144 (refboolvalue) { test(value); }
145 );
146 147 y.visit(
148 () { test(false); },
149 (refboolvalue) { test(!value); }
150 );
151 152 z.visit(
153 () { test(true); },
154 (refboolvalue) { test(false); }
155 );
156 }
157 158 unittest159 {
160 Optional!(int) x;
161 test(!x.isDefined());
162 inty = 10;
163 boolok = x.get(y);
164 test(!ok);
165 test(y == 10);
166 x = 42;
167 ok = x.get(y);
168 test(ok);
169 test(y == 42);
170 }
171 172 /******************************************************************************
173 174 Shortcut on top of Optional to created defined value, uses IFTI to reduce
175 the noise
176 177 Parameters:
178 value = value to wrap into Optional
179 180 Returns:
181 wrapped value
182 183 ******************************************************************************/184 185 publicOptional!(T) optional ( T ) ( Tvalue )
186 {
187 returnOptional!(T)(value, true);
188 }
189 190 ///191 unittest192 {
193 Optional!(int) foo ( boolx )
194 {
195 if (x)
196 returnoptional(42);
197 else198 returnOptional!(int).undefined;
199 }
200 201 foo(true).visit(
202 () { test(false); },
203 (refintvalue) { test(value == 42); }
204 );
205 206 foo(false).visit(
207 () { },
208 (refintvalue) { test(false); }
209 );
210 }