Main Page   Class Hierarchy   Alphabetical List   Compound List   Examples  
codec_chain.h
1/***************************************************************************
2 copyright : (C) 2002-2008 by Stefano Barbato
3 email : stefano@codesink.org
4
5 $Id: codec_chain.h,v 1.13 2008-10-07 11:06:26 tat Exp $
6 ***************************************************************************/
7#ifndef _MIMETIC_CODEC_CODEC_CHAIN_
8#define _MIMETIC_CODEC_CODEC_CHAIN_
9#include <iterator>
10#include <string>
11#include <mimetic/codec/codec_base.h>
12
13
14namespace mimetic
15{
16
17struct null_node;
18
19template<typename C, typename N = null_node>
20struct codec_chain;
21
22
23/*
24 * push_back_node
25 */
26template<typename Node, typename LastNode>
27struct push_back_node
28{
29 typedef
30 codec_chain<
31 typename Node::content_type,
32 typename
33 push_back_node<
34 typename Node::next_node_type,
35 LastNode
36 >::node_type
37 > node_type;
38};
39
40template<typename LastNode>
41struct push_back_node<null_node, LastNode>
42{
43 typedef LastNode node_type;
44};
45
46
47/*
48 * returns item[idx] of the Node passed to the ctor
49 */
50template<typename Node, unsigned int idx>
51struct item
52{
53 typedef typename Node::next_node_type next_node_type;
54 typedef typename item<next_node_type, idx-1>::node_type node_type;
55 item(const Node& node)
56 : m_node(node)
57 {}
58 const node_type& node() const
59 {
60 return item<next_node_type, idx-1>(m_node.m_next).node();
61 }
62 const typename node_type::content_type& content() const
63 {
64 return node().m_c;
65 }
66
67private:
68 const Node& m_node;
69};
70
71template<typename Node>
72struct item<Node, 0>
73{
74 typedef Node node_type;
75 item(const Node& node)
76 :m_node(node)
77 {}
78 const node_type& node() const
79 {
80 return m_node;
81 }
82 const typename node_type::content_type& content() const
83 {
84 return m_node.m_c;
85 }
86private:
87 const Node& m_node;
88};
89
90
91/*
92 * build push_back_node<Node,TailNode::node_type and
93 * initialize it with values stored in Node
94 */
95template<typename Node, typename TailNode, unsigned int idx = Node::count-1>
96struct build_push_back_node
97{
98 typedef typename item<Node,idx>::node_type nth_node_type;
99 typedef typename nth_node_type::content_type nth_content_type;
100 typedef codec_chain<nth_content_type,TailNode>
101 next_tail_node_type;
102 typedef typename
103 build_push_back_node<Node,next_tail_node_type,idx-1>::result_node_type
104 result_node_type;
105 /*
106 result_node_type is equal to push_back_node<Node,TailNode>::node_type
107 */
108 build_push_back_node(const Node& initn, const TailNode& tailn)
109 : m_initn(initn), m_tailn(tailn)
110 {
111 }
112 operator const result_node_type() const
113 {
114 return get();
115 }
116 const result_node_type get() const
117 {
118 const nth_content_type& nth_c=item<Node,idx>(m_initn).content();
119 next_tail_node_type next_tail(nth_c, m_tailn);
120 return build_push_back_node<Node,next_tail_node_type,idx-1>(m_initn,next_tail).get();
121 }
122private:
123 const Node& m_initn;
124 const TailNode& m_tailn;
125};
126
127
128template<typename Node, typename TailNode>
129struct build_push_back_node<Node,TailNode,0>
130{
131 typedef typename item<Node,0>::node_type nth_node_type;
132 typedef typename nth_node_type::content_type nth_content_type;
133 typedef codec_chain<nth_content_type, TailNode> next_tail_node_type;
134 typedef next_tail_node_type result_node_type;
135
136 build_push_back_node(const Node& initn, const TailNode& tailn)
137 : m_initn(initn), m_tailn(tailn)
138 {
139 }
140 operator const result_node_type() const
141 {
142 return get();
143 }
144 const result_node_type get() const
145 {
146 const nth_content_type& nth_c=item<Node,0>(m_initn).content();
147 next_tail_node_type next_tail(nth_c, m_tailn);
148 return next_tail;
149 }
150private:
151 const Node& m_initn;
152 const TailNode& m_tailn;
153};
154
155/// Defines a chain of codecs
156/*!
157 Chain of codecs. <b>Don't use it directly use | operator instead</b>.
158
159 \code
160 // converts test string to upper case, replaces LF chars with
161 // CRLF and encodes it using quoted-printable codec
162 ToUpperCase tuc;
163 Lf2CrLf l2c;
164 QP::Encoder qp;
165 char buf[MAXLEN];
166
167 string test("....some text here....");
168 code(test.begin(), test.end(), tuc | l2c | qp, buf);
169 \endcode
170
171 \warning Chainable codecs must derive from chainable_codec<>
172 \sa encode decode
173 */
174
175
176template<typename C, typename N>
178{
180 typedef C content_type;
181 typedef N next_node_type;
182 enum { count = 1 + next_node_type::count };
184 {
185 setName();
186 }
187 codec_chain(const content_type& c)
188 : m_c(c)
189 {
190 setName();
191 }
192 codec_chain(const content_type& c, const next_node_type& node)
193 : m_c(c), m_next(node)
194 {
195 setName();
196 }
197 codec_chain(const codec_chain& node)
198 : m_c(node.m_c), m_next(node.m_next)
199 {
200 setName();
201 }
202 codec_chain(const null_node&)
203 {
204 setName();
205 }
206 const char* name() const
207 {
208 return m_name.c_str();
209 }
210 void process(char c)
211 {
212 m_c.process(c, m_next);
213 }
214 void flush()
215 {
216 m_c.flush(m_next);
217 m_next.flush();
218 }
219 template<typename Cn>
220 const Cn& get_c(int idx) const
221 {
222 return get_c(--idx);
223 }
224 const content_type& get_c(int idx) const
225 {
226 if(idx == 0)
227 return m_c;
228 else
229 return get_c(--idx);
230 }
231 template<typename C1>
232 const C1& operator[](int idx) const
233 {
234 if(idx == 0)
235 return m_c;
236 else
237 return m_next[--idx];
238 }
239 self_type& operator*()
240 { return *this; }
241 self_type& operator=(char c)
242 {
243 m_c.process(c, m_next);
244 return *this;
245 }
246 self_type& operator++()
247 { return *this; }
248 self_type& operator++(int)
249 { return *this; }
250 template<typename TailC>
251 typename
252 push_back_node<self_type, codec_chain<TailC> >::node_type
253 operator|(const TailC& l)
254 {
255 typedef codec_chain<TailC> tail_node;
256 tail_node tail = l;
257 build_push_back_node<self_type, tail_node> bpbn(*this,tail);
258 return bpbn.get();
259 }
260 //protected:
261 content_type m_c;
262 next_node_type m_next;
263 std::string m_name;
264private:
265 void setName()
266 {
267 m_name = std::string() + m_c.name() + "|" + m_next.name();
268 }
269};
270
271
272struct null_node
273{
274 enum { idx = 1 };
275 enum { count = 0 };
276 struct null_content
277 {};
278 typedef null_node self_type;
279 typedef null_content content_type;
280 null_node()
281 {
282 }
283 template<typename C1, typename N1>
284 null_node(const codec_chain<C1, N1>& node)
285 {
286 }
287 const char* name() const
288 { return "null_node"; }
289 self_type& operator*()
290 { return *this; }
291 self_type& operator=(char c)
292 { return *this; }
293 self_type& operator++()
294 { return *this; }
295 self_type& operator++(int)
296 { return *this; }
297 void flush()
298 {
299 }
300 null_content m_c;
301};
302
303
304/*
305 * helper classes useful to build codec chains
306 * i.e. node_traits<Base64,QP>::node_type
307 * i.e. node_traits<Base64,QP,Lf2CrLf>::node_type
308 */
309template<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>
310struct node_traits
311{
312};
313
314// class specializations...
315
316template<typename A, typename B, typename C, typename D, typename E,typename F>
317struct node_traits<A,B,C,D,E,F>
318{
319 typedef codec_chain<A,
320 codec_chain<B,
321 codec_chain<C,
322 codec_chain<D,
323 codec_chain<E,
324 codec_chain<F> > > > > > node_type;
325};
326
327template<typename A, typename B, typename C, typename D, typename E>
328struct node_traits<A,B,C,D,E>
329{
330 typedef codec_chain<A,
331 codec_chain<B,
332 codec_chain<C,
333 codec_chain<D,
334 codec_chain<E> > > > > node_type;
335};
336
337template<typename A, typename B, typename C, typename D>
338struct node_traits<A,B,C,D>
339{
340 typedef codec_chain<A,
341 codec_chain<B,
342 codec_chain<C,
343 codec_chain<D> > > > node_type;
344};
345
346template<typename A, typename B, typename C>
347struct node_traits<A,B,C>
348{
349 typedef codec_chain<A,
350 codec_chain<B,
351 codec_chain<C> > > node_type;
352};
353
354
355template<typename A, typename B>
356struct node_traits<A,B>
357{
358 typedef codec_chain<A,
359 codec_chain<B> > node_type;
360};
361
362template<typename A>
363struct node_traits<A>
364{
365 typedef codec_chain<A> node_type;
366};
367
368
369/*
370 * must be the base of all chainable codecs
371 */
372template<typename A>
373struct chainable_codec
374{
375 template<typename B>
376 typename node_traits<A,B>::node_type
377 operator|(const B& b)
378 {
379 typedef codec_chain<B> node_b;
380 const A& a = static_cast<A&>(*this);
381 return typename node_traits<A,B>::node_type(a, node_b(b));
382 }
383};
384
385
386/*
387 * operator|-creates temporary nodes to initialize chain contents
388 */
389
390
391#if 0
392template<class A, class B>
393typename node_traits<A,B>::node_type
394operator|(const A& a, const B& b)
395{
396
397 typedef codec_chain<B> node_b;
398 return typename node_traits<A,B>::node_type(a, node_b(b));
399}
400
401template<typename C, typename Node, typename Last>
402typename
403push_back_node<codec_chain<C, Node>, codec_chain<Last> >::node_type
404operator|(const codec_chain<C, Node>& node, const Last& l)
405{
406 typedef codec_chain<C,Node> InitNode;
407 typedef codec_chain<Last> TailNode;
408 TailNode tailnode = l;
409 build_push_back_node<InitNode,TailNode> bpbn(node,tailnode);
410
411 return bpbn.get();
412}
413
414#endif
415} // namespace mimetic
416
417#endif
418
Definition: body.h:18
Defines a chain of codecs.
Definition: codec_chain.h:178