Merge branch 'main' into macos-is-mean-yet-again

This commit is contained in:
Chloe 2024-07-07 05:46:06 -07:00
commit 04ed383f95
No known key found for this signature in database
GPG key ID: D2D404DD810FE0E3
95 changed files with 555 additions and 3174 deletions
.github
actions/build-debug-info-post
workflows
CHANGELOG.mdVERSION
installer/windows
loader
CMakeLists.txt
include/Geode
resources
src

View file

@ -15,7 +15,7 @@ runs:
mkdir build-debug-info-preprocessed
cd build
sed 's/\\\\/\//g' compile_commands.json | sed 's/D:\//\/d\//' > uni_compile_commands.json
pip install compile-commands
pip install compile-commands --break-system-packages
compile-commands --file=uni_compile_commands.json --filter_files='.*info\.rc.*' --filter='(.*) -o (.*)((?:/|\\).*)\.(?:obj|o) -c (.*)' --replacement="$BASH"' --noprofile --norc -c "mkdir -p ../build-debug-info-preprocessed/\g<2> && \g<1> -o ../build-debug-info-preprocessed/\g<2>\g<3>.i -E \g<4>"' -o ../build-debug-info/preprocess_commands.json --run --verbose
- name: Upload Build Debug Info

View file

@ -104,7 +104,7 @@ jobs:
run: ${{ env.base-configure-command }} -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN ${{ steps.build-debug-info.outputs.extra-configure }}
env:
SPLAT_DIR: ${{ github.workspace }}/.xwin-cache/splat
TOOLCHAIN: ${{ github.workspace }}/toolchain/clang-cl-msvc.cmake
TOOLCHAIN: ${{ github.workspace }}/toolchain/clang-msvc.cmake
HOST_ARCH: x86_64
- name: Build
@ -139,6 +139,9 @@ jobs:
name: Build macOS
runs-on: macos-latest
env:
SCCACHE_CACHE_MULTIARCH: 1
steps:
- name: Checkout
uses: actions/checkout@v4
@ -259,9 +262,8 @@ jobs:
- name: Fix Ubuntu libcstd++
run: |
sudo apt install ninja-build &&
sudo add-apt-repository ppa:ubuntu-toolchain-r/test &&
sudo apt-get update &&
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install --only-upgrade libstdc++6
- name: Configure

View file

@ -1,5 +1,24 @@
# Geode Changelog
## v3.2.0
* Fix auto-updater on MacOS (d752bc2)
* Use tasks for `FileSettingNode` (f94e95e)
* Fix single argument overload of `Task` (6fe1ac9)
* Fix the GLFW message box fix (09c188a)
* Shrink `TextInput` input to give some padding (1da73cf)
* Undither account and editor blank sprites, add missing editor blank sprites (427e86e, efc4a00, 9fd9a78)
* Fix populating web headers and add some new getters (a96ec91)
* Build mods to load stack statically (255066a)
* Force internal mod to always appear enabled (e659b97)
* Bring back uninstall Geode button on Windows (22b2580)
* Add `geode::openChangelogPopup` (e432e72)
* Add special visuals for paid tag (0082765)
* Add 64-bit check to the Windows installer (c45d8f6)
* Add `Mod::checkUpdates` (9d02155)
* Error on attempting to hook missing or inlined functions (2dc989f)
* Implement function bound checking on Windows crashlog for symbol resolution (66c2f9a)
* Add new syntax for image scale arguments (#983)
## v3.1.1
* Update Windows installer translations (ae589d2, dca28db, d12fb37, 08d8af3, f52cf02, 3fa1d9b)
* Add safe mode by holding shift on MacOS (e4905a0)

View file

@ -1 +1 @@
3.1.1
3.2.0

View file

@ -8,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Tento průvodce vás provede odi
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nV této cestě se nenachází Geometry Dash!"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nVaše verze Geometry Dash je moc stará pro tuto verzi Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "V této cestě jsou již nainstalovány jiné mody!$\r$\nGeode bude nainstalován místo nich. (the dll trademark)"
; uninstaller

View file

@ -18,6 +18,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Setup will guide you through the
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nThis path does not have Geometry Dash installed!"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "This path has other mods installed!$\r$\nThey will be overwritten by Geode. (the dll trademark)"
; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Saat tarvittavia ohjeita sitä m
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nValitussa kansiossa ei ole Geometry Dash -peliä asennettuna."
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "Valitussa kansiossa on jo Mega Hack v6/v7 asennettuna.$\r$\nGeode ei ole yhteensopiva MHv6/v7 kanssa (MHv8 on ensimmäinen yhteensopiva versio Geoden kanssa).$\r$\nPoistathan Mega Hackin ennen Geoden asentamista."
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Valitussa kansiossa on jo joitain modeja asennettuna.$\r$\nGeode ei ole yhteensopiva .DLL-muotoisten modien tai niiden lataajien kanssa.$\r$\nPoistathan .DLL-muotoiset modit ja niiden lataajat ennen Geoden asentamista. (the dll trademark)"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nGeometry Dash -pelisi on vanhentunut, eikä ole yhteensopiva tämän Geode-version kanssa!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Valitussa kansiossa on muita modeja asennettuna!$\r$\nGeode tulee poistamaan ne. (the dll trademark)"
; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Le programme d'installation vous
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nGeometry Dash n'est pas installé sur ce chemin !"
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "Ce chemin a déjà Mega Hack v6/v7 installé !$\r$\nGeode ne fonctionne pas avec MHv6/v7 (MHv8 sera compatible avec Geode).$\r$\nVeuillez le désinstaller avant de continuer."
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Ce chemin contient déjà un autre chargeur de mod installé !$\r$\nGeode ne fonctionne avec aucun autre chargeur de mod.$\r$\nVeuillez le désinstaller avant de continuer. (the dll trademark)"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "This path has other mods installed!$\r$\nThey will be overwritten by Geode. (the dll trademark)"
; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Το setup θα σας καθο
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nΑυτό το path δεν έχει το Geometry Dash εγκατεστημένο!"
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "Αυτό το path έχει ήδη το Mega Hack v6/v7 εγκατεστημένο!$\r$\nΤο Geode δεν λειτουργεί με το MHv6/v7 (MHv8 θα είναι συμβατό με το Geode).$\r$\nΠαρακαλώ, απεγκαταστήστε το πριν προχωρήσετε."
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Αυτό το path έχει ήδη ένα mod loader εγκατεστημένο!$\r$\nΤο Geode δεν λειτουργεί με οποιοδήποτε άλλο mod loader.$\r$\nΠαρακαλώ, απεγκαταστήστε το πριν προχωρήσετε. (the dll trademark)"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "This path has other mods installed!$\r$\nThey will be overwritten by Geode. (the dll trademark)"
; uninstaller

View file

@ -8,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "このセットアップは$(^Na
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nこのパスにはGeometry Dashがインストールされていません"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "このパスには他のモッドがインストールされています!$\r$\nそれらはGeodeによって上書きされます。the dll trademark"
; uninstaller

View file

@ -1,12 +1,6 @@
!insertmacro LANGFILE_EXT Korean
!pragma warning disable 6030 ; overwriting default MUI strings on purpose
; to translate these strings:
; 1. copy them from C:\Program Files (x86)\NSIS\Contrib\Language Files\*.nsh
; 2. copy the second line from uninstall text to install text and make it say "installation" instead of "uninstallation"
; 3. replace $(^NameDA) in second line with Geometry Dash
; 4. do not translate "(the dll trademark)", since that is replaced with the actual dll text
!pragma warning disable 6030
${LangFileString} MUI_TEXT_WELCOME_INFO_TEXT "이 프로그램은 $(^NameDA)의 설치를 진행해줄 것입니다.$\r$\n$\r$\n설치를 시작하기 전에, Geometry Dash가 켜져있지 않은지 확인해주세요.$\r$\n$\r$\n$_CLICK"
${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "이 프로그램은 $(^NameDA)의 삭제를 진행해줄 것입니다.$\r$\n$\r$\n삭제를 시작하기 전에, Geometry Dash가 켜져있지 않은지 확인해주세요.$\r$\n$\r$\n$_CLICK"
!pragma warning default 6030
@ -14,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "이 프로그램은 $(^NameDA)
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\n이 경로에는 Geometry Dash가 설치되어 있지 않습니다."
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "이 경로에는 다른 모드가 설치되어 있습니다!$\r$\nGeode에 의해 덮어쓰게 될 것입니다. (the dll trademark)"
; uninstaller

View file

@ -8,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Instalator przeprowadzi Cię prz
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nGeometry Dash nie jest zainstalowane w tym folderze!"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "W tym folderze zainstalowane są inne modyfikacje!$\r$\nZostaną one zastąpione przez Geode. (the dll trademark)"
; uninstaller

View file

@ -8,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "O instalador guiará você atrav
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nEsse caminho não tem Geometry Dash instalado!"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nSua versão do Geometry Dash é muito antiga para essa versão do Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Esse caminho já tem outros mods instalados!$\r$\nEles serão substituídos pelo Geode. (the dll trademark)"
; uninstaller

View file

@ -8,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Эта программа уда
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nПо этому пути не установлен Geometry Dash!"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nВаша версия Geometry Dash слишком старая для этой версии Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "По этому пути уже установлены другие моды!$\r$\nОни будут перезаписаны Geode. (the dll trademark)"
; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Setup会帮您卸载$(^NameDA)
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nGeometry Dash不在这文件夹请再试一遍"
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "这文件夹已经安装了Mega Hack v6/v7$\r$\nGeode不能跟MHv6/v7一起用(可是MHv8可以)。$\r$\n请先卸载MHv6/v7。"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "这文件夹已经安装了不同的游戏修改器加载器!$\r$\nGeode不能和不同的游戏修改器加载器一起用。$\r$\n请先卸载那个游戏修改器加载器。 (the dll trademark)"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "This path has other mods installed!$\r$\nThey will be overwritten by Geode. (the dll trademark)"
; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Este asistente te guiará durant
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\n¡Geometry Dash no está instalado en esta ruta!"
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "¡Mega Hack v6/v7 está instalado en esta ruta!$\r$\nGeode no es compatible con MHv6/v7 (MHv8 será compatible con Geode).$\r$\nPor favor, desinstálalo antes de continuar."
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "¡Hay otro cargador de mods instalado en esta ruta!$\r$\nGeode no funciona con ningún otro cargador de mods.$\r$\nPor favor, desinstálalo antes de continuar. (the dll trademark)"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nTu versión de Geometry Dash es muy vieja para esta versión de Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Esta ruta ya tiene otros mods instalados!$\r$\nEstos serán sobreescritos por Geode. (the dll trademark)"
; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Este asistente le guiará durant
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\n¡Geometry Dash no está instalado en esta ruta!"
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "¡Mega Hack v6/v7 está instalado en esta ruta!$\r$\nGeode no es compatible con MHv6/v7 (MHv8 será compatible con Geode).$\r$\nPor favor, desinstálelo antes de continuar."
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "¡Hay otro mod loader instalado en esta ruta!$\r$\nGeode no funciona con ningún otro mod loader.$\r$\nPor favor, desinstálelo antes de continuar. (the dll trademark)"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "This path has other mods installed!$\r$\nThey will be overwritten by Geode. (the dll trademark)"
; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Denna guide tar dig igenom avins
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nDen valda mappen innehåller ingen installation av Geometry Dash."
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "Den valda mappen innehåller redan Mega Hack v6/v7.$\r$\nGeode är inte kompatibel med MHv6/v7 (MHv8 är den första versionen som är kompatibel med Geode).$\r$\nSe till att avinstallera Mega Hack innan du startar installationen av Geode."
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Den valda mappen innehåller redan några andra mod.$\r$\nGeode är inte kompatibel med .DLL-slag mod eller sin mod loader.$\r$\nSe till att avinstallera .DLL-slag mod och sin mod loader innan du startar installationen av Geode. (the dll trademark)"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nDin version av Geometry Dash är för gammal för denna versionen av Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Den valda versionen av Geometry Dash har andra mod redan installerad!$\r$\nDom ska skrivs över av Geode. (the dll trademark)"
; uninstaller

View file

@ -8,8 +8,8 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Setup會幫您卸載$(^NameDA)
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nGeometry Dash不在這文件夾請再試一遍"
${LangFileString} GEODE_TEXT_MH_ALREADY_INSTALLED "這文件夾已經安裝了Mega Hack v6/v7$\r$\nGeode不能跟MHv6/v7一起用(可是MHv8可以跟Geode一起用)。$\r$\n請先卸載MHv6/v7。"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "這文件夾已經安裝了不同的遊戲修改器加載器!$\r$\nGeode不能跟不同的遊戲修改器加載器一起用。$\r$\n請先卸載那個遊戲修改器加載器。 (the dll trademark)"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nYour version of Geometry Dash is too old for this version of Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "This path has other mods installed!$\r$\nThey will be overwritten by Geode. (the dll trademark)"
; uninstaller

View file

@ -8,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Bu sihirbaz size $(^NameDA) prog
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nBu dizin yolunda Geometry Dash yüklü değildir!"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nGeometry Dash versiyonunuz bu Geode versiyonu için çok eskidir!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Bu dizin yolunda başka modlar yüklüdür!$\r$\nGeode bunların üzerine yazılacaktır. (the dll trademark)"
; uninstaller

View file

@ -8,6 +8,7 @@ ${LangFileString} MUI_UNTEXT_WELCOME_INFO_TEXT "Ця програма допом
; installer
${LangFileString} GEODE_TEXT_GD_MISSING "$\r$\n$\r$\nУ цій теці не встановлено Geometry Dash!"
${LangFileString} GEODE_TEXT_GD_OLD "$\r$\n$\r$\nВаша версія Geometry Dash занадто стара для цієї версії Geode!"
${LangFileString} GEODE_TEXT_MOD_LOADER_ALREADY_INSTALLED "Ця тека вже містить інші моди!$\r$\nВони будуть замінені Geode. (the dll trademark)"
; uninstaller

View file

@ -407,6 +407,11 @@ Function .onVerifyInstDir
IfFileExists $INSTDIR\*.exe 0 noGameNoLife
IfFileExists $INSTDIR\libcocos2d.dll 0 noGameNoLife
; check if we're on 64-bit gd (checks for some of the DLLs introduced in 2.206)
IfFileExists $INSTDIR\libpng16.dll 0 versionIssueImo
IfFileExists $INSTDIR\pthreadVC3.dll 0 versionIssueImo
IfFileExists $INSTDIR\libcrypto-3-x64.dll 0 versionIssueImo
; check if geode is already installed
IfFileExists $INSTDIR\Geode.dll valid
@ -423,6 +428,9 @@ Function .onVerifyInstDir
noGameNoLife:
SendMessage $geode.DirectoryPage.ErrorText ${WM_SETTEXT} "" "STR:$(GEODE_TEXT_GD_MISSING)"
Goto error
versionIssueImo:
SendMessage $geode.DirectoryPage.ErrorText ${WM_SETTEXT} "" "STR:$(GEODE_TEXT_GD_OLD)"
Goto error
other_hackpro:
StrCpy $0 "hackpro.dll"
Goto other

View file

@ -246,9 +246,10 @@ if (NOT GEODE_BUILDING_DOCS)
set(MZ_BZIP2 OFF CACHE INTERNAL "")
set(MZ_OPENSSL OFF CACHE INTERNAL "")
set(MZ_LIBBSD OFF CACHE INTERNAL "")
set(MZ_FETCH_LIBS ON CACHE INTERNAL "")
set(MZ_FETCH_LIBS ON CACHE INTERNAL "" FORCE)
set(MZ_FORCE_FETCH_LIBS ${WIN32} CACHE INTERNAL "")
set(SKIP_INSTALL_ALL ON CACHE INTERNAL "")
CPMAddPackage("gh:geode-sdk/minizip-ng#011a133")
CPMAddPackage("gh:geode-sdk/minizip-ng#7548419")
if (WIN32)
set_target_properties(zlib PROPERTIES SUFFIX "1.dll")
endif()

View file

@ -6,8 +6,6 @@
#if defined(GEODE_IS_ANDROID)
#include "gnustl.hpp"
//#elif defined(GEODE_IS_WINDOWS)
//#include "msvcstl.hpp"
#else
#include "aliastl.hpp"
#endif

View file

@ -1,35 +0,0 @@
#pragma once
#include <Geode/platform/platform.hpp>
#include <cstddef>
#include <type_traits>
namespace geode::stl {
GEODE_DLL void* operatorNew(std::size_t size);
GEODE_DLL void operatorDelete(void* ptr);
template <class T>
struct allocator {
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using propagate_on_container_move_assignment = std::true_type;
constexpr allocator() noexcept {}
constexpr allocator(const allocator& other) noexcept {}
template<class U>
constexpr allocator(const allocator<U>& other) noexcept {}
constexpr ~allocator() {}
[[nodiscard]] T* allocate(std::size_t n) {
return reinterpret_cast<T*>(operatorNew(n * sizeof(T)));
}
void deallocate(T* p, std::size_t n) {
operatorDelete(reinterpret_cast<void*>(p));
}
};
}

View file

@ -1,563 +0,0 @@
// unordered_map standard header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// Per Apache License, Version 2.0, Section 4, Point b: I (kynex7510) changed this file.
#ifndef _GEODE_UNORDERED_MAP_
#define _GEODE_UNORDERED_MAP_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#include "xhash.hpp"
#if _HAS_CXX17
#include <xpolymorphic_allocator.h>
#endif // _HAS_CXX17
#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new
namespace geode::stl {
template <class _Kty, // key type
class _Ty, // mapped type
class _Tr, // comparator predicate type
class _Alloc, // actual _STD allocator type (should be value _STD allocator)
bool _Mfl> // true if multiple equivalent keys are permitted
class _Umap_traits : public _Tr { // traits required to make _Hash behave like a map
public:
using key_type = _Kty;
using value_type = _STD pair<const _Kty, _Ty>;
using _Mutable_value_type = _STD pair<_Kty, _Ty>;
using key_compare = _Tr;
using allocator_type = _Alloc;
#if _HAS_CXX17
using node_type = _STD _Node_handle<_STD _List_node<value_type, typename _STD allocator_traits<_Alloc>::void_pointer>, _Alloc,
_STD _Node_handle_map_base, _Kty, _Ty>;
#endif // _HAS_CXX17
static constexpr bool _Multi = _Mfl;
static constexpr bool _Standard = true;
template <class... _Args>
using _In_place_key_extractor = _STD _In_place_key_extract_map<_Kty, _Args...>;
_Umap_traits() = default;
explicit _Umap_traits(const _Tr& _Traits) noexcept(_STD is_nothrow_copy_constructible_v<_Tr>) : _Tr(_Traits) {}
using value_compare = void; // TRANSITION, remove when _Standard becomes unconditionally true
template <class _Ty1, class _Ty2>
static const _Kty& _Kfn(const _STD pair<_Ty1, _Ty2>& _Val) noexcept { // extract key from element value
return _Val.first;
}
template <class _Ty1, class _Ty2>
static const _Ty2& _Nonkfn(const _STD pair<_Ty1, _Ty2>& _Val) noexcept { // extract non-key from element value
return _Val.second;
}
};
/*_EXPORT_STD*/ template <class _Kty, class _Ty, class _Hasher = _STD hash<_Kty>, class _Keyeq = _STD equal_to<_Kty>,
class _Alloc = _STD allocator<_STD pair<const _Kty, _Ty>>>
class unordered_map : public _Hash<_Umap_traits<_Kty, _Ty, _STD _Uhash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, false>> {
// hash table of {key, mapped} values, unique keys
public:
static_assert(!_ENFORCE_MATCHING_ALLOCATORS || _STD is_same_v<_STD pair<const _Kty, _Ty>, typename _Alloc::value_type>,
_MISMATCHED_ALLOCATOR_MESSAGE("unordered_map<Key, Value, Hasher, Eq, Allocator>", "_STD pair<const Key, Value>"));
static_assert(_STD is_object_v<_Kty>, "The C++ Standard forbids containers of non-object types "
"because of [container.requirements].");
private:
using _Mytraits = _STD _Uhash_compare<_Kty, _Hasher, _Keyeq>;
using _Mybase = _Hash<_Umap_traits<_Kty, _Ty, _Mytraits, _Alloc, false>>;
using _Alnode = typename _Mybase::_Alnode;
using _Alnode_traits = typename _Mybase::_Alnode_traits;
using _Nodeptr = typename _Mybase::_Nodeptr;
using _Key_compare = typename _Mybase::_Key_compare;
public:
using hasher = _Hasher;
using key_type = _Kty;
using mapped_type = _Ty;
using key_equal = _Keyeq;
using value_type = _STD pair<const _Kty, _Ty>;
using allocator_type = typename _Mybase::allocator_type;
using size_type = typename _Mybase::size_type;
using difference_type = typename _Mybase::difference_type;
using pointer = typename _Mybase::pointer;
using const_pointer = typename _Mybase::const_pointer;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = typename _Mybase::iterator;
using const_iterator = typename _Mybase::const_iterator;
using local_iterator = typename _Mybase::iterator;
using const_local_iterator = typename _Mybase::const_iterator;
#if _HAS_CXX17
using insert_return_type = _STD _Insert_return_type<iterator, typename _Mybase::node_type>;
#endif // _HAS_CXX17
unordered_map() : _Mybase(_Key_compare(), allocator_type()) {}
explicit unordered_map(const allocator_type& _Al) : _Mybase(_Key_compare(), _Al) {}
unordered_map(const unordered_map& _Right)
: _Mybase(_Right, _Alnode_traits::select_on_container_copy_construction(_Right._Getal())) {}
unordered_map(const unordered_map& _Right, const allocator_type& _Al) : _Mybase(_Right, _Al) {}
explicit unordered_map(size_type _Buckets) : _Mybase(_Key_compare(), allocator_type()) {
_Mybase::rehash(_Buckets);
}
unordered_map(size_type _Buckets, const allocator_type& _Al) : _Mybase(_Key_compare(), _Al) {
_Mybase::rehash(_Buckets);
}
unordered_map(size_type _Buckets, const hasher& _Hasharg) : _Mybase(_Key_compare(_Hasharg), allocator_type()) {
_Mybase::rehash(_Buckets);
}
unordered_map(size_type _Buckets, const hasher& _Hasharg, const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg), _Al) {
_Mybase::rehash(_Buckets);
}
unordered_map(size_type _Buckets, const hasher& _Hasharg, const _Keyeq& _Keyeqarg)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), allocator_type()) {
_Mybase::rehash(_Buckets);
}
unordered_map(size_type _Buckets, const hasher& _Hasharg, const _Keyeq& _Keyeqarg, const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), _Al) {
_Mybase::rehash(_Buckets);
}
template <class _Iter>
unordered_map(_Iter _First, _Iter _Last) : _Mybase(_Key_compare(), allocator_type()) {
insert(_First, _Last);
}
template <class _Iter>
unordered_map(_Iter _First, _Iter _Last, const allocator_type& _Al) : _Mybase(_Key_compare(), _Al) {
insert(_First, _Last);
}
template <class _Iter>
unordered_map(_Iter _First, _Iter _Last, size_type _Buckets) : _Mybase(_Key_compare(), allocator_type()) {
_Mybase::rehash(_Buckets);
insert(_First, _Last);
}
template <class _Iter>
unordered_map(_Iter _First, _Iter _Last, size_type _Buckets, const allocator_type& _Al)
: _Mybase(_Key_compare(), _Al) {
_Mybase::rehash(_Buckets);
insert(_First, _Last);
}
template <class _Iter>
unordered_map(_Iter _First, _Iter _Last, size_type _Buckets, const hasher& _Hasharg)
: _Mybase(_Key_compare(_Hasharg), allocator_type()) {
_Mybase::rehash(_Buckets);
insert(_First, _Last);
}
template <class _Iter>
unordered_map(_Iter _First, _Iter _Last, size_type _Buckets, const hasher& _Hasharg, const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg), _Al) {
_Mybase::rehash(_Buckets);
insert(_First, _Last);
}
template <class _Iter>
unordered_map(_Iter _First, _Iter _Last, size_type _Buckets, const hasher& _Hasharg, const _Keyeq& _Keyeqarg)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), allocator_type()) {
_Mybase::rehash(_Buckets);
insert(_First, _Last);
}
template <class _Iter>
unordered_map(_Iter _First, _Iter _Last, size_type _Buckets, const hasher& _Hasharg, const _Keyeq& _Keyeqarg,
const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), _Al) {
_Mybase::rehash(_Buckets);
insert(_First, _Last);
}
#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_map(_STD from_range_t, _Rng&& _Range) : _Mybase(_Key_compare(), allocator_type()) {
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_map(_STD from_range_t, _Rng&& _Range, const allocator_type& _Al) : _Mybase(_Key_compare(), _Al) {
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_map(_STD from_range_t, _Rng&& _Range, size_type _Buckets) : _Mybase(_Key_compare(), allocator_type()) {
_Mybase::rehash(_Buckets);
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_map(_STD from_range_t, _Rng&& _Range, size_type _Buckets, const allocator_type& _Al)
: _Mybase(_Key_compare(), _Al) {
_Mybase::rehash(_Buckets);
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_map(_STD from_range_t, _Rng&& _Range, size_type _Buckets, const hasher& _Hasharg)
: _Mybase(_Key_compare(_Hasharg), allocator_type()) {
_Mybase::rehash(_Buckets);
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_map(_STD from_range_t, _Rng&& _Range, size_type _Buckets, const hasher& _Hasharg, const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg), _Al) {
_Mybase::rehash(_Buckets);
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_map(_STD from_range_t, _Rng&& _Range, size_type _Buckets, const hasher& _Hasharg, const _Keyeq& _Keyeqarg)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), allocator_type()) {
_Mybase::rehash(_Buckets);
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_map(_STD from_range_t, _Rng&& _Range, size_type _Buckets, const hasher& _Hasharg, const _Keyeq& _Keyeqarg,
const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), _Al) {
_Mybase::rehash(_Buckets);
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
#endif // _HAS_CXX23 && defined(__cpp_lib_concepts)
unordered_map& operator=(const unordered_map& _Right) {
_Mybase::operator=(_Right);
return *this;
}
unordered_map(unordered_map&& _Right) : _Mybase(_STD move(_Right)) {}
unordered_map(unordered_map&& _Right, const allocator_type& _Al) : _Mybase(_STD move(_Right), _Al) {}
unordered_map& operator=(unordered_map&& _Right) noexcept(_Alnode_traits::is_always_equal::value&&
_STD is_nothrow_move_assignable_v<_Hasher>&& _STD is_nothrow_move_assignable_v<_Keyeq>) {
_Mybase::operator=(_STD move(_Right));
return *this;
}
mapped_type& operator[](key_type&& _Keyval) {
return this->_Try_emplace(_STD move(_Keyval)).first->_Myval.second;
}
void swap(unordered_map& _Right) noexcept(noexcept(_Mybase::swap(_Right))) {
_Mybase::swap(_Right);
}
using _Mybase::insert;
template <class _Valty, _STD enable_if_t<_STD is_constructible_v<value_type, _Valty>, int> = 0>
_STD pair<iterator, bool> insert(_Valty&& _Val) {
return this->emplace(_STD forward<_Valty>(_Val));
}
template <class _Valty, _STD enable_if_t<_STD is_constructible_v<value_type, _Valty>, int> = 0>
iterator insert(const_iterator _Where, _Valty&& _Val) {
return this->emplace_hint(_Where, _STD forward<_Valty>(_Val));
}
template <class... _Mappedty>
_STD pair<iterator, bool> try_emplace(const key_type& _Keyval, _Mappedty&&... _Mapval) {
const auto _Result = this->_Try_emplace(_Keyval, _STD forward<_Mappedty>(_Mapval)...);
return {this->_List._Make_iter(_Result.first), _Result.second};
}
template <class... _Mappedty>
_STD pair<iterator, bool> try_emplace(key_type&& _Keyval, _Mappedty&&... _Mapval) {
const auto _Result = this->_Try_emplace(_STD move(_Keyval), _STD forward<_Mappedty>(_Mapval)...);
return {this->_List._Make_iter(_Result.first), _Result.second};
}
template <class... _Mappedty>
iterator try_emplace(const const_iterator _Hint, const key_type& _Keyval, _Mappedty&&... _Mapval) {
return this->_List._Make_iter(
this->_Try_emplace_hint(_Hint._Ptr, _Keyval, _STD forward<_Mappedty>(_Mapval)...));
}
template <class... _Mappedty>
iterator try_emplace(const const_iterator _Hint, key_type&& _Keyval, _Mappedty&&... _Mapval) {
return this->_List._Make_iter(
this->_Try_emplace_hint(_Hint._Ptr, _STD move(_Keyval), _STD forward<_Mappedty>(_Mapval)...));
}
private:
template <class _Keyty, class _Mappedty>
_STD pair<iterator, bool> _Insert_or_assign(_Keyty&& _Keyval_arg, _Mappedty&& _Mapval) {
const auto& _Keyval = _Keyval_arg;
const size_t _Hashval = this->_Traitsobj(_Keyval);
auto _Target = this->_Find_last(_Keyval, _Hashval);
if (_Target._Duplicate) {
_Target._Duplicate->_Myval.second = _STD forward<_Mappedty>(_Mapval);
return {this->_List._Make_iter(_Target._Duplicate), false};
}
this->_Check_max_size();
// invalidates _Keyval:
_STD _List_node_emplace_op2<_Alnode> _Newnode(
this->_Getal(), _STD forward<_Keyty>(_Keyval_arg), _STD forward<_Mappedty>(_Mapval));
if (this->_Check_rehash_required_1()) {
this->_Rehash_for_1();
_Target = this->_Find_last(_Newnode._Ptr->_Myval.first, _Hashval);
}
return {this->_List._Make_iter(
this->_Insert_new_node_before(_Hashval, _Target._Insert_before, _Newnode._Release())),
true};
}
template <class _Keyty, class _Mappedty>
iterator _Insert_or_assign(const _Nodeptr _Hint, _Keyty&& _Keyval_arg, _Mappedty&& _Mapval) {
const auto& _Keyval = _Keyval_arg;
const size_t _Hashval = this->_Traitsobj(_Keyval);
auto _Target = this->_Find_hint(_Hint, _Keyval, _Hashval);
if (_Target._Duplicate) {
_Target._Duplicate->_Myval.second = _STD forward<_Mappedty>(_Mapval);
return this->_List._Make_iter(_Target._Duplicate);
}
this->_Check_max_size();
// invalidates _Keyval:
_STD _List_node_emplace_op2<_Alnode> _Newnode(
this->_Getal(), _STD forward<_Keyty>(_Keyval_arg), _STD forward<_Mappedty>(_Mapval));
if (this->_Check_rehash_required_1()) {
this->_Rehash_for_1();
_Target = this->_Find_hint(_Hint, _Newnode._Ptr->_Myval.first, _Hashval);
}
return this->_List._Make_iter(
this->_Insert_new_node_before(_Hashval, _Target._Insert_before, _Newnode._Release()));
}
public:
template <class _Mappedty>
_STD pair<iterator, bool> insert_or_assign(const key_type& _Keyval, _Mappedty&& _Mapval) {
return _Insert_or_assign(_Keyval, _STD forward<_Mappedty>(_Mapval));
}
template <class _Mappedty>
_STD pair<iterator, bool> insert_or_assign(key_type&& _Keyval, _Mappedty&& _Mapval) {
return _Insert_or_assign(_STD move(_Keyval), _STD forward<_Mappedty>(_Mapval));
}
template <class _Mappedty>
iterator insert_or_assign(const_iterator _Hint, const key_type& _Keyval, _Mappedty&& _Mapval) {
return _Insert_or_assign(_Hint._Ptr, _Keyval, _STD forward<_Mappedty>(_Mapval));
}
template <class _Mappedty>
iterator insert_or_assign(const_iterator _Hint, key_type&& _Keyval, _Mappedty&& _Mapval) {
return _Insert_or_assign(_Hint._Ptr, _STD move(_Keyval), _STD forward<_Mappedty>(_Mapval));
}
unordered_map(_STD initializer_list<value_type> _Ilist) : _Mybase(_Key_compare(), allocator_type()) {
insert(_Ilist);
}
unordered_map(_STD initializer_list<value_type> _Ilist, const allocator_type& _Al) : _Mybase(_Key_compare(), _Al) {
insert(_Ilist);
}
unordered_map(_STD initializer_list<value_type> _Ilist, size_type _Buckets) : _Mybase(_Key_compare(), allocator_type()) {
_Mybase::rehash(_Buckets);
insert(_Ilist);
}
unordered_map(_STD initializer_list<value_type> _Ilist, size_type _Buckets, const allocator_type& _Al)
: _Mybase(_Key_compare(), _Al) {
_Mybase::rehash(_Buckets);
insert(_Ilist);
}
unordered_map(_STD initializer_list<value_type> _Ilist, size_type _Buckets, const hasher& _Hasharg)
: _Mybase(_Key_compare(_Hasharg), allocator_type()) {
_Mybase::rehash(_Buckets);
insert(_Ilist);
}
unordered_map(
_STD initializer_list<value_type> _Ilist, size_type _Buckets, const hasher& _Hasharg, const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg), _Al) {
_Mybase::rehash(_Buckets);
insert(_Ilist);
}
unordered_map(
_STD initializer_list<value_type> _Ilist, size_type _Buckets, const hasher& _Hasharg, const _Keyeq& _Keyeqarg)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), allocator_type()) {
_Mybase::rehash(_Buckets);
insert(_Ilist);
}
unordered_map(_STD initializer_list<value_type> _Ilist, size_type _Buckets, const hasher& _Hasharg,
const _Keyeq& _Keyeqarg, const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), _Al) {
_Mybase::rehash(_Buckets);
insert(_Ilist);
}
unordered_map& operator=(_STD initializer_list<value_type> _Ilist) {
_Mybase::clear();
insert(_Ilist);
return *this;
}
_NODISCARD hasher hash_function() const {
return _Mybase::_Traitsobj._Mypair._Get_first();
}
_NODISCARD key_equal key_eq() const {
return _Mybase::_Traitsobj._Mypair._Myval2._Get_first();
}
mapped_type& operator[](const key_type& _Keyval) {
return this->_Try_emplace(_Keyval).first->_Myval.second;
}
_NODISCARD mapped_type& at(const key_type& _Keyval) {
const auto _Target = this->_Find_last(_Keyval, this->_Traitsobj(_Keyval));
if (_Target._Duplicate) {
return _Target._Duplicate->_Myval.second;
}
_STD _Xout_of_range("invalid unordered_map<K, T> key");
}
_NODISCARD const mapped_type& at(const key_type& _Keyval) const {
const auto _Target = this->_Find_last(_Keyval, this->_Traitsobj(_Keyval));
if (_Target._Duplicate) {
return _Target._Duplicate->_Myval.second;
}
_STD _Xout_of_range("invalid unordered_map<K, T> key");
}
using _Mybase::_Unchecked_begin;
using _Mybase::_Unchecked_end;
};
#if _HAS_CXX17
template <class _Iter, class _Hasher = _STD hash<_STD _Guide_key_t<_Iter>>, class _Keyeq = _STD equal_to<_STD _Guide_key_t<_Iter>>,
class _Alloc = _STD allocator<_STD _Guide_pair_t<_Iter>>,
_STD enable_if_t<
_STD conjunction_v<_STD _Is_iterator<_Iter>, _Is_hasher<_Hasher>, _STD negation<_STD _Is_allocator<_Keyeq>>, _STD _Is_allocator<_Alloc>>,
int> = 0>
unordered_map(_Iter, _Iter, _STD _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(), _Alloc = _Alloc())
-> unordered_map<_STD _Guide_key_t<_Iter>, _STD _Guide_val_t<_Iter>, _Hasher, _Keyeq, _Alloc>;
template <class _Kty, class _Ty, class _Hasher = _STD hash<_Kty>, class _Keyeq = _STD equal_to<_Kty>,
class _Alloc = _STD allocator<_STD pair<const _Kty, _Ty>>,
_STD enable_if_t<_STD conjunction_v<_Is_hasher<_Hasher>, _STD negation<_STD _Is_allocator<_Keyeq>>, _STD _Is_allocator<_Alloc>>, int> = 0>
unordered_map(_STD initializer_list<_STD pair<_Kty, _Ty>>, _STD _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(),
_Alloc = _Alloc()) -> unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>;
template <class _Iter, class _Alloc, _STD enable_if_t<_STD conjunction_v<_STD _Is_iterator<_Iter>, _STD _Is_allocator<_Alloc>>, int> = 0>
unordered_map(_Iter, _Iter, _Alloc) -> unordered_map<_STD _Guide_key_t<_Iter>, _STD _Guide_val_t<_Iter>,
_STD hash<_STD _Guide_key_t<_Iter>>, _STD equal_to<_STD _Guide_key_t<_Iter>>, _Alloc>;
template <class _Iter, class _Alloc, _STD enable_if_t<_STD conjunction_v<_STD _Is_iterator<_Iter>, _STD _Is_allocator<_Alloc>>, int> = 0>
unordered_map(_Iter, _Iter, _STD _Guide_size_type_t<_Alloc>, _Alloc) -> unordered_map<_STD _Guide_key_t<_Iter>,
_STD _Guide_val_t<_Iter>, _STD hash<_STD _Guide_key_t<_Iter>>, _STD equal_to<_STD _Guide_key_t<_Iter>>, _Alloc>;
template <class _Iter, class _Hasher, class _Alloc,
_STD enable_if_t<_STD conjunction_v<_STD _Is_iterator<_Iter>, _Is_hasher<_Hasher>, _STD _Is_allocator<_Alloc>>, int> = 0>
unordered_map(_Iter, _Iter, _STD _Guide_size_type_t<_Alloc>, _Hasher, _Alloc)
-> unordered_map<_STD _Guide_key_t<_Iter>, _STD _Guide_val_t<_Iter>, _Hasher, _STD equal_to<_STD _Guide_key_t<_Iter>>, _Alloc>;
template <class _Kty, class _Ty, class _Alloc, _STD enable_if_t<_STD _Is_allocator<_Alloc>::value, int> = 0>
unordered_map(_STD initializer_list<_STD pair<_Kty, _Ty>>, _Alloc)
-> unordered_map<_Kty, _Ty, _STD hash<_Kty>, _STD equal_to<_Kty>, _Alloc>;
template <class _Kty, class _Ty, class _Alloc, _STD enable_if_t<_STD _Is_allocator<_Alloc>::value, int> = 0>
unordered_map(_STD initializer_list<_STD pair<_Kty, _Ty>>, _STD _Guide_size_type_t<_Alloc>, _Alloc)
-> unordered_map<_Kty, _Ty, _STD hash<_Kty>, _STD equal_to<_Kty>, _Alloc>;
template <class _Kty, class _Ty, class _Hasher, class _Alloc,
_STD enable_if_t<_STD conjunction_v<_Is_hasher<_Hasher>, _STD _Is_allocator<_Alloc>>, int> = 0>
unordered_map(_STD initializer_list<_STD pair<_Kty, _Ty>>, _STD _Guide_size_type_t<_Alloc>, _Hasher, _Alloc)
-> unordered_map<_Kty, _Ty, _Hasher, _STD equal_to<_Kty>, _Alloc>;
#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
template <_RANGES input_range _Rng, class _Hasher = _STD hash<_STD _Range_key_type<_Rng>>,
class _Keyeq = _STD equal_to<_STD _Range_key_type<_Rng>>, class _Alloc = _STD allocator<_STD _Range_to_alloc_type<_Rng>>,
_STD enable_if_t<_STD conjunction_v<_Is_hasher<_Hasher>, _STD negation<_STD _Is_allocator<_Keyeq>>, _STD _Is_allocator<_Alloc>>, int> = 0>
unordered_map(_STD from_range_t, _Rng&&, _STD _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(),
_Alloc = _Alloc()) -> unordered_map<_STD _Range_key_type<_Rng>, _STD _Range_mapped_type<_Rng>, _Hasher, _Keyeq, _Alloc>;
template <_RANGES input_range _Rng, class _Alloc, _STD enable_if_t<_STD _Is_allocator<_Alloc>::value, int> = 0>
unordered_map(_STD from_range_t, _Rng&&, _STD _Guide_size_type_t<_Alloc>, _Alloc) -> unordered_map<_STD _Range_key_type<_Rng>,
_STD _Range_mapped_type<_Rng>, _STD hash<_STD _Range_key_type<_Rng>>, _STD equal_to<_STD _Range_key_type<_Rng>>, _Alloc>;
template <_RANGES input_range _Rng, class _Alloc, _STD enable_if_t<_STD _Is_allocator<_Alloc>::value, int> = 0>
unordered_map(_STD from_range_t, _Rng&&, _Alloc) -> unordered_map<_STD _Range_key_type<_Rng>, _STD _Range_mapped_type<_Rng>,
_STD hash<_STD _Range_key_type<_Rng>>, _STD equal_to<_STD _Range_key_type<_Rng>>, _Alloc>;
template <_RANGES input_range _Rng, class _Hasher, class _Alloc,
_STD enable_if_t<_STD conjunction_v<_Is_hasher<_Hasher>, _STD _Is_allocator<_Alloc>>, int> = 0>
unordered_map(_STD from_range_t, _Rng&&, _STD _Guide_size_type_t<_Alloc>, _Hasher, _Alloc)
-> unordered_map<_STD _Range_key_type<_Rng>, _STD _Range_mapped_type<_Rng>, _Hasher, _STD equal_to<_STD _Range_key_type<_Rng>>, _Alloc>;
#endif // _HAS_CXX23 && defined(__cpp_lib_concepts)
#endif // _HAS_CXX17
/*_EXPORT_STD*/ template <class _Kty, class _Ty, class _Hasher, class _Keyeq, class _Alloc>
void swap(unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Left,
unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Right) noexcept(noexcept(_Left.swap(_Right))) {
_Left.swap(_Right);
}
#if _HAS_CXX20
/*_EXPORT_STD*/ template <class _Kty, class _Ty, class _Hasher, class _Keyeq, class _Alloc, class _Pr>
unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>::size_type erase_if(
unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Cont, _Pr _Pred) {
return _STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
#endif // _HAS_CXX20
/*_EXPORT_STD*/ template <class _Kty, class _Ty, class _Hasher, class _Keyeq, class _Alloc>
_NODISCARD bool operator==(const unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Left,
const unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Right) {
return ::geode::stl:: _Hash_equal(_Left, _Right);
}
#if !_HAS_CXX20
template <class _Kty, class _Ty, class _Hasher, class _Keyeq, class _Alloc>
_NODISCARD bool operator!=(const unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Left,
const unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>& _Right) {
return !(_Left == _Right);
}
#endif // !_HAS_CXX20
} // namespace geode::stl
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _GEODE_UNORDERED_MAP_

