Implemented unique_ref and started writing test cases
This commit is contained in:
parent
3069874066
commit
3d5b9e9815
104
test/unique_ref_test.cpp
Normal file
104
test/unique_ref_test.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
#include <google/gtest/gtest.h>
|
||||
#include "../unique_ref.h"
|
||||
|
||||
using namespace cpputils;
|
||||
|
||||
//TODO Add some test cases
|
||||
|
||||
class SomeClass0Parameters {};
|
||||
class SomeClass1Parameter {
|
||||
public:
|
||||
SomeClass1Parameter(int param_): param(param_) {}
|
||||
int param;
|
||||
};
|
||||
class SomeClass2Parameters {
|
||||
public:
|
||||
SomeClass2Parameters(int param1_, int param2_): param1(param1_), param2(param2_) {}
|
||||
int param1;
|
||||
int param2;
|
||||
};
|
||||
|
||||
TEST(MakeUniqueRefTest, Primitive) {
|
||||
unique_ref<int> var = make_unique_ref<int>(3);
|
||||
EXPECT_EQ(3, *var);
|
||||
}
|
||||
|
||||
TEST(MakeUniqueRefTest, ClassWith0Parameters) {
|
||||
unique_ref<SomeClass0Parameters> var = make_unique_ref<SomeClass0Parameters>();
|
||||
//Check that the type is correct
|
||||
EXPECT_EQ(var.get(), dynamic_cast<SomeClass0Parameters*>(var.get()));
|
||||
}
|
||||
|
||||
TEST(MakeUniqueRefTest, ClassWith1Parameter) {
|
||||
unique_ref<SomeClass1Parameter> var = make_unique_ref<SomeClass1Parameter>(5);
|
||||
EXPECT_EQ(5, var->param);
|
||||
}
|
||||
|
||||
TEST(MakeUniqueRefTest, ClassWith2Parameters) {
|
||||
unique_ref<SomeClass2Parameters> var = make_unique_ref<SomeClass2Parameters>(7,2);
|
||||
EXPECT_EQ(7, var->param1);
|
||||
EXPECT_EQ(2, var->param2);
|
||||
}
|
||||
|
||||
TEST(MakeUniqueRefTest, TypeIsAutoDeductible) {
|
||||
auto var1 = make_unique_ref<int>(3);
|
||||
auto var2 = make_unique_ref<SomeClass0Parameters>();
|
||||
auto var3 = make_unique_ref<SomeClass1Parameter>(2);
|
||||
auto var4 = make_unique_ref<SomeClass2Parameters>(2, 3);
|
||||
}
|
||||
|
||||
TEST(NullcheckTest, PrimitiveNullptr) {
|
||||
boost::optional<unique_ref<int>> var = nullcheck(std::unique_ptr<int>(nullptr));
|
||||
EXPECT_FALSE((bool)var);
|
||||
}
|
||||
|
||||
TEST(NullcheckTest, ObjectNullptr) {
|
||||
boost::optional<unique_ref<SomeClass0Parameters>> var = nullcheck(std::unique_ptr<SomeClass0Parameters>(nullptr));
|
||||
EXPECT_FALSE((bool)var);
|
||||
}
|
||||
|
||||
TEST(NullcheckTest, Primitive) {
|
||||
boost::optional<unique_ref<int>> var = nullcheck(std::make_unique<int>(3));
|
||||
EXPECT_TRUE((bool)var);
|
||||
EXPECT_EQ(3, **var);
|
||||
}
|
||||
|
||||
TEST(NullcheckTest, ClassWith0Parameters) {
|
||||
boost::optional<unique_ref<SomeClass0Parameters>> var = nullcheck(std::make_unique<SomeClass0Parameters>());
|
||||
EXPECT_TRUE((bool)var);
|
||||
//Check that the type is correct
|
||||
EXPECT_EQ(var->get(), dynamic_cast<SomeClass0Parameters*>(var->get()));
|
||||
}
|
||||
|
||||
TEST(NullcheckTest, ClassWith1Parameter) {
|
||||
boost::optional<unique_ref<SomeClass1Parameter>> var = nullcheck(std::make_unique<SomeClass1Parameter>(5));
|
||||
EXPECT_TRUE((bool)var);
|
||||
EXPECT_EQ(5, (*var)->param);
|
||||
}
|
||||
|
||||
TEST(NullcheckTest, ClassWith2Parameters) {
|
||||
boost::optional<unique_ref<SomeClass2Parameters>> var = nullcheck(std::make_unique<SomeClass2Parameters>(7,2));
|
||||
EXPECT_TRUE((bool)var);
|
||||
EXPECT_EQ(7, (*var)->param1);
|
||||
EXPECT_EQ(2, (*var)->param2);
|
||||
}
|
||||
|
||||
TEST(NullcheckTest, OptionIsResolvable_Primitive) {
|
||||
boost::optional<unique_ref<int>> var = nullcheck(std::make_unique<int>(3));
|
||||
unique_ref<int> resolved = std::move(*var);
|
||||
}
|
||||
|
||||
TEST(NullcheckTest, OptionIsResolvable_Object) {
|
||||
boost::optional<unique_ref<SomeClass0Parameters>> var = nullcheck(std::make_unique<SomeClass0Parameters>());
|
||||
unique_ref<SomeClass0Parameters> resolved = std::move(*var);
|
||||
}
|
||||
|
||||
TEST(NullcheckTest, OptionIsAutoResolvable_Primitive) {
|
||||
auto var = nullcheck(std::make_unique<int>(3));
|
||||
auto resolved = std::move(*var);
|
||||
}
|
||||
|
||||
TEST(NullcheckTest, OptionIsAutoResolvable_Object) {
|
||||
auto var = nullcheck(std::make_unique<SomeClass0Parameters>());
|
||||
auto resolved = std::move(*var);
|
||||
}
|
126
unique_ref.h
Normal file
126
unique_ref.h
Normal file
@ -0,0 +1,126 @@
|
||||
#ifndef MESSMER_CPP_UTILS_UNIQUE_REF_H
|
||||
#define MESSMER_CPP_UTILS_UNIQUE_REF_H
|
||||
|
||||
#include <memory>
|
||||
#include <boost/optional.hpp>
|
||||
#include "macros.h"
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
/**
|
||||
* unique_ref<T> behaves like unique_ptr<T>, but guarantees that the pointer points to a valid object.
|
||||
* You can create objects using make_unique_ref (works like make_unique for unique_ptr).
|
||||
*
|
||||
* If you happen to already have a unique_ptr<T>, you can call nullcheck(unique_ptr),
|
||||
* which returns optional<unique_ref<T>>.
|
||||
* Take care that this should be used very rarely, since it circumvents parts of the guarantee.
|
||||
* It still protects against null pointers, but it does not guarantee anymore that the pointer points
|
||||
* to a valid object. It might hold an arbitrary non-null memory location.
|
||||
*
|
||||
* Caution: There is one way a unique_ref<T> can actually hold a nullptr.
|
||||
* It will hold a nullptr after its value was moved to another unique_ref.
|
||||
* Never use the old instance after moving!
|
||||
*/
|
||||
template<typename T>
|
||||
class unique_ref {
|
||||
public:
|
||||
|
||||
unique_ref(unique_ref&& from): _target(std::move(from._target)) {}
|
||||
|
||||
unique_ref& operator=(unique_ref&& from) {
|
||||
_target = from._target;
|
||||
}
|
||||
|
||||
typename std::add_lvalue_reference<T>::type operator*() const {
|
||||
return *_target;
|
||||
}
|
||||
|
||||
T* operator->() const {
|
||||
return get();
|
||||
}
|
||||
|
||||
T* get() const {
|
||||
return _target.get();
|
||||
}
|
||||
|
||||
T* release() {
|
||||
return _target.release();
|
||||
}
|
||||
|
||||
void swap(unique_ref&& rhs) {
|
||||
_target.swap(rhs._target);
|
||||
}
|
||||
|
||||
private:
|
||||
unique_ref(std::unique_ptr<T> target): _target(std::move(target)) {}
|
||||
template<typename U, typename... Args> friend unique_ref<U> make_unique_ref(Args&&... args);
|
||||
template<typename U> friend boost::optional<unique_ref<U>> nullcheck(std::unique_ptr<U> ptr);
|
||||
|
||||
std::unique_ptr<T> _target;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(unique_ref);
|
||||
};
|
||||
|
||||
template<typename T, typename... Args>
|
||||
inline unique_ref<T> make_unique_ref(Args&&... args) {
|
||||
return unique_ref<T>(std::make_unique<T>(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline boost::optional<unique_ref<T>> nullcheck(std::unique_ptr<T> ptr) {
|
||||
if (ptr.get() != nullptr) {
|
||||
return unique_ref<T>(std::move(ptr));
|
||||
}
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
inline bool operator==(const unique_ref<T1>& lhs, const unique_ref<T2>& rhs) {
|
||||
return lhs.get() == rhs.get();
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
inline bool operator!=(const unique_ref<T1>& lhs, const unique_ref<T2>& rhs) {
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
inline bool operator<(const unique_ref<T1>& lhs, const unique_ref<T2>& rhs) {
|
||||
return lhs.get() < rhs.get();
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
inline bool operator<=(const unique_ref<T1>& lhs, const unique_ref<T2>& rhs) {
|
||||
return !operator<(rhs, lhs);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
inline bool operator>(const unique_ref<T1>& lhs, const unique_ref<T2>& rhs) {
|
||||
return operator<(rhs, lhs);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
inline bool operator>=(const unique_ref<T1>& lhs, const unique_ref<T2>& rhs) {
|
||||
return !operator<(lhs, rhs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template<typename T>
|
||||
inline void swap(cpputils::unique_ref<T>& lhs, cpputils::unique_ref<T>& rhs) {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void swap(cpputils::unique_ref<T>&& lhs, cpputils::unique_ref<T>& rhs) {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void swap(cpputils::unique_ref<T>& lhs, cpputils::unique_ref<T>&& rhs) {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user