/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



#ifndef CSV_RANGE_HXX
#define CSV_RANGE_HXX

#include <cstring>  // for std::size_t




namespace csv
{


/** Represents a range of integer or iterator values.

    @tpl T
    Has to be assignable, add- and subtractable. That is:
    either it is
        - an integral type
        - or a random access iterator.
*/
template <class T>
class range
{
  public:
    typedef T           element_type;       /// Provided for generic programming.
    typedef range<T>    self;

  // LIFECYCLE
                        range(
                            T                   i_inclusiveLowerBorder,
                            T                   i_exclusiveUpperBorder );
						~range();
  // INQUIRY
    T                   begin() const;
    T                   end() const;
    std::size_t         size() const;

    bool                contains(
                            T                   i_value ) const;
    bool                contains(
                            const self &        i_other ) const;
    bool                overlaps(
                            const self &        i_other ) const;
    /// @return i_other.begin() - this->end()
    long                distance_to(
                            const self &        i_other ) const;
  private:
  // DATA
	T                   nBegin;
	T                   nEnd;
};


template <class T>
inline range<T>
make_range(T i1, T i2)
{
    return range<T>(i1, i2);
}

template <class T>
inline range<typename T::const_iterator>
range_of(const T & i_container)
{
    return make_range( i_container.begin(),
                       i_container.end()
                     );
}

template <class T>
inline range<typename T::iterator>
range_of(T & io_container)
{
    return make_range( io_container.begin(),
                       io_container.end()
                     );
}





// IMPLEMENTATION

template <class T>
range<T>::range( T i_inclusiveLowerBorder,
                 T i_exclusiveUpperBorder )
    :   nBegin(i_inclusiveLowerBorder),
        nEnd(i_exclusiveUpperBorder)
{
    csv_assert(  nBegin <= nEnd
                 && "Invalid parameters for range<> constructor.");
}

template <class T>
range<T>::~range()
{
}

template <class T>
inline T
range<T>::begin() const
{
    return nBegin;
}

template <class T>
inline T
range<T>::end() const
{
    return nEnd;
}

template <class T>
inline std::size_t
range<T>::size() const
{
    csv_assert(  nBegin <= nEnd
                 && "Invalid range limits in range<>::size().");
    return static_cast<std::size_t>( end() - begin() );
}

template <class T>
bool
range<T>::contains(T i_value ) const
{
    return      begin() <= i_value
            &&  i_value < end();
}

template <class T>
bool
range<T>::contains(const self & i_other) const
{
    // This is subtle, because this would be wrong:
    //      begin() <= i_other.begin()
    //      &&  i_other.end() <= end();
    // An empty range that begins and starts at my end()
    // must not be contained.

    return      contains(i_other.begin())
            &&  i_other.end() <= end();
}

template <class T>
bool
range<T>::overlaps(const self & i_other) const
{
    return      contains(i_other.begin())
            ||  i_other.contains(begin());
}

template <class T>
long
range<T>::distance_to(const self & i_other) const
{
    return i_other.begin() - end();
}




}   // namespace csv
#endif
