/*============================================================================= Copyright (c) 2011-2019 Bolero MURAKAMI https://github.com/bolero-MURAKAMI/Sprout 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) =============================================================================*/ #ifndef SPROUT_ALGORITHM_STRING_JOIN_HPP #define SPROUT_ALGORITHM_STRING_JOIN_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include namespace sprout { namespace algorithm { namespace detail { template struct string_size; template struct string_size< String, typename std::enable_if::value>::type > : public sprout::integral_constant< typename sprout::container_traits::size_type, sprout::container_traits::static_size - 1 > {}; template struct string_size< String, typename std::enable_if::value>::type > : public sprout::integral_constant< typename sprout::container_traits::size_type, sprout::container_traits::static_size > {}; template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::is_c_str::value, typename sprout::container_traits::difference_type >::type str_size(String const& str) { return sprout::size(str) - 1; } template inline SPROUT_CONSTEXPR typename std::enable_if< !sprout::is_c_str::value, typename sprout::container_traits::difference_type >::type str_size(String const& str) { return sprout::size(str); } } // namespace detail namespace results { // // join // template struct join : public sprout::container_transform_traits< typename sprout::container_traits::value_type >::template rebind_size< sprout::container_traits< typename sprout::container_traits::value_type >::static_size ? (sprout::container_traits< typename sprout::container_traits::value_type >::static_size + sprout::algorithm::detail::string_size::value ) * sprout::container_traits::static_size - sprout::algorithm::detail::string_size::value : 0 > {}; template struct join : public sprout::container_transform_traits< typename sprout::container_traits::value_type >::template rebind_size< sprout::container_traits< typename sprout::container_traits::value_type >::static_size * sprout::container_traits::static_size > {}; } // namespace results namespace detail { template inline SPROUT_CONSTEXPR typename sprout::container_traits::value_type join_impl_ra_2( ContIterator const& first_cont, SizeIterator const& found, Sizes const& sizes, sprout::index_t idx ) { typedef typename sprout::container_traits::value_type value_type; return found == sizes.end() ? value_type() : sprout::begin(first_cont[found - sizes.begin()])[idx - (found != sizes.begin() ? found[-1] : 0)] ; } template inline SPROUT_CONSTEXPR Result join_impl_ra_1( ContIterator const& first_cont, sprout::index_tuple, Sizes const& sizes ) { return sprout::make( sprout::algorithm::detail::join_impl_ra_2( first_cont, sprout::range::lower_bound(sizes, Indexes + 1), sizes, Indexes )... ); } template inline SPROUT_CONSTEXPR Result join_impl_ra(ContainerContainer const& cont_cont) { typedef typename sprout::container_traits::difference_type size_type; typedef sprout::array< size_type, sprout::container_traits::static_size > sizes_type; return sprout::algorithm::detail::join_impl_ra_1( sprout::begin(cont_cont), sprout::container_indexes::make(), sprout::range::fixed::partial_sum( cont_cont | sprout::adaptors::size_enumed, sprout::pit() ) ); } template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::container_traits::static_size == sizeof...(Args), Result >::type join_impl( ContIterator const& first_cont, ContIterator const& last_cont, Args const&... args ); template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::container_traits::static_size != sizeof...(Args), Result >::type join_impl( ContIterator const& first_cont, ContIterator const& last_cont, Args const&... args ); template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::container_traits::static_size == sizeof...(Args), Result >::type join_impl_1( ContIterator, ContIterator, InputIterator const&, InputIterator const&, Args const&... args ) { return sprout::make(args...); } template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::container_traits::static_size != sizeof...(Args), Result >::type join_impl_1( ContIterator const& first_cont, ContIterator const& last_cont, InputIterator const& first, InputIterator const& last, Args const&... args ) { return first != last ? sprout::algorithm::detail::join_impl_1( first_cont, last_cont, sprout::next(first), last, args..., *first ) : sprout::algorithm::detail::join_impl(sprout::next(first_cont), last_cont, args...) ; } template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::container_traits::static_size == sizeof...(Args), Result >::type join_impl( ContIterator, ContIterator, Args const&... args ) { return sprout::make(args...); } template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::container_traits::static_size != sizeof...(Args), Result >::type join_impl( ContIterator const& first_cont, ContIterator const& last_cont, Args const&... args ) { return first_cont != last_cont ? sprout::algorithm::detail::join_impl_1( first_cont, last_cont, sprout::begin(*first_cont), sprout::end(*first_cont), args... ) : sprout::make(args...) ; } template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::is_random_access_iterator< typename sprout::container_traits::iterator >::value && sprout::is_random_access_iterator< typename sprout::container_traits< typename sprout::container_traits::value_type >::iterator >::value , typename sprout::algorithm::results::join::type >::type join(ContainerContainer const& cont_cont) { typedef typename sprout::algorithm::results::join::type result_type; return sprout::algorithm::detail::join_impl_ra(cont_cont); } template inline SPROUT_CONSTEXPR typename std::enable_if::iterator >::value && sprout::is_random_access_iterator< typename sprout::container_traits< typename sprout::container_traits::value_type >::iterator >::value ), typename sprout::algorithm::results::join::type >::type join(ContainerContainer const& cont_cont) { typedef typename sprout::algorithm::results::join::type result_type; return sprout::algorithm::detail::join_impl( sprout::begin(cont_cont), sprout::end(cont_cont) ); } } // namespace detail // // join // template inline SPROUT_CONSTEXPR typename sprout::algorithm::results::join::type join(ContainerContainer const& cont_cont) { return sprout::algorithm::detail::join(cont_cont); } namespace detail { template inline SPROUT_CONSTEXPR typename sprout::container_traits::value_type join_impl_ra_2( ContIterator const& first_cont, SepIterator const& first, SizeIterator const& found, Sizes const& sizes, sprout::index_t idx ) { typedef typename sprout::container_traits::value_type value_type; return found == sizes.end() ? value_type() : (found - sizes.begin()) % 2 ? first[idx - found[-1]] : sprout::begin(first_cont[(found - sizes.begin()) / 2])[idx - (found != sizes.begin() ? found[-1] : 0)] ; } template inline SPROUT_CONSTEXPR Result join_impl_ra_1( ContIterator const& first_cont, SepIterator const& first, sprout::index_tuple, Sizes const& sizes ) { return sprout::make( sprout::algorithm::detail::join_impl_ra_2( first_cont, first, sprout::range::lower_bound(sizes, Indexes + 1), sizes, Indexes )... ); } template inline SPROUT_CONSTEXPR Result join_impl_ra(ContainerContainer const& cont_cont, Separator const& separator) { typedef typename sprout::container_traits::difference_type size_type; typedef sprout::array< size_type, sprout::container_traits::static_size ? sprout::container_traits::static_size * 2 - 1 : 0 > sizes_type; return sprout::algorithm::detail::join_impl_ra_1( sprout::begin(cont_cont), sprout::begin(separator), sprout::container_indexes::make(), sprout::range::fixed::partial_sum( cont_cont | sprout::adaptors::size_enumed(sprout::algorithm::detail::str_size(separator), true), sprout::pit() ) ); } template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::container_traits::static_size == sizeof...(Args), Result >::type join_impl( ContIterator const& first_cont, ContIterator const& last_cont, Args const&... args ); template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::container_traits::static_size != sizeof...(Args), Result >::type join_impl( ContIterator const& first_cont, ContIterator const& last_cont, Args const&... args ); template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::container_traits::static_size == sizeof...(Args), Result >::type join_impl_1( ContIterator, ContIterator, SepIterator, SepIterator, bool, InputIterator const&, InputIterator const&, Args const&... args ) { return sprout::make(args...); } template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::container_traits::static_size != sizeof...(Args), Result >::type join_impl_1( ContIterator const& first_cont, ContIterator const& last_cont, SepIterator const& sep_first, SepIterator const& sep_last, bool sep, InputIterator const& first, InputIterator const& last, Args const&... args ) { return first != last ? sprout::algorithm::detail::join_impl_1( first_cont, last_cont, sep_first, sep_last, sep, sprout::next(first), last, args..., *first ) : sep ? sprout::algorithm::detail::join_impl( sprout::next(first_cont), last_cont, sep_first, sep_last, false, args... ) : sprout::algorithm::detail::join_impl( first_cont, last_cont, sep_first, sep_last, true, args... ) ; } template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::container_traits::static_size == sizeof...(Args), Result >::type join_impl( ContIterator, ContIterator, SepIterator, SepIterator, bool, Args const&... args ) { return sprout::make(args...); } template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::container_traits::static_size != sizeof...(Args), Result >::type join_impl( ContIterator const& first_cont, ContIterator const& last_cont, SepIterator const& sep_first, SepIterator const& sep_last, bool sep, Args const&... args ) { return first_cont != last_cont ? sep ? sprout::algorithm::detail::join_impl_1( first_cont, last_cont, sep_first, sep_last, sep, sep_first, sep_last, args... ) : sprout::algorithm::detail::join_impl_1( first_cont, last_cont, sep_first, sep_last, sep, sprout::begin(*first_cont), sprout::end(*first_cont), args... ) : sprout::make(args...) ; } template inline SPROUT_CONSTEXPR typename std::enable_if< sprout::is_random_access_iterator< typename sprout::container_traits::iterator >::value && sprout::is_random_access_iterator< typename sprout::container_traits< typename sprout::container_traits::value_type >::iterator >::value && sprout::is_random_access_iterator< typename sprout::container_traits::iterator >::value , typename sprout::algorithm::results::join::type >::type join(ContainerContainer const& cont_cont, Separator const& separator) { typedef typename sprout::algorithm::results::join::type result_type; return sprout::algorithm::detail::join_impl_ra(cont_cont, separator); } template inline SPROUT_CONSTEXPR typename std::enable_if::iterator >::value && sprout::is_random_access_iterator< typename sprout::container_traits< typename sprout::container_traits::value_type >::iterator >::value && sprout::is_random_access_iterator< typename sprout::container_traits::iterator >::value ), typename sprout::algorithm::results::join::type >::type join(ContainerContainer const& cont_cont, Separator const& separator) { typedef typename sprout::algorithm::results::join::type result_type; return sprout::algorithm::detail::join_impl( sprout::begin(cont_cont), sprout::end(cont_cont), sprout::begin(separator), sprout::end(separator), false ); } } // namespace detail // // join // template inline SPROUT_CONSTEXPR typename sprout::algorithm::results::join::type join(ContainerContainer const& cont_cont, Separator const& separator) { return sprout::algorithm::detail::join(cont_cont, separator); } } // namespace algorithm } // namespace sprout #endif // #ifndef SPROUT_ALGORITHM_STRING_JOIN_HPP