Skip to content

Instantly share code, notes, and snippets.

@christophercrouzet
Last active November 30, 2018 12:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save christophercrouzet/b840aed577071e66b50d to your computer and use it in GitHub Desktop.
Save christophercrouzet/b840aed577071e66b50d to your computer and use it in GitHub Desktop.
Nested initializer lists for multidimensional arrays in C++11.
#ifndef MULTIDIMENSIONALARRAY_H
#define MULTIDIMENSIONALARRAY_H
#include <array>
#include <cstddef>
#include <type_traits>
// https://github.com/christophercrouzet/m3ta
#include <m3ta/nestedinitializerlists>
#include <m3ta/pass>
#include <m3ta/product>
#include "nestedinitializerlistsprocessor.h"
template<typename T, std::size_t ... T_dimensions>
class MultidimensionalArray
{
static_assert(sizeof ... (T_dimensions) > 0,
"At least one dimension needs to be defined.");
public:
static constexpr std::size_t
size()
{
return m3ta::product(T_dimensions ...);
}
MultidimensionalArray(m3ta::NestedInitializerListsT<T, 1> values)
{
initialize<size()>(values);
}
using NestedInitializerLists =
m3ta::NestedInitializerListsT<T, sizeof ... (T_dimensions)>;
template<
typename T_Dummy = T,
typename = typename std::enable_if<
(sizeof ... (T_dimensions) > 1),
m3ta::PassT<void, T_Dummy>
>::type
>
MultidimensionalArray(NestedInitializerLists values)
{
initialize<T_dimensions ...>(values);
}
using Iterator = typename std::array<T, size()>::iterator;
Iterator
begin()
{
return _data.begin();
}
Iterator
end()
{
return _data.end();
}
private:
template<std::size_t ... T_shape, typename T_NestedInitializerLists>
void
initialize(T_NestedInitializerLists values)
{
auto iterator = _data.begin();
NestedInitializerListsProcessor<T, T_shape ...>::
process(
values,
[&iterator](T value) { *(iterator++) = value; }
);
}
std::array<T, size()> _data;
};
#endif // MULTIDIMENSIONALARRAY_H
#include <chrono>
#include <iostream>
#include "multidimensionalarray.h"
int main(int argc, char **argv)
{
int loop = 10e6;
auto start = std::chrono::system_clock::now();
for (int i = 0; i < loop; ++i) {
MultidimensionalArray<int, 4, 4> array = {
{ 0, 1, 2, 3},
{ 4, 5, 6, 7},
{ 8, 9, 10, 11},
{12, 13, 14, 15}
};
}
auto end = std::chrono::system_clock::now();
auto duration = std::chrono::duration_cast<
std::chrono::milliseconds
>(end - start);
std::cout << "elapsed: " << duration.count() << "ms." << std::endl;
return 0;
}
#ifndef NESTEDINITIALIZERLISTSPROCESSOR_H
#define NESTEDINITIALIZERLISTSPROCESSOR_H
#include <algorithm>
#include <cstddef>
#include <sstream>
#include <stdexcept>
// https://github.com/christophercrouzet/m3ta
#include <m3ta/nestedinitializerlists>
#include <m3ta/product>
template<typename T, std::size_t ... T_shape>
struct NestedInitializerListsProcessor;
template<typename T, std::size_t T_first, std::size_t ... T_others>
struct NestedInitializerListsProcessor<T, T_first, T_others ...>
{
using NestedInitializerLists =
m3ta::NestedInitializerListsT<T, 1 + sizeof ... (T_others)>;
template<typename T_Function>
static void
process(NestedInitializerLists values, T_Function function)
{
if (values.size() > T_first) {
throw std::invalid_argument(
"Elements in excess within the initilizer list."
);
}
for (auto nested : values) {
NestedInitializerListsProcessor<T, T_others ...>::
process(nested, function);
}
if (values.size() < T_first) {
std::size_t count =
m3ta::Product<std::size_t, T_others ...>::value
* (T_first - values.size());
while (count-- > 0) {
function(static_cast<T>(0));
}
}
}
};
template<typename T, std::size_t T_last>
struct NestedInitializerListsProcessor<T, T_last>
{
using InitializerList = m3ta::NestedInitializerListsT<T, 1>;
template<typename T_Function>
static void
process(InitializerList values, T_Function function)
{
if (values.size() > T_last) {
std::ostringstream message;
message << "Elements in excess: "
<< "expected " << T_last << ", "
<< "got " << values.size() << ".";
throw std::invalid_argument(message.str());
}
std::for_each(values.begin(), values.end(), function);
if (values.size() < T_last) {
std::size_t count = T_last - values.size();
while (count-- > 0) {
function(static_cast<T>(0));
}
}
}
};
#endif // NESTEDINITIALIZERLISTSPROCESSOR_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment