Added more stuff like Logging, DynamicPointer, utilities for using STL allocators and NotNullable.

This commit is contained in:
2025-06-21 08:07:57 +02:00
parent 17bd408d3c
commit 061c58ef41
16 changed files with 970 additions and 1 deletions

146
source/mijin/util/annot.hpp Normal file
View File

@@ -0,0 +1,146 @@
#pragma once
#if !defined(MIJIN_UTIL_ANNOT_HPP_INCLUDED)
#define MIJIN_UTIL_ANNOT_HPP_INCLUDED 1
#include <utility>
#include "../internal/common.hpp"
#include "../debug/assert.hpp"
#if !defined(__has_include)
#define __has_include(x) (false)
#endif
#if !defined(MIJIN_USE_GSL)
#if __has_include(<gsl/gsl>)
#define MIJIN_USE_GSL 1
#else
#define MIJIN_USE_GSL 0
#endif
#endif // !defined(MIJIN_USE_GSL)
#include <concepts>
#include "./concepts.hpp"
#if MIJIN_USE_GSL
#include <gsl/gsl>
#endif
namespace mijin
{
template<typename T> requires(!std::is_same_v<T, std::nullptr_t>) && requires(T t) { t == nullptr; }
class NotNullable
{
private:
T base_;
public:
template<typename U> requires(std::is_same_v<T, U> && std::is_copy_constructible_v<T>)
constexpr NotNullable(U base) MIJIN_NOEXCEPT_IF(std::is_nothrow_copy_constructible_v<T>)
: base_(base)
{
MIJIN_ASSERT(base_ != nullptr, "Constructed non-nullable type with nullptr.");
}
template<typename TArg, typename... TArgs> requires(!std::is_same_v<TArg, std::nullptr_t>
&& (!std::is_same_v<TArg, T> && sizeof...(TArgs) == 0)
&& std::is_constructible_v<T, TArg&&, TArgs&&...>)
constexpr NotNullable(TArg&& arg, TArgs&&... args) MIJIN_NOEXCEPT_IF((std::is_nothrow_constructible_v<T, TArg&&, TArgs&&...>))
: base_(std::forward<TArg>(arg), std::forward<TArgs>(args)...)
{
MIJIN_ASSERT(base_ != nullptr, "Constructed non-nullable type with nullptr.");
}
constexpr NotNullable(T&& base) MIJIN_NOEXCEPT_IF(std::is_nothrow_move_constructible_v<T>)
requires(std::is_move_constructible_v<T>)
: base_(std::move(base))
{
MIJIN_ASSERT(base_ != nullptr, "Constructed non-nullable type with nullptr.");
}
constexpr NotNullable(NotNullable&& other) MIJIN_NOEXCEPT_IF(std::is_nothrow_move_constructible_v<T>)
requires(std::is_move_constructible_v<T>)
: base_(std::exchange(other.base_, nullptr))
{
MIJIN_ASSERT(base_ != nullptr, "Constructed non-nullable type with nullptr.");
}
constexpr NotNullable(std::nullptr_t) MIJIN_DELETE("Type is not nullable.");
constexpr NotNullable& operator=(const NotNullable& other) MIJIN_NOEXCEPT_IF(std::is_nothrow_copy_constructible_v<T>)
requires(std::is_copy_constructible_v<T>)
{
if (this != &other)
{
this->base_ = other.base_;
}
MIJIN_ASSERT(base_ != nullptr, "Assigned nullptr to non-nullable type."); // might still happen if the other type was moved from
return *this;
}
constexpr NotNullable& operator=(NotNullable&& other) MIJIN_NOEXCEPT_IF(std::is_nothrow_move_assignable_v<T>)
requires(std::is_move_assignable_v<T>)
{
if (this != &other)
{
this->base_ = std::exchange(other.base_, nullptr);
}
MIJIN_ASSERT(base_ != nullptr, "Assigned nullptr to non-nullable type."); // might still happen if the other type was moved from
return *this;
}
constexpr NotNullable& operator=(std::nullptr_t) MIJIN_DELETE("Type is not nullable.");
template<std::equality_comparable_with<T> TOther>
bool operator==(const NotNullable<TOther>& other) MIJIN_NOEXCEPT_IF(noexcept(std::declval<T>() == std::declval<TOther>()))
{
return base_ == other.base_;
}
template<std::equality_comparable_with<T> TOther>
bool operator!=(const NotNullable<TOther>& other) MIJIN_NOEXCEPT_IF(noexcept(std::declval<T>() != std::declval<TOther>()))
{
return base_ != other.base_;
}
template<std::equality_comparable_with<T> TOther> requires(!std::is_same_v<TOther, std::nullptr_t>)
bool operator==(const TOther& other) MIJIN_NOEXCEPT_IF(noexcept(std::declval<T>() == std::declval<TOther>()))
{
return base_ == other;
}
template<std::equality_comparable_with<T> TOther> requires(!std::is_same_v<TOther, std::nullptr_t>)
bool operator!=(const TOther& other) MIJIN_NOEXCEPT_IF(noexcept(std::declval<T>() != std::declval<TOther>()))
{
return base_ != other;
}
bool operator==(std::nullptr_t) MIJIN_DELETE("Type is not nullable.");
bool operator!=(std::nullptr_t) MIJIN_DELETE("Type is not nullable.");
constexpr operator const T&() const MIJIN_NOEXCEPT { return get(); }
constexpr operator std::nullptr_t() const MIJIN_DELETE("Type is not nullable.");
constexpr const T& operator->() const MIJIN_NOEXCEPT { return get(); }
constexpr decltype(auto) operator*() const MIJIN_NOEXCEPT_IF(noexcept(*get())) { return *get(); }
NotNullable& operator++() MIJIN_DELETE("Operator disabled for non-nullable types.");
NotNullable& operator--() MIJIN_DELETE("Operator disabled for non-nullable types.");
NotNullable operator++(int) MIJIN_DELETE("Operator disabled for non-nullable types.");
NotNullable operator--(int) MIJIN_DELETE("Operator disabled for non-nullable types.");
NotNullable& operator+=(std::ptrdiff_t) MIJIN_DELETE("Operator disabled for non-nullable types.");
NotNullable& operator-=(std::ptrdiff_t) MIJIN_DELETE("Operator disabled for non-nullable types.");
void operator[](std::ptrdiff_t) const MIJIN_DELETE("Operator disabled for non-nullable types.");
[[nodiscard]]
constexpr const T& get() const MIJIN_NOEXCEPT { return base_; }
};
#if MIJIN_USE_GSL
template<mijin::pointer_type T>
using owner_t = gsl::owner<T>;
#else
template<mijin::pointer_type T>
using owner_t = T;
#endif
template<typename T>
using not_null_t = NotNullable<T>;
}
#endif // !defined(MIJIN_UTIL_ANNOT_HPP_INCLUDED)

