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 
14 namespace mimetic
15 {
16 
17 struct null_node;
18 
19 template<typename C, typename N = null_node>
20 struct codec_chain;
21 
22 
23 /*
24  * push_back_node
25  */
26 template<typename Node, typename LastNode>
27 struct push_back_node
28 {
29  typedef
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 
40 template<typename LastNode>
41 struct 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  */
50 template<typename Node, unsigned int idx>
51 struct 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 
67 private:
68  const Node& m_node;
69 };
70 
71 template<typename Node>
72 struct 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  }
86 private:
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  */
95 template<typename Node, typename TailNode, unsigned int idx = Node::count-1>
96 struct 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  }
122 private:
123  const Node& m_initn;
124  const TailNode& m_tailn;
125 };
126 
127 
128 template<typename Node, typename TailNode>
129 struct 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  }
150 private:
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 
176 template<typename C, typename N>
177 struct codec_chain
178 {
179  typedef codec_chain<C, N> self_type;
180  typedef C content_type;
181  typedef N next_node_type;
182  enum { count = 1 + next_node_type::count };
183  codec_chain()
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;
264 private:
265  void setName()
266  {
267  m_name = std::string() + m_c.name() + "|" + m_next.name();
268  }
269 };
270 
271 
272 struct 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  */
309 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>
310 struct node_traits
311 {
312 };
313 
314 // class specializations...
315 
316 template<typename A, typename B, typename C, typename D, typename E,typename F>
317 struct 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 
327 template<typename A, typename B, typename C, typename D, typename E>
328 struct 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 
337 template<typename A, typename B, typename C, typename D>
338 struct 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 
346 template<typename A, typename B, typename C>
347 struct node_traits<A,B,C>
348 {
349  typedef codec_chain<A,
350  codec_chain<B,
351  codec_chain<C> > > node_type;
352 };
353 
354 
355 template<typename A, typename B>
356 struct node_traits<A,B>
357 {
358  typedef codec_chain<A,
359  codec_chain<B> > node_type;
360 };
361 
362 template<typename A>
363 struct 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  */
372 template<typename A>
373 struct 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
392 template<class A, class B>
393 typename node_traits<A,B>::node_type
394 operator|(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 
401 template<typename C, typename Node, typename Last>
402 typename
403 push_back_node<codec_chain<C, Node>, codec_chain<Last> >::node_type
404 operator|(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:17
Defines a chain of codecs.
Definition: codec_chain.h:20