AuROXTL/Include/auROXTL/auContainerUtils.hpp
2022-10-06 20:18:56 +01:00

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 {};
}