//  Boost string_algo library join.hpp header file  ---------------------------//



//  Copyright Pavol Droba 2002-2006.

//

// Distributed under the Boost Software License, Version 1.0.

//    (See accompanying file LICENSE_1_0.txt or copy at

//          http://www.boost.org/LICENSE_1_0.txt)



//  See http://www.boost.org/ for updates, documentation, and revision history.



#ifndef BOOST_STRING_JOIN_HPP

#define BOOST_STRING_JOIN_HPP



#include <boost/algorithm/string/config.hpp>

#include <boost/algorithm/string/detail/sequence.hpp>

#include <boost/range/value_type.hpp>

#include <boost/range/as_literal.hpp>



/*! \file

    Defines join algorithm. 



    Join algorithm is a counterpart to split algorithms.

    It joins strings from a 'list' by adding user defined separator.

    Additionally there is a version that allows simple filtering

    by providing a predicate.

*/



namespace boost {

    namespace algorithm {



//  join --------------------------------------------------------------//



        //! Join algorithm

        /*!

            This algorithm joins all strings in a 'list' into one long string.

            Segments are concatenated by given separator.



            \param Input A container that holds the input strings. It must be a container-of-containers.

            \param Separator A string that will separate the joined segments.

            \return Concatenated string.



            \note This function provides the strong exception-safety guarantee

        */

        template< typename SequenceSequenceT, typename Range1T>

        inline typename range_value<SequenceSequenceT>::type 

        join(

            const SequenceSequenceT& Input,

            const Range1T& Separator)

        {

            // Define working types

            typedef typename range_value<SequenceSequenceT>::type ResultT;

            typedef typename range_const_iterator<SequenceSequenceT>::type InputIteratorT;



            // Parse input

            InputIteratorT itBegin=begin(Input);

            InputIteratorT itEnd=end(Input);



            // Construct container to hold the result

            ResultT Result;

            

            // Append first element

            if(itBegin!=itEnd)

            {

                detail::insert(Result, end(Result), *itBegin);

                ++itBegin;

            }



            for(;itBegin!=itEnd; ++itBegin)

            {

                // Add separator

                detail::insert(Result, end(Result), as_literal(Separator));

                // Add element

                detail::insert(Result, end(Result), *itBegin);

            }



            return Result;

        }



// join_if ----------------------------------------------------------//



        //! Conditional join algorithm

        /*!

            This algorithm joins all strings in a 'list' into one long string.

            Segments are concatenated by given separator. Only segments that

            satisfy the predicate will be added to the result.



            \param Input A container that holds the input strings. It must be a container-of-containers.

            \param Separator A string that will separate the joined segments.

            \param Pred A segment selection predicate

            \return Concatenated string.



            \note This function provides the strong exception-safety guarantee

        */

        template< typename SequenceSequenceT, typename Range1T, typename PredicateT>

        inline typename range_value<SequenceSequenceT>::type 

        join_if(

            const SequenceSequenceT& Input,

            const Range1T& Separator,

            PredicateT Pred)

        {

            // Define working types

            typedef typename range_value<SequenceSequenceT>::type ResultT;

            typedef typename range_const_iterator<SequenceSequenceT>::type InputIteratorT;



            // Parse input

            InputIteratorT itBegin=begin(Input);

            InputIteratorT itEnd=end(Input);



            // Construct container to hold the result

            ResultT Result;



            // Roll to the first element that will be added

            while(itBegin!=itEnd && !Pred(*itBegin)) ++itBegin;

            // Add this element

            if(itBegin!=itEnd)

            {

                detail::insert(Result, end(Result), *itBegin);

                ++itBegin;

            }



            for(;itBegin!=itEnd; ++itBegin)

            {

                if(Pred(*itBegin))

                {

                    // Add separator

                    detail::insert(Result, end(Result), as_literal(Separator));

                    // Add element

                    detail::insert(Result, end(Result), *itBegin);

                }

            }



            return Result;

        }



    } // namespace algorithm



    // pull names to the boost namespace

    using algorithm::join;

    using algorithm::join_if;



} // namespace boost





#endif  // BOOST_STRING_JOIN_HPP



