Last active
November 30, 2018 12:35
-
-
Save christophercrouzet/b840aed577071e66b50d to your computer and use it in GitHub Desktop.
Nested initializer lists for multidimensional arrays in C++11.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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