Skip to content

Instantly share code, notes, and snippets.

@DBJDBJ
Last active Nov 18, 2021
Embed
What would you like to do?
Very simple but light and probably fast 2D array. C++17. Version 6. Types left in here, from std lib are in just for testing code. Used Visual Studio 2019 and clang-cl .
#define DBJ_MTX_TESTING
// (c) 2019-2021 by dbj@dbj.org
// License: CC BY SA 4.0
#include <assert.h>
#include <stdlib.h>
#include <string.h> // memcpy
namespace dbj::mtx {
enum class version { major = 6, minor = 1, patch = 0 };
// the limits
constexpr auto MAX_STACK_BLOCK = 0xFF;
constexpr auto MAX_HEAP_BLOCK = 0xFFFF;
// we do not need std::array
template< typename T, size_t N >
inline auto simple_stack() noexcept {
static_assert(N < MAX_STACK_BLOCK, "max stack block is 0xFF");
T buff_[N]{};
return[buff_, size = N](size_t const& idx) mutable->T& {
assert(idx < size);
return buff_[idx];
};
}
// and we do not need std::vector too
template< typename T, size_t N >
inline auto simple_heap() noexcept
{
static_assert(N < MAX_HEAP_BLOCK, "max heap_block_type block is 0xFFFF");
// Q: is this machinery really needed?
// A: yes it is, proper copy and move struct with pointer member is the only way
// also the destructor in here is the only way this is free'd
struct heap_block_type
{
size_t size{ N };
// this has to be proper copy/move able struct
// seeing bellow compiler does not know the block size
T* block{};
heap_block_type() noexcept : block((T*)calloc(N, sizeof(T))) { assert(block); }
~heap_block_type() noexcept { if (block) { free(block); block = nullptr; } }
void copy(heap_block_type & left, heap_block_type const& right) noexcept {
assert(left.block);
assert(left.size == right.size);
::memcpy(left.block, right.block, left.size);
}
heap_block_type(heap_block_type const& other_) noexcept : block((T*)calloc(N, sizeof(T))) {
copy(*this, other_);
}
heap_block_type & operator = (heap_block_type const& other_) noexcept {
copy(*this, other_); return *this;
}
void swap(heap_block_type & left, heap_block_type & right) noexcept {
using namespace std;
left.size = right.size;
left.block = right.block;
right.block = nullptr;
}
heap_block_type(heap_block_type&& other_) noexcept {
swap(*this, other_);
}
heap_block_type& operator = (heap_block_type && other_) noexcept {
swap(*this, other_); return *this;
}
};
return[heap_instance_ = heap_block_type{}, size = N](size_t const& idx) mutable->T& {
assert(idx < size);
return heap_instance_.block[idx];
};
} // simple_heap()
template< typename T, size_t rows, size_t cols, typename F >
inline constexpr auto mx(F source_)
{
// source_ has to be callable
// lambda is local class
// arry will be a member of that class
return[arry = source_()]
// and this will be a function call operator on that class
(size_t row_, size_t col_) mutable->T&
{
assert(row_ < rows); // from here we reach the template args
assert(col_ < cols); // of the immediate closure
return arry(row_ * rows + col_);
};
} // mx()
#undef dbj_mx_make
#undef dbj_mx_make_heap
#undef dbj_mx_make_stack
#define dbj_mx_make(T, R, C, K) dbj::mtx::mx<T, R, C>(dbj::mtx::K<T, (R+1) * (C+1)>)
#define dbj_mx_make_heap(T,R,C) dbj_mx_make(T, R, C, simple_heap)
#define dbj_mx_make_stack(T,R,C) dbj_mx_make(T, R, C, simple_stack)
} // dbj::mtx
///
/// Testing
///
#ifdef DBJ_MTX_TESTING
#include <iomanip> // setw
#include <sstream>
#include <iostream>
namespace dbj::mtx {
inline auto changer = [](auto matrix_, size_t row_, size_t col_, auto value_) {
matrix_(row_, col_) = value_;
return matrix_;
};
// print to buffer
// NOTE: compared to C, this is almost tragi-comical code
inline auto
printer = [](auto matrix_, size_t width_, size_t height_)
-> std::string {
using namespace std;
std::ostringstream rez_;
rez_ << std::boolalpha ;
for (size_t row_ = 0; row_ < width_; row_++) {
rez_ << "\n";
for (size_t col_ = 0; col_ < height_; col_++) {
rez_ << setw(3) << matrix_(row_, col_) << " ";
}
}
rez_ << "\n";
return rez_.str();
};
///
/// log callback signature:
/// void (*)( std::string_view )
///
template<
typename log_callback,
typename value_type ,
size_t width_ = 3, // 0,1,2
size_t height_ = 3, // 0,1,2
size_t last_col_ = width_ - 1, // 0,1,2
size_t last_row_ = height_ - 1 // 0,1,2
>
inline void test_dbj_matrix_creation(log_callback log, value_type const& val_)
{
using namespace dbj::mtx;
using namespace std;
// test move in, move out and the rest
auto reporter = [&](auto matrix_, const char* prompt_) {
string report = prompt_ +
printer(changer(matrix_, last_col_, last_row_, val_), width_, height_);
log(report);
return matrix_;
};
auto stack_mx_ = reporter(dbj_mx_make_stack(value_type, width_, height_),
"\n matrix_on_stack \n");
auto heap_mx_ = reporter(dbj_mx_make_heap(value_type, width_, height_),
"\n matrix_on_heap \n");
}
} // dbj::mtx
// log callback signature: void (*)( std::string_view )
void log_(std::string_view sv)
{
printf("%s", sv.data());
}
int main(void)
{
dbj::mtx::test_dbj_matrix_creation(log_, 42);
dbj::mtx::test_dbj_matrix_creation(log_, true);
return 42;
}
#endif // DBJ_MTX_TESTING
@DBJDBJ
Copy link
Author

DBJDBJ commented Mar 16, 2021

Please read this https://dbj.org/lambda-powered-matrix/ beforehand

@DBJDBJ
Copy link
Author

DBJDBJ commented Jul 23, 2021

Copied over the source from: https://godbolt.org/z/v1zhb7Er8

@DBJDBJ
Copy link
Author

DBJDBJ commented Nov 18, 2021

6.1 -- testing completely decoupled

Godbolt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment