mirror of
https://github.com/bolero-MURAKAMI/Sprout.git
synced 2024-11-14 10:39:05 +00:00
500 lines
18 KiB
C++
500 lines
18 KiB
C++
/*=============================================================================
|
|
Copyright (c) 2011-2013 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 <type_traits>
|
|
#include <sprout/config.hpp>
|
|
#include <sprout/container/traits.hpp>
|
|
#include <sprout/container/functions.hpp>
|
|
#include <sprout/container/indexes.hpp>
|
|
#include <sprout/index_tuple/metafunction.hpp>
|
|
#include <sprout/pit/pit.hpp>
|
|
#include <sprout/iterator/type_traits/category.hpp>
|
|
#include <sprout/range/adaptor/size_enumed.hpp>
|
|
#include <sprout/range/algorithm/lower_bound.hpp>
|
|
#include <sprout/range/numeric/partial_sum.hpp>
|
|
#include <sprout/type_traits/is_c_str.hpp>
|
|
|
|
namespace sprout {
|
|
namespace algorithm {
|
|
namespace detail {
|
|
template<typename String, typename = void>
|
|
struct string_size;
|
|
template<typename String>
|
|
struct string_size<
|
|
String,
|
|
typename std::enable_if<sprout::is_c_str<String>::value>::type
|
|
>
|
|
: public std::integral_constant<
|
|
typename sprout::container_traits<String>::size_type,
|
|
sprout::container_traits<String>::static_size - 1
|
|
>
|
|
{};
|
|
template<typename String>
|
|
struct string_size<
|
|
String,
|
|
typename std::enable_if<!sprout::is_c_str<String>::value>::type
|
|
>
|
|
: public std::integral_constant<
|
|
typename sprout::container_traits<String>::size_type,
|
|
sprout::container_traits<String>::static_size
|
|
>
|
|
{};
|
|
|
|
template<typename String>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
sprout::is_c_str<String>::value,
|
|
typename sprout::container_traits<String>::difference_type
|
|
>::type
|
|
str_size(String const& str) {
|
|
return sprout::size(str) - 1;
|
|
}
|
|
template<typename String>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
!sprout::is_c_str<String>::value,
|
|
typename sprout::container_traits<String>::difference_type
|
|
>::type
|
|
str_size(String const& str) {
|
|
return sprout::size(str);
|
|
}
|
|
} // namespace detail
|
|
|
|
namespace result_of {
|
|
//
|
|
// join
|
|
//
|
|
template<typename ContainerContainer, typename Separator = void>
|
|
struct join
|
|
: public sprout::container_transform_traits<
|
|
typename sprout::container_traits<ContainerContainer>::value_type
|
|
>::template rebind_size<
|
|
sprout::container_traits<
|
|
typename sprout::container_traits<ContainerContainer>::value_type
|
|
>::static_size
|
|
? (sprout::container_traits<
|
|
typename sprout::container_traits<ContainerContainer>::value_type
|
|
>::static_size
|
|
+ sprout::algorithm::detail::string_size<Separator>::value
|
|
)
|
|
* sprout::container_traits<ContainerContainer>::static_size
|
|
- sprout::algorithm::detail::string_size<Separator>::value
|
|
: 0
|
|
>
|
|
{};
|
|
template<typename ContainerContainer>
|
|
struct join<ContainerContainer, void>
|
|
: public sprout::container_transform_traits<
|
|
typename sprout::container_traits<ContainerContainer>::value_type
|
|
>::template rebind_size<
|
|
sprout::container_traits<
|
|
typename sprout::container_traits<ContainerContainer>::value_type
|
|
>::static_size
|
|
* sprout::container_traits<ContainerContainer>::static_size
|
|
>
|
|
{};
|
|
} // namespace result_of
|
|
|
|
namespace detail {
|
|
template<typename Result, typename ContIterator, typename SizeIterator, typename Sizes>
|
|
inline SPROUT_CONSTEXPR typename sprout::container_traits<Result>::value_type
|
|
join_impl_ra_2(
|
|
ContIterator first_cont,
|
|
SizeIterator found,
|
|
Sizes const& sizes,
|
|
sprout::index_t idx
|
|
)
|
|
{
|
|
typedef typename sprout::container_traits<Result>::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<typename Result, typename ContIterator, sprout::index_t... Indexes, typename Sizes>
|
|
inline SPROUT_CONSTEXPR Result
|
|
join_impl_ra_1(
|
|
ContIterator first_cont,
|
|
sprout::index_tuple<Indexes...>,
|
|
Sizes const& sizes
|
|
)
|
|
{
|
|
return sprout::make<Result>(
|
|
sprout::algorithm::detail::join_impl_ra_2<Result>(
|
|
first_cont,
|
|
sprout::range::lower_bound(sizes, Indexes + 1),
|
|
sizes,
|
|
Indexes
|
|
)...
|
|
);
|
|
}
|
|
template<typename Result, typename ContainerContainer>
|
|
inline SPROUT_CONSTEXPR Result
|
|
join_impl_ra(ContainerContainer const& cont_cont) {
|
|
typedef typename sprout::container_traits<Result>::difference_type size_type;
|
|
typedef sprout::array<
|
|
size_type,
|
|
sprout::container_traits<ContainerContainer>::static_size
|
|
> sizes_type;
|
|
return sprout::algorithm::detail::join_impl_ra_1<Result>(
|
|
sprout::begin(cont_cont),
|
|
sprout::container_indexes<Result>::make(),
|
|
sprout::range::partial_sum(
|
|
cont_cont | sprout::adaptors::size_enumed,
|
|
sprout::pit<sizes_type>()
|
|
)
|
|
);
|
|
}
|
|
|
|
template<typename Result, typename ContIterator, typename... Args>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
sprout::container_traits<Result>::static_size == sizeof...(Args),
|
|
Result
|
|
>::type join_impl(
|
|
ContIterator first_cont, ContIterator last_cont,
|
|
Args const&... args
|
|
);
|
|
template<typename Result, typename ContIterator, typename... Args>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
sprout::container_traits<Result>::static_size != sizeof...(Args),
|
|
Result
|
|
>::type join_impl(
|
|
ContIterator first_cont, ContIterator last_cont,
|
|
Args const&... args
|
|
);
|
|
template<typename Result, typename ContIterator, typename InputIterator, typename... Args>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
sprout::container_traits<Result>::static_size == sizeof...(Args),
|
|
Result
|
|
>::type join_impl_1(
|
|
ContIterator, ContIterator,
|
|
InputIterator, InputIterator,
|
|
Args const&... args
|
|
)
|
|
{
|
|
return sprout::make<Result>(args...);
|
|
}
|
|
template<typename Result, typename ContIterator, typename InputIterator, typename... Args>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
sprout::container_traits<Result>::static_size != sizeof...(Args),
|
|
Result
|
|
>::type join_impl_1(
|
|
ContIterator first_cont, ContIterator last_cont,
|
|
InputIterator first, InputIterator last,
|
|
Args const&... args
|
|
)
|
|
{
|
|
return first != last
|
|
? sprout::algorithm::detail::join_impl_1<Result>(
|
|
first_cont, last_cont,
|
|
sprout::next(first), last,
|
|
args..., *first
|
|
)
|
|
: sprout::algorithm::detail::join_impl<Result>(sprout::next(first_cont), last_cont, args...)
|
|
;
|
|
}
|
|
template<typename Result, typename ContIterator, typename... Args>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
sprout::container_traits<Result>::static_size == sizeof...(Args),
|
|
Result
|
|
>::type join_impl(
|
|
ContIterator, ContIterator,
|
|
Args const&... args
|
|
)
|
|
{
|
|
return sprout::make<Result>(args...);
|
|
}
|
|
template<typename Result, typename ContIterator, typename... Args>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
sprout::container_traits<Result>::static_size != sizeof...(Args),
|
|
Result
|
|
>::type join_impl(
|
|
ContIterator first_cont, ContIterator last_cont,
|
|
Args const&... args
|
|
)
|
|
{
|
|
return first_cont != last_cont
|
|
? sprout::algorithm::detail::join_impl_1<Result>(
|
|
first_cont, last_cont,
|
|
sprout::begin(*first_cont), sprout::end(*first_cont),
|
|
args...
|
|
)
|
|
: sprout::make<Result>(args...)
|
|
;
|
|
}
|
|
|
|
template<typename ContainerContainer>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
sprout::is_random_access_iterator<
|
|
typename sprout::container_traits<ContainerContainer const>::iterator
|
|
>::value
|
|
&& sprout::is_random_access_iterator<
|
|
typename sprout::container_traits<
|
|
typename sprout::container_traits<ContainerContainer const>::value_type
|
|
>::iterator
|
|
>::value
|
|
,
|
|
typename sprout::algorithm::result_of::join<ContainerContainer>::type
|
|
>::type
|
|
join(ContainerContainer const& cont_cont) {
|
|
typedef typename sprout::algorithm::result_of::join<ContainerContainer>::type result_type;
|
|
return sprout::algorithm::detail::join_impl_ra<result_type>(cont_cont);
|
|
}
|
|
template<typename ContainerContainer>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<!(
|
|
sprout::is_random_access_iterator<
|
|
typename sprout::container_traits<ContainerContainer const>::iterator
|
|
>::value
|
|
&& sprout::is_random_access_iterator<
|
|
typename sprout::container_traits<
|
|
typename sprout::container_traits<ContainerContainer const>::value_type
|
|
>::iterator
|
|
>::value
|
|
),
|
|
typename sprout::algorithm::result_of::join<ContainerContainer>::type
|
|
>::type
|
|
join(ContainerContainer const& cont_cont) {
|
|
typedef typename sprout::algorithm::result_of::join<ContainerContainer>::type result_type;
|
|
return sprout::algorithm::detail::join_impl<result_type>(
|
|
sprout::begin(cont_cont),
|
|
sprout::end(cont_cont)
|
|
);
|
|
}
|
|
} // namespace detail
|
|
//
|
|
// join
|
|
//
|
|
template<typename ContainerContainer>
|
|
inline SPROUT_CONSTEXPR typename sprout::algorithm::result_of::join<ContainerContainer>::type
|
|
join(ContainerContainer const& cont_cont) {
|
|
return sprout::algorithm::detail::join(cont_cont);
|
|
}
|
|
|
|
namespace detail {
|
|
template<typename Result, typename ContIterator, typename SepIterator, typename SizeIterator, typename Sizes>
|
|
inline SPROUT_CONSTEXPR typename sprout::container_traits<Result>::value_type
|
|
join_impl_ra_2(
|
|
ContIterator first_cont, SepIterator first,
|
|
SizeIterator found,
|
|
Sizes const& sizes,
|
|
sprout::index_t idx
|
|
)
|
|
{
|
|
typedef typename sprout::container_traits<Result>::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<typename Result, typename ContIterator, typename SepIterator, sprout::index_t... Indexes, typename Sizes>
|
|
inline SPROUT_CONSTEXPR Result
|
|
join_impl_ra_1(
|
|
ContIterator first_cont,
|
|
SepIterator first,
|
|
sprout::index_tuple<Indexes...>,
|
|
Sizes const& sizes
|
|
)
|
|
{
|
|
return sprout::make<Result>(
|
|
sprout::algorithm::detail::join_impl_ra_2<Result>(
|
|
first_cont,
|
|
first,
|
|
sprout::range::lower_bound(sizes, Indexes + 1),
|
|
sizes,
|
|
Indexes
|
|
)...
|
|
);
|
|
}
|
|
template<typename Result, typename ContainerContainer, typename Separator>
|
|
inline SPROUT_CONSTEXPR Result
|
|
join_impl_ra(ContainerContainer const& cont_cont, Separator const& separator) {
|
|
typedef typename sprout::container_traits<Result>::difference_type size_type;
|
|
typedef sprout::array<
|
|
size_type,
|
|
sprout::container_traits<ContainerContainer>::static_size
|
|
? sprout::container_traits<ContainerContainer>::static_size * 2 - 1
|
|
: 0
|
|
> sizes_type;
|
|
return sprout::algorithm::detail::join_impl_ra_1<Result>(
|
|
sprout::begin(cont_cont),
|
|
sprout::begin(separator),
|
|
sprout::container_indexes<Result>::make(),
|
|
sprout::range::partial_sum(
|
|
cont_cont | sprout::adaptors::size_enumed(sprout::algorithm::detail::str_size(separator), true),
|
|
sprout::pit<sizes_type>()
|
|
)
|
|
);
|
|
}
|
|
|
|
template<typename Result, typename ContIterator, typename... Args>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
sprout::container_traits<Result>::static_size == sizeof...(Args),
|
|
Result
|
|
>::type join_impl(
|
|
ContIterator first_cont, ContIterator last_cont,
|
|
Args const&... args
|
|
);
|
|
template<typename Result, typename ContIterator, typename... Args>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
sprout::container_traits<Result>::static_size != sizeof...(Args),
|
|
Result
|
|
>::type join_impl(
|
|
ContIterator first_cont, ContIterator last_cont,
|
|
Args const&... args
|
|
);
|
|
template<typename Result, typename ContIterator, typename SepIterator, typename InputIterator, typename... Args>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
sprout::container_traits<Result>::static_size == sizeof...(Args),
|
|
Result
|
|
>::type join_impl_1(
|
|
ContIterator, ContIterator,
|
|
SepIterator, SepIterator,
|
|
bool,
|
|
InputIterator, InputIterator,
|
|
Args const&... args
|
|
)
|
|
{
|
|
return sprout::make<Result>(args...);
|
|
}
|
|
template<typename Result, typename ContIterator, typename SepIterator, typename InputIterator, typename... Args>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
sprout::container_traits<Result>::static_size != sizeof...(Args),
|
|
Result
|
|
>::type join_impl_1(
|
|
ContIterator first_cont, ContIterator last_cont,
|
|
SepIterator sep_first, SepIterator sep_last,
|
|
bool sep,
|
|
InputIterator first, InputIterator last,
|
|
Args const&... args
|
|
)
|
|
{
|
|
return first != last
|
|
? sprout::algorithm::detail::join_impl_1<Result>(
|
|
first_cont, last_cont,
|
|
sep_first, sep_last,
|
|
sep,
|
|
sprout::next(first), last,
|
|
args..., *first
|
|
)
|
|
: sep
|
|
? sprout::algorithm::detail::join_impl<Result>(
|
|
sprout::next(first_cont), last_cont,
|
|
sep_first, sep_last,
|
|
false,
|
|
args...
|
|
)
|
|
: sprout::algorithm::detail::join_impl<Result>(
|
|
first_cont, last_cont,
|
|
sep_first, sep_last,
|
|
true,
|
|
args...
|
|
)
|
|
;
|
|
}
|
|
template<typename Result, typename ContIterator, typename SepIterator, typename... Args>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
sprout::container_traits<Result>::static_size == sizeof...(Args),
|
|
Result
|
|
>::type join_impl(
|
|
ContIterator, ContIterator,
|
|
SepIterator, SepIterator,
|
|
bool,
|
|
Args const&... args
|
|
)
|
|
{
|
|
return sprout::make<Result>(args...);
|
|
}
|
|
template<typename Result, typename ContIterator, typename SepIterator, typename... Args>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
sprout::container_traits<Result>::static_size != sizeof...(Args),
|
|
Result
|
|
>::type join_impl(
|
|
ContIterator first_cont, ContIterator last_cont,
|
|
SepIterator sep_first, SepIterator sep_last,
|
|
bool sep,
|
|
Args const&... args
|
|
)
|
|
{
|
|
return first_cont != last_cont
|
|
? sep
|
|
? sprout::algorithm::detail::join_impl_1<Result>(
|
|
first_cont, last_cont,
|
|
sep_first, sep_last,
|
|
sep,
|
|
sep_first, sep_last,
|
|
args...
|
|
)
|
|
: sprout::algorithm::detail::join_impl_1<Result>(
|
|
first_cont, last_cont,
|
|
sep_first, sep_last,
|
|
sep,
|
|
sprout::begin(*first_cont), sprout::end(*first_cont),
|
|
args...
|
|
)
|
|
: sprout::make<Result>(args...)
|
|
;
|
|
}
|
|
|
|
template<typename ContainerContainer, typename Separator>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<
|
|
sprout::is_random_access_iterator<
|
|
typename sprout::container_traits<ContainerContainer const>::iterator
|
|
>::value
|
|
&& sprout::is_random_access_iterator<
|
|
typename sprout::container_traits<
|
|
typename sprout::container_traits<ContainerContainer const>::value_type
|
|
>::iterator
|
|
>::value
|
|
&& sprout::is_random_access_iterator<
|
|
typename sprout::container_traits<Separator const>::iterator
|
|
>::value
|
|
,
|
|
typename sprout::algorithm::result_of::join<ContainerContainer, Separator>::type
|
|
>::type
|
|
join(ContainerContainer const& cont_cont, Separator const& separator) {
|
|
typedef typename sprout::algorithm::result_of::join<ContainerContainer, Separator>::type result_type;
|
|
return sprout::algorithm::detail::join_impl_ra<result_type>(cont_cont, separator);
|
|
}
|
|
template<typename ContainerContainer, typename Separator>
|
|
inline SPROUT_CONSTEXPR typename std::enable_if<!(
|
|
sprout::is_random_access_iterator<
|
|
typename sprout::container_traits<ContainerContainer const>::iterator
|
|
>::value
|
|
&& sprout::is_random_access_iterator<
|
|
typename sprout::container_traits<
|
|
typename sprout::container_traits<ContainerContainer const>::value_type
|
|
>::iterator
|
|
>::value
|
|
&& sprout::is_random_access_iterator<
|
|
typename sprout::container_traits<Separator const>::iterator
|
|
>::value
|
|
),
|
|
typename sprout::algorithm::result_of::join<ContainerContainer, Separator>::type
|
|
>::type
|
|
join(ContainerContainer const& cont_cont, Separator const& separator) {
|
|
typedef typename sprout::algorithm::result_of::join<ContainerContainer, Separator>::type result_type;
|
|
return sprout::algorithm::detail::join_impl<result_type>(
|
|
sprout::begin(cont_cont),
|
|
sprout::end(cont_cont),
|
|
sprout::begin(separator),
|
|
sprout::end(separator),
|
|
false
|
|
);
|
|
}
|
|
} // namespace detail
|
|
//
|
|
// join
|
|
//
|
|
template<typename ContainerContainer, typename Separator>
|
|
inline SPROUT_CONSTEXPR typename sprout::algorithm::result_of::join<ContainerContainer, Separator>::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
|