blob: 73e106891250b3f20731e0bdd3769fc27091f066 [file] [log] [blame]
Junxiao Shi1aecae22016-08-30 11:23:59 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoba4fbbe2017-07-03 01:06:30 -04002/*
Junxiao Shi3688d722018-04-10 05:04:45 +00003 * Copyright (c) 2013-2018 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
Davide Pesavento1c597a12017-10-06 15:34:24 -040045#include "backports.hpp"
Junxiao Shi1aecae22016-08-30 11:23:59 +000046
Davide Pesavento1c597a12017-10-06 15:34:24 -040047#if (__cplusplus > 201402L) && NDN_CXX_HAS_INCLUDE(<optional>)
48# include <optional>
49# define NDN_CXX_HAVE_STD_OPTIONAL
50#elif (__cplusplus > 201103L) && NDN_CXX_HAS_INCLUDE(<experimental/optional>)
51# include <experimental/optional>
52# if __cpp_lib_experimental_optional >= 201411
53# define NDN_CXX_HAVE_EXPERIMENTAL_OPTIONAL
Davide Pesavento6db13602017-02-26 22:05:53 -050054# endif
55#endif
56
57#if defined(NDN_CXX_HAVE_STD_OPTIONAL)
58
59namespace ndn {
60using std::optional;
61using std::in_place;
62using std::nullopt;
63using std::bad_optional_access;
64using std::make_optional;
65} // namespace ndn
66
67#elif defined(NDN_CXX_HAVE_EXPERIMENTAL_OPTIONAL)
68
69namespace ndn {
70using std::experimental::optional;
71using std::experimental::in_place;
72using std::experimental::nullopt;
73using std::experimental::bad_optional_access;
74using std::experimental::make_optional;
75
76template<typename T, typename... Args>
77constexpr optional<T>
78make_optional(Args&&... args)
79{
80 return optional<T>(in_place, std::forward<Args>(args)...);
81}
82} // namespace ndn
83
84#else
85
Junxiao Shi1aecae22016-08-30 11:23:59 +000086#include <boost/none.hpp>
87#include <boost/optional.hpp>
88#include <boost/utility/typed_in_place_factory.hpp>
89
90namespace ndn {
91
92template<typename T>
93class optional;
94
95struct in_place_t
96{
97};
98constexpr in_place_t in_place{};
99
100class nullopt_t
101{
102public:
103 constexpr explicit
104 nullopt_t(int)
105 {
106 }
107};
Davide Pesavento6db13602017-02-26 22:05:53 -0500108constexpr nullopt_t nullopt{0};
Junxiao Shi1aecae22016-08-30 11:23:59 +0000109
Junxiao Shi1aecae22016-08-30 11:23:59 +0000110using boost::bad_optional_access;
Junxiao Shi1aecae22016-08-30 11:23:59 +0000111
112template<typename T>
113constexpr bool
114operator==(const optional<T>& lhs, const optional<T>& rhs);
115
116template<typename T>
117constexpr bool
118operator!=(const optional<T>& lhs, const optional<T>& rhs);
119
120template<typename T>
121constexpr bool
122operator<(const optional<T>& lhs, const optional<T>& rhs);
123
124template<typename T>
125constexpr bool
126operator<=(const optional<T>& lhs, const optional<T>& rhs);
127
128template<typename T>
129constexpr bool
130operator>(const optional<T>& lhs, const optional<T>& rhs);
131
132template<typename T>
133constexpr bool
134operator>=(const optional<T>& lhs, const optional<T>& rhs);
135
136template<typename T>
137class optional
138{
139public:
140 static_assert(!std::is_same<typename std::remove_cv<T>::type, in_place_t>::value &&
141 !std::is_same<typename std::remove_cv<T>::type, nullopt_t>::value &&
142 !std::is_reference<T>::value,
143 "Invalid instantiation of optional<T>");
144
145 typedef T value_type;
146
147 constexpr
148 optional() noexcept
149 {
150 }
151
152 constexpr
153 optional(nullopt_t) noexcept
154 {
155 }
156
157 constexpr
158 optional(const T& value)
159 : m_boostOptional(value)
160 {
161 }
162
163 template<typename... Args>
164 constexpr explicit
165 optional(in_place_t, Args&&... args)
166 : m_boostOptional(boost::in_place<T>(std::forward<Args>(args)...))
167 {
168 }
169
170 optional&
171 operator=(nullopt_t) noexcept
172 {
173 m_boostOptional = boost::none;
174 return *this;
175 }
176
177 optional&
178 operator=(const optional& other)
179 {
180 m_boostOptional = other.m_boostOptional;
181 return *this;
182 }
183
184 template<typename U,
185 typename = typename std::enable_if<std::is_same<typename std::decay<U>::type, T>::value>::type>
186 optional&
187 operator=(U&& value)
188 {
189 m_boostOptional = std::forward<U>(value);
190 return *this;
191 }
192
193public: // observers
194 constexpr const T*
195 operator->() const
196 {
197 return m_boostOptional.get_ptr();
198 }
199
200 T*
201 operator->()
202 {
203 return m_boostOptional.get_ptr();
204 }
205
206 constexpr const T&
207 operator*() const
208 {
209 return m_boostOptional.get();
210 }
211
212 T&
213 operator*()
214 {
215 return m_boostOptional.get();
216 }
217
218 constexpr explicit
219 operator bool() const noexcept
220 {
221 return static_cast<bool>(m_boostOptional);
222 }
223
224 const T&
225 value() const
226 {
227 return const_cast<optional*>(this)->value();
228 }
229
230 T&
231 value()
232 {
Junxiao Shi1aecae22016-08-30 11:23:59 +0000233 return m_boostOptional.value();
Junxiao Shi1aecae22016-08-30 11:23:59 +0000234 }
235
236 template<typename U>
237 constexpr T
238 value_or(U&& default_value) const
239 {
Junxiao Shi1aecae22016-08-30 11:23:59 +0000240 return m_boostOptional.value_or(default_value);
Junxiao Shi1aecae22016-08-30 11:23:59 +0000241 }
242
243public: // modifiers
244 void
245 swap(optional& other)
246 {
247 boost::swap(m_boostOptional, other.m_boostOptional);
248 }
249
Junxiao Shi3688d722018-04-10 05:04:45 +0000250 void
251 reset() noexcept
252 {
253 m_boostOptional = boost::none;
254 }
255
Junxiao Shi1aecae22016-08-30 11:23:59 +0000256 template<typename... Args>
257 void
258 emplace(Args&&... args)
259 {
260 m_boostOptional = boost::in_place<T>(std::forward<Args>(args)...);
261 }
262
263private:
264 boost::optional<T> m_boostOptional;
265
266 friend bool operator==<T>(const optional<T>&, const optional<T>&);
267 friend bool operator!=<T>(const optional<T>&, const optional<T>&);
268 friend bool operator< <T>(const optional<T>&, const optional<T>&);
269 friend bool operator<=<T>(const optional<T>&, const optional<T>&);
270 friend bool operator> <T>(const optional<T>&, const optional<T>&);
271 friend bool operator>=<T>(const optional<T>&, const optional<T>&);
272};
273
274template<typename T>
275constexpr bool
276operator==(const optional<T>& lhs, const optional<T>& rhs)
277{
278 return operator==(lhs.m_boostOptional, rhs.m_boostOptional);
279}
280
281template<typename T>
282constexpr bool
283operator!=(const optional<T>& lhs, const optional<T>& rhs)
284{
285 return operator!=(lhs.m_boostOptional, rhs.m_boostOptional);
286}
287
288template<typename T>
289constexpr bool
290operator<(const optional<T>& lhs, const optional<T>& rhs)
291{
292 return operator<(lhs.m_boostOptional, rhs.m_boostOptional);
293}
294
295template<typename T>
296constexpr bool
297operator<=(const optional<T>& lhs, const optional<T>& rhs)
298{
299 return operator<=(lhs.m_boostOptional, rhs.m_boostOptional);
300}
301
302template<typename T>
303constexpr bool
304operator>(const optional<T>& lhs, const optional<T>& rhs)
305{
306 return operator>(lhs.m_boostOptional, rhs.m_boostOptional);
307}
308
309template<typename T>
310constexpr bool
311operator>=(const optional<T>& lhs, const optional<T>& rhs)
312{
313 return operator>=(lhs.m_boostOptional, rhs.m_boostOptional);
314}
315
316template<typename T>
317constexpr optional<typename std::decay<T>::type>
318make_optional(T&& value)
319{
320 return optional<typename std::decay<T>::type>(std::forward<T>(value));
321}
322
323template<typename T, typename... Args>
324constexpr optional<T>
325make_optional(Args&&... args)
326{
327 return optional<T>(in_place, std::forward<Args>(args)...);
328}
329
330} // namespace ndn
331
Davide Pesavento6db13602017-02-26 22:05:53 -0500332#endif
Junxiao Shi1aecae22016-08-30 11:23:59 +0000333#endif // NDN_UTIL_BACKPORTS_OPTIONAL_HPP