$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r56475 - in trunk/boost/spirit/home/karma: directive operator
From: hartmut.kaiser_at_[hidden]
Date: 2009-09-29 12:58:04
Author: hkaiser
Date: 2009-09-29 12:58:03 EDT (Tue, 29 Sep 2009)
New Revision: 56475
URL: http://svn.boost.org/trac/boost/changeset/56475
Log:
Spirit: fixed Karma repeating operators and directives to account for failing subjects
Text files modified: 
   trunk/boost/spirit/home/karma/directive/repeat.hpp |    58 +++++++++++++++++++++------------------ 
   trunk/boost/spirit/home/karma/operator/kleene.hpp  |     9 ++++--                                  
   trunk/boost/spirit/home/karma/operator/list.hpp    |    46 ++++++++++++++++++++++++++-----         
   trunk/boost/spirit/home/karma/operator/plus.hpp    |    13 +++++---                                
   4 files changed, 83 insertions(+), 43 deletions(-)
Modified: trunk/boost/spirit/home/karma/directive/repeat.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/directive/repeat.hpp	(original)
+++ trunk/boost/spirit/home/karma/directive/repeat.hpp	2009-09-29 12:58:03 EDT (Tue, 29 Sep 2009)
@@ -124,11 +124,28 @@
     struct repeat_generator 
       : unary_generator<repeat_generator<Subject, LoopIter> >
     {
+    private:
+        // iterate over the given container until its exhausted or the embedded
+        // (left) generator succeeds
+        template <
+            typename OutputIterator, typename Context, typename Delimiter
+          , typename Iterator>
+        bool generate_subject(OutputIterator& sink, Context& ctx
+          , Delimiter const& d, Iterator& it, Iterator const& end) const
+        {
+            while (!traits::compare(it, end))
+            {
+                if (subject.generate(sink, ctx, d, traits::deref(it)))
+                    return true;
+                traits::next(it);
+            }
+            return false;
+        }
+
+    public:
         typedef Subject subject_type;
 
-        typedef mpl::int_<
-            generator_properties::countingbuffer | subject_type::properties::value
-        > properties;
+        typedef mpl::int_<subject_type::properties::value> properties;
 
         // Build a std::vector from the subject's attribute. Note
         // that build_std_vector may return unused_type if the
@@ -156,38 +173,25 @@
             iterator_type end = traits::end(attr);
             typename LoopIter::type i = iter.start();
 
+            // generate the minimal required amount of output
+            for (/**/; !iter.got_min(i); ++i, traits::next(it))
             {
-                // inhibit (redirect) output, disable counting while buffering
-                detail::enable_buffering<OutputIterator> buffering(sink);
-
+                if (!generate_subject(sink, ctx, d, it, end))
                 {
-                    detail::disable_counting<OutputIterator> nocounting(sink);
-
-                    // generate the minimal required amount of output
-                    for (/**/; !iter.got_min(i); ++i, traits::next(it))
-                    {
-                        if (traits::compare(it, end) ||
-                            !subject.generate(sink, ctx, d, traits::deref(it)))
-                        {
-                            // if we fail before reaching the minimum iteration
-                            // required, do not output anything and return false
-                            return false;
-                        }
-                    }
-                }   // re-enable counting
-
-                // copy the output generated so far to the target output iterator
-                buffering.buffer_copy();
+                    // if we fail before reaching the minimum iteration
+                    // required, do not output anything and return false
+                    return false;
+                }
             }
 
             // generate some more up to the maximum specified
-            bool result = true;
-            for (/**/; result && !iter.got_max(i) && !traits::compare(it, end); 
+            for (/**/; detail::sink_is_good(sink) && !iter.got_max(i); 
                  ++i, traits::next(it))
             {
-                result = subject.generate(sink, ctx, d, traits::deref(it));
+                if (!generate_subject(sink, ctx, d, it, end))
+                    break;
             }
-            return result;
+            return detail::sink_is_good(sink);
         }
 
         template <typename Context>
Modified: trunk/boost/spirit/home/karma/operator/kleene.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/operator/kleene.hpp	(original)
+++ trunk/boost/spirit/home/karma/operator/kleene.hpp	2009-09-29 12:58:03 EDT (Tue, 29 Sep 2009)
@@ -69,10 +69,13 @@
             iterator_type end = traits::end(attr);
 
             // kleene fails only if the underlying output fails
