| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303 |
- // The MIT License (MIT)
- // Copyright (c) 2013-2022 Rapptz, ThePhD and contributors
- // Permission is hereby granted, free of charge, to any person obtaining a copy of
- // this software and associated documentation files (the "Software"), to deal in
- // the Software without restriction, including without limitation the rights to
- // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- // the Software, and to permit persons to whom the Software is furnished to do so,
- // subject to the following conditions:
- // The above copyright notice and this permission notice shall be included in all
- // copies or substantial portions of the Software.
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- // Taken from: TartanLlama/optional on Github, because
- // holy shit am I done dealing with C++11 constexpr
- ///
- // optional - An implementation of std::optional with extensions
- // Written in 2017 by Simon Brand (@TartanLlama)
- //
- // To the extent possible under law, the author(s) have dedicated all
- // copyright and related and neighboring rights to this software to the
- // public domain worldwide. This software is distributed without any warranty.
- //
- // You should have received a copy of the CC0 Public Domain Dedication
- // along with this software. If not, see
- // <http://creativecommons.org/publicdomain/zero/1.0/>.
- ///
- #ifndef SOL_TL_OPTIONAL_HPP
- #define SOL_TL_OPTIONAL_HPP
- #include <sol/version.hpp>
- #include <sol/in_place.hpp>
- #define SOL_TL_OPTIONAL_VERSION_MAJOR 0
- #define SOL_TL_OPTIONAL_VERSION_MINOR 5
- #include <exception>
- #include <functional>
- #include <new>
- #include <type_traits>
- #include <utility>
- #include <cstdlib>
- #include <optional>
- #if (defined(_MSC_VER) && _MSC_VER == 1900)
- #define SOL_TL_OPTIONAL_MSVC2015
- #endif
- #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__))
- #define SOL_TL_OPTIONAL_GCC49
- #endif
- #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && !defined(__clang__))
- #define SOL_TL_OPTIONAL_GCC54
- #endif
- #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && !defined(__clang__))
- #define SOL_TL_OPTIONAL_GCC55
- #endif
- #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__))
- // GCC < 5 doesn't support overloading on const&& for member functions
- #define SOL_TL_OPTIONAL_NO_CONSTRR
- // GCC < 5 doesn't support some standard C++11 type traits
- #define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) std::has_trivial_copy_constructor<T>::value
- #define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign<T>::value
- // This one will be different for GCC 5.7 if it's ever supported
- #define SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value
- // GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks std::vector
- // for non-copyable types
- #elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
- #ifndef SOL_TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
- #define SOL_TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
- namespace sol { namespace detail {
- template <class T>
- struct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T> { };
- #ifdef _GLIBCXX_VECTOR
- template <class T, class A>
- struct is_trivially_copy_constructible<std::vector<T, A>> : std::is_trivially_copy_constructible<T> { };
- #endif
- }} // namespace sol::detail
- #endif
- #define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) sol::detail::is_trivially_copy_constructible<T>::value
- #define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::is_trivially_copy_assignable<T>::value
- #define SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value
- #else
- #define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) std::is_trivially_copy_constructible<T>::value
- #define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::is_trivially_copy_assignable<T>::value
- #define SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value
- #endif
- #if __cplusplus > 201103L
- #define SOL_TL_OPTIONAL_CXX14
- #endif
- // constexpr implies const in C++11, not C++14
- #if (__cplusplus == 201103L || defined(SOL_TL_OPTIONAL_MSVC2015) || defined(SOL_TL_OPTIONAL_GCC49))
- /// \exclude
- #define SOL_TL_OPTIONAL_11_CONSTEXPR
- #else
- /// \exclude
- #define SOL_TL_OPTIONAL_11_CONSTEXPR constexpr
- #endif
- namespace sol {
- #ifndef SOL_TL_MONOSTATE_INPLACE_MUTEX
- #define SOL_TL_MONOSTATE_INPLACE_MUTEX
- /// \brief Used to represent an optional with no data; essentially a bool
- class monostate { };
- #endif
- template <class T>
- class optional;
- /// \exclude
- namespace detail {
- #ifndef SOL_TL_TRAITS_MUTEX
- #define SOL_TL_TRAITS_MUTEX
- // C++14-style aliases for brevity
- template <class T>
- using remove_const_t = typename std::remove_const<T>::type;
- template <class T>
- using remove_reference_t = typename std::remove_reference<T>::type;
- template <class T>
- using decay_t = typename std::decay<T>::type;
- template <bool E, class T = void>
- using enable_if_t = typename std::enable_if<E, T>::type;
- template <bool B, class T, class F>
- using conditional_t = typename std::conditional<B, T, F>::type;
- // std::conjunction from C++17
- template <class...>
- struct conjunction : std::true_type { };
- template <class B>
- struct conjunction<B> : B { };
- template <class B, class... Bs>
- struct conjunction<B, Bs...> : std::conditional<bool(B::value), conjunction<Bs...>, B>::type { };
- #if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
- #define SOL_TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND
- #endif
- // In C++11 mode, there's an issue in libc++'s std::mem_fn
- // which results in a hard-error when using it in a noexcept expression
- // in some cases. This is a check to workaround the common failing case.
- #ifdef SOL_TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND
- template <class T>
- struct is_pointer_to_non_const_member_func : std::false_type { };
- template <class T, class Ret, class... Args>
- struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)> : std::true_type { };
- template <class T, class Ret, class... Args>
- struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...)&> : std::true_type { };
- template <class T, class Ret, class... Args>
- struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) &&> : std::true_type { };
- template <class T, class Ret, class... Args>
- struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile> : std::true_type { };
- template <class T, class Ret, class... Args>
- struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile&> : std::true_type { };
- template <class T, class Ret, class... Args>
- struct is_pointer_to_non_const_member_func<Ret (T::*)(Args...) volatile&&> : std::true_type { };
- template <class T>
- struct is_const_or_const_ref : std::false_type { };
- template <class T>
- struct is_const_or_const_ref<T const&> : std::true_type { };
- template <class T>
- struct is_const_or_const_ref<T const> : std::true_type { };
- #endif
- // std::invoke from C++17
- // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
- template <typename Fn, typename... Args,
- #ifdef SOL_TL_OPTIONAL_LIBCXX_MEM_FN_WORKAROUND
- typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value && is_const_or_const_ref<Args...>::value)>,
- #endif
- typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>, int = 0>
- constexpr auto invoke(Fn&& f, Args&&... args) noexcept(noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
- -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
- return std::mem_fn(f)(std::forward<Args>(args)...);
- }
- template <typename Fn, typename... Args, typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>
- constexpr auto invoke(Fn&& f, Args&&... args) noexcept(noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
- -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
- return std::forward<Fn>(f)(std::forward<Args>(args)...);
- }
- // std::invoke_result from C++17
- template <class F, class, class... Us>
- struct invoke_result_impl;
- template <class F, class... Us>
- struct invoke_result_impl<F, decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()), Us...> {
- using type = decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
- };
- template <class F, class... Us>
- using invoke_result = invoke_result_impl<F, void, Us...>;
- template <class F, class... Us>
- using invoke_result_t = typename invoke_result<F, Us...>::type;
- #endif
- // std::void_t from C++17
- template <class...>
- struct voider {
- using type = void;
- };
- template <class... Ts>
- using void_t = typename voider<Ts...>::type;
- // Trait for checking if a type is a sol::optional
- template <class T>
- struct is_optional_impl : std::false_type { };
- template <class T>
- struct is_optional_impl<optional<T>> : std::true_type { };
- template <class T>
- using is_optional = is_optional_impl<decay_t<T>>;
- // Change void to sol::monostate
- template <class U>
- using fixup_void = conditional_t<std::is_void<U>::value, monostate, U>;
- template <class F, class U, class = invoke_result_t<F, U>>
- using get_map_return = optional<fixup_void<invoke_result_t<F, U>>>;
- // Check if invoking F for some Us returns void
- template <class F, class = void, class... U>
- struct returns_void_impl;
- template <class F, class... U>
- struct returns_void_impl<F, void_t<invoke_result_t<F, U...>>, U...> : std::is_void<invoke_result_t<F, U...>> { };
- template <class F, class... U>
- using returns_void = returns_void_impl<F, void, U...>;
- template <class T, class... U>
- using enable_if_ret_void = enable_if_t<returns_void<T&&, U...>::value>;
- template <class T, class... U>
- using disable_if_ret_void = enable_if_t<!returns_void<T&&, U...>::value>;
- template <class T, class U>
- using enable_forward_value = detail::enable_if_t<std::is_constructible<T, U&&>::value && !std::is_same<detail::decay_t<U>, in_place_t>::value
- && !std::is_same<optional<T>, detail::decay_t<U>>::value>;
- template <class T, class U, class Other>
- using enable_from_other = detail::enable_if_t<std::is_constructible<T, Other>::value && !std::is_constructible<T, optional<U>&>::value
- && !std::is_constructible<T, optional<U>&&>::value && !std::is_constructible<T, const optional<U>&>::value
- && !std::is_constructible<T, const optional<U>&&>::value && !std::is_convertible<optional<U>&, T>::value
- && !std::is_convertible<optional<U>&&, T>::value && !std::is_convertible<const optional<U>&, T>::value
- && !std::is_convertible<const optional<U>&&, T>::value>;
- template <class T, class U>
- using enable_assign_forward = detail::enable_if_t<!std::is_same<optional<T>, detail::decay_t<U>>::value
- && !detail::conjunction<std::is_scalar<T>, std::is_same<T, detail::decay_t<U>>>::value && std::is_constructible<T, U>::value
- && std::is_assignable<T&, U>::value>;
- template <class T, class U, class Other>
- using enable_assign_from_other = detail::enable_if_t<std::is_constructible<T, Other>::value && std::is_assignable<T&, Other>::value
- && !std::is_constructible<T, optional<U>&>::value && !std::is_constructible<T, optional<U>&&>::value
- && !std::is_constructible<T, const optional<U>&>::value && !std::is_constructible<T, const optional<U>&&>::value
- && !std::is_convertible<optional<U>&, T>::value && !std::is_convertible<optional<U>&&, T>::value
- && !std::is_convertible<const optional<U>&, T>::value && !std::is_convertible<const optional<U>&&, T>::value
- && !std::is_assignable<T&, optional<U>&>::value && !std::is_assignable<T&, optional<U>&&>::value
- && !std::is_assignable<T&, const optional<U>&>::value && !std::is_assignable<T&, const optional<U>&&>::value>;
- #ifdef _MSC_VER
- // TODO make a version which works with MSVC
- template <class T, class U = T>
- struct is_swappable : std::true_type { };
- template <class T, class U = T>
- struct is_nothrow_swappable : std::true_type { };
- #else
- // https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
- namespace swap_adl_tests {
- // if swap ADL finds this then it would call std::swap otherwise (same
- // signature)
- struct tag { };
- template <class T>
- tag swap(T&, T&);
- template <class T, std::size_t N>
- tag swap(T (&a)[N], T (&b)[N]);
- // helper functions to test if an unqualified swap is possible, and if it
- // becomes std::swap
- template <class, class>
- std::false_type can_swap(...) noexcept(false);
- template <class T, class U, class = decltype(swap(std::declval<T&>(), std::declval<U&>()))>
- std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T&>(), std::declval<U&>())));
- template <class, class>
- std::false_type uses_std(...);
- template <class T, class U>
- std::is_same<decltype(swap(std::declval<T&>(), std::declval<U&>())), tag> uses_std(int);
- template <class T>
- struct is_std_swap_noexcept
- : std::integral_constant<bool, std::is_nothrow_move_constructible<T>::value && std::is_nothrow_move_assignable<T>::value> { };
- template <class T, std::size_t N>
- struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> { };
- template <class T, class U>
- struct is_adl_swap_noexcept : std::integral_constant<bool, noexcept(can_swap<T, U>(0))> { };
- } // namespace swap_adl_tests
- template <class T, class U = T>
- struct is_swappable : std::integral_constant<bool,
- decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value
- && (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value
- || (std::is_move_assignable<T>::value && std::is_move_constructible<T>::value))> { };
- template <class T, std::size_t N>
- struct is_swappable<T[N], T[N]> : std::integral_constant<bool,
- decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value
- && (!decltype(detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value || is_swappable<T, T>::value)> { };
- template <class T, class U = T>
- struct is_nothrow_swappable
- : std::integral_constant<bool,
- is_swappable<T, U>::value
- && ((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value&& detail::swap_adl_tests::is_std_swap_noexcept<T>::value)
- || (!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value&& detail::swap_adl_tests::is_adl_swap_noexcept<T, U>::value))> { };
- #endif
- // The storage base manages the actual storage, and correctly propagates
- // trivial destroyion from T. This case is for when T is not trivially
- // destructible.
- template <class T, bool = ::std::is_trivially_destructible<T>::value>
- struct optional_storage_base {
- SOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept : m_dummy(), m_has_value(false) {
- }
- template <class... U>
- SOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U&&... u) : m_value(std::forward<U>(u)...), m_has_value(true) {
- }
- ~optional_storage_base() {
- if (m_has_value) {
- m_value.~T();
- m_has_value = false;
- }
- }
- struct dummy { };
- union {
- dummy m_dummy;
- T m_value;
- };
- bool m_has_value;
- };
- // This case is for when T is trivially destructible.
- template <class T>
- struct optional_storage_base<T, true> {
- SOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept : m_dummy(), m_has_value(false) {
- }
- template <class... U>
- SOL_TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U&&... u) : m_value(std::forward<U>(u)...), m_has_value(true) {
- }
- // No destructor, so this class is trivially destructible
- struct dummy { };
- union {
- dummy m_dummy;
- T m_value;
- };
- bool m_has_value = false;
- };
- // This base class provides some handy member functions which can be used in
- // further derived classes
- template <class T>
- struct optional_operations_base : optional_storage_base<T> {
- using optional_storage_base<T>::optional_storage_base;
- void hard_reset() noexcept {
- get().~T();
- this->m_has_value = false;
- }
- template <class... Args>
- void construct(Args&&... args) noexcept {
- new (std::addressof(this->m_value)) T(std::forward<Args>(args)...);
- this->m_has_value = true;
- }
- template <class Opt>
- void assign(Opt&& rhs) {
- if (this->has_value()) {
- if (rhs.has_value()) {
- this->m_value = std::forward<Opt>(rhs).get();
- }
- else {
- this->m_value.~T();
- this->m_has_value = false;
- }
- }
- else if (rhs.has_value()) {
- construct(std::forward<Opt>(rhs).get());
- }
- }
- bool has_value() const {
- return this->m_has_value;
- }
- SOL_TL_OPTIONAL_11_CONSTEXPR T& get() & {
- return this->m_value;
- }
- SOL_TL_OPTIONAL_11_CONSTEXPR const T& get() const& {
- return this->m_value;
- }
- SOL_TL_OPTIONAL_11_CONSTEXPR T&& get() && {
- return std::move(this->m_value);
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- constexpr const T&& get() const&& {
- return std::move(this->m_value);
- }
- #endif
- };
- // This class manages conditionally having a trivial copy constructor
- // This specialization is for when T is trivially copy constructible
- template <class T, bool = SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>
- struct optional_copy_base : optional_operations_base<T> {
- using optional_operations_base<T>::optional_operations_base;
- };
- // This specialization is for when T is not trivially copy constructible
- template <class T>
- struct optional_copy_base<T, false> : optional_operations_base<T> {
- using base_t = optional_operations_base<T>;
- using base_t::base_t;
- optional_copy_base() = default;
- optional_copy_base(const optional_copy_base& rhs) : base_t() {
- if (rhs.has_value()) {
- this->construct(rhs.get());
- }
- else {
- this->m_has_value = false;
- }
- }
- optional_copy_base(optional_copy_base&& rhs) = default;
- optional_copy_base& operator=(const optional_copy_base& rhs) = default;
- optional_copy_base& operator=(optional_copy_base&& rhs) = default;
- };
- // This class manages conditionally having a trivial move constructor
- // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
- // doesn't implement an analogue to std::is_trivially_move_constructible. We
- // have to make do with a non-trivial move constructor even if T is trivially
- // move constructible
- #ifndef SOL_TL_OPTIONAL_GCC49
- template <class T, bool = std::is_trivially_move_constructible<T>::value>
- struct optional_move_base : optional_copy_base<T> {
- using optional_copy_base<T>::optional_copy_base;
- };
- #else
- template <class T, bool = false>
- struct optional_move_base;
- #endif
- template <class T>
- struct optional_move_base<T, false> : optional_copy_base<T> {
- using optional_copy_base<T>::optional_copy_base;
- optional_move_base() = default;
- optional_move_base(const optional_move_base& rhs) = default;
- optional_move_base(optional_move_base&& rhs) noexcept(std::is_nothrow_move_constructible<T>::value) {
- if (rhs.has_value()) {
- this->construct(std::move(rhs.get()));
- }
- else {
- this->m_has_value = false;
- }
- }
- optional_move_base& operator=(const optional_move_base& rhs) = default;
- optional_move_base& operator=(optional_move_base&& rhs) = default;
- };
- // This class manages conditionally having a trivial copy assignment operator
- template <class T,
- bool = SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) && SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)
- && SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T)>
- struct optional_copy_assign_base : optional_move_base<T> {
- using optional_move_base<T>::optional_move_base;
- };
- template <class T>
- struct optional_copy_assign_base<T, false> : optional_move_base<T> {
- using optional_move_base<T>::optional_move_base;
- optional_copy_assign_base() = default;
- optional_copy_assign_base(const optional_copy_assign_base& rhs) = default;
- optional_copy_assign_base(optional_copy_assign_base&& rhs) = default;
- optional_copy_assign_base& operator=(const optional_copy_assign_base& rhs) {
- this->assign(rhs);
- return *this;
- }
- optional_copy_assign_base& operator=(optional_copy_assign_base&& rhs) = default;
- };
- // This class manages conditionally having a trivial move assignment operator
- // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
- // doesn't implement an analogue to std::is_trivially_move_assignable. We have
- // to make do with a non-trivial move assignment operator even if T is trivially
- // move assignable
- #ifndef SOL_TL_OPTIONAL_GCC49
- template <class T,
- bool = std::is_trivially_destructible<T>::value&& std::is_trivially_move_constructible<T>::value&& std::is_trivially_move_assignable<T>::value>
- struct optional_move_assign_base : optional_copy_assign_base<T> {
- using optional_copy_assign_base<T>::optional_copy_assign_base;
- };
- #else
- template <class T, bool = false>
- struct optional_move_assign_base;
- #endif
- template <class T>
- struct optional_move_assign_base<T, false> : optional_copy_assign_base<T> {
- using optional_copy_assign_base<T>::optional_copy_assign_base;
- optional_move_assign_base() = default;
- optional_move_assign_base(const optional_move_assign_base& rhs) = default;
- optional_move_assign_base(optional_move_assign_base&& rhs) = default;
- optional_move_assign_base& operator=(const optional_move_assign_base& rhs) = default;
- optional_move_assign_base& operator=(optional_move_assign_base&& rhs) noexcept(
- std::is_nothrow_move_constructible<T>::value&& std::is_nothrow_move_assignable<T>::value) {
- this->assign(std::move(rhs));
- return *this;
- }
- };
- // optional_delete_ctor_base will conditionally delete copy and move
- // constructors depending on whether T is copy/move constructible
- template <class T, bool EnableCopy = std::is_copy_constructible<T>::value, bool EnableMove = std::is_move_constructible<T>::value>
- struct optional_delete_ctor_base {
- optional_delete_ctor_base() = default;
- optional_delete_ctor_base(const optional_delete_ctor_base&) = default;
- optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = default;
- optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default;
- optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default;
- };
- template <class T>
- struct optional_delete_ctor_base<T, true, false> {
- optional_delete_ctor_base() = default;
- optional_delete_ctor_base(const optional_delete_ctor_base&) = default;
- optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = delete;
- optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default;
- optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default;
- };
- template <class T>
- struct optional_delete_ctor_base<T, false, true> {
- optional_delete_ctor_base() = default;
- optional_delete_ctor_base(const optional_delete_ctor_base&) = delete;
- optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = default;
- optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default;
- optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default;
- };
- template <class T>
- struct optional_delete_ctor_base<T, false, false> {
- optional_delete_ctor_base() = default;
- optional_delete_ctor_base(const optional_delete_ctor_base&) = delete;
- optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = delete;
- optional_delete_ctor_base& operator=(const optional_delete_ctor_base&) = default;
- optional_delete_ctor_base& operator=(optional_delete_ctor_base&&) noexcept = default;
- };
- // optional_delete_assign_base will conditionally delete copy and move
- // constructors depending on whether T is copy/move constructible + assignable
- template <class T, bool EnableCopy = (std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value),
- bool EnableMove = (std::is_move_constructible<T>::value && std::is_move_assignable<T>::value)>
- struct optional_delete_assign_base {
- optional_delete_assign_base() = default;
- optional_delete_assign_base(const optional_delete_assign_base&) = default;
- optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;
- optional_delete_assign_base& operator=(const optional_delete_assign_base&) = default;
- optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = default;
- };
- template <class T>
- struct optional_delete_assign_base<T, true, false> {
- optional_delete_assign_base() = default;
- optional_delete_assign_base(const optional_delete_assign_base&) = default;
- optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;
- optional_delete_assign_base& operator=(const optional_delete_assign_base&) = default;
- optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = delete;
- };
- template <class T>
- struct optional_delete_assign_base<T, false, true> {
- optional_delete_assign_base() = default;
- optional_delete_assign_base(const optional_delete_assign_base&) = default;
- optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;
- optional_delete_assign_base& operator=(const optional_delete_assign_base&) = delete;
- optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = default;
- };
- template <class T>
- struct optional_delete_assign_base<T, false, false> {
- optional_delete_assign_base() = default;
- optional_delete_assign_base(const optional_delete_assign_base&) = default;
- optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;
- optional_delete_assign_base& operator=(const optional_delete_assign_base&) = delete;
- optional_delete_assign_base& operator=(optional_delete_assign_base&&) noexcept = delete;
- };
- } // namespace detail
- /// \brief A tag type to represent an empty optional
- using nullopt_t = std::nullopt_t;
- /// \brief Represents an empty optional
- /// \synopsis static constexpr nullopt_t nullopt;
- ///
- /// *Examples*:
- /// ```
- /// sol::optional<int> a = sol::nullopt;
- /// void foo (sol::optional<int>);
- /// foo(sol::nullopt); //pass an empty optional
- /// ```
- using std::nullopt;
- /// @brief An exception for when an optional is accessed through specific methods while it is not engaged.
- class bad_optional_access : public std::exception {
- public:
- /// @brief Default-constructs an optional exception.
- bad_optional_access() = default;
- /// @brief Returns a pointer to a null-terminated string containing the reason for the exception.
- const char* what() const noexcept override {
- return "Optional has no value";
- }
- };
- /// An optional object is an object that contains the storage for another
- /// object and manages the lifetime of this contained object, if any. The
- /// contained object may be initialized after the optional object has been
- /// initialized, and may be destroyed before the optional object has been
- /// destroyed. The initialization state of the contained object is tracked by
- /// the optional object.
- template <class T>
- class optional : private detail::optional_move_assign_base<T>,
- private detail::optional_delete_ctor_base<T>,
- private detail::optional_delete_assign_base<T> {
- using base = detail::optional_move_assign_base<T>;
- static_assert(!std::is_same<T, in_place_t>::value, "instantiation of optional with in_place_t is ill-formed");
- static_assert(!std::is_same<detail::decay_t<T>, nullopt_t>::value, "instantiation of optional with nullopt_t is ill-formed");
- public:
- // The different versions for C++14 and 11 are needed because deduced return
- // types are not SFINAE-safe. This provides better support for things like
- // generic lambdas. C.f.
- // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html
- #if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55)
- /// \group and_then
- /// Carries out some operation which returns an optional on the stored
- /// object if there is one. \requires `std::invoke(std::forward<F>(f),
- /// value())` returns a `std::optional<U>` for some `U`. \returns Let `U` be
- /// the result of `std::invoke(std::forward<F>(f), value())`. Returns a
- /// `std::optional<U>`. The return value is empty if `*this` is empty,
- /// otherwise the return value of `std::invoke(std::forward<F>(f), value())`
- /// is returned.
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) & {
- using result = detail::invoke_result_t<F, T&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);
- }
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &&;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) && {
- using result = detail::invoke_result_t<F, T&&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt);
- }
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &;
- template <class F>
- constexpr auto and_then(F&& f) const& {
- using result = detail::invoke_result_t<F, const T&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &&;
- template <class F>
- constexpr auto and_then(F&& f) const&& {
- using result = detail::invoke_result_t<F, const T&&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt);
- }
- #endif
- #else
- /// \group and_then
- /// Carries out some operation which returns an optional on the stored
- /// object if there is one. \requires `std::invoke(std::forward<F>(f),
- /// value())` returns a `std::optional<U>` for some `U`.
- /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
- /// value())`. Returns a `std::optional<U>`. The return value is empty if
- /// `*this` is empty, otherwise the return value of
- /// `std::invoke(std::forward<F>(f), value())` is returned.
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&> and_then(F&& f) & {
- using result = detail::invoke_result_t<F, T&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);
- }
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &&;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&&> and_then(F&& f) && {
- using result = detail::invoke_result_t<F, T&&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt);
- }
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &;
- template <class F>
- constexpr detail::invoke_result_t<F, const T&> and_then(F&& f) const& {
- using result = detail::invoke_result_t<F, const T&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &&;
- template <class F>
- constexpr detail::invoke_result_t<F, const T&&> and_then(F&& f) const&& {
- using result = detail::invoke_result_t<F, const T&&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt);
- }
- #endif
- #endif
- #if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55)
- /// \brief Carries out some operation on the stored object if there is one.
- /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
- /// value())`. Returns a `std::optional<U>`. The return value is empty if
- /// `*this` is empty, otherwise an `optional<U>` is constructed from the
- /// return value of `std::invoke(std::forward<F>(f), value())` and is
- /// returned.
- ///
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) &;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) & {
- return optional_map_impl(*this, std::forward<F>(f));
- }
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) &&;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) && {
- return optional_map_impl(std::move(*this), std::forward<F>(f));
- }
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) const&;
- template <class F>
- constexpr auto map(F&& f) const& {
- return optional_map_impl(*this, std::forward<F>(f));
- }
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) const&&;
- template <class F>
- constexpr auto map(F&& f) const&& {
- return optional_map_impl(std::move(*this), std::forward<F>(f));
- }
- #else
- /// \brief Carries out some operation on the stored object if there is one.
- /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
- /// value())`. Returns a `std::optional<U>`. The return value is empty if
- /// `*this` is empty, otherwise an `optional<U>` is constructed from the
- /// return value of `std::invoke(std::forward<F>(f), value())` and is
- /// returned.
- ///
- /// \group map
- /// \synopsis template <class F> auto map(F &&f) &;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval<optional&>(), std::declval<F&&>())) map(F&& f) & {
- return optional_map_impl(*this, std::forward<F>(f));
- }
- /// \group map
- /// \synopsis template <class F> auto map(F &&f) &&;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval<optional&&>(), std::declval<F&&>())) map(F&& f) && {
- return optional_map_impl(std::move(*this), std::forward<F>(f));
- }
- /// \group map
- /// \synopsis template <class F> auto map(F &&f) const&;
- template <class F>
- constexpr decltype(optional_map_impl(std::declval<const optional&>(), std::declval<F&&>())) map(F&& f) const& {
- return optional_map_impl(*this, std::forward<F>(f));
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group map
- /// \synopsis template <class F> auto map(F &&f) const&&;
- template <class F>
- constexpr decltype(optional_map_impl(std::declval<const optional&&>(), std::declval<F&&>())) map(F&& f) const&& {
- return optional_map_impl(std::move(*this), std::forward<F>(f));
- }
- #endif
- #endif
- /// \brief Calls `f` if the optional is empty
- /// \requires `std::invoke_result_t<F>` must be void or convertible to
- /// `optional<T>`.
- /// \effects If `*this` has a value, returns `*this`.
- /// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)` and returns
- /// `std::nullopt`. Otherwise, returns `std::forward<F>(f)()`.
- ///
- /// \group or_else
- /// \synopsis template <class F> optional<T> or_else (F &&f) &;
- template <class F, detail::enable_if_ret_void<F>* = nullptr>
- optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & {
- if (has_value())
- return *this;
- std::forward<F>(f)();
- return nullopt;
- }
- /// \exclude
- template <class F, detail::disable_if_ret_void<F>* = nullptr>
- optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & {
- return has_value() ? *this : std::forward<F>(f)();
- }
- /// \group or_else
- /// \synopsis template <class F> optional<T> or_else (F &&f) &&;
- template <class F, detail::enable_if_ret_void<F>* = nullptr>
- optional<T> or_else(F&& f) && {
- if (has_value())
- return std::move(*this);
- std::forward<F>(f)();
- return nullopt;
- }
- /// \exclude
- template <class F, detail::disable_if_ret_void<F>* = nullptr>
- optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) && {
- return has_value() ? std::move(*this) : std::forward<F>(f)();
- }
- /// \group or_else
- /// \synopsis template <class F> optional<T> or_else (F &&f) const &;
- template <class F, detail::enable_if_ret_void<F>* = nullptr>
- optional<T> or_else(F&& f) const& {
- if (has_value())
- return *this;
- std::forward<F>(f)();
- return nullopt;
- }
- /// \exclude
- template <class F, detail::disable_if_ret_void<F>* = nullptr>
- optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) const& {
- return has_value() ? *this : std::forward<F>(f)();
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \exclude
- template <class F, detail::enable_if_ret_void<F>* = nullptr>
- optional<T> or_else(F&& f) const&& {
- if (has_value())
- return std::move(*this);
- std::forward<F>(f)();
- return nullopt;
- }
- /// \exclude
- template <class F, detail::disable_if_ret_void<F>* = nullptr>
- optional<T> or_else(F&& f) const&& {
- return has_value() ? std::move(*this) : std::forward<F>(f)();
- }
- #endif
- /// \brief Maps the stored value with `f` if there is one, otherwise returns
- /// `u`.
- ///
- /// \details If there is a value stored, then `f` is called with `**this`
- /// and the value is returned. Otherwise `u` is returned.
- ///
- /// \group map_or
- template <class F, class U>
- U map_or(F&& f, U&& u) & {
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u);
- }
- /// \group map_or
- template <class F, class U>
- U map_or(F&& f, U&& u) && {
- return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u);
- }
- /// \group map_or
- template <class F, class U>
- U map_or(F&& f, U&& u) const& {
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u);
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group map_or
- template <class F, class U>
- U map_or(F&& f, U&& u) const&& {
- return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u);
- }
- #endif
- /// \brief Maps the stored value with `f` if there is one, otherwise calls
- /// `u` and returns the result.
- ///
- /// \details If there is a value stored, then `f` is
- /// called with `**this` and the value is returned. Otherwise
- /// `std::forward<U>(u)()` is returned.
- ///
- /// \group map_or_else
- /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) &;
- template <class F, class U>
- detail::invoke_result_t<U> map_or_else(F&& f, U&& u) & {
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)();
- }
- /// \group map_or_else
- /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u)
- /// &&;
- template <class F, class U>
- detail::invoke_result_t<U> map_or_else(F&& f, U&& u) && {
- return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)();
- }
- /// \group map_or_else
- /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u)
- /// const &;
- template <class F, class U>
- detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const& {
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)();
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group map_or_else
- /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u)
- /// const &&;
- template <class F, class U>
- detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const&& {
- return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)();
- }
- #endif
- /// \returns `u` if `*this` has a value, otherwise an empty optional.
- template <class U>
- constexpr optional<typename std::decay<U>::type> conjunction(U&& u) const {
- using result = optional<detail::decay_t<U>>;
- return has_value() ? result { u } : result { nullopt };
- }
- /// \returns `rhs` if `*this` is empty, otherwise the current value.
- /// \group disjunction
- SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) & {
- return has_value() ? *this : rhs;
- }
- /// \group disjunction
- constexpr optional disjunction(const optional& rhs) const& {
- return has_value() ? *this : rhs;
- }
- /// \group disjunction
- SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) && {
- return has_value() ? std::move(*this) : rhs;
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group disjunction
- constexpr optional disjunction(const optional& rhs) const&& {
- return has_value() ? std::move(*this) : rhs;
- }
- #endif
- /// \group disjunction
- SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) & {
- return has_value() ? *this : std::move(rhs);
- }
- /// \group disjunction
- constexpr optional disjunction(optional&& rhs) const& {
- return has_value() ? *this : std::move(rhs);
- }
- /// \group disjunction
- SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) && {
- return has_value() ? std::move(*this) : std::move(rhs);
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group disjunction
- constexpr optional disjunction(optional&& rhs) const&& {
- return has_value() ? std::move(*this) : std::move(rhs);
- }
- #endif
- /// Takes the value out of the optional, leaving it empty
- /// \group take
- optional take() & {
- optional ret = *this;
- reset();
- return ret;
- }
- /// \group take
- optional take() const& {
- optional ret = *this;
- reset();
- return ret;
- }
- /// \group take
- optional take() && {
- optional ret = std::move(*this);
- reset();
- return ret;
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group take
- optional take() const&& {
- optional ret = std::move(*this);
- reset();
- return ret;
- }
- #endif
- using value_type = T;
- /// Constructs an optional that does not contain a value.
- /// \group ctor_empty
- constexpr optional() noexcept = default;
- /// \group ctor_empty
- constexpr optional(nullopt_t) noexcept {
- }
- /// Copy constructor
- ///
- /// If `rhs` contains a value, the stored value is direct-initialized with
- /// it. Otherwise, the constructed optional is empty.
- SOL_TL_OPTIONAL_11_CONSTEXPR optional(const optional& rhs) = default;
- /// Move constructor
- ///
- /// If `rhs` contains a value, the stored value is direct-initialized with
- /// it. Otherwise, the constructed optional is empty.
- SOL_TL_OPTIONAL_11_CONSTEXPR optional(optional&& rhs) = default;
- /// Constructs the stored value in-place using the given arguments.
- /// \group in_place
- /// \synopsis template <class... Args> constexpr explicit optional(in_place_t, Args&&... args);
- template <class... Args>
- constexpr explicit optional(detail::enable_if_t<std::is_constructible<T, Args...>::value, in_place_t>, Args&&... args)
- : base(in_place, std::forward<Args>(args)...) {
- }
- /// \group in_place
- /// \synopsis template <class U, class... Args> \n constexpr explicit optional(in_place_t, std::initializer_list<U>&, Args&&... args);
- template <class U, class... Args>
- SOL_TL_OPTIONAL_11_CONSTEXPR explicit optional(detail::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, in_place_t>,
- std::initializer_list<U> il, Args&&... args) {
- this->construct(il, std::forward<Args>(args)...);
- }
- #if 0 // SOL_MODIFICATION
- /// Constructs the stored value with `u`.
- /// \synopsis template <class U=T> constexpr optional(U &&u);
- template <class U = T, detail::enable_if_t<std::is_convertible<U&&, T>::value>* = nullptr, detail::enable_forward_value<T, U>* = nullptr>
- constexpr optional(U&& u) : base(in_place, std::forward<U>(u)) {
- }
- /// \exclude
- template <class U = T, detail::enable_if_t<!std::is_convertible<U&&, T>::value>* = nullptr, detail::enable_forward_value<T, U>* = nullptr>
- constexpr explicit optional(U&& u) : base(in_place, std::forward<U>(u)) {
- }
- #else
- /// Constructs the stored value with `u`.
- /// \synopsis template <class U=T> constexpr optional(U &&u);
- constexpr optional(T&& u) : base(in_place, std::move(u)) {
- }
- /// \exclude
- constexpr optional(const T& u) : base(in_place, u) {
- }
- #endif // sol2 modification
- /// Converting copy constructor.
- /// \synopsis template <class U> optional(const optional<U> &rhs);
- template <class U, detail::enable_from_other<T, U, const U&>* = nullptr, detail::enable_if_t<std::is_convertible<const U&, T>::value>* = nullptr>
- optional(const optional<U>& rhs) {
- if (rhs.has_value()) {
- this->construct(*rhs);
- }
- }
- /// \exclude
- template <class U, detail::enable_from_other<T, U, const U&>* = nullptr, detail::enable_if_t<!std::is_convertible<const U&, T>::value>* = nullptr>
- explicit optional(const optional<U>& rhs) {
- if (rhs.has_value()) {
- this->construct(*rhs);
- }
- }
- /// Converting move constructor.
- /// \synopsis template <class U> optional(optional<U> &&rhs);
- template <class U, detail::enable_from_other<T, U, U&&>* = nullptr, detail::enable_if_t<std::is_convertible<U&&, T>::value>* = nullptr>
- optional(optional<U>&& rhs) {
- if (rhs.has_value()) {
- this->construct(std::move(*rhs));
- }
- }
- /// \exclude
- template <class U, detail::enable_from_other<T, U, U&&>* = nullptr, detail::enable_if_t<!std::is_convertible<U&&, T>::value>* = nullptr>
- explicit optional(optional<U>&& rhs) {
- this->construct(std::move(*rhs));
- }
- /// Destroys the stored value if there is one.
- ~optional() = default;
- /// Assignment to empty.
- ///
- /// Destroys the current value if there is one.
- optional& operator=(nullopt_t) noexcept {
- if (has_value()) {
- this->m_value.~T();
- this->m_has_value = false;
- }
- return *this;
- }
- /// Copy assignment.
- ///
- /// Copies the value from `rhs` if there is one. Otherwise resets the stored
- /// value in `*this`.
- optional& operator=(const optional& rhs) = default;
- /// Move assignment.
- ///
- /// Moves the value from `rhs` if there is one. Otherwise resets the stored
- /// value in `*this`.
- optional& operator=(optional&& rhs) = default;
- /// Assigns the stored value from `u`, destroying the old value if there was
- /// one.
- /// \synopsis optional &operator=(U &&u);
- template <class U = T, detail::enable_assign_forward<T, U>* = nullptr>
- optional& operator=(U&& u) {
- if (has_value()) {
- this->m_value = std::forward<U>(u);
- }
- else {
- this->construct(std::forward<U>(u));
- }
- return *this;
- }
- /// Converting copy assignment operator.
- ///
- /// Copies the value from `rhs` if there is one. Otherwise resets the stored
- /// value in `*this`.
- /// \synopsis optional &operator=(const optional<U> & rhs);
- template <class U, detail::enable_assign_from_other<T, U, const U&>* = nullptr>
- optional& operator=(const optional<U>& rhs) {
- if (has_value()) {
- if (rhs.has_value()) {
- this->m_value = *rhs;
- }
- else {
- this->hard_reset();
- }
- }
- if (rhs.has_value()) {
- this->construct(*rhs);
- }
- return *this;
- }
- // TODO check exception guarantee
- /// Converting move assignment operator.
- ///
- /// Moves the value from `rhs` if there is one. Otherwise resets the stored
- /// value in `*this`.
- /// \synopsis optional &operator=(optional<U> && rhs);
- template <class U, detail::enable_assign_from_other<T, U, U>* = nullptr>
- optional& operator=(optional<U>&& rhs) {
- if (has_value()) {
- if (rhs.has_value()) {
- this->m_value = std::move(*rhs);
- }
- else {
- this->hard_reset();
- }
- }
- if (rhs.has_value()) {
- this->construct(std::move(*rhs));
- }
- return *this;
- }
- /// Constructs the value in-place, destroying the current one if there is
- /// one.
- /// \group emplace
- template <class... Args>
- T& emplace(Args&&... args) {
- static_assert(std::is_constructible<T, Args&&...>::value, "T must be constructible with Args");
- *this = nullopt;
- this->construct(std::forward<Args>(args)...);
- return value();
- }
- /// \group emplace
- /// \synopsis template <class U, class... Args> \n T& emplace(std::initializer_list<U> il, Args &&... args);
- template <class U, class... Args>
- detail::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, T&> emplace(std::initializer_list<U> il, Args&&... args) {
- *this = nullopt;
- this->construct(il, std::forward<Args>(args)...);
- return value();
- }
- /// Swaps this optional with the other.
- ///
- /// If neither optionals have a value, nothing happens.
- /// If both have a value, the values are swapped.
- /// If one has a value, it is moved to the other and the movee is left
- /// valueless.
- void swap(optional& rhs) noexcept(std::is_nothrow_move_constructible<T>::value&& detail::is_nothrow_swappable<T>::value) {
- if (has_value()) {
- if (rhs.has_value()) {
- using std::swap;
- swap(**this, *rhs);
- }
- else {
- new (std::addressof(rhs.m_value)) T(std::move(this->m_value));
- this->m_value.T::~T();
- }
- }
- else if (rhs.has_value()) {
- new (std::addressof(this->m_value)) T(std::move(rhs.m_value));
- rhs.m_value.T::~T();
- }
- }
- /// \returns a pointer to the stored value
- /// \requires a value is stored
- /// \group pointer
- /// \synopsis constexpr const T *operator->() const;
- constexpr const T* operator->() const {
- return std::addressof(this->m_value);
- }
- /// \group pointer
- /// \synopsis constexpr T *operator->();
- SOL_TL_OPTIONAL_11_CONSTEXPR T* operator->() {
- return std::addressof(this->m_value);
- }
- /// \returns the stored value
- /// \requires a value is stored
- /// \group deref
- /// \synopsis constexpr T &operator*();
- SOL_TL_OPTIONAL_11_CONSTEXPR T& operator*() & {
- return this->m_value;
- }
- /// \group deref
- /// \synopsis constexpr const T &operator*() const;
- constexpr const T& operator*() const& {
- return this->m_value;
- }
- /// \exclude
- SOL_TL_OPTIONAL_11_CONSTEXPR T&& operator*() && {
- return std::move(this->m_value);
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \exclude
- constexpr const T&& operator*() const&& {
- return std::move(this->m_value);
- }
- #endif
- /// \returns whether or not the optional has a value
- /// \group has_value
- constexpr bool has_value() const noexcept {
- return this->m_has_value;
- }
- /// \group has_value
- constexpr explicit operator bool() const noexcept {
- return this->m_has_value;
- }
- /// \returns the contained value if there is one, otherwise throws
- /// [bad_optional_access]
- /// \group value
- /// \synopsis constexpr T &value();
- SOL_TL_OPTIONAL_11_CONSTEXPR T& value() & {
- if (has_value())
- return this->m_value;
- #if SOL_IS_OFF(SOL_EXCEPTIONS)
- std::abort();
- #else
- throw bad_optional_access();
- #endif // No exceptions allowed
- }
- /// \group value
- /// \synopsis constexpr const T &value() const;
- SOL_TL_OPTIONAL_11_CONSTEXPR const T& value() const& {
- if (has_value())
- return this->m_value;
- #if SOL_IS_OFF(SOL_EXCEPTIONS)
- std::abort();
- #else
- throw bad_optional_access();
- #endif // No exceptions allowed
- }
- /// \exclude
- SOL_TL_OPTIONAL_11_CONSTEXPR T&& value() && {
- if (has_value())
- return std::move(this->m_value);
- #if SOL_IS_OFF(SOL_EXCEPTIONS)
- std::abort();
- #else
- throw bad_optional_access();
- #endif // No exceptions allowed
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \exclude
- SOL_TL_OPTIONAL_11_CONSTEXPR const T&& value() const&& {
- if (has_value())
- return std::move(this->m_value);
- #if SOL_IS_OFF(SOL_EXCEPTIONS)
- std::abort();
- #else
- throw bad_optional_access();
- #endif // No exceptions allowed
- }
- #endif
- /// \returns the stored value if there is one, otherwise returns `u`
- /// \group value_or
- template <class U>
- constexpr T value_or(U&& u) const& {
- static_assert(std::is_copy_constructible<T>::value && std::is_convertible<U&&, T>::value, "T must be copy constructible and convertible from U");
- return has_value() ? **this : static_cast<T>(std::forward<U>(u));
- }
- /// \group value_or
- template <class U>
- SOL_TL_OPTIONAL_11_CONSTEXPR T value_or(U&& u) && {
- static_assert(std::is_move_constructible<T>::value && std::is_convertible<U&&, T>::value, "T must be move constructible and convertible from U");
- return has_value() ? **this : static_cast<T>(std::forward<U>(u));
- }
- /// Destroys the stored value if one exists, making the optional empty
- void reset() noexcept {
- if (has_value()) {
- this->m_value.~T();
- this->m_has_value = false;
- }
- }
- }; // namespace sol
- /// \group relop
- /// \brief Compares two optional objects
- /// \details If both optionals contain a value, they are compared with `T`s
- /// relational operators. Otherwise `lhs` and `rhs` are equal only if they are
- /// both empty, and `lhs` is less than `rhs` only if `rhs` is empty and `lhs`
- /// is not.
- template <class T, class U>
- inline constexpr bool operator==(const optional<T>& lhs, const optional<U>& rhs) {
- return lhs.has_value() == rhs.has_value() && (!lhs.has_value() || *lhs == *rhs);
- }
- /// \group relop
- template <class T, class U>
- inline constexpr bool operator!=(const optional<T>& lhs, const optional<U>& rhs) {
- return lhs.has_value() != rhs.has_value() || (lhs.has_value() && *lhs != *rhs);
- }
- /// \group relop
- template <class T, class U>
- inline constexpr bool operator<(const optional<T>& lhs, const optional<U>& rhs) {
- return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs);
- }
- /// \group relop
- template <class T, class U>
- inline constexpr bool operator>(const optional<T>& lhs, const optional<U>& rhs) {
- return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs);
- }
- /// \group relop
- template <class T, class U>
- inline constexpr bool operator<=(const optional<T>& lhs, const optional<U>& rhs) {
- return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs);
- }
- /// \group relop
- template <class T, class U>
- inline constexpr bool operator>=(const optional<T>& lhs, const optional<U>& rhs) {
- return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs);
- }
- /// \group relop_nullopt
- /// \brief Compares an optional to a `nullopt`
- /// \details Equivalent to comparing the optional to an empty optional
- template <class T>
- inline constexpr bool operator==(const optional<T>& lhs, nullopt_t) noexcept {
- return !lhs.has_value();
- }
- /// \group relop_nullopt
- template <class T>
- inline constexpr bool operator==(nullopt_t, const optional<T>& rhs) noexcept {
- return !rhs.has_value();
- }
- /// \group relop_nullopt
- template <class T>
- inline constexpr bool operator!=(const optional<T>& lhs, nullopt_t) noexcept {
- return lhs.has_value();
- }
- /// \group relop_nullopt
- template <class T>
- inline constexpr bool operator!=(nullopt_t, const optional<T>& rhs) noexcept {
- return rhs.has_value();
- }
- /// \group relop_nullopt
- template <class T>
- inline constexpr bool operator<(const optional<T>&, nullopt_t) noexcept {
- return false;
- }
- /// \group relop_nullopt
- template <class T>
- inline constexpr bool operator<(nullopt_t, const optional<T>& rhs) noexcept {
- return rhs.has_value();
- }
- /// \group relop_nullopt
- template <class T>
- inline constexpr bool operator<=(const optional<T>& lhs, nullopt_t) noexcept {
- return !lhs.has_value();
- }
- /// \group relop_nullopt
- template <class T>
- inline constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept {
- return true;
- }
- /// \group relop_nullopt
- template <class T>
- inline constexpr bool operator>(const optional<T>& lhs, nullopt_t) noexcept {
- return lhs.has_value();
- }
- /// \group relop_nullopt
- template <class T>
- inline constexpr bool operator>(nullopt_t, const optional<T>&) noexcept {
- return false;
- }
- /// \group relop_nullopt
- template <class T>
- inline constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept {
- return true;
- }
- /// \group relop_nullopt
- template <class T>
- inline constexpr bool operator>=(nullopt_t, const optional<T>& rhs) noexcept {
- return !rhs.has_value();
- }
- /// \group relop_t
- /// \brief Compares the optional with a value.
- /// \details If the optional has a value, it is compared with the other value
- /// using `T`s relational operators. Otherwise, the optional is considered
- /// less than the value.
- template <class T, class U>
- inline constexpr bool operator==(const optional<T>& lhs, const U& rhs) {
- return lhs.has_value() ? *lhs == rhs : false;
- }
- /// \group relop_t
- template <class T, class U>
- inline constexpr bool operator==(const U& lhs, const optional<T>& rhs) {
- return rhs.has_value() ? lhs == *rhs : false;
- }
- /// \group relop_t
- template <class T, class U>
- inline constexpr bool operator!=(const optional<T>& lhs, const U& rhs) {
- return lhs.has_value() ? *lhs != rhs : true;
- }
- /// \group relop_t
- template <class T, class U>
- inline constexpr bool operator!=(const U& lhs, const optional<T>& rhs) {
- return rhs.has_value() ? lhs != *rhs : true;
- }
- /// \group relop_t
- template <class T, class U>
- inline constexpr bool operator<(const optional<T>& lhs, const U& rhs) {
- return lhs.has_value() ? *lhs < rhs : true;
- }
- /// \group relop_t
- template <class T, class U>
- inline constexpr bool operator<(const U& lhs, const optional<T>& rhs) {
- return rhs.has_value() ? lhs < *rhs : false;
- }
- /// \group relop_t
- template <class T, class U>
- inline constexpr bool operator<=(const optional<T>& lhs, const U& rhs) {
- return lhs.has_value() ? *lhs <= rhs : true;
- }
- /// \group relop_t
- template <class T, class U>
- inline constexpr bool operator<=(const U& lhs, const optional<T>& rhs) {
- return rhs.has_value() ? lhs <= *rhs : false;
- }
- /// \group relop_t
- template <class T, class U>
- inline constexpr bool operator>(const optional<T>& lhs, const U& rhs) {
- return lhs.has_value() ? *lhs > rhs : false;
- }
- /// \group relop_t
- template <class T, class U>
- inline constexpr bool operator>(const U& lhs, const optional<T>& rhs) {
- return rhs.has_value() ? lhs > *rhs : true;
- }
- /// \group relop_t
- template <class T, class U>
- inline constexpr bool operator>=(const optional<T>& lhs, const U& rhs) {
- return lhs.has_value() ? *lhs >= rhs : false;
- }
- /// \group relop_t
- template <class T, class U>
- inline constexpr bool operator>=(const U& lhs, const optional<T>& rhs) {
- return rhs.has_value() ? lhs >= *rhs : true;
- }
- /// \synopsis template <class T> \n void swap(optional<T> &lhs, optional<T> &rhs);
- template <class T, detail::enable_if_t<std::is_move_constructible<T>::value>* = nullptr, detail::enable_if_t<detail::is_swappable<T>::value>* = nullptr>
- void swap(optional<T>& lhs, optional<T>& rhs) noexcept(noexcept(lhs.swap(rhs))) {
- return lhs.swap(rhs);
- }
- namespace detail {
- struct i_am_secret { };
- } // namespace detail
- template <class T = detail::i_am_secret, class U, class Ret = detail::conditional_t<std::is_same<T, detail::i_am_secret>::value, detail::decay_t<U>, T>>
- inline constexpr optional<Ret> make_optional(U&& v) {
- return optional<Ret>(std::forward<U>(v));
- }
- template <class T, class... Args>
- inline constexpr optional<T> make_optional(Args&&... args) {
- return optional<T>(in_place, std::forward<Args>(args)...);
- }
- template <class T, class U, class... Args>
- inline constexpr optional<T> make_optional(std::initializer_list<U> il, Args&&... args) {
- return optional<T>(in_place, il, std::forward<Args>(args)...);
- }
- #if __cplusplus >= 201703L
- template <class T>
- optional(T) -> optional<T>;
- #endif
- /// \exclude
- namespace detail {
- #ifdef SOL_TL_OPTIONAL_CXX14
- template <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())),
- detail::enable_if_t<!std::is_void<Ret>::value>* = nullptr>
- constexpr auto optional_map_impl(Opt&& opt, F&& f) {
- return opt.has_value() ? detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)) : optional<Ret>(nullopt);
- }
- template <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())),
- detail::enable_if_t<std::is_void<Ret>::value>* = nullptr>
- auto optional_map_impl(Opt&& opt, F&& f) {
- if (opt.has_value()) {
- detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt));
- return make_optional(monostate {});
- }
- return optional<monostate>(nullopt);
- }
- #else
- template <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())),
- detail::enable_if_t<!std::is_void<Ret>::value>* = nullptr>
- constexpr auto optional_map_impl(Opt&& opt, F&& f) -> optional<Ret> {
- return opt.has_value() ? detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt)) : optional<Ret>(nullopt);
- }
- template <class Opt, class F, class Ret = decltype(detail::invoke(std::declval<F>(), *std::declval<Opt>())),
- detail::enable_if_t<std::is_void<Ret>::value>* = nullptr>
- auto optional_map_impl(Opt&& opt, F&& f) -> optional<monostate> {
- if (opt.has_value()) {
- detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt));
- return monostate {};
- }
- return nullopt;
- }
- #endif
- } // namespace detail
- /// Specialization for when `T` is a reference. `optional<T&>` acts similarly
- /// to a `T*`, but provides more operations and shows intent more clearly.
- ///
- /// *Examples*:
- ///
- /// ```
- /// int i = 42;
- /// sol::optional<int&> o = i;
- /// *o == 42; //true
- /// i = 12;
- /// *o = 12; //true
- /// &*o == &i; //true
- /// ```
- ///
- /// Assignment has rebind semantics rather than assign-through semantics:
- ///
- /// ```
- /// int j = 8;
- /// o = j;
- ///
- /// &*o == &j; //true
- /// ```
- template <class T>
- class optional<T&> {
- public:
- // The different versions for C++14 and 11 are needed because deduced return
- // types are not SFINAE-safe. This provides better support for things like
- // generic lambdas. C.f.
- // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html
- #if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55)
- /// \group and_then
- /// Carries out some operation which returns an optional on the stored
- /// object if there is one. \requires `std::invoke(std::forward<F>(f),
- /// value())` returns a `std::optional<U>` for some `U`. \returns Let `U` be
- /// the result of `std::invoke(std::forward<F>(f), value())`. Returns a
- /// `std::optional<U>`. The return value is empty if `*this` is empty,
- /// otherwise the return value of `std::invoke(std::forward<F>(f), value())`
- /// is returned.
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) & {
- using result = detail::invoke_result_t<F, T&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);
- }
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &&;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) && {
- using result = detail::invoke_result_t<F, T&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);
- }
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &;
- template <class F>
- constexpr auto and_then(F&& f) const& {
- using result = detail::invoke_result_t<F, const T&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &&;
- template <class F>
- constexpr auto and_then(F&& f) const&& {
- using result = detail::invoke_result_t<F, const T&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);
- }
- #endif
- #else
- /// \group and_then
- /// Carries out some operation which returns an optional on the stored
- /// object if there is one. \requires `std::invoke(std::forward<F>(f),
- /// value())` returns a `std::optional<U>` for some `U`. \returns Let `U` be
- /// the result of `std::invoke(std::forward<F>(f), value())`. Returns a
- /// `std::optional<U>`. The return value is empty if `*this` is empty,
- /// otherwise the return value of `std::invoke(std::forward<F>(f), value())`
- /// is returned.
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&> and_then(F&& f) & {
- using result = detail::invoke_result_t<F, T&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);
- }
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) &&;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T&> and_then(F&& f) && {
- using result = detail::invoke_result_t<F, T&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);
- }
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &;
- template <class F>
- constexpr detail::invoke_result_t<F, const T&> and_then(F&& f) const& {
- using result = detail::invoke_result_t<F, const T&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group and_then
- /// \synopsis template <class F> \n constexpr auto and_then(F &&f) const &&;
- template <class F>
- constexpr detail::invoke_result_t<F, const T&> and_then(F&& f) const&& {
- using result = detail::invoke_result_t<F, const T&>;
- static_assert(detail::is_optional<result>::value, "F must return an optional");
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);
- }
- #endif
- #endif
- #if defined(SOL_TL_OPTIONAL_CXX14) && !defined(SOL_TL_OPTIONAL_GCC49) && !defined(SOL_TL_OPTIONAL_GCC54) && !defined(SOL_TL_OPTIONAL_GCC55)
- /// \brief Carries out some operation on the stored object if there is one.
- /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
- /// value())`. Returns a `std::optional<U>`. The return value is empty if
- /// `*this` is empty, otherwise an `optional<U>` is constructed from the
- /// return value of `std::invoke(std::forward<F>(f), value())` and is
- /// returned.
- ///
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) &;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) & {
- return detail::optional_map_impl(*this, std::forward<F>(f));
- }
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) &&;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR auto map(F&& f) && {
- return detail::optional_map_impl(std::move(*this), std::forward<F>(f));
- }
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) const&;
- template <class F>
- constexpr auto map(F&& f) const& {
- return detail::optional_map_impl(*this, std::forward<F>(f));
- }
- /// \group map
- /// \synopsis template <class F> constexpr auto map(F &&f) const&&;
- template <class F>
- constexpr auto map(F&& f) const&& {
- return detail::optional_map_impl(std::move(*this), std::forward<F>(f));
- }
- #else
- /// \brief Carries out some operation on the stored object if there is one.
- /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
- /// value())`. Returns a `std::optional<U>`. The return value is empty if
- /// `*this` is empty, otherwise an `optional<U>` is constructed from the
- /// return value of `std::invoke(std::forward<F>(f), value())` and is
- /// returned.
- ///
- /// \group map
- /// \synopsis template <class F> auto map(F &&f) &;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval<optional&>(), std::declval<F&&>())) map(F&& f) & {
- return detail::optional_map_impl(*this, std::forward<F>(f));
- }
- /// \group map
- /// \synopsis template <class F> auto map(F &&f) &&;
- template <class F>
- SOL_TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval<optional&&>(), std::declval<F&&>())) map(F&& f) && {
- return detail::optional_map_impl(std::move(*this), std::forward<F>(f));
- }
- /// \group map
- /// \synopsis template <class F> auto map(F &&f) const&;
- template <class F>
- constexpr decltype(detail::optional_map_impl(std::declval<const optional&>(), std::declval<F&&>())) map(F&& f) const& {
- return detail::optional_map_impl(*this, std::forward<F>(f));
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group map
- /// \synopsis template <class F> auto map(F &&f) const&&;
- template <class F>
- constexpr decltype(detail::optional_map_impl(std::declval<const optional&&>(), std::declval<F&&>())) map(F&& f) const&& {
- return detail::optional_map_impl(std::move(*this), std::forward<F>(f));
- }
- #endif
- #endif
- /// \brief Calls `f` if the optional is empty
- /// \requires `std::invoke_result_t<F>` must be void or convertible to
- /// `optional<T>`. \effects If `*this` has a value, returns `*this`.
- /// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)` and returns
- /// `std::nullopt`. Otherwise, returns `std::forward<F>(f)()`.
- ///
- /// \group or_else
- /// \synopsis template <class F> optional<T> or_else (F &&f) &;
- template <class F, detail::enable_if_ret_void<F>* = nullptr>
- optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & {
- if (has_value())
- return *this;
- std::forward<F>(f)();
- return nullopt;
- }
- /// \exclude
- template <class F, detail::disable_if_ret_void<F>* = nullptr>
- optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) & {
- return has_value() ? *this : std::forward<F>(f)();
- }
- /// \group or_else
- /// \synopsis template <class F> optional<T> or_else (F &&f) &&;
- template <class F, detail::enable_if_ret_void<F>* = nullptr>
- optional<T> or_else(F&& f) && {
- if (has_value())
- return std::move(*this);
- std::forward<F>(f)();
- return nullopt;
- }
- /// \exclude
- template <class F, detail::disable_if_ret_void<F>* = nullptr>
- optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) && {
- return has_value() ? std::move(*this) : std::forward<F>(f)();
- }
- /// \group or_else
- /// \synopsis template <class F> optional<T> or_else (F &&f) const &;
- template <class F, detail::enable_if_ret_void<F>* = nullptr>
- optional<T> or_else(F&& f) const& {
- if (has_value())
- return *this;
- std::forward<F>(f)();
- return nullopt;
- }
- /// \exclude
- template <class F, detail::disable_if_ret_void<F>* = nullptr>
- optional<T> SOL_TL_OPTIONAL_11_CONSTEXPR or_else(F&& f) const& {
- return has_value() ? *this : std::forward<F>(f)();
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \exclude
- template <class F, detail::enable_if_ret_void<F>* = nullptr>
- optional<T> or_else(F&& f) const&& {
- if (has_value())
- return std::move(*this);
- std::forward<F>(f)();
- return nullopt;
- }
- /// \exclude
- template <class F, detail::disable_if_ret_void<F>* = nullptr>
- optional<T> or_else(F&& f) const&& {
- return has_value() ? std::move(*this) : std::forward<F>(f)();
- }
- #endif
- /// \brief Maps the stored value with `f` if there is one, otherwise returns
- /// `u`.
- ///
- /// \details If there is a value stored, then `f` is called with `**this`
- /// and the value is returned. Otherwise `u` is returned.
- ///
- /// \group map_or
- template <class F, class U>
- U map_or(F&& f, U&& u) & {
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u);
- }
- /// \group map_or
- template <class F, class U>
- U map_or(F&& f, U&& u) && {
- return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u);
- }
- /// \group map_or
- template <class F, class U>
- U map_or(F&& f, U&& u) const& {
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u);
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group map_or
- template <class F, class U>
- U map_or(F&& f, U&& u) const&& {
- return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u);
- }
- #endif
- /// \brief Maps the stored value with `f` if there is one, otherwise calls
- /// `u` and returns the result.
- ///
- /// \details If there is a value stored, then `f` is
- /// called with `**this` and the value is returned. Otherwise
- /// `std::forward<U>(u)()` is returned.
- ///
- /// \group map_or_else
- /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u) &;
- template <class F, class U>
- detail::invoke_result_t<U> map_or_else(F&& f, U&& u) & {
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)();
- }
- /// \group map_or_else
- /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u)
- /// &&;
- template <class F, class U>
- detail::invoke_result_t<U> map_or_else(F&& f, U&& u) && {
- return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)();
- }
- /// \group map_or_else
- /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u)
- /// const &;
- template <class F, class U>
- detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const& {
- return has_value() ? detail::invoke(std::forward<F>(f), **this) : std::forward<U>(u)();
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group map_or_else
- /// \synopsis template <class F, class U> \n auto map_or_else(F &&f, U &&u)
- /// const &&;
- template <class F, class U>
- detail::invoke_result_t<U> map_or_else(F&& f, U&& u) const&& {
- return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : std::forward<U>(u)();
- }
- #endif
- /// \returns `u` if `*this` has a value, otherwise an empty optional.
- template <class U>
- constexpr optional<typename std::decay<U>::type> conjunction(U&& u) const {
- using result = optional<detail::decay_t<U>>;
- return has_value() ? result { u } : result { nullopt };
- }
- /// \returns `rhs` if `*this` is empty, otherwise the current value.
- /// \group disjunction
- SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) & {
- return has_value() ? *this : rhs;
- }
- /// \group disjunction
- constexpr optional disjunction(const optional& rhs) const& {
- return has_value() ? *this : rhs;
- }
- /// \group disjunction
- SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional& rhs) && {
- return has_value() ? std::move(*this) : rhs;
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group disjunction
- constexpr optional disjunction(const optional& rhs) const&& {
- return has_value() ? std::move(*this) : rhs;
- }
- #endif
- /// \group disjunction
- SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) & {
- return has_value() ? *this : std::move(rhs);
- }
- /// \group disjunction
- constexpr optional disjunction(optional&& rhs) const& {
- return has_value() ? *this : std::move(rhs);
- }
- /// \group disjunction
- SOL_TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional&& rhs) && {
- return has_value() ? std::move(*this) : std::move(rhs);
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group disjunction
- constexpr optional disjunction(optional&& rhs) const&& {
- return has_value() ? std::move(*this) : std::move(rhs);
- }
- #endif
- /// Takes the value out of the optional, leaving it empty
- /// \group take
- optional take() & {
- optional ret = *this;
- reset();
- return ret;
- }
- /// \group take
- optional take() const& {
- optional ret = *this;
- reset();
- return ret;
- }
- /// \group take
- optional take() && {
- optional ret = std::move(*this);
- reset();
- return ret;
- }
- #ifndef SOL_TL_OPTIONAL_NO_CONSTRR
- /// \group take
- optional take() const&& {
- optional ret = std::move(*this);
- reset();
- return ret;
- }
- #endif
- using value_type = T&;
- /// Constructs an optional that does not contain a value.
- /// \group ctor_empty
- constexpr optional() noexcept : m_value(nullptr) {
- }
- /// \group ctor_empty
- constexpr optional(nullopt_t) noexcept : m_value(nullptr) {
- }
- /// Copy constructor
- ///
- /// If `rhs` contains a value, the stored value is direct-initialized with
- /// it. Otherwise, the constructed optional is empty.
- SOL_TL_OPTIONAL_11_CONSTEXPR optional(const optional& rhs) noexcept = default;
- /// Move constructor
- ///
- /// If `rhs` contains a value, the stored value is direct-initialized with
- /// it. Otherwise, the constructed optional is empty.
- SOL_TL_OPTIONAL_11_CONSTEXPR optional(optional&& rhs) = default;
- /// Constructs the stored value with `u`.
- /// \synopsis template <class U=T> constexpr optional(U &&u);
- template <class U = T, detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>::value>* = nullptr>
- constexpr optional(U&& u) : m_value(std::addressof(u)) {
- static_assert(std::is_lvalue_reference<U>::value, "U must be an lvalue");
- }
- /// \exclude
- template <class U>
- constexpr explicit optional(const optional<U>& rhs) : optional(*rhs) {
- }
- /// No-op
- ~optional() = default;
- /// Assignment to empty.
- ///
- /// Destroys the current value if there is one.
- optional& operator=(nullopt_t) noexcept {
- m_value = nullptr;
- return *this;
- }
- /// Copy assignment.
- ///
- /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise
- /// resets the stored value in `*this`.
- optional& operator=(const optional& rhs) = default;
- /// Rebinds this optional to `u`.
- ///
- /// \requires `U` must be an lvalue reference.
- /// \synopsis optional &operator=(U &&u);
- template <class U = T, detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>::value>* = nullptr>
- optional& operator=(U&& u) {
- static_assert(std::is_lvalue_reference<U>::value, "U must be an lvalue");
- m_value = std::addressof(u);
- return *this;
- }
- /// Converting copy assignment operator.
- ///
- /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise
- /// resets the stored value in `*this`.
- template <class U>
- optional& operator=(const optional<U>& rhs) {
- m_value = std::addressof(rhs.value());
- return *this;
- }
- /// Constructs the value in-place, destroying the current one if there is
- /// one.
- ///
- /// \group emplace
- template <class... Args>
- T& emplace(Args&&... args) noexcept {
- static_assert(std::is_constructible<T, Args&&...>::value, "T must be constructible with Args");
- *this = nullopt;
- this->construct(std::forward<Args>(args)...);
- }
- /// Swaps this optional with the other.
- ///
- /// If neither optionals have a value, nothing happens.
- /// If both have a value, the values are swapped.
- /// If one has a value, it is moved to the other and the movee is left
- /// valueless.
- void swap(optional& rhs) noexcept {
- std::swap(m_value, rhs.m_value);
- }
- /// \returns a pointer to the stored value
- /// \requires a value is stored
- /// \group pointer
- /// \synopsis constexpr const T *operator->() const;
- constexpr const T* operator->() const {
- return m_value;
- }
- /// \group pointer
- /// \synopsis constexpr T *operator->();
- SOL_TL_OPTIONAL_11_CONSTEXPR T* operator->() {
- return m_value;
- }
- /// \returns the stored value
- /// \requires a value is stored
- /// \group deref
- /// \synopsis constexpr T &operator*();
- SOL_TL_OPTIONAL_11_CONSTEXPR T& operator*() {
- return *m_value;
- }
- /// \group deref
- /// \synopsis constexpr const T &operator*() const;
- constexpr const T& operator*() const {
- return *m_value;
- }
- /// \returns whether or not the optional has a value
- /// \group has_value
- constexpr bool has_value() const noexcept {
- return m_value != nullptr;
- }
- /// \group has_value
- constexpr explicit operator bool() const noexcept {
- return m_value != nullptr;
- }
- /// \returns the contained value if there is one, otherwise throws
- /// [bad_optional_access]
- /// \group value
- /// synopsis constexpr T &value();
- SOL_TL_OPTIONAL_11_CONSTEXPR T& value() {
- if (has_value())
- return *m_value;
- #if SOL_IS_OFF(SOL_EXCEPTIONS)
- std::abort();
- #else
- throw bad_optional_access();
- #endif // No exceptions allowed
- }
- /// \group value
- /// \synopsis constexpr const T &value() const;
- SOL_TL_OPTIONAL_11_CONSTEXPR const T& value() const {
- if (has_value())
- return *m_value;
- #if SOL_IS_OFF(SOL_EXCEPTIONS)
- std::abort();
- #else
- throw bad_optional_access();
- #endif // No exceptions allowed
- }
- /// \returns the stored value if there is one, otherwise returns `u`
- /// \group value_or
- template <class U>
- constexpr T& value_or(U&& u) const {
- static_assert(std::is_convertible<U&&, T&>::value, "T must be convertible from U");
- return has_value() ? const_cast<T&>(**this) : static_cast<T&>(std::forward<U>(u));
- }
- /// Destroys the stored value if one exists, making the optional empty
- void reset() noexcept {
- m_value = nullptr;
- }
- private:
- T* m_value;
- };
- } // namespace sol
- namespace std {
- // TODO SFINAE
- template <class T>
- struct hash<::sol::optional<T>> {
- ::std::size_t operator()(const ::sol::optional<T>& o) const {
- if (!o.has_value())
- return 0;
- return ::std::hash<::sol::detail::remove_const_t<T>>()(*o);
- }
- };
- } // namespace std
- #endif // SOL_TL_OPTIONAL_HPP
|