Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit f60f2dc

Browse files
committed
Add std::optional
1 parent 0cbfdbb commit f60f2dc

File tree

6 files changed

+210
-0
lines changed

6 files changed

+210
-0
lines changed

changelog/std_optional.dd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Added `core.stdcpp.optional`.
2+
3+
Added `core.stdcpp.optional`, which links against C++ `std::optional`

mak/COPY

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ COPY=\
7979
$(IMPDIR)\core\stdcpp\array.d \
8080
$(IMPDIR)\core\stdcpp\exception.d \
8181
$(IMPDIR)\core\stdcpp\new_.d \
82+
$(IMPDIR)\core\stdcpp\optional.d \
8283
$(IMPDIR)\core\stdcpp\string.d \
8384
$(IMPDIR)\core\stdcpp\string_view.d \
8485
$(IMPDIR)\core\stdcpp\typeinfo.d \

mak/DOCS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ DOCS=\
4848
$(DOCDIR)\core_stdcpp_array.html \
4949
$(DOCDIR)\core_stdcpp_exception.html \
5050
$(DOCDIR)\core_stdcpp_new_.html \
51+
$(DOCDIR)\core_stdcpp_optional.html \
5152
$(DOCDIR)\core_stdcpp_string.html \
5253
$(DOCDIR)\core_stdcpp_string_view.html \
5354
$(DOCDIR)\core_stdcpp_typeinfo.html \

mak/SRCS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ SRCS=\
7777
src\core\stdcpp\array.d \
7878
src\core\stdcpp\exception.d \
7979
src\core\stdcpp\new_.d \
80+
src\core\stdcpp\optional.d \
8081
src\core\stdcpp\string.d \
8182
src\core\stdcpp\string_view.d \
8283
src\core\stdcpp\type_traits.d \

mak/WINDOWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,9 @@ $(IMPDIR)\core\stdcpp\exception.d : src\core\stdcpp\exception.d
282282
$(IMPDIR)\core\stdcpp\new_.d : src\core\stdcpp\new_.d
283283
copy $** $@
284284

285+
$(IMPDIR)\core\stdcpp\optional.d : src\core\stdcpp\optional.d
286+
copy $** $@
287+
285288
$(IMPDIR)\core\stdcpp\string.d : src\core\stdcpp\string.d
286289
copy $** $@
287290