-            bool result = true;
-            for (/**/; result && !traits::compare(it, end); traits::next(it))
+            for (/**/; detail::sink_is_good(sink) && !traits::compare(it, end); 
+                 traits::next(it))
             {
-                result = subject.generate(sink, ctx, d, traits::deref(it));
+                // Ignore return value, failing subject generators are just 
+                // skipped. This allows to selectively generate items in the 
+                // provided attribute.
+                subject.generate(sink, ctx, d, traits::deref(it));
             }
             return detail::sink_is_good(sink);
         }
Modified: trunk/boost/spirit/home/karma/operator/list.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/operator/list.hpp	(original)
+++ trunk/boost/spirit/home/karma/operator/list.hpp	2009-09-29 12:58:03 EDT (Tue, 29 Sep 2009)
@@ -36,11 +36,33 @@
     template <typename Left, typename Right>
     struct list : binary_generator<list<Left, Right> >
     {
+    private:
+        // iterate over the given container until its exhausted or the embedded
+        // (left) generator succeeds
+        template <
+            typename OutputIterator, typename Context, typename Delimiter
+          , typename Iterator>
+        bool generate_left(OutputIterator& sink, Context& ctx
+          , Delimiter const& d, Iterator& it, Iterator const& end) const
+        {
+            while (!traits::compare(it, end))
+            {
+                if (left.generate(sink, ctx, d, traits::deref(it)))
+                    return true;
+                traits::next(it);
+            }
+            return false;
+        }
+
+    public:
         typedef Left left_type;
         typedef Right right_type;
 
         typedef mpl::int_<
-            left_type::properties::value | right_type::properties::value
+            left_type::properties::value 
+          | right_type::properties::value 
+          | generator_properties::buffering 
+          | generator_properties::counting
         > properties;
 
         // Build a std::vector from the LHS's attribute. Note
@@ -69,16 +91,24 @@
             iterator_type it = traits::begin(attr);
             iterator_type end = traits::end(attr);
 
-            bool result = !traits::compare(it, end);
-            if (result && left.generate(sink, ctx, d, traits::deref(it)))
+            if (generate_left(sink, ctx, d, it, end))
             {
-                for (traits::next(it); result && !traits::compare(it, end);
-                     traits::next(it))
+                for (traits::next(it); !traits::compare(it, end); traits::next(it))
                 {
-                    result = right.generate(sink, ctx, d, unused) &&
-                             left.generate(sink, ctx, d, traits::deref(it));
+                    // wrap the given output iterator as generate_left might fail
+                    detail::enable_buffering<OutputIterator> buffering(sink);
+                    {
+                        detail::disable_counting<OutputIterator> nocounting(sink);
+
+                        if (!right.generate(sink, ctx, d, unused))
+                            return false;     // shouldn't happen
+
+                        if (!generate_left(sink, ctx, d, it, end))
+                            break;            // return true as one item succeeded
+                    }
+                    buffering.buffer_copy();
                 }
-                return result;
+                return true;
             }
             return false;
         }
Modified: trunk/boost/spirit/home/karma/operator/plus.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/operator/plus.hpp	(original)
+++ trunk/boost/spirit/home/karma/operator/plus.hpp	2009-09-29 12:58:03 EDT (Tue, 29 Sep 2009)
@@ -72,13 +72,16 @@
             if (traits::compare(it, end))
                 return false;
 
-            // from now on plus fails only if the underlying output fails
-            bool result = true;
-            for (/**/; result && !traits::compare(it, end); traits::next(it))
+            // from now on plus fails if the underlying output fails or overall
+            // no subject generators succeeded
+            bool result = false;
+            for (/**/; detail::sink_is_good(sink) && !traits::compare(it, end); 
+                 traits::next(it))
             {
-                result = subject.generate(sink, ctx, d, traits::deref(it));
+                if (subject.generate(sink, ctx, d, traits::deref(it)))
+                    result = true;
             }
-            return detail::sink_is_good(sink);
+            return result && detail::sink_is_good(sink);
         }
 
         template <typename Context>