1 // ==========================================================================
2 //                 SeqAn - The Library for Sequence Analysis
3 // ==========================================================================
4 // Copyright (c) 2006-2018, Knut Reinert, FU Berlin
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 //     * Redistributions of source code must retain the above copyright
11 //       notice, this list of conditions and the following disclaimer.
12 //     * Redistributions in binary form must reproduce the above copyright
13 //       notice, this list of conditions and the following disclaimer in the
14 //       documentation and/or other materials provided with the distribution.
15 //     * Neither the name of Knut Reinert or the FU Berlin nor the names of
16 //       its contributors may be used to endorse or promote products derived
17 //       from this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
23 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29 // DAMAGE.
30 //
31 // ==========================================================================
32 // Author: David Weese <david.weese@fu-berlin.de>
33 // ==========================================================================
34 
35 #ifndef SEQAN_HEADER_PIPE_ECHOER_H
36 #define SEQAN_HEADER_PIPE_ECHOER_H
37 
38 namespace seqan
39 {
40 
41 //namespace SEQAN_NAMESPACE_PIPELINING
42 //{
43 
44     //////////////////////////////////////////////////////////////////////////////
45     // some metaprogramming to unrool fixed-size loops
46     struct EchoerFillWorker_ {
47         template <typename Arg>
bodyEchoerFillWorker_48         static inline void body(Arg &arg, unsigned I) {
49             arg.tmp.i2[I-1] = *(arg.in); ++(arg.in);
50         }
51     };
52 
53     struct EchoerClearWorker_ {
54         template <typename Arg>
bodyEchoerClearWorker_55         static inline void body(Arg &arg, unsigned I) {
56             arg.i2[I] = typename Value< typename Value<Arg, 2>::Type >::Type ();
57         }
58     };
59 
60     struct EchoerShiftWorker_ {
61         template <typename Arg>
bodyEchoerShiftWorker_62         static inline void body(Arg &arg, unsigned I) {
63             arg.i2[I] = arg.i2[I-1];
64         }
65     };
66 
67 
68     template < unsigned echoRepeats, bool omitFirst >
69     struct Echoer;
70 
71     template < typename TInput, unsigned echoRepeats, bool omitFirst >
72     struct Value< Pipe< TInput, Echoer< echoRepeats, omitFirst > > > {
73         typedef Tuple<typename Value<TInput>::Type, echoRepeats>    EchoType;
74         typedef Pair<typename Size<TInput>::Type, EchoType>            Type;
75     };
76 
77 /*!
78  * @class Echoer
79  * @extends Pipe
80  * @headerfile <seqan/pipe.h>
81  *
82  * @brief Outputs tuples of the <tt>echoRepeats</tt> last elements of the input stream.
83  *
84  * @signature template <typename Input, unsigned ECHO_REPEATS, bool OMIT_FIRST>
85  *            class Pipe;
86  *
87  * @tparam TInput       The type of the pipeline module this module reads from.
88  * @tparam ECHO_REPEATS The tuple length.The tuples contain elements <tt>in[i]in[i-1]...in[i-(echoRepeats-1)]</tt>.
89  * @tparam OMIT_FIRST   Omit half filled tuples.  If <tt>true</tt>, the output stream is <tt>echoRepeats-1</tt>
90  *                      elements shorter than the input stream.  If <tt>false</tt>, the lengths are identical and the
91  *                      tuple is filled with blanks (default constructed elements) for undefined entries.
92  *
93  * The output type is a @link Tuple @endlink of input elements and length <tt>echoRepeats</tt> (i.e.
94  * <tt>Tuple&lt;Value&lt;TInput&lt;::Type, echoRepeats&gt;</tt>).
95  *
96  * The tuples are sequences of the form <tt>in[i]in[i-1]in[i-2]..in[i-echoRepeats+1]</tt>. For <tt>omitFirst=false</tt>
97  * <tt>i</tt> begins with 0 and for <tt>omitFirst=true</tt> <tt>i</tt> begins with <tt>echoRepeats-1</tt>.
98  */
99 
100     //////////////////////////////////////////////////////////////////////////////
101     // echoer class
102     template < typename TInput, unsigned echoRepeats, bool omitFirst >
103     struct Pipe< TInput, Echoer<echoRepeats, omitFirst> >
104     {
105         typedef typename Value<Pipe>::Type TValue;
106 
107         TInput    &in;
108         TValue    tmp;
109 
110         Pipe(TInput& _in):
111             in(_in),
112             tmp(0, typename Value<TValue, 2>::Type()) {}
113 
114         inline typename Value<Pipe>::Type const & operator*() const {
115             return tmp;
116         }
117 
118         inline Pipe& operator++() {
119             ++in;
120             if (eof(in)) return *this;
121             LoopReverse<EchoerShiftWorker_, echoRepeats - 1>::run(this->tmp);
122             ++tmp.i1;
123             tmp.i2[0] = *in;
124             return *this;
125         }
126     };
127 
128 
129     //////////////////////////////////////////////////////////////////////////////
130     // global pipe functions
131     template < typename TInput, unsigned echoRepeats, bool omitFirst >
132     inline bool control(Pipe< TInput, Echoer< echoRepeats, omitFirst > > &me, ControlBeginRead const &command) {
133         if (!control(me.in, command)) return false;
134         me.tmp.i1 = 0;
135         Loop<EchoerClearWorker_, echoRepeats - 1>::run(me.tmp);
136         if (!eof(me.in)) me.tmp.i2[0] = *me.in;
137         return true;
138     }
139 
140     template < typename TInput, unsigned echoRepeats >
141     inline bool control(Pipe< TInput, Echoer< echoRepeats, true > > &me, ControlBeginRead const &command) {
142         if (!control(me.in, command) || length(me.in) < echoRepeats - 1) return false;
143         me.tmp.i1 = 0;
144         LoopReverse<EchoerFillWorker_, echoRepeats - 1>::run(me);
145         if (!eof(me.in)) me.tmp.i2[0] = *me.in;
146         return true;
147     }
148 
149     template < typename TInput, unsigned echoRepeats >
150     inline Size< Pipe< TInput, Echoer< echoRepeats, true > > >
151     length(Pipe< TInput, Echoer< echoRepeats, true > > const &me) {
152         return length(me.in) - (echoRepeats - 1);
153     }
154 
155 //}
156 
157 }
158 
159 #endif
160