Major patch [1/2]

This commit is contained in:
Reece Wilson 2021-09-06 11:58:08 +01:00
parent 3e33533276
commit ffe4bc31fc
186 changed files with 7313 additions and 1900 deletions

5
.gitignore vendored
View File

@ -19,4 +19,7 @@ Build_Develop/*
.vs
compile_flags.txt
*.mk
*.project
*.project
*cmake
.intellij
.clion

View File

@ -6,9 +6,9 @@
"impDefines": ["AURORA_ENGINE_KERNEL"],
"staticImpDefines": "AURORA_ENGINE_KERNEL_STATIC",
"defines": [],
"soft-depends": ["wxwidgets"],
"depends": ["glm", "asio", "mimalloc", "uuid", "fmt", "json", "bzip2", "ltc", "o1heap", "zstd", "zlib", "lz4", "mbedtls"],
"features": ["remove-platform-code", "guess-platform-code"],
"soft-depends": ["wxwidgets", "glm"],
"depends": ["mimalloc", "uuid", "fmt", "json", "bzip2", "ltc", "o1heap", "zstd", "zlib", "lz4", "mbedtls"],
"features": ["guess-platform-code"],
"linkSources": "Source/Alloc.cpp",
"actions": [
{

View File

@ -2,7 +2,7 @@
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Async.hpp
Date: 2021-6-10
Date: 2021-7-14
Author: Reece
***/
#pragma once
@ -19,8 +19,8 @@ namespace Aurora::Async
using ThreadGroup_t = AuUInt8;
using ThreadId_t = AuUInt16;
using WorkerId_t = std::pair<ThreadGroup_t, ThreadId_t>;
using DispatchTarget_t = std::pair<ThreadGroup_t, std::optional<ThreadId_t>>;
using WorkerId_t = AuPair<ThreadGroup_t, ThreadId_t>;
using DispatchTarget_t = AuPair<ThreadGroup_t, AuOptional<ThreadId_t>>;
struct IWorkItemHandler
{
@ -50,7 +50,6 @@ namespace Aurora::Async
virtual void Shutdown() = 0;
};
template<class Info_t = AVoid, class Result_t = AVoid>
struct FJob
{
@ -68,13 +67,13 @@ namespace Aurora::Async
template<class Info_t = AVoid, class Result_t = AVoid>
struct FTask
{
std::function<std::optional<Result_t>(const Info_t &)> onFrame = 0;
std::function<AuOptional<Result_t>(const Info_t &)> onFrame = 0;
};
template<class Info_t = AVoid, class Result_t = AVoid>
struct CTask
{
std::optional<Result_t>(* onFrame)(const Info_t &);
AuOptional<Result_t>(* onFrame)(const Info_t &);
};
class IWorkItem
@ -116,7 +115,7 @@ namespace Aurora::Async
{}
private:
#if !defined(_CPPSHARP)
void DispatchFrame(ProcessInfo &info) override
{
try
@ -143,8 +142,10 @@ namespace Aurora::Async
Debug::PrintError();
}
}
#endif
};
#if !defined(_CPPSHARP)
template<typename Info_t, typename Result_t, typename Task_t = FTask<Info_t, Result_t>, typename Job_t = FJob<Info_t, Result_t>>
struct BasicWorkCallback : IWorkItemHandler, std::enable_shared_from_this<IWorkItemHandler>
{
@ -158,24 +159,43 @@ namespace Aurora::Async
Info_t input;
BasicWorkCallback<Info_t, Result_t, Task_t, Job_t> &SetTask(const Task_t &task)
{
this->task = task;
return *this;
}
BasicWorkCallback<Info_t, Result_t, Task_t, Job_t> &SetTask(const Job_t &callback)
{
this->callback = callback;
return *this;
}
private:
static constexpr bool IsCallbackPtr = std::is_pointer_v<Job_t> || is_base_of_template<std::shared_ptr, Job_t>::value;
static constexpr bool IsTaskPtr = std::is_pointer_v<Task_t> || is_base_of_template<std::shared_ptr, Task_t>::value;
static constexpr bool IsCallbackPtr = std::is_pointer_v<Job_t> || AuIsBaseOfTemplate<std::shared_ptr, Job_t>::value;
static constexpr bool IsTaskPtr = std::is_pointer_v<Task_t> || AuIsBaseOfTemplate<std::shared_ptr, Task_t>::value;
WorkerId_t caller;
void DispatchFrame(ProcessInfo &info) override
{
std::optional<Result_t> ret;
AuOptional<Result_t> ret;
if constexpr (IsTaskPtr)
try
{
ret = task->onFrame(input);
if constexpr (IsTaskPtr)
{
ret = task->onFrame(input);
}
else
{
ret = task.onFrame(input);
}
}
else
catch (...)
{
ret = task.onFrame(input);
Debug::PrintError();
Shutdown();
}
auto pin = std::static_pointer_cast<std::remove_pointer_t<decltype(this)>>(this->shared_from_this());
@ -220,7 +240,7 @@ namespace Aurora::Async
};
// TODO: this is somewhat evil. double alloc when we could reuse this
NewWorkItem(caller, std::make_shared<BasicWorkStdFunc>(func, err))->Dispatch();
NewWorkItem(caller, AuMakeShared<BasicWorkStdFunc>(func, err))->Dispatch();
}
}
catch (...)
@ -246,7 +266,7 @@ namespace Aurora::Async
{
if constexpr (IsCallbackPtr)
{
if constexpr (is_base_of_template<std::function, decltype(callback->onFailure)>::value)
if constexpr (AuIsBaseOfTemplate<std::function, decltype(callback->onFailure)>::value)
{
if (!callback->onFailure)
{
@ -258,7 +278,7 @@ namespace Aurora::Async
}
else
{
if constexpr (is_base_of_template<std::function, decltype(callback.onFailure)>::value)
if constexpr (AuIsBaseOfTemplate<std::function, decltype(callback.onFailure)>::value)
{
if (!callback.onFailure)
{
@ -295,7 +315,7 @@ namespace Aurora::Async
auto cur = GetAsyncApp()->GetCurrentThread();
return [=](Args... in) -> void
{
auto work = std::make_shared<BasicWorkStdFunc>([=]() -> void {
auto work = AuMakeShared<BasicWorkStdFunc>([=]() -> void {
func(in...);
});
auto workItem = NewWorkItem(cur, work);
@ -310,8 +330,8 @@ namespace Aurora::Async
auto cur = GetAsyncApp()->GetCurrentThread();
return [=](std::function<void(const B&)> callback, Args... in) -> void
{
auto work = std::make_shared<BasicWorkCallback<AVoid, B>>();
work.task.onProcess = [](const AVoid &) -> std::optional<B>
auto work = AuMakeShared<BasicWorkCallback<AVoid, B>>();
work.task.onProcess = [](const AVoid &) -> AuOptional<B>
{
return func(in...);
};
@ -325,6 +345,8 @@ namespace Aurora::Async
};
}
#endif
class IAsyncApp
{
public:

View File

@ -2,7 +2,7 @@
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: CompressionInfo.hpp
Date: 2021-6-10
Date: 2021-7-14
Author: Reece
***/
#pragma once

View File

@ -2,7 +2,7 @@
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ICompressionStream.hpp
Date: 2021-6-10
Date: 2021-7-14
Author: Reece
***/
#pragma once
@ -12,7 +12,9 @@ namespace Aurora::Compression
class ICompressionStream
{
public:
virtual std::pair<AuUInt32, AuUInt32> Ingest(AuUInt32 input) = 0;
virtual bool Read(void * /*opt*/, AuUInt32 &len, bool ingestUntilEOS = true) = 0;
virtual AuStreamReadWrittenPair_t Ingest(AuUInt32 bytesFromInputSource) = 0;
virtual bool ReadByInflatedN(void * /*opt*/, AuUInt32 minimumInflated, AuStreamReadWrittenPair_t &pair, bool ingestUntilEOS = true) = 0;
virtual bool GoBackByInflatedN(AuUInt32 offset) = 0;
virtual bool GoForwardByInflatedN(AuUInt32 offset) = 0;
};
}

View File

@ -2,7 +2,7 @@
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: StreamProcessor.hpp
Date: 2021-6-9
Date: 2021-7-14
Author: Reece
***/
#pragma once

View File

@ -12,7 +12,22 @@
namespace Aurora::Console
{
/// Writes a log message to the console subscribers and telemetry outputs
AUKN_SYM void WriteLine(const ConsoleMessage &msg);
/// nonblocking [!!!]
/// you must disable the stdio console logger before using this api [!!!]
/// you must not expect locale translation
AUKN_SYM AuUInt32 ReadStdIn(void *buffer, AuUInt32 length);
/// nonblocking [!!!]
/// you should disable the stdio console logger before using this api [!!!]
/// expect system locale if the logger is not enabled
/// edge case, utf8 if windows and logger is enabled
AUKN_SYM AuUInt32 WriteStdIn(const void *buffer, AuUInt32 length);
AUKN_SYM void OpenLateStd();
AUKN_SYM void OpenLateGUI();
}
#include "Commands/Commands.hpp"

View File

@ -9,7 +9,18 @@
namespace Aurora::Console::Hooks
{
class IConsoleSubscriber
{
public:
virtual void OnMessage(const ConsoleMessage &string) = 0;
};
AUKN_SYM void AddSubscription(const AuSPtr<IConsoleSubscriber> &subscriber);
AUKN_SYM void RemoveSubscription(const AuSPtr<IConsoleSubscriber> &subscriber);
using LineHook_cb = std::function<void(const ConsoleMessage &string)>;
AUKN_SYM void AddHook(LineHook_cb hook);
/// @deprecated wont ever remove
/// Most c++ styleguides would have you chuck an IConsoleSubscriber in your app somewhere
AUKN_SYM void AddFunctionalHook(LineHook_cb hook);
}

View File

@ -9,6 +9,7 @@
namespace Aurora::Console::Logging
{
#if defined(_AUHAS_FMT)
template<typename ... T>
static inline void WriteLinef(const AuString &tag, const AuString &msg, T... args)
{
@ -44,4 +45,5 @@ namespace Aurora::Console::Logging
{
Aurora::Console::Logging::WriteLinef(EAnsiColor::eBlue, "Game", line, args...);
}
#endif
}

View File

@ -25,11 +25,11 @@ namespace Aurora::Crypto::AES
const void* iv, void* outIv, AuUInt ivLength,
const void* key, AuUInt keyLength,
AuList<AuUInt8>& out,
bool safe);
bool auCoolCodePadding);
AUKN_SYM bool Decrypt(const void* cipherText, AuUInt cipherTextLength,
const void* iv, void* outIv, AuUInt ivLength,
const void* key, AuUInt keyLength,
AuList<AuUInt8>& plainText,
bool safe);
bool auCoolCodePadding);
}

View File

@ -31,11 +31,16 @@ namespace Aurora::Data
kTypeStructInt32,
kTypeSpecialComponent, // Special QST
kTypeSpecialArray, //
kTypeSpecialObject, //
kTypeSpecialArray, //
kTypeSpecialObject, //
kTypeSpecialReserved1, //
kTypeSpecialReserved2, //
kTypeSpecialReserved3, //
kTypeSpecialReserved4, //
kTypeEND,
// Out of order
kTypeStructDouble = kTypeNumber, // overlap bin serial with human friendly aliases
kTypeStructUInt64 = kTypeUInt, //
kTypeStructInt64 = kTypeSInt, //
@ -47,8 +52,8 @@ namespace Aurora::Data
AuInt64 sint;
double number;
bool boolean;
glm::vec3 vec3;
glm::vec4 vec4;
AuVec3 vec3;
AuVec4 vec4;
};
struct Value
@ -58,8 +63,8 @@ namespace Aurora::Data
{\
primitive.member = val;\
}
CONSTRUCTOR(const glm::vec3 &, vec3);
CONSTRUCTOR(const glm::vec4 &, vec4);
CONSTRUCTOR(const AuVec3 &, vec3);
CONSTRUCTOR(const AuVec4 &, vec4);
CONSTRUCTOR(bool, boolean);
CONSTRUCTOR(double, number);
CONSTRUCTOR(AuInt64, sint);
@ -97,6 +102,7 @@ namespace Aurora::Data
Value value;
};
#if !defined(_CPPSHARP)
template<DataType type>
static constexpr AuUInt GetDatatypeLength()
{
@ -139,4 +145,5 @@ namespace Aurora::Data
default: return 0;
}
}
#endif
}

View File

@ -51,6 +51,9 @@ namespace Aurora::Debug
May attempt some hardened telemetry debug ops
*/
AUKN_SYM AU_NORETURN void Panic();
AUKN_SYM void DebugBreak();
}
#include "SysPanic.hpp"

View File

@ -11,10 +11,10 @@ namespace Aurora::Debug
{
struct StackTraceEntry
{
std::optional<AuString> label;
AuOptional<AuString> label;
AuUInt64 address;
std::optional<AuString> module;
std::optional<std::tuple<AuString, int, int>> file; // file, line, offset
AuOptional<AuString> module;
AuOptional<std::tuple<AuString, int, int>> file; // file, line, offset
AUKN_SYM AuString Stringify() const;
};

View File

@ -2,7 +2,7 @@
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: SysAssertions.hpp
Date: 2021-6-10
Date: 2021-7-14
Author: Reece
***/

View File

@ -30,6 +30,12 @@ namespace Aurora::Debug
{
_PushError(_DBG_RET_ADDR, FailureCategory::kFailureNested, nullptr);
}
template<typename ... T>
static AU_NOINLINE void ErrorMakeNested(const AuString &msg, T... args) _FREECOMPILER_OPTIMIZE_OFF
{
_PushError(_DBG_RET_ADDR, FailureCategory::kFailureNested, fmt::format(msg, args...).c_str());
}
template<typename ... T>
static AU_NOINLINE void SysPushError(FailureCategory category, const AuString &msg, T... args) _FREECOMPILER_OPTIMIZE_OFF
@ -40,7 +46,11 @@ namespace Aurora::Debug
}
else
{
#if defined(_AUHAS_FMT)
_PushError(_DBG_RET_ADDR, category, fmt::format(msg, args...).c_str());
#else
_PushError(_DBG_RET_ADDR, category, "Missing dependency");
#endif
}
}
@ -54,9 +64,10 @@ namespace Aurora::Debug
#endif
}
#define SysCheckReturn(x, ...) if (!(x)) { Aurora::Debug::ErrorMakeNested(); return ##__VA_ARGS__; }
#define SysCheckReturn(x, ...) if (!(static_cast<bool>(x))) { Aurora::Debug::ErrorMakeNested(); return __VA_ARGS__; }
#define SysPushErrorError(error, ...) Aurora::Debug::SysPushError(Aurora::Debug::error, ## __VA_ARGS__)
#define SysPushErrorError(error, ...) Aurora::Debug::SysPushError(Aurora::Debug::error, ## __VA_ARGS__)
#define SysPushUserError(exp, ...) Aurora::Debug::SysPushError((Aurora::Debug::FailureCategory)exp, ## __VA_ARGS__)
// legacy
#define SysPushErrorArg(...) SysPushErrorError(kFailureParam, ## __VA_ARGS__)
@ -66,7 +77,7 @@ namespace Aurora::Debug
#define SysPushErrorMem(...) SysPushErrorError(kFailureMemory, ## __VA_ARGS__)
// edge case
#define SysPushErrorNested() Aurora::Debug::ErrorMakeNested();
#define SysPushErrorNested(...) Aurora::Debug::ErrorMakeNested(__VA_ARGS__);
// enums
#define SysPushErrorGeneric(...) SysPushErrorError(kFailureGeneric, ## __VA_ARGS__)
@ -86,39 +97,38 @@ namespace Aurora::Debug
#define SysPushErrorWatchdogError(...) SysPushErrorError(kFailureWatchdogError, ## __VA_ARGS__)
#define SysPushErrorServiceError(...) SysPushErrorError(kFailureServiceError, ## __VA_ARGS__)
#define SysPushErrorPermissionError(...) SysPushErrorError(kFailurePermissionError, ## __VA_ARGS__)
#define SysPushErrorOutOfRange(...) SysPushErrorError(kFailureOutOfRange, ## __VA_ARGS__)
#define SysPushErrorSyntaxError(...) SysPushErrorError(kFailureSyntaxError, ## __VA_ARGS__)
#define SysPushErrorDisconnected(...) SysPushErrorError(kFailureDisconnected, ## __VA_ARGS__)
#define SysPushErrorUninitialized(...) SysPushErrorError(kFailureUninitialized, ## __VA_ARGS__)
#define SysPushErrorOutOfRange(...) SysPushErrorError(kFailureOutOfRange, ## __VA_ARGS__)
#define SysPushErrorSyntaxError(...) SysPushErrorError(kFailureSyntaxError, ## __VA_ARGS__)
#define SysPushErrorDisconnected(...) SysPushErrorError(kFailureDisconnected, ## __VA_ARGS__)
#define SysPushErrorUninitialized(...) SysPushErrorError(kFailureUninitialized, ## __VA_ARGS__)
#if defined(DEBUG) || defined(STAGING)
#if defined(DEBUG) || defined(INTERNAL)
#define SysPushErrorArgDbg SysPushErrorArg
#define SysPushErrorGenDbg SysPushErrorGen
#define SysPushErrorCryptDbg SysPushErrorCrypt
#define SysPushErrorNetDbg SysPushErrorNet
#define SysPushErrorMemDbg SysPushErrorMem
#define SysPushUserErrorDbg SysPushUserError
#define SysPushErrorArgDbg SysPushErrorArg
#define SysPushErrorGenDbg SysPushErrorGen
#define SysPushErrorCryptDbg SysPushErrorCrypt
#define SysPushErrorNetDbg SysPushErrorNet
#define SysPushErrorMemDbg SysPushErrorMem
#define SysPushErrorGenericDbg SysPushErrorGeneric
#define SysPushErrorNestedDbg SysPushErrorNested
#define SysPushErrorMemoryDbg SysPushErrorMemory
#define SysPushErrorIODbg SysPushErrorIO
#define SysPushErrorFIODbg SysPushErrorFIO
#define SysPushErrorNetDbg SysPushErrorNet
#define SysPushErrorAudioDbg SysPushErrorAudio
#define SysPushErrorHALDbg SysPushErrorHAL
#define SysPushErrorHALContextDbg SysPushErrorHALContext
#define SysPushErrorCryptoDbg SysPushErrorCrypto
#define SysPushErrorParamDbg SysPushErrorParam
#define SysPushErrorLogicErrorDbg SysPushErrorLogicError
#define SysPushErrorMathErrorDbg SysPushErrorMathError
#define SysPushErrorUnavailableErrorDbg SysPushErrorUnavailableError
#define SysPushErrorTimeoutErrorDbg SysPushErrorTimeoutError
#define SysPushErrorWatchdogErrorDbg SysPushErrorWatchdogError
#define SysPushErrorGenericDbg SysPushErrorGeneric
#define SysPushErrorNestedDbg SysPushErrorNested
#define SysPushErrorMemoryDbg SysPushErrorMemory
#define SysPushErrorIODbg SysPushErrorIO
#define SysPushErrorFIODbg SysPushErrorFIO
#define SysPushErrorNetDbg SysPushErrorNet
#define SysPushErrorAudioDbg SysPushErrorAudio
#define SysPushErrorHALDbg SysPushErrorHAL
#define SysPushErrorHALContextDbg SysPushErrorHALContext
#define SysPushErrorCryptoDbg SysPushErrorCrypto
#define SysPushErrorParamDbg SysPushErrorParam
#define SysPushErrorLogicErrorDbg SysPushErrorLogicError
#define SysPushErrorMathErrorDbg SysPushErrorMathError
#define SysPushErrorUnavailableErrorDbg SysPushErrorUnavailableError
#define SysPushErrorTimeoutErrorDbg SysPushErrorTimeoutError
#define SysPushErrorWatchdogErrorDbg SysPushErrorWatchdogError
#define SysPushErrorServiceErrorDbg SysPushErrorServiceError
#define SysPushErrorPermissionErrorDbg SysPushErrorPermissionError
#define SysPushErrorOutOfRangeDbg SysPushErrorOutOfRange
@ -128,34 +138,34 @@ namespace Aurora::Debug
#else
#define SysPushErrorArgDbg(...)
#define SysPushErrorGenDbg(...)
#define SysPushErrorCryptDbg(...)
#define SysPushErrorNetDbg(...)
#define SysPushErrorMemDbg(...)
#define SysPushUserErrorDbg(...)
#define SysPushErrorArgDbg(...)
#define SysPushErrorGenDbg(...)
#define SysPushErrorCryptDbg(...)
#define SysPushErrorNetDbg(...)
#define SysPushErrorMemDbg(...)
#define SysPushErrorGenericDbg(...)
#define SysPushErrorNestedDbg(...)
#define SysPushErrorMemoryDbg(...)
#define SysPushErrorIODbg(...)
#define SysPushErrorFIODbg(...)
#define SysPushErrorNetDbg(...)
#define SysPushErrorAudioDbg(...)
#define SysPushErrorHALDbg(...)
#define SysPushErrorHALContextDbg(...)
#define SysPushErrorCryptoDbg(...)
#define SysPushErrorParamDbg(...)
#define SysPushErrorLogicErrorDbg(...)
#define SysPushErrorMathErrorDbg(...)
#define SysPushErrorGenericDbg(...)
#define SysPushErrorNestedDbg(...)
#define SysPushErrorMemoryDbg(...)
#define SysPushErrorIODbg(...)
#define SysPushErrorFIODbg(...)
#define SysPushErrorNetDbg(...)
#define SysPushErrorAudioDbg(...)
#define SysPushErrorHALDbg(...)
#define SysPushErrorHALContextDbg(...)
#define SysPushErrorCryptoDbg(...)
#define SysPushErrorParamDbg(...)
#define SysPushErrorLogicErrorDbg(...)
#define SysPushErrorMathErrorDbg(...)
#define SysPushErrorUnavailableErrorDbg(...)
#define SysPushErrorTimeoutErrorDbg(...)
#define SysPushErrorWatchdogErrorDbg(...)
#define SysPushErrorServiceErrorDbg(...)
#define SysPushErrorTimeoutErrorDbg(...)
#define SysPushErrorWatchdogErrorDbg(...)
#define SysPushErrorServiceErrorDbg(...)
#define SysPushErrorPermissionErrorDbg(...)
#define SysPushErrorOutOfRangeDbg(...)
#define SysPushErrorSyntaxErrorDbg(...)
#define SysPushErrorDisconnectedDbg(...)
#define SysPushErrorUninitializedDbg(...)
#endif

View File

@ -7,9 +7,11 @@
***/
#pragma once
#if defined(_AUHAS_FMT)
template<typename ... T>
static inline void __declspec(noreturn) SysPanic(T... args)
{
Aurora::Console::Logging::WriteLinef(Aurora::Console::EAnsiColor::eBoldRed, "Fatal", args...);
Aurora::Debug::Panic();
}
}
#endif

View File

@ -11,12 +11,12 @@ namespace Aurora::Hashing
{
namespace CE
{
constexpr uint64_t val_64_const = 0xcbf29ce484222325;
constexpr uint64_t prime_64_const = 0x100000001b3;
constexpr uint64_t kFnv1MagicVal64 = 0xcbf29ce484222325;
constexpr uint64_t kFnv1MagicPrime64 = 0x100000001b3;
inline constexpr uint64_t fnv1a(const char *const str, const uint64_t value = val_64_const) noexcept
inline constexpr uint64_t fnv1a(const char *const str, const uint64_t value = kFnv1MagicVal64) noexcept
{
return (str[0] == '\0') ? value : fnv1a(&str[1], (value ^ uint64_t(str[0])) * prime_64_const);
return (str[0] == '\0') ? value : fnv1a(&str[1], (value ^ uint64_t(str[0])) * kFnv1MagicPrime64);
}
inline constexpr uint32_t fnv1a_trunc(const char *const str) noexcept
@ -24,12 +24,12 @@ namespace Aurora::Hashing
return static_cast<uint32_t>(fnv1a(str));
}
constexpr uint64_t val_32_const = 0x811c9dc5;
constexpr uint64_t prime_32_const = 0x01000193;
constexpr uint64_t kFnv1MagicVal32 = 0x811c9dc5;
constexpr uint64_t kFnv1MagicPrime32 = 0x01000193;
inline constexpr uint32_t fnv1a_32(const char *const str, const uint32_t value = val_32_const) noexcept
inline constexpr uint32_t fnv1a_32(const char *const str, const uint32_t value = kFnv1MagicVal32) noexcept
{
return (str[0] == '\0') ? value : fnv1a_32(&str[1], (value ^ uint32_t(str[0])) * prime_32_const);
return (str[0] == '\0') ? value : fnv1a_32(&str[1], (value ^ uint32_t(str[0])) * kFnv1MagicPrime32);
}
}
}

View File

@ -12,8 +12,15 @@ namespace Aurora::Hashing
class IHashStream
{
public:
virtual void Ingest(const void *, AuUInt32) = 0;
virtual AuUInt8 *GetBytes(AuUInt32 &length) = 0;
/*
* Digest length of pBuf bytes
*/
virtual void Ingest(const void *pBuf, AuUInt32 length) = 0;
/**
* Locks and returns the internal buffer
*/
virtual AuUInt8 const* GetBytes(AuUInt32 &length) = 0;
};
AUKN_SHARED_API(HashStream, IHashStream, EHashType type);

View File

@ -0,0 +1,43 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AFIO.hpp
Date: 2021-8-21
Author: Reece
***/
#pragma once
namespace Aurora::IO::AFIO
{
class IAsyncTransaction;
class IAsyncFileStream
{
public:
virtual AuSPtr<IAsyncTransaction> NewTransaction() = 0;
};
class IAsyncFinishedSubscriber
{
public:
virtual OnAsyncFileOpFinished(AuUInt64 offset, AuUInt32 length) = 0;
};
class IAsyncTransaction
{
public:
virtual void StartRead(AuUInt64 offset, void *, AuUInt32 length) = 0;
virtual void StartWrite(AuUInt64 offset, const void *, AuUInt32 length) = 0;
virtual bool Complete() = 0;
virtual AuUInt32 GetLastPacketLength() = 0;
virtual void SetCallback(const AuSPtr<IAsyncFinishedSubscriber> &sub) = 0;
virtual void Wait(AuUInt32 timeout) = 0;
};
AUKN_SHARED_API(Open, IAsyncFileStream, const AuString &path, bool readOnly = true, bool directIO = false);
AUKN_SHARED bool WaitMultiple(const AuList<IAsyncTransaction> &files, AuUInt32 timeout);
}

