diff --git a/meson.build b/meson.build index 4339f9c..c3939ff 100644 --- a/meson.build +++ b/meson.build @@ -45,4 +45,21 @@ c_5_lab_5_1 = executable( install: true, ) -c_6_lab_6 = executable('c_6_lab-6', ['src/chapter_6/lab-6/main.cpp', 'src/chapter_6/lab-6/IntVector.h', 'src/chapter_6/lab-6/IntVector.cpp'], install: true) +c_6_lab_6 = executable( + 'c_6_lab-6', + [ + 'src/chapter_6/lab-6/main.cpp', + 'src/chapter_6/lab-6/IntVector.h', + 'src/chapter_6/lab-6/IntVector.cpp', + ], + install: true, +) +c_6_program_4 = executable( + 'c_6_program-4', + [ + 'src/chapter_6/program-4/main.cpp', + 'src/chapter_6/program-4/IntVector.h', + 'src/chapter_6/program-4/IntVector.cpp', + ], + install: true, +) diff --git a/src/chapter_6/program-4/IntVector.cpp b/src/chapter_6/program-4/IntVector.cpp new file mode 100644 index 0000000..bd92023 --- /dev/null +++ b/src/chapter_6/program-4/IntVector.cpp @@ -0,0 +1,149 @@ +#include "IntVector.h" +#include +using namespace std; + +IntVector::IntVector(unsigned capacity, int value) { + __size = capacity; + __capacity = capacity; + + if (__size > 0) { + __data = new int[__size]; + } else { + __data = nullptr; + } + + for (unsigned i = 0; i < __size; i++) { + __data[i] = value; + } +} + +IntVector::~IntVector() { delete[] __data; } + +const int &IntVector::at(unsigned index) const { + if (index >= __size) + throw out_of_range("IntVector::at_range_check"); + + return __data[index]; +} + +int &IntVector::at(unsigned index) { + if (index >= __size) + throw out_of_range("IntVector::at_range_check"); + + return __data[index]; +} + +unsigned IntVector::size() const { return __size; } +unsigned IntVector::capacity() const { return __capacity; }; +bool IntVector::empty() const { return __size == 0; }; +const int &IntVector::front() const { return __data[0]; } +const int &IntVector::back() const { return __data[__size - 1]; } + +int &IntVector::front() { return __data[0]; }; +int &IntVector::back() { return __data[__size - 1]; }; +void IntVector::reserve(unsigned n) { + if (n <= __capacity) { + return; + } + expand(n - __capacity); +}; + +void IntVector::clear() { __size = 0; }; + +void IntVector::expand(unsigned amount) { + __capacity += amount; + int *newVec = new int[__capacity]; + for (unsigned i = 0; i < __size; i++) { + newVec[i] = __data[i]; + } + delete[] __data; + __data = newVec; +} + +void IntVector::expand() { + if (__capacity == 0) { + expand(1); + return; + } + expand(__capacity); +} + +void IntVector::push_back(int value) { + if (__size >= __capacity) { + expand(); + } + __size++; + back() = value; +}; + +void IntVector::assign(unsigned n, int value) { + if (n > __capacity && n - __capacity > __capacity) { + expand(n - __capacity); + } else if (n > __capacity) { + expand(); + } + + delete[] __data; + __data = new int[__capacity]; + + __size = n; + + for (unsigned i = 0; i < __size; i++) { + __data[i] = value; + } +}; + +void IntVector::pop_back() { __size--; }; + +void IntVector::resize(unsigned n, int value) { + if (n == __size) + return; + + if (n < __size) { + __size = n; + return; + } + + if (n > __capacity) { + if (n - __capacity > __capacity) { + reserve(n); + } else { + expand(); + } + + int *newVec = new int[__capacity]; + for (unsigned i = 0; i < __size; i++) { + newVec[i] = __data[i]; + } + delete[] __data; + __data = newVec; + } + + for (; __size < n; __size++) { + __data[__size] = value; + } +}; + +void IntVector::insert(unsigned idx, int value) { + if (idx > __size) { + throw out_of_range("IntVector::insert_range_check"); + } + if (__size == __capacity) { + expand(); + } + __size++; + for (unsigned i = idx; i < __size - 1; i++) { + __data[i + 1] = __data[i]; + } + __data[idx] = value; +} + +void IntVector::erase(unsigned idx) { + if (idx >= __size) { + throw out_of_range("IntVector::erase_range_check"); + } + for (unsigned i = idx; i < __size - 1; i++) { + __data[i] = __data[i + 1]; + } + __size--; +} diff --git a/src/chapter_6/program-4/IntVector.h b/src/chapter_6/program-4/IntVector.h new file mode 100644 index 0000000..13aabc0 --- /dev/null +++ b/src/chapter_6/program-4/IntVector.h @@ -0,0 +1,31 @@ +#pragma once + +class IntVector { +public: + IntVector(unsigned capacity = 0, int value = 0); + ~IntVector(); + unsigned size() const; + unsigned capacity() const; + bool empty() const; + const int &at(unsigned index) const; + const int &front() const; + const int &back() const; + int &at(unsigned index); + int &front(); + int &back(); + void assign(unsigned, int); + void push_back(int value); + void pop_back(); + void clear(); + void resize(unsigned n, int value = 0); + void reserve(unsigned n); + void insert(unsigned, int); + void erase(unsigned); + +private: + unsigned __size; + unsigned __capacity; + int *__data; + void expand(); + void expand(unsigned); +}; diff --git a/src/chapter_6/program-4/main.cpp b/src/chapter_6/program-4/main.cpp new file mode 100644 index 0000000..9e20d9b --- /dev/null +++ b/src/chapter_6/program-4/main.cpp @@ -0,0 +1,180 @@ +#include "IntVector.h" +#include +#include +#include +using namespace std; + +int main() { + cout << "Running test bench!" << endl; + + IntVector *testVec = nullptr; + + testVec = new IntVector(); + assert(testVec->empty()); + cout << "[SUCCESS] empty() works as expected for empty vector." << endl; + assert(testVec->size() == 0); + assert(testVec->capacity() == 0); + cout << "[SUCCESS] Default constructor sets size and capacity properly." + << endl; + + delete testVec; + testVec = new IntVector(1); + assert(!testVec->empty()); + cout << "[SUCCESS] empty() works as expected for nonempty vector." << endl; + assert(testVec->at(0) == 0); + cout << "[SUCCESS] Basic vector initialization works." << endl; + + for (unsigned i = 0; i < 100; i++) { + delete testVec; + testVec = new IntVector(i, 50 - i); + + assert(testVec->capacity() == i); + assert(testVec->size() == i); + + for (unsigned j = 0; j < testVec->size(); j++) { + assert(testVec->at(j) == 50 - static_cast(i)); + } + } + + cout << "[SUCCESS] Size and capacity work as expected" << endl; + cout << "[SUCCESS] Initializing values getting values at indices work." + << endl; + + delete testVec; + testVec = new IntVector(5, 2); + + bool failed = false; + try { + testVec->at(5); + } catch (const out_of_range &e) { + failed = true; + } + assert(failed); + cout << "[SUCCESS] at() correctly throws for out of range access." << endl; + + assert((testVec->front() == testVec->at(0))); + cout << "[SUCCESS] Output of front() is consistent with output of at(0)." + << endl; + + assert(testVec->front() == 2); + cout << "[SUCCESS] Output of front() is correct." << endl; + + assert((testVec->back() == testVec->at(testVec->size() - 1))); + cout + << "[SUCCESS] Output of back() is consistent with output of at(size - 1)." + << endl; + + assert(testVec->front() == 2); + cout << "[SUCCESS] Output of back() is correct." << endl; + + delete testVec; + testVec = new IntVector(5); + assert(testVec->capacity() == 5); + testVec->reserve(20); + assert(testVec->capacity() == 20); + testVec->reserve(5); + assert(testVec->capacity() == 20); + cout << "[SUCCESS] reserve() works as expected." << endl; + + testVec->clear(); + assert(testVec->capacity() == 20); + assert(testVec->size() == 0); + assert(testVec->empty()); + cout << "[SUCCESS] clear() works as expected." << endl; + + delete testVec; + testVec = new IntVector(5); + testVec->at(3) = 2; + assert(testVec->back() == 0); + testVec->pop_back(); + assert(testVec->size() == 4); + assert(testVec->back() == 2); + cout << "[SUCCESS] pop_back() works as expected." << endl; + + delete testVec; + testVec = new IntVector(5); + testVec->push_back(5); + assert(testVec->size() == 6); + assert(testVec->back() == 5); + cout << "[SUCCESS] push_back() works as expected." << endl; + + delete testVec; + testVec = new IntVector(5); + testVec->resize(3, 2); + assert(testVec->size() == 3); + assert(testVec->capacity() == 5); + assert(testVec->front() == 0); + cout << "[SUCCESS] resize() to lesser capacity works." << endl; + testVec->resize(8); + assert(testVec->size() == 8); + assert(testVec->capacity() == 10); + assert(testVec->back() == 0); + cout << "[SUCCESS] resize() doubles capacity when appropriate." << endl; + testVec->resize(100, 5); + assert(testVec->size() == 100); + assert(testVec->capacity() == 100); + assert(testVec->back() == 5); + testVec->resize(500); + assert(testVec->capacity() == 500); + assert(testVec->size() == 500); + assert(testVec->back() == 0); + cout << "[SUCCESS] resize() increases capacity when appropriate." << endl; + + delete testVec; + testVec = new IntVector(5); + testVec->assign(3, 10); + assert(testVec->size() == 3); + assert(testVec->capacity() == 5); + assert(testVec->at(1) == 10); + testVec->assign(8, 0); + assert(testVec->capacity() == 10); + assert(testVec->front() == 0); + testVec->assign(50, 2); + assert(testVec->capacity() == 50); + assert(testVec->front() == 2); + cout << "[SUCCESS] assign() works as expected." << endl; + + delete testVec; + testVec = new IntVector(5); + testVec->insert(3, 3); + assert(testVec->at(3) == 3); + assert(testVec->size() == 6); + testVec->insert(3, 3); + assert(testVec->size() == 7); + assert(testVec->capacity() == 10); + failed = false; + cout << "[SUCCESS] Basic insertion works" << endl; + try { + testVec->insert(10, 3); + } catch (const out_of_range &e) { + failed = true; + } + assert(failed); + cout << "[SUCCESS] insert() correctly throws exception when out of range" + << endl; + + delete testVec; + testVec = new IntVector(5); + testVec->erase(3); + assert(testVec->size() == 4); + cout << "[SUCCESS] erase() modifies size properly." << endl; + testVec->insert(3, 4); + testVec->erase(3); + assert(testVec->at(3) == 0); + cout << "[SUCCESS] erase() removes the correct element." << endl; + assert(testVec->capacity() == 5); + cout << "[SUCCESS] erase() doesn't modify capacity" << endl; + failed = false; + try { + testVec->erase(10); + } catch (const out_of_range &e) { + failed = true; + } + assert(failed); + cout << "[SUCCESS] insert() correctly throws exception when out of range" + << endl; + + delete testVec; + testVec = nullptr; + cout << "All tests passed!" << endl; +}