From 4d645c7ae610fac4dffddc38891ba2c42dc47124 Mon Sep 17 00:00:00 2001 From: James N <59348282+RandomSpaceship@users.noreply.github.com> Date: Tue, 24 Dec 2024 16:24:43 +1000 Subject: [PATCH] ptr-wrapper: Initial implementation --- software/shared/overlay.nix | 1 + software/shared/ptr-wrapper/CMakeLists.txt | 83 +++++++++++++++++++ software/shared/ptr-wrapper/config.cmake.in | 1 + software/shared/ptr-wrapper/default.nix | 17 ++++ .../ptr-wrapper/include/ptr_wrapper.hpp | 83 +++++++++++++++++++ .../shared/ptr-wrapper/src/ptr_wrapper.cpp | 1 + 6 files changed, 186 insertions(+) create mode 100644 software/shared/ptr-wrapper/CMakeLists.txt create mode 100644 software/shared/ptr-wrapper/config.cmake.in create mode 100644 software/shared/ptr-wrapper/default.nix create mode 100644 software/shared/ptr-wrapper/include/ptr_wrapper.hpp create mode 100644 software/shared/ptr-wrapper/src/ptr_wrapper.cpp diff --git a/software/shared/overlay.nix b/software/shared/overlay.nix index 8b6061d..2347123 100644 --- a/software/shared/overlay.nix +++ b/software/shared/overlay.nix @@ -3,4 +3,5 @@ final: prev: { hi-can = final.callPackage ./hi-can { }; hi-can-raw = final.callPackage ./hi-can-raw { }; hi-can-net = final.callPackage ./hi-can-net { }; + ptr-wrapper = final.callPackage ./ptr-wrapper { }; } diff --git a/software/shared/ptr-wrapper/CMakeLists.txt b/software/shared/ptr-wrapper/CMakeLists.txt new file mode 100644 index 0000000..32bf532 --- /dev/null +++ b/software/shared/ptr-wrapper/CMakeLists.txt @@ -0,0 +1,83 @@ +# PROJECT SETUP +cmake_minimum_required(VERSION 3.23) + +project( + ptr_wrapper + VERSION 0.0.1 + LANGUAGES CXX) + +# credit https://www.kitware.com/cmake-and-the-default-build-type/ +set(default_build_type "Debug") +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message( + STATUS + "Setting build type to '${default_build_type}' as none was specified.") + set(CMAKE_BUILD_TYPE + "${default_build_type}" + CACHE STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" + "MinSizeRel" "RelWithDebInfo") +endif() +# we always want debug info for stack tracing, so switch to RelWithDebInfo from +# Release +if(CMAKE_BUILD_TYPE STREQUAL "Release") + set(CMAKE_BUILD_TYPE "RelWithDebInfo") +endif() +message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() +# Add -Werror flag for release builds +if(CMAKE_BUILD_TYPE MATCHES "Rel.*") + add_compile_options(-Werror) +endif() + +# Set the C++ standard +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# COMPILE (Libraries) + +# Find all source files in the src directory +file(GLOB_RECURSE CODE_SOURCES src/*.cpp) +# Add the target with those sources +add_library(${PROJECT_NAME} SHARED ${CODE_SOURCES}) +# Set the include directories for the library +target_include_directories( + ${PROJECT_NAME} PUBLIC $ + $) + +# INSTALL (Libraries) +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +# CMake packaging - see https://blog.vito.nyc/posts/cmake-pkg/ for a good +# explanation +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake @ONLY) +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake + COMPATIBILITY SameMinorVersion) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}) + +# Headers +install(DIRECTORY include/ DESTINATION include/${PROJECT_NAME}) + +# Versioning +set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION}) +# The main install - default locations are fine +install( + TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}_targets + ARCHIVE + LIBRARY + RUNTIME) + +# The last of the CMake packaging info +install(EXPORT ${PROJECT_NAME}_targets + DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}) diff --git a/software/shared/ptr-wrapper/config.cmake.in b/software/shared/ptr-wrapper/config.cmake.in new file mode 100644 index 0000000..1d5ac03 --- /dev/null +++ b/software/shared/ptr-wrapper/config.cmake.in @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@_targets.cmake) diff --git a/software/shared/ptr-wrapper/default.nix b/software/shared/ptr-wrapper/default.nix new file mode 100644 index 0000000..1e89253 --- /dev/null +++ b/software/shared/ptr-wrapper/default.nix @@ -0,0 +1,17 @@ +{ + stdenv, + cleanCmakeSource, + cmake, +}: + +stdenv.mkDerivation rec { + pname = "ptr-wrapper"; + version = "0.0.1"; + + src = cleanCmakeSource { + src = ./.; + name = pname; + }; + + nativeBuildInputs = [ cmake ]; +} diff --git a/software/shared/ptr-wrapper/include/ptr_wrapper.hpp b/software/shared/ptr-wrapper/include/ptr_wrapper.hpp new file mode 100644 index 0000000..f1ba444 --- /dev/null +++ b/software/shared/ptr-wrapper/include/ptr_wrapper.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include +#include + +/// @brief A wrapper around a pointer which will automatically deallocate the resource when it goes out of scope +/// @details Intended for use in situations where @ref shared_ptr can't be used, such as when the resource is not allocated with `new` +template +class PtrWrapper +{ +public: + PtrWrapper() = default; + PtrWrapper(T* ptr, std::function deallocator) + : PtrWrapper([ptr](void) + { return ptr; }, deallocator) {} + PtrWrapper(std::function allocator, std::function deallocator) + : _deallocator(deallocator) + { + if (!allocator) + throw std::invalid_argument("Allocator must be provided"); + if (!deallocator) + throw std::invalid_argument("Deallocator must be provided"); + _ptr = allocator(); + } + + ~PtrWrapper() + { + try + { + if (_ptr) + _deallocator(_ptr); + } + catch (...) + { + // ignore - since we're in a destructor, we can't throw + } + } + + // we do NOT want to allow copying, that doesn't make sense. + // Moving is OK though + PtrWrapper(const PtrWrapper&) = delete; + PtrWrapper(PtrWrapper&& other) noexcept + { + swap(*this, other); + } + PtrWrapper& operator=(PtrWrapper) = delete; + PtrWrapper& operator=(PtrWrapper&& other) noexcept + { + swap(*this, other); + return *this; + } + + PtrWrapper& operator=(T* ptr) + { + if (_ptr) + _deallocator(_ptr); + _ptr = ptr; + return *this; + } + + T** operator&() + { + return &_ptr; + } + + friend void swap(PtrWrapper& first, PtrWrapper& second) + { + using std::swap; + swap(first._ptr, second._ptr); + swap(first._deallocator, second._deallocator); + } + + // allow all the common methods of getting the file descriptor/"dereferencing" + virtual inline explicit operator T*() const { return get(); } + virtual inline T* operator*() const { return get(); } + virtual inline T* operator->() const { return get(); } + virtual inline T* get() const { return _ptr; } + +private: + T* _ptr = nullptr; + + std::function _deallocator = nullptr; +}; \ No newline at end of file diff --git a/software/shared/ptr-wrapper/src/ptr_wrapper.cpp b/software/shared/ptr-wrapper/src/ptr_wrapper.cpp new file mode 100644 index 0000000..187f45f --- /dev/null +++ b/software/shared/ptr-wrapper/src/ptr_wrapper.cpp @@ -0,0 +1 @@ +#include "ptr_wrapper.hpp" \ No newline at end of file