View File

@ -26,11 +26,22 @@ namespace Aurora::IO
while ((ret = Read(temp, len)) == EStreamError::eErrorNone)
{
if (len == 0) break;
if (len == 0)
{
break;
}
buffer.insert(buffer.end(), temp, temp + len);
if (len != kBufferSize) break;
if (len != kBufferSize)
{
break;
}
}
if (ret == EStreamError::eErrorEndOfStream)
{
return EStreamError::eErrorNone;
}
return ret;

View File

@ -52,10 +52,101 @@ namespace Aurora::IO::Net
class IBasicSocket;
class IClientSocket;
using StreamHasData_cb = std::function<bool(AuSPtr<IClientSocket> socket)>; // DTLS/UDP/TCP/TLS -> TRUE = expects another frame or stream buffer, FALSE = end of socket life
using InitializeSocket_cb = std::function<bool(AuSPtr<IClientSocket> socket)>;
using ShutdownSocket_cb = std::function<void(AuSPtr<IBasicSocket> socket)>;
/**
* DTLS/UDP/TCP/TLS -> TRUE = expects another datagram or read pump
* -> FALSE = end of socket life
*/
using StreamHasData_cb = std::function<bool(const AuSPtr<IClientSocket> &socket)>;
using InitializeSocket_cb = std::function<bool(const AuSPtr<IClientSocket> &socket)>;
using ShutdownSocket_cb = std::function<void(const AuSPtr<IClientSocket> &socket)>;
class IClientHasData
{
public:
// DTLS/UDP/TCP/TLS -> TRUE = expects another datagram or read pump
// FALSE = end of socket life
virtual bool OnSocketHasData(const AuSPtr<IClientSocket> &socket) = 0;
};
class FunctionalClientHasData : public IClientHasData
{
private:
StreamHasData_cb socket_;
public:
FunctionalClientHasData(const StreamHasData_cb &socket) : socket_(socket)
{}
FunctionalClientHasData(StreamHasData_cb &&socket) : socket_(std::move(socket))
{}
};
class IClientShutdown
{
public:
virtual void OnSocketShutdown(const AuSPtr<IClientSocket> &socket) = 0;
};
class FunctionalClientShutdown : public IClientShutdown
{
private:
ShutdownSocket_cb socket_;
public:
FunctionalClientShutdown(const ShutdownSocket_cb &socket) : socket_(socket)
{}
FunctionalClientShutdown(ShutdownSocket_cb &&socket) : socket_(std::move(socket))
{}
};
class IClientDoS
{
public:
virtual void OnSocketDoS(const AuSPtr<IClientSocket> &socket) = 0;
};
class FunctionalClientDoS: public IClientDoS
{
private:
ShutdownSocket_cb socket_;
public:
FunctionalClientDoS(const ShutdownSocket_cb &socket) : socket_(socket)
{}
FunctionalClientDoS(ShutdownSocket_cb &&socket) : socket_(std::move(socket))
{}
};
class IClientTLSBreakdown
{
public:
virtual void OnSocketTLSBreakdown(const AuSPtr<IClientSocket> &socket) = 0;
};
class FunctionalClientTLSBreakdown : public IClientTLSBreakdown
{
private:
ShutdownSocket_cb socket_;
public:
FunctionalClientTLSBreakdown(const ShutdownSocket_cb &socket) : socket_(socket)
{}
FunctionalClientTLSBreakdown(ShutdownSocket_cb &&socket) : socket_(std::move(socket))
{}
};
class IClientEvents
{
public:
virtual void AddSubscriptionHasData(const AuSPtr<IClientHasData> &iface) = 0;
virtual void RemoveSubscriptionHasData(const AuSPtr<IClientHasData> &iface) = 0;
virtual void AddSubscriptionShutdown(const AuSPtr<IClientShutdown> &iface) = 0;
virtual void RemoveSubscriptionShutdown(const AuSPtr<IClientShutdown> &iface) = 0;
virtual void AddSubscriptionDoS(const AuSPtr<IClientDoS> &iface) = 0;
virtual void RemoveSubscriptionDoS(const AuSPtr<IClientDoS> &iface) = 0;
virtual void AddSubscriptionTlsBreakdown(const AuSPtr<IClientTLSBreakdown> &iface) = 0;
virtual void RemoveSubscriptionTlsBreakdown(const AuSPtr<IClientTLSBreakdown> &iface) = 0;
};
using Error_t = std::error_code;
class IBasicSocket
@ -70,26 +161,43 @@ namespace Aurora::IO::Net
class IClientSocket : public IBasicSocket
{
public:
// called during loop pump
struct ClientCallbacks
{
StreamHasData_cb hasData; // on data available
ShutdownSocket_cb onShutdown; // Socket shutdown or otherwise dead
ShutdownSocket_cb onStreamOverSaturation; // DoS?
ShutdownSocket_cb onTLSHandshakeAbort;
};
virtual IClientEvents *GetClientEvents() = 0;
virtual bool Initialize(const ClientCallbacks &callbacks) = 0;
virtual bool Initialize() = 0;
virtual bool Initialize() = 0;
virtual bool GetRemoteEndpoint(Endpoint &out) = 0;
virtual bool GetRemoteEndpoint(Endpoint &out) = 0;
virtual bool ReadAsync(AuUInt8 *buffer, bool all, AuUInt32 &length) = 0;
virtual bool WriteAsync(const AuUInt8 *buffer, AuUInt32 length) = 0;
virtual bool WriteAsync(const AuUInt8 *buffer, AuUInt32 length, std::function<void(bool)>) = 0;
virtual bool PumpRead() = 0;
virtual bool PumpWrite() = 0;
virtual bool ReadAsync(AuUInt8 *buffer, AuUInt32 &length, bool all = false) = 0;
virtual bool PeakAsync(AuUInt8 *buffer, AuUInt32 &length) = 0;
virtual bool ReadSync(AuUInt8 *buffer, AuUInt32 &length, bool all = true) = 0;
virtual bool WriteAsync(const AuUInt8 *buffer, AuUInt32 length) = 0;
virtual bool WriteAsync(const AuUInt8 *buffer, AuUInt32 length, std::function<void(bool)>) = 0;
virtual bool WriteSync(const AuUInt8 *buffer, AuUInt32 length) = 0;
virtual AuUInt GetInternalRecvBuffer() = 0;
virtual bool SetInternalRecvBuffer(AuUInt bytes) = 0;
/**
* Sets the internal application buffer size
* Noting that Linux's default network buffer looks like this:
* Minimum, Initial, Maximum: 10240 87380 12582912 | 10KB, 86KB, 12MB
*/
virtual AuUInt GetInternalRingBuffer() = 0;
virtual bool SetInternalRingBuffer(AuUInt bytes) = 0;
/**
* Defines the maximum amount of bytes each recieve frame can ingest
*/
virtual void SetRecvLength(AuOptional<AuUInt32> length) = 0;
virtual AuUInt32 GetRecvLength() = 0;
/**
* Enable ad-hoc input buffer ingestion into our internal buffer
* Only use when PumpRead will not suffice by design (ie: sync apps)
*/
virtual void BufferAdhoc(AuOptional<bool> value) = 0;
};
class ILocalClientSocket : public IClientSocket
@ -135,7 +243,7 @@ namespace Aurora::IO::Net
virtual bool AddAcceptCallback(const InitializeSocket_cb &accept) = 0; // on accept*
virtual bool AddExitCallback(const ShutdownSocket_cb &accept) = 0; // server shutdown*
virtual void GetClients(AuList<AuSPtr<IClientSocket>> &soccies) = 0;
virtual void GetClients(AuList<AuSPtr<IClientSocket>> &clients) = 0;
virtual bool Listen() = 0;
};
@ -147,12 +255,12 @@ namespace Aurora::IO::Net
while (true)
{
// read from sockets pre-frame
PumpSOL();
PumpRead();
// process other async network logic here
// process writes and a few early reads before we sleep
PumpEOL();
PumpWrite();
// yield
Yield();
@ -162,22 +270,21 @@ namespace Aurora::IO::Net
{
// process other async network logic here
// run
Run()
// run once
Pump()
}
...and none with BufferAdhoc enabled
*/
virtual void PumpSOL() = 0;
virtual void PumpEOL() = 0;
virtual void PumpRead() = 0;
virtual void PumpWrite() = 0;
virtual void Run() = 0;
virtual void Pump() = 0;
virtual bool NewServer(const ServerInfo &listen, IServer *&out) = 0;
virtual bool NewTlsServer(const TLSServerInfo &keys, IServer *&out) = 0;
virtual void DeleteServer(IServer *socket) = 0;
virtual bool NewServer(const ServerInfo &listen, AuSPtr<IServer> &out) = 0;
virtual bool NewTlsServer(const TLSServerInfo &keys, AuSPtr<IServer> &out) = 0;
virtual bool NewClient(const ClientInfo &info, ILocalClientSocket *&out) = 0;
virtual bool NewTlsClient(const TLSClientInfo &info, ILocalClientSocket *&out) = 0;
virtual void DeleteClient(ILocalClientSocket *socket) = 0;
virtual bool NewClient(const ClientInfo &info, AuSPtr<ILocalClientSocket> &out) = 0;
virtual bool NewTlsClient(const TLSClientInfo &info, AuSPtr<ILocalClientSocket> &out) = 0;
};
}

View File

@ -1,9 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: FS.Win32.hpp
Date: 2021-6-12
File: IPCCV.hpp
Date: 2021-8-27
Author: Reece
***/
#pragma once

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: IPCEvent.hpp
Date: 2021-8-28
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: IPCMemory.hpp
Date: 2021-8-27
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: IPCMutex.hpp
Date: 2021-8-27
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: IPCPipeClient.hpp
Date: 2021-8-28
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: IPCPipeServer.hpp
Date: 2021-8-28
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: IPCSemaphore.hpp
Date: 2021-8-27
Author: Reece
***/

View File

@ -0,0 +1,29 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ECodePage.hpp
Date: 2021-8-20
Author: Reece
***/
#pragma once
namespace Aurora::Locale
{
enum class ECodePage
{
eUTF32,
eUTF32BE,
eUTF16,
eUTF16BE,
eUTF8,
eUTF7,
e18030,
e2312,
eGBK,
eSJIS,
eLatin1,
eSysUnk,
eUnsupported,
eMax = eUnsupported
};
}

View File

@ -0,0 +1,25 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Encoding.hpp
Date: 2021-8-20
Author: Reece
***/
#pragma once
namespace Aurora::Locale::Encoding
{
AUKN_SYM AuStreamReadWrittenPair_t EncodeUTF8(const void *utf8, AuUInt32 ut8Length, void *binary, AuUInt32 binaryLength, ECodePage page = ECodePage::eUnsupported);
static inline AuStreamReadWrittenPair_t EncodeUTF8(const AuString &out, void *binary, AuUInt32 binaryLength, ECodePage page = ECodePage::eUnsupported)
{
return EncodeUTF8(out.data(), static_cast<AuUInt32>(out.size()), binary, binaryLength, page);
}
AUKN_SYM std::optional<AuPair<ECodePage, AuUInt8>> DecodeBOM(const void *binary, AuUInt32 binaryLength);
/// Translates a buffer, possibly a slice of a stream, to UTF-8
/// Returns a pair; bytes consumed, bytes written
AUKN_SYM AuStreamReadWrittenPair_t DecodeUTF8(const void *binary, AuUInt32 binaryLength, void *utf8, AuUInt32 utf8Max, ECodePage page = ECodePage::eUnsupported);
AUKN_SYM AuStreamReadWrittenPair_t DecodeUTF8(const void *binary, AuUInt32 binaryLength, AuString &out, ECodePage page = ECodePage::eUnsupported);
}

View File

@ -7,15 +7,19 @@
***/
#pragma once
#include "ECodePage.hpp"
#include "Encoding/Encoding.hpp"
namespace Aurora::Locale
{
struct LocalizationInfo
{
LocalizationInfo(const AuString& language, const AuString& country, const AuString& codeset) : Language(language), Country(country), Codeset(codeset) {}
LocalizationInfo(const AuString& language, const AuString& country, const AuString& codeset, const ECodePage codePage) : language(language), country(country), codeset(codeset), codepage(codePage) {}
const AuString& Language;
const AuString& Country;
const AuString& Codeset;
const AuString& language;
const AuString& country;
const AuString& codeset;
const ECodePage codepage;
};
/*
@ -25,7 +29,6 @@ namespace Aurora::Locale
*/
AUKN_SYM LocalizationInfo GetLocale();
#if defined(AURORA_PLATFORM_WIN32) || defined(I_REALLY_NEED_WIDECHAR_PUBAPI)
AUKN_SYM std::wstring ConvertFromUTF8(const AuString &in);
AUKN_SYM AuString ConvertFromWChar(const wchar_t *in, AuMach length);

View File

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LSAsync.hpp
Date: 2021-8-21
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LSCV.hpp
Date: 2021-8-28
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LSEvent.hpp
Date: 2021-8-28
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LSFd.hpp
Date: 2021-8-21
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LSGlib.hpp
Date: 2021-8-21
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LSMutex.hpp
Date: 2021-8-28
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LSRWMutex.hpp
Date: 2021-8-21
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LSSemaphore.hpp
Date: 2021-8-28
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LSTimer.hpp
Date: 2021-8-21
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LSWin32.hpp
Date: 2021-8-21
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LSX11.hpp
Date: 2021-8-21
Author: Reece
***/

View File

@ -0,0 +1,40 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Loop.hpp
Date: 2021-8-21
Author: Reece
***/
enum class ELoopSource
{
eSourceInternalReserved1,
eSourceInternalReserved2,
eSourceInternalReserved3,
eSourceInternalReserved4,
// unix only
eSourceFileDescriptor,
// generic
eSourceSemaphore,
eSourceMutex,
eSourceTimer,
// Specific to the runtime subsystem
eSourceAsync,
// glib oses only
eSourceGlib,
// window messge loops
eSourceApple,
eSourceX11,
eSourceWin32
};
class ILoopSource
{
};

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Wait.hpp
Date: 2021-8-21
Author: Reece
***/

View File

@ -0,0 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Array.hpp
Date: 2021-8-5
Author: Reece
***/

View File

@ -0,0 +1,550 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ByteBuffer.hpp
Date: 2021-8-5
Author: Reece
***/
#pragma once
namespace Aurora::Memory
{
static const auto kBufferPageSize = 512;
/***
* A bytebuffer object represents a linear, partially-linear resizable, buffer **or** a ring buffer.
*
* Use cases for a ring buffer include wrapping specific streams whereby your use cases may include
* arbitrarily seeking around wrapped blocks of a more limited block stream, a network stream, or other api
* IE;
* -> peaking a header in a datagram, or tcp stream; where instead of freeing the datagram or saving
* the buffered tcp stream, a ring buffer is used to prevent reallocation on each frame
* -> peaking, or seeking back after, a compression read transaction. A compression api could be fed on-
* demand or ad hoc, writing to its write head pointer, while never running out of space so long as
* the decompressed ring read head continues moving
*
* Small, linear, write/read-once [de]serialization use cases may elect to allocate a buffer and
* follow the linear fast paths; perhaps even enabling flagExpandable for hopefully-smarter-than-stdvec-scaling
*
* Ring buffers scale from the write head, to the read head, potentially going-around in the process
*
* Linear flagExpandable buffers scale from [0, length]; reallocating at end of buffer if flagExpandable is enabled
* if expanding is enabled,
* realloc(max(size + offset, (offset / kBufferPageSize + 1) * kBufferPageSize))
*
* Deprecates INetworkStream, fixes allocation issues around compression backends
* Superseeds abuse of AuList<AuUInt8> for binary blobs, alongside Memory::Array
*/
struct ByteBuffer
{
///////////////////////////////////////////////////////////////////////
// Stable ByteBuffer ABI Header; length and read/write head pointers //
///////////////////////////////////////////////////////////////////////
/// Internal capacity to mitigate trivial reallocs
AuUInt allocSize;
/// Abstract size
AuUInt length;
/// Buffer pointer
AuUInt8 *base;
/// Stream pointer
AuUInt8 *readPtr;
/// Stream pointer
AuUInt8 *writePtr;
///////////////////////////////////////////////////////////////////////
// Stable ByteBuffer ABI Header; u32 flags //
///////////////////////////////////////////////////////////////////////
/// Is ring buffer?
AuUInt32 flagCircular : 1;
/// Should resize linear buffer to accommodate additional writes
AuUInt32 flagExpandable : 1;
AuUInt32 flagReadError : 1;
AuUInt32 flagWriteError : 1;
///////////////////////////////////////////////////////////////////////
ByteBuffer(const ByteBuffer &buffer, bool preservePointers = true)
{
this->base = ZAlloc<AuUInt8 *>(buffer.length);
this->length = buffer.length;
this->allocSize = buffer.length;
if (preservePointers)
{
this->writePtr = this->base + (buffer.writePtr - buffer.base);
this->readPtr = this->base + (buffer.readPtr - buffer.base);
}
else
{
this->writePtr = this->base;
this->readPtr = this->base;
}
std::memcpy(this->base, buffer.base, this->length);
this->flagCircular = buffer.flagCircular;
this->flagExpandable = buffer.flagExpandable;
}
ByteBuffer(const void *in, AuUInt length, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0)
{
this->base = ZAlloc<AuUInt8 *>(length);
this->length = length;
this->allocSize = length;
this->readPtr = this->base;
this->writePtr = this->readPtr + this->length;
std::memcpy(this->base, in, this->length);
}
ByteBuffer(const AuList<AuUInt8> &vector, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0)
{
this->base = ZAlloc<AuUInt8 *>(length);
this->length = vector.size();
this->allocSize = vector.size();
this->readPtr = this->base;
this->writePtr = this->readPtr + this->length;
std::memcpy(this->base, vector.data(), this->length);
}
ByteBuffer(AuUInt length, bool circular = false, bool expandable = false) : flagCircular(circular), flagExpandable(expandable), flagReadError(0), flagWriteError(0)
{
this->base = ZAlloc<AuUInt8 *>(length);
this->length = length;
this->allocSize = length;
this->readPtr = this->base;
this->writePtr = this->base;
}
~ByteBuffer()
{
Free(this->base);
}
inline void ResetPositions()
{
this->flagReadError = 0;
this->flagWriteError = 0;
this->readPtr = base;
this->writePtr = base;
}
// Iterator
AUKN_SYM AuUInt8 *begin();
AUKN_SYM AuUInt8 *end();
// To alternative types
AUKN_SYM AuList<AuUInt8> ToVector();
// Seek
AUKN_SYM bool ReaderTryGoForward(AuUInt32 offset);
AUKN_SYM bool ReaderTryGoBack(AuUInt32 offset);
AUKN_SYM bool WriterTryGoForward(AuUInt32 offset);
AUKN_SYM AuOptional<AuUInt8 *> WriterTryGetWriteHeadFor(AuUInt32 nBytes);
// Template implementation
// TODO: remove to .inl
template<typename T>
inline bool Read(T &out)
{
if constexpr (std::is_class_v<T>)
{
if constexpr (AuIsBaseOfTemplate<AURORA_RUNTIME_AU_LIST, std::remove_reference_t<T>>::value)
{
if (Read<AuUInt32>() != sizeof(typename T::value_type))
{
this->flagReadError = true;
return false;
}
auto len = Read<AuUInt32>();
out.resize(len);
for (auto i = 0u; i < len; i++)
{
Read<T::value_type>(out[i]);
}
return !this->flagReadError;
}
else if constexpr (std::is_same_v<std::remove_reference_t<T>, AuString>)
{
out.resize(Read<AuUInt32>());
Read(out.data(), out.size());
return !this->flagReadError;
}
}
auto oldptr = readPtr;
auto skipped = Read(&out, sizeof(T));
if (skipped != sizeof(T))
{
this->flagReadError = true;
return false;
}
return true;
}
template<typename T>
inline T Read()
{
T a{};
Read(a);
return a;
}
template<typename T>
inline bool Write(const T &in)
{
if constexpr (std::is_class_v<T>)
{
if constexpr (AuIsBaseOfTemplate<AURORA_RUNTIME_AU_LIST, std::remove_reference_t<T>>::value)
{
Write<AuUInt32>(sizeof(typename T::value_type));
Write<AuUInt32>(AuUInt32(in.size()));
for (const auto &item : in)
{
Write<T::value_type>(item);
}
return !this->flagWriteError;
}
else if constexpr (std::is_same_v<std::remove_reference_t<T>, AuString>)
{
Write<AuUInt32>(AuUInt32(in.size()));
Write(in.data(), in.size());
return !this->flagWriteError;
}
}
auto skipped = Write(&in, sizeof(T));
if (skipped != sizeof(T))
{
this->flagWriteError = true;
return false;
}
return true;
}
inline bool Resize(AuUInt length)
{
AuUInt oldWriteIdx, oldReadIdx, oldLength, newLength;
AuUInt8 *nextRead, *nextWrite, *nextPtr;
if (this->allocSize > length)
{
this->length = length;
oldLength = this->length;
newLength = length;
nextPtr = this->base;
oldWriteIdx = this->writePtr - this->base;
oldReadIdx = this->readPtr - this->base;
nextRead = nextPtr + oldReadIdx;
nextWrite = nextPtr + oldWriteIdx;
}
else
{
oldLength = this->length;
newLength = std::max(AuUInt(length), AuUInt(((this->allocSize / kBufferPageSize) + 1) * kBufferPageSize));
nextPtr = ZRealloc(this->base, newLength);
if (!nextPtr)
{
return false;
}
oldWriteIdx = this->writePtr - this->base;
oldReadIdx = this->readPtr - this->base;
nextRead = nextPtr + oldReadIdx;
nextWrite = nextPtr + oldWriteIdx;
this->allocSize = newLength;
this->length = length;
}
this->base = nextPtr;
if (!flagCircular)
{
this->readPtr = nextRead;
this->writePtr = nextWrite;
}
else
{
if (this->writePtr > this->readPtr)
{
this->readPtr = nextRead;
this->writePtr = nextWrite;
}
else
{
auto expansion = newLength - oldLength;
auto movableTail = std::min(oldWriteIdx, expansion);
std::memcpy(nextPtr + oldLength, nextPtr, movableTail);
this->readPtr = nextRead;
this->writePtr = nextPtr + oldLength + movableTail;
}
}
return true;
}
inline AuUInt Write(const void *buffer, AuUInt requestLength)
{
AuUInt linearOverhead = 0, toReadOverhead = 0, linearWritable = 0, toReadWritable = 0, writable = 0;
auto cptr = reinterpret_cast<const AuUInt8 *>(buffer);
if (flagCircular)
{
// 0 1 2 3 4 5
// W R
// 6 - (1) = 5 -> read bound; we have zero overhead not 5
if (writePtr < readPtr)
{
// Handle read-bound writes
linearOverhead = readPtr - writePtr;
toReadOverhead = 0;
}
else
{
// Handle ordinary stream consume bound IO
linearOverhead = length - (writePtr - base);
toReadOverhead = readPtr - base;
}
writable = std::min(linearOverhead + toReadOverhead, requestLength);
linearWritable = std::min(linearOverhead, requestLength);
toReadWritable = writable - linearWritable;
if (cptr)
{
std::memcpy(writePtr, cptr, linearWritable);
}
writePtr += linearWritable;
if (toReadWritable)
{
writePtr = base;
if (cptr)
{
std::memcpy(writePtr, cptr + linearOverhead, toReadWritable);
}
writePtr += toReadWritable;
}
#if 0
if (writePtr == base + length)
{
writePtr = base;
}
#endif
return linearWritable + toReadWritable;
}
else
{
auto offset = writePtr - base;
auto overhead = length - offset;
AuUInt len = std::min(overhead, requestLength);
if ((len != requestLength) && (flagExpandable))
{
if (!Resize(offset + requestLength))
{
return 0;
}
overhead = length - offset;
len = std::min(overhead, requestLength);
}
if (buffer)
{
std::memcpy(writePtr, buffer, len);
}
writePtr += len;
return len;
}
}
inline AuUInt RemainingBytes(bool endAtWrite = true)
{
if (flagCircular)
{
if ((readPtr < writePtr) && (endAtWrite))
{
return length - (writePtr - readPtr);
}
else
{
auto linearOverhead = length - (readPtr - base);
auto toWriteOverhead = writePtr - base;
return linearOverhead + toWriteOverhead;
}
}
else
{
return endAtWrite ? (writePtr - readPtr) : (length - (readPtr - base));
}
}
inline AuList<AuUInt8> RemainingBytesToVector(bool endAtWrite = true)
{
AuList<AuUInt8> vec;
if (flagCircular)
{
if ((readPtr < writePtr) && (endAtWrite))
{
auto len = length - (writePtr - readPtr);
vec.resize(len);
std::memcpy(vec.data(), readPtr, len);
}
else
{
auto linearOverhead = length - (readPtr - base);
auto toWriteOverhead = endAtWrite ? (writePtr - base) : (readPtr - base);
vec.resize(linearOverhead + toWriteOverhead);
std::memcpy(vec.data(), readPtr, linearOverhead);
std::memcpy(vec.data() + linearOverhead, base, linearOverhead);
}
}
else
{
AuUInt len;
if (endAtWrite)
{
len = writePtr - readPtr;
}
else
{
len = length - (readPtr - base);
}
vec.resize(len);
std::memcpy(vec.data(), readPtr, len);
}
return vec;
}
inline bool Skip(AuUInt count)
{
auto oldptr = readPtr;
auto skipped = Read(nullptr, count);
if (skipped != count)
{
readPtr = oldptr;
return false;
}
return true;
}
inline AuUInt GetReadOffset()
{
if (flagCircular)
{
return 0;
}
else
{
return readPtr - base;
}
}
inline AuUInt GetWriteOffset()
{
if (flagCircular)
{
return 0;
}
else
{
return writePtr - base;
}
}
inline AuUInt Read(void *out, AuUInt requestedLength, bool peak = false)
{
AuUInt linearOverhead = 0, toWriteOverhead = 0, linearReadable = 0, toWriteReadable = 0;
if (flagCircular)
{
if (readPtr < writePtr)
{
linearOverhead = writePtr - readPtr;
toWriteOverhead = 0;
}
else
{
linearOverhead = length - (readPtr - base);
toWriteOverhead = writePtr - base;
}
auto readable = std::min(linearOverhead + toWriteOverhead, requestedLength);
linearReadable = std::min(linearOverhead, requestedLength);
toWriteReadable = readable - linearReadable;
if (out)
{
std::memcpy(out, readPtr, linearOverhead);
}
if (!peak)
{
readPtr += linearOverhead;
}
if (toWriteOverhead)
{
std::memcpy(reinterpret_cast<AuUInt8 *>(out) + linearOverhead, base, toWriteReadable);
if (!peak)
{
readPtr = base + toWriteReadable;
}
}
#if 0
if (readPtr == base + length)
{
readPtr = base;
}
#endif
return linearReadable + toWriteReadable;
}
else
{
AuUInt len = std::min(AuUInt(writePtr - readPtr), requestedLength);
if (out)
{
std::memcpy(out, readPtr, len);
}
if (!peak)
{
readPtr += len;
}
return len;
}
}
};
}

View File

@ -11,7 +11,6 @@
#include "MemRef.hpp"
#include "Heap.hpp"
#include "Handles.hpp"
namespace Aurora::Memory
{
@ -33,6 +32,8 @@ namespace Aurora::Memory
// -> do not double init
// TODO: ensure typeof(T) is not a pointer of a class
#if !defined(_CPPSHARP)
template<typename T>
T ZAlloc(Types::size_t length)
{
@ -124,20 +125,24 @@ namespace Aurora::Memory
}
template<typename T>
T SRealloc(T in, Types::size_t length)
T FRealloc(T in, Types::size_t length)
{
return reinterpret_cast<T>(_SRealloc(reinterpret_cast<void *>(in), length));
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(in), length));
}
template<typename T>
T SRealloc(T in, Types::size_t length, Types::size_t alloc)
T FRealloc(T in, Types::size_t length, Types::size_t alloc)
{
return reinterpret_cast<T>(_SRealloc(reinterpret_cast<void *>(in), length), alloc);
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(in), length), alloc);
}
template<typename T>
void Free(T in)
{
_Free(reinterpret_cast<void *>(in));
}
}
#endif
}
#include "Array.hpp"
#include "ByteBuffer.hpp"

View File

@ -0,0 +1,26 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Hex.hpp
Date: 2021-8-28
Author: Reece
***/
#pragma once
namespace Aurora::Parse
{
enum class EHexDump
{
eString,
eZeroXSpace,
eHexEditor,
eCLiteral,
eJSLiteral
};
AUKN_SYM void ByteToHex(AuUInt8 val, char(&hex)[2]);
AUKN_SYM bool HexToInt (const char *hex, AuUInt32 length, AuUInt64 &val);
AUKN_SYM void EncodeHex(const void *pBuf, AuUInt32 length, EHexDump formatting, AuString &out);
AUKN_SYM bool DecodeHex(const AuString &in, AuList<AuUInt8> &out);
}

View File

@ -24,8 +24,48 @@ namespace Aurora::Parse
}
lineCallback(line);
if (startIdx >= in.size())
{
break;
}
}
lineCallback(in.substr(startIdx));
}
static AuList<AuString> SplitString(const AuString &in, AuUInt16 characters)
{
AuList<AuString> ret;
for (auto i = 0u; i < in.size(); i += characters)
{
auto start = i;
auto end = std::min(AuUInt32(in.size()), AuUInt32(i + characters));
auto len = end - start;
ret.push_back(in.substr(start, len));
}
return ret;
}
static AuString SplitStringDelm(const AuString &in, const AuString &delm, AuUInt16 characters)
{
AuString ret;
ret.reserve(in.size());
for (auto i = 0u; i < in.size(); i += characters)
{
AuUInt32 start, end, len;
if (i != 0)
{
ret.insert(ret.size(), delm);
}
start = i;
end = std::min(AuUInt32(in.size()), AuUInt32(i + characters));
len = end - start;
ret.insert(ret.size(), in.substr(start, len));
}
return ret;
}
}

View File

@ -9,6 +9,7 @@
#include "Base32.hpp"
#include "Base64.hpp"
#include "Hex.hpp"
#include "LineParser.hpp"
#include "Parser.hpp"

View File

@ -40,24 +40,23 @@ namespace Aurora::Parse
struct ParseBit
{
ParseBit(ParsableTag _Tag, const AuString &_Label) : tag(_Tag), label(_Label)
{
}
ParseBit(ParsableTag _Tag, const AuString &_Label, bool _Array, bool _Optional, bool _vararg) : tag(_Tag), label(_Label), array(_Array), optional(_Optional), vararg(_vararg)
{
}
ParseBit(ParsableTag _Tag) : tag(_Tag)
{
}
ParseBit(ParsableTag _Tag, bool _Array, bool _Optional, bool _vararg) : tag(_Tag), array(_Array), optional(_Optional), vararg(_vararg)
{
}
ParseBit(ParsableTag tag, const AuString &label) : tag(tag), label(label)
{}
ParseBit(ParsableTag tag, const AuString &label, bool array, bool optional, bool _vararg) : tag(tag), label(label), array(array), optional(optional), vararg(_vararg)
{}
ParseBit(ParsableTag tag) : tag(tag)
{}
ParseBit(ParsableTag tag, bool array, bool optional, bool _vararg) : tag(tag), array(array), optional(optional), vararg(_vararg)
{}
ParseBit(ParseObject _ObjectParse) : tag(ParsableTag::kParseObject), objectParse(_ObjectParse)
{
}
ParseBit(ParseObject _ObjectParse, const AuString &_Label) : tag(ParsableTag::kParseObject), objectParse(_ObjectParse), label(_Label)
{
}
{}
ParseBit(ParseObject _ObjectParse, const AuString &label) : tag(ParsableTag::kParseObject), objectParse(_ObjectParse), label(label)
{}
// marks this "parse bit" and all following part bits optional
bool optional = false;
@ -90,11 +89,10 @@ namespace Aurora::Parse
struct ParsedBit
{
ParsedBit()
{
}
ParsedBit(ParsableTag _tag) : tag(_tag)
{
}
{}
ParsedBit(ParsableTag tag) : tag(tag)
{}
AuMach count;
ParsableTag tag;
@ -131,6 +129,25 @@ namespace Aurora::Parse
return getc;
}
struct ParseState
{
ParseState(ConsumeStream_cb &str) : stringstream(str)
{}
ParseState(ConsumeStream_cb &&str) : stringstream(std::move(str))
{}
ConsumeStream_cb stringstream;
AuUInt8 *additionalTokens {};
AuUInt16 countOfTokens {};
bool hasLastToken {};
AuUInt8 lastTokenCharacter {};
AuMach lastTokenAdditional {};
};
AUKN_SYM void VaildateStructure(const ParseObject &object);
AUKN_SYM bool ConsumeToken(ParsableTag type, ConsumeStream_cb getc, ParseValue &out);
@ -145,17 +162,19 @@ namespace Aurora::Parse
return ConsumeToken(type, StringToConsumable(str, index), out);
}
AUKN_SYM bool Parse(ParseResult &result, const ParseObject &structure, ConsumeStream_cb getc);
AUKN_SYM bool Parse(ParseState &state, const ParseObject &structure, ParseResult &result);
static bool Parse(ParseResult &result, const ParseObject &structure, const AuString &str, AuMach &index)
{
return Parse(result, structure, StringToConsumable(str, index));
ParseState state(StringToConsumable(str, index));
return Parse(state, structure, result);
}
static bool Parse(ParseResult &result, const ParseObject &structure, const AuString &str)
{
AuMach index{};
return Parse(result, structure, StringToConsumable(str, index));
ParseState state(StringToConsumable(str, index));
return Parse(state, structure, result);
}
AUKN_SYM void SerializeToken(ParsableTag type, const ParseValue &value, AuString &str);

View File

@ -8,4 +8,36 @@
#pragma once
#include "Paths.hpp"
#include "ProcessMap.hpp"
#include "ProcessMap.hpp"
namespace Aurora::Process
{
AUKN_SYM AU_NORETURN void Exit(AuUInt32 exitcode);
enum class EModulePath
{
eModulePathCWD,
eModulePathSystemDir, /// /lib/, windir/system32
eModulePathUserDir, /// /usr/lib/
eProcessDirectory, ///
eOSSpecified, /// LD_LIBRARY_PATH + /etc/ld.so.conf, AddDllDirectory
eSpecified
};
static AuList<EModulePath> kUserOverloadableSearchPath = {EModulePath::eSpecified, EModulePath::eModulePathCWD, EModulePath::eProcessDirectory, EModulePath::eModulePathUserDir, EModulePath::eModulePathSystemDir};
static AuList<EModulePath> kAdminOverloadableSearchPath = {EModulePath::eSpecified, EModulePath::eModulePathSystemDir, EModulePath::eProcessDirectory, EModulePath::eModulePathCWD, EModulePath::eModulePathUserDir};
struct ModuleLoadRequest
{
AuString mod;
AuOptional<AuString> version;
AuOptional<AuString> extension;
AuList<AuString> const *specifiedSearchPaths {};
AuList<EModulePath> const *searchPath {};
bool verifyOne {}; // always true if the executable is signed
bool verifyAll {};
};
AUKN_SYM bool LoadModule(const ModuleLoadRequest &request);
AUKN_SYM AuMach GetProcAddress(AuString mod, AuString symbol);
}

View File

@ -18,7 +18,7 @@ namespace Aurora::Process
};
using Segments = AuList<Segment>;
AUKN_SYM std::optional<Segment> GetSegment(AuUInt pointer);
AUKN_SYM AuOptional<Segment> GetSegment(AuUInt pointer);
AUKN_SYM Segments DumpExecutableRoot();
AUKN_SYM Segments DumpExecutableAll();
}

View File

@ -19,8 +19,8 @@ namespace Aurora::Processes
public:
///
/// @return the waitable of a waitable child process or thread leader
virtual Threading::IWaitable *AsWaitable() = 0;
virtual AuSPtr<Threading::IWaitable> AsWaitable() = 0;
/// Assuming AsWaitable()->TryLock() && Spawn != SpawnType::kSpawnAtomicOvermap,
/// returns the true return value of the process
/// otherwise returns zero

View File

@ -0,0 +1,22 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ERngStringCharacters.hpp
Date: 2021-9-3
Author: Reece
***/
#pragma once
namespace Aurora::RNG
{
enum class ERngStringCharacters
{
eAlphaCharacters,
eLowerCharacters,
eUpperCharacters,
eNumericCharacters,
eAlphaNumericCharacters,
eExtendedEntropy,
eCount
};
}

View File

@ -0,0 +1,82 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: IRandomDevice.hpp
Date: 2021-9-3
Author: Reece
***/
#pragma once
namespace Aurora::RNG
{
class IRandomDevice
{
public:
virtual void Read(void *in, AuUInt32 length) = 0;
virtual AuString NextString(AuUInt32 length, ERngStringCharacters type = ERngStringCharacters::eAlphaCharacters) = 0;
virtual void NextString(char *string, AuUInt32 length, ERngStringCharacters type = ERngStringCharacters::eAlphaCharacters) = 0;
virtual AuUInt8 NextByte() = 0;
virtual bool NextBoolean() = 0;
virtual AuUInt32 NextU32() = 0;
virtual AuUInt32 NextU32(AuUInt32 min, AuUInt32 max) = 0;
virtual AuUInt64 NextU64() = 0;
virtual AuInt32 NextInt(AuInt32 min, AuInt32 max) = 0;
virtual double NextDecimal() = 0;
virtual float NextNumber(float min, float max) = 0;
virtual AuUInt32 NextIndex(AuUInt32 count /* = max + 1*/) = 0;
template<typename T, int N>
inline void NextArray(T(&array)[N])
{
Read(array, N * sizeof(T));
}
template<typename T>
inline void NextArray(T *array, AuUInt32 length)
{
Raed(array, length * sizeof(T));
}
template<typename T>
inline T NextTmpl()
{
T ret {};
Read(&ret, sizeof(T));
return ret;
}
template<typename T>
inline T &NextArray(T *items, AuUInt32 count)
{
return items[NextIndex(count)];
}
template<typename T>
inline T &NextVector(const AuList<T> &items)
{
return NextArray(items.data(), items.size());
}
};
struct RandomDef
{
bool secure;
AuOptional<AuUInt32> seed;
inline void SetSeed(AuUInt32 seed)
{
this->seed = seed;
this->secure = false;
}
inline void SetCSRNG()
{
this->secure = true;
this->seed.reset();
}
};
AUKN_SHARED_API(Random, IRandomDevice, const RandomDef &def);
}

View File

@ -2,18 +2,37 @@
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: RNG.hpp
Date: 2021-6-10
Date: 2021-7-14
Author: Reece
***/
#pragma once
#include "ERngStringCharacters.hpp"
#include "IRandomDevice.hpp"
namespace Aurora::RNG
{
AUKN_SYM void ReadSecureRNG(void *in, AuUInt length);
AUKN_SYM void ReadFastRNG(void *in, AuUInt length);
AUKN_SYM void ReadSecureRNG(void *in, AuUInt32 length);
AUKN_SYM void ReadFastRNG (void *in, AuUInt32 length);
AUKN_SYM AuString ReadString(AuUInt32 length, ERngStringCharacters type = ERngStringCharacters::eAlphaCharacters);
AUKN_SYM void RngString(char *string, AuUInt32 length, ERngStringCharacters type = ERngStringCharacters::eAlphaCharacters);
AUKN_SYM AuUInt8 RngByte();
AUKN_SYM bool RngBoolean();
AUKN_SYM AuUInt32 RngU32();
AUKN_SYM AuUInt32 RngU32(AuUInt32 min, AuUInt32 max);
AUKN_SYM AuUInt64 RngU64();
AUKN_SYM AuInt32 RngInt(AuInt32 min, AuInt32 max);
AUKN_SYM double RngDecimal();
AUKN_SYM float RngNumber(float min, float max);
AUKN_SYM AuUInt32 RngIndex(AuUInt32 count /* = max + 1*/);
// Note: it is conceivable that someone may want the following templates for some cryptographic purpose
template<bool fast = true, typename T, int N>
static inline void Read(T(&array)[N])
static inline void RngArray(T(&array)[N])
{
if constexpr (fast)
{
@ -26,7 +45,7 @@ namespace Aurora::RNG
}
template<bool fast = true, typename T>
static inline void Read(T *array, AuUInt length)
static inline void RngArray(T *array, AuUInt32 length)
{
if constexpr (fast)
{
@ -38,50 +57,25 @@ namespace Aurora::RNG
}
}
enum class RngStringCharacters
template<bool fast = true, typename T>
static inline T RngTmpl()
{
eAlphaCharacters,
eAlphaNumericCharacters,
eExtendedEntropy,
eCount
};
static void RngString(char *string, AuUInt length, RngStringCharacters type = RngStringCharacters::eAlphaCharacters)
{
static std::pair<const char *, int> rngSequence[static_cast<int>(RngStringCharacters::eCount)] =
T ret {};
if constexpr (fast)
{
{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 52},
{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", 62},
{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890=-+!$%^*.[];:", 75}
};
ReadSecureRNG(string, length);
const auto &pair = rngSequence[static_cast<int>(type)];
for (auto i = 0; i < length; i++)
{
auto idx = std::floor(static_cast<float>(reinterpret_cast<AuUInt8 *>(string)[i]) / 255.f * static_cast<float>(pair.second - 1));
string[i] = pair.first[static_cast<int>(idx)];
ReadFastRNG(&ret, sizeof(T));
}
}
static inline AuUInt8 RngByte()
{
AuUInt8 x[1];
Read<true>(x);
return x[0];
}
static inline bool RngBoolean()
{
return RngByte() > 127;
else
{
ReadSecureRNG(&ret, sizeof(T));
}
return ret;
}
template<typename T>
static inline T &RngArray(T *items, AuUInt count)
static inline T &RngArray(T *items, AuUInt32 count)
{
return items[static_cast<int>(std::floor(static_cast<float>(RngByte()) / 255.f * static_cast<float>(count - 1)))];
return items[RngIndex(count)];
}
template<typename T>

View File

@ -9,15 +9,157 @@
namespace Aurora::Registry
{
using RegistryType = Aurora::Data::DataType;
using RegistryValue = Aurora::Data::TypedValue;
using RegistryType = Data::DataType;
using RegistryValue = Data::TypedValue;
/**
* This registry implementation is a fairly reliable, small scale, preference, and app variable database
* Do not consider this as a replacement for a "real" high performance kvp database, it is not, it's a small cache backed document serializer for settings
*
* Basic use case:--------------------------------------------------------------
* -> AllocRegistry()
* -> Read("~/Registry/MyApp/DefSettings.dat")
* -> Read("~/Registry/MyApp/UserSettings.dat")
* -> menu.color = GetOrSetKey("theme-color", {.13, .13, .13})
* -> menu.colorChanaged := SetKey("theme-color", color)
* -> app:onExit := SaveAll({})
* -----------------------------------------------------------------------------
*
* Arbitrary write use case:----------------------------------------------------
* -> AllocRegistry()
* -> OpenReadWriteback("~/Registry/MyApp/Settings.dat")
* -> menu.color = GetOrSetKey("theme-color", {.13, .13, .13})
* -> menu.colorChanaged := SetKey("theme-color", color)
* -----------------------------------------------------------------------------
*
* Implementing a protected registry:-------------------------------------------
* -> AllocRegistry()
* -> Read("~/Registry/MyApp/PlayerProfile.dat") will read disk template to the cache, including one "genuine-player-setting"
* -> SetWriteModeCache()
* -> WriteKey("dev-secret-menu-enabled", {0})
* -> LockKey("dev-secret-menu-enabled"), no user write may pass to 'dev-reserved'
* -> SetWriteModeCache()
* -> SetKey("dev-secret-menu-enabled", {1}) originating from an evil script will fail, returning false
* -> SetKey("genuine-ux-setting", {2, 2}) will successfully write to cache
* -> SetKey("genuine-player-setting", {2, 2}) will be assumed to be legitimate, write to cache
* -> GetKey("genuine-ux-setting") will return {2, 2} from the cache
* -> GetKey("genuine-player-setting") will return {2, 2} from the cache
* -> SetKey("some-leftover-magic", {.3, .4, .3}) will successfully write to cache
* -> GetKey("some-leftover-magic") will return {.3, .4, .3} from the cache
* -> OpenSave({})
* -> SetKey("genuine-ux-setting", GetKey("genuine-ux-setting")) will specifically write genuine-ux-setting to disk
* -> var userSetting = GetKey("genuine-player-setting") will return genuine-player-setting from the cache
* -> if (userSetting is inbounds of good constraints) then SetKey("genuine-player-setting", userSetting [=GetKey("genuine-ux-setting")]) will write the cached value back to disk
* -> --
* -> Unload(), some-leftover-magic will be lost
*
*
* -> Prevent malicious usage of development variables while ensuring spurious references work with read only reference values
* -> You may write to the registry the default safe [key:value]s; for instance, zeroing out debug options
* -> You may call `LockKey(...)` to ensure spurious writes, like an unchecked server server command or user request, will not overload the protected variable
*
* -> Some developers may wish to validate the registry dataset before locking the registry,
* -> A general purpose vaildator, schema vaildator, or similar may wish to reset values back to a known good state (`SetWriteModeCache` + `SetKey`) before locking (`SetWriteModeNone`) an otherwise read only database
*
* -----------------------------------------------------------------------------
*
*/
class IRegistry
{
public:
enum class EWriteMode
{
eWriteModeLocked, ///
eWriteModeFileBuffer, /// Write to cache only
eWriteModeFileStream, /// [Default] write database to disk on each set, saving to cache
};
enum class EReadType
{
eClearCacheAndStore,
eStoreNew,
eStoreAll
};
virtual bool Read(const AuString &path, EReadType read) = 0;
/**
* Puts the registry in read only mode
*/
virtual void SetWriteModeNone() = 0; /// read only, eqiv of ForEach((key) => { LockKey(key) }; SetWriteModeCache();
/**
* Puts the registry in an in memory only mode.
* -> Permit local read/write updates
* -> Never allows SetKeys to write manipulated sates to an IO buffer or stream until sanitized or otherwise explicitly written back
*/
virtual void SetWriteModeCache() = 0;
/**
* Puts the registry in a live write mode
*/
virtual void SetWriteModeStream(const AuOptional<AuString> &path) = 0;
/**
* Puts the registry in a write-back-like mode
*/
virtual void SetWriteModeBuffered(const AuOptional<AuString> &path) = 0;
virtual void WriteAllCacheBack() = 0; /// eqiv of ForEach((key) => { WriteKey(key, GetKey(key)); }; writes all updated cache entries back to io buffer or stream
virtual void SaveBuffered() = 0;
/**
* Saves the current state of the registry
*/
virtual void SaveAll(const AuOptional<AuString> &path) = 0;
/**
* Further calls to SetKeys will; update a database on write, if buffered; or write to a buffer and serialize on flush (`SaveBuffered`)
*/
virtual void OpenSave(const AuString &path, bool buffered = false) = 0;
/**
* equiv Read(path, EReadType::eClearCacheAndStore)
*/
virtual void OpenRead(const AuString &path) = 0;
/**
* equiv Read(path, EReadType::eClearCacheAndStore), OpenSave(path, false)
*/
virtual void OpenReadWriteback(const AuString &path) = 0;
virtual void CloseSave() = 0;
virtual bool KeyExists(const AuString &key, RegistryType &type) = 0;
virtual bool GetOrCreateKey(const AuString &key, const RegistryValue &def, RegistryValue &value) = 0;
/**
* Write a key, to cache or to disk
*/
virtual bool SetKey(const AuString &key, const RegistryValue &value) = 0;
/**
* Read key from cache
*/
virtual bool GetKey(const AuString &key, RegistryValue &value) = 0;
virtual void LockKey(const AuString &str) = 0;
virtual void UnlockKey(const AuString &str) = 0;
/**
* @deprecated
*/
inline void Lock()
{
SetWriteModeCache();
}
/**
* @deprecated
*/
inline void Unlock()
{
OpenSave({}, false);
}
};
}

View File

@ -14,5 +14,5 @@
namespace Aurora::Registry
{
AUKN_SHARED_API(Registry, IRegistry, ERegistrySource source, const AuString &name);
AUKN_SHARED_API(Registry, IRegistry, ERegistrySource source);
}

View File

@ -19,19 +19,20 @@
#include "../AuroraMacros.hpp"
#if defined(_AUHAS_ASIO)
#include <asio.hpp>
#endif
#include <optional>
#include <functional>
#include "../AuroraTypedefs.hpp"
#include <glm/glm.hpp>
#if defined(_AUHAS_FMT)
#include <fmt/core.h>
#include <fmt/format.h>
#include <fmt/chrono.h>
#endif
#if !defined(_AUHAS_UUID)
#error Missing stduuid library
#endif
#include <uuid.h>
#define AUKN_SHARED_API(name, type, ...) AU_SHARED_API_EX(AUKN_SYM, name, type, ## __VA_ARGS__)
@ -99,35 +100,66 @@ namespace Aurora
struct ConsoleConfig
{
LocalLogInfo logging;
bool disableAll {};
/// Enables Aurora::Console::xxxStd functions; defer to enableStdXX for default logger behaviour
bool enableStdPassthrough {};
/// Disables standard, debug, and GUI consoles
bool disableAllConsoles {};
/// Attempt to force a terminal emulator host under graphical subsystems
bool forceConsoleWindow {};
/// Attempt to force a GUI console under command line targets
bool forceToolKitWindow {};
/// In conjunction with enableStdPassthrough, enables Aurora::Console::ReadStd to read binary
/// In conjunction with !enableStdPassthrough, enables stdout logging
bool enableStdIn {true};
bool attemptDarkTheme {true};
/// In conjunction with enableStdPassthrough, enables Aurora::Console::WriteStd to write binary
/// In conjunction with !enableStdPassthrough, enables stdin logger
bool enableStdOut {true};
/// Use WxWidgets when possible
bool enableWxWidgets {true};
/// FIO config
LocalLogInfo fio;
AuString supportPublic {"https://jira.reece.sx"};
AuString titleBrand = "Aurora SDK Sample";
AuString supportPublic {"https://git.reece.sx/AuroraSupport/AuroraRuntime/issues"};
AuString supportInternal {"https://jira.reece.sx"};
};
struct CryptoConfig
{
/// Defer to the rationales in the implementation
bool allowChineseCerts {false};
/// Defer to the rationales in the implementation
bool allowRussianCerts {true};
/// WIP
bool allowHTTPRetrievalOfCerts {true};
///
bool enablePinning {true};
bool allowHTTPRetrievalOfCerts {true};
bool enablePinning {true};
///
AuList<AuString> blacklistedCerts{};
AuList<AuString> whitelistedCerts{};
};
struct AsyncConfig
{
AuUInt32 schedularFrequency {2}; // * 0.5 or 1 MS depending on the platform
AuUInt32 sysPumpFrequency {10}; // x amount of schedularFrequencys
AuUInt32 schedularFrequency {2}; // * 0.5 or 1 MS depending on the platform
AuUInt32 sysPumpFrequency {25}; // x amount of schedularFrequencys
};
struct FIOConfig
{
AuOptional<AuString> defaultBrand = "Aurora";
};
struct RuntimeStartInfo
@ -136,10 +168,11 @@ namespace Aurora
CryptoConfig crypto;
TelemetryConfig telemetry;
AsyncConfig async;
FIOConfig fio;
};
AUKN_SYM void RuntimeStart(const RuntimeStartInfo &info);
AUKN_SYM void RuntimeOverloadLocality(const AuPair<AuString, AuString> &locality);
AUKN_SYM void RuntimeShutdown();
AUKN_SYM void RuntimeSysPump();
}

View File

@ -12,20 +12,68 @@ namespace Aurora::Threading
template<typename T>
class LockGuard
{
private:
using Internal_t = std::remove_pointer_t<T>;
public:
LockGuard(Aurora::Memory::MemRef<T> lock) : lockReference_(lock)
LockGuard(T &lock)
{
lockReference_->Lock();
if constexpr (std::is_pointer_v<T>)
{
annoying_ = lock;
}
else
{
annoying_ = &lock;
}
if constexpr (AuIsBaseOfTemplate<AURORA_RUNTIME_AU_SHARED_PTR, Internal_t>::value || AuIsBaseOfTemplate<AURORA_RUNTIME_AU_UNIQUE_PTR, Internal_t>::value)
{
annoying_->get()->Lock();
}
else
{
annoying_->Lock();
}
}
LockGuard(T &&lock)
{
if constexpr (std::is_pointer_v<T>)
{
annoying_ = lock;
}
else
{
annoying_ = &lock;
}
if constexpr (AuIsBaseOfTemplate<AURORA_RUNTIME_AU_SHARED_PTR, Internal_t>::value || AuIsBaseOfTemplate<AURORA_RUNTIME_AU_UNIQUE_PTR, Internal_t>::value)
{
annoying_->get()->Lock();
}
else
{
annoying_->Lock();
}
}
~LockGuard()
{
lockReference_->Unlock();
if constexpr (AuIsBaseOfTemplate<AURORA_RUNTIME_AU_SHARED_PTR, Internal_t>::value || AuIsBaseOfTemplate<AURORA_RUNTIME_AU_UNIQUE_PTR, Internal_t>::value)
{
annoying_->get()->Unlock();
}
else
{
annoying_->Unlock();
}
}
private:
Aurora::Memory::MemRef<T> lockReference_;
std::conditional_t<std::is_pointer_v<T>, T, T*> annoying_;
};
using WaitableLockGuard = LockGuard<IWaitable>;
#define AU_LOCK_GUARD(variable) Aurora::Threading::LockGuard<decltype(variable)> AU_CONCAT(__stack_lock, __COUNTER__) (variable);
}

View File

@ -1,41 +0,0 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LockGuardPtr.hpp
Date: 2021-6-10
Author: Reece
***/
#pragma once
namespace Aurora::Threading
{
template<typename T>
class LockGuardPtr
{
public:
LockGuardPtr(T *lock) : annoying_(lock)
{
lock->Lock();
}
LockGuardPtr(T &lock) : annoying_(&lock)
{
lock->Lock();
}
~LockGuardPtr()
{
if constexpr (is_base_of_template<std::shared_ptr, T>::value || is_base_of_template<std::unique_ptr, T>::value)
{
annoying_->get()->Unlock();
}
else
{
annoying_->Unlock();
}
}
private:
T *annoying_;
};
}

View File

@ -14,6 +14,27 @@ namespace Aurora::Threading::Primitives
public:
virtual IWaitable *AsReadable() = 0;
virtual IWaitable *AsWritable() = 0;
/**
* Solves the problem of atomic write racing
* Consider: Thread 1 | Thread 2
* ReadLock() |
* cmp internal_x, 0|
* jmp not eq +1 |
* ret |
* ReadUnlock() |
* | WriteLock()
* | internal_x = 1
* | WriteUnlock()
* WriteLock() |
* internal_x = 0 |
* WriteUnlock()
*
* where 1 and 0 should have been decided on mutually exclusively, losing the 1 state while assuming a decision in the locked state would remain true
* workaround: [1] check for the race conditions, implmeneting slow and inefficient branching and spurious checks
* workaround: [2] upgrade from read to write
*/
virtual bool UpgradeReadToWrite(AuUInt64 timeout) = 0;
};
AUKN_SHARED_API(RWLock, RWLock);

