diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6d8ad95 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bazel-* \ No newline at end of file diff --git a/BUILD b/BUILD new file mode 100644 index 0000000..b8d56be --- /dev/null +++ b/BUILD @@ -0,0 +1,10 @@ +cc_library( + name = "build_header", + hdrs = [ + "ali_vector.h" + ], + copts = [ + "-std=c++2a", + ], + visibility = ["//visibility:public"] +) diff --git a/README.md b/README.md index 6fcb573..2524557 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,10 @@ # vector + My implementation of std::vector + +## How to test? + +
+
$ bazel test tests:ali_vector_test --repo_env=CC=c++
+
+
diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 0000000..b54973d --- /dev/null +++ b/WORKSPACE @@ -0,0 +1,7 @@ +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +git_repository( + name = "googletest", + remote = "https://github.com/google/googletest", + tag = "release-1.10.0", +) diff --git a/ali_vector.h b/ali_vector.h new file mode 100644 index 0000000..583eba7 --- /dev/null +++ b/ali_vector.h @@ -0,0 +1,205 @@ +// +// Created by Ali Moameri on 4/10/22. +// + +#ifndef ALI_VECTOR_H +#define ALI_VECTOR_H + +#include +#include +#include +#include + +namespace ali { + template class vector { + public: + vector() + : m_size{0}, m_capacity{0}, ptr{nullptr} {} + + explicit vector(const std::size_t& _size) + : m_size{_size}, m_capacity{_size * 2} { + ptr = m_alloc.allocate(m_capacity); + } + + explicit vector(const std::size_t& _size, const T& value) + : m_size{_size}, m_capacity{_size * 2} { + ptr = m_alloc.allocate(m_capacity); + for(std::size_t i{0}; i < m_size; ++i) + m_alloc.construct(ptr + i, value); + } + + vector(const std::initializer_list& ls) + : m_size{ls.size()}, m_capacity{ls.size() * 2} { + ptr = m_alloc.allocate(m_capacity); + for(std::size_t i{0}; i < ls.size(); ++i) + m_alloc.construct(ptr + i, *(ls.begin() + i)); + } + + vector(const ali::vector& rhs) + :m_size{rhs.size()}, m_capacity{rhs.capacity()} { + ptr = m_alloc.allocate(m_capacity); + for(std::size_t i{0}; i < rhs.size(); ++i) + m_alloc.construct(ptr + i, rhs[i]); + } + + vector(ali::vector&& rhs) noexcept + :m_size{rhs.size()}, m_capacity{rhs.capacity()} { + ptr = m_alloc.allocate(m_capacity); + for(std::size_t i{0}; i < rhs.size(); ++i) + m_alloc.construct(ptr + i, rhs[i]); + rhs.clear(); + m_capacity = 0; + } + + ~vector() { m_alloc.deallocate(ptr, m_capacity); } + + [[nodiscard]] constexpr std::size_t size() const noexcept { return m_size; } + [[nodiscard]] constexpr std::size_t capacity() const noexcept { return m_capacity; } + + void clear() noexcept { + delete[] ptr; + ptr = nullptr; + m_size = 0; + } + + void push_back(const T& value) { + if(m_capacity == 0) + reserve(8); + else if(m_size == m_capacity) + reserve(m_size * 2); + ptr[m_size++] = value; + } + + + void pop_back() { + m_size = m_size > 0 ? m_size - 1 : m_size; + } + + T& at(std::size_t index) { + if (index < m_size) + return ptr[index]; + else + throw std::out_of_range("index out of range"); + } + + const T& at(std::size_t index) const { + if (index < m_size) + return ptr[index]; + else + throw std::out_of_range("index out of range"); + } + + void shrink_to_fit() { + if (m_size < m_capacity) { + T* new_ptr{m_alloc.allocate(m_size)}; + for(std::size_t i{0}; i < m_size; ++i) + m_alloc.construct(new_ptr + i, ptr[i]); + for(std::size_t i{0}; i < m_size; ++i) + m_alloc.destroy(ptr + i); + m_alloc.deallocate(ptr, m_capacity); + ptr = new_ptr; + m_capacity = m_size; + } + } + + void reserve(std::size_t space) { + if (space > m_capacity) { + T* new_ptr{m_alloc.allocate(space)}; + + for(std::size_t i{0}; i < m_size; ++i) + m_alloc.construct(new_ptr + i, ptr[i]); + for(std::size_t i{0}; i < m_size; ++i) + m_alloc.destroy(ptr + i); + + m_alloc.deallocate(ptr, m_capacity); + ptr = new_ptr; + m_capacity = space; + } + } + + [[nodiscard]] bool empty() const { return size() == 0; } + + void swap(ali::vector& rhs) { + std::swap(m_size, rhs.m_size); + std::swap(m_capacity, rhs.m_capacity); + std::swap(m_alloc, rhs.m_alloc); + std::swap(ptr, rhs.ptr); + } + + T& operator[](const std::size_t& index) { + if(index >= size()) + throw std::out_of_range("out of range index"); + else + return ptr[index]; + } + + const T& operator[](const std::size_t& index) const { + if(index >= size()) + throw std::out_of_range("out of range index"); + else + return ptr[index]; + } + + ali::vector& operator=(const ali::vector& rhs) noexcept { + if(this == &rhs) + return *this; + + if(rhs.size() <= m_capacity) { + std::copy(rhs.ptr, rhs.ptr + rhs.size(), ptr); + m_size = rhs.size(); + return *this; + } + + T* new_ptr{m_alloc.allocate(rhs.size())}; + for(std::size_t i{0}; i < rhs.size(); ++i) + m_alloc.construct(new_ptr + i, rhs[i]); + for(std::size_t i{0}; i < m_size; ++i) + m_alloc.destroy(ptr + i); + m_alloc.deallocate(ptr, m_capacity); + ptr = new_ptr; + m_capacity = m_size = rhs.size(); + return *this; + } + + ali::vector& operator=(ali::vector&& rhs) noexcept { + if(this == &rhs) + return *this; + + if(rhs.size() <= m_capacity) { + std::copy(rhs.ptr, rhs.ptr + rhs.size(), ptr); + m_size = rhs.size(); + } else { + T* new_ptr{m_alloc.allocate(rhs.size())}; + for(std::size_t i{0}; i < rhs.size(); ++i) + m_alloc.construct(new_ptr + i, rhs[i]); + for(std::size_t i{0}; i < m_size; ++i) + m_alloc.destroy(ptr + i); + m_alloc.deallocate(ptr, m_capacity); + ptr = new_ptr; + m_capacity = m_size = rhs.size(); + } + + rhs.clear(); + rhs.m_capacity = 0; + return *this; + } + + bool operator==(const vector &rhs) const { + if (size() != rhs.size()) + return false; + for (std::size_t i{0}; i < size(); ++i) { + if (ptr[i] != rhs[i]) + return false; + } + return true; + } + + private: + std::size_t m_size{0}; + std::size_t m_capacity{0}; + std::allocator m_alloc; + T* ptr{nullptr}; + }; +} + +#endif //ALI_VECTOR_H diff --git a/tests/BUILD b/tests/BUILD new file mode 100644 index 0000000..be95c33 --- /dev/null +++ b/tests/BUILD @@ -0,0 +1,11 @@ +cc_test( + name = "ali_vector_test", + srcs = glob(["**/*.cc"]), + copts = [ + "-std=c++2a", + ], + deps = [ + "//:build_header", + "@googletest//:gtest_main", + ], +) diff --git a/tests/ali_vector_ptr_test.cc b/tests/ali_vector_ptr_test.cc new file mode 100644 index 0000000..9e8f43c --- /dev/null +++ b/tests/ali_vector_ptr_test.cc @@ -0,0 +1,99 @@ +#include "ali_vector.h" +#include +#include + +struct T { + int x; + + T(const int input) : x(input) + {} +}; + +constexpr std::size_t size {10}; +constexpr std::size_t capacity {size*2}; + +TEST(VectorTest, DefaultConstructor) { + ali::vector v; + EXPECT_EQ(v.size(), 0); + EXPECT_EQ(v.capacity(), 0); +} + +TEST(VectorTest, Constructors) { + ali::vector v(size); + EXPECT_EQ(v.size(), size); + EXPECT_EQ(v.capacity(), capacity); + + ali::vector v2(size, 6); + EXPECT_EQ(v2.size(), size); + EXPECT_EQ(v2.capacity(), capacity); + EXPECT_EQ(v2[5].x, 6); + + ali::vector v3{1, 2 ,3 ,4}; + EXPECT_EQ(v3.size(), 4); + EXPECT_EQ(v3[1].x, 2); +} + +TEST(VectorTest, CopyConstructor) { + ali::vector v{1, 2, 3}; + ali::vector v2{v}; + EXPECT_EQ(v == v2, true); +} + +TEST(VectorTest, MoveConstructor) { + ali::vector v{1, 2, 3}; + ali::vector v2{std::move(v)}; + EXPECT_EQ(v.empty(), true); + EXPECT_EQ(v2[1].x, 2); +} + +TEST(VectorTest, Clear) { + ali::vector v{1, 2, 3}; + v.clear(); + EXPECT_EQ(v.size(), 0); +} + +TEST(VectorTest, PushBack) { + ali::vector v{1, 2, 3}; + v.push_back(T{4}); + EXPECT_EQ(v.size(), 4); + EXPECT_EQ(v[3].x, 4); +} + +TEST(VectorTest, PopBack) { + ali::vector v{1, 2, 3}; + v.pop_back(); + EXPECT_EQ(v.size(), 2); +} + +TEST(VectorTest, Empty) { + ali::vector v{1, 2, 3}; + ali::vector v2; + EXPECT_EQ(v.empty(), false); + EXPECT_EQ(v2.empty(), true); +} + +TEST(VectorTest, Assigment) { + ali::vector v{1, 2, 3}; + ali::vector v2; + v2 = v; + for(std::size_t i{0}; i < v.size(); ++i) + EXPECT_EQ(v[i].x, v2[i].x); +} + +TEST(VectorTest, MoveAssigment) { + ali::vector v{1, 2, 3}; + ali::vector v2{v}; + ali::vector v3; + v3 = std::move(v); + + for(std::size_t i{0}; i < v3.size(); ++i) + EXPECT_EQ(v3[i].x, v2[i].x); + + EXPECT_EQ(v.empty(), true); +} + +TEST(VectorTest, ConstDerefence) { + const ali::vector v{1, 2, 3}; + EXPECT_EQ(v[2].x, 3); +} +