bison-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Add "%define assert" to variants.


From: Akim Demaille
Subject: [PATCH] Add "%define assert" to variants.
Date: Fri, 07 Nov 2008 20:38:14 -0000

This is used to help the user catch cases where some value gets
ovewritten by a new one.  This should not happen, as this will
probably leak.

Unfortunately this uncovered a bug in the C++ parser itself: the
lookahead value was not destroyed between two calls to yylex.  For
instance if the previous lookahead was a std::string, and then an int,
then the value of the std::string was correctly taken (i.e., the
lookahead was now an empty string), but std::string structure itself
was not reclaimed.

This is now done in variant::build(other&) (which is used to take the
value of the lookahead): other is not only stolen from its value, it
is also destroyed.  This incurs a new performance penalty of a few
percent, and union becomes faster again.

        * data/lalr1-fusion.cc (variant::build(other&)): Destroy other.
        (b4_variant_if): New.
        (variant::built): New.
        Use it whereever the status of the variant changes.
        * etc/bench.pl.in: Check the penalty of %define assert.
---
 ChangeLog            |   25 +++++++++++++++++++++++++
 data/lalr1-fusion.cc |   31 ++++++++++++++++++++++++++-----
 etc/bench.pl.in      |    1 +
 3 files changed, 52 insertions(+), 5 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 8054b25..b7cac25 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,30 @@
 2008-11-07  Akim Demaille  <address@hidden>
 
+       Add "%define assert" to variants.
+       This is used to help the user catch cases where some value gets
+       ovewritten by a new one.  This should not happen, as this will
+       probably leak.
+       
+       Unfortunately this uncovered a bug in the C++ parser itself: the
+       lookahead value was not destroyed between two calls to yylex.  For
+       instance if the previous lookahead was a std::string, and then an int,
+       then the value of the std::string was correctly taken (i.e., the
+       lookahead was now an empty string), but std::string structure itself
+       was not reclaimed.
+       
+       This is now done in variant::build(other&) (which is used to take the
+       value of the lookahead): other is not only stolen from its value, it
+       is also destroyed.  This incurs a new performance penalty of a few
+       percent, and union becomes faster again.
+       
+       * data/lalr1-fusion.cc (variant::build(other&)): Destroy other.
+       (b4_variant_if): New.
+       (variant::built): New.
+       Use it whereever the status of the variant changes.
+       * etc/bench.pl.in: Check the penalty of %define assert.
+
+2008-11-07  Akim Demaille  <address@hidden>
+
        Use "%define variant" in bench.pl.
        * etc/bench.pl.in: No longer use the pseudo directive %variants,
        just use %define variants.
diff --git a/data/lalr1-fusion.cc b/data/lalr1-fusion.cc
index 63bc1d5..1f1129a 100644
--- a/data/lalr1-fusion.cc
+++ b/data/lalr1-fusion.cc
@@ -40,6 +40,12 @@ b4_variant_if([
 ]) # b4_variant_if
 
 
+# b4_assert_if([IF-ASSERTIONS-ARE-USED], [IF-NOT])
+# ----------------------------------------------------
+m4_define([b4_assert_if],
+[b4_percent_define_ifdef([[assert]], [$1], [$2])])
+
+
 # b4_rhs_value(RULE-LENGTH, NUM, [TYPE])
 # --------------------------------------
 # Expansion of $<TYPE>NUM, where the current rule has RULE-LENGTH
@@ -161,6 +167,7 @@ dnl FIXME: This is wrong, we want computed header guards.
 
 ]b4_percent_code_get([[requires]])[
 
+]b4_assert_if([#include <cassert>])[
 #include <string>
 #include <iostream>
 #include "stack.hh"
@@ -177,12 +184,22 @@ dnl FIXME: This is wrong, we want computed header guards.
   /// via the current state.
   template <size_t S>
   struct variant
-  {
+  {]b4_assert_if([
+    /// Whether something is contained.
+    bool built;
+
+    /// Initially uninitialized.
+    variant ()
+      : built(false)
+    {}])[
+
     /// Instantiate a \a T in here.
     template <typename T>
     inline T&
     build()
-    {
+    {]b4_assert_if([
+      assert(!built);
+      built = true;])[
       return *new (buffer) T;
     }
 
@@ -190,7 +207,8 @@ dnl FIXME: This is wrong, we want computed header guards.
     template <typename T>
     inline T&
     as()
-    {
+    {]b4_assert_if([
+      assert(built);])[
       return reinterpret_cast<T&>(buffer);
     }
 
@@ -198,7 +216,8 @@ dnl FIXME: This is wrong, we want computed header guards.
     template <typename T>
     inline const T&
     as() const
-    {
+    {]b4_assert_if([
+      assert(built);])[
       return reinterpret_cast<const T&>(buffer);
     }
 
@@ -218,6 +237,7 @@ dnl FIXME: This is wrong, we want computed header guards.
     {
       build<T>();
       swap<T>(other);
+      other.destroy<T>();
     }
 
     /// Destroy the stored \a T.
@@ -225,7 +245,8 @@ dnl FIXME: This is wrong, we want computed header guards.
     inline void
     destroy()
     {
-      as<T>().~T();
+      as<T>().~T();]b4_assert_if([
+      built = false;])[
     }
 
     /// A buffer large enough to store any of the semantic values.
diff --git a/etc/bench.pl.in b/etc/bench.pl.in
index f4f5a7e..97facb5 100755
--- a/etc/bench.pl.in
+++ b/etc/bench.pl.in
@@ -816,6 +816,7 @@ sub bench_variant_parser ()
       "f-var-deb" => ['%skeleton "lalr1-fusion.cc"', '%debug', '%define 
variant'],
       "f-var-dtr"       => ['%skeleton "lalr1-fusion.cc"', '%define variant', 
"%code {\n#define VARIANT_DESTROY\n}"],
       "f-var-deb-dtr" => ['%skeleton "lalr1-fusion.cc"', '%debug', '%define 
variant', "%code {\n#define VARIANT_DESTROY\n}"],
+      "f-var-deb-dtr-ass" => ['%skeleton "lalr1-fusion.cc"', '%debug', 
'%define variant', "%code {\n#define VARIANT_DESTROY\n}", "%define assert"],
      )
     );
 }
-- 
1.6.0.2.588.g3102





reply via email to

[Prev in Thread] Current Thread [Next in Thread]