View File

@@ -5,6 +5,7 @@
#define MIJIN_UTIL_CONCEPTS_HPP_INCLUDED 1
#include <type_traits>
#include "./traits.hpp"
namespace mijin
{
@@ -39,6 +40,32 @@ concept pointer_type = std::is_pointer_v<T>;
template<typename T>
concept reference_type = std::is_reference_v<T>;
namespace impl
{
template<typename T>
using pointer_t = typename T::pointer;
}
template<typename T>
concept allocator_type = requires(T alloc, typename T::value_type value, detect_or_t<typename T::value_type*, impl::pointer_t, T> pointer, int count)
{
typename T::value_type;
{ alloc.allocate(count) } -> std::same_as<decltype(pointer)>;
{ alloc.deallocate(pointer, count) } -> std::same_as<void>;
} && !std::is_const_v<typename T::value_type> && !std::is_volatile_v<typename T::value_type>;
template<typename T, typename TOther>
concept allocator_type_for = allocator_type<T> && std::is_same_v<typename T::value_type, TOther>;
template<template<typename> typename T>
concept allocator_tmpl = allocator_type<T<int>>;
template<typename T, typename TData>
concept deleter_type = requires(T deleter, TData* ptr)
{
deleter(ptr);
};
//
// public functions
//

View File

@@ -5,11 +5,14 @@
#include "../debug/assert.hpp"
#if MIJIN_TARGET_OS == MIJIN_OS_LINUX
#include <bit>
#include <cstring>
#include <mutex>
#include <dlfcn.h>
#include <pthread.h>
#elif MIJIN_TARGET_OS == MIJIN_OS_WINDOWS
#include <array>
#include <malloc.h>
#include <windows.h>
#include "../util/winundef.hpp"
#endif
@@ -139,4 +142,40 @@ std::string getExecutablePath() MIJIN_NOEXCEPT
#endif
}
void* alignedAlloc(std::size_t alignment, std::size_t size) MIJIN_NOEXCEPT
{
#if MIJIN_TARGET_OS == MIJIN_OS_WINDOWS
return _aligned_alloc(size, alignment);
#else
return std::aligned_alloc(alignment, size);
#endif
}
void* alignedRealloc(void* ptr, std::size_t alignment, std::size_t size) MIJIN_NOEXCEPT
{
#if MIJIN_TARGET_OS == MIJIN_OS_WINDOWS
return _aligned_realloc(ptr, size, alignment);
#else
void* newPtr = std::realloc(ptr, size);
if (newPtr == ptr || (std::bit_cast<std::uintptr_t>(newPtr) % alignment) == 0)
{
return newPtr;
}
// bad luck, have to copy a second time
void* newPtr2 = std::aligned_alloc(alignment, size);
std::memcpy(newPtr2, newPtr, size);
std::free(newPtr);
return newPtr2;
#endif
}
void alignedFree(void* ptr)
{
#if MIJIN_TARGET_OS == MIJIN_OS_WINDOWS
_aligned_free(ptr);
#else
std::free(ptr);
#endif
}
} // namespace mijin

View File

@@ -81,6 +81,10 @@ void setCurrentThreadName(const char* threadName) MIJIN_NOEXCEPT;
[[nodiscard]] std::string makeLibraryFilename(std::string_view libraryName) MIJIN_NOEXCEPT;
[[nodiscard]] void* alignedAlloc(std::size_t alignment, std::size_t size) MIJIN_NOEXCEPT;
[[nodiscard]] void* alignedRealloc(void* ptr, std::size_t alignment, std::size_t size) MIJIN_NOEXCEPT;
void alignedFree(void* ptr);
SharedLibrary::~SharedLibrary() MIJIN_NOEXCEPT
{
close();

View File

@@ -146,7 +146,24 @@ template<template<typename...> typename TTemplate, typename... TArgs>
struct is_template_instance<TTemplate, TTemplate<TArgs...>> : std::true_type {};
template<template<typename...> typename TTemplate, typename TType>
constexpr bool is_template_instance_v = is_template_instance<TTemplate, TType>::value;
constexpr bool is_template_instance_v = is_template_instance<TTemplate, TType>::value;
template<typename TDefault, template<typename...> typename TOper, typename... TArgs>
struct detect_or
{
using type = TDefault;
static constexpr bool detected = false;
};
template<typename TDefault, template<typename...> typename TOper, typename... TArgs>
requires requires { typename TOper<TArgs...>; }
struct detect_or<TDefault, TOper, TArgs...>
{
using type = TOper<TArgs...>;
static constexpr bool detected = true;
};
template<typename TDefault, template<typename...> typename TOper, typename... TArgs>
using detect_or_t = detect_or<TDefault, TOper, TArgs...>::type;
//
// public functions