blob: d00cb6002810ff1b05cb09e46a5fd066e49a104d [file] [log] [blame]
Junxiao Shi1aecae22016-08-30 11:23:59 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Davide Pesavento6db13602017-02-26 22:05:53 -05003 * Copyright (c) 2013-2017 Regents of the University of California.
Junxiao Shi1aecae22016-08-30 11:23:59 +00004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22/** \file
23 * \brief C++17 std::optional backport implemented using boost::optional
24 * \sa http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/n4594.pdf section 20.6
25 * \sa http://en.cppreference.com/w/cpp/utility/optional
26 *
27 * Differences from C++17 include:
28 * \li No constructor and operator= taking a T&&,
29 * because boost::optional lacks a move constructor as of Boost 1.54
30 * \li No constructor, operator=, emplace, and make_optional with std::initializer_list
31 * \li In-place constructor and emplace require copyable arguments,
32 * because boost::in_place requires such
33 * \li Move constructor may or may not exist (it's implicitly defined when available),
34 * because boost::optional lacks a move constructor as of Boost 1.54
35 * \li Non-const operator-> and operator* are not constexpr
36 * \li value() is not constexpr
37 * \li swap is declared without noexcept specification
38 * \li No comparison operators with const T& or nullopt_t
39 * \li No specialized std::hash support
40 */
41
42#ifndef NDN_UTIL_BACKPORTS_OPTIONAL_HPP
43#define NDN_UTIL_BACKPORTS_OPTIONAL_HPP
44
45#include "../common.hpp"
46
Davide Pesavento6db13602017-02-26 22:05:53 -050047#ifdef __has_include
48# if (__cplusplus > 201402L) && __has_include(<optional>)
49# include <optional>
50# define NDN_CXX_HAVE_STD_OPTIONAL
51# elif (__cplusplus > 201103L) && __has_include(<experimental/optional>)
52# include <experimental/optional>
53# if __cpp_lib_experimental_optional >= 201411
54# define NDN_CXX_HAVE_EXPERIMENTAL_OPTIONAL
55# endif
56# endif
57#endif
58
59#if defined(NDN_CXX_HAVE_STD_OPTIONAL)
60
61namespace ndn {
62using std::optional;
63using std::in_place;
64using std::nullopt;
65using std::bad_optional_access;
66using std::make_optional;
67} // namespace ndn
68
69#elif defined(NDN_CXX_HAVE_EXPERIMENTAL_OPTIONAL)
70
71namespace ndn {
72using std::experimental::optional;
73using std::experimental::in_place;
74using std::experimental::nullopt;
75using std::experimental::bad_optional_access;
76using std::experimental::make_optional;
77
78template<typename T, typename... Args>
79constexpr optional<T>
80make_optional(Args&&... args)
81{
82 return optional<T>(in_place, std::forward<Args>(args)...);
83}
84} // namespace ndn
85
86#else
87
Junxiao Shi1aecae22016-08-30 11:23:59 +000088#include <boost/none.hpp>
89#include <boost/optional.hpp>
90#include <boost/utility/typed_in_place_factory.hpp>
91
92namespace ndn {
93
94template<typename T>
95class optional;
96
97struct in_place_t
98{
99};
100constexpr in_place_t in_place{};
101
102class nullopt_t
103{
104public:
105 constexpr explicit
106 nullopt_t(int)
107 {
108 }
109};
Davide Pesavento6db13602017-02-26 22:05:53 -0500110constexpr nullopt_t nullopt{0};
Junxiao Shi1aecae22016-08-30 11:23:59 +0000111
112#if BOOST_VERSION >= 105600
113using boost::bad_optional_access;
114#else
115class bad_optional_access : public std::logic_error
116{
117public:
118 bad_optional_access()
119 : std::logic_error("bad optional access")
120 {
121 }
122};
123#endif
124
125template<typename T>
126constexpr bool
127operator==(const optional<T>& lhs, const optional<T>& rhs);
128
129template<typename T>
130constexpr bool
131operator!=(const optional<T>& lhs, const optional<T>& rhs);
132
133template<typename T>
134constexpr bool
135operator<(const optional<T>& lhs, const optional<T>& rhs);
136
137template<typename T>
138constexpr bool
139operator<=(const optional<T>& lhs, const optional<T>& rhs);
140
141template<typename T>
142constexpr bool
143operator>(const optional<T>& lhs, const optional<T>& rhs);
144
145template<typename T>
146constexpr bool
147operator>=(const optional<T>& lhs, const optional<T>& rhs);
148
149template<typename T>
150class optional
151{
152public:
153 static_assert(!std::is_same<typename std::remove_cv<T>::type, in_place_t>::value &&
154 !std::is_same<typename std::remove_cv<T>::type, nullopt_t>::value &&
155 !std::is_reference<T>::value,
156 "Invalid instantiation of optional<T>");
157
158 typedef T value_type;
159
160 constexpr
161 optional() noexcept
162 {
163 }
164
165 constexpr
166 optional(nullopt_t) noexcept
167 {
168 }
169
170 constexpr
171 optional(const T& value)
172 : m_boostOptional(value)
173 {
174 }
175
176 template<typename... Args>
177 constexpr explicit
178 optional(in_place_t, Args&&... args)
179 : m_boostOptional(boost::in_place<T>(std::forward<Args>(args)...))
180 {
181 }
182
183 optional&
184 operator=(nullopt_t) noexcept
185 {
186 m_boostOptional = boost::none;
187 return *this;
188 }
189
190 optional&
191 operator=(const optional& other)
192 {
193 m_boostOptional = other.m_boostOptional;
194 return *this;
195 }
196
197 template<typename U,
198 typename = typename std::enable_if<std::is_same<typename std::decay<U>::type, T>::value>::type>
199 optional&
200 operator=(U&& value)
201 {
202 m_boostOptional = std::forward<U>(value);
203 return *this;
204 }
205
206public: // observers
207 constexpr const T*
208 operator->() const
209 {
210 return m_boostOptional.get_ptr();
211 }
212
213 T*
214 operator->()
215 {
216 return m_boostOptional.get_ptr();
217 }
218
219 constexpr const T&
220 operator*() const
221 {
222 return m_boostOptional.get();
223 }
224
225 T&
226 operator*()
227 {
228 return m_boostOptional.get();
229 }
230
231 constexpr explicit
232 operator bool() const noexcept
233 {
234 return static_cast<bool>(m_boostOptional);
235 }
236
237 const T&
238 value() const
239 {
240 return const_cast<optional*>(this)->value();
241 }
242
243 T&
244 value()
245 {
246#if BOOST_VERSION >= 105600
247 return m_boostOptional.value();
248#else
249 if (!m_boostOptional) {
250 BOOST_THROW_EXCEPTION(bad_optional_access());
251 }
252 return m_boostOptional.get();
253#endif
254 }
255
256 template<typename U>
257 constexpr T
258 value_or(U&& default_value) const
259 {
260#if BOOST_VERSION >= 105600
261 return m_boostOptional.value_or(default_value);
262#else
263 return m_boostOptional.get_value_or(default_value);
264#endif
265 }
266
267public: // modifiers
268 void
269 swap(optional& other)
270 {
271 boost::swap(m_boostOptional, other.m_boostOptional);
272 }
273
274 template<typename... Args>
275 void
276 emplace(Args&&... args)
277 {
278 m_boostOptional = boost::in_place<T>(std::forward<Args>(args)...);
279 }
280
281private:
282 boost::optional<T> m_boostOptional;
283
284 friend bool operator==<T>(const optional<T>&, const optional<T>&);
285 friend bool operator!=<T>(const optional<T>&, const optional<T>&);
286 friend bool operator< <T>(const optional<T>&, const optional<T>&);
287 friend bool operator<=<T>(const optional<T>&, const optional<T>&);
288 friend bool operator> <T>(const optional<T>&, const optional<T>&);
289 friend bool operator>=<T>(const optional<T>&, const optional<T>&);
290};
291
292template<typename T>
293constexpr bool
294operator==(const optional<T>& lhs, const optional<T>& rhs)
295{
296 return operator==(lhs.m_boostOptional, rhs.m_boostOptional);
297}
298
299template<typename T>
300constexpr bool
301operator!=(const optional<T>& lhs, const optional<T>& rhs)
302{
303 return operator!=(lhs.m_boostOptional, rhs.m_boostOptional);
304}
305
306template<typename T>
307constexpr bool
308operator<(const optional<T>& lhs, const optional<T>& rhs)
309{
310 return operator<(lhs.m_boostOptional, rhs.m_boostOptional);
311}
312
313template<typename T>
314constexpr bool
315operator<=(const optional<T>& lhs, const optional<T>& rhs)
316{
317 return operator<=(lhs.m_boostOptional, rhs.m_boostOptional);
318}
319
320template<typename T>
321constexpr bool
322operator>(const optional<T>& lhs, const optional<T>& rhs)
323{
324 return operator>(lhs.m_boostOptional, rhs.m_boostOptional);
325}
326
327template<typename T>
328constexpr bool
329operator>=(const optional<T>& lhs, const optional<T>& rhs)
330{
331 return operator>=(lhs.m_boostOptional, rhs.m_boostOptional);
332}
333
334template<typename T>
335constexpr optional<typename std::decay<T>::type>
336make_optional(T&& value)
337{
338 return optional<typename std::decay<T>::type>(std::forward<T>(value));
339}
340
341template<typename T, typename... Args>
342constexpr optional<T>
343make_optional(Args&&... args)
344{
345 return optional<T>(in_place, std::forward<Args>(args)...);
346}
347
348} // namespace ndn
349
Davide Pesavento6db13602017-02-26 22:05:53 -0500350#endif
Junxiao Shi1aecae22016-08-30 11:23:59 +0000351#endif // NDN_UTIL_BACKPORTS_OPTIONAL_HPP