View file

@ -1,418 +0,0 @@
// unordered_set standard header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// Per Apache License, Version 2.0, Section 4, Point b: I (kynex7510) changed this file.
#ifndef _GEODE_UNORDERED_SET_
#define _GEODE_UNORDERED_SET_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#include "xhash.hpp"
#if _HAS_CXX17
#include <xpolymorphic_allocator.h>
#endif // _HAS_CXX17
#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new
namespace geode::stl {
template <class _Kty, // key type (same as value type)
class _Tr, // comparator predicate type
class _Alloc, // actual allocator type (should be value allocator)
bool _Mfl> // true if multiple equivalent keys are permitted
class _Uset_traits : public _Tr { // traits required to make _Hash behave like a set
public:
using key_type = _Kty;
using value_type = _Kty;
using _Mutable_value_type = _Kty;
using key_compare = _Tr;
using allocator_type = _Alloc;
#if _HAS_CXX17
using node_type = _STD _Node_handle<_STD _List_node<value_type, typename _STD allocator_traits<_Alloc>::void_pointer>, _Alloc,
_STD _Node_handle_set_base, _Kty>;
#endif // _HAS_CXX17
static constexpr bool _Multi = _Mfl;
static constexpr bool _Standard = true;
template <class... _Args>
using _In_place_key_extractor = _STD _In_place_key_extract_set<_Kty, _Args...>;
_Uset_traits() = default;
explicit _Uset_traits(const _Tr& _Traits) noexcept(_STD is_nothrow_copy_constructible_v<_Tr>) : _Tr(_Traits) {}
using value_compare = void; // TRANSITION, remove when _Standard becomes unconditionally true
static const _Kty& _Kfn(const value_type& _Val) noexcept {
return _Val;
}
static int _Nonkfn(const value_type&) noexcept { // extract "non-key" from element value (for container equality)
return 0;
}
};
/* _EXPORT_STD */ template <class _Kty, class _Hasher = _STD hash<_Kty>, class _Keyeq = _STD equal_to<_Kty>,
class _Alloc = allocator<_Kty>>
class unordered_set : public _Hash<_Uset_traits<_Kty, _STD _Uhash_compare<_Kty, _Hasher, _Keyeq>, _Alloc, false>> {
// hash table of key-values, unique keys
public:
static_assert(!_ENFORCE_MATCHING_ALLOCATORS || _STD is_same_v<_Kty, typename _Alloc::value_type>,
_MISMATCHED_ALLOCATOR_MESSAGE("unordered_set<T, Hasher, Eq, Allocator>", "T"));
static_assert(_STD is_object_v<_Kty>, "The C++ Standard forbids containers of non-object types "
"because of [container.requirements].");
private:
using _Mytraits = _STD _Uhash_compare<_Kty, _Hasher, _Keyeq>;
using _Mybase = _Hash<_Uset_traits<_Kty, _Mytraits, _Alloc, false>>;
using _Alnode = typename _Mybase::_Alnode;
using _Alnode_traits = typename _Mybase::_Alnode_traits;
using _Key_compare = typename _Mybase::_Key_compare;
public:
using hasher = _Hasher;
using key_type = _Kty;
using key_equal = _Keyeq;
using value_type = typename _Mybase::value_type;
using allocator_type = typename _Mybase::allocator_type;
using size_type = typename _Mybase::size_type;
using difference_type = typename _Mybase::difference_type;
using pointer = typename _Mybase::pointer;
using const_pointer = typename _Mybase::const_pointer;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = typename _Mybase::iterator;
using const_iterator = typename _Mybase::const_iterator;
using local_iterator = typename _Mybase::iterator;
using const_local_iterator = typename _Mybase::const_iterator;
#if _HAS_CXX17
using insert_return_type = _STD _Insert_return_type<iterator, typename _Mybase::node_type>;
#endif // _HAS_CXX17
unordered_set() : _Mybase(_Key_compare(), allocator_type()) {}
explicit unordered_set(const allocator_type& _Al) : _Mybase(_Key_compare(), _Al) {}
unordered_set(const unordered_set& _Right)
: _Mybase(_Right, _Alnode_traits::select_on_container_copy_construction(_Right._Getal())) {}
unordered_set(const unordered_set& _Right, const allocator_type& _Al) : _Mybase(_Right, _Al) {}
explicit unordered_set(size_type _Buckets) : _Mybase(_Key_compare(), allocator_type()) {
this->rehash(_Buckets);
}
unordered_set(size_type _Buckets, const allocator_type& _Al) : _Mybase(_Key_compare(), _Al) {
this->rehash(_Buckets);
}
unordered_set(size_type _Buckets, const hasher& _Hasharg) : _Mybase(_Key_compare(_Hasharg), allocator_type()) {
this->rehash(_Buckets);
}
unordered_set(size_type _Buckets, const hasher& _Hasharg, const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg), _Al) {
this->rehash(_Buckets);
}
unordered_set(size_type _Buckets, const hasher& _Hasharg, const _Keyeq& _Keyeqarg)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), allocator_type()) {
this->rehash(_Buckets);
}
unordered_set(size_type _Buckets, const hasher& _Hasharg, const _Keyeq& _Keyeqarg, const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), _Al) {
this->rehash(_Buckets);
}
template <class _Iter>
unordered_set(_Iter _First, _Iter _Last) : _Mybase(_Key_compare(), allocator_type()) {
this->insert(_First, _Last);
}
template <class _Iter>
unordered_set(_Iter _First, _Iter _Last, const allocator_type& _Al) : _Mybase(_Key_compare(), _Al) {
this->insert(_First, _Last);
}
template <class _Iter>
unordered_set(_Iter _First, _Iter _Last, size_type _Buckets) : _Mybase(_Key_compare(), allocator_type()) {
this->rehash(_Buckets);
this->insert(_First, _Last);
}
template <class _Iter>
unordered_set(_Iter _First, _Iter _Last, size_type _Buckets, const allocator_type& _Al)
: _Mybase(_Key_compare(), _Al) {
this->rehash(_Buckets);
this->insert(_First, _Last);
}
template <class _Iter>
unordered_set(_Iter _First, _Iter _Last, size_type _Buckets, const hasher& _Hasharg)
: _Mybase(_Key_compare(_Hasharg), allocator_type()) {
this->rehash(_Buckets);
this->insert(_First, _Last);
}
template <class _Iter>
unordered_set(_Iter _First, _Iter _Last, size_type _Buckets, const hasher& _Hasharg, const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg), _Al) {
this->rehash(_Buckets);
this->insert(_First, _Last);
}
template <class _Iter>
unordered_set(_Iter _First, _Iter _Last, size_type _Buckets, const hasher& _Hasharg, const _Keyeq& _Keyeqarg)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), allocator_type()) {
this->rehash(_Buckets);
this->insert(_First, _Last);
}
template <class _Iter>
unordered_set(_Iter _First, _Iter _Last, size_type _Buckets, const hasher& _Hasharg, const _Keyeq& _Keyeqarg,
const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), _Al) {
this->rehash(_Buckets);
this->insert(_First, _Last);
}
#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_set(_STD from_range_t, _Rng&& _Range) : _Mybase(_Key_compare(), allocator_type()) {
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_set(_STD from_range_t, _Rng&& _Range, const allocator_type& _Al) : _Mybase(_Key_compare(), _Al) {
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_set(_STD from_range_t, _Rng&& _Range, size_type _Buckets) : _Mybase(_Key_compare(), allocator_type()) {
_Mybase::rehash(_Buckets);
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_set(_STD from_range_t, _Rng&& _Range, size_type _Buckets, const allocator_type& _Al)
: _Mybase(_Key_compare(), _Al) {
_Mybase::rehash(_Buckets);
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_set(_STD from_range_t, _Rng&& _Range, size_type _Buckets, const hasher& _Hasharg)
: _Mybase(_Key_compare(_Hasharg), allocator_type()) {
_Mybase::rehash(_Buckets);
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_set(_STD from_range_t, _Rng&& _Range, size_type _Buckets, const hasher& _Hasharg, const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg), _Al) {
_Mybase::rehash(_Buckets);
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_set(_STD from_range_t, _Rng&& _Range, size_type _Buckets, const hasher& _Hasharg, const _Keyeq& _Keyeqarg)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), allocator_type()) {
_Mybase::rehash(_Buckets);
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
template <_STD _Container_compatible_range<value_type> _Rng>
unordered_set(_STD from_range_t, _Rng&& _Range, size_type _Buckets, const hasher& _Hasharg, const _Keyeq& _Keyeqarg,
const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), _Al) {
_Mybase::rehash(_Buckets);
this->_Insert_range_unchecked(_RANGES _Ubegin(_Range), _RANGES _Uend(_Range));
}
#endif // _HAS_CXX23 && defined(__cpp_lib_concepts)
unordered_set& operator=(const unordered_set& _Right) {
_Mybase::operator=(_Right);
return *this;
}
unordered_set(unordered_set&& _Right) : _Mybase(_STD move(_Right)) {}
unordered_set(unordered_set&& _Right, const allocator_type& _Al) : _Mybase(_STD move(_Right), _Al) {}
unordered_set& operator=(unordered_set&& _Right) noexcept(_Alnode_traits::is_always_equal::value&&
_STD is_nothrow_move_assignable_v<_Hasher>&& _STD is_nothrow_move_assignable_v<_Keyeq>) {
_Mybase::operator=(_STD move(_Right));
return *this;
}
void swap(unordered_set& _Right) noexcept(noexcept(_Mybase::swap(_Right))) {
_Mybase::swap(_Right);
}
unordered_set(_STD initializer_list<value_type> _Ilist) : _Mybase(_Key_compare(), allocator_type()) {
this->insert(_Ilist);
}
unordered_set(_STD initializer_list<value_type> _Ilist, const allocator_type& _Al) : _Mybase(_Key_compare(), _Al) {
this->insert(_Ilist);
}
unordered_set(_STD initializer_list<value_type> _Ilist, size_type _Buckets) : _Mybase(_Key_compare(), allocator_type()) {
this->rehash(_Buckets);
this->insert(_Ilist);
}
unordered_set(_STD initializer_list<value_type> _Ilist, size_type _Buckets, const allocator_type& _Al)
: _Mybase(_Key_compare(), _Al) {
this->rehash(_Buckets);
this->insert(_Ilist);
}
unordered_set(_STD initializer_list<value_type> _Ilist, size_type _Buckets, const hasher& _Hasharg)
: _Mybase(_Key_compare(_Hasharg), allocator_type()) {
this->rehash(_Buckets);
this->insert(_Ilist);
}
unordered_set(
_STD initializer_list<value_type> _Ilist, size_type _Buckets, const hasher& _Hasharg, const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg), _Al) {
this->rehash(_Buckets);
this->insert(_Ilist);
}
unordered_set(
_STD initializer_list<value_type> _Ilist, size_type _Buckets, const hasher& _Hasharg, const _Keyeq& _Keyeqarg)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), allocator_type()) {
this->rehash(_Buckets);
this->insert(_Ilist);
}
unordered_set(_STD initializer_list<value_type> _Ilist, size_type _Buckets, const hasher& _Hasharg,
const _Keyeq& _Keyeqarg, const allocator_type& _Al)
: _Mybase(_Key_compare(_Hasharg, _Keyeqarg), _Al) {
this->rehash(_Buckets);
this->insert(_Ilist);
}
unordered_set& operator=(_STD initializer_list<value_type> _Ilist) {
this->clear();
this->insert(_Ilist);
return *this;
}
_NODISCARD hasher hash_function() const {
return this->_Traitsobj._Mypair._Get_first();
}
_NODISCARD key_equal key_eq() const {
return this->_Traitsobj._Mypair._Myval2._Get_first();
}
using _Mybase::_Unchecked_begin;
using _Mybase::_Unchecked_end;
};
#if _HAS_CXX17
template <class _Iter, class _Hasher = _STD hash<_STD _Iter_value_t<_Iter>>, class _Keyeq = _STD equal_to<_STD _Iter_value_t<_Iter>>,
class _Alloc = allocator<_STD _Iter_value_t<_Iter>>,
_STD enable_if_t<
_STD conjunction_v<_STD _Is_iterator<_Iter>, _Is_hasher<_Hasher>, _STD negation<_STD _Is_allocator<_Keyeq>>, _STD _Is_allocator<_Alloc>>,
int> = 0>
unordered_set(_Iter, _Iter, _STD _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(), _Alloc = _Alloc())
-> unordered_set<_STD _Iter_value_t<_Iter>, _Hasher, _Keyeq, _Alloc>;
template <class _Kty, class _Hasher = _STD hash<_Kty>, class _Keyeq = _STD equal_to<_Kty>, class _Alloc = allocator<_Kty>,
_STD enable_if_t<_STD conjunction_v<_Is_hasher<_Hasher>, _STD negation<_STD _Is_allocator<_Keyeq>>, _STD _Is_allocator<_Alloc>>, int> = 0>
unordered_set(_STD initializer_list<_Kty>, _STD _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(),
_Alloc = _Alloc()) -> unordered_set<_Kty, _Hasher, _Keyeq, _Alloc>;
template <class _Iter, class _Alloc, _STD enable_if_t<_STD conjunction_v<_STD _Is_iterator<_Iter>, _STD _Is_allocator<_Alloc>>, int> = 0>
unordered_set(_Iter, _Iter, _STD _Guide_size_type_t<_Alloc>, _Alloc)
-> unordered_set<_STD _Iter_value_t<_Iter>, _STD hash<_STD _Iter_value_t<_Iter>>, _STD equal_to<_STD _Iter_value_t<_Iter>>, _Alloc>;
template <class _Iter, class _Hasher, class _Alloc,
_STD enable_if_t<_STD conjunction_v<_STD _Is_iterator<_Iter>, _Is_hasher<_Hasher>, _STD _Is_allocator<_Alloc>>, int> = 0>
unordered_set(_Iter, _Iter, _STD _Guide_size_type_t<_Alloc>, _Hasher, _Alloc)
-> unordered_set<_STD _Iter_value_t<_Iter>, _Hasher, _STD equal_to<_STD _Iter_value_t<_Iter>>, _Alloc>;
template <class _Kty, class _Alloc, _STD enable_if_t<_STD _Is_allocator<_Alloc>::value, int> = 0>
unordered_set(_STD initializer_list<_Kty>, _STD _Guide_size_type_t<_Alloc>, _Alloc)
-> unordered_set<_Kty, _STD hash<_Kty>, _STD equal_to<_Kty>, _Alloc>;
template <class _Kty, class _Hasher, class _Alloc,
_STD enable_if_t<_STD conjunction_v<_Is_hasher<_Hasher>, _STD _Is_allocator<_Alloc>>, int> = 0>
unordered_set(_STD initializer_list<_Kty>, _STD _Guide_size_type_t<_Alloc>, _Hasher, _Alloc)
-> unordered_set<_Kty, _Hasher, _STD equal_to<_Kty>, _Alloc>;
#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395
template <_RANGES input_range _Rng, class _Hasher = _STD hash<_RANGES range_value_t<_Rng>>,
class _Keyeq = _STD equal_to<_RANGES range_value_t<_Rng>>, class _Alloc = allocator<_RANGES range_value_t<_Rng>>,
_STD enable_if_t<_STD conjunction_v<_Is_hasher<_Hasher>, _STD negation<_STD _Is_allocator<_Keyeq>>, _STD _Is_allocator<_Alloc>>, int> = 0>
unordered_set(_STD from_range_t, _Rng&&, _STD _Guide_size_type_t<_Alloc> = 0, _Hasher = _Hasher(), _Keyeq = _Keyeq(),
_Alloc = _Alloc()) -> unordered_set<_RANGES range_value_t<_Rng>, _Hasher, _Keyeq, _Alloc>;
template <_RANGES input_range _Rng, class _Alloc, _STD enable_if_t<_STD _Is_allocator<_Alloc>::value, int> = 0>
unordered_set(_STD from_range_t, _Rng&&, _STD _Guide_size_type_t<_Alloc>, _Alloc) -> unordered_set<_RANGES range_value_t<_Rng>,
_STD hash<_RANGES range_value_t<_Rng>>, _STD equal_to<_RANGES range_value_t<_Rng>>, _Alloc>;
template <_RANGES input_range _Rng, class _Alloc, _STD enable_if_t<_STD _Is_allocator<_Alloc>::value, int> = 0>
unordered_set(_STD from_range_t, _Rng&&, _Alloc) -> unordered_set<_RANGES range_value_t<_Rng>,
_STD hash<_RANGES range_value_t<_Rng>>, _STD equal_to<_RANGES range_value_t<_Rng>>, _Alloc>;
template <_RANGES input_range _Rng, class _Hasher, class _Alloc,
_STD enable_if_t<_STD conjunction_v<_Is_hasher<_Hasher>, _STD _Is_allocator<_Alloc>>, int> = 0>
unordered_set(_STD from_range_t, _Rng&&, _STD _Guide_size_type_t<_Alloc>, _Hasher, _Alloc)
-> unordered_set<_RANGES range_value_t<_Rng>, _Hasher, _STD equal_to<_RANGES range_value_t<_Rng>>, _Alloc>;
#endif // _HAS_CXX23 && defined(__cpp_lib_concepts)
#endif // _HAS_CXX17
/* _EXPORT_STD */ template <class _Kty, class _Hasher, class _Keyeq, class _Alloc>
void swap(unordered_set<_Kty, _Hasher, _Keyeq, _Alloc>& _Left,
unordered_set<_Kty, _Hasher, _Keyeq, _Alloc>& _Right) noexcept(noexcept(_Left.swap(_Right))) {
_Left.swap(_Right);
}
#if _HAS_CXX20
/* _EXPORT_STD */ template <class _Kty, class _Hasher, class _Keyeq, class _Alloc, class _Pr>
unordered_set<_Kty, _Hasher, _Keyeq, _Alloc>::size_type erase_if(
unordered_set<_Kty, _Hasher, _Keyeq, _Alloc>& _Cont, _Pr _Pred) {
return _STD _Erase_nodes_if(_Cont, _STD _Pass_fn(_Pred));
}
#endif // _HAS_CXX20
/* _EXPORT_STD */ template <class _Kty, class _Hasher, class _Keyeq, class _Alloc>
_NODISCARD bool operator==(const unordered_set<_Kty, _Hasher, _Keyeq, _Alloc>& _Left,
const unordered_set<_Kty, _Hasher, _Keyeq, _Alloc>& _Right) {
return geode::stl:: _Hash_equal(_Left, _Right);
}
#if !_HAS_CXX20
template <class _Kty, class _Hasher, class _Keyeq, class _Alloc>
_NODISCARD bool operator!=(const unordered_set<_Kty, _Hasher, _Keyeq, _Alloc>& _Left,
const unordered_set<_Kty, _Hasher, _Keyeq, _Alloc>& _Right) {
return !(_Left == _Right);
}
#endif // !_HAS_CXX20
} // namespace geode::stl
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _GEODE_UNORDERED_SET_

File diff suppressed because it is too large Load diff

View file

@ -1,26 +0,0 @@
#pragma once
#include "msvc/allocator.hpp"
#include "msvc/umap.hpp"
#include "msvc/uset.hpp"
#include <map>
#include <vector>
#include <set>
namespace gd {
template <class T>
using vector = std::vector<T>;
template <class K, class V>
using map = std::map<K, V>;
template <class K, class V>
using unordered_map = geode::stl::unordered_map<K, V, std::hash<K>, std::equal_to<K>, geode::stl::allocator<std::pair<const K, V>>>;
template <class K>
using set = std::set<K>;
template <class K>
using unordered_set = geode::stl::unordered_set<K, std::hash<K>, std::equal_to<K>, geode::stl::allocator<K>>;
}

View file

@ -183,7 +183,7 @@ public:
private:
void getSetOfTouchesEndOrCancel(CCSet& set, int num, int ids[], float xs[], float ys[]);
protected:
public:
EGLTouchDelegate* m_pDelegate;
// real screen size

View file

@ -244,130 +244,4 @@ namespace geode {
virtual ~Event();
};
// template <is_filter F, std::move_constructible T>
// class [[nodiscard]] EventMapper final {
// public:
// using Value = T;
// class Handle final {
// std::optional<EventListener<F>> m_listener;
// class PrivateMarker final {};
// static std::shared_ptr<Handle> create() {
// return std::make_shared<Handle>(PrivateMarker());
// }
// friend class EventMapper;
// public:
// Handle(PrivateMarker) {}
// };
// class Event final : public geode::Event {
// private:
// std::shared_ptr<Handle> m_handle;
// T m_value;
// Event(std::shared_ptr<Handle> handle, T&& value)
// : m_handle(handle), m_value(std::move(value)) {}
// friend class EventMapper;
// public:
// T& getValue() & {
// return m_value;
// }
// T const& getValue() const& {
// return m_value;
// }
// T&& getValue() && {
// return std::move(m_value);
// }
// operator T*() const {
// return m_value;
// }
// T* operator*() const {
// return m_value;
// }
// T* operator->() const {
// return m_value;
// }
// };
// using Mapper = utils::MiniFunction<T(typename F::Event*)>;
// using Callback = void(Event*);
// private:
// EventListenerProtocol* m_listener = nullptr;
// std::shared_ptr<Handle> m_handle;
// EventMapper(std::shared_ptr<Handle> handle) : m_handle(handle) {}
// public:
// EventMapper() : m_handle(nullptr) {}
// static EventMapper immediate(T&& value) {
// auto emapper = EventMapper(Handle::create());
// Loader::get()->queueInMainThread([handle = emapper.m_handle, value = std::move(value)]() mutable {
// EventMapper::Event(handle, std::move(value)).post();
// });
// return emapper;
// }
// static EventMapper create(F&& filter, Mapper&& mapper) {
// auto emapper = EventMapper(Handle::create());
// emapper.m_handle->m_listener.emplace(EventListener(
// // The event listener should not own itself (circular ref = memory leak!!)
// [handle = std::weak_ptr(emapper.m_handle), mapper = std::move(mapper)](F::Event* event) {
// if (auto lock = handle.lock()) {
// EventMapper::Event(lock, mapper(event)).post();
// }
// },
// std::move(filter)
// ));
// return emapper;
// }
// template <class NewMapper>
// auto map(NewMapper&& mapper) {
// using T2 = decltype(mapper(std::declval<T*>()));
// return mapEvent(*this, [mapper = std::move(mapper)](Event* event) -> T2 {
// return mapper(&event->getValue());
// });
// }
// ListenerResult handle(utils::MiniFunction<Callback> fn, Event* e) {
// if (e->m_handle == m_handle) {
// fn(e);
// }
// return ListenerResult::Propagate;
// }
// // todo: i believe alk wanted these to be in their own pool
// EventListenerPool* getPool() const {
// return DefaultEventListenerPool::get();
// }
// void setListener(EventListenerProtocol* listener) {
// m_listener = listener;
// }
// EventListenerProtocol* getListener() const {
// return m_listener;
// }
// };
// template <is_filter F, class Mapper>
// static auto mapEvent(F&& filter, Mapper&& mapper) {
// using T = decltype(mapper(std::declval<typename F::Event*>()));
// return EventMapper<F, T>::create(std::move(filter), std::move(mapper));
// }
// template <is_filter F, class Mapper>
// requires std::copy_constructible<F>
// static auto mapEvent(F const& filter, Mapper&& mapper) {
// using T = decltype(mapper(std::declval<typename F::Event*>()));
// return EventMapper<F, T>::create(F(filter), std::move(mapper));
// }
}

