Main Page   Class Hierarchy   Alphabetical List   Compound List   Examples  

codec_chain.h

00001 /***************************************************************************
00002     copyright            : (C) 2002-2005 by Stefano Barbato
00003     email                : [email protected]
00004 
00005     $Id: codec__chain_8h-source.html,v 1.4 2006-03-12 12:28:31 tat Exp $
00006  ***************************************************************************/
00007 
00008 /***************************************************************************
00009  *                                                                         *
00010  *   This program is free software; you can redistribute it and/or modify  *
00011  *   it under the terms of the GNU General Public License as published by  *
00012  *   the Free Software Foundation; either version 2 of the License, or     *
00013  *   (at your option) any later version.                                   *
00014  *                                                                         *
00015  ***************************************************************************/
00016 #ifndef _MIMETIC_CODEC_CODEC_CHAIN_
00017 #define _MIMETIC_CODEC_CODEC_CHAIN_
00018 #include <iterator>
00019 #include <string>
00020 #include <mimetic/codec/codec_base.h>
00021 
00022 
00023 namespace mimetic
00024 {
00025 
00026 struct null_node;
00027 
00028 template<typename C, typename N = null_node>
00029 struct codec_chain;
00030 
00031 
00032 /*
00033  * push_back_node
00034  */
00035 template<typename Node, typename LastNode>
00036 struct push_back_node
00037 {
00038     typedef    
00039      codec_chain<
00040          typename Node::content_type,
00041         typename
00042          push_back_node<
00043             typename Node::next_node_type, 
00044             LastNode
00045             >::node_type
00046         > node_type;
00047 };
00048 
00049 template<typename LastNode>
00050 struct push_back_node<null_node, LastNode>
00051 {
00052     typedef LastNode node_type;
00053 };
00054 
00055 
00056 /*
00057  * returns item[idx] of the Node passed to the ctor
00058  */
00059 template<typename Node, unsigned int idx>
00060 struct item
00061 {
00062     typedef typename Node::next_node_type next_node_type;
00063     typedef typename item<next_node_type, idx-1>::node_type node_type;
00064     item(const Node& node)
00065     : m_node(node)
00066     {}
00067     const node_type& node() const
00068     {
00069         return item<next_node_type, idx-1>(m_node.m_next).node();
00070     }
00071     const typename node_type::content_type& content() const
00072     {
00073         return node().m_c;
00074     }
00075 
00076 private:
00077     const Node& m_node;
00078 };
00079 
00080 template<typename Node>
00081 struct item<Node, 0>
00082 {
00083     typedef Node node_type;
00084     item(const Node& node)
00085     :m_node(node)
00086     {}
00087     const node_type& node() const
00088     {
00089         return m_node;
00090     }
00091     const typename node_type::content_type& content() const
00092     {
00093         return m_node.m_c;
00094     }
00095 private:
00096     const Node& m_node;
00097 };
00098 
00099 
00100 /*
00101  * build push_back_node<Node,TailNode::node_type and
00102  * initialize it with values stored in Node
00103  */
00104 template<typename Node, typename TailNode, unsigned int idx = Node::count-1>
00105 struct build_push_back_node
00106 {
00107     typedef typename item<Node,idx>::node_type nth_node_type;
00108     typedef typename nth_node_type::content_type nth_content_type;
00109     typedef codec_chain<nth_content_type,TailNode>     
00110         next_tail_node_type;
00111     typedef typename 
00112         build_push_back_node<Node,next_tail_node_type,idx-1>::result_node_type
00113         result_node_type;
00114     /* 
00115     result_node_type is equal to push_back_node<Node,TailNode>::node_type
00116     */
00117     build_push_back_node(const Node& initn, const TailNode& tailn)
00118     : m_initn(initn), m_tailn(tailn)
00119     {
00120     }
00121     operator const result_node_type() const
00122     {
00123         return get();
00124     }
00125     const result_node_type get() const
00126     {
00127         const nth_content_type& nth_c=item<Node,idx>(m_initn).content();
00128         next_tail_node_type next_tail(nth_c, m_tailn);
00129         return build_push_back_node<Node,next_tail_node_type,idx-1>(m_initn,next_tail).get();
00130     }
00131 private:
00132     const Node& m_initn;
00133     const TailNode& m_tailn;
00134 };
00135 
00136 
00137 template<typename Node, typename TailNode>
00138 struct build_push_back_node<Node,TailNode,0>
00139 {
00140     typedef typename item<Node,0>::node_type nth_node_type;
00141     typedef typename nth_node_type::content_type nth_content_type;
00142     typedef codec_chain<nth_content_type, TailNode> next_tail_node_type;
00143     typedef next_tail_node_type result_node_type;
00144 
00145     build_push_back_node(const Node& initn, const TailNode& tailn)
00146     : m_initn(initn), m_tailn(tailn)
00147     {
00148     }
00149     operator const result_node_type() const
00150     {
00151         return get();
00152     }
00153     const result_node_type get() const
00154     {
00155         const nth_content_type& nth_c=item<Node,0>(m_initn).content();
00156         next_tail_node_type next_tail(nth_c, m_tailn);
00157         return next_tail;    
00158     }
00159 private:
00160     const Node& m_initn;
00161     const TailNode& m_tailn;
00162 };
00163 
00164 /// Defines a chain of codecs
00165 /*!
00166  Chain of codecs. <b>Don't use it directly use | operator instead</b>.
00167 
00168  \code
00169      // converts test string to upper case, replaces LF chars with
00170     // CRLF and encodes it using quoted-printable codec
00171     ToUpperCase tuc;
00172     Lf2CrLf l2c;
00173     QP::Encoder qp; 
00174     char buf[MAXLEN]; 
00175 
00176     string test("....some text here....");
00177     code(test.begin(), test.end(), tuc | l2c | qp, buf);
00178  \endcode
00179 
00180  \warning Chainable codecs must derive from chainable_codec<>
00181  \sa encode decode
00182  */
00183 
00184 
00185 template<typename C, typename N>
00186 struct codec_chain
00187 {
00188     typedef codec_chain<C, N> self_type;
00189     typedef C content_type;
00190     typedef N next_node_type;
00191     enum { count = 1 + next_node_type::count };
00192     codec_chain()
00193     {
00194         setName();
00195     }
00196     codec_chain(const content_type& c)
00197     : m_c(c)
00198     {
00199         setName();
00200     }
00201     codec_chain(const content_type& c, const next_node_type& node)
00202     : m_c(c), m_next(node)
00203     {
00204         setName();
00205     }
00206     codec_chain(const codec_chain& node)
00207     : m_c(node.m_c), m_next(node.m_next)
00208     {
00209         setName();
00210     }
00211     codec_chain(const null_node&) 
00212     {
00213         setName();
00214     }
00215     const char* name() const
00216     {
00217         return m_name.c_str();
00218     }
00219     void process(char c)
00220     {
00221         m_c.process(c, m_next);
00222     }
00223     void flush()
00224     {
00225         m_c.flush(m_next);
00226         m_next.flush();
00227     }
00228     template<typename Cn>
00229     const Cn& get_c(int idx) const
00230     {
00231         return get_c(--idx);
00232     }
00233     const content_type& get_c(int idx) const
00234     {
00235         if(idx == 0)
00236             return m_c;
00237         else
00238             return get_c(--idx);
00239     }
00240     template<typename C1>
00241     const C1& operator[](int idx) const
00242     {
00243         if(idx == 0)
00244             return m_c;
00245         else
00246             return m_next[--idx];
00247     }
00248     self_type& operator*()
00249     {    return *this;    }
00250     self_type& operator=(char c)
00251     {
00252         m_c.process(c, m_next);
00253         return *this;
00254     }
00255     self_type& operator++()
00256     {    return *this;    }
00257     self_type& operator++(int)
00258     {    return *this;    }
00259     template<typename TailC>
00260     typename 
00261     push_back_node<self_type, codec_chain<TailC> >::node_type 
00262     operator|(const TailC& l)
00263     {
00264         typedef codec_chain<TailC> tail_node;
00265         tail_node tail = l;
00266         build_push_back_node<self_type, tail_node> bpbn(*this,tail);
00267         return bpbn.get();
00268     }
00269  //protected:
00270     content_type m_c;
00271     next_node_type m_next;
00272     std::string m_name;
00273 private:
00274     void setName()
00275     {
00276         m_name = std::string() + m_c.name() + "|" + m_next.name();
00277     }
00278 };
00279 
00280 
00281 struct null_node
00282 {
00283     enum { idx = 1 };
00284     enum { count = 0 };
00285     struct null_content
00286     {};
00287     typedef null_node self_type;
00288     typedef null_content content_type;
00289     null_node()
00290     {
00291     }
00292     template<typename C1, typename N1>
00293     null_node(const codec_chain<C1, N1>& node)
00294     {
00295     }
00296     const char* name() const
00297     {    return "null_node";    }
00298     self_type& operator*()
00299     {    return *this;    }
00300     self_type& operator=(char c)
00301     {    return *this;    }
00302     self_type& operator++()
00303     {    return *this;    }
00304     self_type& operator++(int)
00305     {    return *this;    }
00306     void flush()
00307     {
00308     }
00309     null_content m_c;
00310 };
00311 
00312 
00313 /*
00314  * helper classes useful to build codec chains
00315  * i.e.  node_traits<Base64,QP>::node_type
00316  * i.e.  node_traits<Base64,QP,Lf2CrLf>::node_type
00317  */
00318 template<typename A, typename B=null_node, typename C=null_node, typename D=null_node, typename E=null_node, typename F=null_node, typename G=null_node>
00319 struct node_traits
00320 {
00321 };
00322 
00323 // class specializations...
00324 
00325 template<typename A, typename B, typename C, typename D, typename E,typename F>
00326 struct node_traits<A,B,C,D,E,F>
00327 {
00328     typedef codec_chain<A,
00329         codec_chain<B,
00330         codec_chain<C,
00331         codec_chain<D,
00332         codec_chain<E,
00333         codec_chain<F> > > > > > node_type;
00334 };
00335 
00336 template<typename A, typename B, typename C, typename D, typename E>
00337 struct node_traits<A,B,C,D,E>
00338 {
00339     typedef codec_chain<A,
00340         codec_chain<B,
00341         codec_chain<C,
00342         codec_chain<D,
00343         codec_chain<E> > > > > node_type;
00344 };
00345 
00346 template<typename A, typename B, typename C, typename D>
00347 struct node_traits<A,B,C,D>
00348 {
00349     typedef codec_chain<A,
00350         codec_chain<B,
00351         codec_chain<C,
00352         codec_chain<D> > > > node_type;
00353 };
00354 
00355 template<typename A, typename B, typename C>
00356 struct node_traits<A,B,C>
00357 {
00358     typedef codec_chain<A,
00359         codec_chain<B,
00360         codec_chain<C> > > node_type;
00361 };
00362 
00363 
00364 template<typename A, typename B>
00365 struct node_traits<A,B>
00366 {
00367     typedef codec_chain<A,
00368         codec_chain<B> > node_type;
00369 };
00370 
00371 template<typename A>
00372 struct node_traits<A>
00373 {
00374     typedef codec_chain<A> node_type;
00375 };
00376 
00377 
00378 /*
00379  * must be the base of all chainable codecs
00380  */
00381 template<typename A>
00382 struct chainable_codec
00383 {
00384     template<typename B>
00385     typename node_traits<A,B>::node_type
00386     operator|(const B& b)
00387     {
00388         typedef codec_chain<B> node_b;
00389         const A& a = static_cast<A&>(*this);
00390         return typename node_traits<A,B>::node_type(a, node_b(b));
00391     }
00392 };
00393 
00394 
00395 /*
00396  * operator|-creates temporary nodes to initialize chain contents
00397  */
00398 
00399 
00400 #if 0
00401 template<class A, class B>
00402 typename node_traits<A,B>::node_type 
00403 operator|(const A& a, const B& b)
00404 {
00405 
00406     typedef codec_chain<B> node_b;
00407     return typename node_traits<A,B>::node_type(a, node_b(b));
00408 }
00409 
00410 template<typename C, typename Node, typename Last>
00411 typename 
00412 push_back_node<codec_chain<C, Node>, codec_chain<Last> >::node_type 
00413 operator|(const codec_chain<C, Node>& node, const Last& l)
00414 {
00415     typedef codec_chain<C,Node> InitNode;
00416     typedef codec_chain<Last> TailNode;
00417     TailNode tailnode = l;
00418     build_push_back_node<InitNode,TailNode> bpbn(node,tailnode);
00419 
00420     return bpbn.get();
00421 }
00422 
00423 #endif
00424 } // namespace mimetic
00425 
00426 #endif
00427