compilation-bundle/dwarf-compilation.base/contrib/libsrk31cxx/include/srk31/array.hpp

223 lines
5.9 KiB
C++

#ifndef LIBSRK31CXX_ARRAY_HPP_
#define LIBSRK31CXX_ARRAY_HPP_
#include <cstdlib>
namespace srk31 {
/* This is (perhaps) the thinnest possible wrapper around C-style arrays in C++,
* designed with one goal only: to implement objects that may be returned by value
* from a function, but are otherwise interchangeable with C-style arrays. */
template <typename El, int Dim>
class array
{
El a[Dim];
typedef El raw_array[Dim];
typedef raw_array& raw_array_ref;
typedef raw_array const& raw_array_const_ref;
public:
El& operator[](int ind) { return a[ind]; }
const El& operator[](int ind) const { return a[ind]; }
// constructors
array(){}
array(const array<El, Dim>& o)
{
for (int i = 0; i < Dim; ++i) a[i] = o[i];
}
array(const raw_array& o)
{
for (int i = 0; i < Dim; ++i) a[i] = o[i];
}
operator raw_array_ref() { return a; }
operator raw_array_const_ref() const { return a; }
// I would like to have these,
// so we can just call f(my_array) for f(El *) { ... }, BUT
// they make calls to function_taking_array (below) ambiguous
// and the reference-based options (above) win, because
// they are more type-safe (although more restricted)
//operator El* () { return &a[0]; }
//operator El const* () const { return &a[0]; }
};
template <typename El>
class array<El, 0>
{
// typedef El raw_array[];
// typedef raw_array& raw_array_ref;
// typedef raw_array const& raw_array_const_ref;
public:
El& operator[](int ind) { if (ind != 0) abort(); return reinterpret_cast<El&>(this); }
const El& operator[](int ind) const { if (ind != 0) abort(); return reinterpret_cast<El&>(this); }
// constructors
array(){}
array(const array<El, 0>& o)
{
}
//array(const raw_array& o)
//{
//}
//operator raw_array_ref() { return &(*this)[0]; }
//operator raw_array_const_ref() const { return &(*this)[0]; }
};
template <typename El, int Dim>
class array_wrapper;
/* We will define a tail() template for array_wrappers. */
template <typename El, int Dim>
inline
array_wrapper<El, Dim - 1>
tail(array_wrapper<El, Dim>);
/* This is similar, but doesn't include any storage of its own. Rather,
* it provides an interface around some preexisting array. It's necessary
* when you want to assign to an array from an srk31::array or another array. */
template <typename El, int Dim>
class array_wrapper
{
typedef El wrapped_type[Dim];
wrapped_type& storage;
typedef El raw_array[Dim];
typedef raw_array& raw_array_ref;
typedef raw_array const& raw_array_const_ref;
public:
El& operator[](int ind) { return storage[ind]; }
const El& operator[](int ind) const { return storage[ind]; }
// constructors -- unlike array, these don't copy!
// there is no default constructor, and no copy-from-object
explicit array_wrapper(raw_array& o) : storage(o) {}
explicit array_wrapper(srk31::array<El, Dim>& obj) : storage(obj) {}
// there *is* an assignment operator
array_wrapper& operator=(const wrapped_type& arg)
{
for (int i = 0; i < Dim; ++i) storage[i] = arg[i];
return *this;
}
operator raw_array_ref() { return storage; }
operator raw_array_const_ref() const { return storage; }
template <typename El_, int Dim_>
friend
struct tail_t;
};
template <typename El>
class array_wrapper<El, 0>
{
typedef void wrapped_type;
wrapped_type *p_storage;
// typedef El raw_array[];
// typedef raw_array& raw_array_ref;
// typedef raw_array const& raw_array_const_ref;
public:
El& operator[](int ind) { if (ind != 0) abort(); return *reinterpret_cast<El *>(p_storage); }
const El& operator[](int ind) const { if (ind != 0) abort(); return *reinterpret_cast<El *>(p_storage); }
// constructors -- unlike array, these don't copy!
// there is no default constructor, and no copy-from-object
template <typename T>
explicit array_wrapper(T& o) : p_storage(&o) {}
explicit array_wrapper(srk31::array<El, 0>& obj) : p_storage(&obj) {}
//operator raw_array_ref() { return storage; }
// operator raw_array_const_ref() const { return storage; }
};
/* helper construct from array */
template <typename El, int Dim>
srk31::array_wrapper<El, Dim> make_array_wrapper(El (&from)[Dim])
{
return array_wrapper<El, Dim>(from);
}
/* helper to make tail (suffix) array_wrapper */
template <typename El, int Dim>
struct tail_t
{
static array_wrapper<El, Dim - 1>
get(array_wrapper<El, Dim> arg)
{
typedef El tail_wrapped_type[Dim - 1];
return array_wrapper<El, Dim - 1>(*reinterpret_cast<tail_wrapped_type*>(&arg.storage[1]));
}
};
template <typename El>
struct tail_t<El, 1>
{
static array_wrapper<El, 0>
get(array_wrapper<El, 1> arg)
{
return array_wrapper<El, 0>(arg.storage[1]);
}
};
template <typename El, int Dim>
inline
array_wrapper<El, Dim - 1>
tail(array_wrapper<El, Dim> arg)
{
return tail_t<El, Dim>::get(arg);
}
} // end namespace srk31
/* To compile this test code into an executable, use
* $(CXX) -x c++ -DMAKE_TEST_PROGRAM ... */
#ifdef MAKE_TEST_PROGRAM
#include <iostream>
srk31::array<int, 3> function_returning_array()
{
int blah[] = { 4, 5, 6 };
return srk31::array<int, 3>(blah);
}
void function_taking_array(int args[3])
{
std::cout << "Received a triple: "
<< args[0] << ", " << args[1] << ", " << args[2] << std::endl;
}
int main(void)
{
srk31::array<int, 42> my_arr;
// can we return an array?
auto triple = function_returning_array();
// can we pass it to a function taking a vanilla array?
function_taking_array(triple);
// can we assign to a local array? we need array_wrapper;
int my_triple[3];
srk31::make_array_wrapper(my_triple) = triple;
std::cout << "My new triple has been assigned: "
<< my_triple[0] << ", " << my_triple[1] << ", " << my_triple[2] << std::endl;
// can we get the tail of an existing array?
srk31::array_wrapper<int, 3> triple_again(my_triple);
std::cout << "Tail begins: " << srk31::tail(triple_again)[0] << std::endl;
std::cout << "Tail continues: " << srk31::tail(srk31::tail(triple_again))[0] << std::endl;
return 0;
}
#endif
#endif /* !defined LIBSRK31CXX_ARRAY_HPP_ */