Skip to content

Commit 76980f9

Browse files
committed
🔀 Add variant implementation
This adds the variant implementation to Backport, complete with proper constexpr, trivial destructor, and unit tests! Currently absent is a proper implementation of 'visit' to work with multiple variants -- to be added at a later time. Closes #1
2 parents 4c91ed2 + 42788c2 commit 76980f9

File tree

12 files changed

+4515
-3
lines changed

12 files changed

+4515
-3
lines changed

CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
4141
set(CMAKE_CXX_EXTENSIONS OFF)
4242

4343
set(header_files
44+
"include/bpstd/detail/nth_type.hpp"
45+
"include/bpstd/detail/variant_fwds.hpp"
46+
"include/bpstd/detail/variant_union.hpp"
47+
"include/bpstd/detail/variant_base.hpp"
48+
"include/bpstd/detail/variant_traits.hpp"
49+
"include/bpstd/detail/variant_visitors.hpp"
4450
"include/bpstd/detail/move.hpp"
4551
"include/bpstd/detail/invoke.hpp"
4652
"include/bpstd/detail/proxy_iterator.hpp"
@@ -60,6 +66,7 @@ set(header_files
6066
"include/bpstd/span.hpp"
6167
"include/bpstd/chrono.hpp"
6268
"include/bpstd/string.hpp"
69+
"include/bpstd/variant.hpp"
6370
)
6471

6572
add_library(${PROJECT_NAME} INTERFACE)
@@ -79,6 +86,9 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND
7986
# Disable the ridiculous compatibility warnings, since it fails on files not
8087
# ending in newlines
8188
add_compile_options(-Wno-c++98-compat -Wno-c++98-compat-pedantic)
89+
90+
# This gives an unbelievable amount of false-positives spuriously. Ignore it.
91+
add_compile_options(-Wno-unneeded-member-function)
8292
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR
8393
"${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" )
8494
add_compile_options(-Wall -Werror -Wextra -pedantic -pedantic-errors)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ C++17, and C++20.
9090
|| `bpstd::apply` | [`N3915`][3915] |
9191
|| `bpstd::make_from_tuple` | [`P0209R2`][02092] |
9292
|| `bpstd::as_const` | [`P0007R1`][00071] |
93-
| 🚧 | `bpstd::variant` | [`P0088R3`][00883]<br> [`P0032R3`][00323]<br> [`P0393R3`][03933] |
93+
| | `bpstd::variant` | [`P0088R3`][00883]<br> [`P0032R3`][00323]<br> [`P0393R3`][03933] |
9494
|| `bpstd::uncaught_exceptions` | [`N4152`][4152]<br> [`N4259`][4259] |
9595
|| `bpstd::byte` | [`P0298R3`][02983] |
9696
|| `bpstd::not_fn` | [`P0005R4`][00054] |

include/bpstd/detail/config.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,16 @@
7070
# define BPSTD_MAY_ALIAS
7171
#endif // defined __clang__ || defined __GNUC__
7272

73-
#if defined(__clang__) || defined(__GNUC__)
73+
// When using 'clang-cl', don't forceinline -- since it results in code generation
74+
// failures in 'variant'
75+
#if defined(__clang__) && defined(_MSC_VER)
76+
# define BPSTD_INLINE_VISIBILITY __attribute__((visibility("hidden"), no_instrument_function))
77+
#elif defined(__clang__) || defined(__GNUC__)
7478
# define BPSTD_INLINE_VISIBILITY __attribute__((visibility("hidden"), always_inline, no_instrument_function))
7579
#elif defined(_MSC_VER)
7680
# define BPSTD_INLINE_VISIBILITY __forceinline
7781
#else
78-
# define inline
82+
# define BPSTD_INLINE_VISIBILITY
7983
#endif
8084

8185
#endif /* BPSTD_DETAIL_CONFIG_HPP */

