$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r70871 - in branches/quickbook-dev/tools/quickbook: src test/unit
From: dnljms_at_[hidden]
Date: 2011-04-02 13:45:11
Author: danieljames
Date: 2011-04-02 13:45:09 EDT (Sat, 02 Apr 2011)
New Revision: 70871
URL: http://svn.boost.org/trac/boost/changeset/70871
Log:
Quickbook: Alternative tst that's cheaper to copy.
Added:
   branches/quickbook-dev/tools/quickbook/src/symbols.hpp   (contents, props changed)
   branches/quickbook-dev/tools/quickbook/test/unit/symbols_add_null.cpp   (contents, props changed)
   branches/quickbook-dev/tools/quickbook/test/unit/symbols_find_null.cpp   (contents, props changed)
   branches/quickbook-dev/tools/quickbook/test/unit/symbols_tests.cpp   (contents, props changed)
Text files modified: 
   branches/quickbook-dev/tools/quickbook/src/actions.cpp       |     7 ++++---                                 
   branches/quickbook-dev/tools/quickbook/src/actions.hpp       |     3 +--                                     
   branches/quickbook-dev/tools/quickbook/src/actions_class.cpp |    25 ++-----------------------               
   branches/quickbook-dev/tools/quickbook/src/actions_class.hpp |     6 +-----                                  
   branches/quickbook-dev/tools/quickbook/test/unit/Jamfile.v2  |     5 +++++                                   
   5 files changed, 13 insertions(+), 33 deletions(-)
Modified: branches/quickbook-dev/tools/quickbook/src/actions.cpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions.cpp	(original)
+++ branches/quickbook-dev/tools/quickbook/src/actions.cpp	2011-04-02 13:45:09 EDT (Sat, 02 Apr 2011)
@@ -899,7 +899,6 @@
         std::string phrase = values.consume().get_boostbook();
         values.finish();
 
