// -*- coding: utf-8 -*- // Time-stamp: // Implementation of Array2d using only usual pointers // Each Array2d has only one pointer to an representaion. // This representation is an instance of a subclass of Rep. // // // Array2d Rep // +----------+ +-----------+ Abstract class // | rep |----------->| nlin | with pure virtual // +----------+ +-----------+ methods // | ncol | // +-----------+ // | refs | // +-----------+ // ^ // | // | // +------------+------------+ // | Two subclasses | // | with different | // | implementation | // // Repd Repi // +------------+ +------------+ // |+----------+| |+----------+| // || Rep || || Rep || // || || || || // || || || || // || || || || // || || || || // |+----------+| |+----------+| // +------------+ +------------+ // | p | | p | // +------------+ +------------+ // Each constructor/destructor and assigment operator of Array2d // take care of incrementing or decrementing the reference count // of the Rep they take or leave. #ifndef ARRAY2D_HPP #define ARRAY2D_HPP #include using namespace std; #include "rep.hpp" #include "repd.hpp" #include "repi.hpp" #include "iterator.hpp" template class Iterator; template class Array2d { friend Iterator; public: // Constructors & destructor // Contruct an array of dim 0×0 with hint indicating the representation // 0: direct representation // 1: indirect representation Array2d(int hint = 0) : Array2d(0, 0, hint) {} // Contruct an array of dim m×n with hint indicating the representation // 0: direct representation // 1: indirect representation Array2d(int m, int n, int hint = 0); Array2d(const Array2d& array); // Copy constructor Array2d(Array2d&& array); // Move constructor ~Array2d() { detach(); } // Destructor // Assignment operators Array2d& operator=(const Array2d& array); // Copy assignment operator Array2d& operator=(const Array2d&& array); // Move assignment operator // Access to an item of a non-const array // Make sure the array is not shared typename Rep::Line operator[](int i) { unique(); return (*rep)[i]; } // Access to an item of a const array const typename Rep::Line operator[](int i) const { return (*rep)[i]; } int ldim() const { return rep->nlin; } // Number of lines int cdim() const { return rep->ncol; } // Number of columns // Iterators Iterator begin() { return Iterator(*this, 0, 0); } Iterator end() { return Iterator(*this, rep->nlin, 0); } private: // Links to rep void attach(); // Create link void detach(); // Remove link void unique(); // Make representation not shared // Pointer to the representation or nullptr if none Rep* rep; }; // Contruct an array of dim m×n with hint indicating the representation template Array2d::Array2d(int m, int n, int hint) { #ifdef TRACE cout << "Array2d(" << m << "," << n << "," << hint << ")" << endl; #endif // Create representation according to hint switch (hint) { case 0: // Direct representation rep = new Repd(m, n); break; case 1: // Indirect representation rep = new Repi(m, n); break; #ifdef TRACE default: // Unexpected case throw new exception(); #endif } // Attaching is not necessary because ref count is initialized to 1. } // Copy constructor template Array2d::Array2d(const Array2d& array) : rep(array.rep) { #ifdef TRACE cout << "Array2d(const Array2d& " << array.rep << ")" << endl; #endif attach(); } // Move constructor (C++11) template Array2d::Array2d(Array2d&& array) : rep(array.rep) { #ifdef TRACE cout << "Array2d(Array2d&& " << array.rep << ")" << endl; #endif array.rep = 0; // Move link from array to this } // Copy assignment operator template Array2d& Array2d::operator=(const Array2d& array) { #ifdef TRACE cout << "Array2d::operator=(const Array2d&" << array.rep << ")" << endl; #endif // This test avoid self-assigment if (rep != array.rep) { detach(); // Detach from previous rep rep = array.rep; // Share rep of array attach(); } return *this; // Return it self } // Move assignment operator (C++11) template Array2d& Array2d::operator=(const Array2d&& array) { #ifdef TRACE cout << "Array2d::operator=(const Array2d&&" << array.rep << ")" << endl; #endif detach(); // Detach from previous rep rep = array.rep; // Take rep of array array.rep = 0; return *this; // Return it self } // Create link : increase reference count template void Array2d::attach() { #ifdef TRACE cout << "Attach to rep " << rep << endl; if (rep == nullptr) // Check that the rep does really exist throw new exception(); #endif ++rep->refs; // Increment number of links } // Remove link : decrease the reference count // Delete rep if reference count becomes zero // Deleting the rep also deletes the array. template void Array2d::detach() { #ifdef TRACE cout << "Detach from rep " << rep << endl; #endif // Decrement number of links and delete if no more links if (rep != nullptr && --rep->refs == 0) { delete rep; } } // Insures the rep is not shared. // If it is shared, create a new one by copy. template void Array2d::unique() { #ifdef TRACE cout << "Unique for rep " << rep; cout << " [" << rep->refs << "]" << endl; #endif if (rep->refs != 1) { Rep* tmp = rep->clone(); // Clone current rep detach(); // Detach from the current rep rep = tmp; // Attach to the new rep // Attaching is not necessary because ref count is initialized to 1. } } #endif