Created
January 25, 2016 18:24
-
-
Save Rycieos/c3f4fbc73acbd396cd40 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template<typename Item> | |
class Array { | |
private: | |
unsigned int first_, last_, capacity_, size_; | |
Item* myArray; | |
public: | |
/*! | |
* Array constructor method. | |
* @param size The maximum capacity of the Array. | |
*/ | |
// This is a standard constructor, simply creates a basic array | |
// Note that the reason for this Array class instead of using a | |
// normal List or Vector is that this needs to be static and fast to | |
// handle the large amounts of video objects being strung through it | |
// thousands of times per second. This design prevents hangs from | |
// dynamic size increases. | |
Array(unsigned int size) { | |
capacity_ = size; | |
myArray = new Item[size]; | |
myArray[0] = nullptr; | |
first_ = last_ = size_ = 0; | |
} | |
/*! | |
* Array destructor method. | |
* Frees up memory allocated to an Array instance. | |
*/ | |
virtual ~Array() { | |
clear(); | |
delete[] myArray; | |
} | |
/*! | |
* Empties the internal array and resets it, deleting contained objects. | |
*/ | |
// This is the complicated part. Since the first and last locations are arbitrary, | |
// we need to loop from the first to the last, but we might need to wrap around. | |
// We could simply clear the entire array from the actual start to the end, but if | |
// the whole array is not full, that is a large waste of time. | |
void clear() { | |
if (first_ > last_) { // Check if the array wraps around | |
for (; first_ < capacity_; first_++) { // Delete from first to the end (but only if it wraps around) | |
delete myArray[first_]; | |
myArray[first_] = nullptr; // We do not need to do this pointer reset, but it adds almost no time and is safer | |
} | |
first_ = 0; // Move first to the beginning | |
} | |
for (; first_ <= last_; first_++) { // Delete from first to last (if it wrapped around, first is now 0, the beginning) | |
delete myArray[first_]; | |
myArray[first_] = nullptr; | |
} | |
first_ = last_ = size_ = 0; // Reset all vars | |
} | |
/*! | |
* Empties the internal array but does not delete the objects it contains. | |
* \note This method doesn't delete the shapes inside of it; it only moves pointers around. | |
* \warning <b>This will result in a memory leak if the objects are not pointed to anywhere else!</b> | |
*/ | |
// This method is needed if the contents of this Array are dumpped into some other storage, meaning that | |
// the objects cannot be deleted. It is rarely used, but the design called for a way to drop the pointers of the Array. | |
// It would be easier to delete the array object and create a new one, but this clear loop is almost always faster, and | |
// if we did not care about clearing the | |
void shallowClear() { | |
if (first_ > last_) { // If the array wraps around... | |
for (; first_ < capacity_; first_++) // Delete from first to the end | |
myArray[first_] = nullptr; | |
first_ = 0; // Move first to the beginning | |
} | |
for (; first_ <= last_; first_++) // Delete from first to last | |
myArray[first_] = nullptr; | |
first_ = last_ = size_ = 0; // Reset all vars | |
} | |
/*! | |
* Returns the item at index index. | |
* @param index The index of the item in the internal array. | |
* @note This is the read version of the subscript operator. | |
* @eturn The item at index index. | |
*/ | |
// I will only comment on the first of these, since they do the same thing/ | |
// This is where the boundry checking happens, to prevent reading outside real data. | |
// Note that although the user is requesting an Item at an index, the index given is not | |
// the same in the underlying array. This is where the shifting comes into play. | |
// Also note that since the array is designed to wrap around, most often the user is not | |
// going to use this [] operator and will just use push(), pop(), first(), and last(), making this | |
// Array much like a list. | |
const Item& operator[](unsigned int index) const { | |
if (size_ == 0) | |
throw std::out_of_range("Array::operator[](): array is empty"); | |
else if (index >= size_) | |
throw std::out_of_range("Array::operator[](): index is larger than number of items in array"); | |
else | |
return myArray[(first_ + index) % capacity_]; // Wrap around for the underlying array | |
} | |
/*! | |
* Returns the item at index index. | |
* @param index The index of the item in the internal array. | |
* @note This is the write version of the subscript operator. | |
* @eturn The item at index index. | |
*/ | |
Item& operator[](unsigned int index) { | |
if (size_ == 0) { | |
throw std::out_of_range("Array::operator[](): array is empty"); | |
} else if (index >= size_) { | |
throw std::out_of_range("Array::operator[](): index is larger than number of items in array"); | |
} else { | |
return myArray[(first_ + index) % capacity_]; // Wrap around for the underlying array | |
} | |
} | |
/*! Returns the number of items in the internal array. */ | |
unsigned int size() const { | |
return size_; | |
} | |
/*! Returns the maximum amount of items the internal array can store. */ | |
unsigned int capacity() const { | |
return capacity_; | |
} | |
/*! Returns true if the internal array contains no items, false otherwise. */ | |
bool isEmpty() const { | |
return (size_ == 0); | |
} | |
/*! | |
* Adds the item to the end of the internal array. | |
* @note If the internal array is full, push() will remove the oldest item. | |
* @param item The item to add. | |
* @return The same item. | |
*/ | |
// This is the complicated part of the Array. Since the array can wrap around the | |
// true pysical end of the memory array, we need to handle that as well as the case | |
// of a full array. This is done with some careful logic using our first_, last_, and capacity_ | |
// variables. | |
Item push(Item item) { | |
if (myArray[first_] != nullptr) // If the array has items (the first item is not null) | |
(last_ + 1) == capacity_ ? last_ = 0 : last_++; // Increment last (the index of our new item) (handle wrap around) | |
if (last_ == first_ && myArray[first_] != nullptr) { // If the array is out of room (ie. if our new last index == our first) | |
// (but also double check to make sure the array is not empty) | |
delete myArray[first_]; // Delete the first element | |
(first_ + 1) == capacity_ ? first_ = 0 : first_++; // Increment first (the index of the deleted item) (handle wrap around) | |
} else | |
size_++; // Otherwise (we were not out of room), we added an item (so size goes up) | |
return myArray[last_] = item; // Actually add the item (now that our indexes are fixed) | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment