blob: c93e855a83e040bcc01c2c742c24deb6f1ab7a8e [file] [log] [blame]
Junxiao Shi1aecae22016-08-30 11:23:59 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2016 Regents of the University of California.
4 *
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
47#include <boost/none.hpp>
48#include <boost/optional.hpp>
49#include <boost/utility/typed_in_place_factory.hpp>
50
51namespace ndn {
52
53template<typename T>
54class optional;
55
56struct in_place_t
57{
58};
59constexpr in_place_t in_place{};
60
61class nullopt_t
62{
63public:
64 constexpr explicit
65 nullopt_t(int)
66 {
67 }
68};
69constexpr nullopt_t nullopt(0);
70
71#if BOOST_VERSION >= 105600
72using boost::bad_optional_access;
73#else
74class bad_optional_access : public std::logic_error
75{
76public:
77 bad_optional_access()
78 : std::logic_error("bad optional access")
79 {
80 }
81};
82#endif
83
84template<typename T>
85constexpr bool
86operator==(const optional<T>& lhs, const optional<T>& rhs);
87
88template<typename T>
89constexpr bool
90operator!=(const optional<T>& lhs, const optional<T>& rhs);
91
92template<typename T>
93constexpr bool
94operator<(const optional<T>& lhs, const optional<T>& rhs);
95
96template<typename T>
97constexpr bool
98operator<=(const optional<T>& lhs, const optional<T>& rhs);
99
100template<typename T>
101constexpr bool
102operator>(const optional<T>& lhs, const optional<T>& rhs);
103
104template<typename T>
105constexpr bool
106operator>=(const optional<T>& lhs, const optional<T>& rhs);
107
108template<typename T>
109class optional
110{
111public:
112 static_assert(!std::is_same<typename std::remove_cv<T>::type, in_place_t>::value &&
113 !std::is_same<typename std::remove_cv<T>::type, nullopt_t>::value &&
114 !std::is_reference<T>::value,
115 "Invalid instantiation of optional<T>");
116
117 typedef T value_type;
118
119 constexpr
120 optional() noexcept
121 {
122 }
123
124 constexpr
125 optional(nullopt_t) noexcept
126 {
127 }
128
129 constexpr
130 optional(const T& value)
131 : m_boostOptional(value)
132 {
133 }
134
135 template<typename... Args>
136 constexpr explicit
137 optional(in_place_t, Args&&... args)
138 : m_boostOptional(boost::in_place<T>(std::forward<Args>(args)...))
139 {
140 }
141
142 optional&
143 operator=(nullopt_t) noexcept
144 {
145 m_boostOptional = boost::none;
146 return *this;
147 }
148
149 optional&
150 operator=(const optional& other)
151 {
152 m_boostOptional = other.m_boostOptional;
153 return *this;
154 }
155
156 template<typename U,
157 typename = typename std::enable_if<std::is_same<typename std::decay<U>::type, T>::value>::type>
158 optional&
159 operator=(U&& value)
160 {
161 m_boostOptional = std::forward<U>(value);
162 return *this;
163 }
164
165public: // observers
166 constexpr const T*
167 operator->() const
168 {
169 return m_boostOptional.get_ptr();
170 }
171
172 T*
173 operator->()
174 {
175 return m_boostOptional.get_ptr();
176 }
177
178 constexpr const T&
179 operator*() const
180 {
181 return m_boostOptional.get();
182 }
183
184 T&
185 operator*()
186 {
187 return m_boostOptional.get();
188 }
189
190 constexpr explicit
191 operator bool() const noexcept
192 {
193 return static_cast<bool>(m_boostOptional);
194 }
195
196 const T&
197 value() const
198 {
199 return const_cast<optional*>(this)->value();
200 }
201
202 T&
203 value()
204 {
205#if BOOST_VERSION >= 105600
206 return m_boostOptional.value();
207#else
208 if (!m_boostOptional) {
209 BOOST_THROW_EXCEPTION(bad_optional_access());
210 }
211 return m_boostOptional.get();
212#endif
213 }
214
215 template<typename U>
216 constexpr T
217 value_or(U&& default_value) const
218 {
219#if BOOST_VERSION >= 105600
220 return m_boostOptional.value_or(default_value);
221#else
222 return m_boostOptional.get_value_or(default_value);
223#endif
224 }
225
226public: // modifiers
227 void
228 swap(optional& other)
229 {
230 boost::swap(m_boostOptional, other.m_boostOptional);
231 }
232
233 template<typename... Args>
234 void
235 emplace(Args&&... args)
236 {
237 m_boostOptional = boost::in_place<T>(std::forward<Args>(args)...);
238 }
239
240private:
241 boost::optional<T> m_boostOptional;
242
243 friend bool operator==<T>(const optional<T>&, const optional<T>&);
244 friend bool operator!=<T>(const optional<T>&, const optional<T>&);
245 friend bool operator< <T>(const optional<T>&, const optional<T>&);
246 friend bool operator<=<T>(const optional<T>&, const optional<T>&);
247 friend bool operator> <T>(const optional<T>&, const optional<T>&);
248 friend bool operator>=<T>(const optional<T>&, const optional<T>&);
249};
250
251template<typename T>
252constexpr bool
253operator==(const optional<T>& lhs, const optional<T>& rhs)
254{
255 return operator==(lhs.m_boostOptional, rhs.m_boostOptional);
256}
257
258template<typename T>
259constexpr bool
260operator!=(const optional<T>& lhs, const optional<T>& rhs)
261{
262 return operator!=(lhs.m_boostOptional, rhs.m_boostOptional);
263}
264
265template<typename T>
266constexpr bool
267operator<(const optional<T>& lhs, const optional<T>& rhs)
268{
269 return operator<(lhs.m_boostOptional, rhs.m_boostOptional);
270}
271
272template<typename T>
273constexpr bool
274operator<=(const optional<T>& lhs, const optional<T>& rhs)
275{
276 return operator<=(lhs.m_boostOptional, rhs.m_boostOptional);
277}
278
279template<typename T>
280constexpr bool
281operator>(const optional<T>& lhs, const optional<T>& rhs)
282{
283 return operator>(lhs.m_boostOptional, rhs.m_boostOptional);
284}
285
286template<typename T>
287constexpr bool
288operator>=(const optional<T>& lhs, const optional<T>& rhs)
289{
290 return operator>=(lhs.m_boostOptional, rhs.m_boostOptional);
291}
292
293template<typename T>
294constexpr optional<typename std::decay<T>::type>
295make_optional(T&& value)
296{
297 return optional<typename std::decay<T>::type>(std::forward<T>(value));
298}
299
300template<typename T, typename... Args>
301constexpr optional<T>
302make_optional(Args&&... args)
303{
304 return optional<T>(in_place, std::forward<Args>(args)...);
305}
306
307} // namespace ndn
308
309#endif // NDN_UTIL_BACKPORTS_OPTIONAL_HPP