inst/include/seqan/basic/tuple_base.h
d92ab6f0
 // ==========================================================================
 //                 SeqAn - The Library for Sequence Analysis
 // ==========================================================================
 // Copyright (c) 2006-2018, Knut Reinert, FU Berlin
 // Copyright (c) 2013 NVIDIA Corporation
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are met:
 //
 //     * Redistributions of source code must retain the above copyright
 //       notice, this list of conditions and the following disclaimer.
 //     * Redistributions in binary form must reproduce the above copyright
 //       notice, this list of conditions and the following disclaimer in the
 //       documentation and/or other materials provided with the distribution.
 //     * Neither the name of Knut Reinert or the FU Berlin nor the names of
 //       its contributors may be used to endorse or promote products derived
 //       from this software without specific prior written permission.
 //
 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 // ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 // DAMAGE.
 //
 // ==========================================================================
 // Author: David Weese <david.weese@fu-berlin.de>
 // ==========================================================================
 // Tuple base class.
 // ==========================================================================
 
 // TODO(holtgrew): What about move construction? Useful for pairs of strings and such. Tricky to implement since ints have no move constructor, for example.
 
 #ifndef SEQAN_INCLUDE_SEQAN_BASIC_TUPLE_BASE_H_
 #define SEQAN_INCLUDE_SEQAN_BASIC_TUPLE_BASE_H_
 
 namespace seqan {
 
 // ============================================================================
 // Forwards
 // ============================================================================
 
 // ============================================================================
 // Tags, Classes, Enums
 // ============================================================================
 
 template <typename TValue>
 struct StoredTupleValue_
 {
     typedef TValue Type;
 };
 
 template <typename TValue, typename TSpec>
 struct StoredTupleValue_< SimpleType<TValue, TSpec> >
 {
     typedef TValue Type;
 };
 
 /*!
  * @class Tuple
  * @headerfile <seqan/basic.h>
  * @brief A constant-size tuple of the same type.
  *
  * @signature template <typename TValue, unsigned SIZE[, typename TSpec]>
  *            class Tuple;
  *
  * @tparam TValue The value that the tuple should be over.
  * @tparam SIZE   The number of entries in the tuple.
  * @tparam TSpec  Specialization tag, optional;  defaults to void.
  */
 
 /*!
  * @fn Tuple::i
  * @brief Array of tuple value.
  *
  * @signature TValue Tuple::i[SIZE];
  *
  * The array of the tuple's values.
  */
 
 template <typename TValue, unsigned SIZE, typename TSpec = void>
 struct Tuple
 {
     // -----------------------------------------------------------------------
     // Members
     // -----------------------------------------------------------------------
 
     typename StoredTupleValue_<TValue>::Type i[SIZE];
 
     // -----------------------------------------------------------------------
     // Subscription Operators;  Have to be declared in class.
     // -----------------------------------------------------------------------
 
     // TODO(holtgrew): Return Value<>::Type?
 
     template <typename TPos>
     inline
     typename StoredTupleValue_<TValue>::Type &
     operator[](TPos k)
     {
         SEQAN_ASSERT_GEQ(static_cast<int64_t>(k), 0);
         SEQAN_ASSERT_LT(static_cast<int64_t>(k), static_cast<int64_t>(SIZE));
         return i[k];
     }
 
     template <typename TPos>
     inline
     typename StoredTupleValue_<TValue>::Type const &
     operator[](TPos k) const
     {
         SEQAN_ASSERT_GEQ(static_cast<int64_t>(k), 0);
         SEQAN_ASSERT_LT(static_cast<int64_t>(k), static_cast<int64_t>(SIZE));
         return i[k];
     }
 
     // This has to be inline because elements (like this tuple) of packed
     // structs can't be arguments.
     template <typename TPos, typename TValue2>
     inline TValue2
     assignValue(TPos k, TValue2 const source)
     {
         return i[k] = source;
     }
 };
 
 
 #pragma pack(push,1)
 template <typename TValue, unsigned SIZE>
 struct Tuple<TValue, SIZE, Pack>
 {
     // -----------------------------------------------------------------------
     // Members
     // -----------------------------------------------------------------------
 
     typename StoredTupleValue_<TValue>::Type i[SIZE];
 
     // -----------------------------------------------------------------------
     // Subscription Operators;  Have to be declared in class.
     // -----------------------------------------------------------------------
 
     // TODO(holtgrew): Return Value<>::Type?
 
     template <typename TPos>
     inline typename StoredTupleValue_<TValue>::Type &
     operator[](TPos k)
     {
         SEQAN_ASSERT_GEQ(static_cast<int64_t>(k), 0);
         SEQAN_ASSERT_LT(static_cast<int64_t>(k), static_cast<int64_t>(SIZE));
         return i[k];
     }
 
     template <typename TPos>
     inline typename StoredTupleValue_<TValue>::Type const &
     operator[](TPos k) const
     {
         SEQAN_ASSERT_GEQ(static_cast<int64_t>(k), 0);
         SEQAN_ASSERT_LT(static_cast<int64_t>(k), static_cast<int64_t>(SIZE));
         return i[k];
     }
 
     // This has to be inline because elements (like this tuple) of packed
     // structs can't be arguments.
     template <typename TPos, typename TValue2>
     inline TValue2
     assignValue(TPos k, TValue2 const source)
     {
         return i[k] = source;
     }
 };
 #pragma pack(pop)
 
 //template <typename TValue, unsigned SIZE>
 //const unsigned Tuple<TValue, SIZE, Pack>::SIZE = SIZE;
 
 // ============================================================================
 // Metafunctions
 // ============================================================================
 
 // -----------------------------------------------------------------------
 // Metafunction LENGTH
 // -----------------------------------------------------------------------
 
 /*!
  * @mfn Tuple#LENGTH
  * @brief Return the length of a tuple.
  *
  * @signature LENGTH<TTuple>::VALUE;
  *
  * @tparam TTuple The tuple to query for its length.
  *
  * @return VALUE The length of the tuple.
  */
 
 template <typename TValue, unsigned SIZE, typename TSpec>
 struct LENGTH<Tuple<TValue, SIZE, TSpec> >
 {
     enum { VALUE = SIZE };
 };
 
 // -----------------------------------------------------------------------
 // Metafunction Value
 // -----------------------------------------------------------------------
 
 /*!
  * @mfn Tuple#Value
  * @brief Return the value type of a tuple.
  *
  * @signature Value<TTuple>::Type;
  *
  * @tparam TTuple The tuple type to query for its value type.
  *
  * @return Type The resulting value type.
  */
 
 template <typename TValue, unsigned SIZE, typename TSpec>
 struct Value<Tuple<TValue, SIZE, TSpec> >
 {
     typedef TValue Type;
 };
 
 // -----------------------------------------------------------------------
 // Metafunction Spec
 // -----------------------------------------------------------------------
 
 template <typename TValue, unsigned SIZE, typename TSpec>
 struct Spec<Tuple<TValue, SIZE, TSpec> >
 {
     typedef TSpec Type;
 };
 
 // ============================================================================
 // Functions
 // ============================================================================
 
 // -----------------------------------------------------------------------
 // Function operator<<();  Stream Output.
 // -----------------------------------------------------------------------
 
 template <typename TTarget, typename TValue, unsigned SIZE, typename TSpec>
 inline void
 write(TTarget &target, Tuple<TValue, SIZE, TSpec> const &a)
 {
     writeValue(target, '[');
     if (SIZE > 0)
         write(target, (TValue)a[0]);
     for (unsigned j = 1; j < SIZE; ++j)
     {
         writeValue(target, ' ');
         write(target, (TValue)a[j]);
     }
     writeValue(target, ']');
 }
 
 template <typename TStream, typename TValue, unsigned SIZE, typename TSpec>
 inline TStream &
 operator<<(TStream & target,
            Tuple<TValue, SIZE, TSpec> const & source)
 {
     typename DirectionIterator<TStream, Output>::Type it = directionIterator(target, Output());
     write(it, source);
     return target;
 }
 
 // ----------------------------------------------------------------------------
 // Function set().
 // ----------------------------------------------------------------------------
 
 template <typename TTuple1, typename TTuple2>
 struct TupleMoveSetWorkerContext_
 {
     TTuple1 & t1;
     TTuple2 & t2;
 
     TupleMoveSetWorkerContext_(TTuple1 & _t1, TTuple2 & _t2)
             : t1(_t1), t2(_t2)
     {}
 };
 
 struct TupleSetWorker_
 {
     template <typename TArg>
     static inline void body(TArg & arg, unsigned I)
     {
         set(arg.t1.i[I - 1], arg.t2.i[I - 1]);
     }
 };
 
 template <typename TValue, unsigned SIZE, typename TSpec>
 inline void
 set(Tuple<TValue, SIZE, TSpec> & t1, Tuple<TValue, SIZE, TSpec> const & t2)
 {
     typedef Tuple<TValue, SIZE, TSpec> TTuple1;
     typedef Tuple<TValue, SIZE, TSpec> const TTuple2;
     TupleMoveSetWorkerContext_<TTuple1, TTuple2> context(t1, t2);
     Loop<TupleSetWorker_, SIZE>::run(context);
 }
 
 template <typename TValue, unsigned SIZE, typename TSpec>
 inline void
 set(Tuple<TValue, SIZE, TSpec> & t1, Tuple<TValue, SIZE, TSpec> & t2)
 {
     set(t1, const_cast<Tuple<TValue, SIZE, TSpec> const &>(t2));
 }
 
 // ----------------------------------------------------------------------------
 // Function move().
 // ----------------------------------------------------------------------------
 
 struct TupleMoveWorker_
 {
     template <typename TArg>
     static inline void body(TArg & arg, unsigned I)
     {
         move(arg.t1.i[I - 1], arg.t2.i[I - 1]);
     }
 };
 
 template <typename TValue, unsigned SIZE, typename TSpec>
 inline void
 move(Tuple<TValue, SIZE, TSpec> & t1, Tuple<TValue, SIZE, TSpec> & t2)
 {
     typedef Tuple<TValue, SIZE, TSpec> TTuple1;
     typedef Tuple<TValue, SIZE, TSpec> TTuple2;
     TupleMoveSetWorkerContext_<TTuple1, TTuple2> context(t1, t2);
     Loop<TupleMoveWorker_, SIZE>::run(context);
 }
 
 // -----------------------------------------------------------------------
 // Function assignValue()
 // -----------------------------------------------------------------------
 
 template <typename TValue, unsigned SIZE, typename TSpec, typename TPos, typename TValue2>
 inline TValue2
 assignValue(Tuple<TValue, SIZE, TSpec> & me, TPos k, TValue2 const source)
 {
     SEQAN_CHECK((unsigned(k) < SIZE), "Invalid position, k = %u, SIZE = %u.", unsigned(k), unsigned(SIZE));
     return me.i[k] = source;
 }
 
 // -----------------------------------------------------------------------
 // Function getValue()
 // -----------------------------------------------------------------------
 
 template <typename TValue, unsigned SIZE, typename TSpec, typename TPos>
 inline TValue
 getValue(Tuple<TValue, SIZE, TSpec> & me, TPos k)
 {
     SEQAN_CHECK((unsigned(k) < SIZE), "Invalid position, k = %u, SIZE = %u.", unsigned(k), unsigned(SIZE));
     return me.i[k];
 }
 
 template <typename TValue, unsigned SIZE, typename TSpec, typename TPos>
 inline TValue
 getValue(Tuple<TValue, SIZE, TSpec> const & me, TPos k)
 {
     SEQAN_CHECK((unsigned(k) < SIZE), "Invalid position, k = %u, SIZE = %u.", unsigned(k), unsigned(SIZE));
     return me.i[k];
 }
 
 // -----------------------------------------------------------------------
 // Function setValue()
 // -----------------------------------------------------------------------
 
 template <typename TValue, unsigned SIZE, typename TSpec, typename TPos, typename TValue2>
 inline void
 setValue(Tuple<TValue, SIZE, TSpec> & me, TPos k, TValue2 const & source)
 {
     SEQAN_CHECK((unsigned(k) < SIZE), "Invalid position, k = %u, SIZE = %u.", unsigned(k), unsigned(SIZE));
     set(me.i[k], source);
 }
 
 // -----------------------------------------------------------------------
 // Function moveValue()
 // -----------------------------------------------------------------------
 
 template <typename TValue, unsigned SIZE, typename TSpec, typename TPos, typename TValue2>
 inline void
 moveValue(Tuple<TValue, SIZE, TSpec> & me, TPos k, TValue2 & source)
 {
     SEQAN_CHECK((unsigned(k) < SIZE), "Invalid position, k = %u, SIZE = %u.", unsigned(k), unsigned(SIZE));
     move(me.i[k], source);
 }
 
 // -----------------------------------------------------------------------
 // Function shiftLeft()
 // -----------------------------------------------------------------------
 
 // TODO(holtgrew): Document!
 
 struct TupleShiftLeftWorker_
 {
     template <typename TArg>
     static inline void body(TArg & arg, unsigned I)
     {
         arg[I-1] = arg[I];  // TODO(holtgrew): Do we really want assignment or movement here?
     }
 };
 
 template <typename TValue, unsigned SIZE, typename TSpec>
 inline void shiftLeft(Tuple<TValue, SIZE, TSpec> &me)
 {
     Loop<TupleShiftLeftWorker_, SIZE - 1>::run(me.i);
 }
 
 // -----------------------------------------------------------------------
 // Function shiftRight()
 // -----------------------------------------------------------------------
 
 // TODO(holtgrew): Document!
 
 struct TupleShiftRightWorker_
 {
     template <typename TArg>
     static inline void body(TArg & arg, unsigned I)
     {
         arg[I] = arg[I - 1];  // TODO(holtgrew): Do we really want assignment or movement here?
     }
 };
 
 template <typename TValue, unsigned SIZE, typename TSpec>
 inline void shiftRight(Tuple<TValue, SIZE, TSpec> & me)
 {
     LoopReverse<TupleShiftRightWorker_, SIZE - 1>::run(me.i);
 }
 
 // -----------------------------------------------------------------------
 // Function length()
 // -----------------------------------------------------------------------
 
 template <typename TValue, unsigned SIZE, typename TSpec>
 inline unsigned length(Tuple<TValue, SIZE, TSpec> const &)
 {
     return SIZE;
 }
 
 // -----------------------------------------------------------------------
 // Function clear()
 // -----------------------------------------------------------------------
 
 template <typename TValue, unsigned SIZE, typename TSpec>
 inline void clear(Tuple<TValue, SIZE, TSpec> & me)
 {
    memset<sizeof(me.i), 0>(&(me.i));
 }
 
 // -----------------------------------------------------------------------
 // Function operator==()
 // -----------------------------------------------------------------------
 
 template <typename TTupleL, typename TTupleR>
 struct ComparisonWorkerContext_
 {
     int result;
     TTupleL const & left;
     TTupleR const & right;
 
     ComparisonWorkerContext_(int b, TTupleL const & l, TTupleR const & r)
             : result(b), left(l), right(r)
     {}
 };
 
 struct TupleComparisonWorkerEq_
 {
     template <typename TArg>
     static inline void body(TArg & arg, unsigned I)
     {
         if (arg.result != 1)
             return;
         if (getValue(arg.left, I - 1) != getValue(arg.right, I - 1))
             arg.result = 0;
     }
 };
 
 template <typename TValue, unsigned SIZE, typename TSpecL, typename TSpecR>
 inline bool
 operator==(Tuple<TValue, SIZE, TSpecL> const & left,
            Tuple<TValue, SIZE, TSpecR> const & right)
 {
     typedef Tuple<TValue, SIZE, TSpecL> TTupleL;
     typedef Tuple<TValue, SIZE, TSpecR> TTupleR;
     ComparisonWorkerContext_<TTupleL, TTupleR> context(1, left, right);
     Loop<TupleComparisonWorkerEq_, SIZE>::run(context);
     return context.result == 1;
 }
 
 // -----------------------------------------------------------------------
 // Function operator!=()
 // -----------------------------------------------------------------------
 
 
 template <typename TValue, unsigned SIZE, typename TSpecL, typename TSpecR>
 inline bool
 operator!=(Tuple<TValue, SIZE, TSpecL> const & left,
            Tuple<TValue, SIZE, TSpecR> const & right)
 {
     return !operator==(left, right);
 }
 
 // -----------------------------------------------------------------------
 // Function operator<()
 // -----------------------------------------------------------------------
 
 struct TupleComparisonWorkerLt_
 {
     template <typename TArg>
     static inline void body(TArg & arg, unsigned I)
     {
         if (arg.result != -1)
             return;
         if (arg.left.i[I - 1] == arg.right.i[I - 1])
             return;
         if (arg.left.i[I - 1] < arg.right.i[I - 1])
             arg.result = 1;
         if (arg.left.i[I - 1] > arg.right.i[I - 1])
             arg.result = 0;
     }
 };
 
 template <typename TValue, unsigned SIZE, typename TSpecL, typename TSpecR>
 inline bool
 operator<(Tuple<TValue, SIZE, TSpecL> const & left,
           Tuple<TValue, SIZE, TSpecR> const & right)
 {
     typedef Tuple<TValue, SIZE, TSpecL> TTupleL;
     typedef Tuple<TValue, SIZE, TSpecR> TTupleR;
     ComparisonWorkerContext_<TTupleL, TTupleR> context(-1, left, right);
     Loop<TupleComparisonWorkerLt_, SIZE>::run(context);
     return context.result == 1;
 }
 
 // -----------------------------------------------------------------------
 // Function operator>()
 // -----------------------------------------------------------------------
 
 struct TupleComparisonWorkerGt_
 {
     template <typename TArg>
     static inline void body(TArg & arg, unsigned I)
     {
         if (arg.result != -1)
             return;
         if (arg.left.i[I - 1] == arg.right.i[I - 1])
             return;
         if (arg.left.i[I - 1] > arg.right.i[I - 1])
             arg.result = 1;
         if (arg.left.i[I - 1] < arg.right.i[I - 1])
             arg.result = 0;
     }
 };
 
 template <typename TValue, unsigned SIZE, typename TSpecL, typename TSpecR>
 inline bool
 operator>(Tuple<TValue, SIZE, TSpecL> const & left,
           Tuple<TValue, SIZE, TSpecR> const & right)
 {
     typedef Tuple<TValue, SIZE, TSpecL> TTupleL;
     typedef Tuple<TValue, SIZE, TSpecR> TTupleR;
     ComparisonWorkerContext_<TTupleL, TTupleR> context(-1, left, right);
     Loop<TupleComparisonWorkerGt_, SIZE>::run(context);
     return context.result == 1;
 }
 
 // -----------------------------------------------------------------------
 // Function operator<=()
 // -----------------------------------------------------------------------
 
 template <typename TValue, unsigned SIZE, typename TSpecL, typename TSpecR>
 inline bool
 operator<=(Tuple<TValue, SIZE, TSpecL> const & left,
            Tuple<TValue, SIZE, TSpecR> const & right)
 {
     return !operator>(left, right);
 }
 
 // -----------------------------------------------------------------------
 // Function operator>=()
 // -----------------------------------------------------------------------
 
 template <typename TValue, unsigned SIZE, typename TSpecL, typename TSpecR>
 inline bool
 operator>=(Tuple<TValue, SIZE, TSpecL> const & left,
            Tuple<TValue, SIZE, TSpecR> const & right)
 {
     return !operator<(left, right);
 }
 
 // -----------------------------------------------------------------------
 // Function operator+()
 // -----------------------------------------------------------------------
 
 template <typename TValue, unsigned SIZE, typename TSpecL, typename TSpecR>
 inline Tuple<TValue, SIZE, TSpecL>
 operator+(Tuple<TValue, SIZE, TSpecL> const & left,
           Tuple<TValue, SIZE, TSpecR> const & right)
 {
     Tuple<TValue, SIZE, TSpecL>  tuple;
 
     for (unsigned j = 0; j < SIZE; ++j)
         tuple[j] = left[j] + right[j];
 
     return tuple;
 }
 
 template <typename TValue1, unsigned SIZE, typename TSpecL, typename TValue2, typename TSpecR>
 inline Tuple<TValue1, SIZE, TSpecL>
 operator+(Tuple<TValue1, SIZE, TSpecL> const & left,
           Tuple<TValue2, SIZE, TSpecR> const & right)
 {
     Tuple<TValue1, SIZE, TSpecL>  tuple;
 
     for (unsigned j = 0; j < SIZE; ++j)
         tuple[j] = left[j] + right[j];
 
     return tuple;
 }
 
 }  // namespace seqan
 
 #endif  // #ifndef SEQAN_INCLUDE_SEQAN_BASIC_TUPLE_BASE_H_