First
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include "tl/iterator.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// adjacent_find()
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::adjacent_find()` function to
|
||||
// find equal adjacent elements within a container.
|
||||
template <typename Squence>
|
||||
auto adjacent_find(Squence& sequence) noexcept -> decltype(tl::begin(sequence));
|
||||
|
||||
// Overload of adjacent_find() for using a predicate evaluation other than `==` as
|
||||
// the function's test condition.
|
||||
template <typename Sequence, typename BinaryPredicate>
|
||||
auto adjacent_find(Sequence& sequence, BinaryPredicate&& p) noexcept -> decltype(tl::begin(sequence));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // end namespace tl
|
||||
|
||||
#include "tl/detail/algorithm/adjacent_find.inl"
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include "tl/algorithm.h"
|
||||
#include "tl/iterator.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename C, typename Pred>
|
||||
bool all_of(const C& c, Pred&& pred) noexcept
|
||||
{
|
||||
return eastl::all_of(tl::begin(c), tl::end(c), std::forward<Pred>(pred));
|
||||
}
|
||||
|
||||
template <typename C, typename Pred>
|
||||
bool any_of(const C& c, Pred&& pred) noexcept
|
||||
{
|
||||
return eastl::any_of(tl::begin(c), tl::end(c), std::forward<Pred>(pred));
|
||||
}
|
||||
|
||||
template <typename C, typename Pred>
|
||||
bool none_of(const C& c, Pred&& pred) noexcept
|
||||
{
|
||||
return eastl::none_of(tl::begin(c), tl::end(c), std::forward<Pred>(pred));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include "tl/type_traits.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <forward_list>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// associative containers (ordered & unordered) [maps, unordered_maps, multimaps, unordered_multimaps ...]
|
||||
template <typename SrcContainer, typename DstContainer>
|
||||
void append(std::true_type, DstContainer& dst, const SrcContainer& src) noexcept
|
||||
{
|
||||
dst.insert(std::begin(src), std::end(src));
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// sequence containers [vector, dequeue, forward_list, list, ...]
|
||||
template <typename SrcContainer, typename DstContainer>
|
||||
void append(std::false_type, DstContainer& dst, const SrcContainer& src) noexcept
|
||||
{
|
||||
dst.insert(std::end(dst), std::begin(src), std::end(src));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Obs: std::forward_list don't support fast traversal to the end
|
||||
// thus going to std::prev(std::end(dst)) must be done manually
|
||||
// Cost: O(N)
|
||||
template <typename T, typename SrcContainer>
|
||||
void append(std::false_type, std::forward_list<T>& dst, const SrcContainer& src) noexcept
|
||||
{
|
||||
auto before_end = dst.before_begin();
|
||||
for (auto& _ : dst)
|
||||
++before_end;
|
||||
|
||||
dst.insert_after(before_end, std::begin(src), std::end(src));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
} // namespace detail
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename SrcContainer, typename DstContainer>
|
||||
void append(DstContainer& dst, const SrcContainer& src) noexcept
|
||||
{
|
||||
detail::append(tl::is_associative_container<DstContainer>{}, dst, src);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include "tl/functional.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
namespace algorithm
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @brief Count the number of bit set for the given value.
|
||||
*/
|
||||
inline uint8_t bits_count(uint32_t i_value) noexcept
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return uint8_t(__popcnt(i_value));
|
||||
#elif defined(__clang__) || defined(__GNUC__)
|
||||
return uint8_t(__builtin_popcount(i_value));
|
||||
#else
|
||||
static_assert(!std::is_same_v<T, T>, "no-builtin function found for this compiler");
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @brief Count the number of bit set for the given value.
|
||||
*/
|
||||
inline uint64_t bits_count(uint64_t i_value) noexcept
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(TL_PLATFORM_64)
|
||||
return uint8_t(__popcnt64(i_value));
|
||||
#elif defined(TL_PLATFORM_32)
|
||||
return bits_count(uint32_t(i_value >> 32)) + bits_count(uint32_t(i_value & 0xffffffff));
|
||||
#else
|
||||
static_assert(!std::is_same_v<T, T>, "no-builtin function found for this compiler);");
|
||||
#endif // TL_PLATFORM_XX
|
||||
#elif defined(__clang__) || defined(__GNUC__)
|
||||
return uint8_t(__builtin_popcountl(i_value));
|
||||
#else
|
||||
static_assert(!std::is_same_v<T, T>, "no-builtin function found for this compiler");
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @brief Position of the top bit set to 1.
|
||||
* @param the given value
|
||||
* @return -1 in case value is 0 otherwise the position.
|
||||
*/
|
||||
inline int8_t top_bit(uint32_t i_value) noexcept
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
unsigned long index = 0;
|
||||
return _BitScanReverse(&index, (unsigned long)i_value) ? uint8_t(index) : -1;
|
||||
#elif defined(__clang__) || defined(__GNUC__)
|
||||
return i_value ? 31u - __builtin_clzl(i_value) : -1;
|
||||
#else
|
||||
static_assert(!std::is_same_v<T, T>, "no-builtin function found for this compiler);");
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @brief Position of the top bit set to 1.
|
||||
* @param the given value
|
||||
* @return -1 in case value is 0 otherwise the position.
|
||||
*/
|
||||
inline int8_t top_bit(uint64_t i_value) noexcept
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
unsigned long index = 0;
|
||||
#if defined(TL_PLATFORM_64)
|
||||
return _BitScanReverse64(&index, (unsigned long long)i_value) ? uint8_t(index) : -1;
|
||||
#elif defined(TL_PLATFORM_32)
|
||||
const int8_t position = top_bit(uint32_t(i_value >> 32));
|
||||
if (position > -1)
|
||||
{
|
||||
return position + 32;
|
||||
}
|
||||
|
||||
return top_bit(uint32_t(i_value & 0xffffffff));
|
||||
#else
|
||||
static_assert(!std::is_same_v<T, T>, "no-builtin function found for this compiler);");
|
||||
#endif // TL_PLATFORM_XX
|
||||
#elif defined(__clang__) || defined(__GNUC__)
|
||||
return i_value ? 63u - __builtin_clzll(i_value) : -1;
|
||||
#else
|
||||
static_assert(!std::is_same_v<T, T>, "no-builtin function found for this compiler);");
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace algorithm
|
||||
} // namespace tl
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
namespace algorithm
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T, typename... Comparators> struct chained_sorting_predicate;
|
||||
|
||||
template <typename T, typename... Comparators>
|
||||
chained_sorting_predicate<T, Comparators...> make_chained_sorting_predicate(const Comparators&... args) noexcept;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
|
||||
// see https://en.cppreference.com/w/cpp/algorithm
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Non-modifiying sequence operations (STL specializations)
|
||||
// -----------------------------------------------------------------------------
|
||||
#include "tl/algorithm/all_any_none_of.h"
|
||||
#include "tl/algorithm/for_each.h"
|
||||
#include "tl/algorithm/count.h"
|
||||
#include "tl/algorithm/mismatch.h"
|
||||
#include "tl/algorithm/find.h"
|
||||
#include "tl/algorithm/find_end.h"
|
||||
#include "tl/algorithm/find_first_of.h"
|
||||
#include "tl/algorithm/adjacent_find.h"
|
||||
#include "tl/algorithm/search.h"
|
||||
// -----------------------------------------------------------------------------
|
||||
// Non-modifiying sequence operations (our own versions)
|
||||
// -----------------------------------------------------------------------------
|
||||
#include "tl/algorithm/contains.h"
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Modifiying sequence operations
|
||||
// -----------------------------------------------------------------------------
|
||||
#include "tl/algorithm/copy.h"
|
||||
#include "tl/algorithm/remove.h"
|
||||
#include "tl/algorithm/unique.h"
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Modifiying sequence operations (our own versions)
|
||||
// -----------------------------------------------------------------------------
|
||||
#include "tl/algorithm/append.h"
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include "tl/algorithm/find.h"
|
||||
#include <iterator>
|
||||
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename C, typename T>
|
||||
bool contains(C& c, T&& value) noexcept
|
||||
{
|
||||
return tl::find(c, std::forward<T>(value)) != tl::end(c);
|
||||
}
|
||||
|
||||
template <typename C, typename T>
|
||||
bool contains(const C& c, T&& value) noexcept
|
||||
{
|
||||
return tl::cfind(c, std::forward<T>(value)) != tl::end(c);
|
||||
}
|
||||
|
||||
template <typename C, typename UnaryPredicate>
|
||||
bool contains_if(C& c, UnaryPredicate&& p) noexcept
|
||||
{
|
||||
return tl::find_if(c, std::forward<UnaryPredicate>(p)) != tl::end(c);
|
||||
}
|
||||
|
||||
template <typename C, typename UnaryPredicate>
|
||||
bool contains_if(const C& c, UnaryPredicate&& p) noexcept
|
||||
{
|
||||
return tl::cfind_if(c, std::forward<UnaryPredicate>(p)) != tl::end(c);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Container, typename OutputIt> auto copy(const Container& container, OutputIt d_first) noexcept -> OutputIt;
|
||||
template <typename Container, typename OutputIt, typename UnaryPredicate> auto copy_if(const Container& container, OutputIt d_first, const UnaryPredicate& predicate) noexcept -> OutputIt;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include "tl/iterator.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// count()
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::count()` function to
|
||||
// count values that match within a container
|
||||
template <typename C, typename T>
|
||||
auto count(const C& c, T&& value) noexcept -> typename std::iterator_traits<typename C::iterator>::difference_type;
|
||||
|
||||
// count_if()
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::count()` function to
|
||||
// count values that match within a container
|
||||
template <typename C, typename UnaryPredicate>
|
||||
auto count_if(const C& c, UnaryPredicate&& p) noexcept -> typename std::iterator_traits<typename C::iterator>::difference_type;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // end namespace tl
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include <tl/algorithm.h>
|
||||
#include <tl/utility.h>
|
||||
#include <tl/type_traits.h>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
// associative containers (ordered & unordered) [maps, unordered_maps, multimaps, unordered_multimaps ...]
|
||||
template <typename C, typename Key>
|
||||
auto find(std::true_type, C& c, const Key& key) noexcept -> decltype(c.begin())
|
||||
{
|
||||
return c.find(key);
|
||||
}
|
||||
|
||||
// sequence containers [array, vector, dequeue, forward_list, list, ...]
|
||||
template <typename C, typename T>
|
||||
auto find(std::false_type, C& c, const T& value) noexcept -> decltype(c.begin())
|
||||
{
|
||||
return eastl::find(tl::begin(c), tl::end(c), value);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename C, typename T>
|
||||
auto find(C& c, const T& value) noexcept -> decltype(c.begin())
|
||||
{
|
||||
return detail::find(is_associative_container<C>{}, c, value);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// associative containers (ordered & unordered) [maps, unordered_maps, multimaps, unordered_multimaps ...]
|
||||
template <typename C, typename Key>
|
||||
auto cfind(std::true_type, const C& c, const Key& key) noexcept -> decltype(c.cbegin())
|
||||
{
|
||||
return c.find(key);
|
||||
}
|
||||
|
||||
// sequence containers [array, vector, dequeue, forward_list, list, ...]
|
||||
template <typename C, typename T>
|
||||
auto cfind(std::false_type, const C& c, const T& value) noexcept -> decltype(c.cbegin())
|
||||
{
|
||||
return eastl::find(tl::cbegin(c), tl::cend(c), value);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
|
||||
template <typename C, typename T>
|
||||
auto cfind(const C& c, const T& value) noexcept -> decltype(c.cbegin())
|
||||
{
|
||||
return detail::cfind(is_associative_container<C>{}, c, value);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// associative containers (ordered) [maps, multimaps ...]
|
||||
template <typename C, typename Key>
|
||||
auto rfind(std::true_type, C& c, const Key& key) noexcept -> decltype(c.rbegin())
|
||||
{
|
||||
auto forward_iterator = c.find(key);
|
||||
return tl::make_reverse_iterator(forward_iterator);
|
||||
}
|
||||
|
||||
// sequence containers [array, vector, dequeue, list, ...]
|
||||
template <typename C, typename T>
|
||||
auto rfind(std::false_type, C& c, const T& value) noexcept -> decltype(c.rbegin())
|
||||
{
|
||||
return eastl::find(tl::rbegin(c), tl::rend(c), value);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <typename C, typename T>
|
||||
auto rfind(C& c, const T& value) noexcept -> decltype(c.rbegin())
|
||||
{
|
||||
return detail::rfind(is_associative_container<C>{}, c, value);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// associative containers (ordered) [maps, multimaps ...]
|
||||
template <typename C, typename Key>
|
||||
auto crfind(std::true_type, const C& c, const Key& key) noexcept -> decltype(c.crbegin())
|
||||
{
|
||||
auto forward_iterator = c.find(key);
|
||||
return tl::make_reverse_iterator(forward_iterator);
|
||||
}
|
||||
|
||||
// sequence containers [array, vector, dequeue, forward_list, list, ...]
|
||||
template <typename C, typename T>
|
||||
auto crfind(std::false_type, const C& c, const T& value) noexcept -> decltype(c.crbegin())
|
||||
{
|
||||
return eastl::find(tl::rbegin(c), tl::rend(c), value);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <typename C, typename T>
|
||||
auto crfind(const C& c, const T& value) noexcept -> decltype(c.crbegin())
|
||||
{
|
||||
return detail::rfind(is_associative_container<C>{}, c, value);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename C, typename UnaryPredicate>
|
||||
auto find_if(C& c, UnaryPredicate&& p) noexcept -> decltype(c.begin())
|
||||
{
|
||||
return eastl::find_if(tl::begin(c), tl::end(c), std::forward<UnaryPredicate>(p));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename C, typename UnaryPredicate>
|
||||
auto cfind_if(const C& c, UnaryPredicate&& p) noexcept -> decltype(c.cbegin())
|
||||
{
|
||||
return eastl::find_if(tl::cbegin(c), tl::cend(c), std::forward<UnaryPredicate>(p));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename C, typename UnaryPredicate>
|
||||
auto rfind_if(C& c, UnaryPredicate&& p) noexcept -> decltype(c.rbegin())
|
||||
{
|
||||
return eastl::find_if(tl::rbegin(c), tl::rend(c), std::forward<UnaryPredicate>(p));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename C, typename UnaryPredicate>
|
||||
auto crfind_if(const C& c, UnaryPredicate&& p) noexcept -> decltype(c.crbegin())
|
||||
{
|
||||
return eastl::find_if(tl::crbegin(c), tl::crend(c), std::forward<UnaryPredicate>(p));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename C, typename UnaryPredicate>
|
||||
auto find_if_not(C& c, UnaryPredicate&& q) noexcept -> decltype(tl::begin(c))
|
||||
{
|
||||
return eastl::find_if(tl::begin(c), tl::end(c), std::forward<UnaryPredicate>(q));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include "tl/iterator.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// find_end()
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::find_end()` function to
|
||||
// find the last subsequence within a container.
|
||||
template <typename SquenceA, typename SequenceB>
|
||||
auto find_end(SquenceA& sequence, SequenceB& subsequence) noexcept -> decltype(tl::begin(sequence));
|
||||
|
||||
// Overload of find_end() for using a predicate evaluation other than `==` as
|
||||
// the function's test condition.
|
||||
template <typename SequenceA, typename SequenceB, typename BinaryPredicate>
|
||||
auto find_end(SequenceA& sequence, SequenceB& subsequence, BinaryPredicate&& p) noexcept -> decltype(tl::begin(sequence));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // end namespace tl
|
||||
|
||||
#include "tl/detail/algorithm/find_end.inl"
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include "tl/iterator.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// find_first_of()
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::find_first_of()` function to
|
||||
// find the first elements in an ordered set within a container.
|
||||
template <typename SquenceA, typename SequenceB>
|
||||
auto find_first_of(SquenceA& sequence, SequenceB& subsequence) noexcept -> decltype(tl::begin(sequence));
|
||||
|
||||
// Overload of find_first_of() for using a predicate evaluation other than `==` as
|
||||
// the function's test condition.
|
||||
template <typename SequenceA, typename SequenceB, typename BinaryPredicate>
|
||||
auto find_first_of(SequenceA& sequence, SequenceB& subsequence, BinaryPredicate&& p) noexcept -> decltype(tl::begin(sequence));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // end namespace tl
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include "tl/type_traits.h"
|
||||
#include "tl/iterator.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// for_each()
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::for_each()` function to
|
||||
// apply a function to a container's elements.
|
||||
template <typename C, typename Function>
|
||||
decay_t<Function> for_each(C&& c, Function&& f) noexcept;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // end namespace tl
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include "tl/iterator.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// mismatch()
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::mismatch()` function to
|
||||
// return the first element where two ordered containers differ
|
||||
template <typename C1, typename C2>
|
||||
auto mismatch(C1& c1, C2& c2) noexcept -> std::pair<decltype(tl::begin(c1)), decltype(tl::begin(c2))>;
|
||||
|
||||
// Overload of mismatch() for using a predicate evaluation other than `==` as
|
||||
// the function's test condition.
|
||||
template <typename C1, typename C2, typename BinaryPredicate>
|
||||
auto mismatch(C1& c1, C2& c2, BinaryPredicate&& p) noexcept -> std::pair<decltype(tl::begin(c1)), decltype(tl::begin(c2))>;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // end namespace tl
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Container, typename OutputIt> auto move(Container& container, OutputIt d_first) noexcept -> OutputIt;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include "tl/algorithm.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Container, typename T>
|
||||
auto remove(Container& container, const T& value) noexcept -> decltype(container.begin())
|
||||
{
|
||||
return eastl::remove(container.begin(), container.end(), value);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Container, typename UnaryPredicate>
|
||||
auto remove_if(Container& container, const UnaryPredicate& predicate) noexcept -> decltype(container.begin())
|
||||
{
|
||||
return eastl::remove_if(container.begin(), container.end(), predicate);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Container, typename T>
|
||||
auto erase(Container& container, const T& value) noexcept -> decltype(container.begin())
|
||||
{
|
||||
return container.erase(remove(container, value), container.end());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Container, typename UnaryPredicate>
|
||||
auto erase_if(Container& container, const UnaryPredicate& predicate) noexcept -> decltype(container.begin())
|
||||
{
|
||||
return container.erase(remove_if(container, predicate), container.end());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include "tl/iterator.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// search()
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::search()` function to search
|
||||
// a container for a subsequence.
|
||||
template <typename Sequence1, typename Sequence2>
|
||||
auto search(Sequence1& sequence, Sequence2& subsequence) noexcept -> decltype(tl::begin(sequence));
|
||||
|
||||
// Overload of search() for using a predicate evaluation other than
|
||||
// `==` as the function's test condition.
|
||||
template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
|
||||
auto search(Sequence1& sequence, Sequence2& subsequence, BinaryPredicate&& pred) noexcept -> decltype(tl::begin(sequence));
|
||||
|
||||
// search_n()
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::search_n()` function to
|
||||
// search a container for the first sequence of N elements.
|
||||
template <typename Sequence, typename Size, typename T>
|
||||
auto search_n(Sequence& sequence, Size count, T&& value) noexcept -> decltype(tl::begin(sequence));
|
||||
|
||||
// Overload of search_n() for using a predicate evaluation other than
|
||||
// `==` as the function's test condition.
|
||||
template <typename Sequence, typename Size, typename T, typename BinaryPredicate>
|
||||
auto search_n(Sequence& sequence, Size count, T&& value, BinaryPredicate&& pred) noexcept -> decltype(tl::begin(sequence));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // end namespace tl
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include <EASTL/algorithm.h>
|
||||
#include <EASTL/sort.h>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Container>
|
||||
void sort(Container& container) noexcept
|
||||
{
|
||||
eastl::sort(container.begin(), container.end());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Container, typename Compare>
|
||||
void sort(Container& container, const Compare& compare) noexcept
|
||||
{
|
||||
eastl::sort(container.begin(), container.end(), compare);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Container>
|
||||
void stable_sort(Container& container) noexcept
|
||||
{
|
||||
eastl::stable_sort(container.begin(), container.end());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Container, typename Compare>
|
||||
void stable_sort(Container& container, const Compare& compare) noexcept
|
||||
{
|
||||
eastl::stable_sort(container.begin(), container.end(), compare);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
@@ -0,0 +1,622 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include "tl/functional.h"
|
||||
#include <EASTL/vector.h>
|
||||
#include <tl/fixed_vector.h>
|
||||
|
||||
#include "tl/string.h"
|
||||
#include "tl/optional.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
namespace algorithm
|
||||
{
|
||||
enum class empty_token_policy
|
||||
{
|
||||
discard,
|
||||
keep
|
||||
};
|
||||
|
||||
template <class DstContainer, class SrcContainer>
|
||||
DstContainer to_lower_ascii_copy(const SrcContainer& str) noexcept
|
||||
{
|
||||
if constexpr (tl::is_same_v<DstContainer, string>)
|
||||
{
|
||||
if (str.empty())
|
||||
return string();
|
||||
|
||||
const string::size_type s = str.size();
|
||||
fixed_vector<char, 512> b(s);
|
||||
char const* string = str.data();
|
||||
for (string::size_type i = 0; i < s; i++)
|
||||
b[i] = (char)ascii::tolower(string[i]);
|
||||
|
||||
return { b.data(), s };
|
||||
}
|
||||
else
|
||||
{
|
||||
DstContainer dst;
|
||||
dst.resize(str.size());
|
||||
eastl::transform(tl::begin(str), tl::end(str), tl::begin(dst), ascii::tolower);
|
||||
return dst;
|
||||
}}
|
||||
|
||||
template <class Container>
|
||||
Container to_lower_ascii_copy(const Container& str) noexcept
|
||||
{
|
||||
return to_lower_ascii_copy<Container, Container>(str);
|
||||
}
|
||||
|
||||
|
||||
template <class DstContainer, class SrcContainer>
|
||||
DstContainer to_upper_ascii_copy(const SrcContainer& str) noexcept
|
||||
{
|
||||
if constexpr (tl::is_same_v<DstContainer, string>)
|
||||
{
|
||||
if (str.empty())
|
||||
return string();
|
||||
|
||||
const string::size_type s = str.size();
|
||||
fixed_vector<char, 512> b(s);
|
||||
char const* string = str.data();
|
||||
for (string::size_type i = 0; i < s; i++)
|
||||
b[i] = (char)ascii::toupper(string[i]);
|
||||
|
||||
return { b.data(), s };
|
||||
}
|
||||
else
|
||||
{
|
||||
DstContainer dst;
|
||||
dst.resize(str.size());
|
||||
eastl::transform(tl::begin(str), tl::end(str), tl::begin(dst), ascii::toupper);
|
||||
return dst;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
Container to_upper_ascii_copy(const Container& str) noexcept
|
||||
{
|
||||
return to_upper_ascii_copy<Container, Container>(str);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
void to_lower_ascii(Container& str) noexcept
|
||||
{
|
||||
eastl::transform(tl::begin(str), tl::end(str), tl::begin(str), ascii::tolower);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void to_lower_ascii(string& str) noexcept
|
||||
{
|
||||
str = to_lower_ascii_copy(str);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
void to_upper_ascii(Container& str) noexcept
|
||||
{
|
||||
eastl::transform(tl::begin(str), tl::end(str), tl::begin(str), ascii::toupper);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void to_upper_ascii(string& str) noexcept
|
||||
{
|
||||
str = to_upper_ascii_copy(str);
|
||||
}
|
||||
|
||||
template <class String>
|
||||
tl::vector<String> split_on_any(const String& str, const char* separators, empty_token_policy token_policy = empty_token_policy::discard) noexcept
|
||||
{
|
||||
return split_on_any(str, String(separators), token_policy);
|
||||
}
|
||||
|
||||
template <class String, class Delim>
|
||||
tl::vector<String> split_on_any(const String& str, const Delim& separators, empty_token_policy token_policy = empty_token_policy::discard) noexcept
|
||||
{
|
||||
tl::vector<String> dst;
|
||||
dst.reserve(32);
|
||||
split_on_any(str,
|
||||
separators,
|
||||
[&dst](const String& token)
|
||||
{
|
||||
dst.push_back(token);
|
||||
},
|
||||
token_policy);
|
||||
return dst;
|
||||
}
|
||||
|
||||
template <class String, class Delim>
|
||||
tl::vector<String> split_on_all(const String& str, const Delim& separator, empty_token_policy token_policy = empty_token_policy::discard) noexcept
|
||||
{
|
||||
tl::vector<String> dst;
|
||||
dst.reserve(32);
|
||||
split_on_all(str,
|
||||
separator,
|
||||
[&dst](const String& token)
|
||||
{
|
||||
dst.push_back(token);
|
||||
},
|
||||
token_policy);
|
||||
return dst;
|
||||
}
|
||||
|
||||
template <class String, class Func>
|
||||
void split_on_any(const String& str, const char* delimiters, const Func& functor, empty_token_policy token_policy = empty_token_policy::discard) noexcept
|
||||
{
|
||||
return split_on_any(str, String(delimiters), functor, token_policy);
|
||||
}
|
||||
|
||||
template <class String, class Func>
|
||||
void split_on_any(const String& str, char delimiter, const Func& functor, empty_token_policy token_policy = empty_token_policy::discard) noexcept
|
||||
{
|
||||
String token;
|
||||
const char* cstr = str.data();
|
||||
size_t offset = 0;
|
||||
const size_t endOffset = str.size();
|
||||
while (offset <= endOffset)
|
||||
{
|
||||
const char* nextCstr = static_cast<const char*>(::memchr(cstr + offset, delimiter, endOffset - offset));
|
||||
const size_t nextOffset = nextCstr ? nextCstr - cstr : endOffset;
|
||||
|
||||
if (offset < nextOffset || token_policy == empty_token_policy::keep)
|
||||
{
|
||||
token.clear();
|
||||
token.append(cstr + offset, cstr + nextOffset);
|
||||
functor(token);
|
||||
}
|
||||
offset = nextOffset + 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class String, class Delim, class Func>
|
||||
void split_on_any(const String& str, const Delim& delimiters, const Func& functor, empty_token_policy token_policy = empty_token_policy::discard) noexcept
|
||||
{
|
||||
const size_t k_delims_size = delimiters.size();
|
||||
if (k_delims_size == 1)
|
||||
return split_on_any(str, delimiters[0], functor, token_policy);
|
||||
|
||||
if (k_delims_size == 0)
|
||||
{
|
||||
TL_PLAIN_FAIL("'delimiters' cannot be empty");
|
||||
return;
|
||||
}
|
||||
|
||||
String token;
|
||||
const char* cstr = str.data();
|
||||
const char* delimsStr = delimiters.data();
|
||||
size_t offset = 0;
|
||||
const size_t endOffset = str.size();
|
||||
while (offset <= endOffset)
|
||||
{
|
||||
size_t nextOffset = offset;
|
||||
for (; nextOffset < endOffset; ++nextOffset)
|
||||
{
|
||||
if (::memchr(delimsStr, cstr[nextOffset], k_delims_size) != nullptr)
|
||||
break;
|
||||
}
|
||||
|
||||
if (offset < nextOffset || token_policy == empty_token_policy::keep)
|
||||
{
|
||||
token.clear();
|
||||
token.append(cstr + offset, cstr + nextOffset);
|
||||
functor(token);
|
||||
}
|
||||
offset = nextOffset + 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class String, class Delim, class Func>
|
||||
void split_on_all(const String& str, const Delim& sep, const Func& functor, empty_token_policy token_policy = empty_token_policy::discard) noexcept
|
||||
{
|
||||
String separator(sep);
|
||||
if (separator.empty())
|
||||
{
|
||||
TL_PLAIN_FAIL("'delimiters' cannot be empty");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t p0 = 0;
|
||||
size_t p1 = 0;
|
||||
String token;
|
||||
while ((p1 = str.find(separator, p0)) != String::npos)
|
||||
{
|
||||
if (p1 > p0)
|
||||
{
|
||||
token.clear();
|
||||
token.append(str, p0, p1 - p0);
|
||||
functor(token);
|
||||
}
|
||||
else if (token_policy == empty_token_policy::keep)
|
||||
functor(String{});
|
||||
|
||||
p0 = p1 + separator.size();
|
||||
}
|
||||
|
||||
if (str.size() > p0)
|
||||
{
|
||||
token.clear();
|
||||
token.append(str, p0, String::npos);
|
||||
functor(token);
|
||||
}
|
||||
else if (token_policy == empty_token_policy::keep)
|
||||
functor(String{});
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String left(const String& text, size_t length) noexcept
|
||||
{
|
||||
size_t textSize = text.size();
|
||||
return text.substr(0, length > textSize ? textSize : length);
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String right(const String& text, size_t length) noexcept
|
||||
{
|
||||
const size_t textSize = text.size();
|
||||
size_t startPos = textSize >= length ? textSize - length : 0;
|
||||
return text.substr(startPos);
|
||||
}
|
||||
|
||||
template <class String>
|
||||
bool starts_with(const String& text, const String& prefix) noexcept
|
||||
{
|
||||
const size_t textSize = text.size();
|
||||
const size_t prefixSize = prefix.size();
|
||||
if (textSize < prefixSize)
|
||||
return false;
|
||||
|
||||
return memcmp(text.data(), prefix.data(), prefixSize) == 0;
|
||||
}
|
||||
|
||||
template <class String>
|
||||
bool starts_with_ci(const String& text, const String& prefix) noexcept
|
||||
{
|
||||
const size_t textSize = text.size();
|
||||
const size_t prefixSize = prefix.size();
|
||||
if (textSize < prefixSize)
|
||||
return false;
|
||||
|
||||
return ascii::memicmp(text.data(), prefix.data(), prefixSize) == 0;
|
||||
}
|
||||
|
||||
template <class String>
|
||||
bool ends_with(const String& text, const String& suffix) noexcept
|
||||
{
|
||||
const size_t textSize = text.size();
|
||||
const size_t suffixSize = suffix.size();
|
||||
if (textSize < suffixSize)
|
||||
return false;
|
||||
|
||||
return memcmp(text.data() + (textSize - suffixSize), suffix.data(), suffixSize) == 0;
|
||||
}
|
||||
|
||||
template <class String>
|
||||
bool ends_with_ci(const String& text, const String& suffix) noexcept
|
||||
{
|
||||
const size_t textSize = text.size();
|
||||
const size_t suffixSize = suffix.size();
|
||||
if (textSize < suffixSize)
|
||||
return false;
|
||||
|
||||
return ascii::memicmp(text.data() + (textSize - suffixSize), suffix.data(), suffixSize) == 0;
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String remove_prefix(const String& text, const String& prefix) noexcept
|
||||
{
|
||||
if (starts_with(text, prefix))
|
||||
return text.substr(prefix.size(), text.size() - prefix.size());
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String remove_prefix_ci(const String& text, const String& prefix) noexcept
|
||||
{
|
||||
if (starts_with_ci(text, prefix))
|
||||
return text.substr(prefix.size(), text.size() - prefix.size());
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String remove_suffix(const String& text, const String& suffix) noexcept
|
||||
{
|
||||
if (ends_with(text, suffix))
|
||||
return text.substr(0, text.size() - suffix.size());
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String remove_suffix_ci(const String& text, const String& suffix) noexcept
|
||||
{
|
||||
if (ends_with_ci(text, suffix))
|
||||
return text.substr(0, text.size() - suffix.size());
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
template <class String>
|
||||
eastl::optional<size_t> contains(const String& text, const String& subText) noexcept
|
||||
{
|
||||
const size_t offset = text.find(subText);
|
||||
if (offset != String::npos)
|
||||
return offset;
|
||||
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
template <class String>
|
||||
eastl::optional<size_t> contains_ci(const String& text, const String& subText) noexcept
|
||||
{
|
||||
const size_t offset = text.find_ci(subText);
|
||||
if (offset != String::npos)
|
||||
return offset;
|
||||
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String quote(const String& text, const String& quote) noexcept
|
||||
{
|
||||
String result = quote;
|
||||
result += text;
|
||||
result += quote;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String unquote(const String& text, const String& quote) noexcept
|
||||
{
|
||||
if (starts_with(text, quote) && ends_with(text, quote) && text.size() >= quote.size() * 2)
|
||||
return text.substr(quote.size(), text.size() - quote.size() * 2);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
static const char* s_defaultWhiteSpaceCStr = " \t\f\v\n\r";
|
||||
|
||||
template <class String>
|
||||
String trim_left_any_of(const String& text, const String& characters) noexcept
|
||||
{
|
||||
const typename String::size_type startPos = text.find_first_not_of(characters);
|
||||
if (startPos == String::npos)
|
||||
return String();
|
||||
|
||||
return text.substr(startPos);
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String trim_left_any_of_ci(const String& text, const String& characters) noexcept
|
||||
{
|
||||
const typename String::size_type startPos = text.find_first_not_of_ci(characters);
|
||||
if (startPos == String::npos)
|
||||
return String();
|
||||
|
||||
return text.substr(startPos);
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String trim_left(const String& text) noexcept
|
||||
{
|
||||
static String s_defaultWhiteSpace(s_defaultWhiteSpaceCStr);
|
||||
return trim_left_any_of(text, s_defaultWhiteSpace);
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String trim_left_ci(const String& text) noexcept
|
||||
{
|
||||
static String s_defaultWhiteSpace(s_defaultWhiteSpaceCStr);
|
||||
return trim_left_any_of_ci(text, s_defaultWhiteSpace);
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String trim_right_any_of(const String& text, const String& characters) noexcept
|
||||
{
|
||||
const typename String::size_type startPos = text.find_last_not_of(characters);
|
||||
if (startPos == String::npos)
|
||||
return String();
|
||||
|
||||
return text.substr(0, startPos + 1);
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String trim_right_any_of_ci(const String& text, const String& characters) noexcept
|
||||
{
|
||||
const typename String::size_type startPos = text.find_last_not_of_ci(characters);
|
||||
if (startPos == String::npos)
|
||||
return String();
|
||||
|
||||
return text.substr(0, startPos + 1);
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String trim_right(const String& text) noexcept
|
||||
{
|
||||
static String s_defaultWhiteSpace(s_defaultWhiteSpaceCStr);
|
||||
return trim_right_any_of(text, String(s_defaultWhiteSpace));
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String trim_right_ci(const String& text) noexcept
|
||||
{
|
||||
static String s_defaultWhiteSpace(s_defaultWhiteSpaceCStr);
|
||||
return trim_right_any_of_ci(text, String(s_defaultWhiteSpace));
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String trim(const String& text) noexcept
|
||||
{
|
||||
return trim_right(trim_left(text));
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String trim_ci(const String& text) noexcept
|
||||
{
|
||||
return trim_right_ci(trim_left_ci(text));
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String trim_any_of(const String& text, const String& characters) noexcept
|
||||
{
|
||||
return trim_right_any_of(trim_left_any_of(text, characters), characters);
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String trim_any_of_ci(const String& text, const String& characters) noexcept
|
||||
{
|
||||
return trim_right_any_of_ci(trim_left_any_of_ci(text, characters), characters);
|
||||
}
|
||||
|
||||
template <class String, class RepString>
|
||||
String replace(const String& text, const String& target, const function<eastl::optional<RepString>(size_t, size_t)>& functor) noexcept
|
||||
{
|
||||
if (target.empty())
|
||||
return text;
|
||||
|
||||
eastl::fixed_vector<size_t, 512> positions;
|
||||
|
||||
size_t position = 0;
|
||||
while ((position = text.find(target, position)) != String::npos)
|
||||
{
|
||||
positions.push_back(position);
|
||||
position += target.length();
|
||||
}
|
||||
|
||||
String result;
|
||||
result.reserve(text.size());
|
||||
|
||||
auto start = text.begin();
|
||||
for (auto it = positions.begin(); it != positions.end(); ++it)
|
||||
{
|
||||
const size_t position = *it;
|
||||
size_t index = eastl::distance(positions.begin(), it);
|
||||
|
||||
eastl::optional<RepString> replacementString = functor(index, positions.size());
|
||||
if (!replacementString)
|
||||
continue;
|
||||
|
||||
auto end = text.begin() + position;
|
||||
result.append(start, end); //copy up to the result
|
||||
result.append(*replacementString);
|
||||
start = end + target.size();
|
||||
}
|
||||
|
||||
if (start != text.end())
|
||||
result.append(start, text.end()); //copy the end run
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class String, typename Fun>
|
||||
String replace(const String& text, const String& target, Fun f) noexcept
|
||||
{
|
||||
return replace(text, target, function<eastl::optional<String>(size_t, size_t)>(f));
|
||||
}
|
||||
|
||||
template <class Func>
|
||||
size_t replace_first(const string& text, const string& target, const string& replacement, size_t startingOffset, const Func& functor) noexcept
|
||||
{
|
||||
if (target.empty())
|
||||
{
|
||||
functor(text);
|
||||
return string::npos;
|
||||
}
|
||||
|
||||
const size_t startPos = text.find(target, startingOffset);
|
||||
if (startPos == string::npos)
|
||||
{
|
||||
functor(text);
|
||||
return string::npos;
|
||||
}
|
||||
|
||||
eastl::string result(text.eastl_str());
|
||||
string res2(result.replace(startPos, target.length(), eastl::string(replacement.eastl_str())));
|
||||
|
||||
functor(res2);
|
||||
return startPos + replacement.length();
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class Container, class String>
|
||||
String join_worker(const Container& container, const String& delimiter) noexcept
|
||||
{
|
||||
String dst;
|
||||
//reserve some space based on some heuristics:
|
||||
// We'll have size - 1 delimiters
|
||||
// And an average string size of 2 chars. The small choice is made to help with the small string case only where the allocator overhead is significant.
|
||||
dst.reserve((delimiter.size() + 2) * container.size());
|
||||
|
||||
auto end = std::end(container);
|
||||
auto it = std::begin(container);
|
||||
while (true)
|
||||
{
|
||||
dst += *it;
|
||||
++it;
|
||||
if (it == end)
|
||||
break;
|
||||
|
||||
dst += delimiter;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
string join_worker(const Container& container, const string& delimiter) noexcept
|
||||
{
|
||||
eastl::string buffer;
|
||||
//reserve some space based on some heuristics:
|
||||
// We'll have size - 1 delimiters
|
||||
// And an average string size of 2 chars. The small choice is made to help with the small string case only where the allocator overhead is significant.
|
||||
buffer.reserve((delimiter.size() + 2) * container.size());
|
||||
|
||||
auto end = std::end(container);
|
||||
auto it = std::begin(container);
|
||||
while (true)
|
||||
{
|
||||
const string& s = *it;
|
||||
buffer.append(s.data(), s.size());
|
||||
++it;
|
||||
if (it == end)
|
||||
break;
|
||||
|
||||
buffer.append(delimiter.data(), delimiter.size());
|
||||
}
|
||||
return string(buffer);
|
||||
}
|
||||
|
||||
//joiner used when the Delim and String are of the same type
|
||||
template <class Container, class Delim, class String>
|
||||
std::enable_if_t<
|
||||
std::is_same_v<
|
||||
std::remove_const_t<std::remove_reference_t<String>>,
|
||||
std::remove_const_t<std::remove_reference_t<Delim>>>,
|
||||
String> join(const Container& container, const Delim& delimiter) noexcept
|
||||
{
|
||||
return join_worker(container, delimiter);
|
||||
}
|
||||
|
||||
//joiner used when the Delim and String are different types
|
||||
template <class Container, class Delim, class String>
|
||||
std::enable_if_t<
|
||||
!std::is_same_v<
|
||||
std::remove_const_t<std::remove_reference_t<String>>,
|
||||
std::remove_const_t<std::remove_reference_t<Delim>>>,
|
||||
String> join(const Container& container, const Delim& delimiter) noexcept
|
||||
{
|
||||
return join_worker(container, String(delimiter));
|
||||
}
|
||||
} //namespace detail
|
||||
|
||||
template <class Container, class Delim, class String>
|
||||
String join(const Container& container, const Delim& delimiter) noexcept
|
||||
{
|
||||
if (container.empty())
|
||||
return String();
|
||||
|
||||
return detail::join<Container, Delim, String>(container, delimiter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/detail/prologue.h"
|
||||
#include <EASTL/algorithm.h>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Container>
|
||||
auto unique(Container& container) noexcept -> decltype(container.begin())
|
||||
{
|
||||
return eastl::unique(container.begin(), container.end());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Container, typename BinaryPredicate>
|
||||
auto unique(Container& container, const BinaryPredicate& predicate) noexcept -> decltype(container.begin())
|
||||
{
|
||||
return eastl::unique(container.begin(), container.end(), predicate);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
Reference in New Issue
Block a user