Skip to content
Permalink
Browse files

Containers: added ArrayReference wrapper.

Unlike Array this class doesn't do any memory management.
  • Loading branch information...
mosra committed Jun 16, 2013
1 parent e50f478 commit ca6f44b4225381f42dc5167d7faa2daf8232066f
@@ -29,6 +29,7 @@
* @brief Class Corrade::Containers::Array
*/

#include <type_traits>
#include <utility>

namespace Corrade { namespace Containers {
@@ -85,17 +86,99 @@ template<class T> class Array {

/** @brief Pointer to first element */
T* begin() { return _data; }
const T* begin() const { return _data; } /**< @overload */
const T* cbegin() const { return _data; } /**< @overload */
const T* begin() const { return _data; } /**< @overload */
const T* cbegin() const { return _data; } /**< @overload */

/** @brief Pointer to (one item after) last element */
T* end() { return _data+_size; }
const T* end() const { return _data+_size; } /**< @overload */
const T* cend() const { return _data+_size; } /**< @overload */
const T* end() const { return _data+_size; } /**< @overload */
const T* cend() const { return _data+_size; } /**< @overload */

/** @brief Conversion to array type */
operator T*() { return _data; }
operator const T*() const { return _data; } /**< @overload */
operator const T*() const { return _data; } /**< @overload */

private:
T* _data;
std::size_t _size;
};

/**
@brief %Array reference wrapper with size information
Immutable wrapper around plain C array. Unlike Array this class doesn't do any
memory management. Main use case is passing array around along with size
information. If @p T is `const` type, the class is implicitly constructible
also from const references to Array and ArrayReference of non-const types.
*/
template<class T> class ArrayReference {
public:
typedef T Type; /**< @brief Element type */

/**
* @brief Default constructor
*
* Creates zero-sized array. Move array with nonzero size onto the
* instance to make it useful.
*/
constexpr explicit ArrayReference() noexcept: _data(nullptr), _size(0) {}

/**
* @brief Constructor
* @param data Data pointer
* @param size Data size
*/
constexpr /*implicit*/ ArrayReference(T* data, std::size_t size) noexcept: _data(data), _size(size) {}

/**
* @brief Construct reference to fixed-size array
* @param data Fixed-size array
*/
template<std::size_t size> constexpr /*implicit*/ ArrayReference(T(&data)[size]) noexcept: _data(data), _size(size) {}

/** @brief Construct reference to Array */
constexpr /*implicit*/ ArrayReference(Array<T>& array) noexcept: _data(array), _size(array.size()) {}

/**
* @brief Construct const reference to Array
*
* Enabled only if @p T is `const U`.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class U>
#else
template<class U, class V = typename std::enable_if<std::is_same<const U, T>::value>::type>
#endif
constexpr /*implicit*/ ArrayReference(const Array<U>& array) noexcept: _data(array), _size(array.size()) {}

/**
* @brief Construct const reference from non-const reference
*
* Enabled only if @p T is `const U`.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class U>
#else
template<class U, class V = typename std::enable_if<std::is_same<const U, T>::value>::type>
#endif
constexpr /*implicit*/ ArrayReference(const ArrayReference<U>& array) noexcept: _data(array), _size(array.size()) {}

/** @brief Whether the array is empty */
constexpr bool empty() const { return !_size; }

/** @brief %Array size */
constexpr std::size_t size() const { return _size; }

/** @brief Pointer to first element */
constexpr T* begin() const { return _data; }
constexpr T* cbegin() const { return _data; } /**< @overload */

/** @brief Pointer to (one item after) last element */
T* end() const { return _data+_size; }
T* cend() const { return _data+_size; } /**< @overload */

/** @brief Conversion to array type */
constexpr operator T*() const { return _data; }

private:
T* _data;
@@ -32,6 +32,7 @@
namespace Corrade { namespace Containers {

template<class> class Array;
template<class> class ArrayReference;
template<class, class U, U fullValue = U(~0)> class EnumSet;
template<class> class LinkedList;
template<class Derived, class List = LinkedList<Derived>> class LinkedListItem;
@@ -0,0 +1,141 @@
/*
This file is part of Corrade.
Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013
Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

#include "Containers/Array.h"
#include "TestSuite/Tester.h"

namespace Corrade { namespace Containers { namespace Test {

class ArrayReferenceTest: public TestSuite::Tester {
public:
explicit ArrayReferenceTest();

void constructEmpty();
void construct();
void constructFixedSize();
void constructArray();
void emptyCheck();
void access();
void rangeBasedFor();

void constReference();
};

typedef Containers::Array<int> Array;
typedef Containers::ArrayReference<int> ArrayReference;
typedef Containers::ArrayReference<const int> ConstArrayReference;

ArrayReferenceTest::ArrayReferenceTest() {
addTests({&ArrayReferenceTest::constructEmpty,
&ArrayReferenceTest::construct,
&ArrayReferenceTest::constructFixedSize,
&ArrayReferenceTest::constructArray,
&ArrayReferenceTest::emptyCheck,
&ArrayReferenceTest::access,
&ArrayReferenceTest::rangeBasedFor});
}

void ArrayReferenceTest::constructEmpty() {
const ArrayReference a;
CORRADE_VERIFY(a == nullptr);
CORRADE_COMPARE(a.size(), 0);
}

void ArrayReferenceTest::construct() {
int a[30];

const ArrayReference b = {a, 20};
CORRADE_VERIFY(b == a);
CORRADE_COMPARE(b.size(), 20);
}

void ArrayReferenceTest::constructFixedSize() {
int a[13];

const ArrayReference b = a;
CORRADE_VERIFY(b == a);
CORRADE_COMPARE(b.size(), 13);
}

void ArrayReferenceTest::constructArray() {
Array a(5);

const ArrayReference b = a;
CORRADE_VERIFY(b.begin() == a.begin());
CORRADE_COMPARE(b.size(), 5);
}

void ArrayReferenceTest::emptyCheck() {
ArrayReference a;
CORRADE_VERIFY(!a);
CORRADE_VERIFY(a.empty());

int b[5];
ArrayReference c = {b, 5};
CORRADE_VERIFY(c);
CORRADE_VERIFY(!c.empty());
}

void ArrayReferenceTest::access() {
int a[7];
ArrayReference b = a;
for(std::size_t i = 0; i != 7; ++i)
b[i] = i;

CORRADE_COMPARE(*(b.begin()+2), 2);
CORRADE_COMPARE(b[4], 4);
CORRADE_COMPARE(b.end()-b.begin(), b.size());
}

void ArrayReferenceTest::rangeBasedFor() {
int a[5];
ArrayReference b = a;
for(auto& i: b)
i = 3;

CORRADE_COMPARE(b[0], 3);
CORRADE_COMPARE(b[1], 3);
CORRADE_COMPARE(b[2], 3);
CORRADE_COMPARE(b[3], 3);
CORRADE_COMPARE(b[4], 3);
}

void ArrayReferenceTest::constReference() {
const int a[] = {3, 4, 7, 12, 0, -15};

ConstArrayReference b = a;
CORRADE_COMPARE(b.size(), 6);
CORRADE_COMPARE(b[2], 7);

int c[3];
ArrayReference d = c;
ConstArrayReference e = d;
CORRADE_VERIFY(e == a);
CORRADE_COMPARE(e.size(), 3);
}

}}}

CORRADE_TEST_MAIN(Corrade::Containers::Test::ArrayReferenceTest)
@@ -24,6 +24,7 @@
#

corrade_add_test(ContainersArrayTest ArrayTest.cpp)
corrade_add_test(ContainersArrayReferenceTest ArrayReferenceTest.cpp)
corrade_add_test(ContainersEnumSetTest EnumSetTest.cpp)
corrade_add_test(ContainersLinkedListTest LinkedListTest.cpp)

0 comments on commit ca6f44b

Please sign in to comment.
You can’t perform that action at this time.