-        actions.copy_macros_for_write();
         actions.macro.add(
             macro_id.begin()
           , macro_id.end()
@@ -1805,7 +1804,6 @@
 
         // scope the macros
         string_symbols macro = actions.macro;
-        std::size_t macro_change_depth = actions.macro_change_depth;
         // scope the templates
         //~ template_symbols templates = actions.templates; $$$ fixme $$$
 
@@ -1837,9 +1835,12 @@
 
         // restore the macros
         actions.macro = macro;
-        actions.macro_change_depth = macro_change_depth;
         // restore the templates
         //~ actions.templates = templates; $$$ fixme $$$
+
+        // restore the __FILENAME__ macro
+        *boost::spirit::classic::find(actions.macro, "__FILENAME__")
+            = detail::path_to_generic(actions.filename_relative);
     }
 
     void phrase_to_docinfo_action_impl::operator()(iterator first, iterator last,
Modified: branches/quickbook-dev/tools/quickbook/src/actions.hpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions.hpp	(original)
+++ branches/quickbook-dev/tools/quickbook/src/actions.hpp	2011-04-02 13:45:09 EDT (Sat, 02 Apr 2011)
@@ -19,6 +19,7 @@
 #include "utils.hpp"
 #include "values.hpp"
 #include "scoped.hpp"
+#include "symbols.hpp"
 
 namespace quickbook
 {
@@ -51,8 +52,6 @@
         return quickbook_range(0, max_);
     }
 
-    typedef cl::symbols<std::string> string_symbols;
-
     int load_snippets(std::string const& file, std::vector<template_symbol>& storage,
         std::string const& extension);
     std::string syntax_highlight(
Modified: branches/quickbook-dev/tools/quickbook/src/actions_class.cpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions_class.cpp	(original)
+++ branches/quickbook-dev/tools/quickbook/src/actions_class.cpp	2011-04-02 13:45:09 EDT (Sat, 02 Apr 2011)
@@ -47,7 +47,6 @@
         , filename(filein_)
         , filename_relative(filein_.filename())
         , xinclude_base(xinclude_base_)
-        , macro_change_depth(0)
         , macro()
         , section_level(0)
         , min_section_level(0)
@@ -101,7 +100,7 @@
             boost::make_tuple(
                 filename
               , xinclude_base
-              , macro_change_depth
+              , macro
               , section_level
               , min_section_level
               , section_id
@@ -116,32 +115,12 @@
         values.builder.save();
     }
     
-    // Pushing and popping the macro symbol table is pretty expensive, so
-    // instead implement a sort of 'stack on write'. Call this whenever a
-    // change is made to the macro table, and it'll stack the current macros
-    // if necessary. Would probably be better to implement macros in a less
-    // expensive manner.
-    void actions::copy_macros_for_write()
-    {
-        if(macro_change_depth != state_stack.size())
-        {
-            macro_stack.push(macro);
-            macro_change_depth = state_stack.size();
-        }
-    }
-
     void actions::pop()
     {
-        if(macro_change_depth == state_stack.size())
-        {
-            macro = macro_stack.top();
-            macro_stack.pop();
-        }
-    
         boost::tie(
             filename
           , xinclude_base
-          , macro_change_depth
+          , macro
           , section_level
           , min_section_level
           , section_id
Modified: branches/quickbook-dev/tools/quickbook/src/actions_class.hpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions_class.hpp	(original)
+++ branches/quickbook-dev/tools/quickbook/src/actions_class.hpp	2011-04-02 13:45:09 EDT (Sat, 02 Apr 2011)
@@ -71,7 +71,6 @@
                                                     // (relative to the original file
                                                     //  or include path).
         fs::path                xinclude_base;
-        std::size_t             macro_change_depth;
         string_symbols          macro;
         int                     section_level;
         int                     min_section_level;
@@ -82,7 +81,7 @@
         typedef boost::tuple<
             fs::path
           , fs::path
-          , std::size_t
+          , string_symbols
           , int
           , int
           , std::string
@@ -91,8 +90,6 @@
         state_tuple;
 
         std::stack<state_tuple> state_stack;
-        // Stack macros separately as copying macros is expensive.
-        std::stack<string_symbols> macro_stack;
 
     // temporary or global state
         int                     template_depth;
@@ -105,7 +102,6 @@
         int                     context;
 
     // push/pop the states and the streams
-        void copy_macros_for_write();
         void push();
         void pop();
         quickbook_grammar& grammar() const;
Added: branches/quickbook-dev/tools/quickbook/src/symbols.hpp
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/quickbook/src/symbols.hpp	2011-04-02 13:45:09 EDT (Sat, 02 Apr 2011)
@@ -0,0 +1,279 @@
+/*=============================================================================
+    Copyright (c) 2001-2003 Joel de Guzman
+    Copyright (c) 2011 Daniel James
+    http://spirit.sourceforge.net/
+
+    Use, modification and distribution is subject to the Boost Software
+    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+    http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+#ifndef QUICKBOOK_SYMBOLS_IPP
+#define QUICKBOOK_SYMBOLS_IPP
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include <boost/spirit/home/classic/symbols.hpp>
+#include <boost/spirit/home/classic/core/assert.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+///////////////////////////////////////////////////////////////////////////////
+namespace quickbook
+{
+
+///////////////////////////////////////////////////////////////////////////////
+//
+//  tst class
+//
+//      This it the Ternary Search Tree from
+//      <boost/spirit/home/classic/symbols/impl/tst.ipp> adapted to be cheap
+//      to copy.
+//
+//      Ternary Search Tree implementation. The data structure is faster than
+//      hashing for many typical search problems especially when the search
+//      interface is iterator based. Searching for a string of length k in a
+//      ternary search tree with n strings will require at most O(log n+k)
+//      character comparisons. TSTs are many times faster than hash tables
+//      for unsuccessful searches since mismatches are discovered earlier
+//      after examining only a few characters. Hash tables always examine an
+//      entire key when searching.
+//
+//      For details see http://www.cs.princeton.edu/~rs/strings/.
+//
+//      *** This is a low level class and is
+//          not meant for public consumption ***
+//
+///////////////////////////////////////////////////////////////////////////////
+
+    template <typename T, typename CharT>
+    struct tst_node
+    {
+        tst_node(CharT value_)
+        : reference_count(0)
+        , value(value_)
+        , data(0)
+        {
+        }
+        
+        tst_node(tst_node const& other)
+        : reference_count(0)
+        , value(other.value)
+        , left(other.left)
+        , middle(other.middle)
+        , right(other.right)
+        , data(0)
+        {
+            if (other.data)
+                data = new T(*other.data);
+        }
+        
+        tst_node& operator=(tst_node other)
+        {
+            swap(other);
+            return *this;
+        }
+
+        ~tst_node()
+        {
+            delete data;
+        }
+        
+        void swap(tst_node& x, tst_node& y)
+        {
+            boost::swap(x.reference_count, y.reference_count);
+            boost::swap(x.value, y.value);
+            boost::swap(x.left, y.left);
+            boost::swap(x.middle, y.middle);
+            boost::swap(x.right, y.right);
+            boost::swap(x.data, y.data);
+        }
+
+        short reference_count;
+        CharT value;
+        boost::intrusive_ptr<tst_node> left;
+        boost::intrusive_ptr<tst_node> middle;
+        boost::intrusive_ptr<tst_node> right;
+        T* data;
+    };
+
+    template <typename T, typename CharT>
+    void intrusive_ptr_add_ref(tst_node<T, CharT>* ptr)
+        { ++ptr->reference_count; }
+
+    template <typename T, typename CharT>
+    void intrusive_ptr_release(tst_node<T, CharT>* ptr)
+        { if(--ptr->reference_count == 0) delete ptr; }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    template <typename T, typename CharT>
+    class tst
+    {
+    public:
+
+        struct search_info
+        {
+            T*          data;
+            std::size_t length;
+        };
+
+        void swap(tst& other)
+        {
+            root.swap(other.root);
+        }
+
+        // TODO: Make sure you check for readdition.
+        template <typename IteratorT>
+        T* add(IteratorT first, IteratorT const& last, T const& data)
+        {
+            if (first == last)
+                return 0;
+
+            node_ptr* np = &root;
+            CharT ch = *first;
+
+            BOOST_SPIRIT_ASSERT((first == last || ch != 0)
+                && "Won't add string containing null character");
+
+            for (;;)
+            {
+                if (!*np || ch == 0)
+                {
+                    node_ptr right = *np;
+                    *np = new node_t(ch);
+                    if (right)
+                        (*np)->right = right;
+                }
+                else if ((*np)->reference_count > 1)
+                {
+                    *np = new node_t(**np);
+                }
+
+                if (ch < (*np)->value)
+                {
+                    np = &(*np)->left;
+                }
+                else
+                {
+                    if (ch == (*np)->value)
+                    {
+                        if (ch == 0)
+                        {
+                            if ((*np)->data == 0)
+                            {
+                                (*np)->data = new T(data);
+                                return (*np)->data;
+                            }
+                            else
+                            {
+                                //  re-addition is disallowed
+                                return 0;
+                            }
+                       }
+                        ++first;
+                        ch = (first == last) ? CharT(0) : *first;
+                        BOOST_SPIRIT_ASSERT((first == last || ch != 0)
+                            && "Won't add string containing null character");
+                        np = &(*np)->middle;
+                    }
+                    else
+                    {
+                        np = &(*np)->right;
+                    }
+                }
+            }
+        }
+
+        template <typename ScannerT>
+        search_info find(ScannerT const& scan) const
+        {
+            search_info result = { 0, 0 };
+            if (scan.at_end()) {
+                return result;
+            }
+
+            typedef typename ScannerT::iterator_t iterator_t;
+            node_ptr    np = root;
+            CharT       ch = *scan;
+            iterator_t  save = scan.first;
+            iterator_t  latest = scan.first;
+            std::size_t latest_len = 0;
+
+            while (np)
+            {
+
+                if (ch < np->value) // => go left!
+                {
+                    if (np->value == 0)
+                    {
+                        result.data = np->data;
+                        if (result.data)
+                        {
+                            latest = scan.first;
+                            latest_len = result.length;
+                        }
+                    }
+
+                    np = np->left;
+                }
+                else if (ch == np->value) // => go middle!
+                {
+                    // Matching the null character is not allowed.
+                    if (np->value == 0)
+                    {
+                        result.data = np->data;
+                        if (result.data)
+                        {
+                            latest = scan.first;
+                            latest_len = result.length;
+                        }
+                        break;
+                    }
+
+                    ++scan;
+                    ch = scan.at_end() ? CharT(0) : *scan;
+                    np = np->middle;
+                    ++result.length;
+                }
+                else // (ch > np->value) => go right!
+                {
+                    if (np->value == 0)
+                    {
+                        result.data = np->data;
+                        if (result.data)
+                        {
+                            latest = scan.first;
+                            latest_len = result.length;
+                        }
+                    }
+
+                    np = np->right;
+                }
+            }
+
+            if (result.data == 0)
+            {
+                scan.first = save;
+            }
+            else
+            {
+                scan.first = latest;
+                result.length = latest_len;
+            }
+            return result;
+        }
+
+    private:
+
+        typedef tst_node<T, CharT> node_t;
+        typedef boost::intrusive_ptr<node_t> node_ptr;
+        node_ptr root;
+    };
+
+    typedef boost::spirit::classic::symbols<
+        std::string,
+        char,
+        quickbook::tst<std::string, char>
+    > string_symbols;
+} // namespace quickbook
+
+#endif
Modified: branches/quickbook-dev/tools/quickbook/test/unit/Jamfile.v2
==============================================================================
--- branches/quickbook-dev/tools/quickbook/test/unit/Jamfile.v2	(original)
+++ branches/quickbook-dev/tools/quickbook/test/unit/Jamfile.v2	2011-04-02 13:45:09 EDT (Sat, 02 Apr 2011)
@@ -7,3 +7,8 @@
 run values_test.cpp ../../src/values.cpp ;
 run post_process_test.cpp ../../src/post_process.cpp ;
 run iterator_tests.cpp ../../src/values.cpp ;
+
+# Copied from spirit
+run symbols_tests.cpp ;
+run symbols_add_null.cpp ;
+run symbols_find_null.cpp ;
\ No newline at end of file
Added: branches/quickbook-dev/tools/quickbook/test/unit/symbols_add_null.cpp
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/quickbook/test/unit/symbols_add_null.cpp	2011-04-02 13:45:09 EDT (Sat, 02 Apr 2011)
@@ -0,0 +1,79 @@
+/*=============================================================================
+    Copyright (c) 2004 Joao Abecasis
+    http://spirit.sourceforge.net/
+
+    Use, modification and distribution is subject to the Boost Software
+    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+    http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+
+// This test requires NDEBUG to be undefined,  because it depends on 
+// BOOST_SPIRIT_ASSERT throwing an exception.
+#ifdef NDEBUG  
+#  undef NDEBUG  
+#endif  
+
+#include <stdexcept>
+
+#define BOOST_SPIRIT_ASSERT_EXCEPTION ::spirit_exception
+
+struct spirit_exception : std::exception
+{
+    spirit_exception(char const * msg)
+        : message(msg)
+    {
+    }
+    ~spirit_exception() throw() {}
+
+    char const* what() const throw() { return message; }
+
+    char const * message;
+};
+
+#include <boost/spirit/include/classic_scanner.hpp>
+#include <boost/utility/addressof.hpp>
+#include "symbols.hpp"
+
+#include <boost/detail/lightweight_test.hpp>
+
+typedef char char_type;
+typedef char const * iterator;
+
+char_type data_[] = "whatever";
+
+iterator begin = data_;
+iterator end = data_
+    + sizeof(data_)/sizeof(char_type); // Yes, this is an intentional bug ;)
+
+char_type data2_[] = "\0something";
+iterator begin2 = data2_;
+iterator end2 = data2_ + sizeof(data2_)/sizeof(char_type) - 1;
+
+int main()
+{
+    typedef BOOST_SPIRIT_CLASSIC_NS::scanner<> scanner;
+    typedef quickbook::tst<void *, char_type> symbols;
+
+    symbols symbols_;
+
+    try
+    {
+        // It is not ok to add strings containing the null character.
+        symbols_.add(begin, end, (void*) boost::addressof(symbols_));
+        BOOST_TEST(0);
+    }
+    catch (spirit_exception &/*e*/)
+    {
+    }
+
+    try
+    {
+        // It is not ok to add strings containing the null character.
+        symbols_.add(begin2, end2, (void*) boost::addressof(symbols_));
+        BOOST_TEST(0);
+    }
+    catch (spirit_exception &/*e*/)
+    {
+    }
+    return boost::report_errors();
+}
Added: branches/quickbook-dev/tools/quickbook/test/unit/symbols_find_null.cpp
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/quickbook/test/unit/symbols_find_null.cpp	2011-04-02 13:45:09 EDT (Sat, 02 Apr 2011)
@@ -0,0 +1,35 @@
+/*=============================================================================
+    Copyright (c) 2004 Joao Abecasis
+    http://spirit.sourceforge.net/
+
+    Use, modification and distribution is subject to the Boost Software
+    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+    http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+
+#include <boost/spirit/include/classic_scanner.hpp>
+#include <boost/utility/addressof.hpp>
+#include "symbols.hpp"
+
+typedef char char_type;
+typedef char const * iterator;
+
+char_type data_[] = "whatever";
+
+iterator begin = data_;
+iterator end = data_
+    + sizeof(data_)/sizeof(char_type); // Yes, this is an intentional bug ;)
+
+int main()
+{
+    typedef BOOST_SPIRIT_CLASSIC_NS::scanner<> scanner;
+    typedef quickbook::tst<void *, char_type> symbols;
+
+    symbols symbols_;
+
+    symbols_.add(begin, end - 1, (void*) boost::addressof(symbols_));
+
+    // The symbol table parser should not choke on input containing the null
+    // character.
+    symbols_.find(scanner(begin, end));
+}
Added: branches/quickbook-dev/tools/quickbook/test/unit/symbols_tests.cpp
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/quickbook/test/unit/symbols_tests.cpp	2011-04-02 13:45:09 EDT (Sat, 02 Apr 2011)
@@ -0,0 +1,356 @@
+/*=============================================================================
+    Copyright (c) 1998-2003 Joel de Guzman
+    Copyright (c)      2003 Martin Wille
+    http://spirit.sourceforge.net/
+
+    Use, modification and distribution is subject to the Boost Software
+    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+    http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+#include <iostream>
+#include <string>
+#include <boost/detail/lightweight_test.hpp>
+#include <boost/spirit/include/classic_core.hpp>
+#include <boost/spirit/include/classic_symbols.hpp>
+#include <boost/detail/lightweight_test.hpp>
+#include <boost/swap.hpp>
+#include "symbols.hpp"
+
+///////////////////////////////////////////////////////////////////////////////
+using namespace std;
+using namespace BOOST_SPIRIT_CLASSIC_NS;
+
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename IteratorT>
+bool
+equal(IteratorT p, IteratorT q)
+{
+    while (*p && *p == *q)
+    {
+        ++p;
+        ++q;
+    }
+    return *p == *q;
+}
+
+template <class SymbolsT, typename CharT>
+void
+docheck
+(
+    SymbolsT const &sym,
+    CharT    const *candidate,
+    bool           hit,
+    CharT    const *result,
+    int            length
+)
+{
+    parse_info<CharT const*> info = parse(candidate, sym);
+
+#define correctly_matched hit == info.hit
+#define correct_match_length unsigned(length) == info.length
+#define correct_tail equal(candidate + (hit?1:0)*length, result)
+
+    BOOST_TEST(correctly_matched);
+
+    if (hit)
+    {
+        BOOST_TEST(correct_match_length);
+        BOOST_TEST(correct_tail);
+    }
+    else
+    {
+        BOOST_TEST(correct_tail);
+    }
+}
+
+template <typename T>
+struct store_action
+{
+    store_action(T const &v) : value(v) {}
+    void operator()(T &v) const { v = value; }
+private:
+    T const value;
+};
+
+template <typename T>
+store_action<T>
+store(T const &v)
+{
+    return v;
+}
+
+template <typename T>
+struct check_action
+{
+    check_action(T const &v) : value(v) {}
+
+#define correct_value_stored (v==value)
+    void operator()(T const &v) const { BOOST_TEST(correct_value_stored); }
+private:
+    T const value;
+};
+
+template <typename T>
+check_action<T>
+docheck(T const &v)
+{
+    return v;
+}
+
+static void
+default_constructible()
+{   // this actually a compile time test
+    symbols<int, char, quickbook::tst<int, char> > ns1;
+    symbols<int, wchar_t, quickbook::tst<int, wchar_t> > ws1;
+    symbols<std::string, char, quickbook::tst<std::string, char> > ns2;
+    symbols<std::string, wchar_t, quickbook::tst<std::string, wchar_t> > ws2;
+
+    (void)ns1; (void)ws1; (void)ns2; (void)ws2;
+}
+
+typedef symbols<int, char, quickbook::tst<int, char> > nsymbols;
+typedef symbols<int, wchar_t, quickbook::tst<int, wchar_t> > wsymbols;
+
+static void
+narrow_match_tests()
+{
+    nsymbols sym;
+    sym = "pineapple", "orange", "banana", "applepie", "apple";
+
+    docheck(sym, "pineapple", true, "", 9);
+    docheck(sym, "orange", true, "", 6);
+    docheck(sym, "banana", true, "", 6);
+    docheck(sym, "apple", true, "", 5);
+    docheck(sym, "pizza", false, "pizza", -1);
+    docheck(sym, "steak", false, "steak", -1);
+    docheck(sym, "applepie", true, "", 8);
+    docheck(sym, "bananarama", true, "rama", 6);
+    docheck(sym, "applet", true, "t", 5);
+    docheck(sym, "applepi", true, "pi", 5);
+    docheck(sym, "appl", false, "appl", -1);
+
+    docheck(sym, "pineapplez", true, "z", 9);
+    docheck(sym, "orangez", true, "z", 6);
+    docheck(sym, "bananaz", true, "z", 6);
+    docheck(sym, "applez", true, "z", 5);
+    docheck(sym, "pizzaz", false, "pizzaz", -1);
+    docheck(sym, "steakz", false, "steakz", -1);
+    docheck(sym, "applepiez", true, "z", 8);
+    docheck(sym, "bananaramaz", true, "ramaz", 6);
+    docheck(sym, "appletz", true, "tz", 5);
+    docheck(sym, "applepix", true, "pix", 5);
+}
+
+static void
+narrow_copy_ctor_tests()
+{
+    nsymbols sym;
+    sym = "pineapple", "orange", "banana", "applepie", "apple";
+
+    nsymbols sym2(sym);
+    docheck(sym2, "pineapple", true, "", 9);
+    docheck(sym2, "pizza", false, "pizza", -1);
+    docheck(sym2, "bananarama", true, "rama", 6);
+}
+
+static void
+narrow_assigment_operator_tests()
+{
+    nsymbols sym;
+    sym = "pineapple", "orange", "banana", "applepie", "apple";
+
+    nsymbols sym2;
+    sym2 = sym;
+
+    docheck(sym2, "pineapple", true, "", 9);
+    docheck(sym2, "pizza", false, "pizza", -1);
+    docheck(sym2, "bananarama", true, "rama", 6);
+}
+
+static void
+narrow_swap_tests()
+{
+    nsymbols sym, sym2;
+    sym = "pineapple", "orange", "banana", "applepie", "apple";
+    sym2 = "potato", "cucumber", "cauliflower", "carrot";
+
+    boost::swap(sym, sym2);
+
+    docheck(sym2, "pineapple", true, "", 9);
+    docheck(sym2, "pizza", false, "pizza", -1);
+    docheck(sym2, "bananarama", true, "rama", 6);
+    docheck(sym, "potatoe", true, "e", 6);
+    docheck(sym, "cauliflour", false, "cauliflour", -1);
+}
+
+static void
+narrow_value_tests()
+{   // also tests the add member functions
+    nsymbols sym;
+
+    sym = "orange", "banana";
+    sym.add("pineapple",1234);
+    sym.add("lemon");
+
+    parse("orange", sym[store(12345)]);
+    parse("orange", sym[docheck(12345)]);
+    parse("pineapple", sym[docheck(1234)]);
+    parse("banana", sym[docheck(int())]);
+    parse("lemon", sym[docheck(int())]);
+}
+
+static void
+narrow_free_functions_tests()
+{
+    nsymbols sym;
+
+#define add_returned_non_null_value (res!=0)
+#define add_returned_null (res==0)
+#define find_returned_non_null_value (res!=0)
+#define find_returned_null (res==0)
+
+    int *res = add(sym,"pineapple");
+    BOOST_TEST(add_returned_non_null_value);
+    res = add(sym,"pineapple");
+    BOOST_TEST(add_returned_null);
+
+    res = find(sym, "pineapple");
+    BOOST_TEST(find_returned_non_null_value);
+    res = find(sym, "banana");
+    BOOST_TEST(find_returned_null);
+}
+
+static void
+wide_match_tests()
+{
+    wsymbols sym;
+    sym = L"pineapple", L"orange", L"banana", L"applepie", L"apple";
+
+    docheck(sym, L"pineapple", true, L"", 9);
+    docheck(sym, L"orange", true, L"", 6);
+    docheck(sym, L"banana", true, L"", 6);
+    docheck(sym, L"apple", true, L"", 5);
+    docheck(sym, L"pizza", false, L"pizza", -1);
+    docheck(sym, L"steak", false, L"steak", -1);
+    docheck(sym, L"applepie", true, L"", 8);
+    docheck(sym, L"bananarama", true, L"rama", 6);
+    docheck(sym, L"applet", true, L"t", 5);
+    docheck(sym, L"applepi", true, L"pi", 5);
+    docheck(sym, L"appl", false, L"appl", -1);
+
+    docheck(sym, L"pineapplez", true, L"z", 9);
+    docheck(sym, L"orangez", true, L"z", 6);
+    docheck(sym, L"bananaz", true, L"z", 6);
+    docheck(sym, L"applez", true, L"z", 5);
+    docheck(sym, L"pizzaz", false, L"pizzaz", -1);
+    docheck(sym, L"steakz", false, L"steakz", -1);
+    docheck(sym, L"applepiez", true, L"z", 8);
+    docheck(sym, L"bananaramaz", true, L"ramaz", 6);
+    docheck(sym, L"appletz", true, L"tz", 5);
+    docheck(sym, L"applepix", true, L"pix", 5);
+}
+
+static void
+wide_copy_ctor_tests()
+{
+    wsymbols sym;
+    sym = L"pineapple", L"orange", L"banana", L"applepie", L"apple";
+
+    wsymbols sym2(sym);
+    docheck(sym2, L"pineapple", true, L"", 9);
+    docheck(sym2, L"pizza", false, L"pizza", -1);
+    docheck(sym2, L"bananarama", true, L"rama", 6);
+}
+
+static void
+wide_assigment_operator_tests()
+{
+    wsymbols sym;
+    sym = L"pineapple", L"orange", L"banana", L"applepie", L"apple";
+
+    wsymbols sym2;
+    sym2 = sym;
+
+    docheck(sym2, L"pineapple", true, L"", 9);
+    docheck(sym2, L"pizza", false, L"pizza", -1);
+    docheck(sym2, L"bananarama", true, L"rama", 6);
+}
+
+static void
+wide_swap_tests()
+{
+    wsymbols sym, sym2;
+    sym = L"pineapple", L"orange", L"banana", L"applepie", L"apple";
+    sym2 = L"potato", L"cucumber", L"cauliflower", L"carrot";
+
+    boost::swap(sym, sym2);
+
+    docheck(sym2, L"pineapple", true, L"", 9);
+    docheck(sym2, L"pizza", false, L"pizza", -1);
+    docheck(sym2, L"bananarama", true, L"rama", 6);
+    docheck(sym, L"potatoe", true, L"e", 6);
+    docheck(sym, L"cauliflour", false, L"cauliflour", -1);
+}
+
+static void
+wide_value_tests()
+{   // also tests the add member functions
+    wsymbols sym;
+
+    sym = L"orange", L"banana";
+    sym.add(L"pineapple",1234);
+    sym.add(L"lemon");
+
+    parse(L"orange", sym[store(12345)]);
+    parse(L"orange", sym[docheck(12345)]);
+    parse(L"pineapple", sym[docheck(1234)]);
+    parse(L"banana", sym[docheck(int())]);
+    parse(L"lemon", sym[docheck(int())]);
+}
+
+static void
+wide_free_functions_tests()
+{
+    wsymbols sym;
+
+    int *res = add(sym,L"pineapple");
+    BOOST_TEST(add_returned_non_null_value);
+    res = add(sym,L"pineapple");
+    BOOST_TEST(add_returned_null);
+
+    res = find(sym, L"pineapple");
+    BOOST_TEST(find_returned_non_null_value);
+    res = find(sym, L"banana");
+    BOOST_TEST(find_returned_null);
+}
+
+static 
+void free_add_find_functions_tests()
+{
+    nsymbols sym;
+    BOOST_TEST(*add(sym, "a", 0) == 0);
+    BOOST_TEST(*add(sym, "a2", 1) == 1);
+    BOOST_TEST(find(sym, "a2"));
+    BOOST_TEST(find(sym, "a"));
+}
+
+int
+main()
+{
+    default_constructible();
+    narrow_match_tests();
+    narrow_copy_ctor_tests();
+    narrow_assigment_operator_tests();
+    narrow_swap_tests();
+    narrow_value_tests();
+    narrow_free_functions_tests();
+    wide_match_tests();
+    wide_copy_ctor_tests();
+    wide_assigment_operator_tests();
+    wide_swap_tests();
+    wide_value_tests();
+    wide_free_functions_tests();
+    free_add_find_functions_tests();
+    return boost::report_errors();
+}