blob: 8f1f498cb2884e9ba5b6d599fc320d954ee5cc46 [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/*
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
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
110#if BOOST_VERSION >= 105600
111using boost::bad_optional_access;
112#else
113class bad_optional_access : public std::logic_error
114{
115public:
116 bad_optional_access()
117 : std::logic_error("bad optional access")
118 {
119 }
120};
121#endif
122
123template<typename T>
124constexpr bool
125operator==(const optional<T>& lhs, const optional<T>& rhs);
126
127template<typename T>
128constexpr bool
129operator!=(const optional<T>& lhs, const optional<T>& rhs);
130
131template<typename T>
132constexpr bool
133operator<(const optional<T>& lhs, const optional<T>& rhs);
134
135template<typename T>
136constexpr bool
137operator<=(const optional<T>& lhs, const optional<T>& rhs);
138
139template<typename T>
140constexpr bool
141operator>(const optional<T>& lhs, const optional<T>& rhs);
142
143template<typename T>
144constexpr bool
145operator>=(const optional<T>& lhs, const optional<T>& rhs);
146
147template<typename T>
148class optional
149{
150public:
151 static_assert(!std::is_same<typename std::remove_cv<T>::type, in_place_t>::value &&
152 !std::is_same<typename std::remove_cv<T>::type, nullopt_t>::value &&
153 !std::is_reference<T>::value,
154 "Invalid instantiation of optional<T>");
155
156 typedef T value_type;
157
158 constexpr
159 optional() noexcept
160 {
161 }
162
163 constexpr
164 optional(nullopt_t) noexcept
165 {
166 }
167
168 constexpr
169 optional(const T& value)
170 : m_boostOptional(value)
171 {
172 }
173
174 template<typename... Args>
175 constexpr explicit
176 optional(in_place_t, Args&&... args)
177 : m_boostOptional(boost::in_place<T>(std::forward<Args>(args)...))
178 {
179 }
180
181 optional&
182 operator=(nullopt_t) noexcept
183 {
184 m_boostOptional = boost::none;
185 return *this;
186 }
187
188 optional&
189 operator=(const optional& other)
190 {
191 m_boostOptional = other.m_boostOptional;
192 return *this;
193 }
194
195 template<typename U,
196 typename = typename std::enable_if<std::is_same<typename std::decay<U>::type, T>::value>::type>
197 optional&
198 operator=(U&& value)
199 {
200 m_boostOptional = std::forward<U>(value);
201 return *this;
202 }
203
204public: // observers
205 constexpr const T*
206 operator->() const
207 {
208 return m_boostOptional.get_ptr();
209 }
210
211 T*
212 operator->()
213 {
214 return m_boostOptional.get_ptr();
215 }
216
217 constexpr const T&
218 operator*() const
219 {
220 return m_boostOptional.get();
221 }
222
223 T&
224 operator*()
225 {
226 return m_boostOptional.get();
227 }
228
229 constexpr explicit
230 operator bool() const noexcept
231 {
232 return static_cast<bool>(m_boostOptional);
233 }
234
235 const T&
236 value() const
237 {
238 return const_cast<optional*>(this)->value();
239 }
240
241 T&
242 value()
243 {
244#if BOOST_VERSION >= 105600
245 return m_boostOptional.value();
246#else
247 if (!m_boostOptional) {
248 BOOST_THROW_EXCEPTION(bad_optional_access());
249 }
250 return m_boostOptional.get();
251#endif
252 }
253
254 template<typename U>
255 constexpr T
256 value_or(U&& default_value) const
257 {
258#if BOOST_VERSION >= 105600
259 return m_boostOptional.value_or(default_value);
260#else
261 return m_boostOptional.get_value_or(default_value);
262#endif
263 }
264
265public: // modifiers
266 void
267 swap(optional& other)
268 {
269 boost::swap(m_boostOptional, other.m_boostOptional);
270 }
271
272 template<typename... Args>
273 void
274 emplace(Args&&... args)
275 {
276 m_boostOptional = boost::in_place<T>(std::forward<Args>(args)...);
277 }
278
279private:
280 boost::optional<T> m_boostOptional;
281
282 friend bool operator==<T>(const optional<T>&, const optional<T>&);
283 friend bool operator!=<T>(const optional<T>&, const optional<T>&);
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};
289
290template<typename T>
291constexpr bool
292operator==(const optional<T>& lhs, const optional<T>& rhs)
293{
294 return operator==(lhs.m_boostOptional, rhs.m_boostOptional);
295}
296
297template<typename T>
298constexpr bool
299operator!=(const optional<T>& lhs, const optional<T>& rhs)
300{
301 return operator!=(lhs.m_boostOptional, rhs.m_boostOptional);
302}
303
304template<typename T>
305constexpr bool
306operator<(const optional<T>& lhs, const optional<T>& rhs)
307{
308 return operator<(lhs.m_boostOptional, rhs.m_boostOptional);
309}
310
311template<typename T>
312constexpr bool
313operator<=(const optional<T>& lhs, const optional<T>& rhs)
314{
315 return operator<=(lhs.m_boostOptional, rhs.m_boostOptional);
316}
317
318template<typename T>
319constexpr bool
320operator>(const optional<T>& lhs, const optional<T>& rhs)
321{
322 return operator>(lhs.m_boostOptional, rhs.m_boostOptional);
323}
324
325template<typename T>
326constexpr bool
327operator>=(const optional<T>& lhs, const optional<T>& rhs)
328{
329 return operator>=(lhs.m_boostOptional, rhs.m_boostOptional);
330}
331
332template<typename T>
333constexpr optional<typename std::decay<T>::type>
334make_optional(T&& value)
335{
336 return optional<typename std::decay<T>::type>(std::forward<T>(value));
337}
338
339template<typename T, typename... Args>
340constexpr optional<T>
341make_optional(Args&&... args)
342{
343 return optional<T>(in_place, std::forward<Args>(args)...);
344}
345
346} // namespace ndn
347
Davide Pesavento6db13602017-02-26 22:05:53 -0500348#endif
Junxiao Shi1aecae22016-08-30 11:23:59 +0000349#endif // NDN_UTIL_BACKPORTS_OPTIONAL_HPP