How to get the length of an array in c++? - c++

I tried to write my own function for this, but I get wrong result
#include <iostream>
using namespace std;
template<typename T>
int array_length(T v[]) {
return (sizeof v)/sizeof(T);
}
int main() {
int v[] = {1, 2, 3, 4};
cout << array_length(v) << endl;
return 0;
}

Something like this:
#include <cstddef> // for size_t
template< typename T, std::size_t N >
std::size_t length( const T (&)[N] )
{
return N;
}
Usage
int data[100];
std::cout << length(data) << "\n";

The length is supplied by the array. So try this:
template <typename T, std::size_t N> std::size_t length( T (&)[N] ) {
return N;
}
std::size_t is found in header <cstddef>. It is an unsigned integer type.

Related

Can multiple parameter packs be expanded in a single expression?

I want to get a matrix from two parameter packs like the following:
template < typename T1, typename T2 > struct Multi{};
template < int ... n > struct N{};
void Print( int n ){ std::cout << n << std::endl; }
template < int ... n1, int ... n2 >
struct Multi< N<n1...>, N<n2...>>
{
Multi()
{
using expander = int[];
// No idea which syntax should be used here:
expander{ 0,((void)Print(n1...*n2),0)... };
}
};
int main()
{
Multi< N<1,2,3,4>, N< 10,20> >{};
}
The result should be
10 20 30 40 20 40 60 80
How can I do this?
No need to use the dummy arrays when you have fold expressions.
The naive (Print(n1 * n2), ...); wouldn't work (it expects the packs to have the same size, and would print N numbers instead of N2).
You need two nested fold expressions. In the inner one, you can prevent one of the packs from being expanded by passing it as a lambda parameter.
([](int n){(Print(n1 * n), ...);}(n2), ...);
This is not single expression, but you can expand it and use for loop
template < int ... n1, int ... n2 >
struct Multi< N<n1...>, N<n2...>>
{
Multi()
{
for(auto j : {n2...})
for(auto i : {n1...})
std::cout << i*j << '\n';
}
};
WandBox
I kind of assume that the output in your code is to check the compile time evaluation, since the output to std::cout only works at runtime.
Another option is not to use structs but to use constexpr functions,
they look more like regular c++ code. And you van validate the correctness at compile time using static_asserts. I did add some output at the end of my example
live demo here : https://onlinegdb.com/iNrqezstg
#include <array>
#include <iostream>
template<int... n>
constexpr auto array()
{
return std::array<int,sizeof...(n)>{n...};
};
template<std::size_t N, std::size_t M>
constexpr auto multiply(const std::array<int, N>& arr1, const std::array<int, M>& arr2)
{
std::array<int, N* M> result{};
std::size_t index{ 0 };
for (std::size_t n = 0; n < N; n++)
{
for (std::size_t m = 0; m < M; m++)
{
result[index] = arr1[n] * arr2[m];
++index;
}
}
return result;
}
template<typename container_t>
void show(const char* msg, const container_t& values)
{
std::cout << msg << " : ";
bool comma{ false };
for (const auto& value : values)
{
if (comma) std::cout << ", ";
std::cout << value;
comma = true;
}
std::cout << "\n";
}
int main()
{
constexpr auto arr1 = array<1, 2, 3, 4>();
constexpr auto arr2 = array<10, 20>();
constexpr auto result = multiply(arr1, arr2);
static_assert(arr1[0] == 1, "");
static_assert(arr2[1] == 20, "");
static_assert(result[0] == 10, "");
static_assert(result[1] == 20, "");
static_assert(result[6] == 40, "");
show("arr1", arr1);
show("arr2", arr2);
show("result", result);
return 0;
}

Obfuscate std::array using constexpr

