├── examples ├── exe │ ├── .sun │ ├── message.hpp │ ├── message.cpp │ └── main.cpp ├── subdirs │ ├── .sun │ └── src │ │ └── dont_do_this.cpp ├── lib │ ├── .sun │ ├── message.hpp │ └── message.cpp ├── dll │ ├── .sun │ ├── foolib │ │ ├── .sun │ │ ├── foolib.hpp │ │ └── foolib.cpp │ └── consumer.cpp └── exe-lib │ ├── .sun │ └── main.cpp ├── Sun ├── vendor │ └── Soup │ │ ├── soup │ │ ├── .sun │ │ ├── type_traits.hpp │ │ ├── deleter.hpp │ │ ├── RngInterface.hpp │ │ ├── SelfDeletingThread.hpp │ │ ├── StringMatch.hpp │ │ ├── Capture.cpp │ │ ├── memory.hpp │ │ ├── Optional.hpp │ │ ├── rand.cpp │ │ ├── Exception.hpp │ │ ├── _update.php │ │ ├── StringWriter.hpp │ │ ├── base.cpp │ │ ├── StringBuilder.hpp │ │ ├── filesystem.hpp │ │ ├── PoppedNode.hpp │ │ ├── type.hpp │ │ ├── LcgRng.hpp │ │ ├── macros.hpp │ │ ├── StringLiteral.hpp │ │ ├── IntStruct.hpp │ │ ├── math.hpp │ │ ├── main.hpp │ │ ├── SharedLibrary.hpp │ │ ├── main.cpp │ │ ├── StringMatch.cpp │ │ ├── Thread.hpp │ │ ├── TransientToken.hpp │ │ ├── Compiler.hpp │ │ ├── SharedLibrary.cpp │ │ ├── HardwareRng.hpp │ │ ├── os.hpp │ │ ├── AtomicStack.hpp │ │ ├── ShortString.hpp │ │ ├── joaat.cpp │ │ ├── UniquePtr.hpp │ │ ├── HardwareRng.cpp │ │ ├── format.hpp │ │ ├── CpuInfo.hpp │ │ ├── Capture.hpp │ │ ├── filesystem.cpp │ │ ├── rand.hpp │ │ ├── Thread.cpp │ │ ├── joaat.hpp │ │ ├── Endian.hpp │ │ ├── fwd.hpp │ │ ├── unicode.hpp │ │ ├── ObfusString.hpp │ │ ├── string.cpp │ │ ├── console.hpp │ │ ├── Callback.hpp │ │ ├── Compiler.cpp │ │ ├── bitutil.hpp │ │ ├── unicode.cpp │ │ ├── CpuInfo.cpp │ │ ├── base.hpp │ │ ├── SharedPtr.hpp │ │ ├── Writer.hpp │ │ ├── ioBase.hpp │ │ ├── Reader.hpp │ │ └── os.cpp │ │ ├── LICENCE │ │ ├── build_lib.php │ │ └── build_common.php ├── .sun └── Sun.vcxproj.filters ├── .chocogen.json ├── .gitignore ├── README.md ├── docs ├── Building.md └── Config (.sun file).md ├── LICENCE ├── test.php ├── Sun.sln └── .github └── workflows └── build.yml /examples/exe/.sun: -------------------------------------------------------------------------------- 1 | +*.cpp 2 | -------------------------------------------------------------------------------- /examples/subdirs/.sun: -------------------------------------------------------------------------------- 1 | +*.cpp -R 2 | -------------------------------------------------------------------------------- /examples/lib/.sun: -------------------------------------------------------------------------------- 1 | +*.cpp 2 | static 3 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/.sun: -------------------------------------------------------------------------------- 1 | +*.cpp 2 | static 3 | -------------------------------------------------------------------------------- /examples/dll/.sun: -------------------------------------------------------------------------------- 1 | +*.cpp 2 | require foolib 3 | -------------------------------------------------------------------------------- /examples/dll/foolib/.sun: -------------------------------------------------------------------------------- 1 | +*.cpp 2 | dynamic 3 | -------------------------------------------------------------------------------- /examples/exe-lib/.sun: -------------------------------------------------------------------------------- 1 | require ../lib 2 | +*.cpp 3 | -------------------------------------------------------------------------------- /examples/exe/message.hpp: -------------------------------------------------------------------------------- 1 | extern const char* message; -------------------------------------------------------------------------------- /examples/lib/message.hpp: -------------------------------------------------------------------------------- 1 | extern const char* message; -------------------------------------------------------------------------------- /.chocogen.json: -------------------------------------------------------------------------------- 1 | { 2 | "path": ["bin/Release/Sun.exe"] 3 | } -------------------------------------------------------------------------------- /examples/exe/message.cpp: -------------------------------------------------------------------------------- 1 | const char* message = "Hello, world!"; -------------------------------------------------------------------------------- /examples/lib/message.cpp: -------------------------------------------------------------------------------- 1 | const char* message = "Hello, world!"; -------------------------------------------------------------------------------- /Sun/.sun: -------------------------------------------------------------------------------- 1 | name Sun 2 | +*.cpp 3 | require vendor/Soup/soup include_dir=vendor/Soup 4 | -------------------------------------------------------------------------------- /examples/subdirs/src/dont_do_this.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | printf("Hello, world!\n"); 6 | } 7 | -------------------------------------------------------------------------------- /examples/exe-lib/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "message.hpp" 4 | 5 | int main() 6 | { 7 | std::cout << message << "\n"; 8 | } 9 | -------------------------------------------------------------------------------- /examples/exe/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "message.hpp" 4 | 5 | int main() 6 | { 7 | std::cout << message << "\n"; 8 | } 9 | -------------------------------------------------------------------------------- /examples/dll/consumer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "foolib/foolib.hpp" 4 | 5 | int main() 6 | { 7 | std::cout << foo() << "\n"; 8 | } 9 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/type_traits.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define SOUP_RESTRICT(...) std::enable_if_t<(__VA_ARGS__), int> = 0 6 | -------------------------------------------------------------------------------- /examples/dll/foolib/foolib.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef _WIN32 4 | #define DLLEXPORT __declspec(dllexport) 5 | #else 6 | #define DLLEXPORT __attribute__ ((visibility ("default"))) 7 | #endif 8 | 9 | DLLEXPORT const char* foo(); 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | bin/ 3 | *.dll 4 | *.exe 5 | *.lib 6 | *.exp 7 | *.o 8 | *.nupkg 9 | *.a 10 | *.so 11 | *.vcxproj.user 12 | # Linux 13 | suncli 14 | Sun/Sun 15 | examples/dll/consumer 16 | examples/exe/exe 17 | examples/exe-lib/exe-lib 18 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/deleter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base.hpp" 4 | 5 | NAMESPACE_SOUP 6 | { 7 | using deleter_t = void(*)(void*); 8 | 9 | template 10 | void deleter_impl(void* ptr) 11 | { 12 | delete reinterpret_cast(ptr); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/dll/foolib/foolib.cpp: -------------------------------------------------------------------------------- 1 | #include "foolib.hpp" 2 | 3 | const char* foo() 4 | { 5 | return "Hello, world!"; 6 | } 7 | 8 | // On Linux systems, the default is to export everything. 9 | // This can be adjusted with -fvisibility=hidden 10 | // You can list exports with nm -D <.so file> 11 | void oopsie_woopsie() 12 | { 13 | } 14 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/RngInterface.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "base.hpp" 6 | 7 | NAMESPACE_SOUP 8 | { 9 | struct RngInterface 10 | { 11 | [[nodiscard]] virtual uint64_t generate() = 0; 12 | 13 | [[nodiscard]] bool coinflip() 14 | { 15 | return generate() & 1; 16 | } 17 | }; 18 | 19 | struct StatelessRngInterface : public RngInterface 20 | { 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/SelfDeletingThread.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Thread.hpp" 4 | #if !SOUP_WASM 5 | 6 | NAMESPACE_SOUP 7 | { 8 | class SelfDeletingThread : public Thread 9 | { 10 | public: 11 | explicit SelfDeletingThread(void(*f)(Capture&&), Capture&& cap = {}); 12 | 13 | protected: 14 | static void run(Capture&& cap); 15 | 16 | void(*f)(Capture&&); 17 | Capture cap; 18 | }; 19 | } 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/StringMatch.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "base.hpp" 6 | 7 | NAMESPACE_SOUP 8 | { 9 | struct StringMatch 10 | { 11 | [[nodiscard]] static bool search(const std::string& query, std::string item); // assumes that query is lowercase 12 | [[nodiscard]] static bool wildcard(const std::string& query, const std::string& item, size_t min_chars_per_wildcard = 0); // case-sensitive 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/Capture.cpp: -------------------------------------------------------------------------------- 1 | #include "Capture.hpp" 2 | 3 | #include "Exception.hpp" 4 | 5 | NAMESPACE_SOUP 6 | { 7 | void Capture::validate() const 8 | { 9 | #if SOUP_BITS == 64 10 | if (reinterpret_cast(data) == 0xdddddddddddddddd) 11 | #else 12 | if (reinterpret_cast(data) == 0xdddddddd) 13 | #endif 14 | { 15 | SOUP_THROW(Exception("Attempt to use Capture after it has been free'd")); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/memory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // forward 4 | 5 | #include "base.hpp" 6 | 7 | NAMESPACE_SOUP 8 | { 9 | // Like std::construct_at except it doesn't require C++ 20 10 | template 11 | /*constexpr*/ T* construct_at(T* addr, Args&&...args) 12 | noexcept(noexcept(::new(addr) T(std::forward(args)...))) 13 | { 14 | return ::new(addr) T(std::forward(args)...); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/Optional.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "base.hpp" 6 | 7 | NAMESPACE_SOUP 8 | { 9 | template 10 | struct Optional : public std::optional 11 | { 12 | using Base = std::optional; 13 | 14 | using Base::Base; 15 | 16 | bool consume(T& outValue) 17 | { 18 | if (Base::has_value()) 19 | { 20 | outValue = std::move(Base::value()); 21 | return true; 22 | } 23 | return false; 24 | } 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/rand.cpp: -------------------------------------------------------------------------------- 1 | #include "rand.hpp" 2 | 3 | #include "HardwareRng.hpp" 4 | 5 | NAMESPACE_SOUP 6 | { 7 | uint64_t rand_impl::getSeed() noexcept 8 | { 9 | return FastHardwareRng::generate64(); 10 | } 11 | 12 | uint8_t rand_impl::byte(uint8_t min) noexcept 13 | { 14 | return t(min, -1); 15 | } 16 | 17 | std::string rand_impl::binstr(size_t len) 18 | { 19 | std::string str{}; 20 | for (size_t i = 0; i < len; i++) 21 | { 22 | str.push_back(byte()); 23 | } 24 | return str; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/Exception.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base.hpp" 4 | 5 | #include 6 | 7 | NAMESPACE_SOUP 8 | { 9 | struct Exception : public std::runtime_error 10 | { 11 | using std::runtime_error::runtime_error; 12 | 13 | [[noreturn]] static void purecall() 14 | { 15 | SOUP_THROW(Exception("Call to virtual function that was not implemented by specialisation")); 16 | } 17 | 18 | [[noreturn]] static void raiseLogicError() 19 | { 20 | SOUP_THROW(Exception("Logic error")); 21 | } 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/_update.php: -------------------------------------------------------------------------------- 1 | ) 7 | - [Project Configuration]() 8 | 9 | ## Installation 10 | 11 | If you do have Chocolatey, then that's probably the easiest way to get the Sun executable directly beamed into a directory in your path: 12 | ``` 13 | choco source add -n "Calamity, Inc." -s https://choco.calamity.gg/index.json 14 | choco install sun 15 | ``` 16 | 17 | You can also find prebuilt binaries in [the releases](https://github.com/calamity-inc/Sun/releases), and of course you can [build it yourself](). 18 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/StringWriter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Writer.hpp" 4 | 5 | NAMESPACE_SOUP 6 | { 7 | class StringWriter final : public Writer 8 | { 9 | public: 10 | std::string data{}; 11 | 12 | StringWriter() 13 | : Writer() 14 | { 15 | } 16 | 17 | ~StringWriter() final = default; 18 | 19 | bool raw(void* data, size_t size) noexcept final 20 | { 21 | SOUP_TRY 22 | { 23 | this->data.append(reinterpret_cast(data), size); 24 | } 25 | SOUP_CATCH_ANY 26 | { 27 | return false; 28 | } 29 | return true; 30 | } 31 | 32 | [[nodiscard]] size_t getPosition() final 33 | { 34 | return data.size(); 35 | } 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.hpp" 2 | 3 | static_assert(sizeof(void*) * 8 == SOUP_BITS); 4 | 5 | #if !SOUP_EXCEPTIONS 6 | #include 7 | #endif 8 | 9 | #include "Exception.hpp" 10 | #include "ObfusString.hpp" 11 | 12 | NAMESPACE_SOUP 13 | { 14 | #if !SOUP_EXCEPTIONS 15 | void throwImpl(std::exception&& e) 16 | { 17 | std::cerr << e.what(); 18 | abort(); 19 | } 20 | #endif 21 | 22 | void throwAssertionFailed() 23 | { 24 | SOUP_THROW(Exception(ObfusString("Assertion failed").str())); 25 | } 26 | 27 | void throwAssertionFailed(const char* what) 28 | { 29 | #if false 30 | std::string msg = "Assertion failed: "; 31 | msg.append(what); 32 | SOUP_THROW(Exception(std::move(msg))); 33 | #else 34 | SOUP_THROW(Exception(what)); 35 | #endif 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/StringBuilder.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "base.hpp" 6 | 7 | NAMESPACE_SOUP 8 | { 9 | class StringBuilder : public std::string 10 | { 11 | private: 12 | const char* copy_start; 13 | 14 | public: 15 | using std::string::string; 16 | 17 | void beginCopy(const char* i) noexcept 18 | { 19 | copy_start = i; 20 | } 21 | 22 | void endCopy(const char* i) 23 | { 24 | append(copy_start, i); 25 | } 26 | 27 | void beginCopy(const std::string& str, std::string::const_iterator it) noexcept 28 | { 29 | return beginCopy(str.data() + (it - str.cbegin())); 30 | } 31 | 32 | void endCopy(const std::string& str, std::string::const_iterator it) 33 | { 34 | return endCopy(str.data() + (it - str.cbegin())); 35 | } 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/filesystem.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "base.hpp" 7 | 8 | NAMESPACE_SOUP 9 | { 10 | struct filesystem 11 | { 12 | [[nodiscard]] static std::filesystem::path u8path(const std::string& str); 13 | 14 | [[nodiscard]] static bool exists_case_sensitive(const std::filesystem::path& p); 15 | [[nodiscard]] static intptr_t filesize(const std::filesystem::path& path); // returns -1 on error 16 | 17 | [[nodiscard]] static std::filesystem::path tempfile(const std::string& ext = {}); 18 | [[nodiscard]] static std::filesystem::path getProgramData() SOUP_EXCAL; 19 | 20 | [[nodiscard]] static const void* createFileMapping(const std::filesystem::path& path, size_t& out_len) noexcept; 21 | static void destroyFileMapping(const void* addr, size_t len) noexcept; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /docs/Building.md: -------------------------------------------------------------------------------- 1 | # Building 2 | 3 | ## Without Sun 4 | 5 | aka. bootstrapping 6 | 7 | ### On Windows 8 | 9 | Use the Visual Studio 2022 project to build Soup as a static lib, then build Sun. 10 | 11 | ### On Linux 12 | 13 | ``` 14 | php Sun/vendor/Soup/build_lib.php 15 | clang -o suncli Sun/sun.cpp -ISun/vendor/Soup Sun/vendor/Soup/libsoup.a -std=c++17 -fuse-ld=lld -lstdc++ -lstdc++fs -pthreads 16 | ``` 17 | 18 | You can then use the following command to make the "suncli" executable globally available as "sun": 19 | 20 | ``` 21 | cp suncli /usr/local/bin/sun 22 | ``` 23 | 24 | ### On MacOS 25 | 26 | Should be more or less the same as on Linux, but MacOS prefers libc++ over libstdc++: 27 | 28 | ``` 29 | clang -o suncli Sun/sun.cpp -ISun/vendor/Soup Sun/vendor/Soup/libsoup.a -std=c++17 -fuse-ld=lld -lc++ -pthreads 30 | ``` 31 | 32 | ## With Sun 33 | 34 | Just run `sun` in the "Sun" folder (the one with the .sun file in it) 35 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/PoppedNode.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base.hpp" 4 | 5 | NAMESPACE_SOUP 6 | { 7 | template 8 | struct PoppedNode 9 | { 10 | Node* node; 11 | 12 | constexpr PoppedNode(Node* node = nullptr) noexcept 13 | : node(node) 14 | { 15 | } 16 | 17 | PoppedNode(PoppedNode&& b) noexcept 18 | : node(b.node) 19 | { 20 | b.node = nullptr; 21 | } 22 | 23 | ~PoppedNode() 24 | { 25 | free(); 26 | } 27 | 28 | operator bool() const noexcept 29 | { 30 | return node != nullptr; 31 | } 32 | 33 | void free() noexcept 34 | { 35 | if (*this) 36 | { 37 | delete node; 38 | } 39 | } 40 | 41 | PoppedNode& operator =(PoppedNode&& b) noexcept 42 | { 43 | free(); 44 | node = b.node; 45 | b.node = nullptr; 46 | return *this; 47 | } 48 | 49 | Data& operator *() 50 | { 51 | return node->data; 52 | } 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/type.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base.hpp" 4 | #include "fwd.hpp" 5 | 6 | #include 7 | #include 8 | 9 | NAMESPACE_SOUP 10 | { 11 | #if SOUP_BITS == 64 12 | using halfintmax_t = int32_t; 13 | using halfsize_t = uint32_t; 14 | #elif SOUP_BITS == 32 15 | using halfintmax_t = int16_t; 16 | using halfsize_t = uint16_t; 17 | #endif 18 | 19 | // net 20 | using certchain_validator_t = bool(*)(const X509Certchain&, const std::string&, StructMap&) SOUP_EXCAL; 21 | 22 | // net.tls 23 | using TlsAlertDescription_t = uint8_t; 24 | using TlsCipherSuite_t = uint16_t; 25 | using TlsContentType_t = uint8_t; 26 | using TlsHandshakeType_t = uint8_t; 27 | using tls_server_on_client_hello_t = void(*)(Socket&, TlsClientHello&&) SOUP_EXCAL; 28 | using tls_server_alpn_select_protocol_t = std::string(*)(Socket&, const TlsExtAlpn&, TlsCipherSuite_t) SOUP_EXCAL; 29 | 30 | // os 31 | using pid_t = unsigned int; 32 | } 33 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/LcgRng.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Endian.hpp" 6 | 7 | NAMESPACE_SOUP 8 | { 9 | // Linear congruential generator (LCG) 10 | struct LcgRng 11 | { 12 | uint64_t state; 13 | // modulus 2^64 (aka. overflowing a 64-bit integer) 14 | uint64_t multiplier = 6364136223846793005ull; 15 | uint64_t increment = 1442695040888963407ull; 16 | 17 | LcgRng(); 18 | 19 | constexpr LcgRng(uint64_t seed) 20 | : state(seed) 21 | { 22 | } 23 | 24 | constexpr void skip() noexcept 25 | { 26 | state *= multiplier; 27 | state += increment; 28 | } 29 | 30 | constexpr uint64_t generate() noexcept 31 | { 32 | skip(); 33 | return Endianness::invert(state); // invert byte order since the higher-order bits have longer periods 34 | } 35 | 36 | constexpr uint8_t generateByte() noexcept 37 | { 38 | skip(); 39 | return state >> (8 * 7); // use highest byte for better entropy 40 | } 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/macros.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define COUNT(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) 4 | 5 | #define FUNC_CHOOSER(_f0, _f1, _f2, _f3, _f4, _f5, _f6, _f7, _f8, _f9, _f10, _f11, _f12, _f13, _f14, _f15, _f16, ...) _f16 6 | #define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses 7 | #define CHOOSE_FROM_ARG_COUNT(F, ...) FUNC_RECOMPOSER((__VA_ARGS__, \ 8 | F##_16, F##_15, F##_14, F##_13, F##_12, F##_11, F##_10, F##_9, F##_8,\ 9 | F##_7, F##_6, F##_5, F##_4, F##_3, F##_2, F##_1, )) 10 | #define NO_ARG_EXPANDER(FUNC) ,,,,,,,,,,,,,,,,FUNC ## _0 11 | #define MACRO_CHOOSER(FUNC, ...) CHOOSE_FROM_ARG_COUNT(FUNC, NO_ARG_EXPANDER __VA_ARGS__ (FUNC)) 12 | #define MULTI_MACRO(FUNC, ...) MACRO_CHOOSER(FUNC, __VA_ARGS__)(__VA_ARGS__) 13 | 14 | #define CONSUMER_CONTINUE return true; 15 | #define CONSUMER_BREAK return false; 16 | 17 | #define CONST_ASSIGN(a, b) *const_cast>>(&a) = b; 18 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/StringLiteral.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base.hpp" 4 | 5 | NAMESPACE_SOUP 6 | { 7 | template 8 | struct StringLiteral 9 | { 10 | char m_data[Size]; 11 | 12 | SOUP_CONSTEVAL StringLiteral(const char(&in)[Size]) 13 | { 14 | for (size_t i = 0; i != Size; ++i) 15 | { 16 | m_data[i] = in[i]; 17 | } 18 | } 19 | 20 | [[nodiscard]] static constexpr size_t size() noexcept 21 | { 22 | return Size - 1; 23 | } 24 | 25 | [[nodiscard]] static constexpr size_t length() noexcept 26 | { 27 | return Size - 1; 28 | } 29 | 30 | [[nodiscard]] constexpr const char* c_str() const noexcept 31 | { 32 | return &m_data[0]; 33 | } 34 | 35 | [[nodiscard]] constexpr const char* data() const noexcept 36 | { 37 | return &m_data[0]; 38 | } 39 | 40 | [[nodiscard]] constexpr const char* begin() const noexcept 41 | { 42 | return &m_data[0]; 43 | } 44 | 45 | [[nodiscard]] constexpr const char* end() const noexcept 46 | { 47 | return &m_data[size()]; 48 | } 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/IntStruct.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "base.hpp" 6 | 7 | NAMESPACE_SOUP 8 | { 9 | template 10 | struct IntStruct 11 | { 12 | IntT data; 13 | 14 | constexpr IntStruct(IntT val = 0) noexcept 15 | : data(val) 16 | { 17 | } 18 | 19 | constexpr IntStruct(const IntStruct& b) noexcept 20 | : data(b.data) 21 | { 22 | } 23 | 24 | constexpr void operator =(IntT val) noexcept 25 | { 26 | data = val; 27 | } 28 | 29 | constexpr operator IntT& () noexcept 30 | { 31 | return data; 32 | } 33 | 34 | constexpr operator const IntT& () const noexcept 35 | { 36 | return data; 37 | } 38 | }; 39 | static_assert(sizeof(IntStruct) == sizeof(uint8_t)); 40 | static_assert(sizeof(IntStruct) == sizeof(uint16_t)); 41 | static_assert(sizeof(IntStruct) == sizeof(uint32_t)); 42 | static_assert(sizeof(IntStruct) == sizeof(uint64_t)); 43 | } 44 | 45 | #define SOUP_INT_STRUCT(name, type) struct name : public ::soup::IntStruct { using IntStruct::IntStruct; }; 46 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/math.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define _USE_MATH_DEFINES 4 | #include 5 | 6 | #define M_TAU (M_PI * 2.0) 7 | 8 | #define DEG_TO_RAD(deg) ((deg) * (float(M_PI) / 180.0f)) 9 | #define DEG_TO_HALF_RAD(deg) ((deg) * (float(M_PI) / 360.0f)) 10 | 11 | #define RAD_TO_DEG(rad) ((rad) / (float(M_PI) / 180.0f)) 12 | 13 | #include "base.hpp" 14 | 15 | NAMESPACE_SOUP 16 | { 17 | template 18 | [[nodiscard]] constexpr T lerp(T a, T b, float t) 19 | { 20 | return (T)(a + (b - a) * t); 21 | } 22 | 23 | template 24 | [[nodiscard]] constexpr T pow(T x, T p) // p must be >= 0 25 | { 26 | // Stolen from https://stackoverflow.com/a/1505791 27 | // Could be better: https://stackoverflow.com/a/101613 (also see comments) 28 | // Tho this should still work for ints and floats. 29 | if (p == T(0)) 30 | { 31 | return 1; 32 | } 33 | if (p == T(1)) 34 | { 35 | return x; 36 | } 37 | auto tmp = pow(x, p / T(2)); 38 | if (p % T(2) == T(0)) 39 | { 40 | return tmp * tmp; 41 | } 42 | return x * tmp * tmp; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2025 Calamity, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-2023 Calamity, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/main.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base.hpp" 4 | 5 | #include 6 | #include 7 | 8 | #if SOUP_WINDOWS 9 | #include 10 | #endif 11 | 12 | #if SOUP_WINDOWS 13 | // make sure you have the /SUBSYSTEM linker option set to WINDOWS 14 | #define SOUP_MAIN_GUI(entrypoint) int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { return ::soup::main_impl::windows_gui(entrypoint, lpCmdLine); } 15 | #define SOUP_MAIN_CLI(entrypoint) int __cdecl wmain(int argc, wchar_t** argv) { return ::soup::main_impl::windows(argc, argv, entrypoint, true); } 16 | #else 17 | #define SOUP_MAIN_CLI(entrypoint) int main(int argc, const char** argv) { return ::soup::main_impl::cli(argc, argv, entrypoint); } 18 | #define SOUP_MAIN_GUI(entrypoint) SOUP_MAIN_CLI(entrypoint) 19 | #endif 20 | 21 | 22 | NAMESPACE_SOUP 23 | { 24 | struct main_impl 25 | { 26 | using entrypoint_t = int(*)(std::vector&& args, bool console); 27 | 28 | #if SOUP_WINDOWS 29 | static int windows_gui(entrypoint_t entrypoint, LPWSTR lpCmdLine); 30 | static int windows(int argc, wchar_t** argv, entrypoint_t entrypoint, bool console); 31 | #else 32 | static int cli(int argc, const char** argv, entrypoint_t entrypoint); 33 | #endif 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /test.php: -------------------------------------------------------------------------------- 1 | 7 | #else 8 | #include 9 | #endif 10 | 11 | #include "type_traits.hpp" 12 | 13 | NAMESPACE_SOUP 14 | { 15 | struct SharedLibrary 16 | { 17 | #if SOUP_WINDOWS 18 | using handle_t = HMODULE; 19 | #else 20 | using handle_t = void*; 21 | #endif 22 | 23 | handle_t handle = nullptr; 24 | 25 | explicit SharedLibrary() noexcept = default; 26 | explicit SharedLibrary(const char* path) noexcept; 27 | explicit SharedLibrary(SharedLibrary&& b) noexcept; 28 | ~SharedLibrary() noexcept; 29 | 30 | void operator=(SharedLibrary&& b) noexcept; 31 | 32 | [[nodiscard]] bool isLoaded() const noexcept; 33 | bool load(const char* path) noexcept; 34 | void unload() noexcept; 35 | void forget() noexcept; 36 | 37 | template )> 38 | [[nodiscard]] T getAddress(const char* name) const noexcept 39 | { 40 | return reinterpret_cast(getAddress(name)); 41 | } 42 | 43 | template )> 44 | [[nodiscard]] T getAddressMandatory(const char* name) const noexcept 45 | { 46 | return reinterpret_cast(getAddressMandatory(name)); 47 | } 48 | 49 | [[nodiscard]] void* getAddress(const char* name) const noexcept; 50 | [[nodiscard]] void* getAddressMandatory(const char* name) const; 51 | }; 52 | } 53 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/main.cpp: -------------------------------------------------------------------------------- 1 | #include "main.hpp" 2 | 3 | #if SOUP_WINDOWS 4 | #include 5 | #pragma comment(lib, "shell32") 6 | #endif 7 | 8 | #include "unicode.hpp" 9 | 10 | NAMESPACE_SOUP 11 | { 12 | #if SOUP_WINDOWS 13 | int main_impl::windows_gui(entrypoint_t entrypoint, LPWSTR lpCmdLine) 14 | { 15 | bool console = false; 16 | if (AttachConsole(ATTACH_PARENT_PROCESS)) 17 | { 18 | console = true; 19 | 20 | FILE* f; 21 | freopen_s(&f, "CONIN$", "r", stdin); 22 | freopen_s(&f, "CONOUT$", "w", stderr); 23 | freopen_s(&f, "CONOUT$", "w", stdout); 24 | } 25 | 26 | // lpCmdLine seems to shift argv[1] to argv[0], so using GetCommandLineW 27 | int argc; 28 | wchar_t** argv = CommandLineToArgvW(GetCommandLineW(), &argc); 29 | 30 | return windows(argc, argv, entrypoint, console); 31 | } 32 | 33 | int main_impl::windows(int argc, wchar_t** argv, entrypoint_t entrypoint, bool console) 34 | { 35 | std::vector args{}; 36 | for (int i = 0; i != argc; ++i) 37 | { 38 | args.emplace_back(unicode::utf16_to_utf8(argv[i])); 39 | } 40 | return entrypoint(std::move(args), console); 41 | } 42 | #else 43 | int main_impl::cli(int argc, const char** argv, entrypoint_t entrypoint) 44 | { 45 | std::vector args{}; 46 | for (int i = 0; i != argc; ++i) 47 | { 48 | args.emplace_back(argv[i]); 49 | } 50 | return entrypoint(std::move(args), true); 51 | } 52 | #endif 53 | } 54 | -------------------------------------------------------------------------------- /Sun.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32328.378 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Sun", "Sun\Sun.vcxproj", "{0DDE856D-DE13-4B3D-BFE9-0C6C63051383}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {0DDE856D-DE13-4B3D-BFE9-0C6C63051383}.Debug|x64.ActiveCfg = Debug|x64 17 | {0DDE856D-DE13-4B3D-BFE9-0C6C63051383}.Debug|x64.Build.0 = Debug|x64 18 | {0DDE856D-DE13-4B3D-BFE9-0C6C63051383}.Debug|x86.ActiveCfg = Debug|Win32 19 | {0DDE856D-DE13-4B3D-BFE9-0C6C63051383}.Debug|x86.Build.0 = Debug|Win32 20 | {0DDE856D-DE13-4B3D-BFE9-0C6C63051383}.Release|x64.ActiveCfg = Release|x64 21 | {0DDE856D-DE13-4B3D-BFE9-0C6C63051383}.Release|x64.Build.0 = Release|x64 22 | {0DDE856D-DE13-4B3D-BFE9-0C6C63051383}.Release|x86.ActiveCfg = Release|Win32 23 | {0DDE856D-DE13-4B3D-BFE9-0C6C63051383}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {80ECF076-815A-4DD7-BD00-C008BEA211CD} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/StringMatch.cpp: -------------------------------------------------------------------------------- 1 | #include "StringMatch.hpp" 2 | 3 | #include "string.hpp" 4 | #include "StringBuilder.hpp" 5 | 6 | NAMESPACE_SOUP 7 | { 8 | bool StringMatch::search(const std::string& query, std::string item) 9 | { 10 | string::lower(item); 11 | 12 | auto words = string::explode(query, ' '); 13 | for (const auto& word : words) 14 | { 15 | if (item.find(word) == std::string::npos) 16 | { 17 | return false; 18 | } 19 | } 20 | return true; 21 | } 22 | 23 | bool StringMatch::wildcard(const std::string& query, const std::string& item, size_t min_chars_per_wildcard) 24 | { 25 | if (item.empty()) 26 | { 27 | return query.empty(); 28 | } 29 | 30 | size_t ii = 0; 31 | auto qi = query.begin(); 32 | 33 | StringBuilder sb; 34 | sb.beginCopy(query, qi); 35 | while (qi != query.end()) 36 | { 37 | if (*qi == '*') 38 | { 39 | sb.endCopy(query, qi); 40 | auto res = item.find(sb, ii); 41 | if (res == std::string::npos) 42 | { 43 | return false; 44 | } 45 | ii = (res + sb.size()); 46 | ii += min_chars_per_wildcard; 47 | if (ii > item.size()) 48 | { 49 | return false; 50 | } 51 | ++qi; 52 | sb.clear(); 53 | sb.beginCopy(query, qi); 54 | } 55 | else 56 | { 57 | ++qi; 58 | } 59 | } 60 | sb.endCopy(query, qi); 61 | if (item.length() < sb.length() || item.length() - sb.length() < ii || item.substr(item.length() - sb.length()) != sb) 62 | { 63 | return false; 64 | } 65 | return true; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/build_lib.php: -------------------------------------------------------------------------------- 1 | 8 | #else 9 | #include 10 | #endif 11 | 12 | #include 13 | 14 | #include "Capture.hpp" 15 | #include "TransientToken.hpp" 16 | #include "UniquePtr.hpp" 17 | 18 | NAMESPACE_SOUP 19 | { 20 | // This class itself is not thread-safe. If you need multiple threads to access the same instance, use a mutex. 21 | class Thread 22 | { 23 | public: 24 | struct RunningData 25 | { 26 | void(*f)(Capture&&); 27 | Capture f_cap; 28 | TransientToken transient_token; 29 | }; 30 | 31 | #if SOUP_WINDOWS 32 | HANDLE handle = INVALID_HANDLE_VALUE; 33 | #else 34 | pthread_t handle{}; 35 | bool have_handle = false; 36 | #endif 37 | TransientTokenRef running_ref{}; 38 | 39 | explicit Thread() SOUP_EXCAL = default; 40 | explicit Thread(void(*f)(Capture&&), Capture&& cap = {}); 41 | explicit Thread(const Thread& b) = delete; 42 | explicit Thread(Thread&& b) noexcept; 43 | void start(void(*f)(Capture&&), Capture&& cap = {}); 44 | 45 | ~Thread() noexcept { awaitCompletion(); } 46 | 47 | #if SOUP_WINDOWS || SOUP_LINUX 48 | void setTimeCritical() noexcept; 49 | #endif 50 | 51 | [[nodiscard]] bool isAttached() const noexcept; 52 | [[nodiscard]] bool isRunning() const noexcept { return running_ref.isValid(); } 53 | 54 | void awaitCompletion() noexcept; 55 | static void awaitCompletion(const std::vector>& threads) noexcept; 56 | 57 | void detach() noexcept; 58 | 59 | protected: 60 | void forget() noexcept; 61 | }; 62 | } 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/TransientToken.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "SharedPtr.hpp" 4 | 5 | NAMESPACE_SOUP 6 | { 7 | class TransientTokenBase 8 | { 9 | public: 10 | SharedPtr sp; 11 | 12 | TransientTokenBase(bool valid) SOUP_EXCAL 13 | : TransientTokenBase(soup::make_shared(valid)) 14 | { 15 | } 16 | 17 | protected: 18 | TransientTokenBase(SharedPtr&& sp) noexcept 19 | : sp(std::move(sp)) 20 | { 21 | } 22 | 23 | TransientTokenBase(const SharedPtr& sp) noexcept 24 | : sp(sp) 25 | { 26 | } 27 | 28 | public: 29 | [[nodiscard]] bool isValid() const noexcept 30 | { 31 | return *sp; 32 | } 33 | }; 34 | 35 | struct TransientToken : public TransientTokenBase 36 | { 37 | using TransientTokenBase::TransientTokenBase; 38 | 39 | TransientToken() SOUP_EXCAL 40 | : TransientTokenBase(soup::make_shared(true)) 41 | { 42 | } 43 | 44 | ~TransientToken() noexcept 45 | { 46 | invalidate(); 47 | } 48 | 49 | void invalidate() const noexcept 50 | { 51 | *sp = false; 52 | } 53 | 54 | void refresh() SOUP_EXCAL 55 | { 56 | invalidate(); 57 | sp = soup::make_shared(true); 58 | } 59 | }; 60 | 61 | struct TransientTokenRef : public TransientTokenBase 62 | { 63 | using TransientTokenBase::TransientTokenBase; 64 | 65 | TransientTokenRef() SOUP_EXCAL 66 | : TransientTokenBase(soup::make_shared(false)) 67 | { 68 | } 69 | 70 | TransientTokenRef(const TransientTokenBase& tt) noexcept 71 | : TransientTokenBase(tt.sp) 72 | { 73 | } 74 | 75 | void reset() SOUP_EXCAL 76 | { 77 | sp = soup::make_shared(false); 78 | } 79 | }; 80 | } 81 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/Compiler.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "base.hpp" 7 | 8 | NAMESPACE_SOUP 9 | { 10 | struct Compiler 11 | { 12 | std::string prog; 13 | std::string prog_ar; 14 | std::string lang; // defaults to "c++20" or "c++17" depending on platform 15 | bool rtti = false; 16 | std::vector extra_args{}; 17 | std::vector extra_linker_args{}; 18 | 19 | Compiler(); 20 | 21 | [[nodiscard]] bool isEmscripten() const noexcept; 22 | [[nodiscard]] bool isCrossCompiler() const noexcept; 23 | 24 | [[nodiscard]] std::vector getArgs() const; 25 | void addLinkerArgs(std::vector& args) const; 26 | 27 | // Intermediate objects (.o) 28 | std::string makeObject(const std::string& in, const std::string& out) const; 29 | 30 | // Executables (.exe) 31 | [[nodiscard]] static const char* getExecutableExtension() noexcept; // ".exe" or "" 32 | std::string makeExecutable(const std::string& in, const std::string& out) const; 33 | std::string makeExecutable(const std::vector& objects, const std::string& out) const; 34 | 35 | // Static libraries 36 | [[nodiscard]] static const char* getStaticLibraryExtension() noexcept; // ".lib" or ".a" 37 | std::string makeStaticLibrary(const std::vector& objects, const std::string& out) const; 38 | 39 | // Dynamic / shared libraries 40 | [[nodiscard]] const char* getDynamicLibraryExtension() const; // ".dll" or ".so" or ".js" 41 | std::string makeDynamicLibrary(const std::string& in, const std::string& out) const; 42 | std::string makeDynamicLibrary(const std::vector& objects, const std::string& out) const; 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/SharedLibrary.cpp: -------------------------------------------------------------------------------- 1 | #include "SharedLibrary.hpp" 2 | 3 | #include 4 | 5 | #include "Exception.hpp" 6 | 7 | NAMESPACE_SOUP 8 | { 9 | SharedLibrary::SharedLibrary(const char* path) noexcept 10 | { 11 | load(path); 12 | } 13 | 14 | SharedLibrary::SharedLibrary(SharedLibrary&& b) noexcept 15 | : handle(b.handle) 16 | { 17 | b.forget(); 18 | } 19 | 20 | SharedLibrary::~SharedLibrary() noexcept 21 | { 22 | unload(); 23 | } 24 | 25 | void SharedLibrary::operator=(SharedLibrary&& b) noexcept 26 | { 27 | unload(); 28 | handle = b.handle; 29 | b.forget(); 30 | } 31 | 32 | bool SharedLibrary::isLoaded() const noexcept 33 | { 34 | return handle != nullptr; 35 | } 36 | 37 | bool SharedLibrary::load(const char* path) noexcept 38 | { 39 | #if SOUP_WINDOWS 40 | handle = LoadLibraryA(path); 41 | #else 42 | handle = dlopen(path, RTLD_LAZY); 43 | #endif 44 | return isLoaded(); 45 | } 46 | 47 | void SharedLibrary::unload() noexcept 48 | { 49 | if (isLoaded()) 50 | { 51 | #if SOUP_WINDOWS 52 | FreeLibrary(handle); 53 | #else 54 | dlclose(handle); 55 | #endif 56 | forget(); 57 | } 58 | } 59 | 60 | void SharedLibrary::forget() noexcept 61 | { 62 | handle = nullptr; 63 | } 64 | 65 | void* SharedLibrary::getAddress(const char* name) const noexcept 66 | { 67 | SOUP_IF_UNLIKELY (!isLoaded()) 68 | { 69 | return nullptr; 70 | } 71 | #if SOUP_WINDOWS 72 | return (void*)GetProcAddress(handle, name); 73 | #else 74 | return dlsym(handle, name); 75 | #endif 76 | } 77 | 78 | void* SharedLibrary::getAddressMandatory(const char* name) const 79 | { 80 | SOUP_IF_LIKELY (auto addr = getAddress(name)) 81 | { 82 | return addr; 83 | } 84 | std::string msg = "Failed to find mandatory symbol: "; 85 | msg.append(name); 86 | SOUP_THROW(Exception(std::move(msg))); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/HardwareRng.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include // size_t 5 | 6 | #include "RngInterface.hpp" 7 | 8 | NAMESPACE_SOUP 9 | { 10 | // For the purposes of this class, "hardware RNG" is a true RNG, with each bit coming directly from a hardware entropy source. 11 | struct HardwareRng 12 | { 13 | [[nodiscard]] static bool isAvailable() noexcept; 14 | 15 | [[nodiscard]] static uint16_t generate16() noexcept; 16 | [[nodiscard]] static uint32_t generate32() noexcept; 17 | [[nodiscard]] static uint64_t generate64() noexcept; 18 | 19 | // To satisfy the named requirement UniformRandomBitGenerator: 20 | using result_type = uint64_t; 21 | [[nodiscard]] static constexpr uint64_t min() noexcept { return 0; } 22 | [[nodiscard]] static constexpr uint64_t max() noexcept { return -1; } 23 | [[nodiscard]] uint64_t operator()() const noexcept { return generate64(); } 24 | }; 25 | 26 | // For the purposes of this class, "fast hardware RNG" is backed by a hardware entropy source, but uses processing (a DRBG) to extrapolate more bits. 27 | struct FastHardwareRng 28 | { 29 | static void generate(void* buf, size_t buflen) noexcept; 30 | [[nodiscard]] static uint16_t generate16() noexcept; 31 | [[nodiscard]] static uint32_t generate32() noexcept; 32 | [[nodiscard]] static uint64_t generate64() noexcept; 33 | 34 | // To satisfy the named requirement UniformRandomBitGenerator: 35 | using result_type = uint64_t; 36 | [[nodiscard]] static constexpr uint64_t min() noexcept { return 0; } 37 | [[nodiscard]] static constexpr uint64_t max() noexcept { return -1; } 38 | [[nodiscard]] uint64_t operator()() const noexcept { return generate64(); } 39 | }; 40 | 41 | template 42 | struct StatelessRngWrapper : public StatelessRngInterface 43 | { 44 | uint64_t generate() final 45 | { 46 | return T::generate64(); 47 | } 48 | }; 49 | using HardwareRngInterface = StatelessRngWrapper; 50 | using FastHardwareRngInterface = StatelessRngWrapper; 51 | } 52 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/os.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base.hpp" 4 | #include "fwd.hpp" 5 | #include "type.hpp" 6 | 7 | #include 8 | #include 9 | 10 | #if SOUP_WINDOWS 11 | #include 12 | #include 13 | #endif 14 | 15 | NAMESPACE_SOUP 16 | { 17 | class os 18 | { 19 | public: 20 | static void escape(std::string& str); 21 | private: 22 | static void escapeNoCheck(std::string& str); 23 | public: 24 | static std::string execute(std::string program, const std::vector& args = {}); 25 | static std::string executeLong(std::string program, const std::vector& args = {}); 26 | private: 27 | static void resolveProgram(std::string& program); 28 | static std::string executeInner(std::string program, const std::vector& args); 29 | public: 30 | 31 | [[nodiscard]] static pid_t getProcessId() noexcept; 32 | 33 | static void sleep(unsigned int ms) noexcept; 34 | static void fastSleep(unsigned int ms) noexcept; // On Windows, this tries to be more accurate for ms < 15. 35 | 36 | #if SOUP_WINDOWS 37 | static bool copyToClipboard(const std::string& text); 38 | [[nodiscard]] static std::string getClipboardTextUtf8(); 39 | [[nodiscard]] static std::wstring getClipboardTextUtf16(); 40 | 41 | #if !SOUP_CROSS_COMPILE 42 | [[nodiscard]] static size_t getMemoryUsage(); 43 | #endif 44 | 45 | [[nodiscard]] static bool isWine(); 46 | 47 | [[nodiscard]] static PEB* getCurrentPeb(); 48 | 49 | #if !SOUP_CROSS_COMPILE 50 | [[nodiscard]] static std::string makeScreenshotBmp(int x, int y, int width, int height); 51 | #endif 52 | 53 | [[nodiscard]] static int getPrimaryScreenWidth() 54 | { 55 | return GetSystemMetrics(SM_CXSCREEN); 56 | } 57 | 58 | [[nodiscard]] static int getPrimaryScreenHeight() 59 | { 60 | return GetSystemMetrics(SM_CYSCREEN); 61 | } 62 | #endif 63 | }; 64 | 65 | #if SOUP_WINDOWS 66 | inline pid_t os::getProcessId() noexcept 67 | { 68 | return GetCurrentProcessId(); 69 | } 70 | 71 | inline void os::sleep(unsigned int ms) noexcept 72 | { 73 | ::Sleep(ms); 74 | } 75 | #else 76 | inline void os::fastSleep(unsigned int ms) noexcept 77 | { 78 | os::sleep(ms); 79 | } 80 | #endif 81 | } 82 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/AtomicStack.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "PoppedNode.hpp" 6 | 7 | NAMESPACE_SOUP 8 | { 9 | template 10 | struct AtomicStack 11 | { 12 | struct Node 13 | { 14 | Node* next = nullptr; 15 | Data data; 16 | 17 | Node(Data&& data) 18 | : data(std::move(data)) 19 | { 20 | } 21 | }; 22 | 23 | std::atomic head = nullptr; 24 | 25 | void emplace_front(Data&& data) 26 | { 27 | Node* node = new Node(std::move(data)); 28 | node->next = head.load(); 29 | while (!head.compare_exchange_weak(node->next, node)) 30 | { 31 | } 32 | } 33 | 34 | PoppedNode pop_front() noexcept 35 | { 36 | Node* node; 37 | do 38 | { 39 | node = head.load(); 40 | } while (node && !head.compare_exchange_weak(node, node->next)); 41 | return node; 42 | } 43 | 44 | // non-atomic operations 45 | 46 | constexpr AtomicStack() noexcept = default; 47 | 48 | AtomicStack(AtomicStack&& b) noexcept 49 | : head(b.head.load()) 50 | { 51 | b.head = nullptr; 52 | } 53 | 54 | ~AtomicStack() noexcept 55 | { 56 | for (Node* node = head.load(); node != nullptr; ) 57 | { 58 | Node* tbd = node; 59 | node = node->next; 60 | delete tbd; 61 | } 62 | } 63 | 64 | void operator=(AtomicStack&& b) noexcept 65 | { 66 | head = b.head.load(); 67 | b.head = nullptr; 68 | } 69 | 70 | [[nodiscard]] bool empty() const noexcept 71 | { 72 | return head.load() == nullptr; 73 | } 74 | 75 | [[nodiscard]] size_t size() const noexcept 76 | { 77 | size_t accum = 0; 78 | for (Node* node = head.load(); node != nullptr; node = node->next) 79 | { 80 | ++accum; 81 | } 82 | return accum; 83 | } 84 | 85 | void erase(Node* target) noexcept 86 | { 87 | if (head.load() == target) 88 | { 89 | head = target->next; 90 | } 91 | else for (Node* node = head.load(); node != nullptr; node = node->next) 92 | { 93 | if (node->next == target) 94 | { 95 | node->next = target->next; 96 | break; 97 | } 98 | } 99 | delete target; 100 | } 101 | }; 102 | } 103 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: push 4 | 5 | jobs: 6 | debian-10: 7 | runs-on: [debian-10] 8 | steps: 9 | - uses: actions/checkout@v4 10 | 11 | - name: Build Soup 12 | run: php Sun/vendor/Soup/build_lib.php 13 | 14 | - name: Build Sun 15 | run: clang -O3 -o suncli Sun/sun.cpp -ISun/vendor/Soup Sun/vendor/Soup/libsoup.a -std=c++17 -fuse-ld=lld -lstdc++ -lstdc++fs -pthreads 16 | 17 | - name: Upload Sun 18 | uses: actions/upload-artifact@v4 19 | with: 20 | name: "Debian 10 and above (X64)" 21 | path: suncli 22 | 23 | - run: php test.php 24 | 25 | macos-13: 26 | runs-on: macos-13 27 | steps: 28 | - uses: actions/checkout@v4 29 | 30 | - name: Build Soup 31 | run: php Sun/vendor/Soup/build_lib.php 32 | 33 | - name: Build Sun 34 | run: clang -O3 -o suncli Sun/sun.cpp -ISun/vendor/Soup Sun/vendor/Soup/libsoup.a -std=c++17 -lc++ 35 | 36 | - name: Upload Sun 37 | uses: actions/upload-artifact@v4 38 | with: 39 | name: "MacOS (X64)" 40 | path: suncli 41 | 42 | - run: php test.php 43 | 44 | macos-14: 45 | runs-on: macos-14 46 | steps: 47 | - uses: actions/checkout@v4 48 | 49 | - name: Setup PHP 50 | uses: shivammathur/setup-php@v2 51 | with: 52 | php-version: "8.2" 53 | 54 | - name: Build Soup 55 | run: php Sun/vendor/Soup/build_lib.php 56 | 57 | - name: Build Sun 58 | run: clang -O3 -o suncli Sun/sun.cpp -ISun/vendor/Soup Sun/vendor/Soup/libsoup.a -std=c++17 -lc++ 59 | 60 | - name: Upload Sun 61 | uses: actions/upload-artifact@v4 62 | with: 63 | name: "MacOS (ARM64)" 64 | path: suncli 65 | 66 | - run: php test.php 67 | 68 | windows-latest: 69 | runs-on: windows-latest 70 | steps: 71 | - uses: actions/checkout@v4 72 | 73 | - name: Build Soup 74 | run: php Sun/vendor/Soup/build_lib.php 75 | 76 | - name: Build Sun 77 | run: clang -O3 -o Sun.exe Sun/sun.cpp -ISun/vendor/Soup Sun/vendor/Soup/soup.lib -std=c++17 78 | 79 | - name: Upload Sun 80 | uses: actions/upload-artifact@v4 81 | with: 82 | name: "Windows (X64)" 83 | path: Sun.exe 84 | 85 | - run: php test.php 86 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/ShortString.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "base.hpp" 7 | 8 | NAMESPACE_SOUP 9 | { 10 | template 11 | class ShortString 12 | { 13 | private: 14 | char m_data[S] = { 0 }; 15 | const char term = 0; 16 | 17 | public: 18 | ShortString() noexcept 19 | { 20 | } 21 | 22 | ShortString(const std::string& b) noexcept 23 | { 24 | operator=(b); 25 | } 26 | 27 | ShortString(const char* b) noexcept 28 | { 29 | operator=(b); 30 | } 31 | 32 | ShortString(const ShortString& b) noexcept 33 | { 34 | operator=(b); 35 | } 36 | 37 | void operator =(const std::string& b) noexcept 38 | { 39 | operator=(b.c_str()); 40 | } 41 | 42 | void operator =(const char* b) noexcept 43 | { 44 | SOUP_DEBUG_ASSERT(strlen(b) <= S); 45 | strncpy(data(), b, S); 46 | } 47 | 48 | void operator =(const ShortString& b) noexcept 49 | { 50 | strncpy(data(), b.data(), S); 51 | } 52 | 53 | [[nodiscard]] char* data() noexcept 54 | { 55 | return &m_data[0]; 56 | } 57 | 58 | [[nodiscard]] const char* data() const noexcept 59 | { 60 | return &m_data[0]; 61 | } 62 | 63 | [[nodiscard]] const char* c_str() const noexcept 64 | { 65 | return &m_data[0]; 66 | } 67 | 68 | [[nodiscard]] static size_t capacity() noexcept 69 | { 70 | return S; 71 | } 72 | 73 | [[nodiscard]] bool empty() const noexcept 74 | { 75 | return m_data[0] == 0; 76 | } 77 | 78 | [[nodiscard]] size_t size() const noexcept 79 | { 80 | return strlen(c_str()); 81 | } 82 | 83 | [[nodiscard]] char& operator [](size_t Index) noexcept 84 | { 85 | SOUP_DEBUG_ASSERT(Index < S); 86 | return m_data[Index]; 87 | } 88 | 89 | [[nodiscard]] const char& operator [](size_t Index) const noexcept 90 | { 91 | SOUP_DEBUG_ASSERT(Index < S); 92 | return m_data[Index]; 93 | } 94 | }; 95 | static_assert(sizeof(ShortString<1>) == 2); 96 | static_assert(sizeof(ShortString<2>) == 3); 97 | static_assert(sizeof(ShortString<3>) == 4); 98 | static_assert(sizeof(ShortString<4>) == 5); 99 | static_assert(sizeof(ShortString<5>) == 6); 100 | static_assert(sizeof(ShortString<6>) == 7); 101 | static_assert(sizeof(ShortString<7>) == 8); 102 | static_assert(sizeof(ShortString<8>) == 9); 103 | static_assert(sizeof(ShortString<9>) == 10); 104 | } 105 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/joaat.cpp: -------------------------------------------------------------------------------- 1 | #include "joaat.hpp" 2 | 3 | #include // memset 4 | 5 | #include "base.hpp" 6 | 7 | NAMESPACE_SOUP 8 | { 9 | [[nodiscard]] static char joaat_find_last_char(uint32_t val) 10 | { 11 | char best_c = 0; 12 | uint32_t best_c_score = -1; 13 | for (uint8_t c = 0; c != 0x80; ++c) 14 | { 15 | uint32_t score = joaat::undo_partial(val, c); 16 | if (score < best_c_score) 17 | { 18 | best_c = c; 19 | best_c_score = score; 20 | } 21 | } 22 | return best_c; 23 | } 24 | 25 | uint32_t joaat::deriveInitial(uint32_t val, const std::string& str) 26 | { 27 | val = deriveInitialNoFinalise(val, str); 28 | finalise(val); 29 | return val; 30 | } 31 | 32 | uint32_t joaat::deriveInitialNoFinalise(uint32_t val, const std::string& str) 33 | { 34 | undo_finalise(val); 35 | for (auto i = str.crbegin(); i != str.crend(); ++i) 36 | { 37 | undo_partial(val); 38 | val -= *i; 39 | } 40 | return val; 41 | } 42 | 43 | std::optional joaat::reverse_short_key(uint32_t val) 44 | { 45 | undo_finalise(val); 46 | undo_partial(val); 47 | 48 | std::string str{}; 49 | if (val == 0) 50 | { 51 | return str; 52 | } 53 | for (uint8_t i = 0; i != 3; ++i) 54 | { 55 | char c = joaat_find_last_char(val); 56 | str.insert(0, 1, c); 57 | val = undo_partial(val, c); 58 | if (val == 0) 59 | { 60 | return str; 61 | } 62 | } 63 | 64 | return {}; 65 | } 66 | 67 | static void collide_inc(char* buf, size_t idx, size_t& len) 68 | { 69 | if (buf[idx] == '\0') 70 | { 71 | buf[idx] = 'a'; 72 | ++len; 73 | return; 74 | } 75 | if (buf[idx] == '9') 76 | { 77 | collide_inc(buf, idx + 1, len); 78 | buf[idx] = 'a'; 79 | return; 80 | } 81 | if (buf[idx] == 'z') 82 | { 83 | buf[idx] = '0'; 84 | return; 85 | } 86 | ++buf[idx]; 87 | } 88 | 89 | #if !SOUP_WINDOWS 90 | #define strncpy_s strncpy 91 | #endif 92 | 93 | std::string joaat::collide(uint32_t val, const char* prefix) 94 | { 95 | joaat::undo_finalise(val); 96 | 97 | char buf[100]; 98 | memset(buf, 0, sizeof(buf)); 99 | 100 | size_t idx = strlen(prefix); 101 | size_t len = idx; 102 | strncpy_s(buf, prefix, len); 103 | 104 | while (joaat::partialRange(&buf[0], len) != val) 105 | { 106 | collide_inc(buf, idx, len); 107 | } 108 | 109 | return std::string((const char*)&buf[0], len); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/build_common.php: -------------------------------------------------------------------------------- 1 | array("pipe", "r"), 77 | 1 => array("file", stream_get_meta_data($file)["uri"], "a"), 78 | 2 => array("file", stream_get_meta_data($file)["uri"], "a"), 79 | ); 80 | $proc = proc_open(array_shift($queued_commands), $descriptorspec, $pipes); 81 | array_push($procs, [ $proc, $file ]); 82 | } 83 | 84 | foreach ($procs as $i => $proc) 85 | { 86 | if (!proc_get_status($proc[0])["running"]) 87 | { 88 | $output .= stream_get_contents($proc[1]); 89 | fclose($proc[1]); 90 | proc_close($proc[0]); 91 | unset($procs[$i]); 92 | 93 | $done += 1; 94 | echo "\r$done/$todo"; 95 | } 96 | } 97 | 98 | usleep(10000); 99 | } 100 | 101 | echo "\n"; 102 | echo $output; 103 | } 104 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/UniquePtr.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // forward 4 | 5 | #include "base.hpp" 6 | #include "type_traits.hpp" 7 | 8 | NAMESPACE_SOUP 9 | { 10 | template 11 | class UniquePtr 12 | { 13 | public: 14 | T* data = nullptr; 15 | 16 | UniquePtr() noexcept = default; 17 | 18 | UniquePtr(T* ptr) noexcept 19 | : data(ptr) 20 | { 21 | } 22 | 23 | UniquePtr(UniquePtr&& b) noexcept 24 | : data(b.data) 25 | { 26 | b.data = nullptr; 27 | } 28 | 29 | template || std::is_base_of_v)> 30 | UniquePtr(UniquePtr&& b) noexcept 31 | : data(static_cast(b.data)) 32 | { 33 | b.data = nullptr; 34 | } 35 | 36 | ~UniquePtr() 37 | { 38 | free(); 39 | } 40 | 41 | private: 42 | void free() 43 | { 44 | // "if ptr is a null pointer, the standard library deallocation functions do nothing" 45 | //if (data != nullptr) 46 | { 47 | delete data; 48 | } 49 | } 50 | 51 | public: 52 | void reset() noexcept 53 | { 54 | // "if ptr is a null pointer, the standard library deallocation functions do nothing" 55 | //if (data != nullptr) 56 | { 57 | delete data; 58 | data = nullptr; 59 | } 60 | } 61 | 62 | UniquePtr& operator =(UniquePtr&& b) noexcept 63 | { 64 | const auto old_data = data; 65 | data = b.data; 66 | b.data = nullptr; 67 | // "if ptr is a null pointer, the standard library deallocation functions do nothing" 68 | //if (old_data != nullptr) 69 | { 70 | delete old_data; 71 | } 72 | return *this; 73 | } 74 | 75 | [[nodiscard]] operator bool() const noexcept 76 | { 77 | return data != nullptr; 78 | } 79 | 80 | [[nodiscard]] operator T*() const noexcept 81 | { 82 | return get(); 83 | } 84 | 85 | [[nodiscard]] T* get() const noexcept 86 | { 87 | return data; 88 | } 89 | 90 | [[nodiscard]] T& operator*() const noexcept 91 | { 92 | return *get(); 93 | } 94 | 95 | [[nodiscard]] T* operator->() const noexcept 96 | { 97 | return get(); 98 | } 99 | 100 | [[nodiscard]] T* release() noexcept 101 | { 102 | T* val = data; 103 | data = nullptr; 104 | return val; 105 | } 106 | }; 107 | 108 | template )> 109 | [[nodiscard]] UniquePtr make_unique(Args&&...args) 110 | { 111 | return UniquePtr(new T(std::forward(args)...)); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/HardwareRng.cpp: -------------------------------------------------------------------------------- 1 | #include "HardwareRng.hpp" 2 | 3 | #include "CpuInfo.hpp" 4 | 5 | #if SOUP_WINDOWS 6 | #include 7 | #include 8 | #pragma comment(lib, "bcrypt.lib") 9 | #elif SOUP_LINUX 10 | #include 11 | #else 12 | #include // open 13 | #include // read, close 14 | #endif 15 | 16 | #if SOUP_X86 17 | #include 18 | #endif 19 | 20 | NAMESPACE_SOUP 21 | { 22 | // HardwareRng 23 | 24 | bool HardwareRng::isAvailable() noexcept 25 | { 26 | #if SOUP_X86 27 | return CpuInfo::get().supportsRDSEED(); 28 | #else 29 | return false; 30 | #endif 31 | } 32 | 33 | #if SOUP_X86 && (defined(__GNUC__) || defined(__clang__)) 34 | __attribute__((target("rdseed"))) 35 | #endif 36 | uint16_t HardwareRng::generate16() noexcept 37 | { 38 | #if SOUP_X86 39 | uint16_t res; 40 | while (_rdseed16_step(&res) == 0); 41 | return res; 42 | #else 43 | SOUP_ASSERT_UNREACHABLE; 44 | #endif 45 | } 46 | 47 | #if SOUP_X86 && (defined(__GNUC__) || defined(__clang__)) 48 | __attribute__((target("rdseed"))) 49 | #endif 50 | uint32_t HardwareRng::generate32() noexcept 51 | { 52 | #if SOUP_X86 53 | uint32_t res; 54 | while (_rdseed32_step(&res) == 0); 55 | return res; 56 | #else 57 | SOUP_ASSERT_UNREACHABLE; 58 | #endif 59 | } 60 | 61 | #if SOUP_X86 && SOUP_BITS >= 64 && (defined(__GNUC__) || defined(__clang__)) 62 | __attribute__((target("rdseed"))) 63 | #endif 64 | uint64_t HardwareRng::generate64() noexcept 65 | { 66 | #if SOUP_X86 67 | #if SOUP_BITS >= 64 68 | unsigned long long res; 69 | while (_rdseed64_step(&res) == 0); 70 | return res; 71 | #else 72 | return (static_cast(generate32()) << 32) | generate32(); 73 | #endif 74 | #else 75 | SOUP_ASSERT_UNREACHABLE; 76 | #endif 77 | } 78 | 79 | // FastHardwareRng 80 | 81 | void FastHardwareRng::generate(void* buf, size_t buflen) noexcept 82 | { 83 | #if SOUP_WINDOWS 84 | BCryptGenRandom(nullptr, (PUCHAR)buf, (ULONG)buflen, BCRYPT_USE_SYSTEM_PREFERRED_RNG); 85 | #elif SOUP_LINUX 86 | getrandom(buf, buflen, 0); 87 | #else 88 | const auto fd = open("/dev/urandom", O_RDONLY); 89 | read(fd, buf, buflen); 90 | close(fd); 91 | #endif 92 | } 93 | 94 | uint16_t FastHardwareRng::generate16() noexcept 95 | { 96 | uint16_t res; 97 | generate(&res, sizeof(res)); 98 | return res; 99 | } 100 | 101 | uint32_t FastHardwareRng::generate32() noexcept 102 | { 103 | uint32_t res; 104 | generate(&res, sizeof(res)); 105 | return res; 106 | } 107 | 108 | uint64_t FastHardwareRng::generate64() noexcept 109 | { 110 | uint64_t res; 111 | generate(&res, sizeof(res)); 112 | return res; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/format.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "base.hpp" 7 | #include "type_traits.hpp" 8 | 9 | NAMESPACE_SOUP 10 | { 11 | // For format strings known at compile-time, std::format is faster. 12 | // Although the way std::format deals with custom types requires more boilerplate and ends up making it lose its time advantage. 13 | // In any case, if performance matters to you, do your own benchmarks and consider not using a format function at all. 14 | // Otherwise, use whichever makes you more productive. 15 | 16 | template 17 | std::string format_toString(const char v) 18 | { 19 | return std::string(1, v); 20 | } 21 | 22 | template 23 | std::string format_toString(const char* v) 24 | { 25 | return v; 26 | } 27 | 28 | template )> 29 | std::string format_toString(const In& v) 30 | { 31 | return std::to_string(v); 32 | } 33 | 34 | template >)> 35 | std::string format_toString(const void* v) 36 | { 37 | std::stringstream stream; 38 | stream << v; 39 | return stream.str(); 40 | } 41 | 42 | template && !std::is_void_v>)> 43 | std::string format_toString(const In& v) 44 | { 45 | return v.toString(); 46 | } 47 | 48 | inline void format_expandLiteralPart(std::string& res, size_t& sep, const std::string& str) 49 | { 50 | sep = str.find('}', sep); 51 | if (sep != std::string::npos) 52 | { 53 | sep += 1; 54 | auto next = str.find('{', sep); 55 | if (next == std::string::npos) 56 | { 57 | res.append(str.substr(sep)); 58 | } 59 | else 60 | { 61 | res.append(str.substr(sep, next - sep)); 62 | } 63 | sep = next; 64 | } 65 | } 66 | 67 | template 68 | void format_expandArg(std::string& res, size_t& sep, const std::string& str, const T& arg) 69 | { 70 | if (sep == std::string::npos) // More arguments than instances of "{}"? 71 | { 72 | return; 73 | } 74 | 75 | if constexpr (std::is_same_v) 76 | { 77 | res.append(arg); 78 | } 79 | else 80 | { 81 | res.append(format_toString(arg)); 82 | } 83 | 84 | format_expandLiteralPart(res, sep, str); 85 | } 86 | 87 | template 88 | std::string format(const std::string& str, const Args&... args) 89 | { 90 | std::string res; 91 | size_t sep = str.find('{'); 92 | res.append(str.substr(0, sep)); 93 | (format_expandArg(res, sep, str, args), ...); 94 | 95 | while (sep != std::string::npos) // More instances of "{}" than arguments? 96 | { 97 | format_expandLiteralPart(res, sep, str); 98 | } 99 | 100 | return res; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/CpuInfo.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base.hpp" 4 | #if !SOUP_WASM 5 | 6 | #include 7 | #if SOUP_X86 8 | #include 9 | 10 | #include "ShortString.hpp" 11 | #endif 12 | 13 | NAMESPACE_SOUP 14 | { 15 | class CpuInfo 16 | { 17 | private: 18 | CpuInfo() noexcept; 19 | 20 | public: 21 | [[nodiscard]] static SOUP_PURE const CpuInfo& get() noexcept 22 | { 23 | static CpuInfo inst; 24 | return inst; 25 | } 26 | 27 | [[nodiscard]] std::string toString() const SOUP_EXCAL; 28 | 29 | #if SOUP_X86 30 | uint32_t cpuid_max_eax; 31 | uint32_t cpuid_extended_max_eax; 32 | ShortString<16> vendor_id; 33 | 34 | // EAX=1 35 | uint8_t stepping_id = 0; 36 | uint8_t model = 0; 37 | uint8_t family = 0; 38 | uint32_t feature_flags_ecx = 0; 39 | uint32_t feature_flags_edx = 0; 40 | 41 | // EAX=7, ECX=0 42 | uint32_t extended_features_max_ecx = 0; 43 | uint32_t extended_features_0_ebx = 0; 44 | 45 | // EAX=7, ECX=1 46 | uint32_t extended_features_1_eax = 0; 47 | 48 | // EAX=16h 49 | uint16_t base_frequency = 0; 50 | uint16_t max_frequency = 0; 51 | uint16_t bus_frequency = 0; 52 | 53 | // EAX=80000001h 54 | uint32_t extended_flags_1_ecx = 0; 55 | 56 | [[nodiscard]] bool supportsSSE() const noexcept 57 | { 58 | return (feature_flags_edx >> 25) & 1; 59 | } 60 | 61 | [[nodiscard]] bool supportsSSE2() const noexcept 62 | { 63 | return (feature_flags_edx >> 26) & 1; 64 | } 65 | 66 | [[nodiscard]] bool supportsSSE3() const noexcept 67 | { 68 | return (feature_flags_ecx >> 0) & 1; 69 | } 70 | 71 | [[nodiscard]] bool supportsPCLMULQDQ() const noexcept 72 | { 73 | return (feature_flags_ecx >> 1) & 1; 74 | } 75 | 76 | [[nodiscard]] bool supportsSSSE3() const noexcept 77 | { 78 | return (feature_flags_ecx >> 9) & 1; 79 | } 80 | 81 | [[nodiscard]] bool supportsSSE4_1() const noexcept 82 | { 83 | return (feature_flags_ecx >> 19) & 1; 84 | } 85 | 86 | [[nodiscard]] bool supportsSSE4_2() const noexcept 87 | { 88 | return (feature_flags_ecx >> 20) & 1; 89 | } 90 | 91 | [[nodiscard]] bool supportsAESNI() const noexcept 92 | { 93 | return (feature_flags_ecx >> 25) & 1; 94 | } 95 | 96 | [[nodiscard]] bool supportsAVX() const noexcept 97 | { 98 | return (feature_flags_ecx >> 28) & 1; 99 | } 100 | 101 | [[nodiscard]] bool supportsRDRAND() const noexcept 102 | { 103 | return (feature_flags_ecx >> 30) & 1; 104 | } 105 | 106 | [[nodiscard]] bool supportsAVX2() const noexcept 107 | { 108 | return (extended_features_0_ebx >> 5) & 1; 109 | } 110 | 111 | [[nodiscard]] bool supportsAVX512F() const noexcept 112 | { 113 | return (extended_features_0_ebx >> 16) & 1; 114 | } 115 | 116 | [[nodiscard]] bool supportsRDSEED() const noexcept 117 | { 118 | return (extended_features_0_ebx >> 18) & 1; 119 | } 120 | 121 | [[nodiscard]] bool supportsSHA() const noexcept 122 | { 123 | return (extended_features_0_ebx >> 29) & 1; 124 | } 125 | 126 | [[nodiscard]] bool supportsAVX512BW() const noexcept 127 | { 128 | return (extended_features_0_ebx >> 30) & 1; 129 | } 130 | 131 | [[nodiscard]] bool supportsSHA512() const noexcept 132 | { 133 | return (extended_features_1_eax >> 0) & 1; 134 | } 135 | 136 | [[nodiscard]] bool supportsXOP() const noexcept 137 | { 138 | return (extended_flags_1_ecx >> 11) & 1; 139 | } 140 | 141 | static void invokeCpuid(void* out, uint32_t eax) noexcept; 142 | static void invokeCpuid(void* out, uint32_t eax, uint32_t ecx) noexcept; 143 | #elif SOUP_ARM 144 | bool armv8_aes; 145 | bool armv8_sha1; 146 | bool armv8_sha2; 147 | bool armv8_crc32; 148 | #endif 149 | }; 150 | } 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/Capture.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // uintptr_t 4 | #include // move 5 | 6 | #include "base.hpp" // SOUP_EXCAL 7 | #include "deleter.hpp" 8 | #include "type_traits.hpp" 9 | 10 | NAMESPACE_SOUP 11 | { 12 | class Capture 13 | { 14 | protected: 15 | void* data = nullptr; 16 | deleter_t deleter = nullptr; 17 | 18 | public: 19 | Capture() noexcept = default; 20 | 21 | Capture(const Capture&) = delete; 22 | 23 | Capture(Capture&& b) noexcept 24 | : data(b.data), deleter(b.deleter) 25 | { 26 | #ifdef _DEBUG 27 | validate(); 28 | #endif 29 | b.forget(); 30 | } 31 | 32 | template >)> 33 | Capture(const T& v) SOUP_EXCAL 34 | : data(new std::remove_reference_t(v)), deleter(&deleter_impl>) 35 | { 36 | } 37 | 38 | template >)> 39 | Capture(T&& v) SOUP_EXCAL 40 | : data(new std::remove_reference_t(std::move(v))), deleter(&deleter_impl>) 41 | { 42 | } 43 | 44 | // For some reason, C++ thinks it can call the T&& overload for non-const SharedPtr references... 45 | template >)> 46 | Capture(T& v) SOUP_EXCAL 47 | : data(new std::remove_reference_t(v)), deleter(&deleter_impl>) 48 | { 49 | } 50 | 51 | template >)> 52 | Capture(T v) noexcept 53 | : data(reinterpret_cast(reinterpret_cast(v))) 54 | { 55 | #ifdef _DEBUG 56 | validate(); 57 | #endif 58 | } 59 | 60 | ~Capture() noexcept 61 | { 62 | free(); 63 | } 64 | 65 | [[nodiscard]] bool empty() const noexcept 66 | { 67 | return data == nullptr; 68 | } 69 | 70 | void reset() noexcept 71 | { 72 | free(); 73 | forget(); 74 | } 75 | 76 | protected: 77 | void free() noexcept 78 | { 79 | if (deleter != nullptr) 80 | { 81 | deleter(data); 82 | } 83 | } 84 | 85 | void forget() noexcept 86 | { 87 | data = nullptr; 88 | deleter = nullptr; 89 | } 90 | 91 | public: 92 | void operator =(const Capture&) = delete; 93 | 94 | void operator =(Capture&& b) noexcept 95 | { 96 | free(); 97 | data = b.data; 98 | deleter = b.deleter; 99 | b.forget(); 100 | } 101 | 102 | template >)> 103 | void operator =(const T& v) SOUP_EXCAL 104 | { 105 | free(); 106 | data = new std::remove_reference_t(v); 107 | deleter = &deleter_impl>; 108 | } 109 | 110 | template >)> 111 | void operator =(T&& v) SOUP_EXCAL 112 | { 113 | free(); 114 | data = new std::remove_reference_t(std::move(v)); 115 | deleter = &deleter_impl>; 116 | } 117 | 118 | template >)> 119 | void operator =(T v) noexcept 120 | { 121 | free(); 122 | data = v; 123 | deleter = nullptr; 124 | } 125 | 126 | [[nodiscard]] operator bool() const noexcept 127 | { 128 | return data != nullptr; 129 | } 130 | 131 | template >)> 132 | [[nodiscard]] T& get() const noexcept 133 | { 134 | #ifdef _DEBUG 135 | validate(); 136 | #endif 137 | return *reinterpret_cast(data); 138 | } 139 | 140 | template >)> 141 | [[nodiscard]] T get() const noexcept 142 | { 143 | #ifdef _DEBUG 144 | validate(); 145 | #endif 146 | return reinterpret_cast(data); 147 | } 148 | 149 | private: 150 | void validate() const; 151 | }; 152 | } 153 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/filesystem.cpp: -------------------------------------------------------------------------------- 1 | #include "filesystem.hpp" 2 | 3 | #include 4 | 5 | #if SOUP_WINDOWS 6 | #include 7 | #include // CSIDL_COMMON_APPDATA 8 | 9 | #pragma comment(lib, "shell32.lib") // SHGetFolderPathW 10 | #pragma comment(lib, "user32.lib") // SendInput 11 | #else 12 | #include 13 | #include 14 | #include 15 | #include 16 | #endif 17 | 18 | #include "rand.hpp" 19 | #if SOUP_CPP20 20 | #include "string.hpp" 21 | #endif 22 | 23 | NAMESPACE_SOUP 24 | { 25 | std::filesystem::path filesystem::u8path(const std::string& str) 26 | { 27 | #if SOUP_CPP20 28 | return soup::string::toUtf8Type(str); 29 | #else 30 | return std::filesystem::u8path(str); 31 | #endif 32 | } 33 | 34 | bool filesystem::exists_case_sensitive(const std::filesystem::path& p) 35 | { 36 | return std::filesystem::exists(p) 37 | #if SOUP_WINDOWS 38 | && p.filename() == std::filesystem::canonical(p).filename() 39 | #endif 40 | ; 41 | } 42 | 43 | intptr_t filesystem::filesize(const std::filesystem::path& path) 44 | { 45 | // This is not guaranteed to work, but works on UNIX, and on Windows in binary mode. 46 | std::ifstream in(path, std::ifstream::ate | std::ifstream::binary); 47 | return static_cast(in.tellg()); 48 | } 49 | 50 | std::filesystem::path filesystem::tempfile(const std::string& ext) 51 | { 52 | std::filesystem::path path; 53 | do 54 | { 55 | auto file = rand.str(20); 56 | if (!ext.empty()) 57 | { 58 | if (ext.at(0) != '.') 59 | { 60 | file.push_back('.'); 61 | } 62 | file.append(ext); 63 | } 64 | path = std::filesystem::temp_directory_path(); 65 | path /= file; 66 | } while (std::filesystem::exists(path)); 67 | return path; 68 | } 69 | 70 | std::filesystem::path filesystem::getProgramData() SOUP_EXCAL 71 | { 72 | #if SOUP_WINDOWS 73 | wchar_t szPath[MAX_PATH]; 74 | if (SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szPath) == 0) 75 | { 76 | return szPath; 77 | } 78 | return "C:\\ProgramData"; 79 | #else 80 | return "/var/lib"; 81 | #endif 82 | } 83 | 84 | static const char empty_file_data = 0; 85 | 86 | const void* filesystem::createFileMapping(const std::filesystem::path& path, size_t& out_len) noexcept 87 | { 88 | const void* addr = nullptr; 89 | #if SOUP_WINDOWS 90 | HANDLE f = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 91 | SOUP_IF_LIKELY (f != INVALID_HANDLE_VALUE) 92 | { 93 | LARGE_INTEGER liSize; 94 | SOUP_IF_LIKELY (GetFileSizeEx(f, &liSize)) 95 | { 96 | out_len = static_cast(liSize.QuadPart); 97 | if (out_len == 0) 98 | { 99 | addr = &empty_file_data; 100 | } 101 | else 102 | { 103 | HANDLE m = CreateFileMappingA(f, nullptr, PAGE_READONLY, liSize.HighPart, liSize.LowPart, NULL); 104 | SOUP_IF_LIKELY (m != NULL) 105 | { 106 | addr = MapViewOfFile(m, FILE_MAP_READ, 0, 0, out_len); 107 | CloseHandle(m); 108 | } 109 | } 110 | } 111 | CloseHandle(f); 112 | } 113 | #else 114 | int f = ::open(path.c_str(), O_RDONLY | O_CLOEXEC); 115 | SOUP_IF_LIKELY (f != -1) 116 | { 117 | struct stat st; 118 | SOUP_IF_LIKELY (fstat(f, &st) != -1) 119 | { 120 | out_len = st.st_size; 121 | if (out_len == 0) 122 | { 123 | addr = &empty_file_data; 124 | } 125 | else 126 | { 127 | addr = mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, f, 0); 128 | SOUP_IF_UNLIKELY (addr == MAP_FAILED) 129 | { 130 | addr = nullptr; 131 | } 132 | } 133 | } 134 | ::close(f); 135 | } 136 | #endif 137 | return addr; 138 | } 139 | 140 | void filesystem::destroyFileMapping(const void* addr, size_t len) noexcept 141 | { 142 | if (addr != &empty_file_data) 143 | { 144 | #if SOUP_WINDOWS 145 | UnmapViewOfFile(addr); 146 | #else 147 | munmap(const_cast(addr), len); 148 | #endif 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/rand.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "base.hpp" 7 | #include "macros.hpp" 8 | 9 | #define ARRAY_RAND(arr) arr[::soup::rand(0, COUNT(arr) - 1)] 10 | 11 | NAMESPACE_SOUP 12 | { 13 | class rand_impl 14 | { 15 | public: 16 | [[nodiscard]] static uint64_t getSeed() noexcept; 17 | 18 | //#define getConstexprSeedCounted() getConstexprSeed(__COUNTER__ + 1) 19 | 20 | [[nodiscard]] static constexpr uint32_t getConstexprSeed(unsigned int lcg_iterations = 1) noexcept 21 | { 22 | uint32_t seed = (((((((((((__TIME__[7] - '0') * 10) + (__TIME__[6] - '0')) * 10) + (__TIME__[4] - '0')) * 10) + (__TIME__[3] - '0')) * 10) + (__TIME__[1] - '0')) * 10) + (__TIME__[0] - '0')); 23 | 24 | // Performing at least 1 iteration of LCG for "better-looking" numbers since `seed` is basically just a timestamp at this point 25 | while (lcg_iterations--) 26 | { 27 | seed *= 22695477u; 28 | seed += 1; 29 | } 30 | 31 | return seed; 32 | } 33 | 34 | private: 35 | [[nodiscard]] static std::mt19937_64 getMersenneTwisterImpl() noexcept 36 | { 37 | return std::mt19937_64{ getSeed() }; 38 | } 39 | 40 | public: 41 | [[nodiscard]] static SOUP_PURE std::mt19937_64& getMersenneTwister() noexcept 42 | { 43 | static std::mt19937_64 mt = getMersenneTwisterImpl(); 44 | return mt; 45 | } 46 | 47 | template 48 | [[nodiscard]] static T t(T min, T max) noexcept 49 | { 50 | std::uniform_int_distribution distr{ min, max }; 51 | return distr(getMersenneTwister()); 52 | } 53 | 54 | [[nodiscard]] size_t operator()(size_t min, size_t max) const noexcept 55 | { 56 | return t(min, max); 57 | } 58 | 59 | template 60 | [[nodiscard]] const T& operator()(const std::vector& vec) const 61 | { 62 | return vec.at(t(0, vec.size() - 1)); 63 | } 64 | 65 | template 66 | [[nodiscard]] T operator()(std::vector&& vec) const 67 | { 68 | return std::move(vec.at(t(0, vec.size() - 1))); 69 | } 70 | 71 | [[nodiscard]] static uint8_t byte(uint8_t min = 0) noexcept; 72 | 73 | [[nodiscard]] static char ch(char min = 0) noexcept 74 | { 75 | return (char)byte(min); 76 | } 77 | 78 | [[nodiscard]] static bool coinflip() noexcept 79 | { 80 | return t(0, 1) != 0; 81 | } 82 | 83 | template 84 | [[nodiscard]] static bool one_in(T odds) noexcept 85 | { 86 | return t(0, odds - 1) == 0; 87 | } 88 | 89 | template 90 | [[nodiscard]] static StrT str(const IntT len) 91 | { 92 | StrT str{}; 93 | static const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 94 | for (IntT i = 0; i < len; i++) 95 | { 96 | str.push_back(chars[t(0, COUNT(chars) - 2)]); 97 | } 98 | return str; 99 | } 100 | 101 | [[nodiscard]] static std::string binstr(size_t len); 102 | 103 | template 104 | static void fill(uint8_t(&arr)[S]) noexcept 105 | { 106 | for (size_t i = 0; i != S; ++i) 107 | { 108 | arr[i] = byte(); 109 | } 110 | } 111 | 112 | template 113 | static void fill(uint8_t arr[S]) noexcept 114 | { 115 | for (size_t i = 0; i != S; ++i) 116 | { 117 | arr[i] = byte(); 118 | } 119 | } 120 | 121 | static void fill(std::vector& vec) noexcept 122 | { 123 | for (auto& b : vec) 124 | { 125 | b = byte(); 126 | } 127 | } 128 | 129 | [[nodiscard]] static std::vector vec_u8(size_t len) noexcept 130 | { 131 | std::vector vec(len, 0); 132 | fill(vec); 133 | return vec; 134 | } 135 | }; 136 | 137 | template <> 138 | inline int8_t rand_impl::t(int8_t min, int8_t max) noexcept 139 | { 140 | return static_cast(t(min, max)); 141 | } 142 | 143 | template <> 144 | inline uint8_t rand_impl::t(uint8_t min, uint8_t max) noexcept 145 | { 146 | return static_cast(t(min, max)); 147 | } 148 | 149 | inline rand_impl rand; 150 | } 151 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/Thread.cpp: -------------------------------------------------------------------------------- 1 | #include "Thread.hpp" 2 | #if !SOUP_WASM 3 | 4 | #if !SOUP_WINDOWS 5 | #include // memcpy 6 | #endif 7 | 8 | #include "Exception.hpp" 9 | #include "format.hpp" 10 | #include "SelfDeletingThread.hpp" 11 | 12 | NAMESPACE_SOUP 13 | { 14 | Thread::Thread(void(*f)(Capture&&), Capture&& cap) 15 | { 16 | start(f, std::move(cap)); 17 | } 18 | 19 | Thread::Thread(Thread&& b) noexcept 20 | : 21 | #if SOUP_WINDOWS 22 | handle(b.handle), 23 | #else 24 | have_handle(b.have_handle), 25 | #endif 26 | running_ref(b.running_ref) 27 | { 28 | #if !SOUP_WINDOWS 29 | memcpy(&handle, &b.handle, sizeof(handle)); 30 | #endif 31 | b.forget(); 32 | } 33 | 34 | static void 35 | #if SOUP_WINDOWS 36 | __stdcall 37 | #endif 38 | threadCreateCallback(void* handover) 39 | { 40 | auto data = reinterpret_cast(handover); 41 | data->f(std::move(data->f_cap)); 42 | delete data; 43 | } 44 | 45 | void Thread::start(void(*f)(Capture&&), Capture&& cap) 46 | { 47 | SOUP_ASSERT(!isRunning()); 48 | 49 | // If we still have a handle, relinquish it. 50 | detach(); 51 | 52 | auto data = new RunningData{ f, std::move(cap) }; 53 | this->running_ref = data->transient_token; 54 | 55 | #if SOUP_WINDOWS 56 | handle = CreateThread(nullptr, 0, reinterpret_cast(&threadCreateCallback), data, 0, nullptr); 57 | SOUP_IF_UNLIKELY (handle == NULL) 58 | { 59 | handle = INVALID_HANDLE_VALUE; 60 | this->running_ref.reset(); 61 | SOUP_THROW(Exception(format("Failed to create thread: {}", GetLastError()))); 62 | } 63 | #else 64 | pthread_attr_t attr; 65 | pthread_attr_init(&attr); 66 | auto ret = pthread_create(&handle, &attr, reinterpret_cast(&threadCreateCallback), data); 67 | SOUP_IF_UNLIKELY (ret != 0) 68 | { 69 | this->running_ref.reset(); 70 | SOUP_THROW(Exception(format("Failed to create thread: {}", ret))); 71 | } 72 | have_handle = true; 73 | #endif 74 | } 75 | 76 | #if SOUP_WINDOWS || SOUP_LINUX 77 | void Thread::setTimeCritical() noexcept 78 | { 79 | #if SOUP_WINDOWS 80 | SetThreadPriority(handle, THREAD_PRIORITY_TIME_CRITICAL); 81 | #else 82 | pthread_setschedprio(handle, 15); 83 | #endif 84 | } 85 | #endif 86 | 87 | bool Thread::isAttached() const noexcept 88 | { 89 | #if SOUP_WINDOWS 90 | return handle != INVALID_HANDLE_VALUE; 91 | #else 92 | return have_handle; 93 | #endif 94 | } 95 | 96 | void Thread::awaitCompletion() noexcept 97 | { 98 | #if SOUP_WINDOWS 99 | if (handle != INVALID_HANDLE_VALUE) 100 | { 101 | WaitForSingleObject(handle, INFINITE); 102 | CloseHandle(handle); 103 | forget(); 104 | } 105 | #else 106 | if (have_handle) 107 | { 108 | pthread_join(handle, nullptr); 109 | forget(); 110 | } 111 | #endif 112 | } 113 | 114 | void Thread::awaitCompletion(const std::vector>& threads) noexcept 115 | { 116 | #if SOUP_WINDOWS 117 | std::vector handles{}; 118 | handles.reserve(threads.size()); 119 | for (auto& t : threads) 120 | { 121 | if (t->handle != INVALID_HANDLE_VALUE) 122 | { 123 | handles.emplace_back(t->handle); 124 | } 125 | } 126 | WaitForMultipleObjects((DWORD)handles.size(), handles.data(), TRUE, INFINITE); 127 | for (auto& t : threads) 128 | { 129 | if (t->handle != INVALID_HANDLE_VALUE) 130 | { 131 | CloseHandle(t->handle); 132 | t->forget(); 133 | } 134 | } 135 | #else 136 | for (auto& t : threads) 137 | { 138 | t->awaitCompletion(); 139 | } 140 | #endif 141 | } 142 | 143 | void Thread::detach() noexcept 144 | { 145 | #if SOUP_WINDOWS 146 | if (handle != INVALID_HANDLE_VALUE) 147 | { 148 | CloseHandle(handle); 149 | forget(); 150 | } 151 | #else 152 | if (have_handle) 153 | { 154 | pthread_detach(handle); 155 | forget(); 156 | } 157 | #endif 158 | } 159 | 160 | void Thread::forget() noexcept 161 | { 162 | #if SOUP_WINDOWS 163 | handle = INVALID_HANDLE_VALUE; 164 | #else 165 | have_handle = false; 166 | #endif 167 | running_ref.reset(); 168 | } 169 | } 170 | 171 | #endif 172 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/joaat.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "base.hpp" 8 | 9 | NAMESPACE_SOUP 10 | { 11 | struct joaat 12 | { 13 | static constexpr uint32_t INITIAL = 0; 14 | 15 | [[nodiscard]] static uint32_t hash(const std::string& str, uint32_t initial = 0) noexcept 16 | { 17 | uint32_t val = partialRange(str.data(), str.size(), initial); 18 | finalise(val); 19 | return val; 20 | } 21 | 22 | [[nodiscard]] static constexpr uint32_t hash(const char* str) noexcept 23 | { 24 | uint32_t val = 0; 25 | while (*str) 26 | { 27 | val += (uint8_t)*(str++); 28 | val += (val << 10); 29 | val ^= (val >> 6); 30 | } 31 | val += (val << 3); 32 | val ^= (val >> 11); 33 | val += (val << 15); 34 | return val; 35 | } 36 | 37 | [[nodiscard]] static SOUP_CONSTEVAL uint32_t compileTimeHash(const char* str) noexcept 38 | { 39 | return hash(str); 40 | } 41 | 42 | [[nodiscard]] static constexpr uint32_t hash(const char* str, uint32_t initial) noexcept 43 | { 44 | uint32_t val = initial; 45 | while (*str) 46 | { 47 | val += (uint8_t)*(str++); 48 | val += (val << 10); 49 | val ^= (val >> 6); 50 | } 51 | val += (val << 3); 52 | val ^= (val >> 11); 53 | val += (val << 15); 54 | return val; 55 | } 56 | 57 | [[nodiscard]] static constexpr uint32_t hashRange(const char* data, size_t size, uint32_t initial = 0) noexcept 58 | { 59 | uint32_t val = partialRange(data, size, initial); 60 | finalise(val); 61 | return val; 62 | } 63 | 64 | [[nodiscard]] static uint32_t concat(uint32_t val, const std::string& str) noexcept 65 | { 66 | undo_finalise(val); 67 | return hash(str, val); 68 | } 69 | 70 | [[nodiscard]] static uint32_t concat(uint32_t val, const char* str) noexcept 71 | { 72 | undo_finalise(val); 73 | return hash(str, val); 74 | } 75 | 76 | [[deprecated]] static constexpr uint32_t partial(const char* data, size_t size, uint32_t initial = 0) noexcept 77 | { 78 | return partialRange(data, size, initial); 79 | } 80 | 81 | [[nodiscard]] static constexpr uint32_t partialRange(const char* data, size_t size, uint32_t initial = 0) noexcept 82 | { 83 | uint32_t val = initial; 84 | while (size-- != 0) 85 | { 86 | val += *(uint8_t*)(data++); 87 | val += (val << 10); 88 | val ^= (val >> 6); 89 | } 90 | return val; 91 | } 92 | 93 | [[nodiscard]] static constexpr uint32_t partialStr(const char* str, uint32_t initial = 0) noexcept 94 | { 95 | uint32_t val = initial; 96 | while (*str) 97 | { 98 | val += (uint8_t)*(str++); 99 | val += (val << 10); 100 | val ^= (val >> 6); 101 | } 102 | return val; 103 | } 104 | 105 | static constexpr void finalise(uint32_t& val) noexcept 106 | { 107 | /*val += (val << 3); 108 | val ^= (val >> 11); 109 | val += (val << 15);*/ 110 | 111 | val = (0x8001 * (((uint32_t)(9 * val) >> 11) ^ (9 * val))); 112 | } 113 | 114 | static void undo_finalise(uint32_t& val) noexcept 115 | { 116 | val *= 0x3FFF8001; // inverse of val += (val << 15); 117 | val ^= (val >> 11) ^ (val >> 22); 118 | val *= 0x38E38E39; // inverse of val += (val << 3); 119 | } 120 | 121 | static void undo_partial(uint32_t& val) noexcept 122 | { 123 | val ^= (val >> 6) ^ (val >> 12) ^ (val >> 18) ^ (val >> 24) ^ (val >> 30); 124 | val *= 0xC00FFC01; // inverse of val += (val << 10); 125 | } 126 | 127 | [[nodiscard]] static uint32_t undo_partial(uint32_t val, char c) noexcept 128 | { 129 | val -= c; 130 | undo_partial(val); 131 | return val; 132 | } 133 | 134 | [[nodiscard]] static uint32_t deriveInitial(uint32_t val, const std::string& str); // deriveInitial(hash("ab"), "b") == hash("a") 135 | [[nodiscard]] static uint32_t deriveInitialNoFinalise(uint32_t val, const std::string& str); 136 | 137 | [[nodiscard]] static std::optional reverse_short_key(uint32_t val); // If the input to joaat is 0..3 characters, this will reverse the hash. 138 | 139 | [[nodiscard]] static std::string collide(uint32_t val, const char* prefix = ""); // Can take quite a while to complete 140 | }; 141 | } 142 | -------------------------------------------------------------------------------- /docs/Config (.sun file).md: -------------------------------------------------------------------------------- 1 | # Config (.sun file) 2 | 3 | When you run Sun, it will look for a `.sun` file in the working directory. 4 | 5 | You can also optionally provide a project name, e.g. with `sun example` it will look for a `example.sun` file. 6 | 7 | ## Comments 8 | 9 | Lines starting with `#` are ignored. 10 | 11 | ## Add source files 12 | 13 | You can add source files by using the `+` operator. All further characters in the line will be considered as a file name. You can also use `*` wildcards. 14 | 15 | For example, you can tell Sun to compile all .cpp files (this is the default): 16 | 17 | ``` 18 | +*.cpp 19 | ``` 20 | 21 | or individual files: 22 | 23 | ``` 24 | +main.cpp 25 | +utils.cpp 26 | ``` 27 | 28 | The wildcard operator will recurse subdirectories when the path also contains a forward slash (`/`). Otherwise, you can explicitly add `-R` to enable recursion, e.g. to have Sun search recursively for cpp files: 29 | 30 | ``` 31 | +*.cpp -R 32 | ``` 33 | 34 | ## Remove source files 35 | 36 | You can remove previously-added source files by using the `-` operator. 37 | 38 | For example, if you want to compile all .cpp files except for wasm.cpp: 39 | 40 | ``` 41 | +*.cpp 42 | -wasm.cpp 43 | ``` 44 | 45 | This operator handles wildcards and recursion exactly like the `+` operator. 46 | 47 | ## Compile as static library 48 | 49 | Add a line that says `static` to the .sun file to indicate that the project is a static library. 50 | 51 | ## Compile as dynamic/shared library 52 | 53 | Add a line that says `dynamic` to the .sun file to indicate that the project is a dynamic library. 54 | 55 | ## Dependencies 56 | 57 | Add `require REL_PATH` to the .sun file to add a dependency to your project. 58 | If the dependency's project file does not have the default name of `.sun`, 59 | you can specify it with `require DIR:NAME` to load `DIR/NAME.sun`. 60 | 61 | Then, when you run Sun, it will build your dependencies first, and finally build your project with relevant compiler and linker include flags. 62 | 63 | If the include directory differs from source directory, you can use 64 | `require REL_PATH[:NAME] include_dir=REL_PATH`. 65 | 66 | ## Project name 67 | 68 | Sun will make a guess about your project name based on the file structure, but you can override this adding `name ...` to the .sun file. 69 | 70 | ## C++ version 71 | 72 | You can use `c++ ...` or `cpp ...` to specify the C++ version for your project. For example: 73 | 74 | ``` 75 | cpp 20 76 | ``` 77 | 78 | ## Compiler arguments 79 | 80 | You can pass arbitrary arguments to the compiler with the `arg` keyword. 81 | `global_arg` works the same but also applies to all dependencies. 82 | 83 | You can define preprocessor macros with the `define` keyword. For example: 84 | 85 | ``` 86 | define FOO=BAR 87 | define ENABLE_FEATURE 88 | ``` 89 | 90 | These lines add `-DFOO=BAR` and `-DENABLE_FEATURE` to the compiler arguments. 91 | 92 | Linker-specific arguments can be provided with the `linker_arg` keyword. 93 | 94 | ## RTTI 95 | 96 | By default, Sun adds `-fno-rtti` to the compiler arguments. To have it omitted, add a line that reads `rtti` to your .sun file. 97 | 98 | ## 32-bit targets 99 | 100 | You can add a line that reads `32bit` to the .sun file to add `-m32` to the global compiler arguments of your project and its dependencies (equivalent to `global_arg -m32`). 101 | 102 | ## Conditionals 103 | 104 | Sun supports basic conditionals with the following syntax: 105 | 106 | ``` 107 | if [not] 108 | ... 109 | endif 110 | ``` 111 | 112 | Valid substitutions for `` are as follows: `windows`, `macos`, `linux`, `x86`, `arm`, `true`, `false`. 113 | 114 | An example: 115 | 116 | ``` 117 | if windows 118 | linker_arg -lKernel32 119 | endif 120 | ``` 121 | 122 | ## Compiler 123 | 124 | You can specify a compiler other than Clang. For example, to build Emscripten projects with Sun: 125 | 126 | ``` 127 | compiler em++ 128 | ``` 129 | 130 | ## Add options via the CLI 131 | 132 | As you may have noticed, the .sun file is parsed line-by-line. You can add additional lines via the CLI using `+`, for example `sun +32bit` loads the file `.sun` and acts as if a line in that file reads `32bit`. 133 | 134 | Note that if the added line contains a space, the argument needs to be quoted, either like `sun +"name myproject"` or `sun "+name myproject"`. 135 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/Endian.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(_MSC_VER) && !defined(__clang__) 4 | #include // _byteswap_* 5 | #include // is_constant_evaluated 6 | #endif 7 | 8 | #include "base.hpp" 9 | 10 | #include "IntStruct.hpp" 11 | 12 | NAMESPACE_SOUP 13 | { 14 | enum Endian : bool 15 | { 16 | ENDIAN_LITTLE = true, 17 | ENDIAN_BIG = false, 18 | #if 'ABCD' == 0x41424344ul 19 | ENDIAN_NATIVE = ENDIAN_LITTLE, 20 | #else 21 | ENDIAN_NATIVE = ENDIAN_BIG, 22 | #endif 23 | ENDIAN_NETWORK = ENDIAN_BIG, 24 | }; 25 | 26 | #if 'ABCD' != 0x41424344ul // Native endian is not little endian? 27 | static_assert('ABCD' == 0x44434241ul); // Then it should be big endian. 28 | #endif 29 | 30 | SOUP_INT_STRUCT(native_u16_t, uint16_t); 31 | SOUP_INT_STRUCT(native_u32_t, uint32_t); 32 | SOUP_INT_STRUCT(native_u64_t, uint64_t); 33 | SOUP_INT_STRUCT(network_u16_t, uint16_t); 34 | SOUP_INT_STRUCT(network_u32_t, uint32_t); 35 | SOUP_INT_STRUCT(network_u64_t, uint64_t); 36 | 37 | struct Endianness 38 | { 39 | [[nodiscard]] static constexpr uint16_t invert(uint16_t val) noexcept 40 | { 41 | #if SOUP_CPP23 42 | return std::byteswap(val); 43 | #elif defined(_MSC_VER) && !defined(__clang__) 44 | #if SOUP_CPP20 45 | if (!std::is_constant_evaluated()) 46 | { 47 | return _byteswap_ushort(val); 48 | } 49 | #endif 50 | #elif defined(__GNUC__) || defined(__clang__) 51 | return __builtin_bswap16(val); 52 | #endif 53 | return (val << 8) | (val >> 8); 54 | } 55 | 56 | [[nodiscard]] static constexpr uint32_t invert(uint32_t val) noexcept 57 | { 58 | #if SOUP_CPP23 59 | return std::byteswap(val); 60 | #elif defined(_MSC_VER) && !defined(__clang__) 61 | #if SOUP_CPP20 62 | if (!std::is_constant_evaluated()) 63 | { 64 | return _byteswap_ulong(val); 65 | } 66 | #endif 67 | #elif defined(__GNUC__) || defined(__clang__) 68 | return __builtin_bswap32(val); 69 | #endif 70 | return val << (32 - 8) 71 | | ((val >> 8) & 0xFF) << (32 - 16) 72 | | ((val >> 16) & 0xFF) << (32 - 24) 73 | | ((val >> 24) & 0xFF) 74 | ; 75 | } 76 | 77 | [[nodiscard]] static constexpr uint64_t invert(uint64_t val) noexcept 78 | { 79 | #if SOUP_CPP23 80 | return std::byteswap(val); 81 | #elif defined(_MSC_VER) && !defined(__clang__) 82 | #if SOUP_CPP20 83 | if (!std::is_constant_evaluated()) 84 | { 85 | return _byteswap_uint64(val); 86 | } 87 | #endif 88 | #elif defined(__GNUC__) || defined(__clang__) 89 | return __builtin_bswap64(val); 90 | #endif 91 | return val << (64 - 8) 92 | | ((val >> 8) & 0xFF) << (64 - 16) 93 | | ((val >> 16) & 0xFF) << (64 - 24) 94 | | ((val >> 24) & 0xFF) << (64 - 32) 95 | | ((val >> 32) & 0xFF) << (64 - 40) 96 | | ((val >> 40) & 0xFF) << (64 - 48) 97 | | ((val >> 48) & 0xFF) << (64 - 56) 98 | | ((val >> 56) & 0xFF) 99 | ; 100 | } 101 | 102 | [[nodiscard]] static constexpr network_u16_t toNetwork(uint16_t val) noexcept 103 | { 104 | if constexpr (ENDIAN_NATIVE != ENDIAN_NETWORK) 105 | { 106 | return invert(val); 107 | } 108 | return network_u16_t(val); 109 | } 110 | 111 | [[nodiscard]] static constexpr network_u32_t toNetwork(uint32_t val) noexcept 112 | { 113 | if constexpr (ENDIAN_NATIVE != ENDIAN_NETWORK) 114 | { 115 | return invert(val); 116 | } 117 | return network_u32_t(val); 118 | } 119 | 120 | [[nodiscard]] static constexpr network_u64_t toNetwork(uint64_t val) noexcept 121 | { 122 | if constexpr (ENDIAN_NATIVE != ENDIAN_NETWORK) 123 | { 124 | return invert(val); 125 | } 126 | return network_u64_t(val); 127 | } 128 | 129 | [[nodiscard]] static constexpr native_u16_t toNative(network_u16_t val) noexcept 130 | { 131 | if constexpr (ENDIAN_NATIVE != ENDIAN_NETWORK) 132 | { 133 | return invert(val.data); 134 | } 135 | return native_u16_t(val.data); 136 | } 137 | 138 | [[nodiscard]] static constexpr native_u32_t toNative(network_u32_t val) noexcept 139 | { 140 | if constexpr (ENDIAN_NATIVE != ENDIAN_NETWORK) 141 | { 142 | return invert(val.data); 143 | } 144 | return native_u32_t(val.data); 145 | } 146 | 147 | [[nodiscard]] static constexpr native_u64_t toNative(network_u64_t val) noexcept 148 | { 149 | if constexpr (ENDIAN_NATIVE != ENDIAN_NETWORK) 150 | { 151 | return invert(val.data); 152 | } 153 | return native_u64_t(val.data); 154 | } 155 | }; 156 | } 157 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/fwd.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "base.hpp" 6 | 7 | NAMESPACE_SOUP 8 | { 9 | // algos.rng.interface 10 | struct RngInterface; 11 | struct StatelessRngInterface; 12 | 13 | // audio 14 | class audPlayback; 15 | struct audSound; 16 | 17 | // crypto 18 | struct CertStore; 19 | struct RsaKeypair; 20 | struct RsaPrivateKey; 21 | class TrustStore; 22 | class YubikeyValidator; 23 | 24 | // crypto.x509 25 | struct X509Certchain; 26 | struct X509Certificate; 27 | 28 | // data 29 | struct Oid; 30 | 31 | // data.asn1 32 | struct Asn1Sequence; 33 | 34 | // data.container 35 | struct StructMap; 36 | 37 | // data.json 38 | struct JsonArray; 39 | struct JsonBool; 40 | struct JsonFloat; 41 | struct JsonInt; 42 | struct JsonObject; 43 | struct JsonString; 44 | struct JsonTreeWriter; 45 | 46 | // data.reflection 47 | class drData; 48 | 49 | // data.regex 50 | struct RegexConstraint; 51 | struct RegexGroup; 52 | struct RegexMatcher; 53 | struct RegexTransitionsVector; 54 | 55 | // data.xml 56 | struct PlistDict; 57 | struct PlistArray; 58 | struct PlistString; 59 | struct XmlMode; 60 | struct XmlNode; 61 | struct XmlTag; 62 | struct XmlText; 63 | 64 | // hardware 65 | class hwHid; 66 | 67 | // hardware.keyboard 68 | enum Key : uint8_t; 69 | 70 | // hardware.keyboard.rgb 71 | class kbRgbWooting; 72 | 73 | // io.bits 74 | class BitReader; 75 | class BitWriter; 76 | 77 | // io.stream 78 | class Reader; 79 | class StringReader; 80 | class Writer; 81 | class StringWriter; 82 | 83 | // lang.compiler 84 | struct astBlock; 85 | struct astNode; 86 | class LangDesc; 87 | struct Lexeme; 88 | struct LexemeParser; 89 | class ParserState; 90 | struct Token; 91 | 92 | // lang.compiler.ir 93 | struct irFunction; 94 | 95 | // lang.reflection 96 | struct rflFunc; 97 | struct rflStruct; 98 | struct rflType; 99 | struct rflVar; 100 | 101 | // ling.chatbot 102 | struct cbCmd; 103 | 104 | // math 105 | class Bigint; 106 | struct Vector2; 107 | struct Vector3; 108 | 109 | // math.3d 110 | class Matrix; 111 | struct Mesh; 112 | struct Poly; 113 | class Quaternion; 114 | struct Ray; 115 | 116 | // math.3d.geometry 117 | struct gmBoxCorners; 118 | 119 | // math.3d.scene 120 | struct Scene; 121 | 122 | // mem 123 | class Pattern; 124 | struct CompiletimePatternWithOptBytesBase; 125 | class Pointer; 126 | class Range; 127 | template class SharedPtr; 128 | template class UniquePtr; 129 | template class WeakRef; 130 | 131 | // mem.allocraii 132 | struct AllocRaiiLocalBase; 133 | struct AllocRaiiRemote; 134 | struct AllocRaiiVirtual; 135 | 136 | // mem.vft 137 | struct memVft; 138 | struct RttiObject; 139 | 140 | // misc.chess 141 | struct ChessCoordinate; 142 | 143 | // net 144 | class IpAddr; 145 | struct netConfig; 146 | class netIntel; 147 | enum netStatus : uint8_t; 148 | class Server; 149 | struct ServerService; 150 | struct ServerServiceUdp; 151 | class ServerWebService; 152 | class Socket; 153 | struct SocketAddr; 154 | 155 | // net.dns.resolver 156 | struct dnsResolver; 157 | struct dnsName; 158 | struct dnsHttpResolver; 159 | 160 | // net.tls 161 | class SocketTlsHandshaker; 162 | struct TlsClientHello; 163 | struct TlsExtAlpn; 164 | 165 | // net.web 166 | class HttpRequest; 167 | class HttpRequestTask; 168 | struct HttpResponse; 169 | struct Uri; 170 | 171 | // net.web.websocket 172 | struct WebSocketMessage; 173 | 174 | // os 175 | struct HandleRaii; 176 | class Module; 177 | enum MouseButton : uint8_t; 178 | class ProcessHandle; 179 | class Thread; 180 | struct Window; 181 | 182 | // task 183 | class Capture; 184 | class DetachedScheduler; 185 | class PromiseBase; 186 | template class Promise; 187 | class Scheduler; 188 | 189 | // util 190 | class Mixed; 191 | 192 | // vis 193 | struct BCanvas; 194 | class Canvas; 195 | struct FormattedText; 196 | class QrCode; 197 | struct RasterFont; 198 | union Rgb; 199 | 200 | // vis.layout 201 | struct lyoContainer; 202 | struct lyoDocument; 203 | struct lyoElement; 204 | struct lyoFlatDocument; 205 | struct lyoTextElement; 206 | 207 | // vis.render 208 | struct RenderTarget; 209 | 210 | // vis.ui.conui 211 | struct ConuiApp; 212 | struct ConuiDiv; 213 | 214 | // vis.ui.editor 215 | struct Editor; 216 | struct EditorText; 217 | } 218 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/unicode.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "base.hpp" 7 | 8 | #define UTF8_CONTINUATION_FLAG 0b10000000 9 | #define UTF8_HAS_CONTINUATION(ch) ((ch) & 0b10000000) 10 | #define UTF8_IS_CONTINUATION(ch) (((ch) & 0b11000000) == UTF8_CONTINUATION_FLAG) 11 | 12 | #define UTF16_IS_HIGH_SURROGATE(ch) (((ch) >> 10) == 0x36) 13 | #define UTF16_IS_LOW_SURROGATE(ch) (((ch) >> 10) == 0x37) 14 | 15 | #if SOUP_WINDOWS 16 | #include 17 | 18 | #define UTF16_CHAR_TYPE wchar_t 19 | #define UTF16_STRING_TYPE std::wstring 20 | #else 21 | #define UTF16_CHAR_TYPE char16_t 22 | #define UTF16_STRING_TYPE std::u16string 23 | #endif 24 | static_assert(sizeof(UTF16_CHAR_TYPE) == 2); 25 | 26 | NAMESPACE_SOUP 27 | { 28 | struct unicode 29 | { 30 | static constexpr uint32_t REPLACEMENT_CHAR = 0xFFFD; 31 | 32 | [[nodiscard]] static char32_t utf8_to_utf32_char(std::string::const_iterator& it, const std::string::const_iterator end) noexcept; 33 | #if SOUP_CPP20 34 | [[nodiscard]] static std::u32string utf8_to_utf32(const char8_t* utf8) noexcept; 35 | #endif 36 | [[nodiscard]] static std::u32string utf8_to_utf32(const std::string& utf8) noexcept; 37 | #if SOUP_CPP20 38 | [[nodiscard]] static UTF16_STRING_TYPE utf8_to_utf16(const char8_t* utf8) noexcept; 39 | #endif 40 | [[nodiscard]] static UTF16_STRING_TYPE utf8_to_utf16(const std::string& utf8) noexcept; 41 | #if SOUP_WINDOWS 42 | [[nodiscard]] static UTF16_STRING_TYPE acp_to_utf16(const std::string& acp) noexcept; 43 | #endif 44 | [[nodiscard]] static UTF16_STRING_TYPE utf32_to_utf16(const std::u32string& utf32) noexcept; 45 | static void utf32_to_utf16_char(UTF16_STRING_TYPE& utf16, char32_t c) noexcept; 46 | [[nodiscard]] static std::string utf32_to_utf8(char32_t utf32) noexcept; 47 | [[nodiscard]] static std::string utf32_to_utf8(const std::u32string& utf32) noexcept; 48 | 49 | template 50 | [[nodiscard]] static char32_t utf16_to_utf32(typename Str::const_iterator& it, const typename Str::const_iterator end) noexcept 51 | { 52 | char32_t w1 = static_cast(*it++); 53 | if (UTF16_IS_HIGH_SURROGATE(w1)) 54 | { 55 | SOUP_IF_UNLIKELY (it == end) 56 | { 57 | return 0; 58 | } 59 | char32_t w2 = static_cast(*it++); 60 | return utf16_to_utf32(w1, w2); 61 | } 62 | return w1; 63 | } 64 | 65 | [[nodiscard]] static char32_t utf16_to_utf32(char32_t hi, char32_t lo) noexcept 66 | { 67 | hi &= 0x3FF; 68 | lo &= 0x3FF; 69 | return (((hi * 0x400) + lo) + 0x10000); 70 | } 71 | 72 | template 73 | [[nodiscard]] static std::u32string utf16_to_utf32(const Str& utf16) 74 | { 75 | std::u32string utf32{}; 76 | auto it = utf16.cbegin(); 77 | const auto end = utf16.cend(); 78 | while (it != end) 79 | { 80 | auto uni = utf16_to_utf32(it, end); 81 | if (uni == 0) 82 | { 83 | utf32.push_back(REPLACEMENT_CHAR); 84 | } 85 | else 86 | { 87 | utf32.push_back(uni); 88 | } 89 | } 90 | return utf32; 91 | } 92 | 93 | template 94 | [[nodiscard]] static std::string utf16_to_utf8(const Str& utf16) 95 | { 96 | #if SOUP_WINDOWS 97 | std::string res; 98 | const int sizeRequired = WideCharToMultiByte(CP_UTF8, 0, (const wchar_t*)utf16.data(), (int)utf16.size(), NULL, 0, NULL, NULL); 99 | SOUP_IF_LIKELY (sizeRequired != 0) 100 | { 101 | res = std::string(sizeRequired, 0); 102 | WideCharToMultiByte(CP_UTF8, 0, (const wchar_t*)utf16.data(), (int)utf16.size(), res.data(), sizeRequired, NULL, NULL); 103 | } 104 | return res; 105 | #else 106 | return utf32_to_utf8(utf16_to_utf32(utf16)); 107 | #endif 108 | } 109 | 110 | [[nodiscard]] static size_t utf8_char_len(const std::string& str) noexcept; 111 | [[nodiscard]] static size_t utf16_char_len(const UTF16_STRING_TYPE& str) noexcept; 112 | 113 | template 114 | static void utf8_add(Iterator& it, Iterator end) 115 | { 116 | if (UTF8_HAS_CONTINUATION(*it)) 117 | { 118 | do 119 | { 120 | ++it; 121 | } while (it != end && UTF8_IS_CONTINUATION(*it)); 122 | } 123 | else 124 | { 125 | ++it; 126 | } 127 | } 128 | 129 | template 130 | static void utf8_sub(Iterator& it, Iterator begin) 131 | { 132 | --it; 133 | while (UTF8_IS_CONTINUATION(*it) && it != begin) 134 | { 135 | --it; 136 | } 137 | } 138 | 139 | static void utf8_sanitise(std::string& str); 140 | }; 141 | } 142 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/ObfusString.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // swap 4 | #include 5 | 6 | #include "base.hpp" 7 | #include "LcgRng.hpp" 8 | #include "rand.hpp" 9 | #include "string.hpp" 10 | #include "StringLiteral.hpp" 11 | 12 | #define SOUP_ASSERT_OBF(x, msg) SOUP_IF_UNLIKELY (!(x)) { soup::ObfusString str(msg); ::soup::throwAssertionFailed(str.c_str()); } 13 | 14 | NAMESPACE_SOUP 15 | { 16 | #pragma pack(push, 1) 17 | template 18 | class ObfusString 19 | { 20 | public: 21 | static constexpr size_t Len = Size - 1; 22 | 23 | private: 24 | // seed serves as null-terminator as it's set to 0 after deobfuscation 25 | char m_data[Len]; 26 | uint32_t seed; 27 | 28 | public: 29 | SOUP_CONSTEVAL ObfusString(const char(&in)[Size]) 30 | { 31 | initialise(in); 32 | } 33 | 34 | template 35 | SOUP_CONSTEVAL ObfusString(const T* in) 36 | { 37 | initialise(in); 38 | } 39 | 40 | private: 41 | SOUP_CONSTEVAL void initialise(const char* in) 42 | { 43 | seed = rand.getConstexprSeed(Len); 44 | LcgRng rng(seed); 45 | 46 | // copy input & apply rot13 47 | for (size_t i = 0; i != Len; ++i) 48 | { 49 | m_data[i] = string::rot13(in[i]); 50 | } 51 | 52 | if (Len < 40'000) 53 | { 54 | // mirror 55 | for (size_t i = 0, j = Len - 1; i != Len / 2; ++i, --j) 56 | { 57 | std::swap(m_data[i], m_data[j]); 58 | } 59 | } 60 | 61 | // flip bits 62 | for (size_t i = 0; i != Len; ++i) 63 | { 64 | const auto m = i % 8; 65 | if (m == 0) 66 | { 67 | rng.skip(); 68 | } 69 | m_data[i] ^= rng.state >> (m * 8); 70 | } 71 | } 72 | 73 | SOUP_NOINLINE void runtime_access() noexcept 74 | { 75 | if (seed == 0) 76 | { 77 | return; 78 | } 79 | LcgRng rng(seed); 80 | seed = 0; 81 | 82 | // flip bits 83 | for (size_t i = 0; i != Len; ++i) 84 | { 85 | const auto m = i % 8; 86 | if (m == 0) 87 | { 88 | rng.skip(); 89 | } 90 | m_data[i] ^= rng.state >> (m * 8); 91 | } 92 | 93 | if constexpr (Len < 40'000) 94 | { 95 | // mirror 96 | for (size_t i = 0, j = Len - 1; i != Len / 2; ++i, --j) 97 | { 98 | std::swap(m_data[i], m_data[j]); 99 | } 100 | } 101 | 102 | // rot13 103 | for (size_t i = 0; i != Len; ++i) 104 | { 105 | m_data[i] = string::rot13(m_data[i]); 106 | } 107 | } 108 | 109 | public: 110 | [[nodiscard]] std::string str() SOUP_EXCAL 111 | { 112 | runtime_access(); 113 | return std::string(m_data, Len); 114 | } 115 | 116 | [[nodiscard]] operator std::string() SOUP_EXCAL 117 | { 118 | return str(); 119 | } 120 | 121 | [[nodiscard]] const char* c_str() noexcept 122 | { 123 | runtime_access(); 124 | return m_data; 125 | } 126 | 127 | [[nodiscard]] const char* data() noexcept 128 | { 129 | runtime_access(); 130 | return m_data; 131 | } 132 | 133 | [[nodiscard]] operator const char* () noexcept 134 | { 135 | return c_str(); 136 | } 137 | 138 | [[nodiscard]] bool operator==(const std::string& b) noexcept 139 | { 140 | return str() == b; 141 | } 142 | 143 | [[nodiscard]] bool operator!=(const std::string& b) noexcept 144 | { 145 | return !operator==(b); 146 | } 147 | 148 | template 149 | [[nodiscard]] bool operator==(const ObfusString& b) noexcept 150 | { 151 | return str() == b.str(); 152 | } 153 | 154 | template 155 | [[nodiscard]] bool operator!=(const ObfusString& b) noexcept 156 | { 157 | return !operator==(b); 158 | } 159 | 160 | [[nodiscard]] bool operator==(const char* b) noexcept 161 | { 162 | return strcmp(c_str(), b) == 0; 163 | } 164 | 165 | [[nodiscard]] bool operator!=(const char* b) noexcept 166 | { 167 | return !operator==(b); 168 | } 169 | 170 | friend std::ostream& operator<<(std::ostream& os, ObfusString& str) 171 | { 172 | os << str.str(); 173 | return os; 174 | } 175 | 176 | [[nodiscard]] constexpr size_t size() const noexcept 177 | { 178 | return Len; 179 | } 180 | 181 | [[nodiscard]] constexpr size_t length() const noexcept 182 | { 183 | return Len; 184 | } 185 | }; 186 | static_assert(sizeof(ObfusString<3>) == 2 + 4); 187 | #pragma pack(pop) 188 | 189 | #if SOUP_CPP20 190 | namespace literals 191 | { 192 | template 193 | SOUP_CONSTEVAL auto operator ""_obfus() 194 | { 195 | return ObfusString(Str.m_data); 196 | } 197 | } 198 | #endif 199 | } 200 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/string.cpp: -------------------------------------------------------------------------------- 1 | #include "string.hpp" 2 | 3 | #include 4 | #include 5 | 6 | #include "filesystem.hpp" 7 | 8 | NAMESPACE_SOUP 9 | { 10 | std::string string::hex2bin(const char* data, size_t size) SOUP_EXCAL 11 | { 12 | std::string bin; 13 | uint8_t val = 0; 14 | bool first_nibble = true; 15 | for (; size; ++data, --size) 16 | { 17 | const auto& c = *data; 18 | if (isNumberChar(c)) 19 | { 20 | val |= (c - '0'); 21 | } 22 | else if (c >= 'a' && c <= 'f') 23 | { 24 | val |= 0xA + (c - 'a'); 25 | } 26 | else if (c >= 'A' && c <= 'F') 27 | { 28 | val |= 0xA + (c - 'A'); 29 | } 30 | else 31 | { 32 | continue; 33 | } 34 | if (first_nibble) 35 | { 36 | val <<= 4; 37 | first_nibble = false; 38 | } 39 | else 40 | { 41 | bin.push_back(val); 42 | val = 0; 43 | first_nibble = true; 44 | } 45 | } 46 | return bin; 47 | } 48 | 49 | void string::replaceAll(std::string& str, char from, char to) SOUP_EXCAL 50 | { 51 | size_t pos = 0; 52 | while ((pos = str.find(from, pos)) != std::string::npos) 53 | { 54 | str.data()[pos] = to; 55 | pos += 1; 56 | } 57 | } 58 | 59 | std::string string::escape(const std::string& str) 60 | { 61 | std::string res; 62 | 63 | res.reserve(str.size() + 2); 64 | res.insert(0, 1, ' '); 65 | res.append(str); 66 | 67 | string::replaceAll(res, "\\", "\\\\"); 68 | string::replaceAll(res, "\"", "\\\""); 69 | 70 | res.at(0) = '\"'; 71 | res.push_back('\"'); 72 | 73 | return res; 74 | } 75 | 76 | std::string string::join(const std::vector& arr, const char glue) 77 | { 78 | std::string res{}; 79 | if (!arr.empty()) 80 | { 81 | res = arr.at(0); 82 | for (size_t i = 1; i != arr.size(); ++i) 83 | { 84 | res.push_back(glue); 85 | res.append(arr.at(i)); 86 | } 87 | } 88 | return res; 89 | } 90 | 91 | std::string string::join(const std::vector& arr, const std::string& glue) 92 | { 93 | std::string res{}; 94 | if (!arr.empty()) 95 | { 96 | res = arr.at(0); 97 | for (size_t i = 1; i != arr.size(); ++i) 98 | { 99 | res.append(glue); 100 | res.append(arr.at(i)); 101 | } 102 | } 103 | return res; 104 | } 105 | 106 | void string::listAppend(std::string& str, std::string add) 107 | { 108 | if (str.empty()) 109 | { 110 | str = std::move(add); 111 | } 112 | else 113 | { 114 | str.append(", ").append(add); 115 | } 116 | } 117 | 118 | std::string string::_xor(const std::string& l, const std::string& r) 119 | { 120 | if (l.size() < r.size()) 121 | { 122 | return _xor(r, l); 123 | } 124 | // l.size() >= r.size() 125 | std::string res(l.size(), '\0'); 126 | for (size_t i = 0; i != l.size(); ++i) 127 | { 128 | res.at(i) = (char)((uint8_t)l.at(i) ^ (uint8_t)r.at(i % r.size())); 129 | } 130 | return res; 131 | } 132 | 133 | std::string string::xorSameLength(const std::string& l, const std::string& r) 134 | { 135 | std::string res(l.size(), '\0'); 136 | for (size_t i = 0; i != l.size(); ++i) 137 | { 138 | res.at(i) = (char)((uint8_t)l.at(i) ^ (uint8_t)r.at(i)); 139 | } 140 | return res; 141 | } 142 | 143 | std::string string::fromFile(const char* file) 144 | { 145 | return fromFile(soup::filesystem::u8path(file)); 146 | } 147 | 148 | std::string string::fromFile(const std::string& file) 149 | { 150 | return fromFile(soup::filesystem::u8path(file)); 151 | } 152 | 153 | std::string string::fromFile(const std::filesystem::path& file) 154 | { 155 | std::string ret; 156 | if (std::filesystem::exists(file)) 157 | { 158 | #if SOUP_WINDOWS // kinda messes with hwHid on Linux, also unsure if memory mapping is faster than direct file access on Linux. 159 | size_t len; 160 | if (auto addr = soup::filesystem::createFileMapping(file, len)) 161 | { 162 | ret = std::string((const char*)addr, len); 163 | soup::filesystem::destroyFileMapping(addr, len); 164 | } 165 | else // File might be open in another process, causing memory mapping to fail. 166 | #endif 167 | { 168 | std::ifstream t(file, std::ios::binary); 169 | 170 | t.seekg(0, std::ios::end); 171 | if (const auto s = static_cast(t.tellg()); s != -1) 172 | { 173 | t.seekg(0, std::ios::beg); 174 | 175 | ret.reserve(s); 176 | ret.assign((std::istreambuf_iterator(t)), std::istreambuf_iterator()); 177 | } 178 | } 179 | } 180 | return ret; 181 | } 182 | 183 | void string::toFile(const char* file, const std::string& contents) 184 | { 185 | return toFile(soup::filesystem::u8path(file), contents); 186 | } 187 | 188 | void string::toFile(const std::string& file, const std::string& contents) 189 | { 190 | return toFile(soup::filesystem::u8path(file), contents); 191 | } 192 | 193 | void string::toFile(const std::filesystem::path& file, const char* data, size_t size) 194 | { 195 | std::ofstream of(file, std::ios_base::binary); 196 | of.write(data, size); 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/console.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base.hpp" 4 | #include "fwd.hpp" 5 | 6 | #include "Callback.hpp" 7 | #include "Rgb.hpp" 8 | #include "string.hpp" 9 | 10 | #include 11 | 12 | #if SOUP_WINDOWS 13 | #include 14 | #else 15 | #include 16 | #endif 17 | 18 | #define BEL "\x7" 19 | #define ESC "\x1B" 20 | #define CSI ESC "[" 21 | #define OSC ESC "]" 22 | #define ST ESC "\\" 23 | 24 | NAMESPACE_SOUP 25 | { 26 | enum ControlInput : uint8_t 27 | { 28 | UP, 29 | DOWN, 30 | LEFT, 31 | RIGHT, 32 | NEW_LINE, 33 | BACKSPACE, 34 | }; 35 | 36 | class console_impl 37 | { 38 | private: 39 | #if SOUP_WINDOWS 40 | bool pressed_lmb = false; 41 | bool pressed_rmb = false; 42 | bool pressed_mmb = false; 43 | #else 44 | inline static struct termios termattrs_og{}; 45 | inline static struct termios termattrs_cur{}; 46 | #endif 47 | 48 | public: 49 | using char_handler_t = void(*)(char32_t); 50 | using control_handler_t = void(*)(ControlInput); 51 | 52 | EventHandler char_handler; 53 | EventHandler control_handler; 54 | private: 55 | EventHandler mouse_click_handler; 56 | 57 | public: 58 | void init(bool fullscreen); 59 | void run(); 60 | void cleanup(); 61 | 62 | void onMouseClick(void(*fp)(MouseButton, unsigned int, unsigned int, const Capture&), Capture&& cap = {}); 63 | 64 | /* This shit is only supported by MingW, like, why bother when you don't support anything else?! 65 | 66 | void hideScrollbar() 67 | { 68 | std::cout << CSI "?47h"; 69 | std::cout << CSI "?30l"; 70 | } 71 | 72 | void showScrollbar() 73 | { 74 | std::cout << CSI "?47l"; 75 | std::cout << CSI "?30h"; 76 | }*/ 77 | 78 | // Window 79 | 80 | static void setTitle(const std::string& title); 81 | 82 | inline static EventHandler size_handler; 83 | #if SOUP_POSIX 84 | static void sigwinch_handler_proc(int); 85 | #endif 86 | static void enableSizeTracking(void(*fp)(unsigned int, unsigned int, const Capture&), Capture&& cap = {}); 87 | 88 | // Output 89 | 90 | static void bell(); 91 | static void clearScreen(); 92 | static void hideCursor(); 93 | static void showCursor(); 94 | static void saveCursorPos(); 95 | static void restoreCursorPos(); 96 | static void fillScreen(Rgb c); 97 | static void fillScreen(unsigned int r, unsigned int g, unsigned int b); 98 | static void setCursorPos(unsigned int x, unsigned int y); 99 | 100 | template 101 | const console_impl& operator << (const T& str) const 102 | { 103 | std::cout << str; 104 | return *this; 105 | } 106 | 107 | const console_impl& operator << (const std::u16string& str) const; 108 | 109 | static void setForegroundColour(Rgb c); 110 | 111 | static void setForegroundColour(int r, int g, int b); 112 | 113 | template 114 | [[nodiscard]] static Str strSetForegroundColour(int r, int g, int b) 115 | { 116 | Str str; 117 | str.push_back(CSI[0]); 118 | str.push_back(CSI[1]); 119 | str.push_back('3'); 120 | str.push_back('8'); 121 | str.push_back(';'); 122 | str.push_back('2'); 123 | str.push_back(';'); 124 | str.append(string::decimal(r)); 125 | str.push_back(';'); 126 | str.append(string::decimal(g)); 127 | str.push_back(';'); 128 | str.append(string::decimal(b)); 129 | str.push_back('m'); 130 | return str; 131 | } 132 | 133 | static void setBackgroundColour(Rgb c); 134 | 135 | static void setBackgroundColour(int r, int g, int b); 136 | 137 | template 138 | [[nodiscard]] static Str strSetBackgroundColour(int r, int g, int b) 139 | { 140 | Str str; 141 | str.push_back(CSI[0]); 142 | str.push_back(CSI[1]); 143 | str.push_back('4'); 144 | str.push_back('8'); 145 | str.push_back(';'); 146 | str.push_back('2'); 147 | str.push_back(';'); 148 | str.append(string::decimal(r)); 149 | str.push_back(';'); 150 | str.append(string::decimal(g)); 151 | str.push_back(';'); 152 | str.append(string::decimal(b)); 153 | str.push_back('m'); 154 | return str; 155 | } 156 | 157 | static void resetColour(); 158 | 159 | template 160 | [[nodiscard]] static Str strResetColour() 161 | { 162 | Str str; 163 | str.push_back(CSI[0]); 164 | str.push_back(CSI[1]); 165 | str.push_back('m'); 166 | return str; 167 | } 168 | 169 | // Ctrl+C 170 | 171 | private: 172 | using ctrl_c_handler_t = void(*)(); 173 | 174 | inline static ctrl_c_handler_t ctrl_c_handler = nullptr; 175 | 176 | #if SOUP_WINDOWS 177 | static BOOL WINAPI CtrlHandler(DWORD ctrlType); 178 | #else 179 | static void sigint_handler_proc(int); 180 | #endif 181 | 182 | public: 183 | static void overrideCtrlC(ctrl_c_handler_t handler); 184 | }; 185 | 186 | inline console_impl console; 187 | } 188 | 189 | #undef BEL 190 | #undef ESC 191 | #undef CSI 192 | #undef OSC 193 | #undef ST 194 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/Callback.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Capture.hpp" 6 | 7 | NAMESPACE_SOUP 8 | { 9 | template 10 | struct CallbackBase 11 | { 12 | using FuncT = Ret(Args...); 13 | using FuncWithCaptureT = Ret(Args..., CaptureArgT); 14 | 15 | FuncWithCaptureT* fp; 16 | Capture cap; 17 | 18 | CallbackBase() noexcept 19 | : fp(nullptr) 20 | { 21 | } 22 | 23 | CallbackBase(const CallbackBase&) = delete; 24 | 25 | CallbackBase(CallbackBase&& b) noexcept 26 | : fp(b.fp), cap(std::move(b.cap)) 27 | { 28 | } 29 | 30 | CallbackBase(FuncT* fp) noexcept 31 | : fp(reinterpret_cast(fp)) 32 | { 33 | } 34 | 35 | CallbackBase(FuncWithCaptureT* fp) noexcept 36 | : fp(fp) 37 | { 38 | } 39 | 40 | CallbackBase(FuncWithCaptureT* fp, Capture&& cap) noexcept 41 | : fp(fp), cap(std::move(cap)) 42 | { 43 | } 44 | 45 | static void redirect_to_std_function(Args... args, CaptureArgT cap) 46 | { 47 | return cap.template get>()(std::forward(args)...); 48 | } 49 | 50 | template , T>)> 51 | CallbackBase(T&& func) noexcept 52 | : CallbackBase(&redirect_to_std_function, std::move(func)) 53 | { 54 | } 55 | 56 | void set(FuncWithCaptureT* fp, Capture&& cap = {}) noexcept 57 | { 58 | this->fp = fp; 59 | this->cap = std::move(cap); 60 | } 61 | 62 | void operator=(FuncWithCaptureT* fp) noexcept 63 | { 64 | this->fp = fp; 65 | this->cap.reset(); 66 | } 67 | 68 | void operator=(CallbackBase&& b) noexcept 69 | { 70 | fp = b.fp; 71 | cap = std::move(b.cap); 72 | } 73 | 74 | void operator=(const CallbackBase& b) noexcept = delete; 75 | 76 | void operator=(FuncT* fp) noexcept 77 | { 78 | this->fp = reinterpret_cast(fp); 79 | this->cap.reset(); 80 | } 81 | 82 | template , T>)> 83 | void operator=(T&& func) noexcept 84 | { 85 | fp = &redirect_to_std_function; 86 | cap = std::move(func); 87 | } 88 | 89 | [[nodiscard]] constexpr operator bool() const noexcept 90 | { 91 | return fp != nullptr; 92 | } 93 | 94 | void reset() 95 | { 96 | fp = nullptr; 97 | cap.reset(); 98 | } 99 | }; 100 | 101 | template 102 | struct Callback; 103 | 104 | template 105 | struct Callback : public CallbackBase 106 | { 107 | using Base = CallbackBase; 108 | 109 | using Base::Base; 110 | 111 | Ret operator() (Args&&...args) 112 | { 113 | return Base::fp(std::forward(args)..., std::move(Base::cap)); 114 | } 115 | }; 116 | 117 | template 118 | struct Callback 119 | { 120 | using FuncT = Ret(Args...) noexcept; 121 | using FuncWithCaptureT = Ret(Args..., Capture&&) noexcept; 122 | 123 | FuncWithCaptureT* fp; 124 | Capture cap; 125 | 126 | Callback() noexcept 127 | : fp(nullptr) 128 | { 129 | } 130 | 131 | Callback(const Callback&) = delete; 132 | 133 | Callback(Callback&& b) noexcept 134 | : fp(b.fp), cap(std::move(b.cap)) 135 | { 136 | } 137 | 138 | Callback(FuncT* fp) noexcept 139 | : fp(reinterpret_cast(fp)) 140 | { 141 | } 142 | 143 | Callback(FuncWithCaptureT* fp) noexcept 144 | : fp(fp) 145 | { 146 | } 147 | 148 | Callback(FuncWithCaptureT* fp, Capture&& cap) noexcept 149 | : fp(fp), cap(std::move(cap)) 150 | { 151 | } 152 | 153 | void set(FuncWithCaptureT* fp, Capture&& cap = {}) noexcept 154 | { 155 | this->fp = fp; 156 | this->cap = std::move(cap); 157 | } 158 | 159 | void operator=(FuncWithCaptureT* fp) noexcept 160 | { 161 | this->fp = fp; 162 | this->cap.reset(); 163 | } 164 | 165 | void operator=(Callback&& b) noexcept 166 | { 167 | fp = b.fp; 168 | cap = std::move(b.cap); 169 | } 170 | 171 | void operator=(const Callback& b) noexcept = delete; 172 | 173 | void operator=(FuncT* fp) noexcept 174 | { 175 | this->fp = reinterpret_cast(fp); 176 | this->cap.reset(); 177 | } 178 | 179 | [[nodiscard]] constexpr operator bool() const noexcept 180 | { 181 | return fp != nullptr; 182 | } 183 | 184 | void reset() 185 | { 186 | fp = nullptr; 187 | cap.reset(); 188 | } 189 | 190 | Ret operator() (Args&&...args) 191 | { 192 | return fp(std::forward(args)..., std::move(cap)); 193 | } 194 | }; 195 | 196 | template 197 | struct EventHandler; 198 | 199 | template 200 | struct EventHandler : public CallbackBase 201 | { 202 | using Base = CallbackBase; 203 | 204 | using Base::Base; 205 | 206 | Ret operator() (Args&&...args) const 207 | { 208 | return Base::fp(std::forward(args)..., Base::cap); 209 | } 210 | }; 211 | } 212 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/Compiler.cpp: -------------------------------------------------------------------------------- 1 | #include "Compiler.hpp" 2 | 3 | #include "base.hpp" 4 | 5 | #include "os.hpp" 6 | 7 | NAMESPACE_SOUP 8 | { 9 | Compiler::Compiler() 10 | : prog("clang"), 11 | #if SOUP_WINDOWS 12 | prog_ar("llvm-ar"), 13 | lang("c++20") 14 | #else 15 | // Debian's at clang 11 right now, which does support C++20, but not enough to compile Soup without modifications. 16 | prog_ar("ar"), 17 | lang("c++17") 18 | #endif 19 | { 20 | } 21 | 22 | bool Compiler::isEmscripten() const noexcept 23 | { 24 | return prog == "em++"; 25 | } 26 | 27 | bool Compiler::isCrossCompiler() const noexcept 28 | { 29 | return prog.find("mingw32") != std::string::npos; 30 | } 31 | 32 | std::vector Compiler::getArgs() const 33 | { 34 | std::vector args{ 35 | #if SOUP_WINDOWS 36 | "-D_CRT_SECURE_NO_WARNINGS", 37 | #endif 38 | "-ffunction-sections", "-fdata-sections", // dead code elimination 39 | "-std=" 40 | }; 41 | args.back().append(lang); 42 | #if SOUP_POSIX && !SOUP_WASM && !SOUP_ANDROID 43 | // Multi-threading on POSIX is delicate: It needs pthreads, but: 44 | // - Tons of extra requirements with Emscripten (WASM) 45 | // - Not supported on Termux (Android) 46 | // - Can't pass `-pthreads` when cross-compiling 47 | if (!isCrossCompiler()) 48 | { 49 | args.emplace_back("-pthreads"); 50 | args.emplace_back("-Wno-unused-command-line-argument"); // And the compiler will cry when pthreads isn't actually used... 51 | } 52 | #endif 53 | if (!rtti) 54 | { 55 | args.emplace_back("-fno-rtti"); 56 | } 57 | args.insert(args.end(), extra_args.begin(), extra_args.end()); 58 | return args; 59 | } 60 | 61 | void Compiler::addLinkerArgs(std::vector& args) const 62 | { 63 | #if SOUP_WINDOWS 64 | if (!isEmscripten()) 65 | { 66 | args.emplace_back("-luser32"); 67 | args.emplace_back("-lgdi32"); 68 | } 69 | args.emplace_back("-fuse-ld=lld"); 70 | #else 71 | #if SOUP_MACOS 72 | args.emplace_back("-lc++"); 73 | #else 74 | args.emplace_back("-fuse-ld=lld"); 75 | args.emplace_back("-Wl,--gc-sections,--icf=safe"); // dead code elimination 76 | args.emplace_back("-lstdc++"); 77 | #endif 78 | if (!isEmscripten()) 79 | { 80 | #if SOUP_LINUX 81 | args.emplace_back("-lstdc++fs"); 82 | #endif 83 | #if !SOUP_ANDROID 84 | if (!isCrossCompiler()) 85 | { 86 | args.emplace_back("-lresolv"); 87 | } 88 | #endif 89 | } 90 | args.emplace_back("-lm"); 91 | if (!isCrossCompiler()) 92 | { 93 | args.emplace_back("-ldl"); 94 | } 95 | #endif 96 | args.insert(args.end(), extra_linker_args.begin(), extra_linker_args.end()); 97 | } 98 | 99 | std::string Compiler::makeObject(const std::string& in, const std::string& out) const 100 | { 101 | auto args = getArgs(); 102 | args.emplace_back("-x"); 103 | args.emplace_back("c++"); 104 | args.emplace_back("-o"); 105 | args.emplace_back(out); 106 | args.emplace_back("-c"); 107 | args.emplace_back(in); 108 | return os::executeLong(prog, std::move(args)); 109 | } 110 | 111 | const char* Compiler::getExecutableExtension() noexcept 112 | { 113 | #if SOUP_WINDOWS 114 | return ".exe"; 115 | #else 116 | return ""; 117 | #endif 118 | } 119 | 120 | std::string Compiler::makeExecutable(const std::string& in, const std::string& out) const 121 | { 122 | auto args = getArgs(); 123 | args.emplace_back("-o"); 124 | args.emplace_back(out); 125 | args.emplace_back(in); 126 | addLinkerArgs(args); 127 | return os::executeLong(prog, std::move(args)); 128 | } 129 | 130 | std::string Compiler::makeExecutable(const std::vector& objects, const std::string& out) const 131 | { 132 | auto args = getArgs(); 133 | args.emplace_back("-o"); 134 | args.emplace_back(out); 135 | args.insert(args.end(), objects.begin(), objects.end()); 136 | addLinkerArgs(args); 137 | return os::executeLong(prog, std::move(args)); 138 | } 139 | 140 | const char* Compiler::getStaticLibraryExtension() noexcept 141 | { 142 | #if SOUP_WINDOWS 143 | return ".lib"; 144 | #else 145 | return ".a"; 146 | #endif 147 | } 148 | 149 | std::string Compiler::makeStaticLibrary(const std::vector& objects, const std::string& out) const 150 | { 151 | std::vector args = { "rc", out }; 152 | args.insert(args.end(), objects.begin(), objects.end()); 153 | #if !SOUP_MACOS 154 | return os::executeLong(prog_ar, std::move(args)); 155 | #else 156 | return os::execute(prog_ar, std::move(args)); 157 | #endif 158 | } 159 | 160 | const char* Compiler::getDynamicLibraryExtension() const 161 | { 162 | if (isEmscripten()) 163 | { 164 | return ".js"; 165 | } 166 | #if SOUP_MACOS 167 | return ".dylib"; 168 | #else 169 | #if SOUP_LINUX 170 | if (!isCrossCompiler()) 171 | { 172 | return ".so"; 173 | } 174 | #endif 175 | return ".dll"; 176 | #endif 177 | } 178 | 179 | std::string Compiler::makeDynamicLibrary(const std::string& in, const std::string& out) const 180 | { 181 | auto args = getArgs(); 182 | #if !SOUP_WINDOWS 183 | args.emplace_back("-fPIC"); 184 | args.emplace_back("-fvisibility=hidden"); 185 | #endif 186 | #if SOUP_MACOS 187 | args.emplace_back("-dynamiclib"); 188 | #else 189 | args.emplace_back("-shared"); 190 | #endif 191 | args.emplace_back("-o"); 192 | args.emplace_back(out); 193 | args.emplace_back(in); 194 | addLinkerArgs(args); 195 | return os::executeLong(prog, std::move(args)); 196 | } 197 | 198 | std::string Compiler::makeDynamicLibrary(const std::vector& objects, const std::string& out) const 199 | { 200 | auto args = getArgs(); 201 | #if !SOUP_WINDOWS 202 | // -fPIC and -fvisibility=hidden need to be set per object 203 | #endif 204 | #if SOUP_MACOS 205 | args.emplace_back("-dynamiclib"); 206 | #else 207 | args.emplace_back("-shared"); 208 | #endif 209 | args.emplace_back("-o"); 210 | args.emplace_back(out); 211 | args.insert(args.end(), objects.begin(), objects.end()); 212 | addLinkerArgs(args); 213 | return os::executeLong(prog, std::move(args)); 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/bitutil.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // size_t 4 | #include 5 | #include 6 | 7 | #include "base.hpp" 8 | 9 | NAMESPACE_SOUP 10 | { 11 | struct bitutil 12 | { 13 | template 14 | [[nodiscard]] static OutContainer msb_first(const InContainer& in) 15 | { 16 | OutContainer out; 17 | out.reserve((in.length() / tobits) * frombits); 18 | 19 | int acc = 0; 20 | int bits = 0; 21 | constexpr int maxv = (1 << tobits) - 1; 22 | constexpr int max_acc = (1 << (frombits + tobits - 1)) - 1; 23 | for (size_t i = 0; i < in.size(); ++i) 24 | { 25 | int value = (uint8_t)in[i]; 26 | acc = ((acc << frombits) | value) & max_acc; 27 | bits += frombits; 28 | while (bits >= tobits) 29 | { 30 | bits -= tobits; 31 | out.push_back((acc >> bits) & maxv); 32 | } 33 | } 34 | //if (pad) 35 | //{ 36 | if (bits) 37 | { 38 | out.push_back((acc << (tobits - bits)) & maxv); 39 | } 40 | //} 41 | //else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) 42 | //{ 43 | // return false; 44 | //} 45 | return out; 46 | } 47 | 48 | [[nodiscard]] static constexpr uint8_t getBitsNeededToEncodeRange(size_t range_size) // aka. ceil(log2(range_size)) 49 | { 50 | #if SOUP_CPP20 51 | if (std::is_constant_evaluated() 52 | #if SOUP_BITS > 32 53 | || range_size > 0xFFFFFFFF 54 | #endif 55 | ) 56 | { 57 | #endif 58 | uint8_t bits = 0; 59 | while ((((size_t)1) << bits) < range_size) 60 | { 61 | ++bits; 62 | } 63 | return bits; 64 | #if SOUP_CPP20 65 | } 66 | else 67 | { 68 | SOUP_IF_LIKELY (range_size > 1) 69 | { 70 | return getMostSignificantSetBit((uint32_t)range_size - 1) + 1; 71 | } 72 | return 0; 73 | } 74 | #endif 75 | } 76 | 77 | [[nodiscard]] static unsigned long getLeastSignificantSetBit(uint16_t mask) noexcept 78 | { 79 | SOUP_DEBUG_ASSERT(mask != 0); // UB! 80 | 81 | // These intrinsic functions just use the bsf instruction. 82 | #if defined(_MSC_VER) && !defined(__clang__) 83 | unsigned long ret; 84 | _BitScanForward(&ret, static_cast(mask)); 85 | return ret; 86 | #else 87 | return __builtin_ctz(mask); 88 | #endif 89 | } 90 | 91 | [[nodiscard]] static unsigned long getLeastSignificantSetBit(uint32_t mask) noexcept 92 | { 93 | SOUP_DEBUG_ASSERT(mask != 0); // UB! 94 | 95 | // These intrinsic functions just use the bsf instruction. 96 | #if defined(_MSC_VER) && !defined(__clang__) 97 | unsigned long ret; 98 | _BitScanForward(&ret, mask); 99 | return ret; 100 | #else 101 | return __builtin_ctz(mask); 102 | #endif 103 | } 104 | 105 | #if SOUP_BITS >= 64 106 | [[nodiscard]] static unsigned long getLeastSignificantSetBit(uint64_t mask) noexcept 107 | { 108 | SOUP_DEBUG_ASSERT(mask != 0); // UB! 109 | 110 | // These intrinsic functions just use the bsf instruction. 111 | #if defined(_MSC_VER) && !defined(__clang__) 112 | unsigned long ret; 113 | _BitScanForward64(&ret, mask); 114 | return ret; 115 | #else 116 | return __builtin_ctzll(mask); 117 | #endif 118 | } 119 | #endif 120 | 121 | [[nodiscard]] static unsigned int getNumTrailingZeros(uint16_t mask) noexcept 122 | { 123 | if (mask != 0) 124 | { 125 | return getLeastSignificantSetBit(mask); 126 | } 127 | return sizeof(mask) * 8; 128 | } 129 | 130 | [[nodiscard]] static unsigned int getNumTrailingZeros(uint32_t mask) noexcept 131 | { 132 | if (mask != 0) 133 | { 134 | return getLeastSignificantSetBit(mask); 135 | } 136 | return sizeof(mask) * 8; 137 | } 138 | 139 | #if SOUP_BITS >= 64 140 | [[nodiscard]] static unsigned int getNumTrailingZeros(uint64_t mask) noexcept 141 | { 142 | if (mask != 0) 143 | { 144 | return getLeastSignificantSetBit(mask); 145 | } 146 | return sizeof(mask) * 8; 147 | } 148 | #endif 149 | 150 | template 151 | static constexpr void unsetLeastSignificantSetBit(T& val) 152 | { 153 | val &= (val - 1); 154 | } 155 | 156 | [[nodiscard]] static unsigned int getNumLeadingZeros(uint32_t mask) noexcept 157 | { 158 | if (mask != 0) 159 | { 160 | #if defined(_MSC_VER) && !defined(__clang__) 161 | unsigned long idx; 162 | _BitScanReverse(&idx, mask); 163 | return 31 - idx; 164 | #else 165 | return __builtin_clz(mask); 166 | #endif 167 | } 168 | return 32; 169 | } 170 | 171 | [[nodiscard]] static unsigned int getMostSignificantSetBit(uint32_t mask) noexcept 172 | { 173 | SOUP_DEBUG_ASSERT(mask != 0); // UB! 174 | 175 | #if defined(_MSC_VER) && !defined(__clang__) 176 | unsigned long idx; 177 | _BitScanReverse(&idx, mask); 178 | return idx; 179 | #else 180 | return 31 - __builtin_clz(mask); 181 | #endif 182 | } 183 | 184 | [[nodiscard]] static auto getNumSetBits(uint16_t i) noexcept 185 | { 186 | #if defined(_MSC_VER) 187 | return __popcnt16(i); 188 | #else 189 | return __builtin_popcount(i); 190 | #endif 191 | } 192 | 193 | [[nodiscard]] static auto getNumSetBits(uint32_t i) noexcept 194 | { 195 | #if defined(_MSC_VER) && !defined(__clang__) 196 | return __popcnt(i); 197 | #else 198 | return __builtin_popcount(i); 199 | #endif 200 | } 201 | 202 | #if SOUP_BITS >= 64 203 | [[nodiscard]] static auto getNumSetBits(uint64_t i) noexcept 204 | { 205 | #if defined(_MSC_VER) && !defined(__clang__) 206 | return __popcnt64(i); 207 | #else 208 | return __builtin_popcountll(i); 209 | #endif 210 | } 211 | #endif 212 | 213 | // https://stackoverflow.com/a/2602885 214 | [[nodiscard]] static uint8_t reverse(uint8_t b) noexcept 215 | { 216 | b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; 217 | b = (b & 0xCC) >> 2 | (b & 0x33) << 2; 218 | b = (b & 0xAA) >> 1 | (b & 0x55) << 1; 219 | return b; 220 | } 221 | 222 | [[nodiscard]] static std::vector interleave(const std::vector>& data); // assumes that all inner vectors have the same size 223 | }; 224 | } 225 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/unicode.cpp: -------------------------------------------------------------------------------- 1 | #include "unicode.hpp" 2 | 3 | #include "bitutil.hpp" 4 | 5 | NAMESPACE_SOUP 6 | { 7 | char32_t unicode::utf8_to_utf32_char(std::string::const_iterator& it, const std::string::const_iterator end) noexcept 8 | { 9 | uint8_t ch = *it++; 10 | if (!UTF8_HAS_CONTINUATION(ch)) 11 | { 12 | return ch; 13 | } 14 | SOUP_IF_UNLIKELY (UTF8_IS_CONTINUATION(ch)) 15 | { 16 | return REPLACEMENT_CHAR; 17 | } 18 | 19 | // 11110xxx: todo = 3 20 | // 1110xxxx: todo = 2 21 | // 110xxxxx: todo = 1 22 | uint8_t todo = bitutil::getNumLeadingZeros(static_cast((uint8_t)~ch)) - 25; 23 | 24 | // Copy 'x' from above into 'uni' 25 | uint32_t uni = ch & ((1 << (6 - todo)) - 1); 26 | 27 | for (uint8_t j = 0; j != todo; ++j) 28 | { 29 | SOUP_IF_UNLIKELY (it == end) 30 | { 31 | return REPLACEMENT_CHAR; 32 | } 33 | uint8_t ch = *it++; 34 | SOUP_IF_UNLIKELY (!UTF8_IS_CONTINUATION(ch)) 35 | { 36 | --it; 37 | return REPLACEMENT_CHAR; 38 | } 39 | uni <<= 6; 40 | uni |= (ch & 0b111111); 41 | } 42 | /*SOUP_IF_UNLIKELY ((uni >= 0xD800 && uni <= 0xDFFF) 43 | || uni > 0x10FFFF 44 | ) 45 | { 46 | return REPLACEMENT_CHAR; 47 | }*/ 48 | return uni; 49 | } 50 | 51 | #if SOUP_CPP20 52 | std::u32string unicode::utf8_to_utf32(const char8_t* utf8) noexcept 53 | { 54 | return utf8_to_utf32(reinterpret_cast(utf8)); 55 | } 56 | #endif 57 | 58 | std::u32string unicode::utf8_to_utf32(const std::string& utf8) noexcept 59 | { 60 | std::u32string utf32{}; 61 | utf32.reserve(utf8_char_len(utf8)); 62 | auto it = utf8.cbegin(); 63 | const auto end = utf8.cend(); 64 | while (it != end) 65 | { 66 | utf32.push_back(utf8_to_utf32_char(it, end)); 67 | } 68 | return utf32; 69 | } 70 | 71 | #if SOUP_CPP20 72 | UTF16_STRING_TYPE unicode::utf8_to_utf16(const char8_t* utf8) noexcept 73 | { 74 | return utf8_to_utf16(reinterpret_cast(utf8)); 75 | } 76 | #endif 77 | 78 | UTF16_STRING_TYPE unicode::utf8_to_utf16(const std::string& utf8) noexcept 79 | { 80 | #if SOUP_WINDOWS 81 | std::wstring utf16; 82 | const int sizeRequired = MultiByteToWideChar(CP_UTF8, 0, utf8.data(), (int)utf8.size(), nullptr, 0); 83 | SOUP_IF_LIKELY (sizeRequired != 0) 84 | { 85 | utf16 = std::wstring(sizeRequired, 0); 86 | MultiByteToWideChar(CP_UTF8, 0, utf8.data(), (int)utf8.size(), utf16.data(), sizeRequired); 87 | } 88 | return utf16; 89 | #else 90 | UTF16_STRING_TYPE utf16{}; 91 | utf16.reserve(utf8.size()); // Note: we could end up with a slightly oversized buffer here if UTF8 input has many 3 or 4 byte symbols 92 | auto it = utf8.cbegin(); 93 | const auto end = utf8.cend(); 94 | while (it != end) 95 | { 96 | utf32_to_utf16_char(utf16, utf8_to_utf32_char(it, end)); 97 | } 98 | return utf16; 99 | #endif 100 | } 101 | 102 | #if SOUP_WINDOWS 103 | UTF16_STRING_TYPE unicode::acp_to_utf16(const std::string& acp) noexcept 104 | { 105 | std::wstring utf16; 106 | const int sizeRequired = MultiByteToWideChar(CP_ACP, 0, acp.data(), (int)acp.size(), nullptr, 0); 107 | SOUP_IF_LIKELY (sizeRequired != 0) 108 | { 109 | utf16 = std::wstring(sizeRequired, 0); 110 | MultiByteToWideChar(CP_ACP, 0, acp.data(), (int)acp.size(), utf16.data(), sizeRequired); 111 | } 112 | return utf16; 113 | } 114 | #endif 115 | 116 | UTF16_STRING_TYPE unicode::utf32_to_utf16(const std::u32string& utf32) noexcept 117 | { 118 | UTF16_STRING_TYPE utf16{}; 119 | utf16.reserve(utf32.size()); 120 | for (char32_t c : utf32) 121 | { 122 | utf32_to_utf16_char(utf16, c); 123 | } 124 | return utf16; 125 | } 126 | 127 | void unicode::utf32_to_utf16_char(UTF16_STRING_TYPE& utf16, char32_t c) noexcept 128 | { 129 | if (c <= 0xFFFF) 130 | { 131 | utf16.push_back((UTF16_CHAR_TYPE)c); 132 | } 133 | else 134 | { 135 | c -= 0x10000; 136 | utf16.push_back((UTF16_CHAR_TYPE)((c >> 10) + 0xD800)); 137 | utf16.push_back((UTF16_CHAR_TYPE)((c & 0x3FF) + 0xDC00)); 138 | } 139 | } 140 | 141 | std::string unicode::utf32_to_utf8(char32_t utf32) noexcept 142 | { 143 | // 1 144 | if (utf32 < 0b10000000) 145 | { 146 | return std::string(1, (char)utf32); 147 | } 148 | // 2 149 | std::string utf8(1, (char)((utf32 & 0b111111) | UTF8_CONTINUATION_FLAG)); 150 | utf32 >>= 6; 151 | if (utf32 <= 0b11111) 152 | { 153 | utf8.insert(0, 1, (char)(utf32 | 0b11000000)); // 110xxxxx 154 | return utf8; 155 | } 156 | // 3 157 | utf8.insert(0, 1, (char)((utf32 & 0b111111) | UTF8_CONTINUATION_FLAG)); 158 | utf32 >>= 6; 159 | if (utf32 <= 0b1111) 160 | { 161 | utf8.insert(0, 1, (char)(utf32 | 0b11100000)); // 1110xxxx 162 | return utf8; 163 | } 164 | // 4 165 | utf8.insert(0, 1, (char)((utf32 & 0b111111) | UTF8_CONTINUATION_FLAG)); 166 | utf32 >>= 6; 167 | utf8.insert(0, 1, (char)(utf32 | 0b11110000)); // 11110xxx 168 | return utf8; 169 | } 170 | 171 | std::string unicode::utf32_to_utf8(const std::u32string& utf32) noexcept 172 | { 173 | std::string utf8{}; 174 | utf8.reserve(utf32.size()); 175 | for (const char32_t& c : utf32) 176 | { 177 | utf8.append(utf32_to_utf8(c)); 178 | } 179 | return utf8; 180 | } 181 | 182 | size_t unicode::utf8_char_len(const std::string& str) noexcept 183 | { 184 | size_t char_len = 0; 185 | for (size_t i = 0; i != str.size(); ++i) 186 | { 187 | char_len += !UTF8_IS_CONTINUATION(str[i]); 188 | } 189 | return char_len; 190 | } 191 | 192 | size_t unicode::utf16_char_len(const UTF16_STRING_TYPE& str) noexcept 193 | { 194 | size_t char_len = 0; 195 | for (size_t i = 0; i != str.size(); ++i) 196 | { 197 | char_len += !UTF16_IS_LOW_SURROGATE(str[i]); 198 | } 199 | return char_len; 200 | } 201 | 202 | void unicode::utf8_sanitise(std::string& str) 203 | { 204 | for (auto it = str.cbegin(); it != str.cend(); ) 205 | { 206 | const auto char_begin = it; 207 | SOUP_IF_UNLIKELY (utf8_to_utf32_char(it, str.cend()) == REPLACEMENT_CHAR) 208 | { 209 | const auto off = char_begin - str.cbegin(); 210 | str.erase(char_begin, it); 211 | str.insert(off, "\xEF\xBF\xBD"); 212 | it = str.cbegin() + off + 3; 213 | } 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/CpuInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "CpuInfo.hpp" 2 | #if !SOUP_WASM 3 | 4 | #if SOUP_X86 5 | #include "string.hpp" 6 | 7 | #if defined(_MSC_VER) 8 | #include 9 | #else 10 | #include 11 | #endif 12 | #elif SOUP_ARM 13 | #if SOUP_WINDOWS 14 | #include 15 | #elif !SOUP_MACOS 16 | #include 17 | #endif 18 | #endif 19 | 20 | NAMESPACE_SOUP 21 | { 22 | CpuInfo::CpuInfo() noexcept 23 | { 24 | #if SOUP_X86 25 | #define EAX arr[0] 26 | #define EBX arr[1] 27 | #define EDX arr[2] 28 | #define ECX arr[3] 29 | 30 | char buf[17]; 31 | buf[16] = 0; 32 | invokeCpuid(buf, 0); 33 | cpuid_max_eax = *reinterpret_cast(&buf[0]); 34 | vendor_id = &buf[4]; 35 | 36 | uint32_t arr[4]; 37 | 38 | if (cpuid_max_eax >= 0x01) 39 | { 40 | invokeCpuid(arr, 0x01); 41 | stepping_id = (EAX & 0xF); 42 | model = ((EAX >> 4) & 0xF); 43 | family = ((EAX >> 8) & 0xF); 44 | feature_flags_ecx = ECX; 45 | feature_flags_edx = EDX; 46 | 47 | if (cpuid_max_eax >= 0x07) 48 | { 49 | invokeCpuid(arr, 0x07, 0); 50 | extended_features_max_ecx = EAX; 51 | extended_features_0_ebx = EBX; 52 | 53 | if (extended_features_max_ecx >= 1) 54 | { 55 | invokeCpuid(arr, 0x07, 1); 56 | extended_features_1_eax = EAX; 57 | } 58 | 59 | if (cpuid_max_eax >= 0x16) 60 | { 61 | invokeCpuid(arr, 0x16); 62 | base_frequency = EAX; 63 | max_frequency = EBX; 64 | bus_frequency = ECX; 65 | } 66 | } 67 | } 68 | 69 | invokeCpuid(arr, 0x80000000); 70 | cpuid_extended_max_eax = EAX; 71 | 72 | if (cpuid_extended_max_eax >= 0x80000001) 73 | { 74 | invokeCpuid(arr, 0x80000001); 75 | extended_flags_1_ecx = ECX; 76 | } 77 | 78 | #undef EAX 79 | #undef EBX 80 | #undef EDX 81 | #undef ECX 82 | #elif SOUP_ARM 83 | #if SOUP_WINDOWS 84 | armv8_aes = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); 85 | armv8_sha1 = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); 86 | armv8_sha2 = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); 87 | armv8_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE); 88 | #elif SOUP_BITS == 32 89 | armv8_aes = false; 90 | armv8_sha1 = false; 91 | armv8_sha2 = false; 92 | armv8_crc32 = false; 93 | #elif SOUP_MACOS 94 | // Assume we are running on an M series chip, because we don't have getauxval. 95 | armv8_aes = true; 96 | armv8_sha1 = true; 97 | armv8_sha2 = true; 98 | armv8_crc32 = true; 99 | #else 100 | // These HWCAP_* are only defined on aarch64. 101 | armv8_aes = getauxval(AT_HWCAP) & HWCAP_AES; 102 | armv8_sha1 = getauxval(AT_HWCAP) & HWCAP_SHA1; 103 | armv8_sha2 = getauxval(AT_HWCAP) & HWCAP_SHA2; 104 | armv8_crc32 = getauxval(AT_HWCAP) & HWCAP_CRC32; 105 | #endif 106 | #endif 107 | } 108 | 109 | std::string CpuInfo::toString() const SOUP_EXCAL 110 | { 111 | #if SOUP_X86 112 | std::string str = "CPUID Support Level: "; 113 | str.append(string::hex(cpuid_max_eax)); 114 | str.append("\nCPUID Extended Support Level: "); 115 | str.append(string::hex(cpuid_extended_max_eax & ~0x80000000)); 116 | str.append("\nVendor: "); 117 | str.append(vendor_id.c_str()); 118 | 119 | if (cpuid_max_eax >= 0x01) 120 | { 121 | str.append("\nStepping ID: ").append(std::to_string(stepping_id)); 122 | str.append("\nModel: ").append(std::to_string(model)); 123 | str.append("\nFamily: ").append(std::to_string(family)); 124 | 125 | if (base_frequency || max_frequency || bus_frequency) 126 | { 127 | str.append("\nBase Frequency: ").append(std::to_string(base_frequency)).append( 128 | " MHz\n" 129 | "Max. Frequency: " 130 | ).append(std::to_string(max_frequency)).append( 131 | " MHz\n" 132 | "Bus (Reference) Frequency: " 133 | ).append(std::to_string(bus_frequency)).append(" MHz"); 134 | } 135 | } 136 | 137 | str.append("\nSSE Support: "); 138 | if (supportsSSE4_2()) { str.append("SSE4.2"); } 139 | else if (supportsSSE4_1()) { str.append("SSE4.1"); } 140 | else if (supportsSSSE3()) { str.append("SSSE3"); } 141 | else if (supportsSSE3()) { str.append("SSE3"); } 142 | else if (supportsSSE2()) { str.append("SSE2"); } 143 | else if (supportsSSE()) { str.append("SSE"); } 144 | else { str.append("None"); } 145 | 146 | str.append("\nAVX Support: "); 147 | if (supportsAVX512F()) { str.append("AVX512F"); } 148 | else if (supportsAVX2()) { str.append("AVX2"); } 149 | else if (supportsAVX()) { str.append("AVX"); } 150 | else { str.append("None"); } 151 | 152 | std::string misc_features{}; 153 | if (supportsPCLMULQDQ()) { string::listAppend(misc_features, "PCLMULQDQ"); } 154 | if (supportsAESNI()) { string::listAppend(misc_features, "AESNI"); } 155 | if (supportsRDRAND()) { string::listAppend(misc_features, "RDRAND"); } 156 | if (supportsRDSEED()) { string::listAppend(misc_features, "RDSEED"); } 157 | if (supportsSHA()) { string::listAppend(misc_features, "SHA"); } 158 | if (supportsSHA512()) { string::listAppend(misc_features, "SHA512"); } 159 | if (supportsXOP()) { string::listAppend(misc_features, "supportsXOP"); } 160 | str.append("\nOther Known Features: ").append(misc_features); 161 | 162 | return str; 163 | #elif SOUP_ARM 164 | std::string str = "ARMv8 AES: "; 165 | str.append(armv8_aes ? "true" : "false"); 166 | str.append("\nARMv8 SHA1: ").append(armv8_sha1 ? "true" : "false"); 167 | str.append("\nARMv8 SHA2: ").append(armv8_sha2 ? "true" : "false"); 168 | str.append("\nARMv8 CRC32: ").append(armv8_crc32 ? "true" : "false"); 169 | return str; 170 | #endif 171 | } 172 | 173 | #if SOUP_X86 174 | void CpuInfo::invokeCpuid(void* out, uint32_t eax) noexcept 175 | { 176 | #if defined(_MSC_VER) 177 | __cpuid(((int*)out), eax); 178 | std::swap(((int*)out)[2], ((int*)out)[3]); 179 | #else 180 | __cpuid(eax, ((int*)out)[0], ((int*)out)[1], ((int*)out)[3], ((int*)out)[2]); 181 | #endif 182 | } 183 | 184 | void CpuInfo::invokeCpuid(void* out, uint32_t eax, uint32_t ecx) noexcept 185 | { 186 | #if defined(_MSC_VER) 187 | __cpuidex(((int*)out), eax, ecx); 188 | std::swap(((int*)out)[2], ((int*)out)[3]); 189 | #else 190 | __cpuid_count(eax, ecx, ((int*)out)[0], ((int*)out)[1], ((int*)out)[3], ((int*)out)[2]); 191 | #endif 192 | } 193 | #endif 194 | } 195 | 196 | #endif 197 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/base.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // === Namespace 4 | 5 | // When vendoring Soup, it is advisable to assign a unique namespace, like so: 6 | // 7 | // namespace soup { namespace PROJECTNAME_vendored {}; using namespace PROJECTNAME_vendored; }; 8 | // #define NAMESPACE_SOUP namespace soup::PROJECTNAME_vendored 9 | // 10 | // Note that this does not change the way you use Soup. 11 | 12 | #define NAMESPACE_SOUP namespace soup 13 | 14 | // === Platform/ABI macros 15 | 16 | #ifdef _WIN32 17 | #define SOUP_WINDOWS true 18 | #define SOUP_WASM false 19 | #define SOUP_LINUX false 20 | #define SOUP_POSIX false 21 | #define SOUP_MACOS false 22 | #define SOUP_ANDROID false 23 | 24 | #define SOUP_EXPORT __declspec(dllexport) 25 | 26 | #ifndef WIN32_LEAN_AND_MEAN 27 | #define WIN32_LEAN_AND_MEAN 28 | #endif 29 | 30 | #ifdef __MINGW32__ 31 | #define SOUP_CROSS_COMPILE true 32 | #if _WIN32_WINNT < 0x600 33 | #undef _WIN32_WINNT 34 | #define _WIN32_WINNT 0x600 35 | #endif 36 | #else 37 | #define SOUP_CROSS_COMPILE false 38 | #endif 39 | #else 40 | #define SOUP_WINDOWS false 41 | #define SOUP_POSIX true 42 | #define SOUP_CROSS_COMPILE false 43 | 44 | #ifdef __EMSCRIPTEN__ 45 | #define SOUP_WASM true 46 | #define SOUP_LINUX false 47 | #define SOUP_MACOS false 48 | 49 | #include "emscripten.h" 50 | #define SOUP_EXPORT EMSCRIPTEN_KEEPALIVE 51 | #else 52 | #define SOUP_WASM false 53 | 54 | #if defined(__linux__) && !defined(__ANDROID__) 55 | #define SOUP_LINUX true 56 | #else 57 | #define SOUP_LINUX false 58 | #endif 59 | 60 | #ifdef __ANDROID__ 61 | #define SOUP_ANDROID true 62 | #else 63 | #define SOUP_ANDROID false 64 | #endif 65 | 66 | #ifdef __APPLE__ 67 | #define SOUP_APPLE true 68 | #else 69 | #define SOUP_APPLE false 70 | #endif 71 | 72 | #if defined(__APPLE__) && defined(__MACH__) 73 | #define SOUP_MACOS true 74 | #else 75 | #define SOUP_MACOS false 76 | #endif 77 | 78 | #define SOUP_EXPORT __attribute__ ((visibility ("default"))) 79 | #endif 80 | #endif 81 | 82 | #define SOUP_CEXPORT extern "C" SOUP_EXPORT 83 | 84 | #if defined(_MSC_VER) && !defined(__clang__) 85 | #define SOUP_FORCEINLINE __forceinline 86 | #define SOUP_NOINLINE __declspec(noinline) 87 | #define SOUP_PURE __declspec(noalias) 88 | #define SOUP_UNIQADDR __restrict 89 | #else 90 | #define SOUP_FORCEINLINE __attribute__((always_inline)) inline 91 | #define SOUP_NOINLINE __attribute__((noinline)) 92 | #define SOUP_PURE __attribute__((pure)) 93 | #define SOUP_UNIQADDR __restrict__ 94 | #endif 95 | 96 | // === CPU macros 97 | 98 | #if defined(__x86_64__) || defined(_M_X64) || defined(__ppc64__) || defined(__aarch64__) || defined(_M_ARM64) 99 | #define SOUP_BITS 64 100 | #else 101 | #define SOUP_BITS 32 102 | #endif 103 | 104 | #if defined(__x86_64__) || defined(_M_X64) || defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86) 105 | #define SOUP_X86 true 106 | #else 107 | #define SOUP_X86 false 108 | #endif 109 | 110 | #if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64) 111 | #define SOUP_ARM true 112 | #if defined(__clang_major__) && __clang_major__ <= 14 && !defined(__ARM_FEATURE_CRYPTO) 113 | #error Your version of Clang predates some important fixes for ARM codegen. Provide -march=armv8+crypto+crc to compile Soup. Note that the resulting binary may be incorrect. 114 | #endif 115 | #else 116 | #define SOUP_ARM false 117 | #endif 118 | 119 | // === Determine if code inspector 120 | 121 | #ifdef __INTELLISENSE__ 122 | #define SOUP_CODE_INSPECTOR true 123 | #else 124 | #define SOUP_CODE_INSPECTOR false 125 | #endif 126 | 127 | // === C++ conditional feature macros 128 | 129 | #ifdef _MSVC_LANG 130 | #define SOUP_CPP_VERSION _MSVC_LANG 131 | #else 132 | #define SOUP_CPP_VERSION __cplusplus 133 | #endif 134 | 135 | #if SOUP_CPP_VERSION < 2020'00L 136 | #define SOUP_CPP20 false 137 | #else 138 | #define SOUP_CPP20 true 139 | #endif 140 | 141 | #if SOUP_CPP20 142 | #define SOUP_CONSTEVAL consteval 143 | #define SOUP_CONSTEXPR20 constexpr 144 | #else 145 | #define SOUP_CONSTEVAL constexpr 146 | #define SOUP_CONSTEXPR20 147 | #endif 148 | 149 | #if SOUP_CPP20 150 | #define SOUP_IF_LIKELY(...) if (__VA_ARGS__) [[likely]] 151 | #define SOUP_IF_UNLIKELY(...) if (__VA_ARGS__) [[unlikely]] 152 | #else 153 | #define SOUP_IF_LIKELY(...) if (__VA_ARGS__) 154 | #define SOUP_IF_UNLIKELY(...) if (__VA_ARGS__) 155 | #endif 156 | 157 | #if SOUP_CPP_VERSION < 2023'00L 158 | #define SOUP_CPP23 false 159 | #else 160 | #define SOUP_CPP23 true 161 | #endif 162 | 163 | #if SOUP_CPP23 164 | #define SOUP_ASSUME(...) [[assume(__VA_ARGS__)]]; 165 | #define SOUP_UNREACHABLE std::unreachable(); 166 | #else 167 | #if defined(_MSC_VER) && !defined(__clang__) 168 | #define SOUP_ASSUME(...) __assume(__VA_ARGS__); 169 | #define SOUP_UNREACHABLE SOUP_ASSUME(false); 170 | #else 171 | #define SOUP_ASSUME(...) ; 172 | #define SOUP_UNREACHABLE __builtin_unreachable(); 173 | #endif 174 | #endif 175 | 176 | #if (__cpp_exceptions < 1997'11L) && (!defined(_MSC_VER) || defined(__clang__)) 177 | #define SOUP_EXCEPTIONS false 178 | #define SOUP_TRY if (true) 179 | #define SOUP_CATCH(T, name) if (const T& name = *(T*)nullptr; false) 180 | #define SOUP_CATCH_ANY if (false) 181 | #define SOUP_THROW(x) ::soup::throwImpl(x); 182 | 183 | #include 184 | 185 | NAMESPACE_SOUP 186 | { 187 | [[noreturn]] void throwImpl(std::exception&& e); 188 | } 189 | #else 190 | #define SOUP_EXCEPTIONS true 191 | #define SOUP_TRY try 192 | #define SOUP_CATCH(T, name) catch (const T& name) 193 | #define SOUP_CATCH_ANY catch (...) 194 | #define SOUP_THROW(x) throw x; 195 | #endif 196 | 197 | #ifndef SOUP_EXCAL 198 | // An 'excal' function may not throw any exception other than std::bad_alloc (in case of an allocation failure). 199 | // 200 | // If you don't handle allocate failures, you can slightly reduce your binary size by setting this macro to `noexcept` or `throw()`. 201 | #define SOUP_EXCAL 202 | #endif 203 | 204 | // === Development helpers 205 | 206 | NAMESPACE_SOUP 207 | { 208 | [[noreturn]] void throwAssertionFailed(); 209 | [[noreturn]] void throwAssertionFailed(const char* what); 210 | } 211 | #define SOUP_ASSERT(x, ...) SOUP_IF_UNLIKELY (!(x)) { ::soup::throwAssertionFailed(__VA_ARGS__); } 212 | #define SOUP_ASSERT_UNREACHABLE ::soup::throwAssertionFailed(); 213 | 214 | #ifndef NDEBUG 215 | #define SOUP_DEBUG_ASSERT(x) SOUP_ASSERT(x) 216 | #define SOUP_DEBUG_ASSERT_UNREACHABLE SOUP_UNREACHABLE 217 | #else 218 | #define SOUP_DEBUG_ASSERT(x) SOUP_ASSUME(x) 219 | #define SOUP_DEBUG_ASSERT_UNREACHABLE SOUP_ASSERT_UNREACHABLE 220 | #endif 221 | 222 | template SOUP_FORCEINLINE void SOUP_UNUSED(T&&) {} 223 | 224 | #define SOUP_RETHROW_FALSE(x) SOUP_IF_UNLIKELY (!(x)) { return {}; } 225 | 226 | // Enable compiler warning for unannotated fallthroughs 227 | #if defined(__clang__) 228 | #pragma clang diagnostic warning "-Wimplicit-fallthrough" 229 | //#elif defined(_MSC_VER) 230 | //#pragma warning(default: 5262) // MSVC is too retarded, it thinks everything is an implicit fallthrough. 231 | #elif defined(__GNUC__) 232 | #pragma GCC diagnostic warning "-Wimplicit-fallthrough" 233 | #endif 234 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/SharedPtr.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include // destroy_at 5 | 6 | #include "Exception.hpp" 7 | #include "memory.hpp" // construct_at 8 | #include "type_traits.hpp" 9 | 10 | #ifndef SOUP_DEBUG_SHAREDPTR 11 | #define SOUP_DEBUG_SHAREDPTR false 12 | #endif 13 | 14 | #if SOUP_DEBUG_SHAREDPTR 15 | #include 16 | #include 17 | #endif 18 | 19 | NAMESPACE_SOUP 20 | { 21 | template 22 | class SharedPtr 23 | { 24 | public: 25 | #if SOUP_DEBUG_SHAREDPTR 26 | inline static std::unordered_set managed_instances{}; 27 | #endif 28 | 29 | struct Data 30 | { 31 | T* inst; 32 | std::atomic_uint refcount; 33 | bool was_created_with_make_shared = false; 34 | 35 | Data(T* inst) noexcept 36 | : inst(inst), refcount(1) 37 | { 38 | #if SOUP_DEBUG_SHAREDPTR 39 | SOUP_ASSERT(inst != nullptr); 40 | #endif 41 | #if SOUP_DEBUG_SHAREDPTR 42 | if (managed_instances.contains(inst)) 43 | { 44 | __debugbreak(); // Already managed by another SharedPtr instance 45 | } 46 | managed_instances.emplace(inst); 47 | std::cout << (void*)inst << " :: New SharedPtr\n"; 48 | #endif 49 | } 50 | 51 | void incref() noexcept 52 | { 53 | #if SOUP_DEBUG_SHAREDPTR 54 | const auto refcount_now = ++refcount; 55 | if (refcount_now == 1) 56 | { 57 | __debugbreak(); // Attempt to revive the dead 58 | } 59 | std::cout << (void*)inst << " :: Increment to " << refcount_now << "\n"; 60 | #else 61 | ++refcount; 62 | #endif 63 | } 64 | 65 | void decref() noexcept 66 | { 67 | #if SOUP_DEBUG_SHAREDPTR 68 | const auto predec = refcount.load(); 69 | #endif 70 | if (--refcount == 0) 71 | { 72 | #if SOUP_DEBUG_SHAREDPTR 73 | std::cout << (void*)inst << " :: Decrement to 0; destroying instance\n"; 74 | managed_instances.erase(inst); 75 | #endif 76 | if (was_created_with_make_shared) 77 | { 78 | const auto inst = this->inst; 79 | std::destroy_at<>(inst); 80 | std::destroy_at<>(this); 81 | ::operator delete(reinterpret_cast(inst)); 82 | } 83 | else 84 | { 85 | delete inst; 86 | delete this; 87 | } 88 | } 89 | #if SOUP_DEBUG_SHAREDPTR 90 | else 91 | { 92 | std::cout << (void*)inst << " :: Decrement to " << refcount.load() << "\n"; 93 | } 94 | #endif 95 | } 96 | }; 97 | 98 | std::atomic data; 99 | 100 | SharedPtr() noexcept 101 | : data(nullptr) 102 | { 103 | } 104 | 105 | SharedPtr(Data* data) noexcept 106 | : data(data) 107 | { 108 | } 109 | 110 | SharedPtr(T* inst) SOUP_EXCAL 111 | : data(new Data(inst)) 112 | { 113 | } 114 | 115 | SharedPtr(const SharedPtr& b) noexcept 116 | : data(b.data.load()) 117 | { 118 | if (data != nullptr) 119 | { 120 | data.load()->incref(); 121 | } 122 | } 123 | 124 | SharedPtr(SharedPtr&& b) noexcept 125 | : data(b.data.load()) 126 | { 127 | b.data = nullptr; 128 | } 129 | 130 | // reinterpret_cast is okay because it contains a pointer to the actual instance, so it's all the same regardless of T. 131 | 132 | template || std::is_base_of_v)> 133 | SharedPtr(const SharedPtr& b) noexcept 134 | : data(reinterpret_cast(b.data.load())) 135 | { 136 | if (data != nullptr) 137 | { 138 | data.load()->incref(); 139 | } 140 | } 141 | 142 | template || std::is_base_of_v)> 143 | SharedPtr(SharedPtr&& b) noexcept 144 | : data(reinterpret_cast(b.data.load())) 145 | { 146 | b.data = nullptr; 147 | } 148 | 149 | void operator=(const SharedPtr& b) noexcept 150 | { 151 | Data* const prev_data = this->data; 152 | Data* const new_data = b.data; 153 | this->data = new_data; 154 | if (new_data != nullptr) 155 | { 156 | new_data->incref(); 157 | } 158 | if (prev_data != nullptr) 159 | { 160 | #if SOUP_DEBUG_SHAREDPTR 161 | SOUP_ASSERT(prev_data != this->data); 162 | #endif 163 | prev_data->decref(); 164 | } 165 | } 166 | 167 | void operator=(SharedPtr&& b) noexcept 168 | { 169 | Data* const prev_data = this->data; 170 | this->data = b.data.load(); 171 | b.data = nullptr; 172 | if (prev_data != nullptr) 173 | { 174 | #if SOUP_DEBUG_SHAREDPTR 175 | SOUP_ASSERT(prev_data != this->data); 176 | #endif 177 | prev_data->decref(); 178 | } 179 | } 180 | 181 | ~SharedPtr() noexcept 182 | { 183 | if (data.load() != nullptr) 184 | { 185 | data.load()->decref(); 186 | } 187 | } 188 | 189 | void reset() noexcept 190 | { 191 | Data* const data = this->data; 192 | if (data != nullptr) 193 | { 194 | this->data = nullptr; 195 | data->decref(); 196 | } 197 | } 198 | 199 | [[nodiscard]] operator bool() const noexcept 200 | { 201 | return data != nullptr; 202 | } 203 | 204 | [[nodiscard]] operator T* () const noexcept 205 | { 206 | return get(); 207 | } 208 | 209 | [[nodiscard]] T* get() const noexcept 210 | { 211 | Data* const data = this->data; 212 | if (data) 213 | { 214 | return data->inst; 215 | } 216 | return nullptr; 217 | } 218 | 219 | [[nodiscard]] T& operator*() const noexcept 220 | { 221 | return *get(); 222 | } 223 | 224 | [[nodiscard]] T* operator->() const noexcept 225 | { 226 | return get(); 227 | } 228 | 229 | [[nodiscard]] size_t getRefCount() const noexcept 230 | { 231 | return data.load()->refcount.load(); 232 | } 233 | 234 | [[nodiscard]] T* release() 235 | { 236 | Data* const data = this->data; 237 | this->data = nullptr; 238 | if (data->refcount.load() != 1) 239 | { 240 | this->data = data; 241 | SOUP_THROW(Exception("Attempt to release SharedPtr with more than 1 reference")); 242 | } 243 | T* const inst = data->inst; 244 | const auto was_created_with_make_shared = data->was_created_with_make_shared; 245 | std::destroy_at<>(data); 246 | if (was_created_with_make_shared) 247 | { 248 | // data will continue to be allocated behind the instance, but once the instance is free'd, data is also free'd. 249 | } 250 | else 251 | { 252 | ::operator delete(reinterpret_cast(data)); 253 | } 254 | return inst; 255 | } 256 | }; 257 | 258 | template )> 259 | [[nodiscard]] SharedPtr make_shared(Args&&...args) 260 | { 261 | struct Combined 262 | { 263 | alignas(T) char t[sizeof(T)]; 264 | typename SharedPtr::Data data; 265 | }; 266 | 267 | void* const b = ::operator new(sizeof(Combined)); 268 | typename SharedPtr::Data* data; 269 | SOUP_TRY 270 | { 271 | auto inst = soup::construct_at<>(reinterpret_cast(b), std::forward(args)...); 272 | data = soup::construct_at<>(reinterpret_cast::Data*>(reinterpret_cast(b) + offsetof(Combined, data)), inst); 273 | } 274 | SOUP_CATCH_ANY 275 | { 276 | ::operator delete(b); 277 | std::rethrow_exception(std::current_exception()); 278 | } 279 | data->was_created_with_make_shared = true; 280 | return SharedPtr(data); 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/Writer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ioBase.hpp" 4 | 5 | #include "fwd.hpp" 6 | 7 | NAMESPACE_SOUP 8 | { 9 | class Writer : public ioBase 10 | { 11 | public: 12 | using ioBase::ioBase; 13 | 14 | bool skip(size_t len) noexcept 15 | { 16 | uint8_t v = 0; 17 | while (len--) 18 | { 19 | u8(v); 20 | } 21 | return true; 22 | } 23 | 24 | // An unsigned 64-bit integer encoded in 1..9 bytes. The most significant bit of bytes 1 to 8 is used to indicate if another byte follows. 25 | // https://github.com/calamity-inc/u64_dyn 26 | bool u64_dyn(const uint64_t& v) noexcept; 27 | 28 | // A signed 64-bit integer encoded in 1..9 bytes. (Specialisation of u64_dyn.) 29 | // https://github.com/calamity-inc/u64_dyn 30 | bool i64_dyn(const int64_t& v) noexcept; 31 | 32 | // An unsigned 64-bit integer encoded in 1..9 bytes. This is a slightly more efficient version of u64_dyn, e.g. 0x4000..0x407f are encoded in 2 bytes instead of 3. 33 | // https://github.com/calamity-inc/u64_dyn 34 | bool u64_dyn_v2(const uint64_t& v) noexcept; 35 | 36 | // A signed 64-bit integer encoded in 1..9 bytes. (Specialisation of u64_dyn_v2. This revision also simplifies how negative integers are handled.) 37 | // https://github.com/calamity-inc/u64_dyn 38 | bool i64_dyn_v2(const int64_t& v) noexcept; 39 | 40 | // An integer where every byte's most significant bit is used to indicate if another byte follows, most significant byte first. 41 | template 42 | bool om(const Int& v) noexcept 43 | { 44 | bool ret = true; 45 | auto chunks = 0; 46 | { 47 | Int val = v; 48 | while (true) 49 | { 50 | val >>= 7; 51 | if (!val) 52 | { 53 | break; 54 | } 55 | ++chunks; 56 | } 57 | } 58 | do 59 | { 60 | uint8_t byte = ((v >> (chunks * 7)) & 0x7F); 61 | if (chunks != 0) 62 | { 63 | byte |= 0x80; 64 | } 65 | ret &= u8(byte); 66 | } while (chunks--); 67 | return ret; 68 | } 69 | 70 | // An integer where every byte's most significant bit is used to indicate if another byte follows, least significant byte first. This is compatible with unsigned LEB128. 71 | template 72 | bool oml(const Int& v) noexcept 73 | { 74 | bool ret = true; 75 | Int in = v; 76 | while (true) 77 | { 78 | uint8_t byte = (in & 0x7F); 79 | in >>= 7; 80 | if (in == 0) 81 | { 82 | ret &= u8(byte); 83 | break; 84 | } 85 | byte |= 0x80; 86 | ret &= u8(byte); 87 | } 88 | return ret; 89 | } 90 | 91 | // Signed LEB128. 92 | template 93 | bool soml(const Int& v) noexcept 94 | { 95 | bool ret = true; 96 | Int in = v; 97 | while (true) 98 | { 99 | uint8_t byte = (in & 0x7F); 100 | in >>= 7; 101 | if ((byte & 0x40) ? (in == -1) : (in == 0)) 102 | { 103 | ret &= u8(byte); 104 | break; 105 | } 106 | byte |= 0x80; 107 | ret &= u8(byte); 108 | } 109 | return ret; 110 | } 111 | 112 | bool mysql_lenenc(const uint64_t& v) noexcept; 113 | 114 | // Null-terminated string. 115 | bool str_nt(const std::string& v) noexcept 116 | { 117 | bool ret = raw(const_cast(v.data()), v.size()); 118 | uint8_t term = 0; 119 | ret &= u8(term); 120 | return ret; 121 | } 122 | 123 | // Length-prefixed string. 124 | template 125 | bool str_lp(const std::string& v, const T max_len = -1) noexcept 126 | { 127 | size_t len = v.size(); 128 | SOUP_IF_LIKELY (len <= max_len) 129 | { 130 | #ifdef _MSC_VER 131 | #pragma warning(push) 132 | #pragma warning(disable: 4267) // possible loss of data 133 | #endif 134 | auto tl = static_cast(len); 135 | #ifdef _MSC_VER 136 | #pragma warning(pop) 137 | #endif 138 | bool ret = ser(tl); 139 | ret &= raw(const_cast(v.data()), v.size()); 140 | return ret; 141 | } 142 | return false; 143 | } 144 | 145 | // Length-prefixed string, using u64_dyn for the length prefix. 146 | bool str_lp_u64_dyn(const std::string& v) noexcept 147 | { 148 | bool ret = u64_dyn(v.size()); 149 | ret &= raw(const_cast(v.data()), v.size()); 150 | return ret; 151 | } 152 | 153 | // Length-prefixed string, using u64_dyn_v2 for the length prefix. 154 | bool str_lp_u64_dyn_v2(const std::string& v) noexcept 155 | { 156 | bool ret = u64_dyn_v2(v.size()); 157 | ret &= raw(const_cast(v.data()), v.size()); 158 | return ret; 159 | } 160 | 161 | // Length-prefixed string, using mysql_lenenc for the length prefix. 162 | bool str_lp_mysql(const std::string& v) noexcept 163 | { 164 | bool ret = mysql_lenenc(v.size()); 165 | ret &= raw(const_cast(v.data()), v.size()); 166 | return ret; 167 | } 168 | 169 | // String with known length. 170 | bool str(size_t len, const std::string& v) noexcept 171 | { 172 | size_t pad = (len - v.size()); 173 | bool ret = raw(const_cast(v.data()), v.size()); 174 | ret &= skip(pad); 175 | return ret; 176 | } 177 | 178 | // String with known length. 179 | bool str(size_t len, const char* v) noexcept 180 | { 181 | return raw(const_cast(v), len); 182 | } 183 | 184 | // std::vector with u8 size prefix. 185 | bool vec_u8_u8(std::vector& v) noexcept 186 | { 187 | SOUP_RETHROW_FALSE(v.size() <= 0xFF); 188 | bool ret = true; 189 | auto len = (uint8_t)v.size(); 190 | ret &= u8(len); 191 | for (auto& entry : v) 192 | { 193 | ret &= u8(entry); 194 | } 195 | return ret; 196 | } 197 | 198 | // vector of u16 with u16 byte length prefix, using big endian over-the-wire. 199 | bool vec_u16_bl_u16_be(std::vector& v) noexcept 200 | { 201 | size_t bl = (v.size() * sizeof(uint16_t)); 202 | SOUP_RETHROW_FALSE(bl <= 0xFFFF); 203 | bool ret = true; 204 | auto bl_u16 = (uint16_t)bl; 205 | ret &= ioBase::u16_be(bl_u16); 206 | for (auto& entry : v) 207 | { 208 | ret &= ioBase::u16_be(entry); 209 | } 210 | return ret; 211 | } 212 | 213 | // vector of str_nt with u64_dyn length prefix. 214 | bool vec_str_nt_u64_dyn(std::vector& v) noexcept 215 | { 216 | bool ret = true; 217 | uint64_t len = v.size(); 218 | ret &= u64_dyn(len); 219 | for (auto& entry : v) 220 | { 221 | ret &= str_nt(entry); 222 | } 223 | return ret; 224 | } 225 | 226 | // vector of str_lp with u24_be byte length prefix. 227 | bool vec_str_lp_u24_bl_u24_be(std::vector& v) noexcept 228 | { 229 | size_t bl = (v.size() * 3); 230 | for (const auto& entry : v) 231 | { 232 | bl += entry.size(); 233 | } 234 | SOUP_RETHROW_FALSE(bl <= 0xFFFFFF); 235 | bool ret = true; 236 | auto bl_u32 = (uint32_t)bl; 237 | ret &= ioBase::u24_be(bl_u32); 238 | for (auto& entry : v) 239 | { 240 | ret &= str_lp(entry); 241 | } 242 | return ret; 243 | } 244 | 245 | // vector of str_lp with u16_be byte length prefix. 246 | bool vec_str_lp_u8_bl_u16_be(std::vector& v) SOUP_EXCAL 247 | { 248 | size_t bl = v.size(); 249 | for (const auto& entry : v) 250 | { 251 | bl += entry.size(); 252 | } 253 | SOUP_RETHROW_FALSE(bl <= 0xFFFF); 254 | bool ret = true; 255 | auto bl_u16 = (uint16_t)bl; 256 | ret &= ioBase::u16_be(bl_u16); 257 | for (auto& entry : v) 258 | { 259 | ret &= str_lp(entry); 260 | } 261 | return ret; 262 | } 263 | }; 264 | } 265 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/ioBase.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Endian.hpp" 8 | #include "IntStruct.hpp" 9 | 10 | NAMESPACE_SOUP 11 | { 12 | // The following types can be used with ioBase::ser<>. 13 | // For u16 and up, they specify if they are serialised as big endian or little endian. The in-memory format is still expected to be native endian. 14 | using u8_t = uint8_t; 15 | SOUP_INT_STRUCT(u16_be_t, uint16_t); 16 | SOUP_INT_STRUCT(u24_be_t, uint32_t); 17 | SOUP_INT_STRUCT(u32_be_t, uint32_t); 18 | SOUP_INT_STRUCT(u16_le_t, uint16_t); 19 | SOUP_INT_STRUCT(u24_le_t, uint32_t); 20 | SOUP_INT_STRUCT(u32_le_t, uint32_t); 21 | 22 | class ioVirtualBase 23 | { 24 | protected: 25 | ioVirtualBase() noexcept 26 | { 27 | } 28 | 29 | public: 30 | virtual ~ioVirtualBase() = default; 31 | 32 | virtual bool raw(void* data, size_t len) noexcept = 0; 33 | [[nodiscard]] virtual size_t getPosition() = 0; 34 | 35 | bool b(bool& v) noexcept 36 | { 37 | return u8(*(uint8_t*)&v); 38 | } 39 | 40 | bool c(char& v) noexcept 41 | { 42 | return u8(*(uint8_t*)&v); 43 | } 44 | 45 | bool u8(uint8_t& v) noexcept 46 | { 47 | return raw(&v, sizeof(v)); 48 | } 49 | }; 50 | 51 | template 52 | class ioBase : public ioVirtualBase 53 | { 54 | protected: 55 | using ioVirtualBase::ioVirtualBase; 56 | 57 | public: 58 | [[nodiscard]] static constexpr bool isRead() noexcept 59 | { 60 | return is_read; 61 | } 62 | 63 | [[nodiscard]] static constexpr bool isWrite() noexcept 64 | { 65 | return !isRead(); 66 | } 67 | 68 | template 69 | bool ser(T& v) noexcept; 70 | 71 | [[deprecated("Renamed to u16_be")]] bool u16be(uint16_t& v) noexcept { return u16_be(v); } 72 | [[deprecated("Renamed to u16_le")]] bool u16le(uint16_t& v) noexcept { return u16_le(v); } 73 | 74 | bool u16_be(uint16_t& v) noexcept 75 | { 76 | return u16(v); 77 | } 78 | 79 | bool u16_le(uint16_t& v) noexcept 80 | { 81 | return u16(v); 82 | } 83 | 84 | protected: 85 | template 86 | bool u16(uint16_t& v) noexcept 87 | { 88 | if constexpr (native_endianness) 89 | { 90 | return raw(&v, sizeof(v)); 91 | } 92 | else 93 | { 94 | if constexpr (is_read) 95 | { 96 | return raw(&v, sizeof(v)) 97 | && (v = Endianness::invert(v), true) 98 | ; 99 | } 100 | else 101 | { 102 | auto tmp = Endianness::invert(v); 103 | return raw(&tmp, sizeof(v)); 104 | } 105 | } 106 | } 107 | 108 | public: 109 | [[deprecated("Renamed to u32_be")]] bool u32be(uint32_t& v) noexcept { return u32_be(v); } 110 | [[deprecated("Renamed to u32_le")]] bool u32le(uint32_t& v) noexcept { return u32_le(v); } 111 | 112 | bool u32_be(uint32_t& v) noexcept 113 | { 114 | return u32(v); 115 | } 116 | 117 | bool u32_le(uint32_t& v) noexcept 118 | { 119 | return u32(v); 120 | } 121 | 122 | protected: 123 | template 124 | bool u32(uint32_t& v) noexcept 125 | { 126 | if constexpr (native_endianness) 127 | { 128 | return raw(&v, sizeof(v)); 129 | } 130 | else 131 | { 132 | if constexpr (is_read) 133 | { 134 | return raw(&v, sizeof(v)) 135 | && (v = Endianness::invert(v), true) 136 | ; 137 | } 138 | else 139 | { 140 | auto tmp = Endianness::invert(v); 141 | return raw(&tmp, sizeof(v)); 142 | } 143 | } 144 | } 145 | 146 | public: 147 | [[deprecated("Renamed to u64_be")]] bool u64be(uint64_t& v) noexcept { return u64_be(v); } 148 | [[deprecated("Renamed to u64_le")]] bool u64le(uint64_t& v) noexcept { return u64_le(v); } 149 | 150 | bool u64_be(uint64_t& v) noexcept 151 | { 152 | return u64(v); 153 | } 154 | 155 | bool u64_le(uint64_t& v) noexcept 156 | { 157 | return u64(v); 158 | } 159 | 160 | protected: 161 | template 162 | bool u64(uint64_t& v) noexcept 163 | { 164 | if constexpr (native_endianness) 165 | { 166 | return raw(&v, sizeof(v)); 167 | } 168 | else 169 | { 170 | if constexpr (is_read) 171 | { 172 | return raw(&v, sizeof(v)) 173 | && (v = Endianness::invert(v), true) 174 | ; 175 | } 176 | else 177 | { 178 | auto tmp = Endianness::invert(v); 179 | return raw(&tmp, sizeof(v)); 180 | } 181 | } 182 | } 183 | 184 | public: 185 | bool i8(int8_t& v) noexcept 186 | { 187 | return u8(*(uint8_t*)&v); 188 | } 189 | 190 | [[deprecated("Renamed to i16_be")]] bool i16le(int16_t& v) noexcept { return i16_be(v); } 191 | [[deprecated("Renamed to i16_le")]] bool i16be(int16_t& v) noexcept { return i16_le(v); } 192 | 193 | bool i16(int16_t& v) noexcept { return u16(*(uint16_t*)&v); } 194 | bool i16_le(int16_t& v) noexcept { return u16_le(*(uint16_t*)&v); } 195 | bool i16_be(int16_t& v) noexcept { return u16_be(*(uint16_t*)&v); } 196 | 197 | [[deprecated("Renamed to i32_be")]] bool i32le(int32_t& v) noexcept { return i32_be(v); } 198 | [[deprecated("Renamed to i32_le")]] bool i32be(int32_t& v) noexcept { return i32_le(v); } 199 | 200 | bool i32(int32_t& v) noexcept { return u32(*(uint32_t*)&v); } 201 | bool i32_le(int32_t& v) noexcept { return u32_le(*(uint32_t*)&v); } 202 | bool i32_be(int32_t& v) noexcept { return u32_be(*(uint32_t*)&v); } 203 | 204 | [[deprecated("Renamed to i64_be")]] bool i64le(int64_t& v) noexcept { return i64_be(v); } 205 | [[deprecated("Renamed to i64_le")]] bool i64be(int64_t& v) noexcept { return i64_le(v); } 206 | 207 | bool i64(int64_t& v) noexcept { return u64(*(uint64_t*)&v); } 208 | bool i64_le(int64_t& v) noexcept { return u64_le(*(uint64_t*)&v); } 209 | bool i64_be(int64_t& v) noexcept { return u64_be(*(uint64_t*)&v); } 210 | 211 | [[deprecated("Renamed to u24_be")]] bool u24be(uint32_t& v) noexcept { return u24_be(v); } 212 | [[deprecated("Renamed to u24_le")]] bool u24le(uint32_t& v) noexcept { return u24_le(v); } 213 | 214 | bool u24_be(uint32_t& v) noexcept 215 | { 216 | return u24(v); 217 | } 218 | 219 | bool u24_le(uint32_t& v) noexcept 220 | { 221 | return u24(v); 222 | } 223 | 224 | protected: 225 | template 226 | bool u24(uint32_t& v) noexcept 227 | { 228 | if constexpr (is_read) 229 | { 230 | v = 0; 231 | } 232 | if constexpr (native_endianness) 233 | { 234 | return u8(((uint8_t*)&v)[0]) 235 | && u8(((uint8_t*)&v)[1]) 236 | && u8(((uint8_t*)&v)[2]); 237 | } 238 | else 239 | { 240 | return u8(((uint8_t*)&v)[2]) 241 | && u8(((uint8_t*)&v)[1]) 242 | && u8(((uint8_t*)&v)[0]); 243 | } 244 | } 245 | 246 | public: 247 | bool f32(float& v) noexcept 248 | { 249 | return u32_le(*reinterpret_cast(&v)); 250 | } 251 | 252 | bool f64(double& v) noexcept 253 | { 254 | return u64_le(*reinterpret_cast(&v)); 255 | } 256 | }; 257 | 258 | #define IOBASE_SER_METHOD_IMPL(t) IOBASE_SER_METHOD_IMPL_2(t, true) IOBASE_SER_METHOD_IMPL_2(t, false) 259 | #define IOBASE_SER_METHOD_IMPL_2(t, is_read) template<> template<> inline bool ioBase::ser(t ## _t& v) noexcept { return t(v); } 260 | 261 | IOBASE_SER_METHOD_IMPL(u8) 262 | IOBASE_SER_METHOD_IMPL(u16_be) 263 | IOBASE_SER_METHOD_IMPL(u24_be) 264 | IOBASE_SER_METHOD_IMPL(u32_be) 265 | IOBASE_SER_METHOD_IMPL(u16_le) 266 | IOBASE_SER_METHOD_IMPL(u24_le) 267 | IOBASE_SER_METHOD_IMPL(u32_le) 268 | } 269 | -------------------------------------------------------------------------------- /Sun/Sun.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vendor\Soup 6 | 7 | 8 | vendor\Soup 9 | 10 | 11 | vendor\Soup 12 | 13 | 14 | vendor\Soup 15 | 16 | 17 | vendor\Soup 18 | 19 | 20 | vendor\Soup 21 | 22 | 23 | 24 | vendor\Soup 25 | 26 | 27 | vendor\Soup 28 | 29 | 30 | vendor\Soup 31 | 32 | 33 | vendor\Soup 34 | 35 | 36 | vendor\Soup 37 | 38 | 39 | vendor\Soup 40 | 41 | 42 | vendor\Soup 43 | 44 | 45 | vendor\Soup 46 | 47 | 48 | vendor\Soup 49 | 50 | 51 | 52 | 53 | {8eadb994-7960-46b8-9fef-5a01f30bd18c} 54 | 55 | 56 | {a23bcb48-4d39-4d5c-a217-6a152109c623} 57 | 58 | 59 | 60 | 61 | vendor\Soup 62 | 63 | 64 | vendor\Soup 65 | 66 | 67 | vendor\Soup 68 | 69 | 70 | vendor\Soup 71 | 72 | 73 | vendor\Soup 74 | 75 | 76 | vendor\Soup 77 | 78 | 79 | vendor\Soup 80 | 81 | 82 | vendor\Soup 83 | 84 | 85 | vendor\Soup 86 | 87 | 88 | vendor\Soup 89 | 90 | 91 | vendor\Soup 92 | 93 | 94 | vendor\Soup 95 | 96 | 97 | vendor\Soup 98 | 99 | 100 | vendor\Soup 101 | 102 | 103 | vendor\Soup 104 | 105 | 106 | vendor\Soup 107 | 108 | 109 | vendor\Soup 110 | 111 | 112 | vendor\Soup 113 | 114 | 115 | vendor\Soup 116 | 117 | 118 | vendor\Soup 119 | 120 | 121 | vendor\Soup 122 | 123 | 124 | vendor\Soup 125 | 126 | 127 | vendor\Soup 128 | 129 | 130 | vendor\Soup 131 | 132 | 133 | vendor\Soup 134 | 135 | 136 | vendor\Soup 137 | 138 | 139 | vendor\Soup 140 | 141 | 142 | vendor\Soup 143 | 144 | 145 | vendor\Soup 146 | 147 | 148 | vendor\Soup 149 | 150 | 151 | vendor\Soup 152 | 153 | 154 | vendor\Soup 155 | 156 | 157 | vendor\Soup 158 | 159 | 160 | vendor\Soup 161 | 162 | 163 | vendor\Soup 164 | 165 | 166 | vendor\Soup 167 | 168 | 169 | vendor\Soup 170 | 171 | 172 | vendor\Soup 173 | 174 | 175 | vendor\Soup 176 | 177 | 178 | vendor\Soup 179 | 180 | 181 | vendor\Soup 182 | 183 | 184 | vendor\Soup 185 | 186 | 187 | vendor\Soup 188 | 189 | 190 | vendor\Soup 191 | 192 | 193 | vendor\Soup 194 | 195 | 196 | vendor\Soup 197 | 198 | 199 | vendor\Soup 200 | 201 | 202 | vendor\Soup 203 | 204 | 205 | vendor\Soup 206 | 207 | 208 | vendor\Soup 209 | 210 | 211 | vendor\Soup 212 | 213 | 214 | vendor\Soup 215 | 216 | 217 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/Reader.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // memset 4 | 5 | #include "ioBase.hpp" 6 | 7 | #include "fwd.hpp" 8 | 9 | NAMESPACE_SOUP 10 | { 11 | class Reader : public ioBase 12 | { 13 | public: 14 | using ioBase::ioBase; 15 | 16 | [[nodiscard]] virtual bool hasMore() noexcept = 0; 17 | virtual void seek(size_t pos) = 0; 18 | void seekBegin() { seek(0); } 19 | virtual void seekEnd() = 0; 20 | 21 | [[nodiscard]] size_t getRemainingBytes() 22 | { 23 | const size_t pos = getPosition(); 24 | seekEnd(); 25 | const size_t remaining = (getPosition() - pos); 26 | seek(pos); 27 | return remaining; 28 | } 29 | 30 | bool skip(size_t len) 31 | { 32 | seek(getPosition() + len); 33 | return true; 34 | } 35 | 36 | virtual const void* getMemoryView(size_t size) const noexcept { return nullptr; } 37 | 38 | // An unsigned 64-bit integer encoded in 1..9 bytes. The most significant bit of bytes 1 to 8 is used to indicate if another byte follows. 39 | // https://github.com/calamity-inc/u64_dyn 40 | bool u64_dyn(uint64_t& v) noexcept; 41 | 42 | // A signed 64-bit integer encoded in 1..9 bytes. (Specialisation of u64_dyn.) 43 | // https://github.com/calamity-inc/u64_dyn 44 | bool i64_dyn(int64_t& v) noexcept; 45 | 46 | // An unsigned 64-bit integer encoded in 1..9 bytes. This is a slightly more efficient version of u64_dyn, e.g. 0x4000..0x407f are encoded in 2 bytes instead of 3. 47 | // https://github.com/calamity-inc/u64_dyn 48 | bool u64_dyn_v2(uint64_t& v) noexcept; 49 | 50 | // A signed 64-bit integer encoded in 1..9 bytes. (Specialisation of u64_dyn_v2. This revision also simplifies how negative integers are handled.) 51 | // https://github.com/calamity-inc/u64_dyn 52 | bool i64_dyn_v2(int64_t& v) noexcept; 53 | 54 | // An integer where every byte's most significant bit is used to indicate if another byte follows, most significant byte first. 55 | template 56 | bool om(Int& v) noexcept 57 | { 58 | v = {}; 59 | uint8_t byte; 60 | while (u8(byte)) 61 | { 62 | v <<= 7; 63 | v |= (byte & 0x7F); 64 | if (!(byte & 0x80)) 65 | { 66 | return true; 67 | } 68 | } 69 | return false; 70 | } 71 | 72 | // An integer where every byte's most significant bit is used to indicate if another byte follows, least significant byte first. This is compatible with unsigned LEB128. 73 | template 74 | bool oml(Int& v) noexcept 75 | { 76 | v = {}; 77 | uint8_t byte; 78 | uint8_t shift = 0; 79 | while (u8(byte)) 80 | { 81 | v |= (static_cast(byte & 0x7F) << shift); 82 | if (!(byte & 0x80)) 83 | { 84 | return true; 85 | } 86 | shift += 7; 87 | } 88 | return false; 89 | } 90 | 91 | // Signed LEB128. 92 | template 93 | bool soml(Int& v) noexcept 94 | { 95 | v = {}; 96 | uint8_t byte; 97 | uint8_t shift = 0; 98 | while (u8(byte)) 99 | { 100 | v |= (static_cast(byte & 0x7F) << shift); 101 | if (!(byte & 0x80)) 102 | { 103 | if (shift < (sizeof(Int) * 8) && (byte & 0x40)) 104 | { 105 | v |= (~0 << shift); 106 | } 107 | return true; 108 | } 109 | shift += 7; 110 | } 111 | return false; 112 | } 113 | 114 | bool mysql_lenenc(uint64_t& v) noexcept 115 | { 116 | uint8_t first; 117 | if (u8(first)) 118 | { 119 | if (first < 0xFB) 120 | { 121 | v = first; 122 | return true; 123 | } 124 | // 0xFB = NULL 125 | if (first == 0xFC) 126 | { 127 | uint16_t val; 128 | if (u16_le(val)) 129 | { 130 | v = val; 131 | return true; 132 | } 133 | } 134 | if (first == 0xFD) 135 | { 136 | uint32_t val; 137 | if (u24_le(val)) 138 | { 139 | v = val; 140 | return true; 141 | } 142 | } 143 | if (first == 0xFE) 144 | { 145 | uint64_t val; 146 | if (u64_le(val)) 147 | { 148 | v = val; 149 | return true; 150 | } 151 | } 152 | // 0xFF = undocumented 153 | } 154 | return false; 155 | } 156 | 157 | // Null-terminated string. 158 | bool str_nt(std::string& v) SOUP_EXCAL 159 | { 160 | v.clear(); 161 | while (true) 162 | { 163 | char c; 164 | SOUP_RETHROW_FALSE(ioBase::c(c)); 165 | if (c == 0) 166 | { 167 | break; 168 | } 169 | v.push_back(c); 170 | } 171 | return true; 172 | } 173 | 174 | // Length-prefixed string. 175 | template 176 | bool str_lp(std::string& v, const T max_len = -1) SOUP_EXCAL 177 | { 178 | T len; 179 | return ser(len) && len <= max_len && str(static_cast(len), v); 180 | } 181 | 182 | // Length-prefixed string, using u64_dyn for the length prefix. 183 | bool str_lp_u64_dyn(std::string& v) SOUP_EXCAL 184 | { 185 | uint64_t len; 186 | return u64_dyn(len) && str((size_t)len, v); 187 | } 188 | 189 | // Length-prefixed string, using u64_dyn_v2 for the length prefix. 190 | bool str_lp_u64_dyn_v2(std::string& v) SOUP_EXCAL 191 | { 192 | uint64_t len; 193 | return u64_dyn_v2(len) && str((size_t)len, v); 194 | } 195 | 196 | // Length-prefixed string, using mysql_lenenc for the length prefix. 197 | bool str_lp_mysql(std::string& v) 198 | { 199 | uint64_t len; 200 | return mysql_lenenc(len) && str((size_t)len, v); 201 | } 202 | 203 | // String with known length. 204 | bool str(size_t len, std::string& v) SOUP_EXCAL 205 | { 206 | v = std::string(len, '\0'); 207 | return raw(v.data(), len); 208 | } 209 | 210 | // String with known length. 211 | bool str(size_t len, char* v) SOUP_EXCAL 212 | { 213 | memset(v, 0, len); 214 | return raw(v, len); 215 | } 216 | 217 | // std::vector with u8 size prefix. 218 | bool vec_u8_u8(std::vector& v) SOUP_EXCAL 219 | { 220 | uint8_t len; 221 | SOUP_RETHROW_FALSE(u8(len)); 222 | v.clear(); 223 | v.reserve(len); 224 | while (len--) 225 | { 226 | uint8_t entry; 227 | SOUP_RETHROW_FALSE(u8(entry)); 228 | v.emplace_back(std::move(entry)); 229 | } 230 | return true; 231 | } 232 | 233 | // vector of u16 with u16 byte length prefix, using big endian over-the-wire. 234 | bool vec_u16_bl_u16_be(std::vector& v) SOUP_EXCAL 235 | { 236 | uint16_t len; 237 | SOUP_RETHROW_FALSE(ioBase::u16_be(len)); 238 | v.clear(); 239 | v.reserve(len / 2); 240 | for (; len >= sizeof(uint16_t); len -= sizeof(uint16_t)) 241 | { 242 | uint16_t entry; 243 | SOUP_RETHROW_FALSE(ioBase::u16_be(entry)); 244 | v.emplace_back(entry); 245 | } 246 | return true; 247 | } 248 | 249 | // vector of str_nt with u64_dyn length prefix. 250 | bool vec_str_nt_u64_dyn(std::vector& v) SOUP_EXCAL 251 | { 252 | uint64_t len; 253 | SOUP_RETHROW_FALSE(u64_dyn(len)); 254 | v.clear(); 255 | v.reserve((size_t)len); 256 | for (; len != 0; --len) 257 | { 258 | std::string entry; 259 | SOUP_RETHROW_FALSE(str_nt(entry)); 260 | v.emplace_back(std::move(entry)); 261 | } 262 | return true; 263 | } 264 | 265 | // vector of str_lp with u24_be byte length prefix. 266 | bool vec_str_lp_u24_bl_u24_be(std::vector& v) SOUP_EXCAL 267 | { 268 | uint32_t len; 269 | SOUP_RETHROW_FALSE(ioBase::u24_be(len)); 270 | v.clear(); 271 | while (len >= 3) 272 | { 273 | std::string entry; 274 | SOUP_RETHROW_FALSE(str_lp(entry)); 275 | len -= ((uint32_t)entry.size() + 3); 276 | v.emplace_back(std::move(entry)); 277 | } 278 | return true; 279 | } 280 | 281 | // vector of str_lp with u16_be byte length prefix. 282 | bool vec_str_lp_u8_bl_u16_be(std::vector& v) SOUP_EXCAL 283 | { 284 | uint16_t len; 285 | SOUP_RETHROW_FALSE(ioBase::u16_be(len)); 286 | v.clear(); 287 | while (len >= 1) 288 | { 289 | std::string entry; 290 | SOUP_RETHROW_FALSE(str_lp(entry)); 291 | len -= ((uint16_t)entry.size() + 1); 292 | v.emplace_back(std::move(entry)); 293 | } 294 | return true; 295 | } 296 | 297 | // Null-terminated vector of str_lp. 298 | bool vec_nt_str_lp_u8(std::vector& v) SOUP_EXCAL 299 | { 300 | v.clear(); 301 | while (true) 302 | { 303 | std::string entry; 304 | SOUP_RETHROW_FALSE(str_lp(entry)); 305 | if (entry.empty()) 306 | { 307 | break; 308 | } 309 | v.emplace_back(std::move(entry)); 310 | } 311 | return true; 312 | } 313 | 314 | // Reader-specific 315 | virtual bool getLine(std::string& line) SOUP_EXCAL 316 | { 317 | line.clear(); 318 | char c; 319 | while (ioBase::c(c)) 320 | { 321 | if (c == '\n') 322 | { 323 | return true; 324 | } 325 | line.push_back(c); 326 | } 327 | return !line.empty(); 328 | } 329 | }; 330 | } 331 | -------------------------------------------------------------------------------- /Sun/vendor/Soup/soup/os.cpp: -------------------------------------------------------------------------------- 1 | #include "os.hpp" 2 | 3 | #include 4 | #include // memcpy 5 | #include 6 | 7 | #if SOUP_WINDOWS 8 | #pragma comment(lib, "gdi32.lib") 9 | #pragma comment(lib, "winmm.lib") // timeBeginPeriod, timeEndPeriod 10 | 11 | #include 12 | #include // timeBeginPeriod, timeEndPeriod 13 | 14 | #include "Exception.hpp" 15 | #include "ObfusString.hpp" 16 | #else 17 | #include // getpid, usleep 18 | #if _POSIX_C_SOURCE >= 199309L 19 | #include // nanosleep 20 | #endif 21 | #endif 22 | 23 | #include "filesystem.hpp" 24 | #include "rand.hpp" 25 | #include "string.hpp" 26 | #include "unicode.hpp" 27 | #include "UniquePtr.hpp" 28 | 29 | NAMESPACE_SOUP 30 | { 31 | void os::escape(std::string& str) 32 | { 33 | if (str.find(' ') != std::string::npos) 34 | { 35 | escapeNoCheck(str); 36 | } 37 | } 38 | 39 | void os::escapeNoCheck(std::string& str) 40 | { 41 | string::replaceAll(str, "\\", "\\\\"); 42 | string::replaceAll(str, "\"", "\\\""); 43 | str.insert(0, 1, '"'); 44 | str.push_back('"'); 45 | } 46 | 47 | std::string os::execute(std::string program, const std::vector& args) 48 | { 49 | resolveProgram(program); 50 | return executeInner(std::move(program), args); 51 | } 52 | 53 | std::string os::executeLong(std::string program, const std::vector& args) 54 | { 55 | resolveProgram(program); 56 | std::string flatargs; 57 | for (auto i = args.begin(); i != args.end(); ++i) 58 | { 59 | std::string escaped = *i; 60 | escapeNoCheck(escaped); 61 | if (!flatargs.empty()) 62 | { 63 | flatargs.push_back(' '); 64 | } 65 | flatargs.append(escaped); 66 | } 67 | auto args_file = filesystem::tempfile(); 68 | { 69 | std::ofstream argsof(args_file); 70 | argsof << std::move(flatargs); 71 | } 72 | auto ret = executeInner(std::move(program), { std::move(std::string(1, '@').append(args_file.string())) }); 73 | std::error_code ec; 74 | std::filesystem::remove(args_file, ec); 75 | return ret; 76 | } 77 | 78 | void os::resolveProgram(std::string& program) 79 | { 80 | #if SOUP_WINDOWS 81 | if (program.find('\\') == std::string::npos 82 | && program.find('/') == std::string::npos 83 | ) 84 | { 85 | std::string program_og = program; 86 | program = executeInner("where", { program }); 87 | if (program.substr(0, 6) == "INFO: ") 88 | { 89 | std::string msg = "Failed to find program \""; 90 | msg.append(program_og); 91 | msg.push_back('"'); 92 | SOUP_THROW(Exception(std::move(msg))); 93 | } 94 | string::limit(program, "\n"); 95 | } 96 | #endif 97 | } 98 | 99 | std::string os::executeInner(std::string cmd, const std::vector& args) 100 | { 101 | escape(cmd); 102 | for (auto i = args.begin(); i != args.end(); ++i) 103 | { 104 | std::string escaped = *i; 105 | escape(escaped); 106 | cmd.push_back(' '); 107 | cmd.append(escaped); 108 | } 109 | cmd.append(" 2>&1"); 110 | //std::cout << "Running <" << cmd << ">" << std::endl; 111 | #if SOUP_WINDOWS 112 | auto pipe = _popen(cmd.c_str(), "r"); 113 | #else 114 | auto pipe = popen(cmd.c_str(), "r"); 115 | #endif 116 | std::array buffer; 117 | std::string result; 118 | while (fgets(buffer.data(), static_cast(buffer.size()), pipe) != nullptr) 119 | { 120 | result += buffer.data(); 121 | } 122 | #if SOUP_WINDOWS 123 | _pclose(pipe); 124 | #else 125 | pclose(pipe); 126 | #endif 127 | return result; 128 | } 129 | 130 | #if !SOUP_WINDOWS 131 | pid_t os::getProcessId() noexcept 132 | { 133 | return ::getpid(); 134 | } 135 | #endif 136 | 137 | #if !SOUP_WINDOWS 138 | void os::sleep(unsigned int ms) noexcept 139 | { 140 | #if _POSIX_C_SOURCE >= 199309L 141 | struct timespec ts; 142 | ts.tv_sec = ms / 1000; 143 | ts.tv_nsec = (ms % 1000) * 1000000; 144 | int res; 145 | do 146 | { 147 | res = ::nanosleep(&ts, &ts); 148 | } while (res && errno == EINTR); 149 | #else 150 | if (ms >= 1000) 151 | { 152 | ::sleep(ms / 1000); 153 | } 154 | ::usleep((ms % 1000) * 1000); 155 | #endif 156 | } 157 | #endif 158 | 159 | #if SOUP_WINDOWS 160 | void os::fastSleep(unsigned int ms) noexcept 161 | { 162 | timeBeginPeriod(ms); 163 | ::Sleep(ms); 164 | timeEndPeriod(ms); 165 | } 166 | #endif 167 | 168 | #if SOUP_WINDOWS 169 | static bool copy_to_clipboard_utf16(const std::wstring& text) 170 | { 171 | const size_t len = (text.length() + 1) * sizeof(wchar_t); 172 | HGLOBAL hMem = GlobalAlloc(GHND | GMEM_DDESHARE, len); 173 | if (hMem != nullptr) 174 | { 175 | void* pMem = GlobalLock(hMem); 176 | if (pMem != nullptr) 177 | { 178 | memcpy(pMem, text.data(), len); 179 | GlobalUnlock(hMem); 180 | if (OpenClipboard(nullptr)) 181 | { 182 | bool success = (EmptyClipboard() && SetClipboardData(CF_UNICODETEXT, hMem) != nullptr); 183 | CloseClipboard(); 184 | return success; 185 | } 186 | GlobalFree(hMem); 187 | } 188 | } 189 | return false; 190 | } 191 | 192 | bool os::copyToClipboard(const std::string& text) 193 | { 194 | return copy_to_clipboard_utf16(unicode::utf8_to_utf16(text)); 195 | } 196 | 197 | std::string os::getClipboardTextUtf8() 198 | { 199 | return unicode::utf16_to_utf8(getClipboardTextUtf16()); 200 | } 201 | 202 | UTF16_STRING_TYPE os::getClipboardTextUtf16() 203 | { 204 | std::wstring text; 205 | if (OpenClipboard(nullptr)) 206 | { 207 | HANDLE hData = GetClipboardData(CF_UNICODETEXT); 208 | if (hData != nullptr) 209 | { 210 | auto pszText = static_cast(GlobalLock(hData)); 211 | if (pszText != nullptr) 212 | { 213 | text = pszText; 214 | GlobalUnlock(hData); 215 | } 216 | } 217 | CloseClipboard(); 218 | } 219 | return text; 220 | } 221 | 222 | #if !SOUP_CROSS_COMPILE 223 | size_t os::getMemoryUsage() 224 | { 225 | PROCESS_MEMORY_COUNTERS_EX pmc; 226 | GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc)); 227 | return pmc.PrivateUsage; 228 | } 229 | #endif 230 | 231 | bool os::isWine() 232 | { 233 | return GetProcAddress(LoadLibraryA(ObfusString("ntdll.dll")), ObfusString("wine_get_version")) != nullptr; 234 | } 235 | 236 | PEB* os::getCurrentPeb() 237 | { 238 | // There is a "simpler" solution (https://gist.github.com/Wack0/849348f9d4f3a73dac864a556e9372a5), but this is what Microsoft does, so we shall, too. 239 | 240 | auto ntdll = LoadLibraryA(ObfusString("ntdll.dll")); 241 | 242 | using NtQueryInformationProcess_t = NTSTATUS(NTAPI*)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength); 243 | auto NtQueryInformationProcess = (NtQueryInformationProcess_t)GetProcAddress(ntdll, ObfusString("NtQueryInformationProcess")); 244 | 245 | PROCESS_BASIC_INFORMATION ProcessInformation; 246 | NtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &ProcessInformation, sizeof(ProcessInformation), 0); 247 | 248 | return ProcessInformation.PebBaseAddress; 249 | } 250 | 251 | #if !SOUP_CROSS_COMPILE 252 | [[nodiscard]] static std::string HBMITMAP_to_BMP(HBITMAP hBitmap) 253 | { 254 | HDC hDC; 255 | int iBits; 256 | WORD wBitCount; 257 | DWORD dwPaletteSize = 0, dwBmBitsSize = 0, dwDIBSize = 0; 258 | BITMAP Bitmap0; 259 | BITMAPFILEHEADER bmfHdr; 260 | BITMAPINFOHEADER bi; 261 | LPBITMAPINFOHEADER lpbi; 262 | HANDLE hDib, hPal, hOldPal2 = NULL; 263 | hDC = CreateDCA("DISPLAY", NULL, NULL, NULL); 264 | iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES); 265 | DeleteDC(hDC); 266 | if (iBits <= 1) 267 | wBitCount = 1; 268 | else if (iBits <= 4) 269 | wBitCount = 4; 270 | else if (iBits <= 8) 271 | wBitCount = 8; 272 | else 273 | wBitCount = 24; 274 | GetObject(hBitmap, sizeof(Bitmap0), (LPSTR)&Bitmap0); 275 | bi.biSize = sizeof(BITMAPINFOHEADER); 276 | bi.biWidth = Bitmap0.bmWidth; 277 | bi.biHeight = -Bitmap0.bmHeight; 278 | bi.biPlanes = 1; 279 | bi.biBitCount = wBitCount; 280 | bi.biCompression = BI_RGB; 281 | bi.biSizeImage = 0; 282 | bi.biXPelsPerMeter = 0; 283 | bi.biYPelsPerMeter = 0; 284 | bi.biClrImportant = 0; 285 | bi.biClrUsed = 256; 286 | dwBmBitsSize = ((Bitmap0.bmWidth * wBitCount + 31) & ~31) / 8 287 | * Bitmap0.bmHeight; 288 | hDib = GlobalAlloc(GHND, dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER)); 289 | lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib); 290 | *lpbi = bi; 291 | 292 | hPal = GetStockObject(DEFAULT_PALETTE); 293 | if (hPal) 294 | { 295 | hDC = GetDC(NULL); 296 | hOldPal2 = SelectPalette(hDC, (HPALETTE)hPal, FALSE); 297 | RealizePalette(hDC); 298 | } 299 | 300 | 301 | GetDIBits(hDC, hBitmap, 0, (UINT)Bitmap0.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER) 302 | + dwPaletteSize, (BITMAPINFO*)lpbi, DIB_RGB_COLORS); 303 | 304 | if (hOldPal2) 305 | { 306 | SelectPalette(hDC, (HPALETTE)hOldPal2, TRUE); 307 | RealizePalette(hDC); 308 | ReleaseDC(NULL, hDC); 309 | } 310 | 311 | bmfHdr.bfType = 0x4D42; // "BM" 312 | dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize; 313 | bmfHdr.bfSize = dwDIBSize; 314 | bmfHdr.bfReserved1 = 0; 315 | bmfHdr.bfReserved2 = 0; 316 | bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize; 317 | 318 | std::string data; 319 | data.reserve(sizeof(BITMAPFILEHEADER) + dwDIBSize); 320 | data.append((const char*)&bmfHdr, sizeof(BITMAPFILEHEADER)); 321 | data.append((const char*)lpbi, dwDIBSize); 322 | 323 | GlobalUnlock(hDib); 324 | GlobalFree(hDib); 325 | 326 | return data; 327 | } 328 | 329 | std::string os::makeScreenshotBmp(int x, int y, int width, int height) 330 | { 331 | HDC dcScreen = GetDC(0); 332 | HDC dcTarget = CreateCompatibleDC(dcScreen); 333 | HBITMAP bmpTarget = CreateCompatibleBitmap(dcScreen, width, height); 334 | HGDIOBJ oldBmp = SelectObject(dcTarget, bmpTarget); 335 | BitBlt(dcTarget, 0, 0, width, height, dcScreen, x, y, SRCCOPY | CAPTUREBLT); 336 | SelectObject(dcTarget, oldBmp); 337 | DeleteDC(dcTarget); 338 | ReleaseDC(0, dcScreen); 339 | 340 | auto bmp = HBMITMAP_to_BMP(bmpTarget); 341 | DeleteObject(bmpTarget); 342 | return bmp; 343 | } 344 | #endif 345 | #endif 346 | } 347 | --------------------------------------------------------------------------------