Main Page   Class Hierarchy   Alphabetical List   Compound List   Examples  

codec_chain.h

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