Commit 0d86bc1a authored by Daniele Kruse's avatar Daniele Kruse Committed by Steven Murray
Browse files

Added the optional class template along with its unit tests

parent b1086c9c
......@@ -130,7 +130,8 @@ set (COMMON_UNIT_TESTS_LIB_SRC_FILES
threading/DaemonTest.cpp
threading/SocketPairTest.cpp
utils/UtilsTest.cpp
UserIdentityTest.cpp)
UserIdentityTest.cpp
optionalTest.cpp)
add_library (ctacommonunittests SHARED
${COMMON_UNIT_TESTS_LIB_SRC_FILES})
......
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <utility> // std::move
#include <type_traits> // std::is_trivially_destructible
#include <stdexcept> // std::logic_error
namespace cta {
struct nullopt_t {
nullopt_t() {}
};
nullopt_t nullopt{};
template <class T> class optional
{
public:
//constructors
optional();
optional(nullopt_t);
optional(const optional& other);
optional(optional&& other);
optional(const T& value);
optional(T&& value);
//destructor
~optional();
//assignment
optional& operator=(nullopt_t);
optional& operator=(optional& other);
optional& operator=(const optional& other);
optional& operator=(optional&& other);
template<class U> optional& operator=(U&& value);
//accessing the value
const T* operator->() const;
T* operator->();
const T& operator*() const&;
T& operator*() &;
const T&& operator*() const&&;
T&& operator*() &&;
//bool operator
explicit operator bool() const;
//returns the contained value
T& value() &;
const T & value() const &;
T&& value() &&;
const T&& value() const &&;
//swap
void swap(optional& other);
private:
bool is_set;
T val;
};
//constructors
template <class T> optional<T>::optional(): is_set(false) {
}
template <class T> optional<T>::optional(nullopt_t): is_set(false) {
}
template <class T> optional<T>::optional(const optional& other) {
if(other.is_set) {
is_set=true;
val=other.val;
}
else {
is_set=false;
}
}
template <class T> optional<T>::optional(optional&& other) {
if(other.is_set) {
is_set=true;
val=std::move(other.val);
}
else {
is_set=false;
}
}
template <class T> optional<T>::optional(const T& value): is_set(true), val(value) {
}
template <class T> optional<T>::optional(T&& value): is_set(true), val(std::move(value)) {
}
//destructor
template <class T> optional<T>::~optional() {
}
//assignment
template <class T> optional<T>& optional<T>::operator=(nullopt_t) {
if(is_set) {
is_set=false;
}
return *this;
}
template <class T> optional<T>& optional<T>::operator=(const optional& other) {
if(!is_set && !other.is_set) {
}
else if(is_set && !other.is_set) {
is_set=false;
}
else { //if(other.is_set)
is_set=true;
val=other.val;
}
return *this;
}
template <class T> optional<T>& optional<T>::operator=(optional& other) {
if(!is_set && !other.is_set) {
}
else if(is_set && !other.is_set) {
is_set=false;
}
else { //if(other.is_set)
is_set=true;
val=other.val;
}
return *this;
}
template <class T> optional<T>& optional<T>::operator=(optional&& other) {
if(!is_set && !other.is_set) {
}
else if(is_set && !other.is_set) {
is_set=false;
}
else { //if(other.is_set)
is_set=true;
val=std::move(other.val);
}
return *this;
}
template <class T> template<class U> optional<T>& optional<T>::operator=(U&& value) {
if(!is_set) {
is_set=true;
val=value;
}
else {
val=value;
}
return *this;
}
//accessing the value
template <class T> const T* optional<T>::operator->() const {
return &val;
}
template <class T> T* optional<T>::operator->() {
return &val;
}
template <class T> const T& optional<T>::operator*() const& {
return val;
}
template <class T> T& optional<T>::operator*() & {
return val;
}
template <class T> const T&& optional<T>::operator*() const&& {
return val;
}
template <class T> T&& optional<T>::operator*() && {
return val;
}
//bool operator
template <class T> optional<T>::operator bool() const {
return is_set;
}
//returns the contained value
template <class T> T& optional<T>::value() & {
if(is_set) {
return val;
}
throw std::logic_error("");
}
template <class T> const T & optional<T>::value() const & {
if(is_set) {
return val;
}
throw std::logic_error("");
}
template <class T> T&& optional<T>::value() && {
if(is_set) {
return std::move(val);
}
throw std::logic_error("");
}
template <class T> const T&& optional<T>::value() const && {
if(is_set) {
return std::move(val);
}
throw std::logic_error("");
}
//swap
template <class T> void optional<T>::swap(optional& other) {
if(!is_set && !other.is_set) {
}
else if(is_set && !other.is_set) {
is_set=false;
other.is_set=true;
other.val=std::move(val);
}
else if(!is_set && other.is_set) {
is_set=true;
other.is_set=false;
val=std::move(other.val);
}
else { //both are set
using std::swap;
swap(**this, *other);
}
}
//compare two optional objects
template<class T> bool operator==(const optional<T>& lhs, const optional<T>& rhs) {
if(bool(lhs)!=bool(rhs)) {
return false;
}
else if(bool(lhs) == false) {
return true;
}
return *lhs == *rhs;
}
template<class T> bool operator!=(const optional<T>& lhs, const optional<T>& rhs) {
return !(lhs == rhs);
}
template<class T> bool operator<(const optional<T>& lhs, const optional<T>& rhs) {
if(bool(rhs) == false) {
return false;
}
else if(bool(lhs) == false) {
return true;
}
else {
return *lhs < *rhs;
}
}
template<class T> bool operator<=(const optional<T>& lhs, const optional<T>& rhs) {
return !(rhs < lhs);
}
template<class T> bool operator>(const optional<T>& lhs, const optional<T>& rhs) {
return rhs < lhs;
}
template<class T> bool operator>=(const optional<T>& lhs, const optional<T>& rhs) {
return !(lhs < rhs);
}
//compare an optional object with a nullopt
template<class T> bool operator==(const optional<T>& opt, nullopt_t) {
return !opt;
}
template<class T> bool operator==(nullopt_t, const optional<T>& opt) {
return !opt;
}
template<class T> bool operator!=(const optional<T>& opt, nullopt_t) {
return bool(opt);
}
template<class T> bool operator!=(nullopt_t, const optional<T>& opt) {
return bool(opt);
}
template<class T> bool operator<(const optional<T>& opt, nullopt_t) {
return false;
}
template<class T> bool operator<(nullopt_t, const optional<T>& opt) {
return bool(opt);
}
template<class T> bool operator<=(const optional<T>& opt, nullopt_t) {
return !opt;
}
template<class T> bool operator<=(nullopt_t, const optional<T>& opt) {
return true;
}
template<class T> bool operator>(const optional<T>& opt, nullopt_t) {
return bool(opt);
}
template<class T> bool operator>(nullopt_t, const optional<T>& opt) {
return false;
}
template<class T> bool operator>=(const optional<T>& opt, nullopt_t) {
return true;
}
template<class T> bool operator>=(nullopt_t, const optional<T>& opt) {
return !opt;
}
//compare an optional object with a T
template<class T> bool operator==(const optional<T>& opt, const T& value) {
return bool(opt) ? *opt == value : false;
}
template<class T> bool operator==(const T& value, const optional<T>& opt) {
return bool(opt) ? value == *opt : false;
}
template<class T> bool operator!=(const optional<T>& opt, const T& value) {
return bool(opt) ? !(*opt == value) : true;
}
template<class T> bool operator!=(const T& value, const optional<T>& opt) {
return bool(opt) ? !(value == *opt) : true;
}
template<class T> bool operator<(const optional<T>& opt, const T& value) {
return bool(opt) ? *opt < value : true;
}
template<class T> bool operator<(const T& value, const optional<T>& opt) {
return bool(opt) ? value < *opt : false;
}
template<class T> bool operator<=(const optional<T>& opt, const T& value) {
return !(opt > value);
}
template<class T> bool operator<=(const T& value, const optional<T>& opt) {
return !(value > opt);
}
template<class T> bool operator>(const optional<T>& opt, const T& value) {
return bool(opt) ? value < *opt : false;
}
template<class T> bool operator>(const T& value, const optional<T>& opt) {
return bool(opt) ? *opt < value : true;
}
template<class T> bool operator>=(const optional<T>& opt, const T& value) {
return !(opt < value);
}
template<class T> bool operator>=(const T& value, const optional<T>& opt) {
return !(value < opt);
}
//std::swap
template<class T> void swap(optional<T>& lhs, optional<T>& rhs) {
lhs.swap(rhs);
}
}
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "optional.hpp"
#include <gtest/gtest.h>
#include <string>
namespace unitTests {
class cta_optionalTest: public ::testing::Test {
protected:
virtual void SetUp() {
}
virtual void TearDown() {
}
};
TEST_F(cta_optionalTest, empty_constructors) {
using namespace cta;
const optional<int> o1;
const optional<int> o2={};
const optional<int> o3=nullopt;
ASSERT_TRUE(o1 == o2);
ASSERT_TRUE(o2 == o3);
ASSERT_TRUE(o1 == nullopt);
ASSERT_FALSE(bool(o1));
ASSERT_FALSE(bool(o2));
ASSERT_FALSE(bool(o3));
}
TEST_F(cta_optionalTest, int_constructors) {
using namespace cta;
const optional<int> o1;
const optional<int> o2=5;
const optional<int> o3(7);
const int x = 9;
const optional<int> o4(x);
const int y = 3;
const optional<int> o5(std::move(y));
ASSERT_FALSE(o1 == o2);
ASSERT_FALSE(o2 == o3);
ASSERT_FALSE(o3 == o4);
ASSERT_FALSE(o4 == o5);
ASSERT_TRUE(o1 == nullopt);
ASSERT_TRUE(o2 == 5);
ASSERT_TRUE(o3 == 7);
ASSERT_TRUE(o4 == x);
ASSERT_TRUE(o5 == 3);
ASSERT_FALSE(bool(o1));
ASSERT_TRUE(bool(o2));
ASSERT_TRUE(bool(o3));
ASSERT_TRUE(bool(o4));
ASSERT_TRUE(bool(o5));
}
TEST_F(cta_optionalTest, string_constructors) {
using namespace cta;
const optional<std::string> o1={};
const optional<std::string> o2("Hello");
const optional<std::string> o3("World");
const std::string x = "Hi";
const optional<std::string> o4(x);
const std::string y = "Mum!";
const optional<std::string> o5(std::move(y));
ASSERT_FALSE(o1 == o2);
ASSERT_FALSE(o2 == o3);
ASSERT_FALSE(o3 == o4);
ASSERT_FALSE(o4 == o5);
ASSERT_TRUE(o1 == nullopt);
ASSERT_TRUE(o2 == std::string("Hello"));
ASSERT_TRUE(o3 == std::string("World"));
ASSERT_TRUE(o4 == x);
ASSERT_TRUE(o5 == std::string("Mum!"));
ASSERT_FALSE(bool(o1));
ASSERT_TRUE(bool(o2));
ASSERT_TRUE(bool(o3));
ASSERT_TRUE(bool(o4));
ASSERT_TRUE(bool(o5));
}
TEST_F(cta_optionalTest, bool_constructors) {
using namespace cta;
const optional<bool> o1={};
const optional<bool> o2(true);
const optional<bool> o3(false);
const bool x = true;
const optional<bool> o4(x);
const bool y = false;
const optional<bool> o5(std::move(y));
ASSERT_FALSE(o1 == o2);
ASSERT_FALSE(o2 == o3);
ASSERT_FALSE(o3 == o4);
ASSERT_FALSE(o4 == o5);
ASSERT_TRUE(o1 == nullopt);
ASSERT_TRUE(o2 == true);
ASSERT_TRUE(o3 == false);
ASSERT_TRUE(o4 == x);
ASSERT_TRUE(o5 == false);
ASSERT_FALSE(bool(o1));
ASSERT_TRUE(bool(o2));
ASSERT_TRUE(bool(o3));
ASSERT_TRUE(bool(o4));
ASSERT_TRUE(bool(o5));
}
TEST_F(cta_optionalTest, assignments) {
using namespace cta;
optional<bool> o1={};
optional<bool> o2(true);
ASSERT_TRUE(o1 == nullopt);
o1 = o2;
ASSERT_TRUE(o1 == true);
o1 = false;
ASSERT_TRUE(o1 == false);
ASSERT_TRUE(bool(o1));
bool x = true;
o1 = std::move(x);
ASSERT_TRUE(o1 == true);
}
TEST_F(cta_optionalTest, accessing_value) {
using namespace cta;
const optional<std::string> o1={};
const optional<std::string> o2("Hello");
const optional<std::string> o3("World");
ASSERT_THROW(o1.value(), std::logic_error);
ASSERT_NO_THROW(o2.value());
ASSERT_TRUE(o2.value() == "Hello");
ASSERT_NO_THROW(*o2);
ASSERT_TRUE(*o2 == "Hello");
ASSERT_NO_THROW(o2->size());
ASSERT_TRUE(o2->size() == 5);
}
TEST_F(cta_optionalTest, swap) {
using namespace cta;
optional<std::string> o1={};
optional<std::string> o2("Hello");
ASSERT_NO_THROW(o1.swap(o2));
ASSERT_THROW(o2.value(), std::logic_error);
ASSERT_NO_THROW(o1.value());
ASSERT_TRUE(o1.value() == "Hello");
ASSERT_NO_THROW(std::swap(o1,o2));
ASSERT_THROW(o1.value(), std::logic_error);
ASSERT_NO_THROW(o2.value());
ASSERT_TRUE(o2.value() == "Hello");
}
TEST_F(cta_optionalTest, comparisons) {
using namespace cta;
optional<std::string> o1={};
optional<std::string> o2("Hello");
optional<std::string> o3("World");
optional<std::string> o4("World");
std::string s2("Hello");
std::string s3("World");
ASSERT_TRUE(o1 == nullopt);
ASSERT_TRUE(nullopt == o1);
ASSERT_TRUE(o2 == std::string("Hello"));
ASSERT_TRUE(o3 == o4);
ASSERT_TRUE(o3 <= o4);
ASSERT_TRUE(o3 >= o4);
ASSERT_FALSE(o3 > o4);
ASSERT_FALSE(o3 < o4);
ASSERT_FALSE(o3 != o4);
ASSERT_TRUE(o3 == s3);
ASSERT_TRUE(s3 == o3);
ASSERT_TRUE(s2 < o3);
ASSERT_TRUE(s3 > o2);
ASSERT_TRUE(o2 > o1);
ASSERT_TRUE(o2 > nullopt);
ASSERT_FALSE(o1 > nullopt);
ASSERT_TRUE(o1 >= nullopt);
}
} // namespace unitTests
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment