Utils/Console: Add std::map and std::set support
g0dil [Thu, 12 Nov 2009 22:31:35 +0000 (22:31 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1519 270642c3-0616-0410-b53a-bc976706d245

senf/Utils/Console/STLSupport.ct
senf/Utils/Console/STLSupport.cti [new file with mode: 0644]
senf/Utils/Console/STLSupport.hh
senf/Utils/Console/STLSupport.ih [new file with mode: 0644]
senf/Utils/Console/STLSupport.test.cc

index 18af3dc..569211e 100644 (file)
 
 #ifndef DOXYGEN
 
-template <class Sequence>
-prefix_ void senf::console::SequenceArgumentTraits<Sequence>::
-parse(ParseCommandInfo::TokensRange const & tokens, type & out)
+///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::CollectionArgumentTraitsBase<Collection>
+
+template <class Collection>
+prefix_ std::string
+senf::console::detail::CollectionArgumentTraitsBase<Collection>::description()
+{
+    std::string type (prettyName(typeid(Collection)));
+    std::string::size_type e (type.find('<'));
+    if (e == std::string::npos) e = type.size();
+    std::string::size_type b (type.rfind(':', e));
+    if (b == std::string::npos) b = 0; else ++b;
+    return type.substr(b,e-b) + "<" 
+        + ArgumentTraits<typename Collection::value_type>::description() + ">";
+}
+
+template <class Collection>
+prefix_ std::string
+senf::console::detail::CollectionArgumentTraitsBase<Collection>::str(Collection const & value)
+{
+    std::stringstream ss;
+    senf::console::format(value, ss);
+    return ss.str();
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::CollectionArgumentTraits<Collection,Adder>
+
+template <class Collection, class Adder>
+prefix_ void senf::console::detail::CollectionArgumentTraits<Collection,Adder>::
+parse(ParseCommandInfo::TokensRange const & tokens, Collection & out)
 {
     out.clear();
     CheckedArgumentIteratorWrapper arg (tokens);
     while (arg) {
-        out.push_back(typename Sequence::value_type());
-        senf::console::parse( *(arg++), out.back() );
+        typename Collection::value_type v;
+        senf::console::parse( *(arg++), v );
+        Adder::add(out,v);
     }
 }
 
-template <class Sequence>
-prefix_ std::string senf::console::SequenceArgumentTraits<Sequence>::description()
+///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::CollectionReturnValueTraits<Collection>
+
+template <class Collection>
+prefix_ void
+senf::console::detail::CollectionReturnValueTraits<Collection>::format(Collection const & value,
+                                                                       std::ostream & os)
 {
-    std::string type (prettyName(typeid(Sequence)));
+    os << "(";
+    typename type::const_iterator i (value.begin());
+    typename type::const_iterator const i_end (value.end());
+    if (i != i_end)
+        for (;;) {
+            senf::console::format(*i, os);
+            if (++i == i_end) 
+                break;
+            else
+                os << " ";
+        }
+    os << ")";
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::MapArgumentTraits<Collection>
+
+template <class Collection>
+prefix_ void senf::console::detail::MapArgumentTraits<Collection>::
+parse(ParseCommandInfo::TokensRange const & tokens, Collection & out)
+{
+    out.clear();
+    CheckedArgumentIteratorWrapper arg (tokens);
+    while (arg) {
+        typename Collection::key_type key;
+        typename Collection::mapped_type data;
+        senf::console::parse( *(arg++), key );
+        ParseCommandInfo::TokensRange sep (*(arg++));
+        if (sep.size() != 1 || sep[0].type() != Token::OtherPunctuation || sep[0].value() != "=")
+            throw SyntaxErrorException("'=' expected");
+        senf::console::parse( *(arg++), data );
+        out.insert(std::make_pair(key,data));
+    }
+}
+
+template <class Collection>
+prefix_ std::string senf::console::detail::MapArgumentTraits<Collection>::description()
+{
+    std::string type (prettyName(typeid(Collection)));
     std::string::size_type e (type.find('<'));
     if (e == std::string::npos) e = type.size();
     std::string::size_type b (type.rfind(':', e));
     if (b == std::string::npos) b = 0; else ++b;
     return type.substr(b,e-b) + "<" 
-        + ArgumentTraits<typename Sequence::value_type>::description() + ">";
+        + ArgumentTraits<typename Collection::key_type>::description() + ","
+        + ArgumentTraits<typename Collection::mapped_type>::description() + ">";
 }
 
-template <class Sequence>
-prefix_ std::string senf::console::SequenceArgumentTraits<Sequence>::str(type const & value)
+template <class Collection>
+prefix_ std::string
+senf::console::detail::MapArgumentTraits<Collection>::str(Collection const & value)
 {
     std::stringstream ss;
     senf::console::format(value, ss);
     return ss.str();
 }
 
-template <class Sequence>
-prefix_ void senf::console::SequenceReturnValueTraits<Sequence>::format(type const & value,
-                                                                        std::ostream & os)
+///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::MapReturnValueTraits<Collection>
+
+template <class Collection>
+prefix_ void
+senf::console::detail::MapReturnValueTraits<Collection>::format(Collection const & value,
+                                                                std::ostream & os)
 {
     os << "(";
     typename type::const_iterator i (value.begin());
     typename type::const_iterator const i_end (value.end());
     if (i != i_end)
         for (;;) {
-            senf::console::format(*i, os);
+            senf::console::format(i->first, os);
+            os << "=";
+            senf::console::format(i->second, os);
             if (++i == i_end) 
                 break;
             else
@@ -83,6 +163,9 @@ prefix_ void senf::console::SequenceReturnValueTraits<Sequence>::format(type con
     os << ")";
 }
 
+///////////////////////////////////////////////////////////////////////////
+// senf::console::ArgumentTraits< std::pair<T1,T2> >
+
 template <class T1, class T2>
 prefix_ void senf::console::ArgumentTraits< std::pair<T1,T2> >::
 parse(ParseCommandInfo::TokensRange const & tokens, type & out)
@@ -108,6 +191,9 @@ prefix_ std::string senf::console::ArgumentTraits< std::pair<T1,T2> >::str(type
     return ss.str();
 }
 
+///////////////////////////////////////////////////////////////////////////
+// senf::console::ReturnValueTraits< std::pair<T1,T2> >
+
 template <class T1, class T2>
 prefix_ void senf::console::ReturnValueTraits< std::pair<T1,T2> >::format(type const & value,
                                                                           std::ostream & os)
diff --git a/senf/Utils/Console/STLSupport.cti b/senf/Utils/Console/STLSupport.cti
new file mode 100644 (file)
index 0000000..6932f1a
--- /dev/null
@@ -0,0 +1,65 @@
+// $Id$
+//
+// Copyright (C) 2009 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief STLSupport inline template implementation */
+
+#include "STLSupport.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::PushBackFunctor
+
+template <class Sequence, class ValueType>
+prefix_ void senf::console::detail::PushBackFunctor::add(Sequence & seq,
+                                                         ValueType const & value)
+{
+    seq.push_back(value);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::InsertFunctor
+
+template <class Collection, class ValueType>
+prefix_ void senf::console::detail::InsertFunctor::add(Collection & seq,
+                                                       ValueType const & value)
+{
+    seq.insert(value);
+}
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
index d459488..5523f21 100644 (file)
@@ -32,6 +32,7 @@
 #include "Traits.hh"
 
 //#include "STLSupport.mpp"
+#include "STLSupport.ih"
 ///////////////////////////////hh.p////////////////////////////////////////
 
 namespace senf {
@@ -39,43 +40,68 @@ namespace console {
 
 #ifndef DOXYGEN
 
-    template <class Sequence>
-    struct SequenceArgumentTraits
-    {
-        typedef Sequence type;
-        static bool const singleToken = false;
-
-        static void parse(ParseCommandInfo::TokensRange const & tokens, type & out);
-        static std::string description();
-        static std::string str(type const & value);
-    };
-
-    template <class Sequence>
-    struct SequenceReturnValueTraits
-    {
-        typedef Sequence type;
-
-        static void format(type const & value, std::ostream & os);
-    };
-
     template <class T, class Alloc>
     struct ArgumentTraits< std::vector<T,Alloc> >
-        : public SequenceArgumentTraits< std::vector<T,Alloc> >
+        : public detail::CollectionArgumentTraits< std::vector<T,Alloc>, 
+                                                   detail::PushBackFunctor >
     {};
 
     template <class T, class Alloc>
     struct ReturnValueTraits< std::vector<T,Alloc> >
-        : public SequenceReturnValueTraits< std::vector<T,Alloc> >
+        : public detail::CollectionReturnValueTraits< std::vector<T,Alloc> >
     {};
 
     template <class T, class Alloc>
     struct ArgumentTraits< std::list<T,Alloc> >
-        : public SequenceArgumentTraits< std::list<T,Alloc> >
+        : public detail::CollectionArgumentTraits< std::list<T,Alloc>, 
+                                                   detail::PushBackFunctor >
     {};
 
     template <class T, class Alloc>
     struct ReturnValueTraits< std::list<T,Alloc> >
-        : public SequenceReturnValueTraits< std::list<T,Alloc> >
+        : public detail::CollectionReturnValueTraits< std::list<T,Alloc> >
+    {};
+
+    template <class Key, class Compare, class Alloc>
+    struct ArgumentTraits< std::set<Key,Compare,Alloc> >
+        : public detail::CollectionArgumentTraits< std::set<Key,Compare,Alloc>, 
+                                                   detail::InsertFunctor >
+    {};
+
+    template <class Key, class Compare, class Alloc>
+    struct ReturnValueTraits< std::set<Key,Compare,Alloc> >
+        : public detail::CollectionReturnValueTraits< std::set<Key,Compare,Alloc> >
+    {};
+
+    template <class Key, class Compare, class Alloc>
+    struct ArgumentTraits< std::multiset<Key,Compare,Alloc> >
+        : public detail::CollectionArgumentTraits< std::multiset<Key,Compare,Alloc>, 
+                                                   detail::InsertFunctor >
+    {};
+
+    template <class Key, class Compare, class Alloc>
+    struct ReturnValueTraits< std::multiset<Key,Compare,Alloc> >
+        : public detail::CollectionReturnValueTraits< std::multiset<Key,Compare,Alloc> >
+    {};
+
+    template <class Key, class Data, class Compare, class Alloc>
+    struct ArgumentTraits< std::map<Key,Data,Compare,Alloc> >
+        : public detail::MapArgumentTraits< std::map<Key,Data,Compare,Alloc> >
+    {};
+
+    template <class Key, class Data, class Compare, class Alloc>
+    struct ReturnValueTraits< std::map<Key,Data,Compare,Alloc> >
+        : public detail::MapReturnValueTraits< std::map<Key,Data,Compare,Alloc> >
+    {};
+
+    template <class Key, class Data, class Compare, class Alloc>
+    struct ArgumentTraits< std::multimap<Key,Data,Compare,Alloc> >
+        : public detail::MapArgumentTraits< std::multimap<Key,Data,Compare,Alloc> >
+    {};
+
+    template <class Key, class Data, class Compare, class Alloc>
+    struct ReturnValueTraits< std::multimap<Key,Data,Compare,Alloc> >
+        : public detail::MapReturnValueTraits< std::multimap<Key,Data,Compare,Alloc> >
     {};
 
     template <class T1, class T2>
@@ -104,7 +130,7 @@ namespace console {
 ///////////////////////////////hh.e////////////////////////////////////////
 //#include "STLSupport.cci"
 #include "STLSupport.ct"
-//#include "STLSupport.cti"
+#include "STLSupport.cti"
 #endif
 
 \f
diff --git a/senf/Utils/Console/STLSupport.ih b/senf/Utils/Console/STLSupport.ih
new file mode 100644 (file)
index 0000000..2372a84
--- /dev/null
@@ -0,0 +1,107 @@
+// $Id$
+//
+// Copyright (C) 2009 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief STLSupport internal header */
+
+#ifndef IH_SENF_senf_Utils_Console_STLSupport_
+#define IH_SENF_senf_Utils_Console_STLSupport_ 1
+
+// Custom includes
+
+///////////////////////////////ih.p////////////////////////////////////////
+
+namespace senf {
+namespace console {
+namespace detail {
+
+    template <class Collection>
+    struct CollectionArgumentTraitsBase
+    {
+        typedef Collection type;
+        static bool const singleToken = false;
+
+        static std::string description();
+        static std::string str(Collection const & value);
+    };
+
+    template <class Collection, class Adder>
+    struct CollectionArgumentTraits
+        : detail::CollectionArgumentTraitsBase<Collection>
+    {
+        static void parse(ParseCommandInfo::TokensRange const & tokens, Collection  & out);
+    };
+
+    template <class Collection>
+    struct CollectionReturnValueTraits
+    {
+        typedef Collection type;
+
+        static void format(Collection const & value, std::ostream & os);
+    };
+
+    struct PushBackFunctor
+    {
+        template <class Sequence, class ValueType>
+        static void add(Sequence & seq, ValueType const & value);
+    };
+
+    struct InsertFunctor
+    {
+        template <class Collection, class ValueType>
+        static void add(Collection & seq, ValueType const & value);
+    };
+
+    template <class Collection>
+    struct MapArgumentTraits
+    {
+        typedef Collection type;
+        static bool const singleToken = false;
+
+        static void parse(ParseCommandInfo::TokensRange const & tokens, Collection & out);
+        static std::string description();
+        static std::string str(Collection const & value);
+    };
+
+    template <class Collection>
+    struct MapReturnValueTraits
+    {
+        typedef Collection type;
+        
+        static void format(Collection const & value, std::ostream & os);
+    };
+
+}}}
+
+///////////////////////////////ih.e////////////////////////////////////////
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
index c920f62..878c909 100644 (file)
 
 namespace {
 
-    int vectorTest(std::vector<int> const & data)
+    template <class Container>
+    struct Summer
     {
-        int sum (0);
-        for (std::vector<int>::const_iterator i (data.begin()); i != data.end(); ++i)
-            sum += *i;
-        return sum;
-    }
-
-    int listTest(std::list<int> const & data)
+        static int test(Container const & data)
+        {
+            int sum (0);
+            for (typename Container::const_iterator i (data.begin()), i_end (data.end());
+                 i != i_end; ++i)
+                sum += *i;
+            return sum;
+        }
+    };
+
+    std::pair<std::string, int> mapTest(std::map<std::string,int> const & data)
     {
+        std::string keys;
         int sum (0);
-        for (std::list<int>::const_iterator i (data.begin()); i != data.end(); ++i)
-            sum += *i;
-        return sum;
+        for (std::map<std::string,int>::const_iterator i (data.begin()), i_end (data.end());
+             i != i_end; ++i) {
+            keys += i->first;
+            sum += i->second;
+        }
+        return std::make_pair(keys,sum);
     }
-
+                
 }
 
 BOOST_AUTO_UNIT_TEST(vectorSupport)
@@ -68,7 +77,7 @@ BOOST_AUTO_UNIT_TEST(vectorSupport)
     senf::console::root().add("test", dir);
 
     std::vector<int> defv (boost::assign::list_of(7)(2).to_container(defv));
-    dir.add("test", &vectorTest)
+    dir.add("test", &Summer<std::vector<int> >::test)
         .arg("data", "test data", senf::console::kw::default_value = defv);
     std::stringstream ss;
 
@@ -99,7 +108,7 @@ BOOST_AUTO_UNIT_TEST(listSupport)
     senf::console::root().add("test", dir);
 
     std::list<int> defv (boost::assign::list_of(7)(2).to_container(defv));
-    dir.add("test", &listTest)
+    dir.add("test", &Summer<std::list<int> >::test)
         .arg("data", "test data", senf::console::kw::default_value = defv);
     std::stringstream ss;
 
@@ -122,6 +131,70 @@ BOOST_AUTO_UNIT_TEST(listSupport)
         "        default: (7 2)\n" );
 }
 
+BOOST_AUTO_UNIT_TEST(setSupport)
+{
+    senf::console::Executor executor;
+    senf::console::CommandParser parser;
+    senf::console::ScopedDirectory<> dir;
+    senf::console::root().add("test", dir);
+
+    std::set<int> defv (boost::assign::list_of(7)(2).to_container(defv));
+    dir.add("test", &Summer<std::set<int> >::test)
+        .arg("data", "test data", senf::console::kw::default_value = defv);
+    std::stringstream ss;
+
+    SENF_CHECK_NO_THROW(
+        parser.parse("test/test; test/test (); test/test 5; test/test (13); test/test (4 5 8)",
+                     boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
+    BOOST_CHECK_EQUAL( ss.str(), "9\n" "0\n" "5\n" "13\n" "17\n" );
+
+    ss.str("");
+    SENF_CHECK_NO_THROW( 
+        parser.parse("help test/test",
+                     boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
+    BOOST_CHECK_EQUAL(
+        ss.str(), 
+        "Usage:\n"
+        "    test [data:set<int>]\n"
+        "\n"
+        "With:\n"
+        "    data      test data\n"
+        "        default: (2 7)\n" );
+}
+
+BOOST_AUTO_UNIT_TEST(mapSupport)
+{
+    senf::console::Executor executor;
+    senf::console::CommandParser parser;
+    senf::console::ScopedDirectory<> dir;
+    senf::console::root().add("test", dir);
+
+    std::map<std::string, int> defv (
+        boost::assign::map_list_of("foo",7)("bar",2).to_container(defv));
+    dir.add("test", &mapTest)
+        .arg("data", "test data", senf::console::kw::default_value = defv);
+    std::stringstream ss;
+
+    SENF_CHECK_NO_THROW(
+        parser.parse("test/test; test/test (); "
+                     "test/test (vier=4 fuenf = 5 acht=8 )",
+                     boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
+    BOOST_CHECK_EQUAL( ss.str(), "(barfoo 9)\n" "( 0)\n" "(achtfuenfvier 17)\n" );
+
+    ss.str("");
+    SENF_CHECK_NO_THROW( 
+        parser.parse("help test/test",
+                     boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
+    BOOST_CHECK_EQUAL(
+        ss.str(), 
+        "Usage:\n"
+        "    test [data:map<string,int>]\n"
+        "\n"
+        "With:\n"
+        "    data      test data\n"
+        "        default: (bar=2 foo=7)\n" );
+}
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_