Compare commits
3 Commits
d0a7f73512
...
b0f8a9970f
Author | SHA1 | Date | |
---|---|---|---|
b0f8a9970f | |||
d313d0ce63 | |||
2efd3407ac |
@ -1,13 +1,14 @@
|
|||||||
---
|
---
|
||||||
BasedOnStyle: LLVM
|
BasedOnStyle: LLVM
|
||||||
AllowShortBlocksOnASingleLine: 'true'
|
AllowShortBlocksOnASingleLine: false
|
||||||
AllowShortCaseLabelsOnASingleLine: 'true'
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
AllowShortFunctionsOnASingleLine: Inline
|
AllowShortFunctionsOnASingleLine: None
|
||||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||||
AllowShortLambdasOnASingleLine: Inline
|
AllowShortLambdasOnASingleLine: Inline
|
||||||
AllowShortLoopsOnASingleLine: 'false'
|
AllowShortLoopsOnASingleLine: false
|
||||||
AlwaysBreakBeforeMultilineStrings: 'true'
|
AlwaysBreakBeforeMultilineStrings: true
|
||||||
IndentWidth: '4'
|
AlwaysBreakTemplateDeclarations: true
|
||||||
ColumnLimit: 100
|
IndentWidth: 4
|
||||||
|
ColumnLimit: 80
|
||||||
|
|
||||||
...
|
...
|
||||||
|
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -5,7 +5,7 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "Debug",
|
"name": "Test",
|
||||||
"type": "gdb",
|
"type": "gdb",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"target": "./vector.out",
|
"target": "./vector.out",
|
||||||
|
@ -6,4 +6,7 @@ Run `scons` in the root directory.
|
|||||||
## Developing
|
## Developing
|
||||||
The `scons` command also generates a `compile_commands.json` which can be used by the VSCodium extension `clangd` for autocompletion, debugging, etc.
|
The `scons` command also generates a `compile_commands.json` which can be used by the VSCodium extension `clangd` for autocompletion, debugging, etc.
|
||||||
|
|
||||||
Build and run scripts for VSCodium are provided as well.
|
Build and run scripts for VSCodium are provided as well.
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
Catch2 for unit tests: https://github.com/catchorg/Catch2
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
#include "Vector.h"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
Vector::Vector() {
|
|
||||||
std::cout << "Vector created" << std::endl;
|
|
||||||
}
|
|
153
Vector.h
153
Vector.h
@ -1,4 +1,155 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
template <class T>
|
||||||
class Vector {
|
class Vector {
|
||||||
public:
|
public:
|
||||||
Vector();
|
// Constructor
|
||||||
|
// If the needed capacity is known, it can be passed; other wise, a default
|
||||||
|
// capacity is reserved.
|
||||||
|
Vector(unsigned int capacity = 10)
|
||||||
|
: capacity(capacity), element_count(0), data(new T[capacity]) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy Constructor
|
||||||
|
Vector(const Vector &other)
|
||||||
|
: capacity(other.capacity), element_count(other.element_count),
|
||||||
|
data(new T[capacity]) {
|
||||||
|
// `std::copy` is used because it is more flexible than `std::memcpy`,
|
||||||
|
// and the compiler will replace it with `memcpy` anyway if appropriate,
|
||||||
|
// so there is no performance loss.
|
||||||
|
std::copy(other.data, other.data + element_count, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move Constructor using the copy-and-swap-idiom
|
||||||
|
Vector(Vector &&other) : data(new T[capacity]) {
|
||||||
|
swap(*this, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy Assignment Operator using the copy-and-swap-idiom
|
||||||
|
// Since this takes a value rather than a const reference due to
|
||||||
|
// copy-and-swap, this is also the Move Assignment Operator.
|
||||||
|
// This works because we pass-by-value, causing the copy constructor (which
|
||||||
|
// does the actual copying) to be called, and then we swap the resulting
|
||||||
|
// temporary into `this`.
|
||||||
|
Vector &operator=(Vector other) {
|
||||||
|
swap(*this, other);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~Vector() {
|
||||||
|
delete[] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bracket Operator for accessing elements
|
||||||
|
T &operator[](unsigned int position) const {
|
||||||
|
return at(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equals Operator: Returns true if the number of elements is identical and
|
||||||
|
// each of these elements are equal
|
||||||
|
bool operator==(const Vector &other) {
|
||||||
|
if (size() != other.size()) return false;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < size(); i++) {
|
||||||
|
if (at(i) != other[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap function for the copy-and-swap idiom.
|
||||||
|
// See also:
|
||||||
|
// https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom
|
||||||
|
// The `friend` keyword is used so it is found through ADL.
|
||||||
|
friend void swap(Vector &first, Vector &second) {
|
||||||
|
// Enable ADL (good practice)
|
||||||
|
using std::swap;
|
||||||
|
|
||||||
|
swap(first.capacity, second.capacity);
|
||||||
|
swap(first.element_count, second.element_count);
|
||||||
|
swap(first.data, second.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_back(const T &element) {
|
||||||
|
// TODO: Allocate additional space if needed
|
||||||
|
|
||||||
|
// Use placement new to directly use pre-allocated memory
|
||||||
|
new (data + element_count) T(element);
|
||||||
|
element_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase(unsigned int position) {
|
||||||
|
assert(position < element_count);
|
||||||
|
|
||||||
|
// Call the destructor on the given element
|
||||||
|
data[position].~T();
|
||||||
|
|
||||||
|
// Copy the other elements forwards
|
||||||
|
std::copy_backward(data + position + 1, data + element_count,
|
||||||
|
data + element_count - 1);
|
||||||
|
|
||||||
|
element_count--;
|
||||||
|
|
||||||
|
// TODO: Consider deallocating memory if a certain threshold was reached
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of elements in the vector, regardless of the actually
|
||||||
|
// reserved memory.
|
||||||
|
unsigned int size() const {
|
||||||
|
return element_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number of elements which could be in the vector using the
|
||||||
|
// currently allocated memory, regardless of how many of these slots are
|
||||||
|
// currently actually used.
|
||||||
|
unsigned int length() const {
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a reference to the element at the given position
|
||||||
|
T &at(unsigned int position) const {
|
||||||
|
assert(position < element_count);
|
||||||
|
return data[position];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expand the capacity of the vector by the given addition
|
||||||
|
void reserve(unsigned int addition) {
|
||||||
|
// TODO: Actual memory allocation
|
||||||
|
capacity += addition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize the size of the vector to the given new_size
|
||||||
|
// If this decreases the size, some elements are deleted
|
||||||
|
// If this increases the size, some default-constructed elements are added
|
||||||
|
void resize(unsigned int new_size) {
|
||||||
|
int difference = new_size - size();
|
||||||
|
|
||||||
|
if (difference > 0) {
|
||||||
|
// TODO: Reserve more space if needed
|
||||||
|
// Add additional default-constructed items
|
||||||
|
for (int i = 0; i < difference; i++) {
|
||||||
|
data[element_count + i] = T();
|
||||||
|
}
|
||||||
|
} else if (difference < 0) {
|
||||||
|
// Call the destructor on all excess items
|
||||||
|
for (int i = -1; i > difference; i--) {
|
||||||
|
data[element_count + i].~T();
|
||||||
|
}
|
||||||
|
// TODO: Consider deallocating space
|
||||||
|
}
|
||||||
|
|
||||||
|
element_count += difference;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T *data;
|
||||||
|
unsigned int element_count;
|
||||||
|
unsigned int capacity;
|
||||||
};
|
};
|
||||||
|
9430
catch_amalgamated.cpp
Normal file
9430
catch_amalgamated.cpp
Normal file
File diff suppressed because it is too large
Load Diff
10987
catch_amalgamated.hpp
Normal file
10987
catch_amalgamated.hpp
Normal file
File diff suppressed because it is too large
Load Diff
6
main.cpp
6
main.cpp
@ -1,6 +0,0 @@
|
|||||||
#include "Vector.h"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
Vector vector;
|
|
||||||
}
|
|
229
test.cpp
Normal file
229
test.cpp
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
#include "Vector.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this
|
||||||
|
// in one cpp file
|
||||||
|
#include "catch_amalgamated.hpp"
|
||||||
|
|
||||||
|
SCENARIO("Vector size and length are correct", "[vector]") {
|
||||||
|
Vector<int> v(20);
|
||||||
|
v.push_back(1);
|
||||||
|
|
||||||
|
REQUIRE(v.size() == 1);
|
||||||
|
REQUIRE(v.length() == 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCENARIO("The bracket operator returns the correct element", "[vector]") {
|
||||||
|
Vector<int> v(20);
|
||||||
|
v.push_back(1);
|
||||||
|
v.push_back(2);
|
||||||
|
v.push_back(3);
|
||||||
|
|
||||||
|
REQUIRE(v[1] == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCENARIO("Equality is returned correctly", "[vector]") {
|
||||||
|
GIVEN("Two vectors with the same items") {
|
||||||
|
Vector<int> v1;
|
||||||
|
Vector<int> v2;
|
||||||
|
|
||||||
|
v1.push_back(1);
|
||||||
|
v2.push_back(1);
|
||||||
|
|
||||||
|
v1.push_back(5);
|
||||||
|
v2.push_back(5);
|
||||||
|
|
||||||
|
REQUIRE(v1.size() == 2);
|
||||||
|
REQUIRE(v2.size() == 2);
|
||||||
|
|
||||||
|
WHEN("Comparing them") {
|
||||||
|
bool equals = v1 == v2;
|
||||||
|
|
||||||
|
THEN("The result should be true") {
|
||||||
|
REQUIRE(equals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GIVEN("Two vectors with different items") {
|
||||||
|
Vector<int> v1;
|
||||||
|
Vector<int> v2;
|
||||||
|
|
||||||
|
v1.push_back(1);
|
||||||
|
v2.push_back(2);
|
||||||
|
|
||||||
|
v1.push_back(5);
|
||||||
|
v2.push_back(5);
|
||||||
|
|
||||||
|
REQUIRE(v1.size() == 2);
|
||||||
|
REQUIRE(v2.size() == 2);
|
||||||
|
|
||||||
|
WHEN("Comparing them") {
|
||||||
|
bool equals = v1 == v2;
|
||||||
|
|
||||||
|
THEN("The result should be false") {
|
||||||
|
REQUIRE_FALSE(equals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SCENARIO("Erasing an item removes it and moves the following ones forward",
|
||||||
|
"[vector]") {
|
||||||
|
GIVEN("Two vectors with almost identical items") {
|
||||||
|
Vector<int> v1;
|
||||||
|
Vector<int> v2;
|
||||||
|
|
||||||
|
v1.push_back(1);
|
||||||
|
v2.push_back(1);
|
||||||
|
|
||||||
|
v1.push_back(2);
|
||||||
|
v2.push_back(5);
|
||||||
|
|
||||||
|
v1.push_back(5);
|
||||||
|
|
||||||
|
v1.push_back(10);
|
||||||
|
v2.push_back(10);
|
||||||
|
|
||||||
|
REQUIRE(v1.size() == 4);
|
||||||
|
REQUIRE(v2.size() == 3);
|
||||||
|
|
||||||
|
WHEN("Comparing them") {
|
||||||
|
bool equals = v1 == v2;
|
||||||
|
|
||||||
|
THEN("The result should be false") {
|
||||||
|
REQUIRE_FALSE(equals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("Erasing the different item") {
|
||||||
|
v1.erase(1);
|
||||||
|
bool equals = v1 == v2;
|
||||||
|
|
||||||
|
THEN("The result should be true") {
|
||||||
|
REQUIRE(equals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SCENARIO("Copy Assignment", "[vector]") {
|
||||||
|
GIVEN("Two vectors with identical items") {
|
||||||
|
Vector<int> v1;
|
||||||
|
Vector<int> v2;
|
||||||
|
|
||||||
|
v1.push_back(1);
|
||||||
|
v2.push_back(1);
|
||||||
|
|
||||||
|
v1.push_back(5);
|
||||||
|
v2.push_back(5);
|
||||||
|
|
||||||
|
REQUIRE(v1.size() == 2);
|
||||||
|
REQUIRE(v2.size() == 2);
|
||||||
|
|
||||||
|
WHEN("Copy assigning the second vector to a third vector") {
|
||||||
|
Vector<int> v3;
|
||||||
|
v3 = v2;
|
||||||
|
|
||||||
|
THEN("All vectors should be identical") {
|
||||||
|
bool equals = v1 == v2 && v2 == v3 && v1 == v3;
|
||||||
|
REQUIRE(equals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SCENARIO("Move Assignment", "[vector]") {
|
||||||
|
GIVEN("Two vectors with identical items") {
|
||||||
|
Vector<int> v1;
|
||||||
|
Vector<int> v2;
|
||||||
|
|
||||||
|
v1.push_back(1);
|
||||||
|
v2.push_back(1);
|
||||||
|
|
||||||
|
v1.push_back(5);
|
||||||
|
v2.push_back(5);
|
||||||
|
|
||||||
|
REQUIRE(v1.size() == 2);
|
||||||
|
REQUIRE(v2.size() == 2);
|
||||||
|
|
||||||
|
WHEN("Move assigning the second vector to a third vector") {
|
||||||
|
Vector<int> v3;
|
||||||
|
v3 = std::move(v2);
|
||||||
|
|
||||||
|
THEN("The first and third vector should be identical") {
|
||||||
|
bool equals = v1 == v3;
|
||||||
|
REQUIRE(equals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SCENARIO("Reserve additional space", "[vector]") {
|
||||||
|
GIVEN("A vector with a given length") {
|
||||||
|
Vector<int> v(5);
|
||||||
|
|
||||||
|
REQUIRE(v.length() == 5);
|
||||||
|
|
||||||
|
WHEN("Reserving additional space") {
|
||||||
|
v.reserve(10);
|
||||||
|
|
||||||
|
THEN("The length has increased accordingly") {
|
||||||
|
REQUIRE(v.length() == 15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SCENARIO("Resizing a vector", "[vector]") {
|
||||||
|
GIVEN("A vector with 3 items") {
|
||||||
|
Vector<int> v;
|
||||||
|
|
||||||
|
v.push_back(1);
|
||||||
|
v.push_back(2);
|
||||||
|
v.push_back(3);
|
||||||
|
|
||||||
|
Vector<int> target;
|
||||||
|
|
||||||
|
target.push_back(1);
|
||||||
|
target.push_back(2);
|
||||||
|
target.push_back(3);
|
||||||
|
target.push_back(0);
|
||||||
|
target.push_back(0);
|
||||||
|
|
||||||
|
WHEN("Resizing to 5") {
|
||||||
|
v.resize(5);
|
||||||
|
|
||||||
|
THEN("The size should be 5") {
|
||||||
|
REQUIRE(v.size() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
THEN("2 new default items should've been added") {
|
||||||
|
bool equals = v == target;
|
||||||
|
REQUIRE(equals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("Resizing to 1") {
|
||||||
|
v.resize(1);
|
||||||
|
|
||||||
|
THEN("The size should be 1") {
|
||||||
|
REQUIRE(v.size() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
THEN("The remaining element should be correct") {
|
||||||
|
REQUIRE(v[0] == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
THEN("Adding the elements again produces the same result again") {
|
||||||
|
v.push_back(2);
|
||||||
|
v.push_back(3);
|
||||||
|
v.push_back(0);
|
||||||
|
v.push_back(0);
|
||||||
|
|
||||||
|
bool equals = v == target;
|
||||||
|
REQUIRE(equals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user