Skip to content

Instantly share code, notes, and snippets.

@Jules-Baratoux
Last active August 2, 2019 15:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jules-Baratoux/504ab726599898f849f6 to your computer and use it in GitHub Desktop.
Save Jules-Baratoux/504ab726599898f849f6 to your computer and use it in GitHub Desktop.
Homework #6 – Array Class Template
#pragma once
#include <ostream>
using std::ostream;
#include <stdexcept>
using std::invalid_argument;
#include <string>
using std::string;
#include <array>
#include <iterator>
#include <cassert>
#include "utils.h"
namespace JulesBaratoux
{
template <typename ElemType,
int SIZE // should be a std::size_t
>
struct Array
{
typedef ElemType value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* iterator;
typedef const value_type* const_iterator;
typedef decltype(SIZE) size_type;
// --------------------------------------------------------------------
// SYNOPSYS
// --------------------------------------------------------------------
#if -0
// Constructors:
Array(void);
Array(const Array& source);
Array(const value_type source[SIZE]);
// Operators:
Array operator = (const Array& source);
bool operator == (const Array& other) const;
bool operator != (const Array& other) const;
const_reference operator [] (size_type pos) const;
reference operator [] (size_type pos);
friend ostream& operator << (ostream& out, const Array& array);
// Methodes
constexpr size_type size() const;
const_iterator begin() const;
const_iterator end() const;
iterator begin();
iterator end();
#endif
// --------------------------------------------------------------------
// IMPLEMENTATION
// --------------------------------------------------------------------
// errors
static constexpr auto E_BOUND_OVER = "pos > array.size()";
static constexpr auto E_BOUND_UNDER = "pos < 0";
static constexpr auto OSTREAM_START = "[";
static constexpr auto OSTREAM_END = "]";
static constexpr auto OSTREAM_SEP = ", ";
Array() {}
Array(const Array& source)
{
for (size_type i = 0; i < SIZE; ++i)
{
elements[i] = source[i];
}
}
Array(const value_type source[SIZE])
{
for (size_type i = 0; i < SIZE; ++i)
{
elements[i] = source[i];
}
}
Array& operator=(const Array& source)
{
if (elements != source.elements)
{
for (size_type i = 0; i < SIZE; ++i)
{
elements[i] = source[i];
}
}
return *this;
}
friend ostream& operator<<(ostream& out, const Array& array)
{
size_type i = 0;
out << OSTREAM_START;
while (i < SIZE - 1)
{
out << array[i++] << OSTREAM_SEP;
}
return out << array[i] << OSTREAM_END;
}
bool operator==(const Array& other) const
{
for (size_type i = 0; i < SIZE; ++i)
{
if (elements[i] != other.elements[i])
{
return false;
}
}
return true;
}
bool operator!=(const Array& other) const
{
return not (*this == other);
}
iterator begin()
{
return iterator(&elements[0]);
}
const_iterator begin() const
{
return const_iterator(&elements[0]);
}
iterator end()
{
return iterator(&elements[SIZE]);
}
const_iterator end() const
{
return const_iterator(&elements[SIZE]);
}
reference operator[]( size_type pos )
{
if (pos >= SIZE)
{
throw invalid_argument("pos > array.size()");
}
else if (pos < 0)
{
throw invalid_argument("pos < 0");
}
else
{
return elements[pos];
}
}
const_reference operator[]( size_type pos ) const
{
if (pos >= SIZE)
{
throw invalid_argument(E_BOUND_OVER);
}
else if (pos < 0)
{
throw invalid_argument(E_BOUND_UNDER);
}
else
{
return elements[pos];
}
}
constexpr size_type size() const
{
return SIZE;
}
struct tests
{
static void constructors(void)
{
// default constructor
Array base;
base.elements[0] = 42; // compile time check
// copy constructor
{
const Array copy(base);
assert(copy.elements[0] == base[0]);
}
// c-style array copy constructor
{
const ElemType base[SIZE] = {5};
const Array copy(base);
assert(copy.elements[0] == 5);
}
}
static void operator_assign()
{
Array array;
Array copy;
// Assert that arrays are different
array.elements[0] = 1;
copy.elements[0] = -array.elements[0];
copy = array;
assert(copy == array);
}
static void operator_at()
{
Array array;
const Array const_array;
// normal usage
{
array[0] = const_array[0];
assert(array.elements[0] == const_array.elements[0]);
}
// invalid_argument
try
{
for (const auto i : {-1, SIZE})
{
volatile size_type trash;
// R-value
try
{
trash = const_array[i];
assert(false); // exception not thrown
}
catch (const invalid_argument& exception) {}
// L-value
try
{
array[i] = trash;
assert(false); // exception not thrown
}
catch (const invalid_argument& exception) {}
}
}
catch (...)
{
assert(false); // bad exception
}
}
static void operator_cmp()
{
const ElemType base[SIZE] = {1};
const Array a(base);
// ==
{
Array b(a);
assert( (a == b) == true);
b[0] = - a[0];
assert( (a == b) == false);
}
// !=
{
Array b(a);
assert( (a != b) == false);
b[0] = -a[0];
assert( (a != b) == true);
}
}
};
private:
ElemType elements[SIZE];
friend struct tests;
};
}
#include <iostream>
#include <cstdlib>
#include <iostream>
using std::cout;
using std::endl;
#include "Array.h"
using JulesBaratoux::Array;
int main(void)
{
// a. Create an Array using the default constructor
Array<int, 3> array;
// b. Modify all of the elements of the Array created in step a
for (auto& c : array)
{
++c;
}
// c. Output all of the elements of the Array created in step a
cout << array << endl;
// d. Create a const Array from another Array using the copy constructor
Array<int, 4>::tests::constructors();
// e. Assign an Array to an existing Array using the copy assignment operator
Array<int, 4>::tests::operator_assign();
// f. Compare two Arrays using the equality operator
// g. Compare two Arrays using the inequality operator
Array<int, 4>::tests::operator_cmp();
// h. Demonstrate an invalid_argument exception being thrown and caught when the
// L-value subscript operator is accessed with an index < 0
// i. Demonstrate an invalid_argument exception being thrown and caught when the
// L-value subscript operator is accessed with an index >= SIZE
// j. Demonstrate an invalid_argument exception being thrown and caught when the
// R-value subscript operator is accessed with an index < 0 (you can force the R-value
// subscript operator to be called by accessing an element in the const Array).
// k. Demonstrate an invalid_argument exception being thrown and caught when the
// R-value subscript operator is accessed with an index >= SIZE (you can force the Rvalue
// subscript operator to be called by accessing an element in the const Array).
Array<int, 4>::tests::operator_at();
return EXIT_SUCCESS;
}
// -----------------------------------------------------------------------------
// utils.h
// -----------------------------------------------------------------------------
#pragma once
// Windows...
#ifdef WIN32
# define or ||
# define and &&
# define not !
#endif
#define warn std::cerr \
<< "warning: In function ‘" << __FUNCTION__ << "’:" << std::endl \
<< "\t"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment