cpp : more robust code and added more documentation

This commit is contained in:
saundersp
2024-04-27 21:08:33 +02:00
parent 45f0f6ab8e
commit c7d21e1014
10 changed files with 355 additions and 319 deletions

View File

@ -4,7 +4,7 @@
#include <cmath>
#include <cassert>
#include <functional>
#include <memory>
#include <stdint.h>
#include "config.hpp"
#define BUFFER_SIZE 256
@ -19,15 +19,6 @@ typedef float float32_t;
typedef double float64_t;
typedef long double float128_t;
__host__ __device__
constexpr inline int print(const char* str) noexcept {
return printf("%s\n", str);
}
inline int print(const std::string& s) noexcept {
return printf("%s\n", s.c_str());
}
namespace np {
constexpr const float64_t inf = std::numeric_limits<float64_t>::infinity();
@ -44,16 +35,16 @@ namespace np {
#endif
__host__ __device__
Shape() noexcept {
// #if __DEBUG
// print("Shape created (default)");
// #endif
Shape(void) noexcept {
}
__host__ __device__
Shape(const size_t& length, size_t* data) noexcept : length(length), data(data), refcount(new size_t(1)) {
Shape(const size_t& length, size_t* const data) noexcept : length(length), data(data), refcount(new size_t(1)) {
#if __DEBUG
//print("Shape created (raw)");
printf("Shape created (raw)\n");
for(size_t i = 0; i < length; ++i)
total *= data[i];
#endif
@ -64,7 +55,7 @@ namespace np {
// #if __DEBUG
// print("Shape created (initializer)");
// #endif
const size_t* begin = dims.begin();
const size_t* const begin = dims.begin();
for(size_t i = 0; i < length; ++i){
data[i] = begin[i];
#if __DEBUG
@ -76,34 +67,31 @@ namespace np {
__host__ __device__
Shape(const Shape& shape) noexcept {
#if __DEBUG
print("Shape created (copy)");
printf("Shape created (copy)\n");
#endif
if (data != nullptr && data != shape.data){
#if __DEBUG
print("Former shape deleted (copy)");
printf("Former shape deleted (copy)\n");
#endif
delete[] data;
}
if (refcount != nullptr && refcount != shape.refcount){
#if __DEBUG
print("Former shape refcount freed (copy)");
printf("Former shape refcount freed (copy)\n");
#endif
delete refcount;
}
length = shape.length;
//data = new size_t[length];
//memcpy(data, shape.data, length * sizeof(size_t));
//refcount = new size_t;
//memcpy(refcount, shape.refcount, sizeof(size_t));
data = shape.data;
refcount = shape.refcount;
if (refcount != nullptr)
(*refcount)++;
#if __DEBUG
else
print("Moved shape has null refcount");
printf("Moved shape has null refcount\n");
#endif
#if __DEBUG
total = shape.total;
#endif
}
@ -115,13 +103,13 @@ namespace np {
// #endif
if (data != nullptr && data != shape.data){
#if __DEBUG
print("Former shape deleted (move)");
printf("Former shape deleted (move)\n");
#endif
delete[] data;
}
if (refcount != nullptr && refcount != shape.refcount){
#if __DEBUG
print("Former shape refcount freed (move)");
printf("Former shape refcount freed (move)\n");
#endif
delete refcount;
}
@ -139,7 +127,7 @@ namespace np {
}
__host__ __device__
~Shape() noexcept {
~Shape(void) noexcept {
if(refcount == nullptr){
// #if __DEBUG
// print("Shape refcount freed more than once");
@ -173,34 +161,29 @@ namespace np {
__host__ __device__
Shape& operator=(const Shape& shape) noexcept {
#if __DEBUG
print("Shape created (assign copy)");
printf("Shape created (assign copy)\n");
#endif
if (data != nullptr && data != shape.data){
#if __DEBUG
print("Former shape deleted (assign copy)");
printf("Former shape deleted (assign copy)\n");
#endif
delete[] data;
}
if (refcount != nullptr && refcount != shape.refcount){
#if __DEBUG
print("Former shape refcount freed (assign copy)");
printf("Former shape refcount freed (assign copy)\n");
#endif
delete refcount;
}
length = shape.length;
// data = new size_t[length];
// memcpy(data, shape.data, length * sizeof(size_t));
// refcount = new size_t;
// memcpy(refcount, shape.refcount, sizeof(size_t));
data = shape.data;
refcount = shape.refcount;
if (refcount != nullptr)
(*refcount)++;
#if __DEBUG
else
printf("Assigned copy shape has null refcount");
printf("Assigned copy shape has null refcount\n");
total = shape.total;
#endif
return *this;
@ -213,13 +196,13 @@ namespace np {
// #endif
if (data != nullptr && data != shape.data){
#if __DEBUG
print("Former shape deleted (assign move)");
printf("Former shape deleted (assign move)\n");
#endif
delete[] data;
}
if (refcount != nullptr && refcount != shape.refcount){
#if __DEBUG
print("Former shape refcount freed (assign move)");
printf("Former shape refcount freed (assign move)\n");
#endif
delete refcount;
}
@ -228,8 +211,6 @@ namespace np {
refcount = shape.refcount;
#if __DEBUG
total = shape.total;
if (refcount == nullptr)
print("Assigned copy shape has null refcount");
shape.total = 1;
#endif
shape.length = 0;
@ -280,17 +261,16 @@ namespace np {
size_t* refcount = nullptr;
__host__ __device__
Array() noexcept {
// #if __DEBUG
// print("Array created (default)");
// #endif
Array(void) noexcept {
}
__host__ __device__
Array(const Shape& shape, T* data) noexcept : shape(shape), data(data), refcount(new size_t(1)) {
// #if __DEBUG
// print("Array created (raw, copy shape)");
// #endif
Array(const Shape& shape, T* const data) noexcept : shape(shape), data(data), refcount(new size_t(1)) {
}
__host__ __device__
@ -301,41 +281,36 @@ namespace np {
}
__host__ __device__
Array(Shape&& shape, T* data) noexcept : shape(std::move(shape)), data(data), refcount(new size_t(1)) {
// #if __DEBUG
// print("Array created (raw, move shape)");
// #endif
Array(Shape&& shape, T* const data) noexcept : shape(shape), data(data), refcount(new size_t(1)) {
}
__host__ __device__
Array(Shape&& shape) noexcept : shape(std::move(shape)), data(new T[np::prod(shape)]), refcount(new size_t(1)) {
// #if __DEBUG
// print("Array created (raw empty, move shape)");
// #endif
Array(Shape&& shape) noexcept : shape(shape), data(new T[np::prod(shape)]), refcount(new size_t(1)) {
}
__host__ __device__
Array(const Array& array) noexcept : shape(array.shape) {
#if __DEBUG
print("Array created (copy)");
printf("Array created (copy)\n");
#endif
if (data != nullptr && data != array.data){
#ifdef __debug
print("Former array deleted (move)");
#if __DEBUG
printf("Former array deleted (copy)\n");
#endif
delete[] data;
}
if (refcount != nullptr && refcount != array.refcount){
#if __DEBUG
print("Former array refcount freed (move)");
printf("Former array refcount freed (copy)\n");
#endif
delete refcount;
}
// const size_t size = np::prod(shape);
// data = new T[size];
// memcpy(data, array.data, size);
// refcount = new size_t;
// memcpy(refcount, array.refcount, sizeof(size_t));
data = array.data;
refcount = array.refcount;
@ -343,28 +318,27 @@ namespace np {
(*refcount)++;
#if __DEBUG
else
print("Moved array has null refcount");
printf("Moved array has null refcount\n");
#endif
}
__host__ __device__
Array(Array&& array) noexcept {
// #if __DEBUG
// print("Array created (move)");
// #endif
Array(Array&& array) noexcept : shape(std::move(array.shape)) {
if (data != nullptr && data != array.data){
#if __DEBUG
print("Former array deleted (move)");
printf("Former array deleted (move)\n");
#endif
delete[] data;
}
if (refcount != nullptr && refcount != array.refcount){
#if __DEBUG
print("Former array refcount freed (move)");
printf("Former array refcount freed (move)\n");
#endif
delete refcount;
}
shape = std::move(array.shape);
data = array.data;
refcount = array.refcount;
@ -373,7 +347,7 @@ namespace np {
}
__host__ __device__
~Array() noexcept {
~Array(void) noexcept {
if(refcount == nullptr){
// #if __DEBUG
// print("Array refcount freed more than once");
@ -404,36 +378,30 @@ namespace np {
__host__ __device__
Array& operator=(const Array& array) noexcept {
#if __DEBUG
print("Array created (assign copy)");
printf("Array created (assign copy)\n");
#endif
if (data != nullptr && data != array.data){
#if __DEBUG
print("Former array deleted (assign copy)");
printf("Former array deleted (assign copy)\n");
#endif
delete[] data;
}
if (refcount != nullptr && refcount != array.refcount){
#if __DEBUG
print("Former array refcount freed (assign copy)");
printf("Former array refcount freed (assign copy)\n");
#endif
delete refcount;
}
shape = array.shape;
// const size_t size = np::prod(shape) * sizeof(T);
// data = new T[size];
// memcpy(data, array.data, size);
// refcount = new size_t;
// memcpy(refcount, array.refcount, sizeof(size_t));
data = array.data;
refcount = array.refcount;
if (refcount != nullptr)
(*refcount)++;
#if __DEBUG
else
print("Assigned array has null refcount");
#endif
printf("Assigned array has null refcount\n");
return *this;
}
@ -444,13 +412,13 @@ namespace np {
// #endif
if (data != nullptr && data != array.data){
#if __DEBUG
print("Former array deleted (assign move)");
printf("Former array deleted (assign move)\n");
#endif
delete[] data;
}
if (refcount != nullptr && refcount != array.refcount){
#if __DEBUG
print("Former array refcount freed (assign move)");
printf("Former array refcount freed (assign move)\n");
#endif
delete refcount;
}
@ -485,35 +453,39 @@ namespace np {
};
template<typename T>
Array<T> empty(Shape&& shape) noexcept {
return { std::move(shape), new T[np::prod(shape)] };
inline Array<T> empty(Shape&& shape) noexcept {
return Array<T>(shape);
}
template<typename T>
Array<T> empty(const Shape& shape) noexcept {
return { std::move(shape), new T[np::prod(shape)] };
inline Array<T> empty(const Shape& shape) noexcept {
return Array<T>(shape);
}
template<typename T>
Array<T> empty(const std::initializer_list<size_t>& dims) noexcept {
const Shape shape(dims);
return { std::move(shape), new T[np::prod(shape)] };
inline Array<T> empty(const std::initializer_list<size_t>& dims) noexcept {
return Array<T>(dims);
}
template<typename T>
Array<T> zeros(Shape&& shape) noexcept {
return { std::move(shape), new T[np::prod(shape)]{0} };
Array<T> res(shape);
memset(res.data, 0, sizeof(T) * np::prod(res.shape));
return res;
}
template<typename T>
Array<T> zeros(const Shape& shape) noexcept {
return { std::move(shape), new T[np::prod(shape)]{0} };
Array<T> res(shape);
memset(res.data, 0, sizeof(T) * np::prod(res.shape));
return res;
}
template<typename T>
Array<T> zeros(const std::initializer_list<size_t>& dims) noexcept {
const Shape shape(dims);
return { std::move(shape), new T[np::prod(shape)]{0} };
Array<T> res(dims);
memset(res.data, 0, sizeof(T) * np::prod(res.shape));
return res;
}
template<typename T>
@ -773,7 +745,7 @@ constexpr np::Array<T>& map(np::Array<T>& a, const std::function<T(const size_t&
template<typename T>
__host__ __device__
constexpr inline static void swap(T* a, T* b) noexcept {
constexpr inline static void swap(T* const a, T* const b) noexcept {
if (a == b) return;
const T temp = *a;
*a = *b;
@ -805,7 +777,7 @@ void quicksort(const np::Array<T>& a) noexcept {
}
template<typename T>
static size_t as_partition(const T* a, uint16_t* indices, const size_t& l, const size_t& h) noexcept {
static size_t as_partition(const T* const a, uint16_t* const indices, const size_t& l, const size_t& h) noexcept {
size_t i = l - 1;
for (size_t j = l; j <= h; ++j)
if (a[indices[j]] < a[indices[h]])
@ -815,10 +787,10 @@ static size_t as_partition(const T* a, uint16_t* indices, const size_t& l, const
}
template<typename T>
void argsort(const T* a, uint16_t* indices, const size_t& l, const size_t& h) noexcept {
void argsort(const T* const a, uint16_t* const indices, const size_t& l, const size_t& h) noexcept {
const size_t total = h - l + 1;
size_t* stack = new size_t[total]{l, h};
size_t* const stack = new size_t[total]{l, h};
size_t top = 1, low = l, high = h;
while (top <= total) {
@ -852,16 +824,16 @@ np::Array<uint16_t> argsort(const np::Array<T>& other, const size_t& l, const si
}
template<typename T>
np::Array<uint16_t> argsort(const np::Array<T>* other, const size_t& length) noexcept {
np::Array<uint16_t> argsort(const np::Array<T>* const other, const size_t& length) noexcept {
return argsort(other, 0, length - 1);
}
std::array<np::Array<uint8_t>, 4> load_datasets(void);
void print_error_file(const char*) noexcept;
void print_error_file(const char* const) noexcept;
template<typename T>
void save(const np::Array<T>& d, const char* filename) {
FILE* output = fopen(filename, "wb");
void save(const np::Array<T>& d, const char* const filename) {
FILE* const output = fopen(filename, "wb");
if (output == NULL) {
print_error_file(filename);
throw;
@ -875,8 +847,8 @@ void save(const np::Array<T>& d, const char* filename) {
}
template<typename T>
np::Array<T> load(const char* filename) {
FILE* input = fopen(filename, "rb");
np::Array<T> load(const char* const filename) {
FILE* const input = fopen(filename, "rb");
if (input == NULL) {
print_error_file(filename);
throw;
@ -887,7 +859,7 @@ np::Array<T> load(const char* filename) {
fclose(input);
throw;
}
size_t* data = new size_t[length];
size_t* const data = new size_t[length];
if(!fread(data, sizeof(size_t), length, input)){
print_error_file(filename);
fclose(input);
@ -905,7 +877,7 @@ np::Array<T> load(const char* filename) {
#ifdef __CUDACC__
template<typename T>
np::Array<T> copyToDevice(const char* name, const np::Array<T>& array) noexcept {
np::Array<T> copyToDevice(const char* const name, const np::Array<T>& array) noexcept {
const size_t array_size = np::prod(array.shape) * sizeof(T);
const size_t shape_size = array.shape.length * sizeof(size_t);
np::Array<T> d_array;
@ -925,7 +897,7 @@ np::Array<T> copyToDevice(const char* name, const np::Array<T>& array) noexcept
}
template<typename T>
constexpr void cudaFree(const char* name, np::Array<T>& array) noexcept {
constexpr void cudaFree(const char* const name, np::Array<T>& array) noexcept {
//_print_cuda_error_(name, cudaFree(array.refcount));
//array.refcount = nullptr;
_print_cuda_error_(name, cudaFree(array.data));
@ -936,16 +908,16 @@ constexpr void cudaFree(const char* name, np::Array<T>& array) noexcept {
array.shape.data = nullptr;
}
constexpr inline void _print_cuda_error_(const char* name, const cudaError_t& err) noexcept {
constexpr inline void _print_cuda_error_(const char* const name, const cudaError_t& err) noexcept {
if (err != cudaSuccess) fprintf(stderr, "Error: %s = %d : %s\n", name, err, cudaGetErrorString(err));
}
#endif
int print(const np::Shape&) noexcept;
int print(const np::Array<uint8_t>&) noexcept;
int print(const np::Array<float64_t>&) noexcept;
int print(const np::Array<uint8_t>&, const np::Slice&) noexcept;
int print(const np::Array<uint32_t>&, const np::Slice&) noexcept;
int print(const np::Array<int32_t>&, const np::Slice&) noexcept;
int print(const np::Array<uint16_t>&, const np::Slice&) noexcept;
int print_feat(const np::Array<uint8_t>&, const np::Slice&) noexcept;
int32_t print(const np::Shape&) noexcept;
int32_t print(const np::Array<uint8_t>&) noexcept;
int32_t print(const np::Array<float64_t>&) noexcept;
int32_t print(const np::Array<uint8_t>&, const np::Slice&) noexcept;
int32_t print(const np::Array<uint32_t>&, const np::Slice&) noexcept;
int32_t print(const np::Array<int32_t>&, const np::Slice&) noexcept;
int32_t print(const np::Array<uint16_t>&, const np::Slice&) noexcept;
int32_t print_feat(const np::Array<uint8_t>&, const np::Slice&) noexcept;