View file

@ -142,8 +142,22 @@ namespace geode {
* @returns The latest available version on the index if there are
* updates for this mod
*/
[[deprecated("Use Mod::checkUpdates instead; this function always returns nullopt")]]
std::optional<VersionInfo> hasAvailableUpdate() const;
using CheckUpdatesTask = Task<Result<std::optional<VersionInfo>, std::string>>;
/**
* Check if this Mod has updates available on the mods index. If
* you're using this for automatic update checking, use
* `openInfoPopup` from the `ui/GeodeUI.hpp` header to open the Mod's
* page to let the user install the update
* @returns A task that resolves to an option, either the latest
* available version on the index if there are updates available, or
* `std::nullopt` if there are no updates. On error, the Task returns
* an error
*/
CheckUpdatesTask checkUpdates() const;
Result<> saveData();
Result<> loadData();

View file

@ -103,7 +103,6 @@ namespace geode {
class FieldIntermediate;
}
// TODO: make ordered
using ModJson = matjson::Value;
}

View file

@ -41,4 +41,11 @@ namespace geode::modifier {
GEODE_AS_STATIC_FUNCTION(constructor)
GEODE_AS_STATIC_FUNCTION(destructor)
#define GEODE_CONCEPT_FUNCTION_CHECK(FunctionName_) \
template <class Class, class... Args> \
concept FunctionExists_##FunctionName_ = requires(Class* self, Args... args) { \
self->FunctionName_(args...); \
};
}

View file

