Added more stuff like Logging, DynamicPointer, utilities for using STL allocators and NotNullable.
This commit is contained in:
146
source/mijin/util/annot.hpp
Normal file
146
source/mijin/util/annot.hpp
Normal 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)
|
||||
@@ -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
|
||||
//
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user