/*=============================================================================
  Spirit V1.7.0
  Copyright (c) 2003 Martin Wille
  http://spirit.sourceforge.net/

  Permission to copy, use, modify, sell and distribute this software
  is granted provided this copyright notice appears in all copies.
  This software is provided "as is" without express or implied
  warranty, and with no claim as to its suitability for any purpose.
 =============================================================================*/

  // see http://article.gmane.org/gmane.comp.parsers.spirit.general/4575
  // or https://sf.net/mailarchive/forum.php?thread_id=2692308&forum_id=1595
  // for a description of the bug being tested for by this program
  //
  // the problem should be solved with version 1.3 of phoenix/closures.hpp

#include <iostream>
#include <boost/config.hpp>
#include <boost/test/included/unit_test_framework.hpp>
#include "impl/util.ipp"

namespace ut = boost::unit_test_framework;
using namespace test;

static char const test_banner_name[]="bug_000008 (closure MT) test";
static char const test_suite_name[]="spirit::bug_000008";

#if defined(DONT_HAVE_BOOST) || !defined(BOOST_HAS_THREADS)
// we end here if we can't do multithreading
static void skipped()
{
    if (test::verbose_runtests)
        std::cout << "skipped\n";
}

ut::test_suite*
init_unit_test_suite( int argc, char* argv[] )
{
    test::init(argc, argv);
    test::banner(test_banner_name);
    ut::test_suite* test= BOOST_TEST_SUITE(test_suite_name);
    test->add(BOOST_TEST_CASE(skipped));
    return test;
}

#else
// the real MT stuff

#undef BOOST_SPIRIT_THREADSAFE
#define BOOST_SPIRIT_THREADSAFE
#undef PHOENIX_THREADSAFE
#define PHOENIX_THREADSAFE

#include <boost/spirit/core.hpp>
#include <boost/spirit/attribute/closure.hpp>
#include <boost/thread.hpp>

static const int number_of_calls_to_parse_per_thread=20000;

struct test_closure
    : boost::spirit::closure<test_closure, char const*>
{
    member1 b;
};

struct test_grammar
    : boost::spirit::grammar<test_grammar, test_closure::context_t>
{
    test_grammar() {}

    template <typename ScannerT>
    struct definition
    {
        definition(test_grammar const &self)
        {
            using namespace phoenix;
            rule = boost::spirit::epsilon_p[self.b = arg1];
        }

        boost::spirit::rule<ScannerT> const &start() const { return rule; }

        boost::spirit::rule<ScannerT> rule;
    };
};

test_grammar const g;

void
in_thread(void)
{
    char const text[]="foo";
    for(int i=0; i<number_of_calls_to_parse_per_thread; ++i)
    {
        boost::spirit::parse(&text[0], text+sizeof(text), g);
    }
}

void
bug_000008()
{
    boost::thread t1(in_thread);
    boost::thread t2(in_thread);
    boost::thread t3(in_thread);
    boost::thread t4(in_thread);

    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

////////////////////////////////////////////////////////////////////////////////
ut::test_suite *
init_unit_test_suite( int argc, char *argv[] )
{
    test::init(argc, argv);
    test::banner(test_banner_name);

    ut::test_suite *suite = BOOST_TEST_SUITE(test_suite_name);

    suite->add(BOOST_TEST_CASE(bug_000008));
    return suite;
}

#endif