View File

@ -16,7 +16,6 @@
#include "Sleep.hpp"
#include "LockGuard.hpp"
#include "LockGuardPtr.hpp"
#include "Threads/Threads.hpp"

View File

@ -0,0 +1,41 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: IAuroraThread.hpp
Date: 2021-8-28
Author: Reece
***/
#pragma once
namespace Aurora::Threading::Threads
{
class TLSView;
/// Threads may be reimplemented as fibers or under some other userland context switcher
class IAuroraThread
{
public:
virtual bool Run() = 0;
virtual void Exit() = 0;
virtual bool Exiting() = 0;
virtual void SendExitSignal() = 0;
virtual void SetPrio(EThreadPrio prio) = 0;
virtual void SetAffinity(AuUInt32 mask) = 0;
virtual void SetName(const AuString &name) = 0;
virtual EThreadPrio GetPrio() = 0;
virtual AuUInt32 GetMask() = 0;
virtual AuString GetName() = 0;
/// Registers a thread feature _not_ calling on init
/// It is not possible for this lower level thread object to schedule an init call (defer to async)
/// Use this to register teardown functions
virtual void AddLastHopeTlsHook(const AuSPtr<Threading::Threads::IThreadFeature> &feature) = 0;
virtual AuSPtr<TLSView> GetTlsView() = 0;
virtual void ExecuteInDeadThread(std::function<void()> callback) = 0;
virtual AuSPtr<IWaitable> AsWaitable() = 0;
};
}

View File

@ -7,41 +7,15 @@
***/
#pragma once
#include "AbstractThreadVectors.hpp"
namespace Aurora::Threading::Threads
{
class TLSView;
/// Threads may be reimplemented as fibers or under some other userland context switcher
class IAuroraThread
{
public:
virtual void Run() = 0;
virtual void Exit() = 0;
virtual bool Exiting() = 0;
virtual void SendExitSignal() = 0;
virtual void SetPrio(EThreadPrio prio) = 0;
virtual void SetAffinity(AuUInt32 mask) = 0;
virtual void SetName(const AuString &name) = 0;
virtual EThreadPrio GetPrio() = 0;
virtual AuUInt32 GetMask() = 0;
virtual AuString GetName() = 0;
virtual AuSPtr<TLSView> GetTlsView() = 0;
virtual void ExecuteInDeadThread(std::function<void()> callback) = 0;
virtual IWaitable * AsWaitable() = 0;
};
AUKN_SYM IAuroraThread *GetThread();
AUKN_SYM AuThreadId_t GetThreadId();
AUKN_SYM AuThreadId_t GetThreadId();
AUKN_SYM void TerminateCurrent();
/**
Constructs a thread instance given a set of callbacks
*/
AUKN_SHARED_API(Thread, IAuroraThread, const AbstractThreadVectors &vectors);
AUKN_SHARED_API(Thread, IAuroraThread, const ThreadInfo &info);
}

View File

@ -0,0 +1,22 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ThreadInfo.hpp
Date: 2021-8-28
Author: Reece
***/
#pragma once
namespace Aurora::Threading::Threads
{
struct ThreadInfo
{
const AbstractThreadVectors &vectors;
ThreadInfo(const AbstractThreadVectors &vectors) : vectors(vectors)
{}
AuOptional<AuUInt32> stackSize;
AuOptional<AuString> name;
};
}

View File

@ -10,6 +10,8 @@
#include "IThreadFeature.hpp"
#include "EThreadPrio.hpp"
#include "AbstractThreadVectors.hpp"
#include "IAuroraThread.hpp"
#include "ThreadInfo.hpp"
#include "Thread.hpp"
#include "TLSView.hpp"
#include "TLSVariable.hpp"

View File

