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 "stack.hh"
]b4_bison_locations_if([[# include "location.hh"]])])[
]b4_variant_if([b4_variant_includes])[
]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
# -----------------
# Define "variant".
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
/// of the stored data, since that knowledge is available
/// via the current state.
template <size_t S>
struct variant
{]b4_parse_assert_if([
/// Whether something is contained.
bool built;
])[
{
/// Type of *this.
typedef variant<S> self_type;
/// Empty construction.
inline
variant ()]b4_parse_assert_if([
: built (false)])[
: built (false)
, tname (YY_NULL)])[
{}
/// Instantiate a \a T in here.
@@ -101,8 +112,11 @@ m4_define([b4_variant_define],
inline T&
build ()
{]b4_parse_assert_if([
assert (!built);
built = true;])[
YYASSERT (!built);
YYASSERT (!tname);
YYASSERT (sizeof (T) <= S);
built = true;
tname = typeid (T).name ();])[
return *new (buffer.raw) T;
}
@@ -111,18 +125,23 @@ m4_define([b4_variant_define],
inline T&
build (const T& t)
{]b4_parse_assert_if([
assert(!built);
built = true;])[
return *new (buffer.raw) T(t);
YYASSERT (!built);
YYASSERT (!tname);
YYASSERT (sizeof (T) <= S);
built = true;
tname = typeid (T).name ();])[
return *new (buffer.raw) T (t);
}
/// Construct and fill.
template <typename T>
inline
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.
@@ -130,8 +149,10 @@ m4_define([b4_variant_define],
inline T&
as ()
{]b4_parse_assert_if([
assert (built);])[
return reinterpret_cast<T&>(buffer.raw);
YYASSERT (built);
YYASSERT (tname == typeid (T).name ());
YYASSERT (sizeof (T) <= S);])[
return reinterpret_cast<T&> (buffer.raw);
}
/// Const accessor to a built \a T (for %printer).
@@ -139,16 +160,21 @@ m4_define([b4_variant_define],
inline const T&
as () const
{]b4_parse_assert_if([
assert(built);])[
return reinterpret_cast<const T&>(buffer.raw);
YYASSERT (built);
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>
inline void
swap (variant<S>& other)
{
std::swap (as<T>(), other.as<T>());
{]b4_parse_assert_if([
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.
@@ -167,10 +193,12 @@ m4_define([b4_variant_define],
inline void
destroy ()
{
as<T>().~T();]b4_parse_assert_if([
built = false;])[
as<T> ().~T ();]b4_parse_assert_if([
built = false;
tname = YY_NULL;])[
}
private:
/// A buffer large enough to store any of the semantic values.
/// Long double is chosen as it has the strongest alignment
/// constraints.
@@ -178,7 +206,11 @@ m4_define([b4_variant_define],
{
long double align_me;
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])[};
/// 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.