I'm looking for a small function that is able to transform a std::array by adding increasing values. The function must be a compile time function.
I was able to write a small constexpr function which does so for an array of length 3, but I was unable to generalize it to std::arrays of arbitrary lengths. I also failed to generalize it to contain something different than chars.
Does anyone knows how to do it?
#include <array>
#include <iostream>
#include <valarray>
constexpr std::array<char,3> obfuscate(const std::array<char,3>& x) {
return std::array<char, 3>{x.at(0)+1, x.at(1) + 2, x.at(2) + 3 };
}
/* Won't compile
template<typename T,typename S, template<typename, typename> L=std::array<T, U>>
constexpr L<T,U> obfuscate(const L<T, U>& x) {
return {x.at(0) + 1, x.at(0) + 2, x.at(0) + 3 };
}
*/
std::ostream& operator<<(std::ostream& str, const std::array<char, 3>& x) {
for (auto i = 0; i < 3; i++) {
str << x.at(i);
}
return str;
}
int main(int argc, char** args) {
std::array<char, 3> x{ 'a','b','c' };
std::cout << x << std::endl;
std::cout << obfuscate(x) << std::endl;
// std::cout << obfuscate<3>(x) << std::endl;
}
You can use std::index_sequence:
template<class T, std::size_t N, std::size_t... Is>
constexpr std::array<T, N> helper (const std::array<T, N> &x, std::index_sequence<Is...>) {
return std::array<T, N>{static_cast<T>(x.at(Is)+Is+1)...};
}
template<class T, std::size_t N>
constexpr std::array<T, N> obfuscate(const std::array<T, N> &x) {
return helper(x, std::make_index_sequence<N>{});
}
There are a few methods that use tuple packs, these are great except that MSVC has a performance problem compiling large strings.
I've found this compromise works well in MSVC.
template<typename I>
struct encrypted_string;
template<size_t... I>
struct encrypted_string<std::index_sequence<I...>>
{
std::array<char, sizeof...(I)+1> buf;
constexpr static char encrypt(char c) { return c ^ 0x41; }
constexpr static char decrypt(char c) { return encrypt(c); }
constexpr explicit __forceinline encrypted_string(const char* str)
: buf{ encrypt(str[I])... } { }
inline const char* decrypt()
{
for (size_t i = 0; i < sizeof...(I); ++i)
{
buf[i] = decrypt(buf[i]);
}
buf[sizeof...(I)] = 0;
return buf.data();
}
};
#define enc(str) encrypted_string<std::make_index_sequence<sizeof(str)>>(str)
And somewhere later
auto stringo = enc(R"(
kernel void prg_PassThru_src(const global unsigned short * restrict A, int srcstepA, int srcoffsetA,
global float * restrict Beta, int srcstepBeta, int srcoffsetBeta,
int rows, int cols) {
int x = get_global_id(0);
int y0 = get_global_id(1);
if (x < cols) {
int srcA_index = mad24(y0, srcstepA / 2, x + srcoffsetA / 2);
int srcBeta_index = mad24(y0, srcstepBeta / 4, x + srcoffsetBeta / 4);
Beta[srcBeta_index] = A[srcA_index];
}
}
//somewhere later
cv::ocl::ProgramSource programSource(stringo.decrypt());
You can see this guy's talk for more sophisticated methods:
https://www.blackhat.com/docs/eu-14/materials/eu-14-Andrivet-C-plus-plus11-Metaprogramming-Applied-To-software-Obfuscation.pdf

memcmp / strcmp vs uint64_t comparisson

I have lots of strings each with size 8 or less.
I need to do lots of comparisons there using memcmp() / strcmp().
I wonder if comparisons will work faster if I convert all them to std::uint64_t. In this case, at least on theory comparison will be branch-less also will happen in single CPU operation.
Did anyone tried something similar?
Here is some test code that generate those numbers. I am assuming little endian machine.
I know code can be significantly simplified if I use htobe32() / htobe64().
#include <cstdint>
#include <algorithm> // std::reverse_copy
namespace rev_impl{
template<typename T>
T rev(const char *s){
T t;
char *pt = reinterpret_cast<char *>(&t);
std::reverse_copy(s, s + sizeof(T), pt);
return t;
}
}
inline uint32_t rev32(const char *s){
return rev_impl::rev<uint32_t>(s);
}
inline uint64_t rev64(const char *s){
return rev_impl::rev<uint64_t>(s);
}
#include <iostream>
#include <iomanip>
template<typename T>
void print_rev(const char *s){
constexpr auto w = sizeof(T) * 2;
std::cout << std::setw(w) << std::setfill('.') << std::hex << rev_impl::rev<T>(s) << '\n';
}
inline void print_rev32(const char *s){
return print_rev<uint32_t>(s);
}
inline void print_rev64(const char *s){
return print_rev<uint64_t>(s);
}
int main(){
print_rev64("\0\0\0\0\0\0\0a");
print_rev64("a\0\0\0\0\0\0\0");
print_rev32("Niki");
print_rev32("Nika");
print_rev32("Nikz");
}
here is test output:
..............61
6100000000000000
4e696b69
4e696b61
4e696b7a
If you have to convert only string literals, you can write rev to accept array of chars as follows
template <typename T, std::size_t N,
typename = typename std::enable_if<(N<=sizeof(T)+1U)>::type>
constexpr T rev (char const (&arr)[N])
{
T ret = 0;
std::size_t ui = -1;
while ( ++ui < N-1U )
ret <<= CHAR_BIT, ret |= arr[ui];
while ( ++ui < sizeof(T) )
ret <<= CHAR_BIT;
return ret;
}
Observe that, starting from C++14, this function can be defined constexpr, so you can write something as
constexpr auto fb = rev<std::uint64_t>("foobar");
The following is you code rewritten to use string literals
#include <cstdint>
#include <climits>
#include <iostream>
#include <iomanip>
#include <type_traits>
namespace rev_impl
{
template <typename T, std::size_t N,
typename = typename std::enable_if<(N<=sizeof(T)+1U)>::type>
T rev (char const (&arr)[N])
{
T ret = 0;
std::size_t ui = -1;
while ( ++ui < N-1U )
ret <<= CHAR_BIT, ret |= arr[ui];
while ( ++ui < sizeof(T) )
ret <<= CHAR_BIT;
return ret;
}
}
template <typename T, std::size_t N>
inline uint32_t rev32 (char const (&s)[N])
{ return rev_impl::rev<uint32_t>(s); }
template <typename T, std::size_t N>
inline uint64_t rev64 (char const (&s)[N])
{ return rev_impl::rev<uint64_t>(s); }
template<typename T, std::size_t N>
void print_rev (char const (&s)[N])
{
constexpr auto w = sizeof(T) * 2;
std::cout << std::setw(w) << std::setfill('.') << std::hex
<< rev_impl::rev<T>(s) << '\n';
}
template <std::size_t N>
inline void print_rev32 (char const (&s)[N])
{ return print_rev<uint32_t>(s); }
template <std::size_t N>
inline void print_rev64 (char const (&s)[N])
{ return print_rev<uint64_t>(s); }
int main ()
{
print_rev64("\0\0\0\0\0\0\0a");
print_rev64("a\0\0\0\0\0\0\0");
print_rev32("Niki");
print_rev32("Nika");
print_rev32("Nikz");
}

Is it possible to evaluate array on compilation time?

I need to store the array of first N Fibonacci numbers.
const int N = 100;
long long int fib[N] = {0};
fib[0] = 1;
fib[1] = 1;
for(int i = 2; i < N; ++i)
fib[i] = fib[i-2] + fib[i-1];
return 0;
Is it possible to make fib[] constexpr, and evaluate it at compilation time somehow ?
First of all you have to write Fibonacci algorithm in compile time version, so consider following:
template <size_t N>
struct Fibo {
static constexpr const size_t value {Fibo<N-2>::value + Fibo<N-1>::value};
};
template <>
struct Fibo<0> {
static constexpr const size_t value {1};
};
template <>
struct Fibo<1> {
static constexpr const size_t value {1};
};
and you can use this as simply as that:
std::cout << Fibo<0>::value << std::endl;
std::cout << Fibo<1>::value << std::endl;
std::cout << Fibo<2>::value << std::endl;
std::cout << Fibo<3>::value << std::endl;
std::cout << Fibo<10>::value << std::endl;
std::cout << Fibo<50>::value << std::endl;
and output values are:
1
1
2
3
89
20365011074
But this is still not you are looking for.
I do not know if you can make constexpr array (but probably there is a possibility), but you can do it slightly different. Consider:
template <size_t N>
struct Storage {
static size_t data[N+1];
};
template <size_t N> size_t Storage<N>::data[N+1] {};
template <size_t N, size_t F>
struct Filler {
static constexpr void fill () {
Storage<N>::data[F] = Fibo<F>::value;
Filler<N, F-1>::fill ();
}
};
template <size_t N>
struct Filler<N, 0> {
static constexpr void fill () {
Storage<N>::data[0] = Fibo<0>::value;
}
};
template <size_t N>
struct Calc {
static constexpr void calc () {
Filler<N, N>::fill ();
}
};
and the usage would be like this:
constexpr const size_t N = 12;
Calc<N>::calc ();
size_t* ptr = Storage<N>::data;
for (int i = 0; i <= N; ++i) {
std::cout << ptr[i] << std::endl;
}
and output:
1
1
2
3
5
8
13
21
34
55
89
144
233
What is important here is the Storage class which stores our array with appropriate number of elements.
General Filler class (with two template parameters) is used for any F value that can be passed, except value of 0. Because if we reach the 0 index, we don't want to call once again fill() member function, because we are done. So that's the reason why partial specialization of Filler class exists.
Hope I can help with this.
There is a way (ugly one), but I can't think of anything else.
#include <iostream>
#include <cmath>
constexpr unsigned long long f(int x)
{
return 1/sqrt(5)*pow(((1+sqrt(5))/2),x) - 1/sqrt(5)*pow(((1-sqrt(5))/2),x);
}
#define FIBB1(x) 1
#define FIBB2(x) FIBB1(x-1),1
#define FIBB3(x) FIBB2(x-1),f(x)
#define FIBB4(x) FIBB3(x-1),f(x)
#define FIBB5(x) FIBB4(x-1),f(x)
#define FIBB6(x) FIBB5(x-1),f(x)
#define FIBB7(x) FIBB6(x-1),f(x)
#define FIBB8(x) FIBB7(x-1),f(x)
#define FIBB9(x) FIBB8(x-1),f(x)
#define FIBB10(x) FIBB9(x-1),f(x)
#define FIBB11(x) FIBB10(x-1),f(x)
#define FIBB12(x) FIBB11(x-1),f(x)
#define FIBB13(x) FIBB12(x-1),f(x)
#define FIBB14(x) FIBB13(x-1),f(x)
#define FIBB15(x) FIBB14(x-1),f(x)
#define FIBB16(x) FIBB15(x-1),f(x)
#define FIBB17(x) FIBB16(x-1),f(x)
#define FIBB18(x) FIBB17(x-1),f(x)
#define FIBB19(x) FIBB18(x-1),f(x)
#define FIBB20(x) FIBB19(x-1),f(x)
// ...
#define FIBB93(x) FIBB92(x-1),f(x)
//#define FIBB94(x) FIBB93(x-1),f(x) //unsigned long long overflow, can't calculate more
#define FIBB(x) {FIBB##x(x)}
constexpr unsigned long long fib[93] = FIBB(93);
int main()
{
// all possible fibbonacci numbers for unsigned long long implementation
for(int i=0; i<93; ++i)
std::cout << fib[i] << std::endl;
}
I think it's the only way for C++ built-in array.
Here's a C++14 solution (GCC >= 5.0.0, Clang >= 3.5.0) using a template argument for the length. You write an imperative loop (identical to your original post) in a constexpr function. Using a disassembler, you can see the sequence is embedded into the program as raw data, even with no optimizations (-O0).
#include <array>
#include <cstddef>
#include <iostream>
#include <type_traits>
#include <utility>
namespace {
// Create an std::array from a C array (internal) via an
// std::index_sequence.
template <typename T, typename TSequence> struct MakeArrayImpl;
template <typename T, std::size_t... TIndices>
struct MakeArrayImpl<T, std::index_sequence<TIndices...>> {
static constexpr std::array<T, sizeof...(TIndices)>
make_array(T values[sizeof...(TIndices)]) {
return std::array<T, sizeof...(TIndices)>{{values[TIndices]...}};
}
};
// Create an std::array from a C array.
template <typename T, std::size_t TLength>
constexpr std::array<T, TLength> make_array(T values[TLength]) {
return MakeArrayImpl<T, std::make_index_sequence<TLength>>::make_array(
values);
}
// Return an std::array of the first numbers in the Fibonacci sequence.
template <std::size_t TLength>
constexpr std::array<long long int, TLength> fibs() {
// Original algorithm.
long long int fib[TLength] = {0};
fib[0] = 1;
fib[1] = 1;
for (std::size_t i = 2; i < TLength; ++i) {
fib[i] = fib[i - 2] + fib[i - 1];
}
return make_array<long long int, TLength>(fib);
}
}
int main() {
// Original algorithm.
const int N = 92;
long long int fib[N] = {0};
fib[0] = 1;
fib[1] = 1;
for (int i = 2; i < N; ++i)
fib[i] = fib[i - 2] + fib[i - 1];
// Test constexpr algorithm against original algorithm.
static constexpr auto values = fibs<N>();
static_assert(values.size() == N, "Expected N values in Fibs");
for (int i = 0; i < N; ++i) {
if (fib[i] != values[i]) {
std::cerr << "Mismatch at index " << i << "\n";
std::cerr << "Expected: " << fib[i] << "\n";
std::cerr << "Actual : " << values[i] << "\n";
}
}
}
In the code sample you posted, there is a decent chance that the compiler may unroll the loop, or at least part of it, on its own, if -O3 optimizations are used. Playing around on godbolt, it appears that this doesn't happen at N=100 but does at N up to about 40. In this case it does happen at compile time, whether or not it is constexpr.
Which also points out -- on many machines, long long int is not large enough to hold the 100'th fibonacci number. Fibonacci numbers grow exponentially, you should expect the 100th number to require about 100 bits or so. Your code as written will exhibit undefined behavior due to integer overflow, on a typical machine.
Using a template you can do it like this:
// Fibonacci recurrence
template <long int n>
struct fib_pair {
typedef fib_pair<n-1> prev;
static constexpr long int fib_n = prev::fib_n_plus_one;
static constexpr long int fib_n_plus_one = prev::fib_n + prev::fib_n_plus_one;
};
template <>
struct fib_pair<0> {
static constexpr long int fib_n = 0;
static constexpr long int fib_n_plus_one = 1;
};
// List structure
template <long int ... > struct list {};
// Concat metafunction
template <typename A, typename B> struct concat;
template <long int... As, long int... Bs> struct concat<list<As...>, list<Bs...>> {
typedef list<As..., Bs...> type;
};
// Get a sequence from the fib_pairs
template <long int n>
struct fib_seq {
typedef typename fib_seq<n-1>::type prev;
typedef typename concat<prev, list<fib_pair<n>::fib_n>>::type type;
};
template <>
struct fib_seq<0> {
typedef list<0> type;
};
// Make an array from pack expansion
#include <array>
template <typename T> struct helper;
template <long int ... nums>
struct helper <list<nums...>> {
typedef std::array<const long int, sizeof...(nums)> array_type;
static constexpr array_type get_array() {
return {{ nums... }};
}
};
// Easy access
template <long int n>
constexpr std::array<const long int, n + 1> get_fib_array() {
return helper<typename fib_seq<n>::type>::get_array();
}
#include <iostream>
int main () {
for (const long int x : get_fib_array<15>()) {
std::cout << x << std::endl;
}
}
Here's a C++11 solution using C++14 library features [1] (GCC >= 4.9.0, Clang >= 3.5.0) using a template argument for the length. You write a loop using recursion. Using a disassembler, you can see the sequence is embedded into the program as raw data, even with no optimizations (-O0).
[1] std::index_sequence can be implemented yourself in C++11 if it is not available in your standard library.
#include <array>
#include <cstddef>
#include <iostream>
#include <type_traits>
#include <utility>
namespace {
// Create an std::array from a C array (internal) via an
// std::index_sequence.
template <typename T, typename TSequence> struct MakeArrayImpl;
template <typename T, std::size_t... TIndices>
struct MakeArrayImpl<T, std::index_sequence<TIndices...>> {
static constexpr std::array<T, sizeof...(TIndices)>
make_array(T values[sizeof...(TIndices)]) {
return std::array<T, sizeof...(TIndices)>{{values[TIndices]...}};
}
};
// Create an std::array from a C array.
template <typename T, std::size_t TLength>
constexpr std::array<T, TLength> make_array(T values[TLength]) {
return MakeArrayImpl<T, std::make_index_sequence<TLength>>::make_array(
values);
}
// Return an std::array of the first numbers in the Fibonacci sequence.
template <std::size_t TLength>
constexpr std::array<long long int, TLength> fibs() {
// Original algorithm.
long long int fib[TLength] = {0};
fib[0] = 1;
fib[1] = 1;
for (std::size_t i = 2; i < TLength; ++i) {
fib[i] = fib[i - 2] + fib[i - 1];
}
return make_array<long long int, TLength>(fib);
}
}
int main() {
// Original algorithm.
const int N = 92;
long long int fib[N] = {0};
fib[0] = 1;
fib[1] = 1;
for (int i = 2; i < N; ++i)
fib[i] = fib[i - 2] + fib[i - 1];
// Test constexpr algorithm against original algorithm.
static constexpr auto values = fibs<N>();
static_assert(values.size() == N, "Expected N values in Fibs");
for (int i = 0; i < N; ++i) {
if (fib[i] != values[i]) {
std::cerr << "Mismatch at index " << i << "\n";
std::cerr << "Expected: " << fib[i] << "\n";
std::cerr << "Actual : " << values[i] << "\n";
}
}
}

Slicing std::array

Is there an easy way to get a slice of an array in C++?
I.e., I've got
array<double, 10> arr10;
and want to get array consisting of five first elements of arr10:
array<double, 5> arr5 = arr10.???
(other than populating it by iterating through first array)
The constructors for std::array are implicitly defined so you can't initialize it with a another container or a range from iterators. The closest you can get is to create a helper function that takes care of the copying during construction. This allows for single phase initialization which is what I believe you're trying to achieve.
template<class X, class Y>
X CopyArray(const Y& src, const size_t size)
{
X dst;
std::copy(src.begin(), src.begin() + size, dst.begin());
return dst;
}
std::array<int, 5> arr5 = CopyArray<decltype(arr5)>(arr10, 5);
You can also use something like std::copy or iterate through the copy yourself.
std::copy(arr10.begin(), arr10.begin() + 5, arr5.begin());
Sure. Wrote this:
template<int...> struct seq {};
template<typename seq> struct seq_len;
template<int s0,int...s>
struct seq_len<seq<s0,s...>>:
std::integral_constant<std::size_t,seq_len<seq<s...>>::value> {};
template<>
struct seq_len<seq<>>:std::integral_constant<std::size_t,0> {};
template<int Min, int Max, int... s>
struct make_seq: make_seq<Min, Max-1, Max-1, s...> {};
template<int Min, int... s>
struct make_seq<Min, Min, s...> {
typedef seq<s...> type;
};
template<int Max, int Min=0>
using MakeSeq = typename make_seq<Min,Max>::type;
template<std::size_t src, typename T, int... indexes>
std::array<T, sizeof...(indexes)> get_elements( seq<indexes...>, std::array<T, src > const& inp ) {
return { inp[indexes]... };
}
template<int len, typename T, std::size_t src>
auto first_elements( std::array<T, src > const& inp )
-> decltype( get_elements( MakeSeq<len>{}, inp ) )
{
return get_elements( MakeSeq<len>{}, inp );
}
Where the compile time indexes... does the remapping, and MakeSeq makes a seq from 0 to n-1.
Live example.
This supports both an arbitrary set of indexes (via get_elements) and the first n (via first_elements).
Use:
std::array< int, 10 > arr = {0,1,2,3,4,5,6,7,8,9};
std::array< int, 6 > slice = get_elements(arr, seq<2,0,7,3,1,0>() );
std::array< int, 5 > start = first_elements<5>(arr);
which avoids all loops, either explicit or implicit.
2018 update, if all you need is first_elements:
Less boilerplaty solution using C++14 (building up on Yakk's pre-14 answer and stealing from "unpacking" a tuple to call a matching function pointer)
template < std::size_t src, typename T, int... I >
std::array< T, sizeof...(I) > get_elements(std::index_sequence< I... >, std::array< T, src > const& inp)
{
return { inp[I]... };
}
template < int N, typename T, std::size_t src >
auto first_elements(std::array<T, src > const& inp)
-> decltype(get_elements(std::make_index_sequence<N>{}, inp))
{
return get_elements(std::make_index_sequence<N>{}, inp);
}
Still cannot explain why this works, but it does (for me on Visual Studio 2017).
This answer might be late... but I was just toying around with slices - so here is my little home brew of std::array slices.
Of course, this comes with a few restrictions and is not ultimately general:
The source array from which a slice is taken must not go out of scope. We store a reference to the source.
I was looking for constant array slices first and did not try to expand this code to both const and non const slices.
But one nice feature of the code below is, that you can take slices of slices...
// ParCompDevConsole.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include "pch.h"
#include <cstdint>
#include <iostream>
#include <array>
#include <stdexcept>
#include <sstream>
#include <functional>
template <class A>
class ArraySliceC
{
public:
using Array_t = A;
using value_type = typename A::value_type;
using const_iterator = typename A::const_iterator;
ArraySliceC(const Array_t & source, size_t ifirst, size_t length)
: m_ifirst{ ifirst }
, m_length{ length }
, m_source{ source }
{
if (source.size() < (ifirst + length))
{
std::ostringstream os;
os << "ArraySliceC::ArraySliceC(<source>,"
<< ifirst << "," << length
<< "): out of bounds. (ifirst + length >= <source>.size())";
throw std::invalid_argument( os.str() );
}
}
size_t size() const
{
return m_length;
}
const value_type& at( size_t index ) const
{
return m_source.at( m_ifirst + index );
}
const value_type& operator[]( size_t index ) const
{
return m_source[m_ifirst + index];
}
const_iterator cbegin() const
{
return m_source.cbegin() + m_ifirst;
}
const_iterator cend() const
{
return m_source.cbegin() + m_ifirst + m_length;
}
private:
size_t m_ifirst;
size_t m_length;
const Array_t& m_source;
};
template <class T, size_t SZ>
std::ostream& operator<<( std::ostream& os, const std::array<T,SZ>& arr )
{
if (arr.size() == 0)
{
os << "[||]";
}
else
{
os << "[| " << arr.at( 0 );
for (auto it = arr.cbegin() + 1; it != arr.cend(); it++)
{
os << "," << (*it);
}
os << " |]";
}
return os;
}
template<class A>
std::ostream& operator<<( std::ostream& os, const ArraySliceC<A> & slice )
{
if (slice.size() == 0)
{
os << "^[||]";
}
else
{
os << "^[| " << slice.at( 0 );
for (auto it = slice.cbegin() + 1; it != slice.cend(); it++)
{
os << "," << (*it);
}
os << " |]";
}
return os;
}
template<class A>
A unfoldArray( std::function< typename A::value_type( size_t )> producer )
{
A result;
for (size_t i = 0; i < result.size(); i++)
{
result[i] = producer( i );
}
return result;
}
int main()
{
using A = std::array<float, 10>;
auto idf = []( size_t i ) -> float { return static_cast<float>(i); };
const auto values = unfoldArray<A>(idf);
std::cout << "values = " << values << std::endl;
// zero copy slice of values array.
auto sl0 = ArraySliceC( values, 2, 4 );
std::cout << "sl0 = " << sl0 << std::endl;
// zero copy slice of the sl0 (the slice of values array)
auto sl01 = ArraySliceC( sl0, 1, 2 );
std::cout << "sl01 = " << sl01 << std::endl;
return 0;
}