From de7d435ccb18a3b400340706a7114476bcd89f10 Mon Sep 17 00:00:00 2001 From: NaifBanana <30419422+NaifBanana@users.noreply.github.com> Date: Fri, 30 Oct 2026 02:19:05 -0500 Subject: [PATCH] Added NDArray, did some light header and CMake restructuring --- .gitignore | 1 + CMakeLists.txt | 6 +- engine/CMakeLists.txt | 43 +++---- engine/NBCore/CMakeLists.txt | 23 ++-- engine/NBCore/include/NBCore/Arrays.hpp | 135 ++++++++++++++++++++ engine/NBCore/include/NBCore/CoreTypes.hpp | 37 ++++++ engine/NBCore/include/NBCore/DataTypes.hpp | 71 ---------- engine/NBCore/include/NBCore/ErrorsImpl.hpp | 4 +- engine/NBCore/include/NBCore/TypeTraits.hpp | 9 +- engine/NBCore/include/NBCore/Utils.hpp | 32 +---- engine/NBCore/tests/CMakeLists.txt | 1 + engine/NBCore/tests/testArrays.cpp | 73 +++++++++++ engine/NBCore/tests/testUtils.cpp | 22 +--- 13 files changed, 287 insertions(+), 170 deletions(-) create mode 100644 engine/NBCore/include/NBCore/Arrays.hpp create mode 100644 engine/NBCore/include/NBCore/CoreTypes.hpp delete mode 100644 engine/NBCore/include/NBCore/DataTypes.hpp create mode 100644 engine/NBCore/tests/testArrays.cpp diff --git a/.gitignore b/.gitignore index 90e6a2c..5d22000 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ CMakeCache.txt docs/* !docs/CMake* !docs/Doxyfile.in + diff --git a/CMakeLists.txt b/CMakeLists.txt index 2eafbf5..68b40bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,15 +56,15 @@ cmake_dependent_option(NBENGINE_INSTALL ) if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - message(STATUS "Building for Windows") + message(STATUS "Targeting Windows") set(NB_TARGET_WINDOWS ON) elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") - message(STATUS "Building for Linux") + message(STATUS "Targeting Linux") set(NB_TARGET_LINUX ON) endif() if(NB_BUILD_TESTS) - message(STATUS "Building tests") + message(STATUS "Targeting tests") enable_testing() include(FetchContent) FetchContent_Declare( diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 884d459..37ad676 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -1,30 +1,17 @@ -add_subdirectory(./NBCore) +set(NBENGINE_MODULES + NBCore + NBGraphics + NBData +) -get_target_property(NBCORE_INTERFACE_INCLUDES NBCore INTERFACE_INCLUDE_DIRECTORIES) -include_directories(${NBCORE_INTERFACE_INCLUDES}) +set(NB_INCLUDE_FILES "") +set(NB_SOURCE_FILES "") +foreach(module ${NBENGINE_MODULES}) + add_subdirectory("./${module}") + get_target_property(MODULE_INCLUDES ${module} INTERFACE_INCLUDE_DIRECTORIES) + list(APPEND NB_INCLUDE_FILES ${MODULE_INCLUDES}) + list(APPEND NB_SOURCE_FILES ${MODULE_INCLUDES}) +endforeach() +set(NB_INCLUDE_FILES ${NB_INCLUDE_FILES} PARENT_SCOPE) +set(NB_SOURCE_FILES ${NB_SOURCE_FILES} PARENT_SCOPE) -#add_subdirectory(./NBEvents) -add_subdirectory(./NBGraphics) -add_subdirectory(./NBData) - -if (NB_CORE_SOURCE OR NB_EVENTS_SOURCE OR NB_GRAPHICS_SOURCE OR NB_DATA_SOURCE) - set(NB_SOURCE_FILES "") - list(APPEND NB_SOURCE_FILES - ${NB_CORE_SOURCE} - ${NB_GRAPHICS_SOURCE} - ${NB_EVENTS_SOURCE} - ${NB_DATA_SOURCE} - ) - set(NB_SOURCE_FILES ${NB_SOURCE_FILES} PARENT_SCOPE) -endif() - -if (NB_CORE_INCLUDE OR NB_EVENTS_INCLUDE OR NB_GRAPHICS_INCLUDE OR NB_DATA_INCLUDE) - set(NB_INCLUDE_FILES "") - list(APPEND NB_INCLUDE_FILES - ${NB_CORE_INCLUDE} - ${NB_GRAPHICS_INCLUDE} - ${NB_EVENTS_INCLUDE} - ${NB_DATA_INCLUDE} - ) - set(NB_INCLUDE_FILES ${NB_INCLUDE_FILES} PARENT_SCOPE) -endif() diff --git a/engine/NBCore/CMakeLists.txt b/engine/NBCore/CMakeLists.txt index a25b7f3..1c52937 100644 --- a/engine/NBCore/CMakeLists.txt +++ b/engine/NBCore/CMakeLists.txt @@ -8,17 +8,10 @@ set(CMAKE_CXX_EXTENSIONS OFF) include(GNUInstallDirs) include(CMakePackageConfigHelpers) -toAbsolutePath(NB_CORE_SOURCE - ./src/ErrorsImpl.cpp - ./src/Logger.cpp - ./src/Processes.cpp - ./src/StringUtils.cpp - ./src/TypeTraits.cpp - ./src/Utils.cpp -) toAbsolutePath(NB_CORE_INCLUDE + ./include/NBCore/Arrays.hpp + ./include/NBCore/CoreTypes.hpp ./include/NBCore/DataSink.hpp - ./include/NBCore/DataTypes.hpp ./include/NBCore/Errors.hpp ./include/NBCore/ErrorsImpl.hpp ./include/NBCore/Logger.hpp @@ -31,10 +24,14 @@ toAbsolutePath(NB_CORE_INCLUDE ./include/NBCore/Utils.hpp ) -set(NB_CORE_SOURCE ${NB_CORE_SOURCE} PARENT_SCOPE) -set(NB_CORE_INCLUDE ${NB_CORE_INCLUDE} PARENT_SCOPE) - -add_library(NBCore ${NB_CORE_SOURCE}) +add_library(NBCore + ./src/ErrorsImpl.cpp + ./src/Logger.cpp + ./src/Processes.cpp + ./src/StringUtils.cpp + ./src/TypeTraits.cpp + ./src/Utils.cpp +) add_library(NBEngine::Core ALIAS NBCore) target_include_directories(NBCore PUBLIC "$" diff --git a/engine/NBCore/include/NBCore/Arrays.hpp b/engine/NBCore/include/NBCore/Arrays.hpp new file mode 100644 index 0000000..f60a9eb --- /dev/null +++ b/engine/NBCore/include/NBCore/Arrays.hpp @@ -0,0 +1,135 @@ +#pragma once +#ifndef _NB_DATA_TYPES +#define _NB_DATA_TYPES + +#include +#include +#include + +#include + +namespace nb { + +/*! + * @brief A multidimensional array template class + * + * */ +template +class NDArray { + public: + using Coordinate = std::array; + + private: + template + static Coordinate ProjectDimensions(const std::array& dims) { + Coordinate p; + unsigned int i=0; + if constexpr (M > N) { + std::for_each(dims.begin(), dims.end(), [&](unsigned int x){ + if (i < N) { + p[i] = x; + } else { + if (x != 1) { + THROW(Error(Error<>::VALUE_ERROR, + "Higher dimensions must have a size of 1" + )); + } + } + i++; + }); + } else if constexpr (M < N) { + p.fill(1); + std::for_each(dims.begin(), dims.end(), [&](unsigned int x) {p[i] = x; i++;}); + } else { p = dims; } + + return p; + } + + + protected: + T* _data; + static unsigned int CalculateTotalSize(const std::array& dims) { + unsigned int ret = 1; + std::for_each(dims.begin(), dims.end(), [&](unsigned int n){ + ret *= n; + }); + return ret; + } + + public: + template + friend class NDArray; + + static NDArray&& MemoryToNDArray(const Coordinate& dimensions_, T* data_) { + auto ret = NDArray(dimensions_); + ret._data = data_; + return std::move(ret); + } + + const Coordinate dimensions; + const unsigned int totalSize; + NDArray(const Coordinate& dimensions_, T* data_=nullptr) : + dimensions(dimensions_), + totalSize(CalculateTotalSize(dimensions_)) + { + if (data_) { data(data_); } + } + + + NDArray(NDArray&& arr) : + dimensions(arr.dimensions), + totalSize(arr.totalSize), + _data(std::move(arr._data)) {} + + NDArray(const NDArray& arr)=delete; + + template + NDArray(NDArray&& arr) : + dimensions(ProjectDimensions(arr.dimensions)), + totalSize(arr.totalSize), + _data(std::move(arr._data)){} + + NDArray& operator=(const NDArray& arr) = delete; + NDArray& operator=(NDArray&& arr) = delete; + ~NDArray() { + if (_data) { delete[] _data; } + }; + + unsigned int coordinateToIndex(const Coordinate& coord) const { + unsigned int blockSize = 1; + unsigned int ret = 0; + for (auto i = 0; i < dimensions.size(); ++i) { + ret += coord[i] * blockSize; + blockSize *= dimensions[i]; + } + return ret; + } + + inline NDArray& copy() const { + return NDArray(dimensions, _data); + } + inline const T& at(const Coordinate& coord) const { + return operator[](coord); + } + inline const T* data() const { return _data; } + inline const T& operator[](const Coordinate& coord) const { + return _data[coordinateToIndex(coord)]; + } + + inline T& at(const Coordinate& coord) { + return _data[coordinateToIndex(coord)]; + } + inline T* data(const T* data_) { + if (!_data) { _data = new T[totalSize]; } + std::memcpy(_data, data_, totalSize * sizeof(T)); + return _data; + } + inline T& operator[](const Coordinate& coord) { + return _data[coordinateToIndex(coord)]; + } + +}; // class NDArray + + +} // namespace nb +#endif // _NB_DATA_TYPES diff --git a/engine/NBCore/include/NBCore/CoreTypes.hpp b/engine/NBCore/include/NBCore/CoreTypes.hpp new file mode 100644 index 0000000..369fddf --- /dev/null +++ b/engine/NBCore/include/NBCore/CoreTypes.hpp @@ -0,0 +1,37 @@ +#pragma once +#ifndef _NB_CORE_TYPES +#define _NB_CORE_TYPES + +#include +#include +#include + +namespace nb { +template +using SharedVector = std::vector>; + +template +using RValueVector = std::vector; + +using ByteVector = std::vector; + +template +class ConstantMap : public std::unordered_map { + using Base = std::unordered_map; + + public: + using Base::Base; + using Base::at; + const B& operator[](const A& key) const { + return at(key); + } +}; + +enum TypeCodes { + UINT8, UINT16, UINT32, UINT64, INT8, INT16, INT32, INT64, + FLOAT16, FLOAT32, DOUBLE64, BOOL, NONE +}; + +}; // namespace nb + +#endif // _NB_NB_CORE_TYPES diff --git a/engine/NBCore/include/NBCore/DataTypes.hpp b/engine/NBCore/include/NBCore/DataTypes.hpp deleted file mode 100644 index df6640e..0000000 --- a/engine/NBCore/include/NBCore/DataTypes.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once -#include -#ifndef _NB_DATA_TYPES -#define _NB_DATA_TYPES - -#include -#include -#include - -namespace nb { - -template -class NDArray { - protected: - std::unique_ptr _data; - static unsigned int calculateTotalSize(const std::array& dims) { - unsigned int ret = 1; - std::for_each(dims.begin(), dims.end(), [&](unsigned int n){ - ret *= n; - }); - return ret; - } - - public: - const std::array dimensions; - const unsigned int totalSize; - static constexpr unsigned int NumberDimensions = N; - NDArray( - const std::array& dimensions_, - T* data_=nullptr - ) : - dimensions(dimensions_), - totalSize(calculateTotalSize(dimensions_)) - { - if (data_) { data(data_); } - } - NDArray( - const std::array& dimensions_, - const T* data_ - ) : NDArray(dimensions_) { data(data_); } - - unsigned int coordinateToIndex(const std::array& coord) const { - unsigned int blockSize = 1; - unsigned int ret = 0; - for (auto i = 0; i < dimensions.size(); ++i) { - ret += coord[i] * blockSize; - blockSize *= dimensions[i]; - } - return ret; - } - - inline const T& at(const std::array& coord) const { - return _data[coordinateToIndex(coord)]; - } - inline std::shared_ptr data() const { return _data; } - - inline T& at(const std::array& coord) { - return _data[coordinateToIndex(coord)]; - } - inline T* data(const T* data_) { - _data = std::make_unique(totalSize); - std::memcpy(_data.get(), data_, totalSize * sizeof(T)); - return _data.get(); - } - - - -}; // namespace nb - -} -#endif // _NB_DATA_TYPES diff --git a/engine/NBCore/include/NBCore/ErrorsImpl.hpp b/engine/NBCore/include/NBCore/ErrorsImpl.hpp index e1f1cdc..96174de 100644 --- a/engine/NBCore/include/NBCore/ErrorsImpl.hpp +++ b/engine/NBCore/include/NBCore/ErrorsImpl.hpp @@ -8,7 +8,7 @@ #include #include -#include +#include namespace nb { @@ -168,4 +168,4 @@ Error(Args...) -> Error; } // namespace nb -#endif // _NB_ERRORS_IMPL \ No newline at end of file +#endif // _NB_ERRORS_IMPL diff --git a/engine/NBCore/include/NBCore/TypeTraits.hpp b/engine/NBCore/include/NBCore/TypeTraits.hpp index 1ac3dfa..585bbb2 100644 --- a/engine/NBCore/include/NBCore/TypeTraits.hpp +++ b/engine/NBCore/include/NBCore/TypeTraits.hpp @@ -5,6 +5,8 @@ #include #include +#include + namespace nb { namespace detail { @@ -33,11 +35,6 @@ namespace detail { template std::pair KeyVal(K key, V val) { return std::pair(key, val); } -enum TypeCodes { - UINT8, UINT16, UINT32, UINT64, INT8, INT16, INT32, INT64, - FLOAT16, FLOAT32, DOUBLE64, BOOL, NONE -}; - template static constexpr TypeCodes GetTypeEnum = NONE; @@ -137,4 +134,4 @@ struct Find { } // namespace nb -#endif // _NB_TYPE_TRAITS \ No newline at end of file +#endif // _NB_TYPE_TRAITS diff --git a/engine/NBCore/include/NBCore/Utils.hpp b/engine/NBCore/include/NBCore/Utils.hpp index e0c8e1d..117a798 100644 --- a/engine/NBCore/include/NBCore/Utils.hpp +++ b/engine/NBCore/include/NBCore/Utils.hpp @@ -2,34 +2,13 @@ #ifndef _NB_UTILTIES #define _NB_UTILTIES -#include -#include #include -// #include +#include +#include namespace nb { -template -class ConstantMap : public std::unordered_map { - using Base = std::unordered_map; - - public: - using Base::Base; - using Base::at; - const B& operator[](const A& key) const { - return at(key); - } -}; - -template -using SharedVector = std::vector>; - -template -using RValueVector = std::vector; - -using ByteVector = std::vector; - /* class ObjectManagerError : public Error { using Base = Error; @@ -67,11 +46,10 @@ ByteVector concatVectorBytes(const std::vector& vec1, const std::vector& v template std::vector bytesToVector(const ByteVector& vec) { if (vec.size() % sizeof(T) != 0) { -/* THROW(Error( + THROW(Error( std::runtime_error("Data size does not align to std::vector<" + std::string(typeid(T).name()) + ">.") - )); */ - throw "byyyyeeee"; - } + )); + } unsigned int num_elmts = vec.size() / sizeof(T); std::vector ret(num_elmts); memcpy(ret.data(), vec.data(), vec.size()); diff --git a/engine/NBCore/tests/CMakeLists.txt b/engine/NBCore/tests/CMakeLists.txt index 030154d..859c5a6 100644 --- a/engine/NBCore/tests/CMakeLists.txt +++ b/engine/NBCore/tests/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.26.0) enable_testing() include(GoogleTest) add_executable(TestCore + ./testArrays.cpp ./testErrors.cpp #./testProcesses.cpp ./testUtils.cpp diff --git a/engine/NBCore/tests/testArrays.cpp b/engine/NBCore/tests/testArrays.cpp new file mode 100644 index 0000000..41aef16 --- /dev/null +++ b/engine/NBCore/tests/testArrays.cpp @@ -0,0 +1,73 @@ +#define CODE_ERROR_LOCATIONS +#include + +#include + +template +using Coord = typename nb::NDArray::Coordinate; + +template +void ASSERT_ARRAY_EQ(A a, B b) { + unsigned int n = a.size(); + for (int i = 0; i < n; ++i) { + ASSERT_EQ(a[i], b[i]); + } +} + +TEST(TestNDArray, TestBasic) { + float* data_f = new float[9] {0,1,2,3,4,5,6,7,8}; + nb::NDArray arr({3, 3}, data_f); + Coord<2> x{1,1}; + ASSERT_ARRAY_EQ(arr.dimensions, Coord<2>{3,3}); + ASSERT_FLOAT_EQ(data_f[4], arr.at(x)); + arr.at(x) = 0.5; + ASSERT_FLOAT_EQ(0.5, arr.at(x)); + delete[] data_f; + + Coord<3> y{1,0,1}; + unsigned int* data_ui = new unsigned int[8] {0,1,2,3,4,5,6,7}; + nb::NDArray arr3d({2,2,2}, data_ui); + ASSERT_ARRAY_EQ(arr3d.dimensions, Coord<3>{2,2,2}); + ASSERT_EQ(data_ui[5], arr3d.at(y)); + arr3d[{0,1,1}] = 23; + ASSERT_EQ(23, arr3d.at({0,1,1})); + delete[] data_ui; + + nb::NDArray arr4d({4,4,4,4}); + arr4d[{0,1,2,3}] = 57; + ASSERT_ARRAY_EQ(arr4d.dimensions, Coord<4>{4,4,4,4}); + ASSERT_EQ(57, arr4d.at({0,1,2,3})); +} + +TEST(TestNDArray, TestMove) { + unsigned int data_ui[8] = {0,1,2,3,4,5,6,7}; + nb::NDArray arr_1({4, 2}, data_ui); + nb::NDArray arr_2(std::move(arr_1)); + Coord<2> x{2, 1}; + ASSERT_EQ(arr_1.data(), nullptr); + ASSERT_ARRAY_EQ(arr_1.dimensions, arr_2.dimensions); + ASSERT_EQ(arr_2.at(x), 6); +} + +TEST(TestNDArray, TestConversion) { + nb::NDArray arr1({3,3}); + nb::NDArray arr2(std::move(arr1)); + ASSERT_EQ(arr1.data(), nullptr); + ASSERT_ARRAY_EQ(arr2.dimensions, Coord<3>{3,3,1}); + nb::NDArray arr3(std::move(arr2)); + ASSERT_EQ(arr2.data(), nullptr); + ASSERT_ARRAY_EQ(arr3.dimensions, Coord<2>{3,3}); +} + +TEST(TestNDArray, TestFromMemory) { + auto data = new float[9]{1,2,3,4,5,6,7,8,9}; + auto arr1 = nb::NDArray::MemoryToNDArray({3,3}, data); + ASSERT_EQ(arr1.data(), data); + ASSERT_FLOAT_EQ(arr1.at({1,2}), data[5]); + auto data2 = new float[9]{9,8,7,6,5,4,3,2,1}; + arr1.data(data2); + ASSERT_EQ(arr1.data(), data); + ASSERT_FLOAT_EQ(arr1.at({3,0}), data2[6]); + delete[] data2; +} + diff --git a/engine/NBCore/tests/testUtils.cpp b/engine/NBCore/tests/testUtils.cpp index 2d927f4..a78f0ea 100644 --- a/engine/NBCore/tests/testUtils.cpp +++ b/engine/NBCore/tests/testUtils.cpp @@ -3,9 +3,9 @@ #include #include -#include -#include #include +#include +#include namespace nb { @@ -107,22 +107,4 @@ TEST(UtilsTest, TestIsDetected) { ASSERT_TRUE(ret); } -TEST(DataTypesTests, TestNDArray) { - float* data_f = new float[9] {0,1,2,3,4,5,6,7,8}; - nb::NDArray arr({3, 3}, data_f); - ASSERT_FLOAT_EQ(data_f[4], arr.at({1,1})); - arr.at({1,1}) = 0.5; - ASSERT_FLOAT_EQ(0.5, arr.at({1,1})); - delete[] data_f; - - unsigned int* data_ui = new unsigned int[8] {0,1,2,3,4,5,6,7}; - nb::NDArray arr3d({2,2,2}, data_ui); - ASSERT_EQ(data_ui[5], arr3d.at({1,0,1})); - arr3d.at({0,1,1}) = 23; - ASSERT_EQ(23, arr3d.at({0,1,1})); - delete[] data_ui; - - -} - } // namespace nb