include/bpstd/detail/nth_type.hpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*****************************************************************************
2+
* \file nth_type.hpp
3+
*
4+
* \brief This internal header provides the definition of the INVOKE overload
5+
*****************************************************************************/
6+
7+
/*
8+
The MIT License (MIT)
9+
10+
Copyright (c) 2020 Matthew Rodusek All rights reserved.
11+
12+
Permission is hereby granted, free of charge, to any person obtaining a copy
13+
of this software and associated documentation files (the "Software"), to deal
14+
in the Software without restriction, including without limitation the rights
15+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16+
copies of the Software, and to permit persons to whom the Software is
17+
furnished to do so, subject to the following conditions:
18+
19+
The above copyright notice and this permission notice shall be included in
20+
all copies or substantial portions of the Software.
21+
22+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28+
SOFTWARE.
29+
*/
30+
#ifndef BPSTD_DETAIL_NTH_TYPE_HPP
31+
#define BPSTD_DETAIL_NTH_TYPE_HPP
32+
33+
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
34+
# pragma once
35+
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
36+
37+
#include <cstddef> // std::size_t
38+
39+
namespace bpstd {
40+
namespace detail {
41+
42+
/// \brief Gets the nth type from a variadic pack of arguments
43+
///
44+
/// \tparam N the argument to retrieve
45+
/// \tparam Args the arguments to extract from
46+
template <std::size_t N, typename...Args>
47+
struct nth_type;
48+
49+
template <std::size_t N, typename Arg0, typename...Args>
50+
struct nth_type<N,Arg0,Args...> : nth_type<N-1,Args...>{};
51+
52+
template <typename Arg0, typename...Args>
53+
struct nth_type<0,Arg0,Args...>
54+
{
55+
using type = Arg0;
56+
};
57+
58+
template <std::size_t N, typename...Args>
59+
using nth_type_t = typename nth_type<N,Args...>::type;
60+
61+
} // namespace detail
62+
} // namespace bpstd
63+
64+
#endif /* BPSTD_DETAIL_NTH_TYPE_HPP */
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
/*****************************************************************************
2+
* \file variant_base.hpp
3+
*
4+
* \brief This internal header provides the definition of a utility for
5+
* variant, variant_base
6+
*****************************************************************************/
7+
8+
/*
9+
The MIT License (MIT)
10+
11+
Copyright (c) 2020 Matthew Rodusek All rights reserved.
12+
13+
Permission is hereby granted, free of charge, to any person obtaining a copy
14+
of this software and associated documentation files (the "Software"), to deal
15+
in the Software without restriction, including without limitation the rights
16+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17+
copies of the Software, and to permit persons to whom the Software is
18+
furnished to do so, subject to the following conditions:
19+
20+
The above copyright notice and this permission notice shall be included in
21+
all copies or substantial portions of the Software.
22+
23+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29+
SOFTWARE.
30+
*/
31+
#ifndef BPSTD_DETAIL_VARIANT_BASE_HPP
32+
#define BPSTD_DETAIL_VARIANT_BASE_HPP
33+
34+
#include "config.hpp" // BPSTD_CPP14_CONSTEXPR
35+
#include "variant_union.hpp" // detail::variant_union
36+
37+
#include <cstddef> // std::size_t
38+
#include <utility> // std::forward
39+
40+
namespace bpstd {
41+
namespace detail {
42+
43+
//==========================================================================
44+
// class : variant_base
45+
//==========================================================================
46+
47+
////////////////////////////////////////////////////////////////////////////
48+
/// \brief The base class used by variant
49+
////////////////////////////////////////////////////////////////////////////
50+
template <bool IsTrivial, typename...Types>
51+
class variant_base;
52+
53+
//==========================================================================
54+
// class : variant_base<true, Types...>
55+
//==========================================================================
56+
57+
template <typename...Types>
58+
class variant_base<true,Types...>
59+
{
60+
//------------------------------------------------------------------------
61+
// Constructors
62+
//------------------------------------------------------------------------
63+
public:
64+
65+
constexpr variant_base();
66+
67+
template <std::size_t N, typename...Args>
68+
constexpr variant_base(variant_index_tag<N>, Args&&...args);
69+
70+
//------------------------------------------------------------------------
71+
// Protected Members
72+
//------------------------------------------------------------------------
73+
protected:
74+
75+
variant_union<true,Types...> m_union;
76+
std::size_t m_index;
77+
78+
//---------------------------------------------------------------------
79+
// Protected Member Functions
80+
//---------------------------------------------------------------------
81+
protected:
82+
83+
void destroy_active_object();
84+
};
85+
86+
//==========================================================================
87+
// class : variant_base<false, Types...>
88+
//==========================================================================
89+
90+
template <typename...Types>
91+
class variant_base<false,Types...>
92+
{
93+
public:
94+
95+
constexpr variant_base();
96+
97+
template <std::size_t N, typename...Args>
98+
constexpr variant_base(variant_index_tag<N>, Args&&...args);
99+
100+
~variant_base();
101+
102+
//---------------------------------------------------------------------
103+
// Protected Members
104+
//---------------------------------------------------------------------
105+
protected:
106+
107+
variant_union<false,Types...> m_union;
108+
std::size_t m_index;
109+
110+
//---------------------------------------------------------------------
111+
// Protected Member Functions
112+
//---------------------------------------------------------------------
113+
protected:
114+
115+
void destroy_active_object();
116+
117+
//---------------------------------------------------------------------
118+
// Private Static Member Functions
119+
//---------------------------------------------------------------------
120+
private:
121+
122+
struct destroy_visitor
123+
{
124+
template <typename T>
125+
inline BPSTD_INLINE_VISIBILITY
126+
void operator()(T& v) {
127+
v.~T();
128+
}
129+
};
130+
};
131+
132+
} // namespace detail
133+
} // namespace bpstd
134+
135+
//==============================================================================
136+
// class : variant_base<true, Types...>
137+
//==============================================================================
138+
139+
//------------------------------------------------------------------------------
140+
// Constructors
141+
//------------------------------------------------------------------------------
142+
143+
template <typename...Types>
144+
inline BPSTD_INLINE_VISIBILITY constexpr
145+
bpstd::detail::variant_base<true,Types...>::variant_base()
146+
: m_union{},
147+
m_index{static_cast<std::size_t>(-1)}
148+
{
149+
150+
}
151+
152+
template <typename...Types>
153+
template <std::size_t N, typename...Args>
154+
inline BPSTD_INLINE_VISIBILITY constexpr
155+
bpstd::detail::variant_base<true,Types...>::variant_base(variant_index_tag<N>,
156+
Args&&...args)
157+
: m_union{variant_index_tag<N>{}, std::forward<Args>(args)...},
158+
m_index{N}
159+
{
160+
161+
}
162+
163+
//------------------------------------------------------------------------------
164+
// Protected Members
165+
//------------------------------------------------------------------------------
166+
167+
template <typename...Types>
168+
inline BPSTD_INLINE_VISIBILITY
169+
void bpstd::detail::variant_base<true,Types...>::destroy_active_object()
170+
{
171+
m_index = static_cast<std::size_t>(-1);
172+
}
173+
174+
//==============================================================================
175+
// class : variant_base<false, Types...>
176+
//==============================================================================
177+
178+
//------------------------------------------------------------------------------
179+
// Constructors / Destructor
180+
//------------------------------------------------------------------------------
181+
182+
template <typename...Types>
183+
inline BPSTD_INLINE_VISIBILITY constexpr
184+
bpstd::detail::variant_base<false,Types...>::variant_base()
185+
: m_union{},
186+
m_index{static_cast<std::size_t>(-1)}
187+
{
188+
189+
}
190+
191+
template <typename...Types>
192+
template <std::size_t N, typename...Args>
193+
inline BPSTD_INLINE_VISIBILITY constexpr
194+
bpstd::detail::variant_base<false,Types...>::variant_base(variant_index_tag<N>,
195+
Args&&...args)
196+
: m_union{variant_index_tag<N>{}, std::forward<Args>(args)...},
197+
m_index{N}
198+
{
199+
200+
}
201+
202+
//------------------------------------------------------------------------------
203+
204+
template <typename...Types>
205+
inline BPSTD_INLINE_VISIBILITY
206+
bpstd::detail::variant_base<false,Types...>::~variant_base()
207+
{
208+
destroy_active_object();
209+
}
210+
211+
//------------------------------------------------------------------------------
212+
// Protected Members
213+
//------------------------------------------------------------------------------
214+
215+
template <typename...Types>
216+
inline BPSTD_INLINE_VISIBILITY
217+
void bpstd::detail::variant_base<false,Types...>::destroy_active_object()
218+
{
219+
if (m_index == static_cast<std::size_t>(-1)) {
220+
return;
221+
}
222+
223+
visit_union(m_index, destroy_visitor{}, m_union);
224+
m_index = static_cast<std::size_t>(-1);
225+
}
226+
227+
#endif /* BPSTD_DETAIL_VARIANT_BASE_HPP */

0 commit comments

Comments
 (0)