Skip to content

DIGarnier/nd_array

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nd_array

A modern, high-performance n-dimensional array implementation using C++20/23 features.

Features

Modern C++ (C++20/23)

  • C++20 Concepts: Type-safe template constraints with clear error messages
  • Requires Clauses: Compile-time validation of template parameters
  • Spaceship Operator (<=>): Full comparison support with auto-generated operators
  • consteval: Compile-time only functions for zero runtime overhead
  • C++23 Multidimensional Subscript: array[x, y, z] syntax (when available)

Performance Optimizations

  • Static constexpr steps: Stride calculations computed once at compile-time, zero per-instance overhead
  • Compiler-friendly inlining: Small hot path functions optimized for automatic inlining
  • [[nodiscard]]: Prevents accidental value discards
  • Zero-overhead abstraction: Fully constexpr, no runtime cost for multidimensional indexing

API Features

  • Iterator support: Compatible with STL algorithms and range-based for loops
  • Type aliases: Standard container-like interface
  • Checked and unchecked access: at() for safety, unsafe_at() for performance
  • Dimension introspection: Query dimension count and sizes at compile-time
  • Aggregate initialization: Direct brace initialization with compile-time size validation

Usage

Basic Example

#include "nd_array.h"

constexpr int xMax = 2;
constexpr int yMax = 2;
constexpr int zMax = 2;

constexpr auto ndarray = nd_array<int, xMax, yMax, zMax>{
    1, 2,
    3, 4,

    5, 6,
    7, 8,
};

// Compile-time validation
static_assert(ndarray.at(0,0,0) == 1);
static_assert(ndarray.at(1,0,0) == 2);
static_assert(ndarray.at(0,1,0) == 3);
static_assert(ndarray.at(1,1,0) == 4);

static_assert(ndarray.at(0,0,1) == 5);
static_assert(ndarray.at(1,0,1) == 6);
static_assert(ndarray.at(0,1,1) == 7);
static_assert(ndarray.at(1,1,1) == 8);

Advanced Features

// Iterator support - works with STL algorithms
auto arr = nd_array<int, 3, 3>{1,2,3,4,5,6,7,8,9};

// Range-based for loop
for (const auto& elem : arr) {
    std::cout << elem << " ";
}

// STL algorithms
auto sum = std::accumulate(arr.begin(), arr.end(), 0);
auto max = *std::max_element(arr.begin(), arr.end());

// Dimension introspection
static_assert(arr.dimension_count() == 2);
static_assert(arr.dimension_size(0) == 3);
static_assert(arr.dimension_size(1) == 3);

// Comparisons (C++20 spaceship operator)
auto arr1 = nd_array<int, 2, 2>{1, 2, 3, 4};
auto arr2 = nd_array<int, 2, 2>{1, 2, 3, 4};
static_assert(arr1 == arr2);
static_assert(arr1 <= arr2);

// Performance-critical unchecked access
constexpr auto value = arr.unsafe_at(1, 1);  // No bounds checking

Type Safety

// Concepts ensure only arithmetic types are allowed
nd_array<int, 2, 2> int_array{};        // OK
nd_array<double, 2, 2> float_array{};   // OK
nd_array<std::string, 2, 2> str_array{};  // Compile error: requires Arithmetic

// Compile-time dimension validation
constexpr auto arr = nd_array<int, 2, 3>{1,2,3,4,5,6};
arr.at(0, 0);     // OK
arr.at(0, 0, 0);  // Compile error: wrong number of indices

Technical Details

Memory Layout

  • Inherits from std::array<T, (N * ...)> for optimal memory layout
  • No virtual functions, no vtable overhead
  • Contiguous memory storage in row-major order

Compile-Time Optimizations

  • All dimension calculations happen at compile-time using consteval
  • Index stride calculations are static constexpr (computed once per type)
  • Full constexpr support for compile-time array operations

Requirements

  • C++20 or later
  • Compiler support for:
    • Concepts and requires clauses
    • consteval
    • Spaceship operator
    • (Optional) C++23 multidimensional subscript for operator[] syntax

Building

# C++20 build
g++ -std=c++20 -Wall -Wextra -O3 -o main main.cpp

# With C++23 features
g++ -std=c++23 -Wall -Wextra -O3 -o main main.cpp

Modernization & Optimizations Applied

Modernization

  1. ✅ Replaced uint32_t with std::size_t for better portability
  2. ✅ Added C++20 concepts (Arithmetic, Integral) for type safety
  3. ✅ Added requires clauses for compile-time validation
  4. ✅ Implemented C++20 spaceship operator for comparisons
  5. ✅ Used consteval for compile-time only functions
  6. ✅ Added C++23 multidimensional subscript operator
  7. ✅ Added [[nodiscard]] attributes
  8. ✅ Exposed iterator interface for range-based operations
  9. ✅ Added standard container type aliases

Optimizations

  1. ✅ Made steps array static constexpr (no per-instance storage)
  2. ✅ Removed redundant seq member variable
  3. ✅ Optimized hot path functions for automatic compiler inlining
  4. ✅ Improved make_steps() with consteval and if constexpr
  5. ✅ Made all helper functions static to avoid this pointer overhead
  6. ✅ Used std::index_sequence_for to generate sequences on-demand
  7. ✅ Optimized index calculation with fold expressions

Performance Impact

  • Memory: Reduced per-instance size by ~32 bytes (removed seq and made steps static)
  • Compile-time: More work at compile-time, zero runtime overhead
  • Runtime: Identical or better performance due to better inlining and optimizations
  • Type safety: Better error messages and compile-time guarantees

License

Public domain / MIT - use as you wish!

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •