AuROXTL/Include/auROXTL/auContainerUtils.hpp
Jamie Reece Wilson b1d6eb0d80 [+] AuROString "support"
[+] AuCodepointsTransformASCIIOp
[+] AuCodepointsCount
[+] AuCodepointsNextLength
[+] AuCodepointsDecode
[+] AuCodepointsEncodeInto
[+] AuCodepointsTransform
2024-04-19 09:37:45 +01:00

632 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>
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();
std::advance(begin, index);
for (AuUInt i = 0; i < length; i++)
{
begin = in.erase(begin);
if (begin == in.end()) break;
}
}
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();
std::advance(begin, index);
for (AuUInt i = 0; i < length; i++)
{
begin = in.erase(begin);
if (begin == in.end()) return i == length - 1;
}
}
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)
{
if constexpr (AuIsSame_v<Key, AuROString> &&
Aurora::Build::kCurrentLanguage != Aurora::Build::ELanguage::eCpp20 &&
(int)Aurora::Build::kCurrentLanguage < 20)
{
for (auto itr = map.begin();
itr != map.end();
)
{
if constexpr (AuIsHashMap_v<Map> || AuIsBST_v<Map>)
{
if (itr->first == key)
{
return true;
}
}
else
{
if (*itr == key)
{
return true;
}
}
itr++;
}
}
else
{
auto itr = map.find(key);
if (itr != map.end())
{
return true;
}
}
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)
{
if constexpr (AuIsSame_v<Key, AuROString> &&
Aurora::Build::kCurrentLanguage != Aurora::Build::ELanguage::eCpp20 &&
(int)Aurora::Build::kCurrentLanguage < 20)
{
for (auto itr = list.begin();
itr != list.end();
)
{
if constexpr (AuIsHashMap_v<Range> || AuIsBST_v<Range>)
{
if (itr->first == key)
{
list.erase(itr);
return true;
}
}
else
{
if (*itr == key)
{
list.erase(itr);
return true;
}
}
itr++;
}
}
else
{
auto itr = std::find(list.begin(), list.end(), key);
if (itr != list.end())
{
list.erase(itr);
return true;
}
}
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)
{
if constexpr (AuIsSame_v<Key, AuROString> &&
Aurora::Build::kCurrentLanguage != Aurora::Build::ELanguage::eCpp20 &&
(int)Aurora::Build::kCurrentLanguage < 20)
{
for (auto itr = map.begin();
itr != map.end();
)
{
if constexpr (AuIsHashMap_v<Map> || AuIsBST_v<Map>)
{
if (itr->first == key)
{
map.erase(itr);
return true;
}
}
else
{
if (*itr == key)
{
map.erase(itr);
return true;
}
}
itr++;
}
}
else
{
auto itr = map.find(key);
if (itr != map.end())
{
map.erase(itr);
return true;
}
}
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 constexpr (__audetail::AuHascapacity_v<Container>)
{
if (container.capacity() >= uRequired)
{
return true;
}
}
if constexpr (__audetail::AuHasreserve_v<Container>)
{
AUROXTL_COMMODITY_TRY
{
container.reserve(uRequired);
}
AUROXTL_COMMODITY_CATCH
{
return false;
}
}
if constexpr (__audetail::AuHascapacity_v<Container>)
{
return container.capacity() >= uRequired;
}
else
{
return true;
}
}
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 {};
}