609 lines
14 KiB
C++
609 lines
14 KiB
C++
/***
|
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: auContainerUtils.hpp
|
|
Date: 2022-2-1
|
|
File: AuroraUtils.hpp
|
|
File: auROXTLUtils.hpp
|
|
Date: 2021-6-9
|
|
Author: Reece
|
|
***/
|
|
#pragma once
|
|
|
|
#include <auROXTL/auTupleUtils.hpp>
|
|
|
|
namespace __audetail
|
|
{
|
|
template <class T>
|
|
struct AuHascapacity
|
|
{
|
|
template <class C> static constexpr AuTrueType Test(decltype(&C::capacity));
|
|
template <class C> static constexpr AuFalseType Test(...);
|
|
using type = decltype(Test<T>(0));
|
|
};
|
|
|
|
template <class T>
|
|
constexpr inline bool AuHascapacity_v = AuHascapacity<T>::type::value;
|
|
|
|
template <class T>
|
|
struct AuHasreserve
|
|
{
|
|
template <class C> static constexpr AuTrueType Test(decltype(&C::reserve));
|
|
template <class C> static constexpr AuFalseType Test(...);
|
|
using type = decltype(Test<T>(0));
|
|
};
|
|
|
|
template <class T>
|
|
constexpr inline bool AuHasreserve_v = AuHasreserve<T>::type::value;
|
|
|
|
template <class T>
|
|
constexpr inline bool AuIsPreallocatable_v = AuHascapacity_v<T> && AuHasreserve_v<T>;
|
|
|
|
template <class T>
|
|
struct AuHastry_emplace
|
|
{
|
|
template <class C> static constexpr AuTrueType Test(decltype(&C::try_emplace));
|
|
template <class C> static constexpr AuFalseType Test(...);
|
|
using type = decltype(Test<T>(0));
|
|
};
|
|
|
|
template <class T>
|
|
constexpr inline bool AuHastry_emplace_v = false;// <T>::type::value;
|
|
|
|
template <class T>
|
|
struct AuHasemplace
|
|
{
|
|
template <class C> static constexpr AuTrueType Test(decltype(&C::emplace));
|
|
template <class C> static constexpr AuFalseType Test(...);
|
|
using type = decltype(Test<T>(0));
|
|
};
|
|
|
|
template <class T>
|
|
constexpr inline bool AuHasemplace_v = true;//AuHasemplace<T>::type::value;
|
|
|
|
template <class T>
|
|
struct AuHasfind
|
|
{
|
|
template <class C> static constexpr AuTrueType Test(decltype(static_cast<typename C::const_iterator(C:: *)(const typename C::key_type &) const>(&C::find)));
|
|
template <class C> static constexpr AuTrueType Test(decltype(static_cast<typename C::const_iterator(C:: *)(const typename C::element_type &) const>(&C::find)));
|
|
template <class C> static constexpr AuFalseType Test(...);
|
|
using type = decltype(Test<T>(0));
|
|
};
|
|
|
|
template <class T>
|
|
constexpr inline bool AuHasfind_v = AuHasfind<T>::type::value;
|
|
|
|
template <class T>
|
|
struct AuHasend
|
|
{
|
|
template <class C> static constexpr AuTrueType Test(decltype(static_cast<typename C::const_iterator(C:: *)() const>(&C::end)));
|
|
template <class C> static constexpr AuFalseType Test(...);
|
|
using type = decltype(Test<T>(0));
|
|
};
|
|
|
|
template <class T>
|
|
constexpr inline bool AuHasend_v = AuHasend<T>::type::value;
|
|
}
|
|
|
|
template <class T, bool all>
|
|
inline bool _AuRemoveIfBase(T &in, const AuPredicate<const AuToValueType_t<T> &> &predicate);
|
|
|
|
template <class T>
|
|
inline bool AuRemoveAllIf(T &in, const AuPredicate<const AuToValueType_t<T> &> &predicate)
|
|
{
|
|
return _AuRemoveIfBase<T, true>(in, predicate);
|
|
}
|
|
|
|
template <class T>
|
|
inline bool AuRemoveIf(T &in, const AuPredicate<const AuToValueType_t<T> &> &predicate)
|
|
{
|
|
return _AuRemoveIfBase<T, false>(in, predicate);
|
|
}
|
|
|
|
template <class T, typename Z>
|
|
inline void AuRemove(T &in, const Z &type)
|
|
{
|
|
auto itr = in.find(type);
|
|
if (itr == in.end())
|
|
{
|
|
return;
|
|
}
|
|
in.erase(itr);
|
|
}
|
|
|
|
template <class T>
|
|
inline void AuRemoveRange(T &in, AuUInt index, AuUInt length)
|
|
{
|
|
if (index + length > in.size())
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto begin = in.begin();
|
|
auto end = begin;
|
|
|
|
std::advance(begin, index);
|
|
std::advance(end, index + length);
|
|
|
|
while (begin != end)
|
|
{
|
|
in.erase(begin++);
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
inline bool AuTryRemoveRange(T &in, AuUInt index, AuUInt length)
|
|
{
|
|
AUROXTL_COMMODITY_TRY
|
|
{
|
|
if (index + length > in.size())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
auto begin = in.begin();
|
|
auto end = begin;
|
|
|
|
std::advance(begin, index);
|
|
std::advance(end, index + length);
|
|
|
|
while (begin != end)
|
|
{
|
|
in.erase(begin++);
|
|
}
|
|
}
|
|
AUROXTL_COMMODITY_CATCH
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class Map, class Key, class Value, AU_TEMPLATE_ENABLE_WHEN(__audetail::AuHasfind_v<Map> && !AuIsPointer_v<Map>)>
|
|
inline bool AuTryFind(Map &map, const Key &key, Value *&ptr)
|
|
{
|
|
auto itr = map.find(key);
|
|
if (itr != map.end())
|
|
{
|
|
ptr = &itr->second;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
ptr = nullptr;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template <class Map, class Key, typename Value>
|
|
inline bool AuTryFind(Map *map, const Key &key, Value *&ptr)
|
|
{
|
|
return AuTryFind(*map, key, ptr);
|
|
}
|
|
|
|
template <AuUInt N, typename List, class Key>
|
|
inline auto AuTryFindByTupleN(List &list, const Key &key)
|
|
{
|
|
for (auto itr = list.begin(); itr != list.end(); )
|
|
{
|
|
if (AuGet<N>(*itr) == key)
|
|
{
|
|
return itr;
|
|
}
|
|
else
|
|
{
|
|
itr++;
|
|
}
|
|
}
|
|
return list.end();
|
|
}
|
|
|
|
template <class Range, class Key, AU_TEMPLATE_ENABLE_WHEN(!__audetail::AuHasfind_v<Range> && !AuIsPointer_v<Range>)>
|
|
inline bool AuExists(const Range &a, const Key &key)
|
|
{
|
|
return std::find(a.begin(), a.end(), key) != a.end();
|
|
}
|
|
|
|
template <class Map, class Key, AU_TEMPLATE_ENABLE_WHEN(__audetail::AuHasfind_v<Map> && !AuIsPointer_v<Map>)>
|
|
inline bool AuExists(const Map &map, const Key &key)
|
|
{
|
|
auto itr = map.find(key);
|
|
if (itr != map.end())
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template <class Map, class Key>
|
|
inline bool AuExists(const Map *map, const Key &key)
|
|
{
|
|
return AuExists(*map, key);
|
|
}
|
|
|
|
template <class Container>
|
|
inline bool AuTryClear(Container &container)
|
|
{
|
|
container.clear();
|
|
return true;
|
|
}
|
|
|
|
template <class Range, class Key, AU_TEMPLATE_ENABLE_WHEN(!__audetail::AuHasfind_v<Range> && !AuIsPointer_v<Range>)>
|
|
inline bool AuTryRemove(Range &list, const Key &key)
|
|
{
|
|
auto itr = std::find(list.begin(), list.end(), key);
|
|
if (itr != list.end())
|
|
{
|
|
list.erase(itr);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template <class Map, class Key, AU_TEMPLATE_ENABLE_WHEN(__audetail::AuHasfind_v<Map> && !AuIsPointer_v<Map>)>
|
|
inline bool AuTryRemove(Map &map, const Key &key)
|
|
{
|
|
auto itr = map.find(key);
|
|
if (itr != map.end())
|
|
{
|
|
map.erase(itr);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template <class Map, class Key>
|
|
inline bool AuTryRemove(Map *map, const Key &key)
|
|
{
|
|
return AuTryRemove(*map, key);
|
|
}
|
|
|
|
template <AuUInt N, typename List, class Key>
|
|
inline bool AuTryRemoveByTupleN(List &list, const Key &key)
|
|
{
|
|
for (auto itr = list.begin(); itr != list.end(); )
|
|
{
|
|
if (AuGet<N>(*itr) == key)
|
|
{
|
|
itr = list.erase(itr);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
itr++;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
template <class Container, typename Key_t, typename Type_t>
|
|
inline bool AuTryInsert(Container &container, Key_t &&key, Type_t &&value, bool overwriteMode = true)
|
|
{
|
|
AUROXTL_COMMODITY_TRY
|
|
{
|
|
auto itr = container.find(key);
|
|
if (itr == container.end())
|
|
{
|
|
#if defined(_AURORA_NULLEXPT_USE_TRY_EMPLACE_AFTER_FIND)
|
|
if constexpr (__audetail::AuHastry_emplace_v<Container>)
|
|
{
|
|
auto [iterator, success] = container.try_emplace(AuMove(key), AuMove(value));
|
|
return success;
|
|
}
|
|
else
|
|
#endif
|
|
if constexpr (__audetail::AuHasemplace_v<Container>)
|
|
{
|
|
container.emplace(AuMove(key), AuMove(value));
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
container.insert(AuMakePair(AuMove(key), AuMove(value)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!overwriteMode)
|
|
{
|
|
return false;
|
|
}
|
|
itr->second = AuMove(value);
|
|
}
|
|
return true;
|
|
}
|
|
AUROXTL_COMMODITY_CATCH
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template <class Container, typename Key_t, typename Type_t>
|
|
inline bool AuTryInsert(Container &container, const Key_t &key, Type_t &&value, bool overwriteMode = true)
|
|
{
|
|
AUROXTL_COMMODITY_TRY
|
|
{
|
|
auto itr = container.find(key);
|
|
if (itr == container.end())
|
|
{
|
|
#if defined(_AURORA_NULLEXPT_USE_TRY_EMPLACE_AFTER_FIND)
|
|
if constexpr (__audetail::AuHastry_emplace_v<Container>)
|
|
{
|
|
auto [iterator, success] = container.try_emplace(key, AuMove(value));
|
|
return success;
|
|
}
|
|
else
|
|
#endif
|
|
if constexpr (__audetail::AuHasemplace_v<Container>)
|
|
{
|
|
container.emplace(key, AuMove(value));
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
container.insert(AuMakePair(key, AuMove(value)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!overwriteMode)
|
|
{
|
|
return false;
|
|
}
|
|
itr->second = AuMove(value);
|
|
}
|
|
return true;
|
|
}
|
|
AUROXTL_COMMODITY_CATCH
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template <class Container>
|
|
inline bool AuTryReserve(Container &container, AuUInt uRequired)
|
|
{
|
|
if (container.capacity() >= uRequired)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
AUROXTL_COMMODITY_TRY
|
|
{
|
|
container.reserve(uRequired);
|
|
}
|
|
AUROXTL_COMMODITY_CATCH
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return container.capacity() >= uRequired;
|
|
}
|
|
|
|
template <class Container>
|
|
inline bool AuContainerReserveSpaceForOne(Container &container)
|
|
{
|
|
auto uCapacity = container.size();
|
|
|
|
if (container.capacity() >= (uCapacity + 1))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return AuTryReserve(container, uCapacity > 512 ? 512 : uCapacity + 32);
|
|
}
|
|
|
|
template <class Container>
|
|
inline bool AuContainerReserveSpaceForOne(Container *container)
|
|
{
|
|
return AuContainerReserveSpaceForOne(*container);
|
|
}
|
|
|
|
template <class Container, typename Value, AU_TEMPLATE_ENABLE_WHEN(!__audetail::AuHasend_v<Container> && !AuIsPointer_v<Container>)>
|
|
inline bool AuTryInsert(Container &container, const Value &value)
|
|
{
|
|
AUROXTL_COMMODITY_TRY
|
|
{
|
|
if constexpr (__audetail::AuIsPreallocatable_v<AuRemoveReference_t<Container>>)
|
|
{
|
|
if (!AuContainerReserveSpaceForOne(container))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
container.insert(AuReference(value));
|
|
|
|
return true;
|
|
}
|
|
AUROXTL_COMMODITY_CATCH
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template <class Container, typename Value, AU_TEMPLATE_ENABLE_WHEN(!__audetail::AuHasend_v<Container> && !AuIsPointer_v<Container>)>
|
|
inline bool AuTryInsert(Container &container, Value &&value)
|
|
{
|
|
AUROXTL_COMMODITY_TRY
|
|
{
|
|
if constexpr (__audetail::AuIsPreallocatable_v<AuRemoveReference_t<Container>>)
|
|
{
|
|
if (!AuContainerReserveSpaceForOne(container))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
container.insert(AuMove(value));
|
|
|
|
return true;
|
|
}
|
|
AUROXTL_COMMODITY_CATCH
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template <class Container, typename Value, AU_TEMPLATE_ENABLE_WHEN(__audetail::AuHasend_v<Container> && !AuIsPointer_v<Container>)>
|
|
inline bool AuTryInsert(Container &container, Value &&value)
|
|
{
|
|
AUROXTL_COMMODITY_TRY
|
|
{
|
|
if constexpr (__audetail::AuIsPreallocatable_v<AuRemoveReference_t<Container>>)
|
|
{
|
|
if (!AuContainerReserveSpaceForOne(container))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
container.insert(container.end(), AuMove(value));
|
|
|
|
return true;
|
|
}
|
|
AUROXTL_COMMODITY_CATCH
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template <class Container, typename Value, AU_TEMPLATE_ENABLE_WHEN(__audetail::AuHasend_v<Container> && !AuIsPointer_v<Container>)>
|
|
inline bool AuTryInsert(Container &container, const Value &value)
|
|
{
|
|
AUROXTL_COMMODITY_TRY
|
|
{
|
|
if constexpr (__audetail::AuIsPreallocatable_v<AuRemoveReference_t<Container>>)
|
|
{
|
|
if (!AuContainerReserveSpaceForOne(container))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
container.insert(container.end(), value);
|
|
|
|
return true;
|
|
}
|
|
AUROXTL_COMMODITY_CATCH
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template <class Map, class Key, class Value>
|
|
inline bool AuTryInsert(Map *map, Key &&key, Value &&value, bool overwriteMode = true)
|
|
{
|
|
return AuTryInsert(*map, AuMove(key), AuMove(value), overwriteMode);
|
|
}
|
|
|
|
template <class Map, class Key, class Value>
|
|
inline bool AuTryInsert(Map *map, const Key &key, Value &&value, bool overwriteMode = true)
|
|
{
|
|
return AuTryInsert(*map, AuReference(key), AuMove(value), overwriteMode);
|
|
}
|
|
|
|
template <class Map, class Value>
|
|
inline bool AuTryInsert(Map *map, Value &&value)
|
|
{
|
|
return AuTryInsert(*map, AuMove(value));
|
|
}
|
|
|
|
template <class Map, class Value>
|
|
inline bool AuTryInsert(Map *map, const Value &value)
|
|
{
|
|
return AuTryInsert(*map, value);
|
|
}
|
|
|
|
namespace Aurora::Memory
|
|
{
|
|
struct ByteBuffer;
|
|
}
|
|
|
|
template <class T>
|
|
inline bool AuTryResize(T &list, AuUInt length)
|
|
{
|
|
AUROXTL_COMMODITY_TRY
|
|
{
|
|
if constexpr (AuIsSame_v<T, Aurora::Memory::ByteBuffer>)
|
|
{
|
|
return list.Resize(length);
|
|
}
|
|
else
|
|
{
|
|
list.resize(length);
|
|
return true;
|
|
}
|
|
}
|
|
AUROXTL_COMMODITY_CATCH
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
inline bool AuTryDownsize(T &list, AuUInt length)
|
|
{
|
|
AUROXTL_COMMODITY_TRY
|
|
{
|
|
if constexpr (AuIsSame_v<T, Aurora::Memory::ByteBuffer>)
|
|
{
|
|
if (!list.Resize(length))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
list.GC();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
list.resize(length);
|
|
list.shrink_to_fit();
|
|
return true;
|
|
}
|
|
}
|
|
AUROXTL_COMMODITY_CATCH
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template <class T, bool all>
|
|
inline bool _AuRemoveIfBase(T &in, const AuPredicate<const AuToValueType_t<T> &> &predicate)
|
|
{
|
|
bool retOne {};
|
|
|
|
for (auto itr = in.begin(); itr != in.end(); )
|
|
{
|
|
if (predicate(*itr))
|
|
{
|
|
itr = in.erase(itr);
|
|
if constexpr (!all)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
retOne = true;
|
|
}
|
|
else
|
|
{
|
|
itr++;
|
|
}
|
|
}
|
|
|
|
// optimization hint
|
|
if constexpr (all) return retOne;
|
|
return {};
|
|
} |