@ -11,7 +11,7 @@
namespace Aurora::Time
{
#if ((defined(AU_FORCE_BENCHMARK) || defined(DEBUG) || defined(INTERNAL)) && (!defined(AU_FORCE_NOBENCHMARK)))
#if ((defined(AU_FORCE_BENCHMARK) || defined(DEBUG) || defined(STAGING)) && (!defined(AU_FORCE_NOBENCHMARK)))
class DebugBenchmark
{

View File

@ -7,16 +7,21 @@
***/
#pragma once
#define AU_NO_COPY(type) type(type&) = delete;
#define AU_NO_MOVE(type) type(type&&) = delete;
#define AU_NO_COPY(type) type(type&) = delete;
#define AU_NO_MOVE(type) type(type&&) = delete;
#define AU_NO_COPY_NO_MOVE(type) AU_NO_COPY(type) AU_NO_MOVE(type)
#define AU_SHARED_FROM_THIS (std::static_pointer_cast<std::remove_pointer_t<decltype(this)>>(this->shared_from_this()))
#define AU_WEAK_FROM_THIS (AuWPtr<std::remove_pointer_t<decltype(this)>>(std::static_pointer_cast<std::remove_pointer_t<decltype(this)>>(this->shared_from_this())))
#define AU_SHARED_FROM_THIS (std::static_pointer_cast<std::remove_pointer_t<decltype(this)>>(this->shared_from_this()))
#define AU_WEAK_FROM_THIS (AuWPtr<std::remove_pointer_t<decltype(this)>>(std::static_pointer_cast<std::remove_pointer_t<decltype(this)>>(this->shared_from_this())))
/// @hideinitializer
#define AU_STRINGIFY_(in) #in
#define AU_STRINGIFY(in) AU_STRINGIFY_(in)
/// @hideinitializer
#define AU_CONCAT_(a, b) a ## b
#define AU_CONCAT(a, b) AU_CONCAT_(a, b)
/// @hideinitializer
#define _AUKCON_STRINGIFY_X(in) AU_STRINGIFY(in)
@ -37,7 +42,7 @@ struct CppDeleter ## name \
} \
}; \
\
using name ## Unique_t = std::unique_ptr<type, CppDeleter ## name>; \
using name ## Unique_t = AURORA_RUNTIME_AU_UNIQUE_PTR<type, CppDeleter ## name>; \
template<typename ... T> \
name ## Unique_t name ## Unique(T... args) \
{ \
@ -59,6 +64,12 @@ name ## Shared_t name ## Shared(T... args) \
#define AU_NOINLINE __attribute__((noinline))
#endif
#if defined(AURORA_COMPILER_MSVC)
#define AU_INLINE __declspec(__forceinline)
#else
#define AU_INLINE __attribute__((always_inline))
#endif
#if defined(AURORA_COMPILER_MSVC)
#define AU_NORETURN __declspec(noreturn)
#else

View File

@ -5,4 +5,5 @@
Date: 2021-6-9
Author: Reece
***/
#include <AuroraCommon.hpp>
#include "Aurora/Runtime.hpp"

View File

@ -7,14 +7,31 @@
***/
#pragma once
#include <vector>
#include <utility>
#include <map>
#include <string>
#include <array>
#include <algorithm>
#include <unordered_map>
#include <memory>
#if !defined(AURORA_RUNTINE_TYPEDEFS_INCLUDE)
#include <vector>
#include <utility>
#include <map>
#include <string>
#include <array>
#include <algorithm>
#include <unordered_map>
#include <memory>
#else
#if defined(AURORA_RUNTINE_TYPEDEFS_INCLUDE_HEADER)
#include <AURORA_RUNTINE_TYPEDEFS_INCLUDE_HEADER>
#endif
#endif
#if !defined(AURORA_RUNTIME_AU_LIST)
#define AURORA_RUNTIME_AU_LIST std::vector
#endif
#if defined(_CPPSHARP)
template<typename T>
using AuList = AURORA_RUNTIME_AU_LIST<T>;
#else
namespace Aurora::Memory
{
@ -22,27 +39,58 @@ namespace Aurora::Memory
struct SpeedyArrayAllocator;
}
template<typename T>
using AuList = typename std::conditional<std::is_class<T>::value, AURORA_RUNTIME_AU_LIST<T>, AURORA_RUNTIME_AU_LIST<T, Aurora::Memory::SpeedyArrayAllocator<T>>>::type;
#endif
#if !defined(AURORA_RUNTIME_AU_HASH_MAP)
#define AURORA_RUNTIME_AU_HASH_MAP std::unordered_map
#endif
template<typename T, typename Z>
using AuHashMap = AURORA_RUNTIME_AU_HASH_MAP<T, Z>;
template<typename T, typename Z, class Utility>
using AuHashMapEx = AURORA_RUNTIME_AU_HASH_MAP<T, Z, Utility, Utility>;
#if !defined(AURORA_RUNTIME_AU_BST)
#define AURORA_RUNTIME_AU_BST std::map
#endif
template<typename T, typename Z>
using AuBST = AURORA_RUNTIME_AU_BST<T, Z>;
template<typename T, typename Z, class Utility>
using AuBSTEx = AURORA_RUNTIME_AU_BST<T, Z, Utility>;
#if !defined(AURORA_RUNTIME_AU_SHARED_PTR)
#define AURORA_RUNTIME_AU_SHARED_PTR std::shared_ptr
#endif
template<typename T>
using AuList = typename std::conditional<std::is_class<T>::value, std::vector<T>, std::vector<T, Aurora::Memory::SpeedyArrayAllocator<T>>>::type;
using AuSPtr = AURORA_RUNTIME_AU_SHARED_PTR<T>;
template<class T, class Z>
using AuHashMap = std::unordered_map<T, Z>;
#if !defined(AURORA_RUNTIME_AU_WEAK_PTR)
#define AURORA_RUNTIME_AU_WEAK_PTR std::weak_ptr
#endif
template<class T, class Z, class Utility>
using AuHashMapEx = std::unordered_map<T, Z, Utility, Utility>;
template<typename T>
using AuWPtr = AURORA_RUNTIME_AU_WEAK_PTR<T>;
template<class T, class Z>
using AuBST = std::map<T, Z>;
#if !defined(AURORA_RUNTIME_AU_UNIQUE_PTR)
#define AURORA_RUNTIME_AU_UNIQUE_PTR std::unique_ptr
#endif
template<class T, class Z, class Utility>
using AuBSTEx = std::map<T, Z, Utility>;
template<typename T, typename Deleter_t>
using AuUPtr = AURORA_RUNTIME_AU_UNIQUE_PTR<T, Deleter_t>;
template<class T>
using AuSPtr = std::shared_ptr<T>;
#if !defined(AURORA_RUNTIME_AU_PAIR)
#define AURORA_RUNTIME_AU_PAIR std::pair
#endif
template<class T>
using AuWPtr = std::weak_ptr<T>;
template<typename A_t, typename B_t>
using AuPair = AURORA_RUNTIME_AU_PAIR<A_t, B_t>;
#if defined(AURORA_COMPILER_MSVC)
using AuAtomicInt = long;
@ -50,10 +98,18 @@ using AuAtomicInt = long;
using AuAtomicInt = int;
#endif
#if !defined(AURORA_RUNTIME_AU_OPTIONAL)
#define AURORA_RUNTIME_AU_OPTIONAL std::optional
#endif
template<typename T>
using AuOptional = AURORA_RUNTIME_AU_OPTIONAL<T>;
//#include "tinyutf8.h"
using AuString = std::string;// tiny_utf8::utf8_string;
using AuUInt64 = Aurora::Types::uint64_t;
using AuUInt32 = Aurora::Types::uint32_t;
using AuUInt16 = Aurora::Types::uint16_t;
@ -61,11 +117,45 @@ using AuUInt8 = Aurora::Types::uint8_t;
using AuInt64 = Aurora::Types::int64_t;
using AuInt32 = Aurora::Types::int32_t;
using AuInt16 = Aurora::Types::int16_t;
#if defined(_CPPSHARP)
using AuInt8 = Aurora::Types::uint8_t;
#else
using AuInt8 = Aurora::Types::int8_t;
#endif
using AuMach = Aurora::Types::size_t;
using AuSMach = Aurora::Types::ssize_t;
using AuSInt = AuSMach;
using AuUInt = AuMach;
using AuStreamReadWrittenPair_t = AuPair<AuUInt32, AuUInt32>;
using AuThreadId_t = AuUInt64;
static const AuThreadId_t kThreadIdSpecialMask = AuThreadId_t(1) << AuThreadId_t(63);
static const AuThreadId_t kThreadIdSpecialMask = AuThreadId_t(1) << AuThreadId_t(63);
#if defined(__has_include) && !defined(_AUHAS_GLM)
#if __has_include(<glm/glm.hpp>)
#define _AUHAS_GLM
#endif
#endif
#if !defined(_AUHAS_GLM)
template<int N>
struct AuFVec
{
float elements[N];
float &operator [](int idx) const
{
return elements[N];
}
};
using AuVec3 = AuFVec<3>;
using AuVec4 = AuFVec<4>;
#else
#include <glm/glm.hpp>
using AuVec3 = glm::vec3;
using AuVec4 = glm::vec4;
#endif

View File

@ -7,18 +7,56 @@
***/
#pragma once
#if !defined(AURORA_RUNTIME_MAKE_SHARED)
#define AURORA_RUNTIME_MAKE_SHARED std::make_shared
#endif
template<typename T, typename... Args>
static inline AuSPtr<T> AuMakeShared(Args... args)
{
return AURORA_RUNTIME_MAKE_SHARED<T>(args...);
}
#if !defined(AURORA_RUNTIME_MAKE_PAIR)
#define AURORA_RUNTIME_MAKE_PAIR std::make_pair
#endif
template<typename... Args>
static inline auto AuMakePair(Args... args)
{
return AURORA_RUNTIME_MAKE_PAIR(args...);
}
#if defined(AURORA_PLATFORM_WIN32)
static inline void AuWin32CloseHandle(HANDLE &handle)
{
HANDLE local;
if ((local = std::exchange(handle, INVALID_HANDLE_VALUE)) != INVALID_HANDLE_VALUE)
{
CloseHandle(local);
}
}
#endif
template<typename T>
static AuSPtr<T> AuUnsafeRaiiToShared(T *in)
{
return AuSPtr<T>(in, [](T *){});
}
template<typename T, int Z>
static constexpr int ArraySize(const T(&array)[Z])
static constexpr int AuArraySize(const T(&array)[Z])
{
return Z;
}
#if defined(DEBUG) || defined(INTERNAL)
#if defined(DEBUG) || defined(STAGING)
template<typename Z, typename T>
static void inline SafeDelete(T *in)
{
static_assert(std::is_base_of<T, std::remove_pointer<Z>::type>::value);
static_assert(std::is_base_of<T, std::remove_pointer<Z>::type>::value, "Couldn't not safe delete from type T because it is not derived from Z");
auto cast = dynamic_cast<Z>(in);
if (cast == nullptr)
{
@ -33,49 +71,102 @@ static void inline SafeDelete(T *in)
template<typename Z, typename T>
static void inline SafeDelete(T *in)
{
static_assert(std::is_base_of<T, std::remove_pointer<Z>::type>::value);
static_assert(std::is_base_of<T, std::remove_pointer<Z>::type>::value, "Couldn't not safe delete from type T because it is not derived from Z");
delete static_cast<Z>(in);
}
#endif
static inline AuUInt64 ConvertMagicTag64(const char buffer[8])
static constexpr inline AuUInt32 AuConvertMagicTag32(const char buffer[4])
{
return *reinterpret_cast<const AuUInt64 *>(buffer);
AuUInt32 magic {};
if (Aurora::Build::kCurrentEndian == Aurora::Build::ECPUEndian::eCPULittle)
{
magic |= AuUInt32(buffer[0]);
magic |= AuUInt32(buffer[1]) << 8;
magic |= AuUInt32(buffer[2]) << 16;
magic |= AuUInt32(buffer[3]) << 24;
// LE will look alright in memory dumps
// MSFT uses tags that read back the initial string value when read back hex ints
// I prefer binary streams and file headers contain a 4x or 8x ascii char headers (eg. LuaX)
}
else
{
// Lazy reinterpret cast reads will always be flipped
// Assume byte buffers read/write machine endian
// Assume *reinterpret_cast<T*> returns machine endian
// BE needs to be flipped in memory
// BE will look fine in memory dumps
// BE will also look fine in stack/variable dumps when printed in hex
magic |= AuUInt32(buffer[4]);
magic |= AuUInt32(buffer[2]) << 8;
magic |= AuUInt32(buffer[1]) << 16;
magic |= AuUInt32(buffer[0]) << 24;
}
// Determinstic across platforms, perhaps unexpected by endian normalized streams
// When asserting read(noEndian) against a tag, an endian swap would cause the
// assertion to fail, thus providing you with the endian match check
// This step is delegated to a de-facto machine endian buffer builder
// ByteBuffers that normalize for endianness continue to work with tags
// irrespective of reader/writer endianness
return magic;
}
static inline AuUInt32 ConvertMagicTag32(const char buffer[4])
static constexpr inline AuUInt64 AuConvertMagicTag64(const char buffer[8])
{
return *reinterpret_cast<const AuUInt32 *>(buffer);
AuUInt64 magic {};
if (Aurora::Build::kCurrentEndian == Aurora::Build::ECPUEndian::eCPULittle)
{
magic |= AuUInt64(buffer[0]);
magic |= AuUInt64(buffer[1]) << 8;
magic |= AuUInt64(buffer[2]) << 16;
magic |= AuUInt64(buffer[3]) << 24;
magic |= AuUInt64(buffer[4]) << 32;
magic |= AuUInt64(buffer[5]) << 40;
magic |= AuUInt64(buffer[6]) << 48;
magic |= AuUInt64(buffer[7]) << 56;
}
else
{
magic |= AuUInt64(buffer[7]);
magic |= AuUInt64(buffer[6]) << 8;
magic |= AuUInt64(buffer[5]) << 16;
magic |= AuUInt64(buffer[4]) << 24;
magic |= AuUInt64(buffer[3]) << 32;
magic |= AuUInt64(buffer[2]) << 40;
magic |= AuUInt64(buffer[1]) << 48;
magic |= AuUInt64(buffer[0]) << 56;
}
return magic;
}
template<typename T, typename Z>
static inline std::optional<AuSPtr<T>> OptionalSharedDynamicCast(std::optional<AuSPtr<Z>> &in)
static inline AuOptional<AuSPtr<T>> AuOptionalSharedDynamicCast(AuOptional<AuSPtr<Z>> &in)
{
if (!in.has_value()) return {};
return std::dynamic_pointer_cast<T>(in.value());
}
template<typename T, typename Z>
static inline std::optional<AuSPtr<T>> OptionalSharedStaticCast(std::optional<AuSPtr<Z>> &in)
static inline AuOptional<AuSPtr<T>> AuOptionalSharedStaticCast(AuOptional<AuSPtr<Z>> &in)
{
if (!in.has_value()) return {};
return std::static_pointer_cast<T>(in.value());
}
static inline bool EndsWith(std::string const &value, std::string const &ending)
static inline bool AuEndsWith(std::string const &value, std::string const &ending)
{
if (ending.size() > value.size()) return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
static inline bool StartsWith(std::string const &value, std::string const &starting)
static inline bool AuStartsWith(std::string const &value, std::string const &starting)
{
return value.rfind(starting, 0) == 0;
}
template<typename T>
static inline AuString ToStringASCIIOp(T op, const AuString &in)
static inline AuString AuToStringASCIIOp(T op, const AuString &in)
{
AuString ret;
ret.resize(in.size());
@ -86,18 +177,18 @@ static inline AuString ToStringASCIIOp(T op, const AuString &in)
return ret;
}
static inline AuString ToLower(const AuString &in)
static inline AuString AuToLower(const AuString &in)
{
return ToStringASCIIOp<int(*)(int)>(std::tolower, in);
return AuToStringASCIIOp<int(*)(int)>(std::tolower, in);
}
static inline AuString ToUpper(const AuString &in)
static inline AuString AuToUpper(const AuString &in)
{
return ToStringASCIIOp<int(*)(int)>(std::toupper, in);
return AuToStringASCIIOp<int(*)(int)>(std::toupper, in);
}
template<typename Map, class Key, typename Value>
static inline bool TryFind(Map &map, const Key &key, Value *&ptr)
static inline bool AuTryFind(Map &map, const Key &key, Value *&ptr)
{
auto itr = map.find(key);
if (itr != map.end())
@ -113,7 +204,7 @@ static inline bool TryFind(Map &map, const Key &key, Value *&ptr)
}
template<typename Map, class Key, typename Value>
static inline bool TryFind(Map *map, const Key &key, Value *&ptr)
static inline bool AuTryFind(Map *map, const Key &key, Value *&ptr)
{
auto itr = map->find(key);
if (itr != map->end())
@ -129,7 +220,7 @@ static inline bool TryFind(Map *map, const Key &key, Value *&ptr)
}
template<typename Map, class Key>
static inline bool TryFind(Map &map, const Key &key)
static inline bool AuTryFind(Map &map, const Key &key)
{
auto itr = map.find(key);
if (itr != map.end())
@ -143,7 +234,7 @@ static inline bool TryFind(Map &map, const Key &key)
}
template<typename Map, class Key>
static inline bool TryFind(Map *map, const Key &key)
static inline bool AuTryFind(Map *map, const Key &key)
{
auto itr = map->find(key);
if (itr != map->end())
@ -155,8 +246,9 @@ static inline bool TryFind(Map *map, const Key &key)
return false;
}
}
template<typename Map, class Key, typename Value>
static inline bool TryFindGeneric(Map &map, const Key &key, Value *&ptr)
static inline bool AuTryFindGeneric(Map &map, const Key &key, Value *&ptr)
{
auto itr = map.find(key);
if (itr != map.end())
@ -172,7 +264,7 @@ static inline bool TryFindGeneric(Map &map, const Key &key, Value *&ptr)
}
template<typename Map, class Key>
static inline bool TryDelete(Map &map, const Key &key)
static inline bool AuTryDelete(Map &map, const Key &key)
{
auto itr = map.find(key);
if (itr != map.end())
@ -187,7 +279,7 @@ static inline bool TryDelete(Map &map, const Key &key)
}
template<typename List, class Key>
static inline bool TryDeleteList(List &list, const Key &key)
static inline bool AuTryDeleteList(List &list, const Key &key)
{
auto itr = std::find(list.begin(), list.end(), key);
if (itr != list.end())
@ -202,7 +294,7 @@ static inline bool TryDeleteList(List &list, const Key &key)
}
template<typename Container, typename Type>
static inline bool TryInsert(Container &container, const Type &value)
static inline bool AuTryInsert(Container &container, const Type &value)
{
try
{
@ -216,7 +308,7 @@ static inline bool TryInsert(Container &container, const Type &value)
}
}
template<typename Container, typename Type>
static inline bool TryInsert(Container &container, Type &&value)
static inline bool AuTryInsert(Container &container, Type &&value)
{
try
{
@ -231,7 +323,7 @@ static inline bool TryInsert(Container &container, Type &&value)
}
template<typename Container, typename Type>
static inline bool TryInsert(Container *container, const Type &value)
static inline bool AuTryInsert(Container *container, const Type &value)
{
try
{
@ -246,7 +338,7 @@ static inline bool TryInsert(Container *container, const Type &value)
}
template<typename Container, typename Type>
static inline bool TryInsert(Container *container, Type &&value)
static inline bool AuTryInsert(Container *container, Type &&value)
{
try
{
@ -261,7 +353,7 @@ static inline bool TryInsert(Container *container, Type &&value)
}
template<typename Container, typename Type>
static inline bool TryInsertNoEnd(Container &container, Type &&value) // move
static inline bool AuTryInsertNoEnd(Container &container, Type &&value) // move
{
try
{
@ -276,7 +368,7 @@ static inline bool TryInsertNoEnd(Container &container, Type &&value) // move
}
template<typename Container, typename Type>
static inline bool TryInsertNoEnd(Container &container, const Type &value) // copy
static inline bool AuTryInsertNoEnd(Container &container, const Type &value) // copy
{
try
{
@ -291,7 +383,7 @@ static inline bool TryInsertNoEnd(Container &container, const Type &value) // co
}
template<typename Container, typename Type>
static inline bool TryInsertNoEnd(Container *container, Type &&value) // move
static inline bool AuTryInsertNoEnd(Container *container, Type &&value) // move
{
try
{
@ -305,9 +397,8 @@ static inline bool TryInsertNoEnd(Container *container, Type &&value) // move
}
}
template<typename Container, typename Type>
static inline bool TryInsertNoEnd(Container *container, const Type &value) // copy
static inline bool AuTryInsertNoEnd(Container *container, const Type &value) // copy
{
try
{
@ -322,7 +413,7 @@ static inline bool TryInsertNoEnd(Container *container, const Type &value) // co
}
template<typename T>
static inline bool TryResize(T &list, AuUInt length)
static inline bool AuTryResize(T &list, AuUInt length)
{
try
{
@ -335,7 +426,7 @@ static inline bool TryResize(T &list, AuUInt length)
}
}
static inline std::string ReplaceAll(std::string &str, const std::string &from, const std::string &to)
static inline std::string AuReplaceAll(std::string &str, const std::string &from, const std::string &to)
{
size_t start_pos = 0;
while ((start_pos = str.find(from, start_pos)) != std::string::npos)
@ -347,7 +438,7 @@ static inline std::string ReplaceAll(std::string &str, const std::string &from,
}
// i told myself not to copy this, required a split function twice, now here we are :D
static inline AuList<AuString> SplitString(const AuString& str, const AuString& delim, bool ignoreEmpty = true)
static inline AuList<AuString> AuSplitString(const AuString& str, const AuString& delim, bool ignoreEmpty = true)
{
AuList<AuString> tokens;
AuUInt prev = 0, pos = 0;
@ -365,8 +456,8 @@ static inline AuList<AuString> SplitString(const AuString& str, const AuString&
// more copy/pasta. work smart, not hard.
// i dont want to waste time working out template kinks between clang and msvc
template < template <typename...> class base,typename derived>
struct is_base_of_template_impl
template<template<typename...> class base,typename derived>
struct is_base_of_template_impl_au
{
template<typename... Ts>
static constexpr std::true_type test(const base<Ts...> *);
@ -375,4 +466,4 @@ struct is_base_of_template_impl
};
template < template <typename...> class base,typename derived>
using is_base_of_template = typename is_base_of_template_impl<base,derived>::type;
using AuIsBaseOfTemplate = typename is_base_of_template_impl_au<base,derived>::type;

View File

@ -28,12 +28,13 @@ namespace Aurora::Async
{
gAsyncApp.Shutdown();
}
}
//STATIC_TLS(WorkerId_t, tlsWorkerId);
static Threading::Threads::TLSVariable<WorkerId_t, true> tlsWorkerId;
using WorkEntry_t = std::pair<std::optional<ThreadId_t>, AuSPtr<IAsyncRunnable>>;
using WorkEntry_t = AuPair<AuOptional<ThreadId_t>, AuSPtr<IAsyncRunnable>>;
struct ThreadState
{
@ -111,7 +112,7 @@ namespace Aurora::Async
auto & semaphore = GetThreadState()->syncSema;
auto unsafeSemaphore = semaphore.get();
auto work = std::make_shared</*Async::BasicWorkStdFunc*/AsyncFuncRunnable>(([=]()
auto work = AuMakeShared</*Async::BasicWorkStdFunc*/AsyncFuncRunnable>(([=]()
{
auto state = GetThreadState();
@ -150,10 +151,10 @@ namespace Aurora::Async
IncRunningTasks();
{
Threading::LockGuardPtr lol(state->cvWorkMutex);
AU_LOCK_GUARD(state->cvWorkMutex);
#if defined(INTERNAL) || defined(DEBUG)
Threading::LockGuardPtr lock(rwlock_->AsReadable());
#if defined(STAGING) || defined(DEBUG)
AU_LOCK_GUARD(rwlock_->AsReadable());
if (target.second.has_value())
{
@ -187,18 +188,18 @@ namespace Aurora::Async
}
#endif
state->workQueue.push_back(std::make_pair(target.second, runnable));
state->workQueue.push_back(AuMakePair(target.second, runnable));
}
if (target.second.has_value())
{
// sad :(
state->cvVariable->Broadcast();
}
else
{
state->cvVariable->Signal();
}
if (target.second.has_value())
{
// sad :(
state->cvVariable->Broadcast();
}
else
{
state->cvVariable->Signal();
}
}
bool AsyncApp::Poll(bool blocking)
@ -206,10 +207,10 @@ namespace Aurora::Async
auto state = GetThreadState();
auto group = state->parent.lock();
state->pendingWorkItems.clear();
//state->pendingWorkItems.clear();
{
Threading::LockGuardPtr lol(group->cvWorkMutex);
AU_LOCK_GUARD(group->cvWorkMutex);
do
{
@ -293,16 +294,17 @@ namespace Aurora::Async
itr = state->pendingWorkItems.erase(itr);
// Atomically decrement global task counter
runningTasks = --gRunningTasks;
runningTasks = gRunningTasks.fetch_sub(1) - 1;
}
// Return popped work back to the groups work pool when our -pump loops were preempted
if (state->pendingWorkItems.size())
{
Threading::LockGuardPtr lol(group->cvWorkMutex);
AU_LOCK_GUARD(group->cvWorkMutex);
group->workQueue.insert(group->workQueue.end(), state->pendingWorkItems.begin(), state->pendingWorkItems.end());
state->pendingWorkItems.clear();
}
if (runningTasks == 0)
{
ShutdownZero();
@ -383,7 +385,7 @@ namespace Aurora::Async
{
// Nested shutdowns can happen a write lock
{
Threading::LockGuardPtr lock(rwlock_->AsReadable());
AU_LOCK_GUARD(rwlock_->AsReadable());
if (shuttingdown_)
{
return;
@ -392,7 +394,7 @@ namespace Aurora::Async
// Set shutdown flag
{
Threading::LockGuardPtr lock(rwlock_->AsWritable());
AU_LOCK_GUARD(rwlock_->AsWritable());
if (std::exchange(shuttingdown_, true))
{
return;
@ -406,7 +408,7 @@ namespace Aurora::Async
//
// Perform the following shutdown of the schedular and other available threads under a read lock
{
Threading::LockGuardPtr lock(rwlock_->AsReadable());
AU_LOCK_GUARD(rwlock_->AsReadable());
StopSched();
@ -424,7 +426,7 @@ namespace Aurora::Async
// then release all group contexts
AuList<Threading::Threads::ThreadShared_t> threads;
{
Threading::LockGuardPtr lock(rwlock_->AsWritable());
AU_LOCK_GUARD(rwlock_->AsWritable());
for (auto &[groupId, group] : this->threads_)
{
@ -447,7 +449,7 @@ namespace Aurora::Async
if (group->cvVariable)
{
Threading::LockGuardPtr lol(group->cvWorkMutex);
AU_LOCK_GUARD(group->cvWorkMutex);
group->cvVariable->Broadcast();
}
}
@ -467,16 +469,16 @@ namespace Aurora::Async
bool AsyncApp::Spawn(WorkerId_t workerId)
{
Threading::LockGuardPtr lock(rwlock_->AsWritable());
AU_LOCK_GUARD(rwlock_->AsWritable());
AuSPtr<GroupState> group;
// Try fetch or allocate group
{
AuSPtr<GroupState>* groupPtr;
if (!TryFind(this->threads_, workerId.first, groupPtr))
if (!AuTryFind(this->threads_, workerId.first, groupPtr))
{
group = std::make_shared<GroupState>();
group = AuMakeShared<GroupState>();
if (!group->Init())
{
@ -484,7 +486,7 @@ namespace Aurora::Async
return false;
}
if (!TryInsert(this->threads_, std::make_pair(workerId.first, group)))
if (!AuTryInsert(this->threads_, AuMakePair(workerId.first, group)))
{
return false;
}
@ -499,14 +501,14 @@ namespace Aurora::Async
{
AuSPtr<ThreadState>* ret;
if (TryFind(group->workers, workerId.second, ret))
if (AuTryFind(group->workers, workerId.second, ret))
{
SysPushErrorGen("Thread ID already exists");
return false;
}
}
auto threadState = std::make_shared<ThreadState>();
auto threadState = AuMakeShared<ThreadState>();
threadState->parent = group;
threadState->running = Threading::Primitives::EventUnique(true, false, true);
threadState->syncSema = Threading::Primitives::SemaphoreUnique(0);
@ -524,10 +526,10 @@ namespace Aurora::Async
}
else
{
threadState->threadObject = std::shared_ptr<Threading::Threads::IAuroraThread>(Threading::Threads::GetThread(), [](Threading::Threads::IAuroraThread *){});
threadState->threadObject = AuSPtr<Threading::Threads::IAuroraThread>(Threading::Threads::GetThread(), [](Threading::Threads::IAuroraThread *){});
}
group->workers.insert(std::make_pair(workerId.second, threadState));
group->workers.insert(AuMakePair(workerId.second, threadState));
return true;
}
@ -540,7 +542,7 @@ namespace Aurora::Async
}
AuSPtr<ThreadState>* ret;
if (!TryFind(group->workers, id.second, ret))
if (!AuTryFind(group->workers, id.second, ret))
{
return {};
}
@ -550,7 +552,7 @@ namespace Aurora::Async
AuBST<ThreadGroup_t, AuList<ThreadId_t>> AsyncApp::GetThreads()
{
Threading::LockGuardPtr lock(rwlock_->AsReadable());
AU_LOCK_GUARD(rwlock_->AsReadable());
AuBST<ThreadGroup_t, AuList<ThreadId_t>> ret;
@ -576,7 +578,7 @@ namespace Aurora::Async
bool AsyncApp::Sync(ThreadGroup_t groupId, bool requireSignal, AuUInt32 timeoutMs)
{
Threading::LockGuardPtr lock(rwlock_->AsReadable());
AU_LOCK_GUARD(rwlock_->AsReadable());
auto group = GetGroup(groupId);
for (auto &jobWorker : group->workers)
@ -592,7 +594,7 @@ namespace Aurora::Async
void AsyncApp::Signal(ThreadGroup_t groupId)
{
Threading::LockGuardPtr lock(rwlock_->AsReadable());
AU_LOCK_GUARD(rwlock_->AsReadable());
auto group = GetGroup(groupId);
@ -609,7 +611,7 @@ namespace Aurora::Async
void AsyncApp::SyncAllSafe()
{
Threading::LockGuardPtr lock(rwlock_->AsReadable());
AU_LOCK_GUARD(rwlock_->AsReadable());
for (const auto &re : this->threads_)
{
@ -622,10 +624,10 @@ namespace Aurora::Async
AuSPtr<GroupState> AsyncApp::GetGroup(ThreadGroup_t type)
{
Threading::LockGuardPtr lock(rwlock_->AsReadable());
AU_LOCK_GUARD(rwlock_->AsReadable());
AuSPtr<GroupState>* ret;
if (!TryFind(this->threads_, type, ret))
if (!AuTryFind(this->threads_, type, ret))
{
return {};
}
@ -635,13 +637,13 @@ namespace Aurora::Async
size_t AsyncApp::GetThreadWorkersCount(ThreadGroup_t group)
{
Threading::LockGuardPtr lock(rwlock_->AsReadable());
AU_LOCK_GUARD(rwlock_->AsReadable());
return GetGroup(group)->workers.size();
}
AuSPtr<ThreadState> AsyncApp::GetThreadState()
{
Threading::LockGuardPtr lock(rwlock_->AsReadable());
AU_LOCK_GUARD(rwlock_->AsReadable());
auto id = GetCurrentThread();
auto state = GetGroup(id.first);
return state->workers[id.second];
@ -662,7 +664,7 @@ namespace Aurora::Async
if (id != WorkerId_t {0, 0})
{
Threading::LockGuardPtr lock(rwlock_->AsReadable());
AU_LOCK_GUARD(rwlock_->AsReadable());
if (!shuttingdown_ && !job->rejecting)
{
@ -691,7 +693,7 @@ namespace Aurora::Async
auto state = GetGroup(id.first);
{
Threading::LockGuardPtr lock(rwlock_->AsWritable());
AU_LOCK_GUARD(rwlock_->AsWritable());
auto itr = state->workers.find(id.second);
auto &jobWorker = itr->second;
@ -732,7 +734,7 @@ namespace Aurora::Async
void AsyncApp::AddFeature(WorkerId_t id, AuSPtr<Threading::Threads::IThreadFeature> feature, bool async)
{
auto work = std::make_shared<BasicWorkStdFunc>(([=]()
auto work = AuMakeShared<BasicWorkStdFunc>(([=]()
{
GetThreadState()->features.push_back(feature);
feature->Init();

View File

@ -78,6 +78,6 @@ namespace Aurora::Async
ThreadDb_t threads_;
bool shuttingdown_ {};
std::optional<WorkerId_t> commandDispatcher_;
AuOptional<WorkerId_t> commandDispatcher_;
};
}

View File

@ -25,7 +25,7 @@ namespace Aurora::Async
static void GetDispatchableTasks(AuList<SchedEntry> &pending)
{
Threading::LockGuardPtr lock(gSchedLock.get());
AU_LOCK_GUARD(gSchedLock);
auto time = Time::CurrentClockNS();
@ -43,6 +43,13 @@ namespace Aurora::Async
}
}
static bool gLockedPump = false;
static void PumpSysThread()
{
RuntimeSysPump();
gLockedPump = false;
}
static void SchedThread()
{
@ -75,11 +82,14 @@ namespace Aurora::Async
}
counter++;
if ((gRuntimeConfig.async.schedularFrequency != 1) || ((gRuntimeConfig.async.sysPumpFrequency) && (counter % gRuntimeConfig.async.sysPumpFrequency) == 0))
if ((!gRuntimeConfig.async.sysPumpFrequency) || ((gRuntimeConfig.async.sysPumpFrequency) && (counter % gRuntimeConfig.async.sysPumpFrequency) == 0))
{
try
{
NewWorkItem({0, 0}, std::make_shared<BasicWorkStdFunc>(RuntimeSysPump))->Dispatch();
if (!std::exchange(gLockedPump, true))
{
NewWorkItem({0, 0}, AuMakeShared<BasicWorkStdFunc>(PumpSysThread))->Dispatch();
}
}
catch (...)
{
@ -120,14 +130,14 @@ namespace Aurora::Async
void Schedule(AuUInt64 ns, DispatchTarget_t target, AuSPtr<IAsyncRunnable> runnable)
{
Threading::LockGuardPtr lock(gSchedLock.get());
AU_LOCK_GUARD(gSchedLock);
IncRunningTasks();
gEntries.push_back({ns, target, runnable});
}
void TerminateSceduledTasks(DispatchTarget_t target)
{
Threading::LockGuardPtr lock(gSchedLock.get());
AU_LOCK_GUARD(gSchedLock);
for (auto itr = gEntries.begin(); itr != gEntries.end(); )
{

View File

@ -34,8 +34,8 @@ namespace Aurora::Async
{
auto dependency = std::reinterpret_pointer_cast<WorkItem>(workItem);
Threading::LockGuard<Threading::Primitives::SpinLock> l(lock);
Threading::LockGuard<Threading::Primitives::SpinLock> l2(dependency->lock);
AU_LOCK_GUARD(lock);
AU_LOCK_GUARD(dependency->lock);
if (dependency->HasFailed())
{
@ -60,12 +60,12 @@ namespace Aurora::Async
bool status {};
{
Threading::LockGuard<Threading::Primitives::SpinLock> l(lock);
AU_LOCK_GUARD(lock);
for (auto &workItem : workItems)
{
auto dependency = std::reinterpret_pointer_cast<WorkItem>(workItem);
Threading::LockGuard<Threading::Primitives::SpinLock> l2(dependency->lock);
AU_LOCK_GUARD(dependency->lock);
if (dependency->HasFailed())
{
@ -125,19 +125,15 @@ namespace Aurora::Async
void WorkItem::DispatchEx(bool check)
{
Threading::LockGuard<Threading::Primitives::SpinLock> l(lock);
AU_LOCK_GUARD(lock);
if (check)
{
if (!dispatchPending_)
if (dispatchPending_)
{
return;
}
}
else
{
dispatchPending_ = true;
}
if (HasFailed())
{
@ -156,6 +152,8 @@ namespace Aurora::Async
itr = waitOn_.erase(itr);
}
dispatchPending_ = true;
if (Time::CurrentClockNS() < dispatchTimeNs_)
{
Schedule();
@ -164,7 +162,7 @@ namespace Aurora::Async
if (auto delay = std::exchange(delayTimeNs_, {}))
{
dispatchTimeNs_ = delay;
dispatchTimeNs_ = delay + Time::CurrentClockNS();
Schedule();
return;
}
@ -174,16 +172,20 @@ namespace Aurora::Async
void WorkItem::CancelAsync()
{
Threading::LockGuard<Threading::Primitives::SpinLock> l(lock);
AU_LOCK_GUARD(lock);
Fail();
}
void WorkItem::RunAsync()
{
Threading::LockGuard<Threading::Primitives::SpinLock> l(lock);
AU_LOCK_GUARD(lock);
IWorkItemHandler::ProcessInfo info(true);
task_->DispatchFrame(info);
if (task_)
{
task_->DispatchFrame(info);
}
switch (info.type)
{
@ -223,16 +225,16 @@ namespace Aurora::Async
}
}
for (auto &waiter : waiters_)
{
std::reinterpret_pointer_cast<WorkItem>(waiter)->DispatchEx(true);
}
finished = true;
if (finishedEvent_)
{
finishedEvent_->Set();
}
for (auto &waiter : waiters_)
{
std::reinterpret_pointer_cast<WorkItem>(waiter)->DispatchEx(true);
}
}
void WorkItem::Fail()
@ -286,6 +288,6 @@ namespace Aurora::Async
AUKN_SYM AuSPtr<IWorkItem> NewWorkItem(const DispatchTarget_t &worker, const AuSPtr<IWorkItemHandler> &task, bool supportsBlocking)
{
return std::make_shared<WorkItem>(worker, task, supportsBlocking);
return AuMakeShared<WorkItem>(worker, task, supportsBlocking);
}
}

View File

@ -16,7 +16,8 @@
namespace Aurora::Compression
{
std::pair<AuUInt32, AuUInt32> BaseStreamDeflate::Ingest(AuUInt32 input)
#if 0
AuStreamReadWrittenPair_t BaseStreamDeflate::Ingest(AuUInt32 input)
{
auto ingest = IngestImpl(input);
_count += ingest.first;
@ -58,4 +59,5 @@ namespace Aurora::Compression
{
SafeDelete<BaseStreamDeflate *>(stream);
}
#endif
}

View File

@ -9,22 +9,24 @@
namespace Aurora::Compression
{
#if 0
class BaseStreamDeflate : public ICompressionStream
{
public:
virtual ~BaseStreamDeflate() { }
virtual std::pair<AuUInt32, AuUInt32> IngestImpl(AuUInt32 input);
virtual AuStreamReadWrittenPair_t IngestImpl(AuUInt32 input);
virtual void Flush() = 0;
virtual bool Init(Aurora::IO::IStreamReader *reader, const CompressionInfo &info) = 0;
bool Read(void * /*opt*/ buffer, AuUInt32 &len, bool ingestUntilError) override;
std::pair<AuUInt32, AuUInt32> Ingest(AuUInt32 input) override;
AuStreamReadWrittenPair_t Ingest(AuUInt32 input) override;
protected:
AuUInt32 _count {};
AuUInt32 _lastCount {};
AuList<AuUInt8> _outbuffer;
};
#endif
}

View File

@ -16,29 +16,51 @@
namespace Aurora::Compression
{
bool BaseStream::Read(void * /*opt*/ buffer, AuUInt32 &len, bool ingestUntilError)
bool BaseStream::ReadByInflatedN(void * buffer, AuUInt32 minimumInflated, AuStreamReadWrittenPair_t &pair, bool ingestUntilEOS)
{
if (ingestUntilError)
AuUInt32 read {}, len {};
if (ingestUntilEOS)
{
while (this->_outbuffer.size() < len)
while (this->_outbuffer.RemainingBytes() < minimumInflated)
{
if (Ingest(4096).second == 0)
{
if (this->_outbuffer.size())
if (!this->_outbuffer.RemainingBytes())
{
break;
return false;
}
return false;
break;
}
read += 4096;
}
}
return StreamRead(buffer, len, this->_outbuffer);
len = this->_outbuffer.Read(buffer, len, buffer == nullptr);
pair = {read, len};
return len != 0;
}
bool BaseStream::GoBackByInflatedN(AuUInt32 offset)
{
return this->_outbuffer.ReaderTryGoBack(offset);
}
bool BaseStream::GoForwardByInflatedN(AuUInt32 offset)
{
return this->_outbuffer.ReaderTryGoForward(offset);
}
class ZSTDInflate : public BaseStream
{
public:
ZSTDInflate() : BaseStream()
{
}
~ZSTDInflate()
{
if (auto dctx = std::exchange(dctx_, {}))
@ -58,12 +80,10 @@ namespace Aurora::Compression
return false;
}
this->_outbuffer.reserve(10 * 1024);
return true;
}
std::pair<AuUInt32, AuUInt32> Ingest(AuUInt32 input) override
AuStreamReadWrittenPair_t Ingest(AuUInt32 input) override
{
AuUInt32 length = ZSTD_DStreamInSize();
void *din = alloca(length);
@ -76,7 +96,7 @@ namespace Aurora::Compression
AuUInt32 request = std::min(input, length);
if (this->reader_->Read(din, request) != IO::EStreamError::eErrorNone)
{
return std::make_pair(read, done);
return AuMakePair(read, done);
}
read += request;
@ -89,17 +109,16 @@ namespace Aurora::Compression
if (ZSTD_isError(ret))
{
SysPushErrorIO("Compression error: {}", ret);
return std::make_pair(read, 0);
return AuMakePair(read, 0);
}
done += output.pos;
this->_outbuffer.insert(this->_outbuffer.end(),
reinterpret_cast<const AuUInt8 *>(output.dst),
reinterpret_cast<const AuUInt8 *>(output.dst) + output.pos);
this->_outbuffer.Write(reinterpret_cast<const AuUInt8 *>(output.dst),
output.pos);
}
}
return std::make_pair(read, done);
return AuMakePair(read, done);
}
private:
@ -130,23 +149,22 @@ namespace Aurora::Compression
return false;
}
this->_outbuffer.reserve(10 * 1024);
this->init_ = true;
return true;
}
std::pair<AuUInt32, AuUInt32> Ingest(AuUInt32 input) override
AuStreamReadWrittenPair_t Ingest(AuUInt32 input) override
{
int ret;
AuUInt32 done{}, read{};
while (read != input)
while (read < input)
{
AuUInt32 request = std::min(input, AuUInt32(ArraySize(din_)));
AuUInt32 request = std::min(input, AuUInt32(AuArraySize(din_)));
if (this->reader_->Read(din_, request) != IO::EStreamError::eErrorNone)
{
return std::make_pair(read, done);
return AuMakePair(read, done);
}
read += request;
@ -156,7 +174,7 @@ namespace Aurora::Compression
do
{
this->ctx_.avail_out = ArraySize(dout_);
this->ctx_.avail_out = AuArraySize(dout_);
this->ctx_.next_out = dout_;
if (!this->ctx_.avail_out)
@ -168,21 +186,20 @@ namespace Aurora::Compression
if (ret != Z_OK)
{
SysPushErrorIO("Error: {}", ret);
return std::make_pair(read, 0);
return AuMakePair(read, 0);
}
auto have = ArraySize(dout_) - this->ctx_.avail_out;
auto have = AuArraySize(dout_) - this->ctx_.avail_out;
done += have;
this->_outbuffer.insert(this->_outbuffer.end(),
reinterpret_cast<const AuUInt8 *>(dout_),
reinterpret_cast<const AuUInt8 *>(dout_) + have);
this->_outbuffer.Write(reinterpret_cast<const AuUInt8 *>(dout_),
have);
} while (this->ctx_.avail_out == 0);
SysAssert(this->ctx_.avail_in == 0);
}
return std::make_pair(read, done);
return AuMakePair(read, done);
}
private:
@ -216,22 +233,21 @@ namespace Aurora::Compression
return false;
}
this->_outbuffer.reserve(10 * 1024);
this->init_ = true;
return true;
}
std::pair<AuUInt32, AuUInt32> Ingest(AuUInt32 input) override
AuStreamReadWrittenPair_t Ingest(AuUInt32 input) override
{
int ret;
AuUInt32 done{}, read{};
while (read != input)
while (read < input)
{
AuUInt32 request = std::min(input, AuUInt32(ArraySize(din_)));
AuUInt32 request = std::min(input, AuUInt32(AuArraySize(din_)));
if (this->reader_->Read(din_, request) != IO::EStreamError::eErrorNone)
{
return std::make_pair(read, done);
return AuMakePair(read, done);
}
read += request;
@ -240,29 +256,28 @@ namespace Aurora::Compression
do
{
this->ctx_.avail_out = ArraySize(dout_);
this->ctx_.avail_out = AuArraySize(dout_);
this->ctx_.next_out = dout_;
ret = BZ2_bzDecompress(&this->ctx_);
if (ret != Z_OK)
{
SysPushErrorIO("Error: {}", ret);
return std::make_pair(read, 0);
return AuMakePair(read, 0);
}
auto have = ArraySize(dout_) - this->ctx_.avail_out;
auto have = AuArraySize(dout_) - this->ctx_.avail_out;
done += have;
this->_outbuffer.insert(this->_outbuffer.end(),
reinterpret_cast<const AuUInt8 *>(dout_),
reinterpret_cast<const AuUInt8 *>(dout_) + have);
this->_outbuffer.Write(reinterpret_cast<const AuUInt8 *>(dout_),
have);
} while (this->ctx_.avail_out == 0);
SysAssert(this->ctx_.avail_in == 0);
}
return std::make_pair(read, done);
return AuMakePair(read, done);
}
private:
@ -277,12 +292,12 @@ namespace Aurora::Compression
class LZ4Inflate : public BaseStream
{
public:
LZ4Inflate() : BaseStream(64 * 1024 * 2)
{}
~LZ4Inflate()
{
if (auto ctx = std::exchange(this->lz4Stream_, {}))
{
LZ4_freeStreamDecode(this->lz4Stream_);
}
}
bool Init(Aurora::IO::IStreamReader *reader)
@ -296,61 +311,13 @@ namespace Aurora::Compression
return false;
}
this->_outbuffer.reserve(10 * 1024);
return true;
}
std::pair<AuUInt32, AuUInt32> Ingest(AuUInt32 input) override
AuStreamReadWrittenPair_t Ingest(AuUInt32 input) override
{
AuUInt32 done {}, read {}, lastFrameSize {};
std::shared_ptr<char> inFrame;
std::shared_ptr<char> outFrames[2];
bool outFrame {};
while (read != input)
{
AuUInt32 frameSize;
AuUInt32 request = sizeof(frameSize);
if (this->reader_->Read(&frameSize, request) != IO::EStreamError::eErrorNone)
{
return std::make_pair(read, done);
}
read += request;
if ((lastFrameSize < frameSize) || (!outFrames[outFrame]))
{
inFrame = std::shared_ptr<char>(new char[frameSize], std::default_delete<char[]>());
outFrames[outFrame] = std::shared_ptr<char>(new char[frameSize], std::default_delete<char[]>());
lastFrameSize = frameSize;
}
request = frameSize;
if (this->reader_->Read(inFrame.get(), request) != IO::EStreamError::eErrorNone)
{
return std::make_pair(read, done);
}
read += request;
auto outPtr = outFrames[outFrame].get();
auto bytes = LZ4_decompress_safe_continue(lz4Stream_, inFrame.get(), outPtr, frameSize, frameSize);
if (bytes <= 0)
{
return std::make_pair(read, 0);
}
done += bytes;
this->_outbuffer.insert(this->_outbuffer.end(),
reinterpret_cast<const AuUInt8 *>(outPtr),
reinterpret_cast<const AuUInt8 *>(outPtr) + bytes);
outFrames[!outFrame] = std::move(outFrames[outFrame]);
outFrame = !outFrame;
}
return std::make_pair(read, done);
return {};
}
private:

View File

@ -12,12 +12,18 @@ namespace Aurora::Compression
class BaseStream : public ICompressionStream
{
public:
virtual ~BaseStream() {}
BaseStream(int bufferSize = 4096 * 4) : _outbuffer(bufferSize, true) {}
virtual ~BaseStream() {}
virtual bool Init(Aurora::IO::IStreamReader *reader) = 0;
bool Read(void * /*opt*/ buffer, AuUInt32 &len, bool ingestUntilError) override;
virtual bool ReadByInflatedN(void * /*opt*/, AuUInt32 minimumInflated, AuStreamReadWrittenPair_t &pair, bool ingestUntilEOS = true) override;
virtual bool GoBackByInflatedN(AuUInt32 offset) override;
virtual bool GoForwardByInflatedN(AuUInt32 offset) override;
protected:
AuList<AuUInt8> _outbuffer;
Aurora::Memory::ByteBuffer _outbuffer;
};
}

View File

@ -14,7 +14,7 @@ namespace Aurora::Compression
{
AUKN_SYM bool Compress(const void *buffer, AuUInt32 length, AuList<AuUInt8> &out, int compressionLevel )
{
if (!TryResize(out, length))
if (!AuTryResize(out, length))
{
return false;
}
@ -36,35 +36,47 @@ namespace Aurora::Compression
AUKN_SYM bool Decompress(const void *buffer, AuUInt32 length, AuList<AuUInt8> &out)
{
auto inflatedLength = ZSTD_getFrameContentSize(buffer, length);
AuUInt32 read = 0;
if (inflatedLength == ZSTD_CONTENTSIZE_ERROR)
while (read != length)
{
return false;
auto startPtr = reinterpret_cast<const AuUInt8 *>(buffer) + read;
auto deflatedLength = ZSTD_findFrameCompressedSize(startPtr, length - read);
auto inflatedLength = ZSTD_getFrameContentSize(startPtr, length - read);
if (inflatedLength == ZSTD_CONTENTSIZE_ERROR)
{
return false;
}
if (inflatedLength == ZSTD_CONTENTSIZE_UNKNOWN)
{
return false;
}
if (ZSTD_isError(inflatedLength))
{
return false;
}
auto startingSize = out.size();
if (!AuTryResize(out, inflatedLength))
{
return false;
}
auto ret = ZSTD_decompress(&out[0], out.size(), buffer, length);
if (ZSTD_isError(ret))
{
return false;
}
out.resize(startingSize + ret);
read += deflatedLength;
}
if (inflatedLength == ZSTD_CONTENTSIZE_UNKNOWN)
{
return false;
}
if (ZSTD_isError(inflatedLength))
{
return false;
}
if (!TryResize(out, inflatedLength))
{
return false;
}
auto ret = ZSTD_decompress(&out[0], out.size(), buffer, length);
if (ZSTD_isError(ret))
{
return false;
}
out.resize(ret);
return true;
}

View File

@ -10,17 +10,4 @@
namespace Aurora::Compression
{
static const AuUInt64 kChunkSize = 4096;
// This is acommon prolog required by BlockCompressors and BlockDecompressors. dw about it.
static inline bool StreamRead(void * buffer, AuUInt32 &len, AuList<AuUInt8> &vec)
{
len = std::min(AuUInt32(vec.size()), len);
if (len == 0) return false;
if (!buffer) return true;
std::memcpy(buffer, vec.data(), len);
auto rem = vec.size() - len;
std::memmove(vec.data(), vec.data() + len, rem);
vec.resize(rem);
return true;
}
}

View File

@ -13,6 +13,7 @@
#include "zstd.h"
#include "zlib.h"
#include "lz4.h"
#include "lz4frame.h"
namespace Aurora::Compression
{
@ -21,7 +22,7 @@ namespace Aurora::Compression
auto length = ZSTD_DStreamInSize();
AuList<AuUInt8> buffer;
auto ok = TryResize(buffer, length);
auto ok = AuTryResize(buffer, length);
if (!ok)
{
SysPushErrorMem("Couldn't reserve inflation buffers");
@ -30,7 +31,7 @@ namespace Aurora::Compression
auto outFrameLength = ZSTD_DStreamOutSize();
AuList<AuUInt8> inflatedBuffer;
ok = TryResize(inflatedBuffer, outFrameLength);
ok = AuTryResize(inflatedBuffer, outFrameLength);
if (!ok)
{
SysPushErrorMem("Couldn't reserve inflation buffers");
@ -83,7 +84,7 @@ namespace Aurora::Compression
const auto buffOutSize = ZSTD_CStreamOutSize();
AuList<AuUInt8> inflatedBuffer;
auto ok = TryResize(inflatedBuffer, buffInSize);
auto ok = AuTryResize(inflatedBuffer, buffInSize);
if (!ok)
{
SysPushErrorMem("Couldn't reserve deflation buffers");
@ -91,7 +92,7 @@ namespace Aurora::Compression
}
AuList<AuUInt8> deflatedBuffer;
ok = TryResize(deflatedBuffer, buffOutSize);
ok = AuTryResize(deflatedBuffer, buffOutSize);
if (!ok)
{
SysPushErrorMem("Couldn't reserve deflation buffers. Out of memory");
@ -209,7 +210,7 @@ namespace Aurora::Compression
do
{
auto read = stream.inPipe(in, ArraySize(in));
auto read = stream.inPipe(in, AuArraySize(in));
strm.avail_in = read;
inputStat += read;
@ -219,7 +220,7 @@ namespace Aurora::Compression
do
{
strm.avail_out = ArraySize(out);
strm.avail_out = AuArraySize(out);
strm.next_out = out;
ret = deflate(&strm, flush);
@ -229,7 +230,7 @@ namespace Aurora::Compression
return false;
}
auto have = ArraySize(out) - strm.avail_out;
auto have = AuArraySize(out) - strm.avail_out;
stream.writePipe(out, have);
@ -267,7 +268,7 @@ namespace Aurora::Compression
do
{
auto read = stream.inPipe(in, ArraySize(in));
auto read = stream.inPipe(in, AuArraySize(in));
inputStat += read;
if (!read)
{
@ -279,7 +280,7 @@ namespace Aurora::Compression
do
{
strm.avail_out = ArraySize(out);
strm.avail_out = AuArraySize(out);
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
@ -289,7 +290,7 @@ namespace Aurora::Compression
return false;
}
auto have = ArraySize(out) - strm.avail_out;
auto have = AuArraySize(out) - strm.avail_out;
stream.writePipe(out, have);
@ -327,7 +328,7 @@ namespace Aurora::Compression
do
{
auto read = stream.inPipe(in, ArraySize(in));
auto read = stream.inPipe(in, AuArraySize(in));
strm.avail_in = read;
inputStat += read;
@ -337,7 +338,7 @@ namespace Aurora::Compression
do
{
strm.avail_out = ArraySize(out);
strm.avail_out = AuArraySize(out);
strm.next_out = out;
ret = BZ2_bzCompress(&strm, flush);
@ -347,7 +348,7 @@ namespace Aurora::Compression
return false;
}
auto have = ArraySize(out) - strm.avail_out;
auto have = AuArraySize(out) - strm.avail_out;
stream.writePipe(out, have);
@ -385,7 +386,7 @@ namespace Aurora::Compression
do
{
auto read = stream.inPipe(in, ArraySize(in));
auto read = stream.inPipe(in, AuArraySize(in));
inputStat += read;
if (!read)
{
@ -397,7 +398,7 @@ namespace Aurora::Compression
do
{
strm.avail_out = ArraySize(out);
strm.avail_out = AuArraySize(out);
strm.next_out = out;
ret = BZ2_bzDecompress(&strm);
@ -407,7 +408,7 @@ namespace Aurora::Compression
return false;
}
auto have = ArraySize(out) - strm.avail_out;
auto have = AuArraySize(out) - strm.avail_out;
stream.writePipe(out, have);
@ -429,27 +430,39 @@ namespace Aurora::Compression
static bool CompressLZ4(const CompressionPipe &stream, const CompressionInfo &info)
{
bool ret = true;
LZ4_stream_t* const lz4Stream = LZ4_createStream();
int size = info.lz4BlockSize ? info.lz4BlockSize : 64 * 1024;
std::shared_ptr<char> in1Buf(new char[size], std::default_delete<char[]>());
std::shared_ptr<char> in2Buf(new char[size], std::default_delete<char[]>());
std::shared_ptr<char> outBuf(new char[size], std::default_delete<char[]>());
std::shared_ptr<char> inBuffers[2] = {in1Buf, in2Buf};
bool inBufState = false;
bool ret;
LZ4F_cctx *cctxPtr;
LZ4F_preferences_t pref {};
AuUInt32 inputStat = 0, outputStat = 0;
LZ4F_compressOptions_t options {};
char header[512];
ret = true;
pref.compressionLevel = info.compressionLevel;
auto maxFrameSize = info.lz4BlockSize ? info.lz4BlockSize : 64 * 1024;
auto buffer = AuSPtr<char>(new char[maxFrameSize], std::default_delete<char[]>());
auto maxOut = LZ4F_compressBound(maxFrameSize, &pref);
auto outBuffer = AuSPtr<char>(new char[maxOut], std::default_delete<char[]>());;
auto err = LZ4F_createCompressionContext(&cctxPtr, LZ4F_getVersion());
if (LZ4F_isError(err))
{
return false;
}
// Write header
{
auto written = LZ4F_compressBegin(cctxPtr, header, AuArraySize(header), &pref);
stream.writePipe(header, written);
}
while (true)
{
auto &inBuf = inBuffers[inBufState = !inBufState];
auto read = stream.inPipe(inBuf.get(), size);
auto read = stream.inPipe(buffer.get(), maxFrameSize);
if (!read) break;
AuUInt32 bufferedBytes = LZ4_compress_fast_continue(lz4Stream, inBuf.get(), outBuf.get(), read, size, 1);
AuUInt32 bufferedBytes = LZ4F_compressUpdate(cctxPtr, outBuffer.get(), maxOut, buffer.get(), read, &options);
if (bufferedBytes <= 0)
{
@ -457,79 +470,113 @@ namespace Aurora::Compression
break;
}
stream.writePipe(&bufferedBytes, sizeof(bufferedBytes));
stream.writePipe(outBuf.get(), bufferedBytes);
stream.writePipe(outBuffer.get(), bufferedBytes);
inputStat += read;
outputStat += bufferedBytes;
if (!stream.reportProgress(inputStat, outputStat)) break;
if (!stream.reportProgress(inputStat, outputStat))
{
ret = false;
break;
}
}
LZ4_freeStream(lz4Stream);
LZ4F_freeCompressionContext(cctxPtr);
return ret;
}
static bool DecompressLZ4(const CompressionPipe &pipe)
{
bool ret = true;
LZ4_streamDecode_t* lz4Stream = LZ4_createStreamDecode();
AuUInt32 inputStat {}, outputStat {}, lastFrameSize {};
std::shared_ptr<char> inFrame;
std::shared_ptr<char> outFrames[2];
bool outFrame {};
LZ4F_dctx *dctxPtr;
AuUInt32 inputStat = 0, outputStat = 0;
LZ4F_decompressOptions_t opts {};
AuUInt32 lastFrameMaxSize {};
AuSPtr<char> bufferIn, bufferOut;
auto err = LZ4F_createDecompressionContext(&dctxPtr, LZ4F_getVersion());
if (LZ4F_isError(err))
{
return false;
}
while (true)
{
AuUInt32 frameSize;
AuUInt32 request = sizeof(frameSize);
auto read = pipe.inPipe(&frameSize, sizeof(frameSize));
if (read != request)
{
ret = false;
break;
}
inputStat += request;
if ((lastFrameSize < frameSize) || (!outFrames[outFrame]))
{
inFrame = std::shared_ptr<char>(new char[frameSize], std::default_delete<char[]>());
outFrames[outFrame] = std::shared_ptr<char>(new char[frameSize], std::default_delete<char[]>());
lastFrameSize = frameSize;
}
request = frameSize;
read = pipe.inPipe(inFrame.get(), request);
if (read != request)
{
ret = false;
break;
}
inputStat += request;
char header[LZ4F_HEADER_SIZE_MAX];
auto outPtr = outFrames[outFrame].get();
auto bytes = LZ4_decompress_safe_continue(lz4Stream, inFrame.get(), outPtr, frameSize, frameSize);
if (bytes <= 0)
LZ4F_frameInfo_t info {};
// Read header
if (pipe.inPipe(header, LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH) != LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH)
{
ret = false;
break;
return {};
}
pipe.writePipe(outPtr, bytes);
inputStat += bytes;
outFrames[!outFrame] = std::move(outFrames[outFrame]);
outFrame = !outFrame;
if (!pipe.reportProgress(inputStat, outputStat))
//
auto sizeOfheader = LZ4F_headerSize(header, LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH);
if (LZ4F_isError(sizeOfheader))
{
break;
return {};
}
const auto req = sizeOfheader - LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH;
if (pipe.inPipe(header + LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH, req) != req)
{
return {};
}
inputStat += sizeOfheader;
size_t sizePtr = sizeOfheader;
auto status = LZ4F_getFrameInfo(dctxPtr, &info, header, &sizePtr);
if (sizePtr != sizeOfheader)
{
return {};
}
auto frameSize = status;
auto min = std::max(info.contentSize, frameSize);
if (min > lastFrameMaxSize)
{
lastFrameMaxSize = min;
if (lastFrameMaxSize > 64 * 1024 * 1024)
{
return {};
}
bufferIn = AuSPtr<char>(new char[lastFrameMaxSize], std::default_delete<char[]>());
bufferOut = AuSPtr<char>(new char[lastFrameMaxSize], std::default_delete<char[]>());
}
if (pipe.inPipe(bufferIn.get(), frameSize) != frameSize)
{
return {};
}
inputStat += frameSize;
if (info.contentSize)
{
size_t frameSPtr = frameSize;
size_t frameS2Ptr = info.contentSize;
LZ4F_decompress(dctxPtr, bufferIn.get(), &frameSPtr, bufferOut.get(), &frameS2Ptr, &opts);
if (frameS2Ptr)
{
pipe.writePipe(bufferOut.get(), frameS2Ptr);
}
outputStat += frameS2Ptr;
if (!pipe.reportProgress(inputStat, outputStat))
{
ret = false;
break;
}
}
}
LZ4_freeStreamDecode(lz4Stream);
LZ4F_freeDecompressionContext(dctxPtr);
return ret;
}
@ -552,7 +599,6 @@ namespace Aurora::Compression
}
}
AUKN_SYM bool Decompress(const CompressionPipe &pipe)
{
switch (pipe.type)

View File

@ -13,33 +13,34 @@ namespace Aurora::Console::Commands
struct Command;
struct CommandDispatch;
static AuHashMap<AuString, Command> gCommands;
static AuList<Hooks::LineHook_cb> gLineCallbacks;
static AuList<CommandDispatch> gPendingCommands;
static auto gMutex = Threading::Primitives::MutexUnique();
static auto gPendingCommandsMutex = Threading::Primitives::MutexUnique();
static std::optional<Async::DispatchTarget_t> gCommandDispatcher;
static AuHashMap<AuString, Command> gCommands;
static AuList<Hooks::LineHook_cb> gLineCallbacks;
static AuList<CommandDispatch> gPendingCommands;
static auto gMutex = Threading::Primitives::MutexUnique();
static auto gPendingCommandsMutex = Threading::Primitives::MutexUnique();
static AuOptional<Async::DispatchTarget_t> gCommandDispatcher;
struct Command
{
AuString tag;
Parse::ParseObject commandStructure;
const CommandCallback_cb &callback;
CommandCallback_cb callback;
Command(AuString tag, Parse::ParseObject commandStructure, const CommandCallback_cb &callback) : tag(tag), commandStructure(commandStructure), callback(callback) {}
Command(AuString tag, Parse::ParseObject commandStructure, CommandCallback_cb &&callback) : tag(tag), commandStructure(commandStructure), callback(std::move(callback)) {}
};
struct CommandDispatch
{
Parse::ParsedObject arguments;
const CommandCallback_cb &callback;
CommandCallback_cb callback;
CommandDispatch(const Parse::ParsedObject &arguments, const CommandCallback_cb &callback) : arguments(arguments), callback(callback) {}
};
static bool Dispatch(const AuString &string)
{
Threading::WaitableLockGuard guard(gPendingCommandsMutex.get());
AU_LOCK_GUARD(gPendingCommandsMutex);
AuString tag;
AuString cmdParse;
AuMach offset;
@ -66,8 +67,8 @@ namespace Aurora::Console::Commands
auto const &cmdEntry = cmdItr->second;
offset = 0;
auto consumable = Parse::StringToConsumable(cmdParse, offset);
auto status = Parse::Parse(res, cmdEntry.commandStructure, consumable);
Parse::ParseState consumable(Parse::StringToConsumable(cmdParse, offset));
auto status = Parse::Parse(consumable, cmdEntry.commandStructure, res);
if (!status)
{
@ -79,21 +80,21 @@ namespace Aurora::Console::Commands
return true;
}
void AddCommand(const AuString &tag, const Parse::ParseObject &commandStructure, const CommandCallback_cb &callback)
AUKN_SYM void AddCommand(const AuString &tag, const Parse::ParseObject &commandStructure, const CommandCallback_cb &callback)
{
Threading::WaitableLockGuard guard(gPendingCommandsMutex.get());
gCommands.insert(std::make_pair(tag, Command(tag, commandStructure, callback)));
AU_LOCK_GUARD(gPendingCommandsMutex);
gCommands.insert(AuMakePair(tag, Command(tag, commandStructure, callback)));
}
bool DispatchCommand(const AuString &string)
AUKN_SYM bool DispatchCommand(const AuString &string)
{
return Dispatch(string);
}
void UpdateDispatcher(std::optional<Async::DispatchTarget_t> target)
void UpdateDispatcher(AuOptional<Async::DispatchTarget_t> target)
{
gMutex->Lock();
gPendingCommandsMutex->Lock();
AU_LOCK_GUARD(gMutex);
AU_LOCK_GUARD(gPendingCommandsMutex);
if ((!target.has_value()) && (gCommandDispatcher == target))
{
@ -105,9 +106,6 @@ namespace Aurora::Console::Commands
}
gCommandDispatcher = target;
gPendingCommandsMutex->Unlock();
gMutex->Unlock();
}
static void DispatchCommandsFromThis(const AuList<CommandDispatch> &commands)
@ -132,13 +130,12 @@ namespace Aurora::Console::Commands
}
else
{
Async::NewWorkItem(gCommandDispatcher.value(),
std::make_shared<Async::BasicWorkStdFunc>([&commands]()
Async::NewWorkItem(gCommandDispatcher.value(),
AuMakeShared<Async::BasicWorkStdFunc>([&commands]()
{
DispatchCommandsFromThis(commands);
}),
}),
true)->Dispatch()->BlockUntilComplete();
}
gMutex->Unlock();

View File

@ -9,6 +9,6 @@
namespace Aurora::Console::Commands
{
void UpdateDispatcher(std::optional<Async::DispatchTarget_t> target);
void UpdateDispatcher(AuOptional<Async::DispatchTarget_t> target);
void PumpCommands();
}

View File

@ -9,40 +9,66 @@
#include "Console.hpp"
#include "Commands/Commands.hpp"
#include "Hooks/Hooks.hpp"
#include "ConsoleAsioStd/ConsoleAsioStd.hpp"
#include "ConsoleStd/ConsoleStd.hpp"
#include "ConsoleWxWidgets/ConsoleWxWidgets.hpp"
#include "ConsoleLogger/ConsoleLogger.hpp"
#include "ConsoleFIO/ConsoleFIO.hpp"
#include "Flusher.hpp"
namespace Aurora::Console
{
void WriteLine(const ConsoleMessage &msg)
AUKN_SYM void WriteLine(const ConsoleMessage &msg)
{
Hooks::WriteLine(msg);
}
AUKN_SYM AuUInt32 ReadStdIn(void *buffer, AuUInt32 length)
{
return ConsoleStd::ReadStdIn(buffer, length);
}
AUKN_SYM AuUInt32 WriteStdIn(const void *buffer, AuUInt32 length)
{
return ConsoleStd::WriteStdOut(buffer, length);
}
void Init()
{
ConsoleAsioStd::Init();
Hooks::Init();
ConsoleStd::Init();
ConsoleWxWidgets::Init();
}
void Init2()
{
ConsoleLogger::Init();
ConsoleFIO::Init();
InitFlusher();
}
void Pump()
{
Commands::PumpCommands();
ConsoleAsioStd::Pump();
ConsoleStd::Pump();
ConsoleWxWidgets::Pump();
ConsoleLogger::Pump();
ConsoleFIO::Pump();
}
void Exit()
{
ConsoleAsioStd::Exit();
DeinitFlusher();
ConsoleStd::Exit();
ConsoleWxWidgets::Exit();
ConsoleLogger::Exit();
ConsoleFIO::Exit();
Hooks::Deinit();
}
AUKN_SYM void OpenLateStd()
{
ConsoleStd::Start();
}
AUKN_SYM void OpenLateGUI()
{
ConsoleWxWidgets::Start();
}
}

View File

@ -1,196 +0,0 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ConsoleAsioStd.cpp
Date: 2021-6-8
Author: Reece
***/
#include <RuntimeInternal.hpp>
#include "ConsoleAsioStd.hpp"
namespace Aurora::Console::ConsoleAsioStd
{
#if defined(AURORA_PLATFORM_WIN32) || defined(AURORA_PLATFORM_LINUX) || defined(AURORA_PLATFORM_APPLE)
#if defined(AURORA_PLATFORM_WIN32)
using StreamDescriptor_t = asio::windows::stream_handle;
#else
using StreamDescriptor_t = asio::posix::stream_descriptor;
#endif
static const AuMach kLineBufferMax = 2048;
static AuUInt8 gLineBuffer[kLineBufferMax] = { 0 };
static AuString gLineString = "";
static StreamDescriptor_t *gInputStream = {};
static StreamDescriptor_t *gOutputStream = {};
static asio::io_context gIOC;
void Init()
{
#if defined(AURORA_PLATFORM_WIN32)
if (GetConsoleWindow() == NULL)
{
if (!gRuntimeConfig.console.forceConsoleWindow)
{
return;
}
if (gRuntimeConfig.console.disableAll)
{
return;
}
auto ok = AllocConsole();
SysAssert(ok, "Request of a Win32 console yielded nada, forceConsole wasn't respected");
}
else
{
// no always means no under UNIX targets; but on windows, if you're compiling a console app, dont be surprised to find console output
// instead of attempting to detach from conhost, link as a WindowedApp and do not setup any windows, if you're looking for windowless
// ignore gRuntimeConfig.console.disableAll
}
DWORD dwMode;
bool ok;
auto hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
SysAssert(hOutput != INVALID_HANDLE_VALUE, "Couldn't open STDOUT");
ok = GetConsoleMode(hOutput, &dwMode);
SysAssert(ok, "Couldn't get console mode");
dwMode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
ok = SetConsoleMode(hOutput, dwMode);
SysAssert(ok, "Couldn't set console mode");
auto fileHandle = CreateFileA("CONIN$",
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
NULL);
SysAssert(fileHandle != INVALID_HANDLE_VALUE, "Couldn't open CONIN");
gInputStream = _new StreamDescriptor_t(gIOC, fileHandle);
fileHandle = CreateFileA("CONOUT$",
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
NULL);
SysAssert(fileHandle != INVALID_HANDLE_VALUE, "Couldn't open CONOUT");
gOutputStream = _new StreamDescriptor_t(gIOC, fileHandle);
#else
// no always means no under UNIX targets
// we *know* stdin/out should be available under these standards
if (gRuntimeConfig.console.disableAll)
{
return;
}
gInputStream = _new StreamDescriptor_t(gIOC, STDIN_FILENO);
gOutputStream = _new StreamDescriptor_t(gIOC, STDOUT_FILENO);
#endif
SysAssert(gInputStream, "Couldn't allocate input stream handler");
SysAssert(gOutputStream, "Couldn't allocate output stream handler");
Aurora::Console::Hooks::AddHook([](const Aurora::Console::ConsoleMessage &string) -> void
{
#if defined(DEBUG) && defined(AURORA_PLATFORM_WIN32)
auto debugLine = string.ToSimplified() + "\r\n";
OutputDebugStringA(debugLine.c_str());
#endif
auto writeLine = string.ToConsole();
#if defined(AURORA_PLATFORM_WIN32)
writeLine += '\r';
#endif
writeLine += '\n';
asio::write(*gOutputStream, asio::buffer(writeLine));
});
}
static void ProcessLines()
{
AuMach index = 0;
while ((index = gLineString.find("\n")) != AuString::npos)
{
auto line = gLineString.substr(0, index);
gLineString = gLineString.substr(index + 1);
if (line[line.size() - 1] == '\r')
{
line.pop_back();
}
if (line.size())
{
Aurora::Console::Commands::DispatchCommand(line);
}
}
}
static void StdInHandler(const asio::error_code &code, std::size_t bytesCopied)
{
if (bytesCopied == 0)
{
return;
}
gLineString.append(reinterpret_cast<const char *>(gLineBuffer), bytesCopied);
ProcessLines();
}
void Pump()
{
if (!gInputStream) return;
gInputStream->async_read_some(asio::buffer(gLineBuffer, kLineBufferMax), StdInHandler);
gIOC.poll_one();
}
void Exit()
{
if (gInputStream)
{
delete gInputStream;
}
if (gOutputStream)
{
delete gOutputStream;
}
}
#else
void Pump()
{
}
void Init()
{
}
void Exit()
{
}
#endif
}

View File

@ -1,15 +0,0 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ConsoleAsioStd.hpp
Date: 2021-6-8
Author: Reece
***/
#pragma once
namespace Aurora::Console::ConsoleAsioStd
{
void Init();
void Pump();
void Exit();
}

View File

@ -1,21 +1,41 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ConsoleLogger.cpp
File: ConsoleFIO.cpp
Date: 2021-6-22
Author: Reece
***/
#include <RuntimeInternal.hpp>
#include "ConsoleLogger.hpp"
#include "ConsoleFIO.hpp"
namespace Aurora::Console::ConsoleLogger
namespace Aurora::Console::ConsoleFIO
{
static Threading::Threads::ThreadUnique_t gFileWriterThread;
static AuList<AuUInt8> gLogBuffer;
static Threading::Primitives::RWLockUnique_t gLogMutex;
static IO::FS::OpenWriteUnique_t gFileHandle;
static const auto & gLogConfig = gRuntimeConfig.console.logging;
static const auto & gLogConfig = gRuntimeConfig.console.fio;
static AuString GetLogDirectory()
{
AuString path;
AuString procName;
if (!IO::FS::GetProfileDomain(path))
{
path = ".";
}
if (!Process::GetProcName(procName))
{
procName = "Unknown";
}
path += "/Logs/";
path += procName;
return path;
}
static void EraseFilesByTimestamp(const AuString &path, /*const its not worth reallocation*/ AuList<AuString> &files)
{
@ -47,47 +67,40 @@ namespace Aurora::Console::ConsoleLogger
static void CleanupOldLogs()
{
AuString path;
AuString procName;
if (!Process::GetProcName(procName))
{
return;
}
if (!IO::FS::GetProfileDomain(path))
{
return;
}
path += "/Logs/";
path += procName;
AuList<AuString> files;
AuBST<AuString, IO::FS::Stat> fileMeta;
AuUInt32 size {};
IO::FS::FilesInDirectory(path, files);
auto baseLogPath = GetLogDirectory();
IO::FS::FilesInDirectory(baseLogPath, files);
for (const auto &file : files)
{
IO::FS::Stat stat;
IO::FS::StatFile(path + "/" + file, stat);
IO::FS::StatFile(baseLogPath + "/" + file, stat);
fileMeta[file] = stat;
size += stat.size;
}
EraseFilesByTimestamp(path, files);
EraseFilesByTimestamp(baseLogPath, files);
// TODO: erase when size >= gLogConfig.maxSizeMb * 1024
}
static void CompressLogs()
{
// TODO: write XZ's
}
void Flush()
{
Threading::WaitableLockGuard a(gLogMutex->AsReadable());
/// It should be expected that the TLS teardown emergency flush to dispatch after deinit
if (!gLogMutex)
{
return;
}
AU_LOCK_GUARD(gLogMutex->AsReadable());
if (gFileHandle)
{
@ -100,39 +113,22 @@ namespace Aurora::Console::ConsoleLogger
static bool OpenLogFile()
{
AuString path;
AuString procName;
if (!Process::GetProcName(procName))
{
return false;
}
if (!IO::FS::GetProfileDomain(path))
{
return false;
}
auto tm = Time::ToCivilTime(Time::CurrentClockMS());
path += fmt::format("/Logs/{}/{:04}-{:02}-{:02}T{:02}-{:02}-{:02}Z.txt",
procName,
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
path = fmt::format("{}/{:04}-{:02}-{:02}T{:02}-{:02}-{:02}Z.txt",
GetLogDirectory(),
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
gFileHandle = IO::FS::OpenWriteUnique(path);
return gFileHandle ? true : false;
return static_cast<bool>(gFileHandle);
}
static void LogThreadInit()
void FIOCleanup()
{
CleanupOldLogs();
auto thread = Threading::Threads::GetThread();
while (!thread->Exiting())
{
Sleep(500);
Flush();
}
CompressLogs();
}
void Init()
@ -152,32 +148,17 @@ namespace Aurora::Console::ConsoleLogger
{
return;
}
Threading::Threads::AbstractThreadVectors handler;
handler.DoRun = [](Threading::Threads::IAuroraThread *)
{
LogThreadInit();
};
gFileWriterThread = Threading::Threads::ThreadUnique(handler);
if (!gFileWriterThread)
{
return;
}
gFileWriterThread->SetName("ConsoleFIO");
gFileWriterThread->Run();
Console::Hooks::AddHook([&](const Console::ConsoleMessage &string) -> void
Console::Hooks::AddFunctionalHook([&](const Console::ConsoleMessage &string) -> void
{
Threading::WaitableLockGuard a(gLogMutex->AsWritable());
AU_LOCK_GUARD(gLogMutex->AsWritable());
auto str = string.ToSimplified();
gLogBuffer.reserve(gLogBuffer.size() + str.size() + 2);
gLogBuffer.insert(gLogBuffer.end(), reinterpret_cast<AuUInt8*>(str.data()), reinterpret_cast<AuUInt8*>(str.data()) + str.size());
#if defined(AURORA_PLATFORM_WIN32)
#if defined(AURORA_IS_MODERNNT_DERIVED)
gLogBuffer.insert(gLogBuffer.end(), AuUInt8('\r'));
#endif
gLogBuffer.insert(gLogBuffer.end(), AuUInt8('\n'));
@ -192,10 +173,7 @@ namespace Aurora::Console::ConsoleLogger
void Exit()
{
Flush();
gFileWriterThread.reset();
gLogMutex.reset();
gFileHandle.reset();
CompressLogs();
}
}

View File

@ -1,16 +1,17 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ConsoleLogger.hpp
File: ConsoleFIO.hpp
Date: 2021-6-22
Author: Reece
***/
#pragma once
namespace Aurora::Console::ConsoleLogger
namespace Aurora::Console::ConsoleFIO
{
void Init();
void Pump();
void Exit();
void Flush();
void FIOCleanup();
}

View File

@ -10,7 +10,8 @@
namespace Aurora::Console
{
static std::array<std::string, static_cast<size_t>(EAnsiColor::eCount)> AnsiCheats{
static std::array<std::string, static_cast<size_t>(EAnsiColor::eCount)> AnsiCheats
{
"\033[0;31m",
"\033[1;31m",
"\033[0;32m",

View File

@ -0,0 +1,516 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ConsoleStd.cpp
Date: 2021-6-8
Author: Reece
***/
#include <RuntimeInternal.hpp>
#include "ConsoleStd.hpp"
#include "Locale/Locale.hpp"
#if defined(AURORA_IS_MODERNNT_DERIVED) || defined(AURORA_IS_POSIX_DERIVED)
#if defined(AURORA_IS_MODERNNT_DERIVED)
// nothing yet
#elif defined(AURORA_IS_POSIX_DERIVED)
#define IO_POSIX_STREAMS
#include <stdio.h>
#include <sys/select.h>
#include <unistd.h>
#endif
// compile time preprocessor definition to strip std stream based IO
#if !(defined(AURORA_DISABLE_STD_CONSOLE))
#define ENABLE_STD_CONSOLE
#endif
#endif
namespace Aurora::Console::ConsoleStd
{
#if defined(ENABLE_STD_CONSOLE)
#if defined(AURORA_IS_MODERNNT_DERIVED)
using StreamHandle_t = HANDLE;
#define IS_STREAM_HANDLE_VALID(h) (h != INVALID_HANDLE_VALUE)
#define DEFAULT_HANDLE_VAL INVALID_HANDLE_VALUE
static StreamHandle_t gWin32Thread = INVALID_HANDLE_VALUE;
#elif defined(IO_POSIX_STREAMS)
#define IS_STREAM_HANDLE_VALID(h) (h != 0)
#define DEFAULT_HANDLE_VAL 0
using StreamHandle_t = int;
#endif
static bool AsyncReadAnyOrReadStreamBlock();
static const AuMach kLineBufferMax = 2048;
static AuUInt8 gLineEncodedBuffer[kLineBufferMax];
static AuUInt gEncodedIndex = 0;
static AuString gLineBuffer(kLineBufferMax, 0);
static AuUInt gLineIndex = 0;
static StreamHandle_t gTerminateConsole;
static StreamHandle_t gInputStream = DEFAULT_HANDLE_VAL;
static StreamHandle_t gOutputStream = DEFAULT_HANDLE_VAL;
static Threading::Primitives::SpinLock gRingLock;
#if defined(AURORA_IS_MODERNNT_DERIVED)
static DWORD WINAPI StdInWin32Thread(void*)
{
HANDLE a[2] = {gInputStream, gTerminateConsole};
while (true)
{
WaitForMultipleObjectsEx(2, a, false, 25, 0);
if (WaitForSingleObject(gTerminateConsole, 0) == WAIT_OBJECT_0)
{
break;
}
AsyncReadAnyOrReadStreamBlock();
}
return 1;
}
#endif
void Start()
{
static bool gConsoleStarted = false;
if (std::exchange(gConsoleStarted, true)) return;
#if defined(AURORA_IS_MODERNNT_DERIVED)
DWORD dwMode;
bool ok;
// Obtain a win32 file HANDLE of STDIN
auto fileHandle = CreateFileA("CONIN$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
SysAssert(fileHandle != INVALID_HANDLE_VALUE, "Couldn't open CONIN");
gInputStream = fileHandle;
// Obtain a win32 file HANDLE of STDOUT
fileHandle = CreateFileA("CONOUT$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
SysAssert(fileHandle != INVALID_HANDLE_VALUE, "Couldn't open CONOUT");
gOutputStream = fileHandle;
// Get current console flags
if (GetConsoleMode(gOutputStream, &dwMode))
{
if (gRuntimeConfig.console.enableStdPassthrough ^ gRuntimeConfig.console.enableStdOut)
{
// Enable escape processing; enable colored output
dwMode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
ok = SetConsoleMode(gOutputStream, dwMode);
SysAssert(ok, "Couldn't set console mode");
// Set the output stream to use UTF-8
ok = SetConsoleOutputCP(CP_UTF8);
SysAssert(ok, "Couldn't maintain UTF-8 stdout stream");
}
}
if (gRuntimeConfig.console.enableStdPassthrough && gRuntimeConfig.console.enableStdOut)
{
SetConsoleMode(gOutputStream, 0);
}
if (gRuntimeConfig.console.enableStdPassthrough ^ gRuntimeConfig.console.enableStdIn)
{
ok = SetConsoleCP(CP_UTF8);
#if 0
SysAssert(ok, "Couldn't maintain UTF-8 stdin stream");
#endif
}
if (gRuntimeConfig.console.enableStdPassthrough && gRuntimeConfig.console.enableStdIn)
{
if (!GetConsoleMode(gInputStream, &dwMode))
{
ok = SetConsoleMode(gInputStream, dwMode & ~(ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
SysAssert(ok, "Couldn't maintain binary stdin stream");
}
}
gTerminateConsole = CreateEvent(nullptr, true, false, nullptr);
gWin32Thread = CreateThread(nullptr, 0, StdInWin32Thread, nullptr, 0, nullptr);
#elif defined(AURORA_IS_POSIX_DERIVED)
gInputStream = STDIN_FILENO;
gOutputStream = STDOUT_FILENO;
#endif
SysAssert(gInputStream, "Couldn't allocate input stream handler");
SysAssert(gOutputStream, "Couldn't allocate output stream handler");
Console::Hooks::AddFunctionalHook([](const Aurora::Console::ConsoleMessage &string) -> void
{
#if (defined(DEBUG) || defined(STAGING)) && defined(AURORA_IS_MODERNNT_DERIVED)
auto debugLine = string.ToSimplified() + "\r\n";
OutputDebugStringW(Locale::ConvertFromUTF8(debugLine).c_str());
#endif
if (!gRuntimeConfig.console.enableStdOut)
{
return;
}
auto writeLine = string.ToConsole();
#if defined(AURORA_IS_MODERNNT_DERIVED)
writeLine += '\r';
#endif
writeLine += '\n';
#if defined(IO_POSIX_STREAMS)
if (Locale::GetInternalCodePage() == Locale::ECodePage::eUTF8)
{
WriteStdOut(writeLine.data(), writeLine.size());
}
else
{
AuString slow;
slow.resize(writeLine.size() * 4);
auto len = Locale::Encoding::EncodeUTF8(writeLine, reinterpret_cast<AuUInt8 *>(slow.data()), slow.size(), Locale::ECodePage::eSysUnk);
if (len.first != 0)
{
WriteStdOut(slow.data(), len.second);
}
else
{
// better write this than nothing
WriteStdOut(writeLine.data(), writeLine.size());
}
}
#elif defined(AURORA_IS_MODERNNT_DERIVED)
WriteStdOut(writeLine.data(), writeLine.size());
#endif
});
}
void Init()
{
#if defined(AURORA_PLATFORM_WIN32)
if (GetConsoleWindow() == NULL)
{
if (!gRuntimeConfig.console.forceConsoleWindow)
{
return;
}
if (gRuntimeConfig.console.disableAllConsoles)
{
return;
}
auto ok = AllocConsole();
SysAssert(ok, "Request of a Win32 console yielded nada, forceConsole wasn't respected");
}
else
{
// Under windows, applications linked with the console subsystem flag should have output no matter what disableAll/forceConsoleWindow says
// The amount of effort it takes to link as console app for a conhost window far exceeds whatever 'forceConsoleWindow' is defined as
// One does not simply switch over to conapp for the fun of it. We can't or at least shouldn't destroy or hide conhost with hacks
// Assuming stdconsole is wanted - DO NOT RETURN - LINK AS A WINDOWED APP IF YOU DO NOT WANT A CONSOLE WINDOW
}
#elif defined(AURORA_IS_POSIX_DERIVED)
// no always means no under UNIX targets
// we *know* stdin/out will be available under these standards
if (gRuntimeConfig.console.disableAllConsoles)
{
return;
}
#endif
Start();
}
AuUInt32 WriteStdOut(const void *data, AuUInt32 length)
{
if (!IS_STREAM_HANDLE_VALID(gOutputStream))
{
return 0;
}
#if defined(IO_POSIX_STREAMS)
AuInt32 written = write(gOutputStream, data, length);
if (written < 0)
{
return 0;
}
#elif defined(AURORA_IS_MODERNNT_DERIVED)
DWORD written;
if (!WriteFile(gOutputStream, data, length, &written, NULL))
{
return 0;
}
#endif
return written;
}
static bool InputStreamAvailable()
{
#if defined(IO_POSIX_STREAMS)
timeval tv {};
fd_set fds {};
FD_ZERO(&fds);
FD_SET(gInputStream, &fds);
select(gInputStream + 1, &fds, NULL, NULL, &tv);
return (FD_ISSET(0, &fds));
#elif defined(AURORA_IS_MODERNNT_DERIVED)
// Inline non-blocking is not legal on windows.
// One can force it with the overlapped flag, seemingly vaid since win8, but defined as illegal since the 90s
return false;
#else
return false;
#endif
}
AuUInt32 ReadStdIn(void *data, AuUInt32 length)
{
Pump();
gRingLock.Lock();
auto readable = std::min(AuUInt32(length), AuUInt32(gEncodedIndex));
std::memcpy(data, gLineEncodedBuffer, readable);
const auto remainingBytes = gEncodedIndex - readable;
if (remainingBytes)
{
std::memmove(gLineEncodedBuffer, &gLineEncodedBuffer[readable], remainingBytes);
}
gEncodedIndex = remainingBytes;
gRingLock.Unlock();
return readable;
}
static void ProcessLines()
{
AuMach index = 0, startIdx = 0;
if (gLineIndex == 0)
{
return;
}
auto end = gLineBuffer.data() + gLineIndex;
while (true)
{
auto a = std::find(gLineBuffer.data() + startIdx, end, '\n');
if (a == end) break;
index = a - gLineBuffer.data();
auto line = gLineBuffer.substr(startIdx, index - startIdx);
startIdx = index + 1;
if (line[line.size() - 1] == '\r')
{
line.pop_back();
}
if (line.size())
{
Console::Commands::DispatchCommand(line);
}
}
if (index != 0)
{
const auto remainingBytes = gLineIndex - startIdx;
if (remainingBytes)
{
std::memmove(gLineBuffer.data(), &gLineBuffer.data()[startIdx], remainingBytes);
gLineIndex -= startIdx;
}
}
}
static void ProcessLinesSysCP()
{
#if defined(AURORA_IS_MODERNNT_DERIVED)
static Locale::Encoding::TextStreamEncoder stream(Locale::ECodePage::eUTF8);
#else
static Locale::Encoding::TextStreamEncoder stream(Locale::GetInternalCodePage());
#endif
AU_LOCK_GUARD(&gRingLock);
auto ret = stream.DecodeUTF8(gLineEncodedBuffer, gEncodedIndex, gLineBuffer.data() + gLineIndex, gLineBuffer.size() - gLineIndex);
// increment backline buffer
{
const auto remainingBytes = gEncodedIndex - ret.first;
if (remainingBytes)
{
std::memmove(gLineEncodedBuffer, &gLineEncodedBuffer[ret.first], remainingBytes);
}
gEncodedIndex = remainingBytes;
}
// increment frontline buffer
{
gLineIndex += ret.second;
}
ProcessLines();
}
static AuUInt32 SyncReadConsole()
{
void *data = &gLineEncodedBuffer[gEncodedIndex];
auto length = kLineBufferMax - gEncodedIndex;
if (!IS_STREAM_HANDLE_VALID(gInputStream))
{
return 0;
}
if (length == 0)
{
return 0;
}
#if defined(AURORA_IS_MODERNNT_DERIVED)
DWORD read = length;
if (!ReadFile(gInputStream, data, read, &read, NULL))
{
return 0;
}
gRingLock.Lock();
gEncodedIndex += read;
gRingLock.Unlock();
return read;
#elif defined(IO_POSIX_STREAMS)
auto bread = ::read(gInputStream, data, length);
if (bread < 0)
{
return 0;
}
gRingLock.Lock();
gEncodedIndex += bread;
gRingLock.Unlock();
return bread;
#else
return 0;
#endif
}
static bool AsyncReadAnyOrReadStreamBlock()
{
if (SyncReadConsole())
{
ProcessLinesSysCP();
return true;
}
return false;
}
void Pump()
{
if (!gRuntimeConfig.console.enableStdIn)
{
return;
}
if (!IS_STREAM_HANDLE_VALID(gInputStream))
{
return;
}
if (!InputStreamAvailable())
{
return;
}
AsyncReadAnyOrReadStreamBlock();
}
void Exit()
{
if (IS_STREAM_HANDLE_VALID(gTerminateConsole))
{
#if defined(AURORA_IS_MODERNNT_DERIVED)
SetEvent(gTerminateConsole);
#endif
}
// Note: CloseHandle in the middle of a ReadFile blocks & we can't legally preempt without the support of docs
#if defined(AURORA_IS_MODERNNT_DERIVED)
if (gWin32Thread != INVALID_HANDLE_VALUE)
{
WaitForSingleObject(gWin32Thread, 200);
TerminateThread(gWin32Thread, 0);
}
AuWin32CloseHandle(gWin32Thread);
AuWin32CloseHandle(gTerminateConsole);
AuWin32CloseHandle(gInputStream);
AuWin32CloseHandle(gOutputStream);
#endif
}
#else
void Pump()
{
}
void Init()
{
}
void Exit()
{
}
void Start()
{
}
#endif
}

View File

@ -0,0 +1,20 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ConsoleStd.hpp
Date: 2021-6-8
Author: Reece
***/
#pragma once
namespace Aurora::Console::ConsoleStd
{
void Init();
void Pump();
void Exit();
void Start();
AuUInt32 ReadStdIn(void *data, AuUInt32 length);
AuUInt32 WriteStdOut(const void *data, AuUInt32 length);
}

View File

@ -9,7 +9,6 @@
#include "ConsoleWxWidgets.hpp"
#if defined(_AUHAS_WXWIDGETS)
#include <asio.hpp>
#include <wx/wxprec.h>
#include <wx/wx.h>
@ -24,6 +23,7 @@ class ConsoleFrame;
static AuList<Aurora::Console::ConsoleMessage> gPendingLines;
static Aurora::Threading::Primitives::MutexUnique_t gMutex;
static bool gWxConsoleReady;
static bool gConsoleStarted = false;
static ConsoleFrame *gWxFrame;
@ -31,7 +31,7 @@ class WxSplitterLine : public wxWindow
{
public:
WxSplitterLine() {}
WxSplitterLine(wxSize splitter, wxColor color, wxWindow *parent, wxWindowID winid) : wxWindow(parent, winid), _color(color)
WxSplitterLine(wxSize splitter, std::optional<wxColor> color, wxWindow *parent, wxWindowID winid) : wxWindow(parent, winid), _color(color)
{
SetMinSize(splitter);
}
@ -39,15 +39,16 @@ public:
void OnPaint(wxPaintEvent &paint)
{
wxPaintDC re(this);
re.SetBrush(_color);
re.SetBackground(_color);
re.SetBrush(_color.value_or(this->GetParent()->GetBackgroundColour()));
re.SetBackground(_color.value_or(this->GetParent()->GetBackgroundColour()));
re.Clear();
}
private:
DECLARE_EVENT_TABLE()
wxColor _color;
std::optional<wxColor> _color;
};
wxBEGIN_EVENT_TABLE(WxSplitterLine, wxPanel)
EVT_PAINT(WxSplitterLine::OnPaint)
@ -66,7 +67,6 @@ ConsoleApp::~ConsoleApp()
}
class ConsoleFrame : public wxFrame
{
public:
@ -90,8 +90,9 @@ private:
void OnShow(wxWindowCreateEvent &event);
void OnCmd(wxCommandEvent &event);
void OnPump(wxTimerEvent& event);
WxSplitterLine *NewSplitter(wxSize splitter, wxColor color);
WxSplitterLine *NewSplitter(wxSize splitter);
wxDECLARE_EVENT_TABLE();
wxRichTextCtrl *richtextbox_;
@ -121,7 +122,8 @@ wxEND_EVENT_TABLE()
bool ConsoleApp::OnInit()
{
ConsoleFrame *frame = _new ConsoleFrame("Aurora Engine Console", wxPoint(50, 50), wxSize(1080, 550));
//gRuntimeConfig.console.
ConsoleFrame *frame = _new ConsoleFrame("Aurora SDK Sample", wxPoint(50, 50), wxSize(1080, 550));
frame->Show(true);
gWxFrame = frame;
return true;
@ -150,6 +152,13 @@ WxSplitterLine *ConsoleFrame::NewSplitter(wxSize splitter, wxColor color)
return re;
}
WxSplitterLine *ConsoleFrame::NewSplitter(wxSize splitter)
{
auto re = new WxSplitterLine(splitter, {}, this, -1);
_splitters.push_back(re);
return re;
}
void ConsoleFrame::WriteLine(const Aurora::Console::ConsoleMessage &string)
{
static std::array<const wxColour, static_cast<size_t>(Aurora::Console::EAnsiColor::eCount)> ColorMap
@ -209,7 +218,7 @@ void ConsoleFrame::WriteLine(const Aurora::Console::ConsoleMessage &string)
if (bold)
richtextbox_->BeginBold();
richtextbox_->WriteText(writeLine);
richtextbox_->WriteText(wxString::FromUTF8(writeLine));
richtextbox_->Newline();
if (bold)
@ -234,6 +243,8 @@ void ConsoleFrame::WriteLine(const Aurora::Console::ConsoleMessage &string)
//richtextbox_->Disable
//richtextbox_->EndParagraphSpacing();
}
#include <wx/gbsizer.h>
ConsoleFrame::ConsoleFrame(const wxString &title, const wxPoint &pos, const wxSize &size)
: wxFrame(NULL, wxID_ANY, title, pos, size)
@ -244,14 +255,42 @@ ConsoleFrame::ConsoleFrame(const wxString &title, const wxPoint &pos, const wxSi
bool useWin32DarkHack = false;
#endif
// _ _ _ _ _ _ _
// (_) | | | | | | | | | | | |
// __ ____ _ _ __ ___ _ __ _ _ __ ___ ___ ___ __ _| |__ ___ __ _ __| | | | | | | | | |
// \ \ /\ / / _` | '__| / __| '__| | '_ ` _ \ / _ \/ __| / _` | '_ \ / _ \/ _` |/ _` | | | | | | | | |
// \ V V / (_| | | | (__| | | | | | | | | __/\__ \ | (_| | | | | __/ (_| | (_| | |_| |_| |_| |_|
// \_/\_/ \__,_|_| \___|_| |_|_| |_| |_|\___||___/ \__,_|_| |_|\___|\__,_|\__,_| (_) (_) (_) (_)
//
static const auto kEnableDark = (useWin32DarkHack) ||
(Aurora::Build::kCurrentPlatform != Aurora::Build::EPlatform::ePlatformWin32);
static const auto kIsBgColorDefault = !kEnableDark;
static const auto kBackgroundColor = kIsBgColorDefault ? this->GetBackgroundColour() : wxColour(38, 38, 38);
static const auto kTextBoxColor = kIsBgColorDefault ? this->GetForegroundColour() : wxColour(255, 255, 255);
static const auto kTextBoxOutter = wxColour(0x15, 0x15, 0x15);
static const auto kTextBoxInner = wxColour(0x38, 0x38, 0x38);
static const auto kHeaderPadUpDown = 14;
static const auto kHeaderPadLeftRight = 15;
static const auto kTextboxWin32PadInner = 2;
static const auto kTextboxWin32PadOutter = 1;
static const auto kTitleContentSplitterDepth = 2;
static const auto kTextboxHeight = 20;
static const auto kTextBoxHandlePad = kEnableDark;
static const auto kTextBoxHandleColor = kEnableDark;
static const auto kDrawOwnCheckboxes = kEnableDark;
// 1080, 550
this->SetClientSize(this->FromDIP(wxSize(903, 434)));
menuBar_ = _new wxMenuBar;
menuBar_ = _new wxMenuBar();
if (!menuBar_) return;
{
wxMenu *menuFile = _new wxMenu;
auto menuFile = _new wxMenu();
if (!menuFile) return;
menuFile->Append(wxID_SAVE, "Export text log");
@ -263,7 +302,7 @@ ConsoleFrame::ConsoleFrame(const wxString &title, const wxPoint &pos, const wxSi
}
{
wxMenu *menuHelp = _new wxMenu;
auto menuHelp = _new wxMenu();
if (!menuHelp) return;
menuHelp->Append(ID_BLACKBOX, "&Report application state to the black box");
@ -272,51 +311,242 @@ ConsoleFrame::ConsoleFrame(const wxString &title, const wxPoint &pos, const wxSi
menuBar_->Append(menuHelp, "&Bugs");
}
richtextbox_ = _new wxRichTextCtrl(this, -1, wxEmptyString,
wxDefaultPosition, wxDefaultSize,
(useWin32DarkHack ? wxBORDER_NONE : 0) | wxTE_MULTILINE | wxRE_READONLY | wxRE_CENTER_CARET);
if (!richtextbox_) return;
commandbox_ = _new wxTextCtrl(this, -1, wxEmptyString,
wxDefaultPosition, wxDefaultSize,
(useWin32DarkHack ? wxBORDER_NONE : 0) | wxTE_PROCESS_ENTER);
if (!commandbox_) return;
if (useWin32DarkHack)
{
this->SetBackgroundColour(wxColour(0, 0, 0));
richtextbox_->SetBackgroundColour(wxColour(0, 0, 0));
richtextbox_->SetForegroundColour(wxColour(255, 255, 255));
commandbox_->SetBackgroundColour(wxColour(0, 0, 0));
commandbox_->SetForegroundColour(wxColour(255, 255, 255));
//this->Connect(wxEVT_SHOW, wxWindowCreateEventHandler(ConsoleFrame::OnShow));
this->Connect(wxEVT_SHOW, wxWindowCreateEventHandler(ConsoleFrame::OnShow));
}
commandbox_->SetHint("Type a command here");
commandbox_->Connect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(ConsoleFrame::OnCmd));
//commandbox_->Bind(wxEVT_COMMAND_TEXT_ENTER, &ConsoleFrame::OnCmd, commandbox_);
sizer_ = _new wxBoxSizer(wxVERTICAL);
if (!sizer_) return;
auto font = this->GetFont();
font.SetPointSize(9);
font.MakeBold();
auto font2 = this->GetFont();
font2.SetPointSize(9);
sizer_->Add(richtextbox_, 3, wxEXPAND);
if (useWin32DarkHack)
auto addTextbox = [&](wxBoxSizer *parent, int minx, int miny, bool alt = false) -> wxTextCtrl *
{
sizer_->Add(NewSplitter(wxSize(4, 2), wxColour(0x38, 0x38, 0x38)), 0, wxEXPAND);
sizer_->Add(NewSplitter(wxSize(4, 1), wxColour(0, 0, 0)), 0, wxEXPAND);
}
sizer_->Add(commandbox_, 0, wxEXPAND | wxBOTTOM);
if (useWin32DarkHack)
auto filterBarContainer = _new wxBoxSizer(wxVERTICAL);
if (!filterBarContainer) return {};
auto filterBar = _new wxBoxSizer(wxHORIZONTAL);
if (!filterBar) return{};
auto filterBox = _new wxTextCtrl(this, -1, wxEmptyString,
wxDefaultPosition, alt ? wxDefaultSize : wxSize(400, 20),
(kTextBoxHandlePad ? wxBORDER_NONE : 0) | wxTE_PROCESS_ENTER | wxEXPAND);
if (!filterBox) return{};
filterBox->SetMinSize({minx, miny});
if (kTextBoxHandlePad)
{
filterBarContainer->Add(NewSplitter(wxSize(kTextboxWin32PadOutter, kTextboxWin32PadOutter), kTextBoxOutter), 0, wxEXPAND);
filterBarContainer->Add(NewSplitter(wxSize(kTextboxWin32PadInner, kTextboxWin32PadInner), kTextBoxInner), 0, wxEXPAND);
}
filterBarContainer->Add(filterBox, wxSizerFlags().Proportion(1).Expand());
if (kTextBoxHandleColor)
{
filterBox->SetBackgroundColour(kBackgroundColor);
filterBox->SetForegroundColour(kTextBoxColor);
}
if (kTextBoxHandlePad)
{
filterBarContainer->Add(NewSplitter(wxSize(kTextboxWin32PadInner, kTextboxWin32PadInner), kTextBoxInner), 0, wxEXPAND);
filterBarContainer->Add(NewSplitter(wxSize(kTextboxWin32PadOutter, kTextboxWin32PadOutter), kTextBoxOutter), 0, wxEXPAND);
}
if (kTextBoxHandlePad)
{
filterBar->Add(NewSplitter(wxSize(kTextboxWin32PadOutter, kTextboxWin32PadOutter), kTextBoxOutter) , 0, wxEXPAND | wxTOP | wxBOTTOM, 1);
filterBar->Add(NewSplitter(wxSize(kTextboxWin32PadInner, kTextboxWin32PadInner), kTextBoxInner), 0, wxEXPAND | wxTOP | wxBOTTOM, 1);
}
filterBar->Add(filterBarContainer, wxSizerFlags().Proportion(1).Expand());
if (kTextBoxHandlePad)
{
filterBar->Add(NewSplitter(wxSize(kTextboxWin32PadInner, kTextboxWin32PadInner), kTextBoxInner), 0, wxEXPAND | wxTOP | wxBOTTOM, 1);
filterBar->Add(NewSplitter(wxSize(kTextboxWin32PadOutter, kTextboxWin32PadOutter), kTextBoxOutter), 0, wxEXPAND | wxTOP | wxBOTTOM, 1);
}
parent->Add(filterBar, wxSizerFlags().Expand());
return filterBox;
};
auto header = _new wxBoxSizer(wxHORIZONTAL);
auto addHeaderPanel = [&](wxBoxSizer *parent, wxBoxSizer *inner, bool up, bool down, bool left, bool right, int top, int sides)
{
sizer_->Add(NewSplitter(wxSize(4, 1), wxColour(0, 0, 0)), 0, wxEXPAND);
sizer_->Add(NewSplitter(wxSize(4, 2), wxColour(0x38, 0x38, 0x38)), 0, wxEXPAND);
auto filterBar = _new wxBoxSizer(wxVERTICAL);
if (!filterBar) return;
auto innerBar = _new wxBoxSizer(wxHORIZONTAL);
if (!innerBar) return;
// PAD FILTER REGION UP
if (up)
{
filterBar->Add(NewSplitter(wxSize(top, top)), wxSizerFlags().Expand());
}
{
// PAD FILTER REGION LEFT
if (left)
{
innerBar->Add(NewSplitter(wxSize(sides, sides)), wxSizerFlags().Expand());
}
innerBar->Add(inner, wxSizerFlags().Expand());
// PAD FILTER REGION RIGHT
if (right)
{
innerBar->Add(NewSplitter(wxSize(sides, sides)), wxSizerFlags().Expand());
}
}
filterBar->Add(innerBar, wxSizerFlags().Expand());
// PAD FILTER REGION DOWN
if (down)
{
filterBar->Add(NewSplitter(wxSize(top, top)), wxSizerFlags().Expand());
}
parent->Add(filterBar, wxSizerFlags().Expand());
};
this->SetBackgroundColour(kBackgroundColor);
// HEADER PANEL 1# filter
{
auto filterBarContainer = _new wxBoxSizer(wxVERTICAL);
if (!filterBarContainer) return;
auto filterLabel = _new wxStaticText(this, -1, "FILTER");
if (!filterLabel) return;
filterLabel->SetFont(font);
filterLabel->SetBackgroundColour(kBackgroundColor);
filterLabel->SetForegroundColour(kTextBoxColor);
filterBarContainer->Add(filterLabel);
filterBarContainer->Add(NewSplitter(wxSize(kTitleContentSplitterDepth, kTitleContentSplitterDepth)), wxSizerFlags().Expand());
addTextbox(filterBarContainer, 400, kTextboxHeight);
addHeaderPanel(header, filterBarContainer, true, true, true, false, kHeaderPadUpDown, kHeaderPadLeftRight);
}
// Align right
header->AddStretchSpacer();
// Draw a little bar
//header->Add(NewSplitter(wxSize(1, 1), wxColour(0x38, 0x38, 0x38)), 0, wxEXPAND);
// HEADER PANEL 2# levels
{
AuList<AuString> chkName = {"Debug", "Warn", "Info", "Game"};
auto checkboxes = _new wxBoxSizer(wxHORIZONTAL);
if (!checkboxes) return;
auto checkboxesContainer = _new wxBoxSizer(wxVERTICAL);
if (!checkboxes) return;
auto checkboxLabel = _new wxStaticText(this, -1, "LEVEL");
if (!checkboxLabel) return;
checkboxLabel->SetFont(font);
checkboxLabel->SetBackgroundColour(kBackgroundColor);
checkboxLabel->SetForegroundColour(kTextBoxColor);
for (int i = 0; i < chkName.size(); i++)
{
const auto &name = chkName[i];
if (kDrawOwnCheckboxes)
{
if (i != 0)
{
checkboxes->Add(NewSplitter(wxSize(6, 6)), wxSizerFlags().Expand());
}
auto label = _new wxStaticText(this, -1, name.c_str());
label->SetBackgroundColour(kBackgroundColor);
label->SetForegroundColour(kTextBoxColor);
label->SetFont(font2);
checkboxes->Add(label);
checkboxes->Add(NewSplitter(wxSize(2, 2)), wxSizerFlags().Expand());
}
auto checkbox1 = new wxCheckBox(this, -1, kDrawOwnCheckboxes ? "" : name.c_str(), wxDefaultPosition, wxDefaultSize);
checkbox1->SetFont(font2);
checkbox1->SetValue(true);
checkboxes->Add(NewSplitter(wxSize(2, 2)), wxSizerFlags().Expand());
checkboxes->Add(checkbox1, wxSizerFlags(0).CenterVertical().GetFlags());
checkboxes->Add(NewSplitter(wxSize(2, 2)), wxSizerFlags().Expand());
}
checkboxesContainer->Add(checkboxLabel);
checkboxesContainer->Add(NewSplitter(wxSize(kTitleContentSplitterDepth, kTitleContentSplitterDepth)), wxSizerFlags().Expand());
checkboxesContainer->Add(checkboxes);
addHeaderPanel(header, checkboxesContainer, true, true, false, true, kHeaderPadUpDown, kHeaderPadLeftRight);
}
sizer_->Add(header, 0, wxEXPAND);
// Shadow down
if (/*useWin32DarkHack*/ true)
{
sizer_->Add(NewSplitter(wxSize(kTextboxWin32PadInner, kTextboxWin32PadInner), kTextBoxInner), 0, wxEXPAND);
sizer_->Add(NewSplitter(wxSize(kTextboxWin32PadOutter, kTextboxWin32PadOutter), kTextBoxOutter), 0, wxEXPAND);
}
// Rich text box
{
richtextbox_ = _new wxRichTextCtrl(this, -1, wxEmptyString,
wxDefaultPosition, wxDefaultSize,
(kTextBoxHandlePad ? wxBORDER_NONE : 0) | wxTE_MULTILINE | wxRE_READONLY | wxRE_CENTER_CARET);
if (!richtextbox_) return;
if (useWin32DarkHack)
{
richtextbox_->SetBackgroundColour(kBackgroundColor);
richtextbox_->SetForegroundColour(kTextBoxColor);
this->Connect(wxEVT_SHOW, wxWindowCreateEventHandler(ConsoleFrame::OnShow));
}
sizer_->Add(richtextbox_, 1, wxEXPAND);
}
// Shadow down
if (/*useWin32DarkHack*/ true)
{
sizer_->Add(NewSplitter(wxSize(kTextboxWin32PadInner, kTextboxWin32PadInner), kTextBoxInner), 0, wxEXPAND);
sizer_->Add(NewSplitter(wxSize(kTextboxWin32PadOutter, kTextboxWin32PadOutter), kTextBoxOutter), 0, wxEXPAND);
}
// Command Box
{
commandbox_ = addTextbox(sizer_, 0, kTextboxHeight, true);
commandbox_->SetHint("Type a command here");
commandbox_->Connect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(ConsoleFrame::OnCmd));
}
SetSizer(sizer_);
SetMenuBar(menuBar_);
// SetAutoLayout(true);
timer_.Bind(wxEVT_TIMER, &ConsoleFrame::OnPump, this);
timer_.Start(100);
@ -324,47 +554,46 @@ ConsoleFrame::ConsoleFrame(const wxString &title, const wxPoint &pos, const wxSi
}
#if defined(AURORA_PLATFORM_WIN32)
#include <Uxtheme.h>
#include <Extensions/Win32/DarkTheme.hpp>
#include <Uxtheme.h>
#include <Extensions/Win32/DarkTheme.hpp>
static bool DarkModeEnabled()
{
return Aurora::Extensions::Win32::g_darkModeSupported;
}
static bool DarkModeEnabled()
{
return Aurora::Extensions::Win32::g_darkModeSupported;
}
void ConsoleFrame::OnInit(wxWindowCreateEvent &event)
{
OnShow(event);
}
void ConsoleFrame::OnInit(wxWindowCreateEvent &event)
{
OnShow(event);
}
void ConsoleFrame::OnShow(wxWindowCreateEvent &event)
{
if (!DarkModeEnabled()) return;
void ConsoleFrame::OnShow(wxWindowCreateEvent &event)
{
if (!DarkModeEnabled()) return;
auto handle = event.GetWindow()->GetHWND();
Aurora::Extensions::Win32::AllowDarkModeForWindow(handle, true);
auto handle = event.GetWindow()->GetHWND();
Aurora::Extensions::Win32::AllowDarkModeForWindow(handle, true);
if (Aurora::Extensions::Win32::_FlushMenuThemes)
Aurora::Extensions::Win32::_FlushMenuThemes();
if (Aurora::Extensions::Win32::_FlushMenuThemes)
Aurora::Extensions::Win32::_FlushMenuThemes();
SetWindowTheme(handle, L"DarkMode_Explorer", NULL);
SendMessageW(handle, WM_THEMECHANGED, 0, 0);
Aurora::Extensions::Win32::RefreshTitleBarThemeColor(handle);
UpdateWindow(handle);
}
SetWindowTheme(handle, L"DarkMode_Explorer", NULL);
SendMessageW(handle, WM_THEMECHANGED, 0, 0);
Aurora::Extensions::Win32::RefreshTitleBarThemeColor(handle);
UpdateWindow(handle);
}
#else
void ConsoleFrame::OnInit(wxWindowCreateEvent &event)
{}
void ConsoleFrame::OnInit(wxWindowCreateEvent &event)
{}
void ConsoleFrame::OnShow(wxWindowCreateEvent &event)
{}
void ConsoleFrame::OnShow(wxWindowCreateEvent &event)
{}
static bool DarkModeEnabled()
{
return Aurora::Build::EPlatform == Aurora::Build::EPlatform::kPlatformLinux;
}
static bool DarkModeEnabled()
{
return Aurora::Build::EPlatform == Aurora::Build::EPlatform::kPlatformLinux;
}
#endif
void ConsoleFrame::OnExit(wxCommandEvent &event)
@ -403,20 +632,25 @@ namespace Aurora::Console::ConsoleWxWidgets
static bool UseWxConsole()
{
if (gRuntimeConfig.console.disableAll)
if (gRuntimeConfig.console.disableAllConsoles)
{
return false;
}
if (!gRuntimeConfig.console.enableWxWidgets)
{
return false;
}
#if defined(AURORA_PLATFORM_WIN32)
if (GetConsoleWindow())
{
if (!gRuntimeConfig.console.forceToolKitWindow)
{
return false;
}
return true;
}
#endif
return true;
}
@ -464,7 +698,7 @@ namespace Aurora::Console::ConsoleWxWidgets
return;
}
Threading::LockGuardPtr re(gMutex.get()); // pupose two of the mutex: locking deconstruction/gWxConsoleReady
AU_LOCK_GUARD(gMutex.get()); // pupose two of the mutex: locking deconstruction/gWxConsoleReady
// its a horible hack, but -
// 1) our dtor comes before the final apps class, and
// 2) the app will deregister the top window before the dtor
@ -509,10 +743,17 @@ namespace Aurora::Console::ConsoleWxWidgets
{
return;
}
Start();
}
void Start()
{
if (std::exchange(gConsoleStarted, true)) return;
gMutex = Aurora::Threading::Primitives::MutexUnique();
Aurora::Console::Hooks::AddHook([&](const Aurora::Console::ConsoleMessage &string) -> void
Aurora::Console::Hooks::AddFunctionalHook([&](const Aurora::Console::ConsoleMessage &string) -> void
{
gMutex->Lock();
gPendingLines.push_back(string);
@ -545,7 +786,7 @@ namespace Aurora::Console::ConsoleWxWidgets
AuList<Console::ConsoleMessage> lines;
{
Aurora::Threading::LockGuardPtr re(gMutex.get());
AU_LOCK_GUARD(gMutex);
lines = std::exchange(gPendingLines, {});
}
@ -557,16 +798,6 @@ namespace Aurora::Console::ConsoleWxWidgets
void Pump()
{
#if 0
Aurora::Threading::LockGuardPtr re(gMutex.get());
if (!gWxConsoleReady) return;
wxTheApp->GetTopWindow()->GetEventHandler()->CallAfter([]()
{
WxWidgetsPump();
});
#endif
}
void Exit()
@ -583,6 +814,7 @@ namespace Aurora::Console::ConsoleWxWidgets
gMutex.reset();
gPendingLines.clear();
gConsoleStarted = false;
}
}
@ -593,12 +825,18 @@ namespace Aurora::Console::ConsoleWxWidgets
void Init()
{
}
void Pump()
{
}
void Exit()
{
}
void Start()
{
}
}
#endif

View File

@ -11,5 +11,6 @@ namespace Aurora::Console::ConsoleWxWidgets
{
void Init();
void Pump();
void Start();
void Exit();
}

View File

@ -0,0 +1,94 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Flusher.cpp
Date: 2021-8-27
Author: Reece
***/
#include <RuntimeInternal.hpp>
#include "Flusher.hpp"
#include "ConsoleFIO/ConsoleFIO.hpp"
namespace Aurora::Console
{
static Threading::Threads::ThreadUnique_t gWriterThread;
class ShutdownFlushHook : public Threading::Threads::IThreadFeature
{
public:
void Init() override;
void Cleanup() override;
};
void ShutdownFlushHook::Init()
{
}
void ShutdownFlushHook::Cleanup()
{
// Flush all internal consoles on shutdown
ForceFlush();
}
static void SlowStartupTasks()
{
ConsoleFIO::FIOCleanup();
}
static void LogThreadEP()
{
auto thread = Threading::Threads::GetThread();
SlowStartupTasks();
while (!thread->Exiting())
{
Sleep(500);
ForceFlush();
}
}
static void DestroyFlushThread()
{
gWriterThread.reset();
}
static void InitFlushThread()
{
// Startup a runner thread that will take care of all the stress inducing IO every so often on a remote thread
Threading::Threads::AbstractThreadVectors handler;
handler.DoRun = [](Threading::Threads::IAuroraThread *)
{
LogThreadEP();
};
gWriterThread = Threading::Threads::ThreadUnique(handler);
if (!gWriterThread)
{
return;
}
gWriterThread->SetName("CasualConsoleAsyncWritter");
gWriterThread->Run();
}
void InitFlusher()
{
// Add a 'ShutdownFlushHook' object to the main threads TLS hook
Threading::Threads::GetThread()->AddLastHopeTlsHook(AuMakeShared<ShutdownFlushHook>());
InitFlushThread();
}
void DeinitFlusher()
{
DestroyFlushThread();
}
void ForceFlush()
{
ConsoleFIO::Flush();
}
}

View File

@ -0,0 +1,15 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Flusher.hpp
Date: 2021-8-27
Author: Reece
***/
#pragma once
namespace Aurora::Console
{
void ForceFlush();
void InitFlusher();
void DeinitFlusher();
}

View File

@ -10,27 +10,43 @@
namespace Aurora::Console::Hooks
{
static auto gMutex = Threading::Primitives::MutexUnique();
static AuList<Hooks::LineHook_cb> gLineCallbacks;
static Threading::Primitives::MutexUnique_t gMutex;
static AuList<Hooks::LineHook_cb> gLineFunctionalCallbacks;
static AuList<AuSPtr<IConsoleSubscriber>> gLineSubscribers;
void AddHook(LineHook_cb hook)
AUKN_SYM void AddSubscription(const AuSPtr<IConsoleSubscriber> &subscriber)
{
Aurora::Threading::WaitableLockGuard guard(gMutex.get());
gLineCallbacks.push_back(hook);
AU_LOCK_GUARD(gMutex);
AuTryInsert(gLineSubscribers, subscriber);
}
AUKN_SYM void RemoveSubscription(const AuSPtr<IConsoleSubscriber> &subscriber)
{
AU_LOCK_GUARD(gMutex);
AuTryDeleteList(gLineSubscribers, subscriber);
}
AUKN_SYM void AddFunctionalHook(LineHook_cb hook)
{
AU_LOCK_GUARD(gMutex);
AuTryInsert(gLineFunctionalCallbacks, hook);
}
void WriteLine(const ConsoleMessage &msg)
{
gMutex->Lock();
auto callbacks = gLineCallbacks;
gMutex->Unlock();
AU_LOCK_GUARD(gMutex);
if (msg.line.find('\n') == std::string::npos) [[likely]]
{
for (const auto &callback : callbacks)
for (const auto &callback : gLineFunctionalCallbacks)
{
callback(msg);
}
for (const auto &sub : gLineSubscribers)
{
sub->OnMessage(msg);
}
}
else [[unlikely]]
{
@ -39,11 +55,29 @@ namespace Aurora::Console::Hooks
{
ConsoleMessage dup = msg;
dup.line = line;
for (const auto &callback : callbacks)
for (const auto &callback : gLineFunctionalCallbacks)
{
callback(dup);
}
for (const auto &sub : gLineSubscribers)
{
sub->OnMessage(dup);
}
});
}
}
void Init()
{
gMutex = Threading::Primitives::MutexUnique();
}
void Deinit()
{
gLineFunctionalCallbacks.clear();
gLineSubscribers.clear();
gMutex.reset();
}
}

Some files were not shown because too many files have changed in this diff Show More