X3: constexpr def_ reduces code size

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

X3: constexpr def_ reduces code size

Mario Lang
Hi.

As an experiment, I just tried what would happen if I change

-        static auto const def_ = (rule_name = BOOST_PP_CAT(rule_name, _def));
+        static auto constexpr def_ = (rule_name = BOOST_PP_CAT(rule_name, _def));

and make all the parsers and their generator functions constexpr.

A long story short: code size is reduced by roughly 35K (422000 to 386800).
Runtime seems (as expected) unaffected.

This emposes a few limitations that we probably don't want, so it is
very likely not worth the trouble.  I found it an interesting
experiment, so I at least wanted to share the result.

The mentioned code size reduction is with GCC 5.
Clang is a bit stricter on enforcing constexpr, I didn't care to make it
happy too (besides, clang 3.6 generates roughly 1/3 more code as GCC 5
when compiling Spirit X3 parsers, so optimizing for size for Clang seems
like really futile at the moment).

I wonder if we want a macro to control the use of constexpr on def_.
This would make it optionally possible for grammars to enable this if
they know they dont make any use of non-constant expressions in their
grammar.  But that is just an idea.

diff --git a/include/boost/spirit/home/x3/auxiliary/attr.hpp b/include/boost/spirit/home/x3/auxiliary/attr.hpp
index 5b3c7a5..377bcbe 100644
--- a/include/boost/spirit/home/x3/auxiliary/attr.hpp
+++ b/include/boost/spirit/home/x3/auxiliary/attr.hpp
@@ -33,10 +33,8 @@ namespace boost { namespace spirit { namespace x3
         static bool const handles_container =
             traits::is_container<attribute_type>::value;
         
-        attr_parser(Value const& value)
-          : value_(value) {}
-        attr_parser(Value&& value)
-          : value_(std::move(value)) {}
+        constexpr attr_parser(Value const& value) : value_(value) {}
+        constexpr attr_parser(Value&& value) : value_(std::move(value)) {}
 
         template <typename Iterator, typename Context
           , typename RuleContext, typename Attribute>
@@ -49,10 +47,6 @@ namespace boost { namespace spirit { namespace x3
         }
 
         Value value_;
-
-    private:
-        // silence MSVC warning C4512: assignment operator could not be generated
-        attr_parser& operator= (attr_parser const&);
     };
     
     template <typename Value, std::size_t N>
@@ -64,12 +58,12 @@ namespace boost { namespace spirit { namespace x3
             !is_same<unused_type, attribute_type>::value;
         static bool const handles_container = true;
         
-        attr_parser(Value const (&value)[N])
+        constexpr attr_parser(Value const (&value)[N])
         {
             std::copy(value + 0, value + N, value_ + 0);
         }
 
-        attr_parser(Value (&&value)[N])
+        constexpr attr_parser(Value (&&value)[N])
         {
             std::move(value + 0, value + N, value_ + 0);
         }
@@ -85,10 +79,6 @@ namespace boost { namespace spirit { namespace x3
         }
 
         Value value_[N];
-
-    private:
-        // silence MSVC warning C4512: assignment operator could not be generated
-        attr_parser& operator= (attr_parser const&);
     };
     
     template <typename Value>
@@ -104,7 +94,7 @@ namespace boost { namespace spirit { namespace x3
     struct attr_gen
     {
         template <typename Value>
-        attr_parser<typename remove_cv<
+        constexpr attr_parser<typename remove_cv<
             typename remove_reference<Value>::type>::type>
         operator()(Value&& value) const
         {
@@ -112,20 +102,20 @@ namespace boost { namespace spirit { namespace x3
         }
         
         template <typename Value, std::size_t N>
-        attr_parser<typename remove_cv<Value>::type[N]>
+        constexpr attr_parser<typename remove_cv<Value>::type[N]>
         operator()(Value (&value)[N]) const
         {
             return { value };
         }
         template <typename Value, std::size_t N>
-        attr_parser<typename remove_cv<Value>::type[N]>
+        constexpr attr_parser<typename remove_cv<Value>::type[N]>
         operator()(Value (&&value)[N]) const
         {
             return { value };
         }
     };
 
-    auto const attr = attr_gen{};
+    constexpr attr_gen attr{};
 }}}
 
 #endif
diff --git a/include/boost/spirit/home/x3/auxiliary/eoi.hpp b/include/boost/spirit/home/x3/auxiliary/eoi.hpp
index 778a20b..05c0866 100644
--- a/include/boost/spirit/home/x3/auxiliary/eoi.hpp
+++ b/include/boost/spirit/home/x3/auxiliary/eoi.hpp
@@ -35,7 +35,7 @@ namespace boost { namespace spirit { namespace x3
         result_type operator()(eoi_parser const &) const { return "eoi"; }
     };
 
-    auto const eoi = eoi_parser{};
+    constexpr eoi_parser eoi{};
 }}}
 
 #endif
diff --git a/include/boost/spirit/home/x3/auxiliary/eol.hpp b/include/boost/spirit/home/x3/auxiliary/eol.hpp
index 00e4488..8330140 100644
--- a/include/boost/spirit/home/x3/auxiliary/eol.hpp
+++ b/include/boost/spirit/home/x3/auxiliary/eol.hpp
@@ -49,7 +49,7 @@ namespace boost { namespace spirit { namespace x3
         result_type operator()(eol_parser const &) const { return "eol"; }
     };
 
-    auto const eol = eol_parser{};
+    constexpr eol_parser eol{};
 }}}
 
 #endif
diff --git a/include/boost/spirit/home/x3/auxiliary/eps.hpp b/include/boost/spirit/home/x3/auxiliary/eps.hpp
index 5f8f459..62941f7 100644
--- a/include/boost/spirit/home/x3/auxiliary/eps.hpp
+++ b/include/boost/spirit/home/x3/auxiliary/eps.hpp
@@ -20,8 +20,7 @@ namespace boost { namespace spirit { namespace x3
         typedef unused_type attribute_type;
         static bool const has_attribute = false;
 
-        semantic_predicate(bool predicate)
-          : predicate(predicate) {}
+        constexpr semantic_predicate(bool predicate) : predicate(predicate) {}
 
         template <typename Iterator, typename Context, typename Attribute>
         bool parse(Iterator& first, Iterator const& last
@@ -40,7 +39,7 @@ namespace boost { namespace spirit { namespace x3
         typedef unused_type attribute_type;
         static bool const has_attribute = false;
 
-        lazy_semantic_predicate(F f)
+        constexpr lazy_semantic_predicate(F f)
           : f(f) {}
 
         template <typename Iterator, typename Context, typename Attribute>
@@ -59,6 +58,8 @@ namespace boost { namespace spirit { namespace x3
         typedef unused_type attribute_type;
         static bool const has_attribute = false;
 
+        constexpr eps_parser() = default;
+
         template <typename Iterator, typename Context
           , typename RuleContext, typename Attribute>
         bool parse(Iterator& first, Iterator const& last
@@ -68,21 +69,21 @@ namespace boost { namespace spirit { namespace x3
             return true;
         }
 
-        semantic_predicate
+        constexpr semantic_predicate
         operator()(bool predicate) const
         {
             return semantic_predicate(predicate);
         }
 
         template <typename F>
-        lazy_semantic_predicate<F>
+        constexpr lazy_semantic_predicate<F>
         operator()(F f) const
         {
             return { f };
         }
     };
 
-    auto const eps = eps_parser{};
+    auto constexpr eps = eps_parser{};
 }}}
 
 #endif
diff --git a/include/boost/spirit/home/x3/auxiliary/guard.hpp b/include/boost/spirit/home/x3/auxiliary/guard.hpp
index b2f1695..e0c0b92 100644
--- a/include/boost/spirit/home/x3/auxiliary/guard.hpp
+++ b/include/boost/spirit/home/x3/auxiliary/guard.hpp
@@ -26,7 +26,7 @@ namespace boost { namespace spirit { namespace x3
         typedef unary_parser<Subject, guard<Subject, Handler>> base_type;
         static bool const is_pass_through_unary = true;
 
-        guard(Subject const& subject, Handler handler)
+        constexpr guard(Subject const& subject, Handler const& handler)
           : base_type(subject), handler(handler) {}
 
         template <typename Iterator, typename Context
diff --git a/include/boost/spirit/home/x3/core/action.hpp b/include/boost/spirit/home/x3/core/action.hpp
index 7c34ac0..e8ba1f3 100644
--- a/include/boost/spirit/home/x3/core/action.hpp
+++ b/include/boost/spirit/home/x3/core/action.hpp
@@ -32,7 +32,7 @@ namespace boost { namespace spirit { namespace x3
         static bool const is_pass_through_unary = true;
         static bool const has_action = true;
 
-        action(Subject const& subject, Action f)
+        constexpr action(Subject const& subject, Action const& f)
           : base_type(subject), f(f) {}
 
         template <typename Iterator, typename Context, typename RuleContext, typename Attribute>
@@ -106,7 +106,7 @@ namespace boost { namespace spirit { namespace x3
     };
 
     template <typename P, typename Action>
-    inline action<typename extension::as_parser<P>::value_type, Action>
+    inline constexpr action<typename extension::as_parser<P>::value_type, Action>
     operator/(P const& p, Action f)
     {
         return { as_parser(p), f };
diff --git a/include/boost/spirit/home/x3/core/parser.hpp b/include/boost/spirit/home/x3/core/parser.hpp
index 0df6930..d696014 100644
--- a/include/boost/spirit/home/x3/core/parser.hpp
+++ b/include/boost/spirit/home/x3/core/parser.hpp
@@ -43,23 +43,23 @@ namespace boost { namespace spirit { namespace x3
         static bool const is_pass_through_unary = false;
         static bool const has_action = false;
 
-        Derived const& derived() const
+        constexpr Derived const& derived() const
         {
             return *static_cast<Derived const*>(this);
         }
 
         template <typename Action>
-        action<Derived, Action>
+        constexpr action<Derived, Action>
         operator[](Action f) const
         {
-            return action<Derived, Action>(this->derived(), f);
+            return { this->derived(), f };
         }
 
         template <typename Handler>
-        guard<Derived, Handler>
+        constexpr guard<Derived, Handler>
         on_error(Handler f) const
         {
-            return guard<Derived, Handler>(this->derived(), f);
+            return { this->derived(), f };
         }
     };
 
@@ -73,7 +73,7 @@ namespace boost { namespace spirit { namespace x3
         typedef Subject subject_type;
         static bool const has_action = Subject::has_action;
 
-        unary_parser(Subject const& subject)
+        constexpr unary_parser(Subject const& subject)
             : subject(subject) {}
 
         unary_parser const& get_unary() const { return *this; }
@@ -90,10 +90,10 @@ namespace boost { namespace spirit { namespace x3
         static bool const has_action =
             left_type::has_action || right_type::has_action;
 
-        binary_parser(Left const& left, Right const& right)
+        constexpr binary_parser(Left const& left, Right const& right)
             : left(left), right(right) {}
 
-        binary_parser const& get_binary() const { return *this; }
+        constexpr binary_parser const& get_binary() const { return *this; }
 
         Left left;
         Right right;
@@ -121,7 +121,7 @@ namespace boost { namespace spirit { namespace x3
                         >::type
                     value_type;
 
-                    static type call(T const& v)
+                    static constexpr type call(T const& v)
                     {
                         return as_spirit_parser(v);
                     }
@@ -153,7 +153,7 @@ namespace boost { namespace spirit { namespace x3
         {
             typedef Derived const& type;
             typedef Derived value_type;
-            static type call(Derived const& p)
+            static constexpr type call(Derived const& p)
             {
                 return p;
             }
@@ -164,7 +164,7 @@ namespace boost { namespace spirit { namespace x3
         {
             typedef Derived const& type;
             typedef Derived value_type;
-            static type call(parser<Derived> const& p)
+            static constexpr type call(parser<Derived> const& p)
             {
                 return p.derived();
             }
@@ -172,14 +172,14 @@ namespace boost { namespace spirit { namespace x3
     }
 
     template <typename T>
-    inline typename extension::as_parser<T>::type
+    inline constexpr typename extension::as_parser<T>::type
     as_parser(T const& x)
     {
         return extension::as_parser<T>::call(x);
     }
 
     template <typename Derived>
-    inline Derived const&
+    inline constexpr Derived const&
     as_parser(parser<Derived> const& p)
     {
         return p.derived();
diff --git a/include/boost/spirit/home/x3/core/proxy.hpp b/include/boost/spirit/home/x3/core/proxy.hpp
index 6fe818d..c9cc114 100644
--- a/include/boost/spirit/home/x3/core/proxy.hpp
+++ b/include/boost/spirit/home/x3/core/proxy.hpp
@@ -18,7 +18,7 @@ namespace boost { namespace spirit { namespace x3
     {
         static bool const is_pass_through_unary = true;
 
-        proxy(Subject const& subject)
+        constexpr proxy(Subject const& subject)
           : unary_parser<Subject, Derived>(subject) {}
 
         // Overload this when appropriate. The proxy parser will pick up
diff --git a/include/boost/spirit/home/x3/directive/confix.hpp b/include/boost/spirit/home/x3/directive/confix.hpp
index 0d99e58..5d33b7d 100644
--- a/include/boost/spirit/home/x3/directive/confix.hpp
+++ b/include/boost/spirit/home/x3/directive/confix.hpp
@@ -20,7 +20,6 @@ namespace boost { namespace spirit { namespace x3
         typedef unary_parser<
             Subject, confix_directive<Prefix, Subject, Postfix>> base_type;
         static bool const is_pass_through_unary = true;
-        static bool const handles_container = Subject::handles_container;
 
         confix_directive(Prefix const& prefix
                          , Subject const& subject
diff --git a/include/boost/spirit/home/x3/directive/expect.hpp b/include/boost/spirit/home/x3/directive/expect.hpp
index 879d92c..13f1432 100644
--- a/include/boost/spirit/home/x3/directive/expect.hpp
+++ b/include/boost/spirit/home/x3/directive/expect.hpp
@@ -40,7 +40,7 @@ namespace boost { namespace spirit { namespace x3
         typedef unary_parser<Subject, expect_directive<Subject> > base_type;
         static bool const is_pass_through_unary = true;
 
-        expect_directive(Subject const& subject)
+        constexpr expect_directive(Subject const& subject)
           : base_type(subject) {}
 
         template <typename Iterator, typename Context
@@ -63,14 +63,14 @@ namespace boost { namespace spirit { namespace x3
     struct expect_gen
     {
         template <typename Subject>
-        expect_directive<typename extension::as_parser<Subject>::value_type>
+        constexpr expect_directive<typename extension::as_parser<Subject>::value_type>
         operator[](Subject const& subject) const
         {
             return { as_parser(subject) };
         }
     };
 
-    auto const expect = expect_gen{};
+    auto constexpr expect = expect_gen{};
 }}}
 
 #endif
diff --git a/include/boost/spirit/home/x3/directive/matches.hpp b/include/boost/spirit/home/x3/directive/matches.hpp
index 2aae43b..75f868e 100644
--- a/include/boost/spirit/home/x3/directive/matches.hpp
+++ b/include/boost/spirit/home/x3/directive/matches.hpp
@@ -21,7 +21,8 @@ namespace boost { namespace spirit { namespace x3
         static bool const has_attribute = true;
         using attribute_type = bool;
 
-        matches_directive(Subject const& subject) : base_type(subject) {}
+        constexpr matches_directive(Subject const& subject)
+            : base_type(subject) {}
 
         template <typename Iterator, typename Context
           , typename RContext, typename Attribute>
@@ -38,14 +39,14 @@ namespace boost { namespace spirit { namespace x3
     struct matches_gen
     {
         template <typename Subject>
-        matches_directive<typename extension::as_parser<Subject>::value_type>
+        constexpr matches_directive<typename extension::as_parser<Subject>::value_type>
         operator[](Subject const& subject) const
         {
             return { as_parser(subject) };
         }
     };
 
-    auto const matches = matches_gen{};
+    constexpr matches_gen matches{};
 }}}
 
 #endif
diff --git a/include/boost/spirit/home/x3/directive/omit.hpp b/include/boost/spirit/home/x3/directive/omit.hpp
index 3053676..d072f30 100644
--- a/include/boost/spirit/home/x3/directive/omit.hpp
+++ b/include/boost/spirit/home/x3/directive/omit.hpp
@@ -23,8 +23,7 @@ namespace boost { namespace spirit { namespace x3
         typedef unused_type attribute_type;
         static bool const has_attribute = false;
 
-        typedef Subject subject_type;
-        omit_directive(Subject const& subject)
+        constexpr omit_directive(Subject const& subject)
           : base_type(subject) {}
 
         template <typename Iterator, typename Context, typename RContext>
@@ -38,14 +37,14 @@ namespace boost { namespace spirit { namespace x3
     struct omit_gen
     {
         template <typename Subject>
-        omit_directive<typename extension::as_parser<Subject>::value_type>
+        constexpr omit_directive<typename extension::as_parser<Subject>::value_type>
         operator[](Subject const& subject) const
         {
             return { as_parser(subject) };
         }
     };
 
-    auto const omit = omit_gen{};
+    constexpr omit_gen omit{};
 }}}
 
 #endif
diff --git a/include/boost/spirit/home/x3/directive/raw.hpp b/include/boost/spirit/home/x3/directive/raw.hpp
index 8432e13..55be062 100644
--- a/include/boost/spirit/home/x3/directive/raw.hpp
+++ b/include/boost/spirit/home/x3/directive/raw.hpp
@@ -25,7 +25,6 @@ namespace boost { namespace spirit { namespace x3
         typedef unary_parser<Subject, raw_directive<Subject> > base_type;
         typedef raw_attribute_type attribute_type;
         static bool const handles_container = Subject::handles_container;
-        typedef Subject subject_type;
 
         raw_directive(Subject const& subject)
           : base_type(subject) {}
diff --git a/include/boost/spirit/home/x3/directive/repeat.hpp b/include/boost/spirit/home/x3/directive/repeat.hpp
index 1cdee97..8ca985c 100644
--- a/include/boost/spirit/home/x3/directive/repeat.hpp
+++ b/include/boost/spirit/home/x3/directive/repeat.hpp
@@ -57,7 +57,7 @@ namespace boost { namespace spirit { namespace x3
         static bool const is_pass_through_unary = true;
         static bool const handles_container = true;
 
-        repeat_directive(Subject const& subject, RepeatCountLimit const& repeat_limit_)
+        constexpr repeat_directive(Subject const& subject, RepeatCountLimit const& repeat_limit_)
           : base_type(subject)
           , repeat_limit(repeat_limit_)
         {}
@@ -93,12 +93,12 @@ namespace boost { namespace spirit { namespace x3
 
     // Infinite loop tag type
     struct inf_type {};
-    const inf_type inf = inf_type();
+    constexpr inf_type inf{};
 
     struct repeat_gen
     {
         template<typename Subject>
-        kleene<typename extension::as_parser<Subject>::value_type>
+        constexpr kleene<typename extension::as_parser<Subject>::value_type>
         operator[](Subject const& subject) const
         {
             return { as_parser(subject) };
@@ -107,12 +107,12 @@ namespace boost { namespace spirit { namespace x3
         template <typename T>
         struct repeat_gen_lvl1
         {
-            repeat_gen_lvl1(T&& repeat_limit_)
+            constexpr repeat_gen_lvl1(T&& repeat_limit_)
               : repeat_limit(repeat_limit_)
             {}
 
             template<typename Subject>
-            repeat_directive< typename extension::as_parser<Subject>::value_type, T>
+            constexpr repeat_directive< typename extension::as_parser<Subject>::value_type, T>
             operator[](Subject const& subject) const
             {
                 return { as_parser(subject),repeat_limit };
@@ -122,28 +122,28 @@ namespace boost { namespace spirit { namespace x3
         };
 
         template <typename T>
-        repeat_gen_lvl1<detail::exact_count<T>>
+        constexpr repeat_gen_lvl1<detail::exact_count<T>>
         operator()(T const exact) const
         {
             return { detail::exact_count<T>{exact} };
         }
 
         template <typename T>
-        repeat_gen_lvl1<detail::finite_count<T>>
+        constexpr repeat_gen_lvl1<detail::finite_count<T>>
         operator()(T const min_val, T const max_val) const
         {
             return { detail::finite_count<T>{min_val,max_val} };
         }
 
         template <typename T>
-        repeat_gen_lvl1<detail::infinite_count<T>>
+        constexpr repeat_gen_lvl1<detail::infinite_count<T>>
         operator()(T const min_val, inf_type const &) const
         {
             return { detail::infinite_count<T>{min_val} };
         }
     };
 
-    auto const repeat = repeat_gen{};
+    constexpr repeat_gen repeat{};
 }}}
 
 namespace boost { namespace spirit { namespace x3 { namespace traits
diff --git a/include/boost/spirit/home/x3/directive/with.hpp b/include/boost/spirit/home/x3/directive/with.hpp
index fe84d9a..6f38cf5 100644
--- a/include/boost/spirit/home/x3/directive/with.hpp
+++ b/include/boost/spirit/home/x3/directive/with.hpp
@@ -16,12 +16,11 @@ namespace boost { namespace spirit { namespace x3
     // with directive injects a value into the context prior to parsing.
     ///////////////////////////////////////////////////////////////////////////
     template <typename Subject, typename Derived, typename T>
-    struct with_value_holder
-      : unary_parser<Subject, Derived>
+    struct with_value_holder : unary_parser<Subject, Derived>
     {
         typedef unary_parser<Subject, Derived> base_type;
         mutable T val;
-        with_value_holder(Subject const& subject, T const& val)
+        constexpr with_value_holder(Subject const& subject, T const& val)
           : base_type(subject)
           , val(val) {}
     };
@@ -32,9 +31,8 @@ namespace boost { namespace spirit { namespace x3
     {
         typedef unary_parser<Subject, Derived> base_type;
         T val;
-        with_value_holder(Subject const& subject, T const& val)
-          : base_type(subject)
-          , val(val) {}
+        constexpr with_value_holder(Subject const& subject, T const& val)
+          : base_type(subject), val(val) {}
     };
 
     template <typename Subject, typename ID, typename T>
@@ -45,9 +43,7 @@ namespace boost { namespace spirit { namespace x3
         static bool const is_pass_through_unary = true;
         static bool const handles_container = Subject::handles_container;
 
-        typedef Subject subject_type;
-
-        with_directive(Subject const& subject, T const& val)
+        constexpr with_directive(Subject const& subject, T const& val)
           : base_type(subject, val) {}
 
         template <typename Iterator, typename Context
@@ -80,11 +76,11 @@ namespace boost { namespace spirit { namespace x3
     {
         T& val;
 
-        with_gen(T& val)
+        constexpr with_gen(T& val)
           : val(val) {}
 
         template <typename Subject>
-        with_directive<typename extension::as_parser<Subject>::value_type, ID, T>
+        constexpr with_directive<typename extension::as_parser<Subject>::value_type, ID, T>
         operator[](Subject const& subject) const
         {
             return { as_parser(subject), val };
@@ -92,15 +88,15 @@ namespace boost { namespace spirit { namespace x3
     };
 
     template <typename ID, typename T>
-    inline with_gen<ID, T> with(T& val)
+    inline constexpr with_gen<ID, T> with(T& val)
     {
-        return with_gen<ID, T>{val};
+        return { val };
     }
     
     template <typename ID, typename T>
-    inline with_gen<ID, T const> with(T const& val)
+    inline constexpr with_gen<ID, T const> with(T const& val)
     {
-        return with_gen<ID, T const>{val};
+        return { val };
     }
 }}}
 
diff --git a/include/boost/spirit/home/x3/nonterminal/rule.hpp b/include/boost/spirit/home/x3/nonterminal/rule.hpp
index cf48da3..b4ba69d 100644
--- a/include/boost/spirit/home/x3/nonterminal/rule.hpp
+++ b/include/boost/spirit/home/x3/nonterminal/rule.hpp
@@ -53,7 +53,7 @@ namespace boost { namespace spirit { namespace x3
         static bool const force_attribute =
             force_attribute_;
 
-        rule_definition(RHS rhs, char const* name)
+        constexpr rule_definition(RHS const& rhs, char const* name)
           : rhs(rhs), name(name) {}
 
         template <typename Iterator, typename Context, typename Attribute_>
@@ -84,16 +84,16 @@ namespace boost { namespace spirit { namespace x3
         static bool const force_attribute = force_attribute_;
 
 #if !defined(BOOST_SPIRIT_X3_NO_RTTI)
-        rule() : name(typeid(rule).name()) {}
+        constexpr rule() : name(typeid(rule).name()) {}
 #else
-        rule() : name("unnamed") {}
+        constexpr rule() : name("unnamed") {}
 #endif
 
-        rule(char const* name)
+        constexpr rule(char const* name)
           : name(name) {}
 
         template <typename RHS>
-        rule_definition<
+        constexpr rule_definition<
             ID, typename extension::as_parser<RHS>::value_type, Attribute, force_attribute_>
         operator=(RHS const& rhs) const
         {
@@ -101,7 +101,7 @@ namespace boost { namespace spirit { namespace x3
         }
 
         template <typename RHS>
-        rule_definition<
+        constexpr rule_definition<
             ID, typename extension::as_parser<RHS>::value_type, Attribute, true>
         operator%=(RHS const& rhs) const
         {
@@ -161,7 +161,7 @@ namespace boost { namespace spirit { namespace x3
       , Context const& context, Attribute& attr)                                \
     {                                                                           \
         using boost::spirit::x3::unused;                                        \
-        static auto const def_ = (rule_name = BOOST_PP_CAT(rule_name, _def));   \
+        static auto constexpr def_ = (rule_name = BOOST_PP_CAT(rule_name, _def));   \
         return def_.parse(first, last, context, unused, attr);                  \
     }                                                                           \
     /***/
diff --git a/include/boost/spirit/home/x3/operator/alternative.hpp b/include/boost/spirit/home/x3/operator/alternative.hpp
index c3a1e40..96f2269 100644
--- a/include/boost/spirit/home/x3/operator/alternative.hpp
+++ b/include/boost/spirit/home/x3/operator/alternative.hpp
@@ -18,7 +18,7 @@ namespace boost { namespace spirit { namespace x3
     {
         typedef binary_parser<Left, Right, alternative<Left, Right>> base_type;
 
-        alternative(Left const& left, Right const& right)
+        constexpr alternative(Left const& left, Right const& right)
             : base_type(left, right) {}
 
         template <typename Iterator, typename Context, typename RContext>
@@ -42,7 +42,7 @@ namespace boost { namespace spirit { namespace x3
     };
 
     template <typename Left, typename Right>
-    inline alternative<
+    inline constexpr alternative<
         typename extension::as_parser<Left>::value_type
       , typename extension::as_parser<Right>::value_type>
     operator|(Left const& left, Right const& right)
diff --git a/include/boost/spirit/home/x3/operator/and_predicate.hpp b/include/boost/spirit/home/x3/operator/and_predicate.hpp
index 1d650f7..6140608 100644
--- a/include/boost/spirit/home/x3/operator/and_predicate.hpp
+++ b/include/boost/spirit/home/x3/operator/and_predicate.hpp
@@ -19,8 +19,7 @@ namespace boost { namespace spirit { namespace x3
         typedef unused_type attribute_type;
         static bool const has_attribute = false;
 
-        and_predicate(Subject const& subject)
-          : base_type(subject) {}
+        constexpr and_predicate(Subject const& subject) : base_type(subject) {}
 
         template <typename Iterator, typename Context
           , typename RContext, typename Attribute>
@@ -33,7 +32,7 @@ namespace boost { namespace spirit { namespace x3
     };
 
     template <typename Subject>
-    inline and_predicate<typename extension::as_parser<Subject>::value_type>
+    inline constexpr and_predicate<typename extension::as_parser<Subject>::value_type>
     operator&(Subject const& subject)
     {
         return { as_parser(subject) };
diff --git a/include/boost/spirit/home/x3/operator/kleene.hpp b/include/boost/spirit/home/x3/operator/kleene.hpp
index b0fb5a1..c012a9e 100644
--- a/include/boost/spirit/home/x3/operator/kleene.hpp
+++ b/include/boost/spirit/home/x3/operator/kleene.hpp
@@ -21,8 +21,7 @@ namespace boost { namespace spirit { namespace x3
         typedef unary_parser<Subject, kleene<Subject>> base_type;
         static bool const handles_container = true;
 
-        kleene(Subject const& subject)
-          : base_type(subject) {}
+        constexpr kleene(Subject const& subject) : base_type(subject) {}
 
         template <typename Iterator, typename Context
           , typename RContext, typename Attribute>
@@ -37,7 +36,7 @@ namespace boost { namespace spirit { namespace x3
     };
 
     template <typename Subject>
-    inline kleene<typename extension::as_parser<Subject>::value_type>
+    inline constexpr kleene<typename extension::as_parser<Subject>::value_type>
     operator*(Subject const& subject)
     {
         return { as_parser(subject) };
diff --git a/include/boost/spirit/home/x3/operator/list.hpp b/include/boost/spirit/home/x3/operator/list.hpp
index 23b398b..48f32af 100644
--- a/include/boost/spirit/home/x3/operator/list.hpp
+++ b/include/boost/spirit/home/x3/operator/list.hpp
@@ -22,7 +22,7 @@ namespace boost { namespace spirit { namespace x3
         static bool const handles_container = true;
         static bool const has_attribute = true;
 
-        list(Left const& left, Right const& right)
+        constexpr list(Left const& left, Right const& right)
           : base_type(left, right) {}
 
         template <typename Iterator, typename Context
@@ -49,9 +49,8 @@ namespace boost { namespace spirit { namespace x3
     };
 
     template <typename Left, typename Right>
-    inline list<
-        typename extension::as_parser<Left>::value_type
-      , typename extension::as_parser<Right>::value_type>
+    inline constexpr list< typename extension::as_parser<Left>::value_type
+                         , typename extension::as_parser<Right>::value_type>
     operator%(Left const& left, Right const& right)
     {
         return { as_parser(left), as_parser(right) };
diff --git a/include/boost/spirit/home/x3/operator/not_predicate.hpp b/include/boost/spirit/home/x3/operator/not_predicate.hpp
index d0302e6..c7e45bb 100644
--- a/include/boost/spirit/home/x3/operator/not_predicate.hpp
+++ b/include/boost/spirit/home/x3/operator/not_predicate.hpp
@@ -19,8 +19,7 @@ namespace boost { namespace spirit { namespace x3
         typedef unused_type attribute_type;
         static bool const has_attribute = false;
 
-        not_predicate(Subject const& subject)
-          : base_type(subject) {}
+        constexpr not_predicate(Subject const& subject) : base_type(subject) {}
 
         template <typename Iterator, typename Context
           , typename RContext, typename Attribute>
@@ -33,7 +32,7 @@ namespace boost { namespace spirit { namespace x3
     };
 
     template <typename Subject>
-    inline not_predicate<typename extension::as_parser<Subject>::value_type>
+    inline constexpr not_predicate<typename extension::as_parser<Subject>::value_type>
     operator!(Subject const& subject)
     {
         return { as_parser(subject) };
diff --git a/include/boost/spirit/home/x3/operator/optional.hpp b/include/boost/spirit/home/x3/operator/optional.hpp
index a402288..346b9d8 100644
--- a/include/boost/spirit/home/x3/operator/optional.hpp
+++ b/include/boost/spirit/home/x3/operator/optional.hpp
@@ -23,8 +23,7 @@ namespace boost { namespace spirit { namespace x3
         typedef proxy<Subject, optional<Subject>> base_type;
         static bool const handles_container = true;
 
-        optional(Subject const& subject)
-          : base_type(subject) {}
+        constexpr optional(Subject const& subject) : base_type(subject) {}
 
         using base_type::parse_subject;
 
@@ -64,7 +63,7 @@ namespace boost { namespace spirit { namespace x3
     };
 
     template <typename Subject>
-    inline optional<typename extension::as_parser<Subject>::value_type>
+    inline constexpr optional<typename extension::as_parser<Subject>::value_type>
     operator-(Subject const& subject)
     {
         return { as_parser(subject) };
diff --git a/include/boost/spirit/home/x3/operator/plus.hpp b/include/boost/spirit/home/x3/operator/plus.hpp
index 152731e..a0dbb2d 100644
--- a/include/boost/spirit/home/x3/operator/plus.hpp
+++ b/include/boost/spirit/home/x3/operator/plus.hpp
@@ -21,8 +21,7 @@ namespace boost { namespace spirit { namespace x3
         typedef unary_parser<Subject, plus<Subject>> base_type;
         static bool const handles_container = true;
 
-        plus(Subject const& subject)
-          : base_type(subject) {}
+        constexpr plus(Subject const& subject) : base_type(subject) {}
 
         template <typename Iterator, typename Context
           , typename RContext, typename Attribute>
@@ -41,7 +40,7 @@ namespace boost { namespace spirit { namespace x3
     };
 
     template <typename Subject>
-    inline plus<typename extension::as_parser<Subject>::value_type>
+    inline constexpr plus<typename extension::as_parser<Subject>::value_type>
     operator+(Subject const& subject)
     {
         return { as_parser(subject) };
diff --git a/include/boost/spirit/home/x3/operator/sequence.hpp b/include/boost/spirit/home/x3/operator/sequence.hpp
index 43f7de6..95018cc 100644
--- a/include/boost/spirit/home/x3/operator/sequence.hpp
+++ b/include/boost/spirit/home/x3/operator/sequence.hpp
@@ -19,7 +19,7 @@ namespace boost { namespace spirit { namespace x3
     {
         typedef binary_parser<Left, Right, sequence<Left, Right>> base_type;
 
-        sequence(Left const& left, Right const& right)
+        constexpr sequence(Left const& left, Right const& right)
             : base_type(left, right) {}
 
         template <typename Iterator, typename Context, typename RContext>
@@ -47,7 +47,7 @@ namespace boost { namespace spirit { namespace x3
     };
 
     template <typename Left, typename Right>
-    inline sequence<
+    inline constexpr sequence<
         typename extension::as_parser<Left>::value_type
       , typename extension::as_parser<Right>::value_type>
     operator>>(Left const& left, Right const& right)
@@ -56,7 +56,7 @@ namespace boost { namespace spirit { namespace x3
     }
 
     template <typename Left, typename Right>
-    inline sequence<
+    inline constexpr sequence<
         typename extension::as_parser<Left>::value_type
       , expect_directive<typename extension::as_parser<Right>::value_type>>
     operator>(Left const& left, Right const& right)
diff --git a/include/boost/spirit/home/x3/support/context.hpp b/include/boost/spirit/home/x3/support/context.hpp
index 048f1fc..c5592fd 100644
--- a/include/boost/spirit/home/x3/support/context.hpp
+++ b/include/boost/spirit/home/x3/support/context.hpp
@@ -16,7 +16,7 @@ namespace boost { namespace spirit { namespace x3
     template <typename ID, typename T, typename Next = unused_type>
     struct context
     {
-        context(T& val, Next const& next)
+        constexpr context(T& val, Next const& next)
             : val(val), next(next) {}
 
         T& get(mpl::identity<ID>) const
@@ -37,10 +37,10 @@ namespace boost { namespace spirit { namespace x3
     template <typename ID, typename T>
     struct context<ID, T, unused_type>
     {
-        context(T& val)
+        constexpr context(T& val)
             : val(val) {}
 
-        context(T& val, unused_type)
+        constexpr context(T& val, unused_type)
             : val(val) {}
 
         T& get(mpl::identity<ID>) const
@@ -58,19 +58,19 @@ namespace boost { namespace spirit { namespace x3
     };
 
     template <typename Tag, typename Context>
-    inline decltype(auto) get(Context const& context)
+    constexpr inline decltype(auto) get(Context const& context)
     {
         return context.get(mpl::identity<Tag>());
     }
 
     template <typename ID, typename T, typename Next>
-    inline context<ID, T, Next> make_context(T& val, Next const& next)
+    constexpr inline context<ID, T, Next> make_context(T& val, Next const& next)
     {
         return { val, next };
     }
 
     template <typename ID, typename T>
-    inline context<ID, T> make_context(T& val)
+    constexpr inline context<ID, T> make_context(T& val)
     {
         return { val };
     }
@@ -93,7 +93,7 @@ namespace boost { namespace spirit { namespace x3
     }
     
     template <typename ID, typename T, typename Next>
-    inline auto
+    constexpr inline auto
     make_unique_context(T& val, Next const& next)
     {
         return detail::make_unique_context<ID>(val, next, x3::get<ID>(next));

--
CYa,
  ⡍⠁⠗⠊⠕ | Debian Developer <URL:http://debian.org/>
  .''`. | Get my public key via finger mlang/[hidden email]
 : :' : | 1024D/7FC1A0854909BCCDBE6C102DDFFC022A6B113E44
 `. `'
   `-      <URL:http://delysid.org/>  <URL:http://www.staff.tugraz.at/mlang/>

------------------------------------------------------------------------------
_______________________________________________
Spirit-general mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/spirit-general
Reply | Threaded
Open this post in threaded view
|

Re: X3: constexpr def_ reduces code size

Joel de Guzman
On 6/18/15 10:30 PM, Mario Lang wrote:

> Hi.
>
> As an experiment, I just tried what would happen if I change
>
> -        static auto const def_ = (rule_name = BOOST_PP_CAT(rule_name, _def));
> +        static auto constexpr def_ = (rule_name = BOOST_PP_CAT(rule_name, _def));
>
> and make all the parsers and their generator functions constexpr.
>
> A long story short: code size is reduced by roughly 35K (422000 to 386800).
> Runtime seems (as expected) unaffected.
>
> This emposes a few limitations that we probably don't want, so it is
> very likely not worth the trouble.  I found it an interesting
> experiment, so I at least wanted to share the result.
>
> The mentioned code size reduction is with GCC 5.
> Clang is a bit stricter on enforcing constexpr, I didn't care to make it
> happy too (besides, clang 3.6 generates roughly 1/3 more code as GCC 5
> when compiling Spirit X3 parsers, so optimizing for size for Clang seems
> like really futile at the moment).
>
> I wonder if we want a macro to control the use of constexpr on def_.
> This would make it optionally possible for grammars to enable this if
> they know they dont make any use of non-constant expressions in their
> grammar.  But that is just an idea.
>
[...]

Now that is interesting! I'm not sure if we need to do it though.
A macro seems good, but is it worth putting the extra gunk?
BTW, I assume you stripped the code?

Cheers,
--
Joel de Guzman
http://www.ciere.com
http://boost-spirit.com
http://www.cycfi.com/


------------------------------------------------------------------------------
_______________________________________________
Spirit-general mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/spirit-general
Reply | Threaded
Open this post in threaded view
|

Re: X3: constexpr def_ reduces code size

Orient
One source of the size bloating is ubiquitous using of reference for pasing empty global objects instances into functions. There is a plenty of ones and obtaining the references to all them is OOD-using. Passing by value is more proper in such a case. Another source of the size may be ubiquitous ODR violation, discussed previously. The latter take place if used a more then one TU.