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..126d27c --- /dev/null +++ b/BUILD @@ -0,0 +1,10 @@ +cc_library( + name = "build_header", + hdrs = [ + "ali_unique_ptr.h" + ], + copts = [ + "-std=c++2a", + ], + visibility = ["//visibility:public"] +) \ No newline at end of file diff --git a/README.md b/README.md index 8b0034a..114db0c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,11 @@ # uniq_ptr -A minimal implementation of std::unique_ptr + +A minimal implementation of std::uniq_ptr. + +## How to test? + +You can use bazel: +
+
$ bazel test tests:ali_unique_ptr_test --repo_env=CC=g++-10
+
+
diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 0000000..275a329 --- /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", +) \ No newline at end of file diff --git a/ali_unique_ptr.h b/ali_unique_ptr.h new file mode 100644 index 0000000..91e4614 --- /dev/null +++ b/ali_unique_ptr.h @@ -0,0 +1,101 @@ +// +// Created by Ali Moammeri on 3/28/22. +// + +#ifndef ALI_UNIQUE_PTR_H +#define ALI_UNIQUE_PTR_H + +#include +#include +#include + +namespace ali { + template class unique_ptr { + friend std::ostream& operator<<(std::ostream&, const unique_ptr&); + public: + unique_ptr() noexcept= default; + explicit unique_ptr(std::nullptr_t nptr) noexcept: _pointer{nptr} {} + explicit unique_ptr(T* pointer) noexcept : _pointer{pointer} {} + unique_ptr(const unique_ptr&) noexcept= delete; + unique_ptr(unique_ptr&& other) noexcept : _pointer {other.release()}{}; + ~unique_ptr() { delete _pointer; } + + T* get() const noexcept { return _pointer; } + T* release() noexcept { + T* temp_ptr {get()}; + _pointer = nullptr; + return temp_ptr; + } + void reset(T* pointer = T()) noexcept { + delete _pointer; + _pointer = pointer; + } + void reset(std::nullptr_t nptr) noexcept { + delete _pointer; + _pointer = nptr; + } + void swap(unique_ptr& other) { std::swap(_pointer, other._pointer); } + unique_ptr& operator=(unique_ptr&& other) noexcept { + reset(other.release()); + return *this; + } + unique_ptr& operator=(const unique_ptr&) noexcept = delete; + auto operator<=>(const unique_ptr& rhs) const = default; + explicit operator bool() const noexcept { return _pointer != nullptr; } + T& operator*() { return *get(); } + T* operator->() { return get(); } + + private: + T* _pointer{nullptr}; + }; + + // Specialization for arrays: + template class unique_ptr { + friend std::ostream& operator<<(std::ostream&, const unique_ptr&); + public: + unique_ptr() noexcept= default; + explicit unique_ptr(std::nullptr_t nptr) noexcept: _pointer{nptr} {} + explicit unique_ptr(T pointer[]) noexcept : _pointer{pointer} {} + unique_ptr(const unique_ptr&) noexcept= delete; + unique_ptr(unique_ptr&& other) noexcept : _pointer {other.release()}{}; + ~unique_ptr() { delete[] _pointer; } + + T* get() const noexcept { return _pointer; } + T* release() noexcept { + T* temp_ptr {get()}; + _pointer = nullptr; + return temp_ptr; + } + void reset(T* pointer = T()) noexcept { + delete _pointer; + _pointer = pointer; + } + void reset(std::nullptr_t nptr) noexcept { + delete _pointer; + _pointer = nptr; + } + void swap(unique_ptr& other) { std::swap(_pointer, other._pointer); } + unique_ptr& operator=(unique_ptr&& other) noexcept { + reset(other.release()); + return *this; + } + + unique_ptr& operator=(const unique_ptr&) noexcept = delete; + auto operator<=>(const unique_ptr& rhs) const = default; + explicit operator bool() const noexcept { return _pointer != nullptr; } + T& operator*() { return *get(); } + T* operator->() { return get(); } + T& operator[](const std::size_t& index) { return *(get() + index); } + + private: + T* _pointer{nullptr}; + }; +} + +template +std::ostream& operator<<(std::ostream& out, const ali::unique_ptr& u_ptr) { + out << u_ptr.get(); + return out; +} + +#endif //ALI_UNIQUE_PTR_H \ No newline at end of file diff --git a/tests/BUILD b/tests/BUILD new file mode 100644 index 0000000..f5cc241 --- /dev/null +++ b/tests/BUILD @@ -0,0 +1,11 @@ +cc_test( + name = "ali_unique_ptr_test", + srcs = glob(["**/*.cc"]), + copts = [ + "-std=c++2a", + ], + deps = [ + "//:build_header", + "@googletest//:gtest_main", + ], +) \ No newline at end of file diff --git a/tests/ali_unique_ptr_test.cc b/tests/ali_unique_ptr_test.cc new file mode 100644 index 0000000..bdabda9 --- /dev/null +++ b/tests/ali_unique_ptr_test.cc @@ -0,0 +1,159 @@ +#include "ali_unique_ptr.h" +#include +#include + +TEST(UniquePtrTest, DefaultConstructor) { + ali::unique_ptr u_ptr; + EXPECT_EQ(u_ptr.get(), nullptr); +} + +TEST(UniquePtrTest, NullConstructor) { + ali::unique_ptr u_ptr{nullptr}; + EXPECT_EQ(u_ptr.get(), nullptr); +} + +TEST(UniquePtrTest, PointerConstructor) { + ali::unique_ptr u_ptr{new int}; + EXPECT_NE(u_ptr.get(), nullptr); +} + +TEST(UniquePtrTest, MoveCostructor) { + ali::unique_ptr u_ptr1{new int}; + ali::unique_ptr u_ptr2{std::move(u_ptr1)}; + EXPECT_EQ(u_ptr1.get(), nullptr); + EXPECT_NE(u_ptr2.get(), nullptr); +} + +TEST(UniquePtrTest, ReleaseTest) { + ali::unique_ptr u_ptr1{new int}; + ali::unique_ptr u_ptr2{u_ptr1.release()}; + EXPECT_EQ(u_ptr1.get(), nullptr); + EXPECT_NE(u_ptr2.get(), nullptr); +} + +TEST(UniquePtrTest, ResetTest) { + ali::unique_ptr u_ptr{new int}; + u_ptr.reset(nullptr); + EXPECT_EQ(u_ptr.get(), nullptr); + u_ptr.reset(new int); + EXPECT_NE(u_ptr.get(), nullptr); +} + +TEST(UniquePtrTest, DereferenceTest) { + constexpr int a {3}; + constexpr int b {5}; + ali::unique_ptr u_ptr1{new int{a}}; + ali::unique_ptr u_ptr2{new int{b}}; + EXPECT_EQ(*u_ptr1, a); + EXPECT_EQ(*u_ptr2, b); +} + +TEST(UniquePtrTest, SwapTest) { + constexpr int a {3}; + constexpr int b {5}; + ali::unique_ptr u_ptr1{new int{a}}; + ali::unique_ptr u_ptr2{new int{b}}; + u_ptr1.swap(u_ptr2); + EXPECT_EQ(*u_ptr1, b); + EXPECT_EQ(*u_ptr2, a); +} + +TEST(UniquePtrTest, EqualityOperator) { + ali::unique_ptr u_ptr1{new int}; + ali::unique_ptr u_ptr2{new int}; + EXPECT_EQ(u_ptr1 == u_ptr2, 0); + EXPECT_EQ(u_ptr1 == u_ptr1, 1); +} + +TEST(UniquePtrTest, NEqualityOperator) { + ali::unique_ptr u_ptr1{new int}; + ali::unique_ptr u_ptr2{new int}; + EXPECT_EQ(u_ptr1 != u_ptr2, true); + EXPECT_EQ(u_ptr1 != u_ptr1, false); +} + +TEST(UniquePtrTest, ComparisionOperatorsTest) { + ali::unique_ptr u_ptr1{new int}; + ali::unique_ptr u_ptr2{new int}; + EXPECT_EQ(u_ptr1 < u_ptr2, false); + EXPECT_EQ(u_ptr1 > u_ptr2, true); +} + +TEST(UniquePtrTest, BoolCastTest) { + ali::unique_ptr u_ptr1; + ali::unique_ptr u_ptr2{new int}; + EXPECT_EQ(static_cast(u_ptr1), false); + EXPECT_EQ(static_cast(u_ptr2), true); +} + +TEST(UniquePtrForArrays, Constructor) { + constexpr std::size_t n {5}; + ali::unique_ptr u_ptr{new int[n]}; + EXPECT_NE(u_ptr.get(), nullptr); +} + +TEST(UniquePtrForArrays, MoveCostructor) { + constexpr std::size_t n{5}; + ali::unique_ptr u_ptr1{new int[n]}; + EXPECT_NE(u_ptr1.get(), nullptr); + ali::unique_ptr u_ptr2(std::move(u_ptr1)); + EXPECT_EQ(u_ptr1.get(), nullptr); + EXPECT_NE(u_ptr2.get(), nullptr); +} + +TEST(UniquePtrForArrays, ReleaseTest) { + constexpr std::size_t n{5}; + ali::unique_ptr u_ptr{new int[n]}; + u_ptr.release(); + EXPECT_EQ(u_ptr.get(), nullptr); +} + +TEST(UniquePtrForArrays, ResetTest) { + constexpr std::size_t n{10}; + ali::unique_ptr u_ptr{new int[n]}; + u_ptr.reset(nullptr); + EXPECT_EQ(u_ptr.get(), nullptr); + u_ptr.reset(new int[n]); + EXPECT_NE(u_ptr.get(), nullptr); +} + +TEST(UniquePtrForArrays, SwapTest) { + constexpr std::size_t n{10}; + ali::unique_ptr u_ptr1{new int[n]}; + ali::unique_ptr u_ptr2; + u_ptr1.swap(u_ptr2); + EXPECT_EQ(u_ptr1.get(), nullptr); + EXPECT_NE(u_ptr2.get(), nullptr); +} + +TEST(UniquePtrForArrays, MoveAssigment) { + constexpr std::size_t n{10}; + ali::unique_ptr u_ptr1{new int[n]}; + ali::unique_ptr u_ptr2{new int[n]}; + u_ptr2 = std::move(u_ptr1); + EXPECT_EQ(u_ptr1.get(), nullptr); + EXPECT_NE(u_ptr2.get(), nullptr); +} + +TEST(UniquePtrForArrays, BoolCast) { + constexpr std::size_t n{10}; + ali::unique_ptr u_ptr1; + ali::unique_ptr u_ptr2{new int[n]}; + EXPECT_EQ(static_cast(u_ptr1), false); + EXPECT_EQ(static_cast(u_ptr2), true); +} + +TEST(UniquePtrForArrays, DereferenceTest) { + constexpr std::size_t n{5}; + ali::unique_ptr u_ptr(new int[n] {1, 2, 3, 4, 5}); + for (size_t i {0}; i < n; i++) + EXPECT_EQ(u_ptr[i], i + 1); +} + +TEST(UniquePtrForArrays, EqualityOperator) { + constexpr std::size_t n{5}; + ali::unique_ptr u_ptr1; + ali::unique_ptr u_ptr2{new int[n]}; + EXPECT_EQ(u_ptr1 == u_ptr1, true); + EXPECT_EQ(u_ptr1 == u_ptr2, false); +} \ No newline at end of file