src/core/stdcpp/optional.d

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/**
2+
* D header file for interaction with C++ std::optional.
3+
*
4+
* Copyright: Copyright (c) 2018 D Language Foundation
5+
* License: Distributed under the
6+
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
7+
* (See accompanying file LICENSE)
8+
* Authors: Manu Evans
9+
* Source: $(DRUNTIMESRC core/stdcpp/optional.d)
10+
*/
11+
12+
module core.stdcpp.optional;
13+
14+
import core.stdcpp.exception : exception;
15+
16+
version (CppRuntime_DigitalMars)
17+
{
18+
pragma(msg, "std::optional not supported by DMC");
19+
}
20+
version (CppRuntime_Clang)
21+
{
22+
private alias AliasSeq(Args...) = Args;
23+
private enum StdNamespace = AliasSeq!("std", "__1");
24+
}
25+
else
26+
{
27+
private enum StdNamespace = "std";
28+
}
29+
30+
31+
extern(C++, "std")
32+
{
33+
///
34+
class bad_optional_access : exception
35+
{
36+
@nogc:
37+
///
38+
this(const(char)* message = "bad exception") nothrow { super(message); }
39+
}
40+
}
41+
42+
43+
extern(C++, (StdNamespace)):
44+
45+
///
46+
struct nullopt_t {}
47+
48+
///
49+
enum nullopt_t nullopt = nullopt_t();
50+
51+
///
52+
struct in_place_t {}
53+
54+
///
55+
enum in_place_t in_place = in_place_t();
56+
57+
/**
58+
* D language counterpart to C++ std::optional.
59+
*
60+
* C++ reference: $(LINK2 https://en.cppreference.com/w/cpp/utility/optional)
61+
*/
62+
extern(C++, class) struct optional(T)
63+
{
64+
static assert(!is(Unqual!T == nullopt_t), "T in optional!T cannot be nullopt_t (N4659 23.6.2 [optional.syn]/1).");
65+
static assert(!is(Unqual!T == in_place_t), "T in optional!T cannot be in_place_t (N4659 23.6.2 [optional.syn]/1).");
66+
static assert(!__traits(hasMember, T, "__xpostblit"), "T in optional!T may not have a postblit `this(this)` constructor. Use copy constructor instead.");
67+
// static assert(is_reference_v<_Ty> || is_object_v<_Ty>, "T in optional!T must be an object type (N4659 23.6.3 [optional.optional]/3).");
68+
// static assert(is_destructible_v<_Ty> && !is_array_v<_Ty>, "T in optional!T must satisfy the requirements of Destructible (N4659 23.6.3 [optional.optional]/3).");
69+
70+
import core.internal.traits : AliasSeq, Unqual, hasElaborateDestructor, hasElaborateCopyConstructor, hasElaborateDestructor;
71+
import core.lifetime : forward, moveEmplace, core_emplace = emplace;
72+
73+
extern(D):
74+
pragma(inline, true):
75+
76+
///
77+
this(nullopt_t) pure nothrow @nogc @safe
78+
{
79+
}
80+
81+
///
82+
this(Args...)(in_place_t, auto ref Args args)
83+
{
84+
static if (Args.length == 1 && is(Unqual!(Args[0]) == T))
85+
moveEmplace(args[0], _value);
86+
else
87+
core_emplace(&_value, forward!args);
88+
_engaged = true;
89+
}
90+
91+
static if (hasElaborateCopyConstructor!T)
92+
{
93+
///
94+
this(ref return scope inout(optional) rhs) inout
95+
{
96+
_engaged = rhs._engaged;
97+
if (rhs._engaged)
98+
core_emplace(cast(T*)&_value, rhs._value);
99+
}
100+
}
101+
102+
static if (hasElaborateDestructor!T)
103+
{
104+
///
105+
~this()
106+
{
107+
if (_engaged)
108+
destroy!false(_value);
109+
}
110+
}
111+
112+
///
113+
void opAssign(nullopt_t)
114+
{
115+
reset();
116+
}
117+
118+
///
119+
void opAssign()(auto ref optional!T rhs)
120+
{
121+
if (rhs._engaged)
122+
opAssign(forward!rhs._value);
123+
else
124+
reset();
125+
}
126+
127+
///
128+
void opAssign()(auto ref T rhs)
129+
{
130+
if (_engaged)
131+
_value = forward!rhs;
132+
else
133+
{
134+
core_emplace(&_value, forward!rhs);
135+
_engaged = true;
136+
}
137+
}
138+
139+
///
140+
bool opCast(T : bool)() const pure nothrow @nogc @safe
141+
{
142+
return has_value();
143+
}
144+
145+
///
146+
void reset()
147+
{
148+
static if (hasElaborateDestructor!T)
149+
{
150+
if (_engaged)
151+
{
152+
destroy!false(_value);
153+
_engaged = false;
154+
}
155+
}
156+
else
157+
_engaged = false;
158+
}
159+
160+
///
161+
ref T emplace(Args...)(auto ref Args args)
162+
{
163+
reset();
164+
core_emplace(&_value, forward!args);
165+
_engaged = true;
166+
return _value;
167+
}
168+
169+
///
170+
bool has_value() const pure nothrow @nogc @safe
171+
{
172+
return _engaged;
173+
}
174+
175+
// TODO: return by-val (move _value) if `this` is an rvalue... (auto ref return?)
176+
///
177+
ref inout(T) value() inout return pure @trusted // @nogc //(DIP1008)
178+
in (_engaged == true)
179+
{
180+
// TODO: support C++ exceptions?
181+
// if (!_engaged)
182+
// throw new bad_optional_access();
183+
return _value;
184+
}
185+
186+
// TODO: return by-val (move _value) if `this` is an rvalue... (auto ref return?)
187+
///
188+
ref inout(T) value_or(scope return ref inout(T) or) inout return pure nothrow @nogc @trusted
189+
{
190+
return _engaged ? _value : or;
191+
}
192+
193+
private:
194+
// amazingly, MSVC, Clang and GCC all share the same struct!
195+
union
196+
{
197+
ubyte _dummy = 0;
198+
Unqual!T _value = void;
199+
}
200+
bool _engaged = false;
201+
}

0 commit comments

Comments
 (0)