/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuroraUtils.hpp Date: 2021-6-9 Author: Reece ***/ #pragma once template static constexpr int ArraySize(const T(&array)[Z]) { return Z; } #if defined(DEBUG) || defined(INTERNAL) template static void inline SafeDelete(T *in) { static_assert(std::is_base_of::type>::value); auto cast = dynamic_cast(in); if (cast == nullptr) { Z re; SysPanic("Tried to free: 0x{:x}, type \"{}\" was not inherited from \"{}\"", AuUInt(in), typeid(in).name(), typeid(re).name()); } delete cast; } #else template static void inline SafeDelete(T *in) { static_assert(std::is_base_of::type>::value); delete static_cast(in); } #endif static inline AuUInt64 ConvertMagicTag64(const char buffer[8]) { return *reinterpret_cast(buffer); } static inline AuUInt32 ConvertMagicTag32(const char buffer[4]) { return *reinterpret_cast(buffer); } template static inline std::optional> OptionalSharedDynamicCast(std::optional> &in) { if (!in.has_value()) return {}; return std::dynamic_pointer_cast(in.value()); } template static inline std::optional> OptionalSharedStaticCast(std::optional> &in) { if (!in.has_value()) return {}; return std::static_pointer_cast(in.value()); } static inline bool EndsWith(std::string const &value, std::string const &ending) { if (ending.size() > value.size()) return false; return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); } static inline bool StartsWith(std::string const &value, std::string const &starting) { return value.rfind(starting, 0) == 0; } template static inline AuString ToStringASCIIOp(T op, const AuString &in) { AuString ret; ret.resize(in.size()); std::transform(in.begin(), in.end(), ret.begin(), [=](const char &c) { return op(c); }); return ret; } static inline AuString ToLower(const AuString &in) { return ToStringASCIIOp(std::tolower, in); } static inline AuString ToUpper(const AuString &in) { return ToStringASCIIOp(std::toupper, in); } template static inline bool TryFind(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 static inline bool TryFind(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 static inline bool TryFind(Map &map, const Key &key) { auto itr = map.find(key); if (itr != map.end()) { return true; } else { return false; } } template static inline bool TryFind(Map *map, const Key &key) { auto itr = map->find(key); if (itr != map->end()) { return true; } else { return false; } } template static inline bool TryFindGeneric(Map &map, const Key &key, Value *&ptr) { auto itr = map.find(key); if (itr != map.end()) { ptr = &*itr; return true; } else { ptr = nullptr; return false; } } template static inline bool TryDelete(Map &map, const Key &key) { auto itr = map.find(key); if (itr != map.end()) { map.erase(itr); return true; } else { return false; } } template static inline bool TryDeleteList(List &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 static inline bool TryInsert(Container &container, const Type &value) { try { container.insert(container.end(), value); return true; } catch (...) { return false; } } template static inline bool TryInsert(Container &container, Type &&value) { try { container.insert(container.end(), value); return true; } catch (...) { return false; } } template static inline bool TryInsert(Container *container, const Type &value) { try { container->insert(container->end(), value); return true; } catch (...) { return false; } } template static inline bool TryInsert(Container *container, Type &&value) { try { container->insert(container->end(), value); return true; } catch (...) { return false; } } template static inline bool TryInsertNoEnd(Container &container, Type &&value) // move { try { container.insert(value); return true; } catch (...) { return false; } } template static inline bool TryInsertNoEnd(Container &container, const Type &value) // copy { try { container.insert(value); return true; } catch (...) { return false; } } template static inline bool TryInsertNoEnd(Container *container, Type &&value) // move { try { container->insert(value); return true; } catch (...) { return false; } } template static inline bool TryInsertNoEnd(Container *container, const Type &value) // copy { try { container->insert(value); return true; } catch (...) { return false; } } template static inline bool TryResize(T &list, AuUInt length) { try { list.resize(length); return true; } catch (...) { return false; } } static inline std::string ReplaceAll(std::string &str, const std::string &from, const std::string &to) { size_t start_pos = 0; while ((start_pos = str.find(from, start_pos)) != std::string::npos) { str.replace(start_pos, from.length(), to); start_pos += to.length(); // Handles case where 'to' is a substring of 'from' } return str; } // i told myself not to copy this, required a split function twice, now here we are :D static inline AuList SplitString(const AuString& str, const AuString& delim) { AuList tokens; AuUInt prev = 0, pos = 0; do { pos = str.find(delim, prev); if (pos == AuString::npos) pos = str.length(); auto token = str.substr(prev, pos-prev); if (!token.empty()) tokens.push_back(token); prev = pos + delim.length(); } while (pos < str.length() && prev < str.length()); return tokens; } // more copy/pasta. work smart, not hard. // i dont want to waste time working out template kinks between clang and msvc template < template class base,typename derived> struct is_base_of_template_impl { template static constexpr std::true_type test(const base *); static constexpr std::false_type test(...); using type = decltype(test(std::declval())); }; template < template class base,typename derived> using is_base_of_template = typename is_base_of_template_impl::type;