@ -42,6 +42,38 @@
} \
} while (0);
#define GEODE_APPLY_MODIFY_FOR_FUNCTION_ERROR(ClassName_, FunctionName_, ...) \
do { \
static_assert(!FunctionExists_##FunctionName_<Derived __VA_ARGS__>, \
"Function " #ClassName_ "::" #FunctionName_ " does not have an available address in the" \
" bindings, please add it to the bindings to hook it." \
); \
} while (0);
#define GEODE_APPLY_MODIFY_FOR_FUNCTION_ERROR_DEFINED(ClassName_, FunctionName_, ...) \
do { \
static auto constexpr different = Unique::different< \
Resolve<__VA_ARGS__>::func(&Base::FunctionName_), \
Resolve<__VA_ARGS__>::func(&Derived::FunctionName_) \
>(); \
static_assert(!different, \
"Function " #ClassName_ "::" #FunctionName_ " does not have an available address in the" \
" bindings, please add it to the bindings to hook it." \
); \
} while (0);
#define GEODE_APPLY_MODIFY_FOR_FUNCTION_ERROR_INLINE(ClassName_, FunctionName_, ...) \
do { \
static auto constexpr different = Unique::different< \
Resolve<__VA_ARGS__>::func(&Base::FunctionName_), \
Resolve<__VA_ARGS__>::func(&Derived::FunctionName_) \
>(); \
static_assert(!different, \
"Function " #ClassName_ "::" #FunctionName_ " cannot be hooked due to an inline definition" \
" existing for the function." \
); \
} while (0);
#define GEODE_APPLY_MODIFY_FOR_CONSTRUCTOR(AddressInline_, Convention_, ClassName_, ...) \
do { \
if constexpr (HasConstructor<Derived>) { \

View file

@ -82,6 +82,10 @@ namespace geode {
Teal = 6,
Aqua = 7,
Cyan = 8,
Magenta = 9,
DimGreen = 10,
BrightGreen = 11,
Salmon = 12,
};
GEODE_DLL const char* baseEnumToString(EditorBaseColor);

View file

@ -11,6 +11,10 @@ namespace geode {
* Open the info popup for a mod
*/
GEODE_DLL void openInfoPopup(Mod* mod);
/**
* Open the info popup for a mod on the changelog page
*/
GEODE_DLL void openChangelogPopup(Mod* mod);
/**
* Open the issue report popup for a mod
*/
@ -23,6 +27,7 @@ namespace geode {
/**
* Open the store page for a mod (if it exists)
*/
[[deprecated("Will be removed, use openInfoPopup instead")]]
GEODE_DLL void openIndexPopup(Mod* mod);
/**
* Open the settings popup for a mod (if it has any settings)

View file

@ -126,7 +126,6 @@ namespace geode::utils::web {
WebRequest& header(std::string_view name, std::string_view value);
WebRequest& param(std::string_view name, std::string_view value);
template <std::integral T>
WebRequest& param(std::string_view name, T value) {
return this->param(name, std::to_string(value));
@ -251,5 +250,55 @@ namespace geode::utils::web {
* @return WebRequest&
*/
WebRequest& bodyJSON(matjson::Value const& json);
/**
* Gets the request method as a string
*
* @return std::string
*/
std::string getMethod() const;
/**
* Gets the request URL
*
* @return std::string
*/
std::string getUrl() const;
/**
* Gets the request headers
*
* @return std::unordered_map<std::string, std::string>
*/
std::unordered_map<std::string, std::string> getHeaders() const;
/**
* Gets the parameters inside the URL
*
* @return std::unordered_map<std::string, std::string>
*/
std::unordered_map<std::string, std::string> getUrlParams() const;
/**
* Gets the post body stream
*
* @return std::optional<ByteVector>
*/
std::optional<ByteVector> getBody() const;
/**
* Gets the request timeout in seconds
*
* @return std::optional<std::chrono::seconds>
*/
std::optional<std::chrono::seconds> getTimeout() const;
/**
* Gets HTTP versions applied to the request
*
* @return HttpVersion
*/
HttpVersion getHttpVersion() const;
};
}

Binary file not shown.

Before

(image error) Size: 18 KiB

After

(image error) Size: 5.3 KiB

Binary file not shown.

Before

(image error) Size: 20 KiB

After

(image error) Size: 5.3 KiB

Binary file not shown.

Before

(image error) Size: 23 KiB

After

(image error) Size: 6.8 KiB

Binary file not shown.

Before

(image error) Size: 73 KiB

After

(image error) Size: 86 KiB

Binary file not shown.

Before

(image error) Size: 20 KiB

After

(image error) Size: 11 KiB

Binary file not shown.

Before

(image error) Size: 19 KiB

After

(image error) Size: 11 KiB

Binary file not shown.

After

(image error) Size: 12 KiB

Binary file not shown.

Before

(image error) Size: 16 KiB

After

(image error) Size: 12 KiB

Binary file not shown.

Before

(image error) Size: 23 KiB

After

(image error) Size: 12 KiB

Binary file not shown.

Before

(image error) Size: 27 KiB

After

(image error) Size: 17 KiB

Binary file not shown.

Before

(image error) Size: 26 KiB

After

(image error) Size: 17 KiB

Binary file not shown.

Before

(image error) Size: 16 KiB

After

(image error) Size: 11 KiB

Binary file not shown.

Before

(image error) Size: 15 KiB

After

(image error) Size: 11 KiB

Binary file not shown.

Before

(image error) Size: 15 KiB

After

(image error) Size: 9.6 KiB

Binary file not shown.

Before

(image error) Size: 14 KiB

After

(image error) Size: 9.5 KiB

Binary file not shown.

Before

(image error) Size: 13 KiB

After

(image error) Size: 8.6 KiB

Binary file not shown.

Before

(image error) Size: 12 KiB

After

(image error) Size: 8.6 KiB

Binary file not shown.

Before

(image error) Size: 12 KiB

After

(image error) Size: 7.9 KiB

Binary file not shown.

Before

(image error) Size: 12 KiB

After

(image error) Size: 7.9 KiB

Binary file not shown.

Before

(image error) Size: 8.1 KiB

After

(image error) Size: 5.1 KiB

Binary file not shown.

Before

(image error) Size: 7.8 KiB

After

(image error) Size: 5.1 KiB

Binary file not shown.

After

(image error) Size: 2.7 KiB

Binary file not shown.

After

(image error) Size: 2.7 KiB

Binary file not shown.

Before

(image error) Size: 18 KiB

After

(image error) Size: 2.6 KiB

Binary file not shown.

Before

(image error) Size: 17 KiB

After

(image error) Size: 2.6 KiB

Binary file not shown.

After

(image error) Size: 2.7 KiB

Binary file not shown.

Before

(image error) Size: 16 KiB

After

(image error) Size: 2.7 KiB

Binary file not shown.

Before

(image error) Size: 17 KiB

After

(image error) Size: 2.6 KiB

Binary file not shown.

Before

(image error) Size: 18 KiB

After

(image error) Size: 2.7 KiB

Binary file not shown.

After

(image error) Size: 2.8 KiB

Binary file not shown.

Before

(image error) Size: 17 KiB

After

(image error) Size: 2.7 KiB

Binary file not shown.

Before

(image error) Size: 16 KiB

After

(image error) Size: 2.7 KiB

Binary file not shown.

After

(image error) Size: 2.7 KiB

Binary file not shown.

Before

(image error) Size: 15 KiB

After

(image error) Size: 2.6 KiB

View file

@ -0,0 +1,25 @@
<svg width="132" height="138" viewBox="0 0 132 138" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_922_144)">
<rect x="4" y="7" width="124" height="124" rx="20" fill="white"/>
</g>
<rect x="8" y="11" width="116" height="116" rx="16" fill="black"/>
<rect x="12" y="15" width="108" height="108" rx="14" fill="url(#paint0_linear_922_144)"/>
<rect x="17" y="20" width="98" height="98" rx="8" fill="#7ADE2D"/>
<defs>
<filter id="filter0_d_922_144" x="4" y="7" width="128" height="131" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="4" dy="7"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.34 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_922_144"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_922_144" result="shape"/>
</filter>
<linearGradient id="paint0_linear_922_144" x1="12" y1="15" x2="120" y2="123" gradientUnits="userSpaceOnUse">
<stop stop-color="#C6F249"/>
<stop offset="0.495303" stop-color="#C6F249"/>
<stop offset="0.495303" stop-color="#49851B"/>
<stop offset="1" stop-color="#49851B"/>
</linearGradient>
</defs>
</svg>

After

(image error) Size: 1.4 KiB

View file

@ -27,7 +27,30 @@ colors = {
"Cyan": ["#58FDFA", "#13D5EA", "#44F9F6", "#0B9FBE"],
"Blue": ["#1AF1F8", "#0AB4FF", "#23DCFA", "#0077FA"],
"Gray": ["#DEDEE0", "#979997", "#CACCCA", "#747472"],
# "DarkPurple": ["#41384b", "#2f2937", "#393142", "#221e28"],
"DarkPurple": ["#41384b", "#2f2937", "#393142", "#221e28"],
"DarkAqua": ["#2a4559", "#1f3441", "#253d4e", "#17272f"],
}
editor_sizes = [
"Normal",
]
editor_color_from = ["#C6F249", "#7ADE2D", "#49851B"]
editor_colors = {
"Cyan": ["#0effff", "#00d2f6", "#007d94"],
"Blue": ["#82d6ff", "#80a1ff", "#4d60d2"],
"Teal": ["#3cfcbc", "#3cfcbc", "#0f7a68"],
"Magenta": ["#ffafff", "#f67fff", "#944cca"],
"Pink": ["#ff93fd", "#ff6fab", "#d44266"],
"Green": ["#a2f30e", "#58d000", "#347c00"],
"BrightGreen": ["#62ff2a", "#23dc23", "#148414"],
"DimGreen": ["#ace83f", "#6ac227", "#3f7417"],
"Orange": ["#ffd387", "#ffa83f", "#b35d1e"],
"LightBlue": ["#52e8ff", "#4fb1ff", "#2f6ac7"],
"Gray": ["#c8c7c9", "#9b9a9b", "#5c5c5d"],
"DarkGray": ["#9a9a9a", "#717171", "#3a3a3a"],
"Salmon": ["#ffbbb9", "#ff9260", "#e15032"],
}
for size in sizes:
@ -35,8 +58,19 @@ for size in sizes:
svg_base = file.read()
for name, cols in colors.items():
svg = svg_base
out = f"../baseCircle_{size}_{name.title()}.png"
out = f"../baseCircle_{size}_{name}.png"
print(f"Generating {out}")
for color_orig, color_to in zip(color_from, cols):
svg = svg.replace(color_orig, color_to)
subprocess.run(["rsvg-convert", "-o", out], input=svg.encode())
for size in editor_sizes:
with open(f"baseEditor_{size}.svg", "r") as file:
svg_base = file.read()
for name, cols in editor_colors.items():
svg = svg_base
out = f"../baseEditor_{size}_{name}.png"
print(f"Generating {out}")
for color_orig, color_to in zip(editor_color_from, cols):
svg = svg.replace(color_orig, color_to)
subprocess.run(["rsvg-convert", "-o", out], input=svg.encode())

Binary file not shown.

After

(image error) Size: 15 KiB

Binary file not shown.

After

(image error) Size: 33 KiB

View file

@ -13,13 +13,12 @@ using namespace geode::prelude;
// no one knows how this is possible (he passes char* to wchar_t*).
// so anyway, here's a fix for it
static void __cdecl fixedErrorHandler(int code, char const* description) {
static void __cdecl fixedErrorHandler2(int code, char const* description) {
log::error("GLFW Error {}: {}", code, description);
MessageBoxA(
nullptr,
fmt::format(
"GLFWError #{}: {}\nPlease contact the "
"Geode Development Team for more information.",
"GLFWError #{}: {}",
code,
description
)
@ -27,32 +26,37 @@ static void __cdecl fixedErrorHandler(int code, char const* description) {
"OpenGL Error",
MB_ICONERROR
);
std::abort();
}
static void __cdecl fixedErrorHandler(CCEGLView*, int code, char const* description) {
fixedErrorHandler2(code, description);
}
$execute {
// updated for 2.206
// check xrefs to "GLFWError #%d Happen, %s\n", now there's two functions with the same exact
// behaviour, one is a member function though... call ds:MessageBoxW
// patch MessageBoxW to MessageBoxA
// geode::base::getCocos() + 0xe2670 = MessageBoxA in .idata
// geode::base::getCocos() + 0xe26b8 = MessageBoxW in .idata
// behaviour, one is a member function though...
// hook them to call our own handler
if (LoaderImpl::get()->isForwardCompatMode()) return;
#if GEODE_COMP_GD_VERSION == 22060
// in x64 these became rip-relative jmp & call respectively, instead of absolute calls,
// so this code is a bit more complicated than it used to be
const uintptr_t importedMessageBoxA = 0xe2670;
const uintptr_t offset1 = 0x75d00; // member function in CCEGLView
const uintptr_t offset2 = 0x75d60; // static function
const uintptr_t offset1 = 0x75d4a;
const uint32_t rel1 = static_cast<uint32_t>(importedMessageBoxA - offset1 - 7);
(void) Mod::get()->hook(
reinterpret_cast<void*>(geode::base::getCocos() + offset1),
fixedErrorHandler,
"onGLFWError"
);
(void) Mod::get()->patch(reinterpret_cast<void*>(geode::base::getCocos() + offset1 + 3), geode::toByteArray(rel1));
(void) Mod::get()->hook(
reinterpret_cast<void*>(geode::base::getCocos() + offset2),
fixedErrorHandler2,
"onGLFWError2"
);
const uintptr_t offset2 = 0x75daf;
const uint32_t rel2 = static_cast<uint32_t>(importedMessageBoxA - offset2 - 6);
(void) Mod::get()->patch(reinterpret_cast<void*>(geode::base::getCocos() + offset2 + 2), geode::toByteArray(rel2));
#else
#pragma message("Unsupported GD version!")
#endif

View file

@ -384,11 +384,6 @@ void Loader::Impl::buildModGraph() {
}
void Loader::Impl::loadModGraph(Mod* node, bool early) {
if (early && !node->needsEarlyLoad()) {
m_modsToLoad.push_back(node);
return;
}
if (node->hasUnresolvedDependencies()) {
log::debug("{} {} has unresolved dependencies", node->getID(), node->getVersion());
return;
@ -402,9 +397,7 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) {
log::pushNest();
if (node->isEnabled()) {
for (auto const& dep : node->m_impl->m_dependants) {
m_modsToLoad.push_front(dep);
}
log::warn("Mod {} already loaded, this should never happen", node->getID());
log::popNest();
return;
}
@ -434,10 +427,6 @@ void Loader::Impl::loadModGraph(Mod* node, bool early) {
m_refreshingModCount -= 1;
return;
}
for (auto const& dep : node->m_impl->m_dependants) {
m_modsToLoad.push_front(dep);
}
}
m_refreshingModCount -= 1;
@ -702,11 +691,18 @@ void Loader::Impl::refreshModGraph() {
this->buildModGraph();
log::popNest();
log::debug("Ordering mod stack");
log::pushNest();
this->orderModStack();
log::popNest();
m_loadingState = LoadingState::EarlyMods;
log::debug("Loading early mods");
log::pushNest();
for (auto const& dep : ModImpl::get()->m_dependants) {
this->loadModGraph(dep, true);
while (!m_modsToLoad.empty() && m_modsToLoad.front()->needsEarlyLoad()) {
auto mod = m_modsToLoad.front();
m_modsToLoad.pop_front();
this->loadModGraph(mod, true);
}
log::popNest();
@ -716,16 +712,60 @@ void Loader::Impl::refreshModGraph() {
log::popNest();
if (m_modsToLoad.empty())
m_loadingState = LoadingState::Problems;
else
m_loadingState = LoadingState::Mods;
m_loadingState = LoadingState::Mods;
queueInMainThread([&]() {
this->continueRefreshModGraph();
});
}
void Loader::Impl::orderModStack() {
std::unordered_set<Mod*> visited;
visited.insert(Mod::get());
Mod* selectedMod = nullptr;
do {
selectedMod = nullptr;
for (auto const& mod : ModImpl::get()->m_dependants) {
if (visited.count(mod) != 0) continue;
for (auto dep : mod->getMetadata().getDependencies()) {
if (dep.mod && dep.importance == ModMetadata::Dependency::Importance::Required &&
visited.count(dep.mod) == 0) {
// the dependency is not visited yet
// so we cant select this mod
goto skip_mod;
}
}
if (selectedMod) {
if (
!selectedMod->m_impl->needsEarlyLoad() &&
mod->m_impl->needsEarlyLoad()
) {
// this mod is implied to be loaded early
// so we can override a mod that is not
selectedMod = mod;
}
}
else {
selectedMod = mod;
}
skip_mod:
continue;
}
if (selectedMod) {
m_modsToLoad.push_back(selectedMod);
visited.insert(selectedMod);
}
} while (selectedMod != nullptr);
for (auto mod : m_modsToLoad) {
log::debug("{}, early: {}", mod->getID(), mod->needsEarlyLoad());
}
}
void Loader::Impl::continueRefreshModGraph() {
if (m_refreshingModCount != 0) {
queueInMainThread([&]() {

View file

@ -22,7 +22,6 @@
#include <queue>
#include <tulip/TulipHook.hpp>
// TODO: Find a file convention for impl headers
namespace geode {
static constexpr std::string_view LAUNCH_ARG_PREFIX = "--geode:";
@ -100,6 +99,7 @@ namespace geode {
void queueMods(std::vector<ModMetadata>& modQueue);
void populateModList(std::vector<ModMetadata>& modQueue);
void buildModGraph();
void orderModStack();
void loadModGraph(Mod* node, bool early);
void findProblems();
void refreshModGraph();

View file

@ -4,6 +4,7 @@
#include <Geode/loader/Mod.hpp>
#include <optional>
#include <string_view>
#include <server/Server.hpp>
using namespace geode::prelude;
@ -101,17 +102,30 @@ std::vector<Mod*> Mod::getDependants() const {
#endif
std::optional<VersionInfo> Mod::hasAvailableUpdate() const {
// TODO
// if (auto item = Index::get()->getItem(this->getID(), std::nullopt)) {
// if (
// item->getMetadata().getVersion() > this->getVersion() &&
// item->getAvailablePlatforms().contains(GEODE_PLATFORM_TARGET)
// ) {
// return item->getMetadata().getVersion();
// }
// }
return std::nullopt;
}
Mod::CheckUpdatesTask Mod::checkUpdates() const {
return server::checkUpdates(this).map(
[](auto* result) -> Mod::CheckUpdatesTask::Value {
if (result->isOk()) {
if (auto value = result->unwrap()) {
if (value->replacement) {
return Err(
"Mod has been replaced by {} - please visit the Geode "
"menu to install the replacement",
value->replacement->id
);
}
return Ok(value->version);
}
return Ok(std::nullopt);
}
auto err = result->unwrapErr();
return Err("{} (code {})", err.details, err.code);
},
[](auto*) { return std::monostate(); }
);
}
Result<> Mod::saveData() {
return m_impl->saveData();

View file

@ -140,7 +140,7 @@ matjson::Value& Mod::Impl::getSavedSettingsData() {
}
bool Mod::Impl::isEnabled() const {
return m_enabled;
return m_enabled || this->isInternal();
}
bool Mod::Impl::isInternal() const {
@ -148,11 +148,11 @@ bool Mod::Impl::isInternal() const {
}
bool Mod::Impl::needsEarlyLoad() const {
auto deps = m_dependants;
return getMetadata().needsEarlyLoad() ||
!deps.empty() && std::any_of(deps.begin(), deps.end(), [&](auto& item) {
return item->needsEarlyLoad();
});
if (this->getMetadata().needsEarlyLoad()) return true;
for (auto& dep : m_dependants) {
if (dep->needsEarlyLoad()) return true;
}
return false;
}
std::vector<Hook*> Mod::Impl::getHooks() const {
@ -800,7 +800,7 @@ void Mod::Impl::setLoggingEnabled(bool enabled) {
}
bool Mod::Impl::shouldLoad() const {
return Mod::get()->getSavedValue<bool>("should-load-" + m_metadata.getID(), true);
return Mod::get()->getSavedValue<bool>("should-load-" + m_metadata.getID(), true) || this->isInternal();
}
bool Mod::Impl::isCurrentlyLoading() const {

View file

@ -91,8 +91,36 @@ static Mod* modFromAddress(PVOID exceptionAddress) {
return nullptr;
}
PVOID GeodeFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase);
typedef union _UNWIND_CODE {
struct {
uint8_t CodeOffset;
uint8_t UnwindOp : 4;
uint8_t OpInfo : 4;
};
uint16_t FrameOffset;
} UNWIND_CODE, *PUNWIND_CODE;
typedef struct _UNWIND_INFO {
uint8_t Version : 3;
uint8_t Flags : 5;
uint8_t SizeOfProlog;
uint8_t CountOfCodes;
uint8_t FrameRegister : 4;
uint8_t FrameOffset : 4;
UNWIND_CODE UnwindCode[1];
/* UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
* union {
* OPTIONAL ULONG ExceptionHandler;
* OPTIONAL ULONG FunctionEntry;
* };
* OPTIONAL ULONG ExceptionData[]; */
} UNWIND_INFO, *PUNWIND_INFO;
static void printAddr(std::ostream& stream, void const* addr, bool fullPath = true) {
HMODULE module = nullptr;
auto proc = GetCurrentProcess();
if (GetModuleHandleEx(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
@ -114,12 +142,26 @@ static void printAddr(std::ostream& stream, void const* addr, bool fullPath = tr
symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFO);
symbolInfo->MaxNameLen = MAX_SYM_NAME;
auto proc = GetCurrentProcess();
if (SymFromAddr(
proc, static_cast<DWORD64>(reinterpret_cast<uintptr_t>(addr)), &displacement,
symbolInfo
)) {
if (auto entry = SymFunctionTableAccess64(proc, static_cast<DWORD64>(reinterpret_cast<uintptr_t>(addr)))) {
auto moduleBase = SymGetModuleBase64(proc, static_cast<DWORD64>(reinterpret_cast<uintptr_t>(addr)));
auto runtimeFunction = static_cast<PRUNTIME_FUNCTION>(entry);
auto unwindInfo = reinterpret_cast<PUNWIND_INFO>(moduleBase + runtimeFunction->UnwindInfoAddress);
// This is a chain of unwind info structures, so we traverse back to the first one
while (unwindInfo->Flags & UNW_FLAG_CHAININFO) {
runtimeFunction = (PRUNTIME_FUNCTION)&(unwindInfo->UnwindCode[( unwindInfo->CountOfCodes + 1 ) & ~1]);
unwindInfo = reinterpret_cast<PUNWIND_INFO>(moduleBase + runtimeFunction->UnwindInfoAddress);
}
if (moduleBase + runtimeFunction->BeginAddress != symbolInfo->Address) {
// the symbol address is not the same as the function address
return;
}
}
stream << " (" << std::string(symbolInfo->Name, symbolInfo->NameLen) << " + "
<< displacement;
@ -141,11 +183,13 @@ static void printAddr(std::ostream& stream, void const* addr, bool fullPath = tr
}
else {
stream << addr;
if (GeodeFunctionTableAccess64(proc, reinterpret_cast<DWORD64>(addr))) {
stream << " (Hook handler)";
}
}
}
PVOID GeodeFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase);
// https://stackoverflow.com/a/50208684/9124836
static std::string getStacktrace(PCONTEXT context, Mod*& suspectedFaultyMod) {
std::stringstream stream;

View file

@ -1,65 +0,0 @@
#include "../../c++stl/msvc/allocator.hpp"
#include "../../c++stl/string-impl.hpp"
static auto constexpr NEW_SYM = "??2@YAPAXI@Z";
static auto constexpr DELETE_SYM = "??3@YAXPAX@Z";
static void* getFn(const char* sym) {
auto msvcr = GetModuleHandleW(L"MSVCR120.dll");
if (msvcr != NULL)
return reinterpret_cast<void*>(GetProcAddress(msvcr, sym));
return nullptr;
}
void* geode::stl::operatorNew(size_t size) {
static auto fnPtr = reinterpret_cast<void*(*)(size_t)>(getFn(NEW_SYM));
return fnPtr(size);
}
void geode::stl::operatorDelete(void* ptr) {
static auto fnPtr = reinterpret_cast<void(*)(void*)>(getFn(DELETE_SYM));
return fnPtr(ptr);
}
namespace geode::stl {
void StringImpl::setEmpty() {
data.m_size = 0;
data.m_capacity = 15;
data.m_smallStorage[0] = 0;
}
void StringImpl::free() {
if (data.m_capacity > 15) {
delete data.m_bigStorage;
}
}
char* StringImpl::getStorage() {
return data.m_capacity <= 15 ? data.m_smallStorage.data() : data.m_bigStorage;
}
void StringImpl::setStorage(const std::string_view str) {
data.m_size = data.m_capacity = str.size();
if (str.size() <= 15) {
data.m_capacity = 15;
} else {
data.m_bigStorage = static_cast<char*>(operator new(str.size() + 1));
}
std::memcpy(getStorage(), str.data(), str.size());
getStorage()[str.size()] = 0;
}
size_t StringImpl::getSize() {
return data.m_size;
}
void StringImpl::setSize(size_t size) {
data.m_size = size;
}
size_t StringImpl::getCapacity() {
return data.m_capacity;
}
void StringImpl::setCapacity(size_t cap) {
data.m_capacity = cap;
}
}

View file

@ -770,7 +770,7 @@ ServerRequest<std::unordered_set<std::string>> server::getTags(bool useCache) {
);
}
ServerRequest<std::optional<ServerModUpdate>> server::checkUpdates(Mod* mod) {
ServerRequest<std::optional<ServerModUpdate>> server::checkUpdates(Mod const* mod) {
return checkAllUpdates().map(
[mod](Result<std::vector<ServerModUpdate>, ServerError>* result) -> Result<std::optional<ServerModUpdate>, ServerError> {
if (result->isOk()) {

View file

@ -150,7 +150,7 @@ namespace server {
ServerRequest<ByteVector> getModLogo(std::string const& id, bool useCache = true);
ServerRequest<std::unordered_set<std::string>> getTags(bool useCache = true);
ServerRequest<std::optional<ServerModUpdate>> checkUpdates(Mod* mod);
ServerRequest<std::optional<ServerModUpdate>> checkUpdates(Mod const* mod);
ServerRequest<std::vector<ServerModUpdate>> checkAllUpdates(bool useCache = true);
void clearServerCaches(bool clearGlobalCaches = false);

View file

@ -66,12 +66,17 @@ void geode::openSupportPopup(ModMetadata const& metadata) {
}
void geode::openInfoPopup(Mod* mod) {
// TODO
// LocalModInfoPopup::create(mod, nullptr)->show();
ModPopup::create(mod)->show();
}
void geode::openIndexPopup(Mod* mod) {
// deprecated func
openInfoPopup(mod);
}
void geode::openIndexPopup(Mod* mod) {
ModPopup::create(mod)->show();
void geode::openChangelogPopup(Mod* mod) {
auto popup = ModPopup::create(mod);
popup->loadTab(ModPopup::Tab::Changelog);
popup->show();
}
void geode::openSettingsPopup(Mod* mod) {

View file

@ -20,7 +20,7 @@ $on_mod(Loaded) {
ColorProvider::get()->define("mod-list-tab-deselected-bg"_spr, { 26, 24, 29, 255 });
ColorProvider::get()->define("mod-list-tab-selected-bg"_spr, { 168, 147, 185, 255 });
ColorProvider::get()->define("mod-list-tab-selected-bg-alt"_spr, { 147, 163, 185, 255 });
ColorProvider::get()->define("mod-list-featured-color"_spr, { 255, 255, 120, 255 });
ColorProvider::get()->define("mod-list-featured-color"_spr, { 240, 211, 42, 255 });
ColorProvider::get()->define("mod-list-enabled"_spr, { 120, 255, 100, 255 });
ColorProvider::get()->define("mod-list-disabled"_spr, { 255, 120, 100, 255 });
ColorProvider::get()->define("mod-list-recommended-bg"_spr, ccc3(25, 255, 167));
@ -28,6 +28,7 @@ $on_mod(Loaded) {
ColorProvider::get()->define("mod-list-recommended-by-2"_spr, ccc3(47, 255, 255));
ColorProvider::get()->define("mod-problems-item-bg"_spr, { 255, 255, 255, 15 });
ColorProvider::get()->define("mod-developer-item-bg"_spr, { 255, 255, 255, 15 });
ColorProvider::get()->define("mod-list-paid-color"_spr, { 0, 255, 63, 255 });
// Only used when GD theme is active
ColorProvider::get()->define("mods-layer-gd-bg"_spr, { 0, 102, 255, 255 });

View file

@ -53,6 +53,7 @@ bool ModItem::init(ModSource&& source) {
m_titleLabel = CCLabelBMFont::create(m_source.getMetadata().getName().c_str(), "bigFont.fnt");
m_titleLabel->setID("title-label");
m_titleLabel->setLayoutOptions(AxisLayoutOptions::create()->setScalePriority(1));
m_titleContainer->addChild(m_titleLabel);
m_versionLabel = CCLabelBMFont::create("", "bigFont.fnt");
@ -182,16 +183,14 @@ bool ModItem::init(ModSource&& source) {
},
[this](server::ServerModMetadata const& metadata) {
if (metadata.featured) {
auto starBG = CCScale9Sprite::createWithSpriteFrameName("GJ_colorBtn_001.png");
starBG->setContentSize({ 50, 38 });
starBG->setColor(to3B(ColorProvider::get()->color("mod-list-featured-color"_spr)));
starBG->setOpacity(45);
auto star = CCSprite::createWithSpriteFrameName("GJ_starsIcon_001.png");
starBG->addChildAtPosition(star, Anchor::Center);
starBG->setID("star-bg");
m_titleContainer->addChild(starBG);
auto star = CCSprite::createWithSpriteFrameName("tag-featured.png"_spr);
star->setLayoutOptions(AxisLayoutOptions::create()->setScaleLimits(.1f, .8f));
m_titleContainer->addChild(star);
}
if (metadata.tags.contains("paid")) {
auto paidModLabel = CCSprite::createWithSpriteFrameName("tag-paid.png"_spr);
paidModLabel->setLayoutOptions(AxisLayoutOptions::create()->setScaleLimits(.1f, .8f));
m_titleContainer->addChild(paidModLabel);
}
// Show mod download count here already so people can make informed decisions
@ -338,9 +337,15 @@ void ModItem::updateState() {
[this](server::ServerModMetadata const& metadata) {
m_bg->setColor(isGeodeTheme() ? ccWHITE : ccBLACK);
m_bg->setOpacity(isGeodeTheme() ? 25 : 90);
if (metadata.tags.contains("paid")) {
m_bg->setColor("mod-list-paid-color"_cc3b);
m_bg->setOpacity(55);
}
if (isGeodeTheme() && metadata.featured) {
m_bg->setColor("mod-list-featured-color"_cc3b);
m_bg->setOpacity(40);
m_bg->setOpacity(65);
}
},
[this](ModSuggestion const& suggestion) {
@ -449,6 +454,22 @@ void ModItem::onCheckUpdates(typename server::ServerRequest<std::optional<server
}
void ModItem::onView(CCObject*) {
// This is a local static and not a mod saved value because we might want
// to periodically remind users that paid mods are paid
static bool shownPaidNotif = false;
if (m_source.asServer() && m_source.asServer()->tags.contains("paid") && !shownPaidNotif) {
shownPaidNotif = true;
return FLAlertLayer::create(
nullptr,
"Paid Content",
"This mod contains <cg>Paid Content</c>. This means that some or all "
"features of the mod <cj>require money to use</c>.\n\n"
"<cy>Geode does not handle any payments. The mod handles all transactions in their own way.</c>\n\n"
"<cp>The paid content may not be available in your country.</c>",
"OK", nullptr, 360
)->show();
}
// Always open up the popup for the installed mod page if that is possible
ModPopup::create(m_source.convertForPopup())->show();
}

View file

@ -19,6 +19,11 @@ bool ConfirmUninstallPopup::setup(Mod* mod) {
deleteDataLabel->setScale(.35f);
m_buttonMenu->addChildAtPosition(deleteDataLabel, Anchor::Center, ccp(-70, -15), ccp(0, .5f));
if (mod->isInternal()) {
deleteDataLabel->setString("Delete ALL mods and their save data");
deleteDataLabel->setScale(0.275f);
}
m_deleteDataToggle = CCMenuItemToggler::createWithStandardSprites(this, nullptr, .6f);
m_buttonMenu->addChildAtPosition(m_deleteDataToggle, Anchor::Center, ccp(-88, -15));

View file

@ -648,9 +648,12 @@ void ModPopup::updateState() {
if (asMod && asMod->isInternal()) {
m_enableBtn->setVisible(false);
// you can uninstall loader ingame just fine on windows
#if !defined(GEODE_IS_WINDOWS)
m_uninstallBtn->setVisible(false);
m_installStatusLabel->setString("N/A");
m_installStatusLabel->setVisible(true);
#endif
}
auto download = server::ModDownloadManager::get()->getDownload(m_source.getID());

View file

@ -10,13 +10,14 @@
using namespace geode::prelude;
class ModPopup : public GeodePopup<ModSource&&> {
protected:
public:
enum class Tab {
Details,
Changelog,
Versions,
};
protected:
ModSource m_source;
CCNode* m_stats;
CCNode* m_tags;
@ -51,7 +52,6 @@ protected:
void onLoadTags(typename server::ServerRequest<std::unordered_set<std::string>>::Event* event);
void onCheckUpdates(typename server::ServerRequest<std::optional<server::ServerModUpdate>>::Event* event);
void loadTab(Tab tab);
void onTab(CCObject* sender);
void onEnable(CCObject*);
void onInstall(CCObject*);
@ -63,5 +63,6 @@ protected:
void onSupport(CCObject*);
public:
void loadTab(Tab tab);
static ModPopup* create(ModSource&& src);
};

View file

@ -95,6 +95,10 @@ const char* geode::baseEnumToString(EditorBaseColor value) {
case EditorBaseColor::Teal: return "Teal";
case EditorBaseColor::Aqua: return "Aqua";
case EditorBaseColor::Cyan: return "Cyan";
case EditorBaseColor::Magenta: return "Magenta";
case EditorBaseColor::DimGreen: return "DimGreen";
case EditorBaseColor::BrightGreen: return "BrightGreen";
case EditorBaseColor::Salmon: return "Salmon";
}
return "Unknown";
}

View file

@ -335,24 +335,45 @@ struct MDParser {
renderer->popDecoFlags();
renderer->popColor();
}
else if (s_lastImage.size()) {
else if (!s_lastImage.empty()) {
bool isFrame = false;
std::vector<std::string> imgArguments = utils::string::split(s_lastImage, "&");
s_lastImage = imgArguments.at(0);
const auto splitOnce = [](const std::string& str, char delim) -> std::pair<std::string, std::string> {
const auto pos = str.find(delim);
if (pos == std::string::npos) {
return { str, {} };
}
return { str.substr(0, pos), str.substr(pos + 1) };
};
imgArguments.erase(imgArguments.begin()); //remove the image path
// key value pair of arguments
std::vector<std::pair<std::string, std::string>> imgArguments;
auto split = splitOnce(s_lastImage, '?');
s_lastImage = split.first;
// TODO: remove this in v4.0.0
// check if this image is using the old format "my.mod/image.png&scale:0.5"
// this will be deprecated and then removed in the future
if (utils::string::contains(s_lastImage, "&")) {
split = splitOnce(s_lastImage, '&');
s_lastImage = split.first;
imgArguments = ranges::map<decltype(imgArguments)>(utils::string::split(split.second, "&"), [&](auto str) {
return splitOnce(str, ':');
});
} else {
// new format "my.mod/image.png?scale=0.5"
imgArguments = ranges::map<decltype(imgArguments)>(utils::string::split(split.second, "&"), [&](auto str) {
return splitOnce(str, '=');
});
}
float spriteScale = 1.0f;
for(std::string arg : imgArguments){
if(utils::string::startsWith(arg, "scale:")){
std::string scaleValue = arg.substr(arg.find(":") + 1);
std::stringstream s(scaleValue);
float scale;
if (s >> scale) { //if valid float, put into spriteScale
spriteScale = scale;
for (auto [key, value] : imgArguments) {
if (key == "scale") {
auto scaleRes = utils::numFromString<float>(value);
if (scaleRes) {
spriteScale = *scaleRes;
}
}
}
@ -368,7 +389,7 @@ struct MDParser {
else {
spr = CCSprite::create(s_lastImage.c_str());
}
if (spr) {
if (spr && spr->getUserObject("geode.texture-loader/fallback") == nullptr) {
spr->setScale(spriteScale);
renderer->renderNode(spr);
}

View file

@ -70,7 +70,7 @@ bool TextInput::init(float width, std::string const& placeholder, std::string co
m_bgSprite->setContentSize({ width * 2, HEIGHT * 2 });
this->addChildAtPosition(m_bgSprite, Anchor::Center);
m_input = CCTextInputNode::create(width, HEIGHT, placeholder.c_str(), 24, font.c_str());
m_input = CCTextInputNode::create(width - 10.f, HEIGHT, placeholder.c_str(), 24, font.c_str());
m_input->setLabelPlaceholderColor({ 150, 150, 150 });
m_input->setLabelPlaceholderScale(.5f);
m_input->setMaxLabelScale(.6f);
@ -132,9 +132,12 @@ void TextInput::setPasswordMode(bool enable) {
m_input->refreshLabel();
}
void TextInput::setWidth(float width) {
m_input->m_maxLabelWidth = width;
m_input->setContentWidth(width * 2);
this->setContentWidth(width);
m_input->m_maxLabelWidth = width - 10.f;
m_input->setContentWidth(width);
m_bgSprite->setContentWidth(width * 2);
m_input->setPositionX(width / 2.f);
m_bgSprite->setPositionX(width / 2.f);
}
void TextInput::setDelegate(TextInputDelegate* delegate, std::optional<int> tag) {
m_input->m_delegate = delegate;

View file

@ -279,9 +279,9 @@ WebTask WebRequest::send(std::string_view method, std::string_view url) {
// Add parameters to the URL and pass it to curl
auto url = impl->m_url;
bool first = true;
for (auto param : impl->m_urlParameters) {
url += (first ? "?" : "&") + urlParamEncode(param.first) + "=" + urlParamEncode(param.second);
bool first = url.find('?') == std::string::npos;
for (auto& [key, value] : impl->m_urlParameters) {
url += (first ? "?" : "&") + urlParamEncode(key) + "=" + urlParamEncode(value);
first = false;
}
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
@ -306,6 +306,7 @@ WebTask WebRequest::send(std::string_view method, std::string_view url) {
} else if (impl->m_method == "POST") {
// curl_easy_perform would freeze on a POST request with no fields, so set it to an empty string
// why? god knows
// SMJS: because the stream isn't complete without a body according to the spec
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
}
@ -470,13 +471,39 @@ WebTask WebRequest::patch(std::string_view url) {
}
WebRequest& WebRequest::header(std::string_view name, std::string_view value) {
if (name == "User-Agent") {
userAgent(value);
return *this;
} if (name == "Accept-Encoding") {
acceptEncoding(value);
return *this;
} if (name == "Keep-Alive") {
const size_t timeoutPos = value.find("timeout");
if (timeoutPos != std::string::npos) {
// At this point idc what happens if I get NPOS or string ends, you shouldn't custom format a spec header
const size_t numStart = value.find('=', timeoutPos) + 1;
const size_t comma = value.find(',', numStart);
const size_t numLength = (comma == std::string::npos ? value.size() : comma) - numStart;
timeout(std::chrono::seconds(std::stol(std::string(value.substr(numStart, numLength)))));
return *this;
}
}
m_impl->m_headers.insert_or_assign(std::string(name), std::string(value));
return *this;
}
WebRequest& WebRequest::param(std::string_view name, std::string_view value) {
m_impl->m_urlParameters.insert_or_assign(std::string(name), std::string(value));
return *this;
}
WebRequest& WebRequest::userAgent(std::string_view name) {
m_impl->m_userAgent = name;
return *this;
@ -540,3 +567,31 @@ WebRequest& WebRequest::bodyJSON(matjson::Value const& json) {
m_impl->m_body = ByteVector { str.begin(), str.end() };
return *this;
}
std::string WebRequest::getMethod() const {
return m_impl->m_method;
}
std::string WebRequest::getUrl() const {
return m_impl->m_url;
}
std::unordered_map<std::string, std::string> WebRequest::getHeaders() const {
return m_impl->m_headers;
}
std::unordered_map<std::string, std::string> WebRequest::getUrlParams() const {
return m_impl->m_urlParameters;
}
std::optional<ByteVector> WebRequest::getBody() const {
return m_impl->m_body;
}
std::optional<std::chrono::seconds> WebRequest::getTimeout() const {
return m_impl->m_timeout;
}
HttpVersion WebRequest::getHttpVersion() const {
return m_impl->m_httpVersion;
}