variant: more assertions

Equip variants with more checking code.  Provide a means to request
includes.

* data/variant.hh (b4_variant_includes): New.
* data/lalr1.cc: Use it.
* data/variant.hh (variant::built): Define at the end, as a private member.
(variant::tname): New.
Somewhat makes "built" useless, but let's keep both for a start, in
case using "typeinfo" is considered unacceptable in some environments.
Fix some formatting issues.
This commit is contained in:
Akim Demaille
2012-12-19 10:09:07 +01:00
parent 7c0d37283d
commit 35f70d169f
2 changed files with 59 additions and 25 deletions

View File

@@ -139,6 +139,7 @@ m4_define([b4_shared_declarations],
# include <string>]b4_defines_if([[ # include <string>]b4_defines_if([[
# include "stack.hh" # include "stack.hh"
]b4_bison_locations_if([[# include "location.hh"]])])[ ]b4_bison_locations_if([[# include "location.hh"]])])[
]b4_variant_if([b4_variant_includes])[
]b4_YYDEBUG_define[ ]b4_YYDEBUG_define[

View File

@@ -74,26 +74,37 @@ m4_map([b4_char_sizeof_], [$@])dnl
])]) ])])
# b4_variant_includes
# -------------------
# The needed includes for variants support.
m4_define([b4_variant_includes],
[b4_parse_assert_if([[#include <typeinfo>]])[
#ifndef YYASSERT
# include <cassert>
# define YYASSERT assert
#endif
]])
# b4_variant_define # b4_variant_define
# ----------------- # -----------------
# Define "variant". # Define "variant".
m4_define([b4_variant_define], m4_define([b4_variant_define],
[[ [[ /// A char[S] buffer to store and retrieve objects.
/// A char[S] buffer to store and retrieve objects.
/// ///
/// Sort of a variant, but does not keep track of the nature /// Sort of a variant, but does not keep track of the nature
/// of the stored data, since that knowledge is available /// of the stored data, since that knowledge is available
/// via the current state. /// via the current state.
template <size_t S> template <size_t S>
struct variant struct variant
{]b4_parse_assert_if([ {
/// Whether something is contained. /// Type of *this.
bool built; typedef variant<S> self_type;
])[
/// Empty construction. /// Empty construction.
inline inline
variant ()]b4_parse_assert_if([ variant ()]b4_parse_assert_if([
: built (false)])[ : built (false)
, tname (YY_NULL)])[
{} {}
/// Instantiate a \a T in here. /// Instantiate a \a T in here.
@@ -101,8 +112,11 @@ m4_define([b4_variant_define],
inline T& inline T&
build () build ()
{]b4_parse_assert_if([ {]b4_parse_assert_if([
assert (!built); YYASSERT (!built);
built = true;])[ YYASSERT (!tname);
YYASSERT (sizeof (T) <= S);
built = true;
tname = typeid (T).name ();])[
return *new (buffer.raw) T; return *new (buffer.raw) T;
} }
@@ -111,18 +125,23 @@ m4_define([b4_variant_define],
inline T& inline T&
build (const T& t) build (const T& t)
{]b4_parse_assert_if([ {]b4_parse_assert_if([
assert(!built); YYASSERT (!built);
built = true;])[ YYASSERT (!tname);
return *new (buffer.raw) T(t); YYASSERT (sizeof (T) <= S);
built = true;
tname = typeid (T).name ();])[
return *new (buffer.raw) T (t);
} }
/// Construct and fill. /// Construct and fill.
template <typename T> template <typename T>
inline inline
variant (const T& t)]b4_parse_assert_if([ variant (const T& t)]b4_parse_assert_if([
: built (true)])[ : built (true)
, tname (typeid (T).name ())])[
{ {
new (buffer.raw) T(t); YYASSERT (sizeof (T) <= S);
new (buffer.raw) T (t);
} }
/// Accessor to a built \a T. /// Accessor to a built \a T.
@@ -130,8 +149,10 @@ m4_define([b4_variant_define],
inline T& inline T&
as () as ()
{]b4_parse_assert_if([ {]b4_parse_assert_if([
assert (built);])[ YYASSERT (built);
return reinterpret_cast<T&>(buffer.raw); YYASSERT (tname == typeid (T).name ());
YYASSERT (sizeof (T) <= S);])[
return reinterpret_cast<T&> (buffer.raw);
} }
/// Const accessor to a built \a T (for %printer). /// Const accessor to a built \a T (for %printer).
@@ -139,16 +160,21 @@ m4_define([b4_variant_define],
inline const T& inline const T&
as () const as () const
{]b4_parse_assert_if([ {]b4_parse_assert_if([
assert(built);])[ YYASSERT (built);
return reinterpret_cast<const T&>(buffer.raw); YYASSERT (tname == typeid (T).name ());
YYASSERT (sizeof (T) <= S);])[
return reinterpret_cast<const T&> (buffer.raw);
} }
/// Swap the content with \a other. /// Swap the content with \a other, of same type.
template <typename T> template <typename T>
inline void inline void
swap (variant<S>& other) swap (variant<S>& other)
{ {]b4_parse_assert_if([
std::swap (as<T>(), other.as<T>()); YYASSERT (tname == other.tname);])[
std::swap (as<T>(), other.as<T>());]b4_parse_assert_if([
std::swap (built, other.built);
std::swap (tname, other.tname);])[
} }
/// Assign the content of \a other to this. /// Assign the content of \a other to this.
@@ -167,10 +193,12 @@ m4_define([b4_variant_define],
inline void inline void
destroy () destroy ()
{ {
as<T>().~T();]b4_parse_assert_if([ as<T> ().~T ();]b4_parse_assert_if([
built = false;])[ built = false;
tname = YY_NULL;])[
} }
private:
/// A buffer large enough to store any of the semantic values. /// A buffer large enough to store any of the semantic values.
/// Long double is chosen as it has the strongest alignment /// Long double is chosen as it has the strongest alignment
/// constraints. /// constraints.
@@ -178,7 +206,11 @@ m4_define([b4_variant_define],
{ {
long double align_me; long double align_me;
char raw[S]; char raw[S];
} buffer; } buffer;]b4_parse_assert_if([
/// Whether something is contained.
bool built;
/// If defined, the name of the stored type.
const char* tname;])[
}; };
]]) ]])
@@ -197,7 +229,8 @@ m4_define([b4_semantic_type_declare],
{]b4_type_foreach([b4_char_sizeof])[}; {]b4_type_foreach([b4_char_sizeof])[};
/// Symbol semantic values. /// Symbol semantic values.
typedef variant<sizeof(union_type)> semantic_type;]) typedef variant<sizeof(union_type)> semantic_type;dnl
])
# How the semantic value is extracted when using variants. # How the semantic value is extracted when using variants.