Sfoglia il codice sorgente

* Refactored indent.h

* Implemented nullable.h
master
bergmann 6 anni fa
parent
commit
45f70cd03b
9 ha cambiato i file con 671 aggiunte e 59 eliminazioni
  1. +4
    -4
      include/cppcore.h
  2. +4
    -4
      include/cppcore/conversion.h
  3. +6
    -6
      include/cppcore/misc.h
  4. +55
    -43
      include/cppcore/misc/indent.h
  5. +69
    -0
      include/cppcore/misc/indent.inl
  6. +262
    -0
      include/cppcore/misc/nullable.h
  7. +1
    -1
      include/cppcore/misc/utils.h
  8. +1
    -1
      include/cppcore/threading.h
  9. +269
    -0
      test/cppcore/misc/nullable_tests.cpp

+ 4
- 4
include/cppcore.h Vedi File

@@ -1,6 +1,6 @@
#pragma once

#include <cppcore/conversion.h>
#include <cppcore/define.h>
#include <cppcore/misc.h>
#include <cppcore/threading.h>
#include "cppcore/conversion.h"
#include "cppcore/define.h"
#include "cppcore/misc.h"
#include "cppcore/threading.h"

+ 4
- 4
include/cppcore/conversion.h Vedi File

@@ -1,6 +1,6 @@
#pragma once

#include <cppcore/conversion/byteorder.h>
#include <cppcore/conversion/enum.h>
#include <cppcore/conversion/string.h>
#include <cppcore/conversion/time.h>
#include "conversion/byteorder.h"
#include "conversion/enum.h"
#include "conversion/string.h"
#include "conversion/time.h"

+ 6
- 6
include/cppcore/misc.h Vedi File

@@ -1,8 +1,8 @@
#pragma once

#include <cppcore/misc/exception.h>
#include <cppcore/misc/flags.h>
#include <cppcore/misc/indent.h>
#include <cppcore/misc/stream.h>
#include <cppcore/misc/typehelper.h>
#include <cppcore/misc/utils.h>
#include "misc/exception.h"
#include "misc/flags.h"
#include "misc/indent.h"
#include "misc/stream.h"
#include "misc/typehelper.h"
#include "misc/utils.h"

+ 55
- 43
include/cppcore/misc/indent.h Vedi File

@@ -7,64 +7,76 @@ namespace cppcore

namespace __impl
{

constexpr long default_indent = 4;

inline int indent_stream_index()
{
static const int value = std::ios::xalloc();
return value;
}
/**
* @brief Returns the index where the indention value is stored inside the stream.
*/
inline int indent_stream_index();

inline int indent_count_stream_index()
{
static const int value = std::ios::xalloc();
return value;
}
/**
* @brief Returns the index where the current indention level is stored inside the stream.
*/
inline int indent_level_stream_index();

/**
* @brief Helper class to set the stream indention.
*/
struct set_indent_impl
{ int value; };

}

inline auto setindent(int value)
{ return __impl::set_indent_impl { value }; }
/**
* @brief Set the indention of a stream.
*
* @param[in] value New indention value.
*
* @return Helper class to set the indention value.
*/
inline auto setindent(int value);

inline std::ostream& incindent(std::ostream& os)
{
++os.iword(__impl::indent_stream_index());
return os;
}
/**
* @brief Increment the current indention level by one.
*
* @param[in] os Stream to increment the indention level for.
*
* @return Stream passed to this function.
*/
inline std::ostream& incindent(std::ostream& os);

inline std::ostream& decindent(std::ostream& os)
{
auto& indent = os.iword(__impl::indent_stream_index());
if (--indent < 0)
indent = 0;
return os;
}
/**
* @brief Decrement the current indention level by one.
*
* @param[in] os Stream to decrement the indention level for.
*
* @return Stream passed to this function.
*/
inline std::ostream& decindent(std::ostream& os);

inline std::ostream& indent(std::ostream& os)
{
auto i = os.iword(__impl::indent_stream_index());
auto c = __impl::default_indent + os.iword(__impl::indent_count_stream_index());
i *= c;
if (i >= 0)
{
os << std::endl;
while (i--)
os.put(' ');
}
return os;
}
/**
* @brief Add a line break and indention to the stream.
*
* @param[in] os Stream to decrement the indention level for.
*
* @return Stream passed to this function.
*/
inline std::ostream& indent(std::ostream& os);

}

namespace std
{

/**
* @brief Write the helper class to stream using the << operator.
*/
template<typename T_char, typename T_traits>
inline basic_ostream<T_char, T_traits>& operator<< (basic_ostream<T_char, T_traits>& os, const cppcore::__impl::set_indent_impl& i)
{
using namespace ::cppcore;
os.iword(__impl::indent_count_stream_index()) = i.value - __impl::default_indent;
return os;
}
inline basic_ostream<T_char, T_traits>& operator<< (
basic_ostream<T_char, T_traits>& os,
const cppcore::__impl::set_indent_impl& i);

}

#include "indent.inl"

+ 69
- 0
include/cppcore/misc/indent.inl Vedi File

@@ -0,0 +1,69 @@
#pragma once

#include "indent.h"

namespace cppcore
{

namespace __impl
{

int indent_stream_index()
{
static const int value = std::ios::xalloc();
return value;
}

int indent_level_stream_index()
{
static const int value = std::ios::xalloc();
return value;
}

}

auto setindent(int value)
{ return __impl::set_indent_impl { value }; }

std::ostream& incindent(std::ostream& os)
{
++os.iword(__impl::indent_stream_index());
return os;
}

std::ostream& decindent(std::ostream& os)
{
auto& indent = os.iword(__impl::indent_stream_index());
if (--indent < 0)
indent = 0;
return os;
}

std::ostream& indent(std::ostream& os)
{
auto i = os.iword(__impl::indent_stream_index());
auto c = __impl::default_indent + os.iword(__impl::indent_level_stream_index());
i *= c;
if (i >= 0)
{
os << std::endl;
while (i--)
os.put(' ');
}
return os;
}

}

namespace std
{

template<typename T_char, typename T_traits>
inline basic_ostream<T_char, T_traits>& operator<< (basic_ostream<T_char, T_traits>& os, const cppcore::__impl::set_indent_impl& i)
{
using namespace ::cppcore;
os.iword(__impl::indent_level_stream_index()) = i.value - __impl::default_indent;
return os;
}

}

+ 262
- 0
include/cppcore/misc/nullable.h Vedi File

@@ -0,0 +1,262 @@
#pragma once

#include <memory>
#include "exception.h"

namespace cppcore
{

template<typename T_value>
struct nullable
{
public:
using value_type = T_value;

struct value_container
{
value_type value;

template<class... T_args>
inline value_container(T_args&&... p_args)
: value(std::forward<T_args>(p_args)...)
{ }
};

using value_container_ptr_u = std::unique_ptr<value_container>;

private:
value_container_ptr_u _container;

public:
/**
* @brief Default constructor.
*/
inline nullable() = default;

/**
* @brief Construtor to create the object. Parameters will passed to the constructor of the value type.
*/
template<class... T_args>
inline nullable(T_args&&... p_args)
: _container(new value_container(std::forward<T_args>(p_args)...))
{ }

/**
* @brief Copy constructor.
*/
inline nullable(nullable& other)
: _container(other
? new value_container(*other)
: nullptr)
{ }

/**
* @brief Copy constructor.
*/
inline nullable(const nullable& other)
: _container(other
? new value_container(*other)
: nullptr)
{ }

/**
* @brief Move constructor.
*/
inline nullable(nullable&& other)
: _container(std::move(other)._container)
{ }

public:
/**
* @brief Assignment constructor.
*/
inline decltype(auto) operator=(value_type&& t)
{
_container.reset(new value_container(std::forward<value_type>(t)));
return *this;
}

/**
* @brief Copy assignment constructor.
*/
inline decltype(auto) operator=(const nullable& other)
{
_container.reset(other
? new value_container(*other)
: nullptr);
return *this;
}

/**
* @brief Move assignment constructor.
*/
inline decltype(auto) operator=(nullable&& other)
{
_container = std::move(other._container);
return *this;
}

public:
/**
* @brief Get the stored value.
*/
inline value_type& value()
{ check(); return _container->value; }

/**
* @brief Get the stored value.
*/
inline const value_type& value() const
{ check(); return _container->value; }

/**
* @brief Check if the object has an value assigned.
*/
inline bool has_value() const
{ return static_cast<bool>(_container); }

/**
* @brief Reset the object. THis will release the stored value.
*/
inline void reset()
{ _container.reset(); }

public:
/**
* @brief Operator to access the stored value.
*/
inline decltype(auto) operator*()
{ return value(); }

/**
* @brief Operator to access the stored value.
*/
inline decltype(auto) operator*() const
{ return value(); }

/**
* @brief Operator to access the stored value.
*/
inline decltype(auto) operator->()
{ return &value(); }

/**
* @brief Operator to access the stored value.
*/
inline decltype(auto) operator->() const
{ return &value(); }

/**
* @brief Operator to access the stored value.
*/
inline decltype(auto) operator()()
{ return value(); }

/**
* @brief Operator to access the soted value.
*/
inline decltype(auto) operator()() const
{ return value(); }

/**
* @brief Convert to boolean.
*/
inline explicit operator bool() const
{ return has_value(); }

private:
/**
* @brief Check if the object has an value assigned. If not raise an exception.
*/
inline void check() const
{
if (!has_value())
throw invalid_operation_exception("nullable does not have a value");
}
};

/* operator== */

template<typename T_nullable>
inline bool operator==(const T_nullable& lhs, const typename T_nullable::value_type& rhs)
{ return lhs.has_value() && *lhs == rhs; }

template<typename T_nullable>
inline bool operator==(const typename T_nullable::value_type& lhs, const T_nullable& rhs)
{ return rhs.has_value() && lhs == *rhs; }

template<typename T_nullable>
inline bool operator==(const T_nullable& lhs, const T_nullable& rhs)
{ return lhs.has_value() && rhs.has_value() && *lhs == *rhs; }

/* operator!= */

template<typename T_nullable>
inline bool operator!=(const T_nullable& lhs, const typename T_nullable::value_type& rhs)
{ return lhs.has_value() && *lhs != rhs; }

template<typename T_nullable>
inline bool operator!=(const typename T_nullable::value_type& lhs, const T_nullable& rhs)
{ return rhs.has_value() && lhs != *rhs; }

template<typename T_nullable>
inline bool operator!=(const T_nullable& lhs, const T_nullable& rhs)
{ return lhs.has_value() && rhs.has_value() && *lhs != *rhs; }

/* operator< */

template<typename T_nullable>
inline bool operator<(const T_nullable& lhs, const typename T_nullable::value_type& rhs)
{ return lhs.has_value() && *lhs < rhs; }

template<typename T_nullable>
inline bool operator<(const typename T_nullable::value_type& lhs, const T_nullable& rhs)
{ return rhs.has_value() && lhs < *rhs; }

template<typename T_nullable>
inline bool operator<(const T_nullable& lhs, const T_nullable& rhs)
{ return lhs.has_value() && rhs.has_value() && *lhs < *rhs; }

/* operator> */

template<typename T_nullable>
inline bool operator>(const T_nullable& lhs, const typename T_nullable::value_type& rhs)
{ return lhs.has_value() && *lhs > rhs; }

template<typename T_nullable>
inline bool operator>(const typename T_nullable::value_type& lhs, const T_nullable& rhs)
{ return rhs.has_value() && lhs > *rhs; }

template<typename T_nullable>
inline bool operator>(const T_nullable& lhs, const T_nullable& rhs)
{ return lhs.has_value() && rhs.has_value() && *lhs > *rhs; }

/* operator<= */

template<typename T_nullable>
inline bool operator<=(const T_nullable& lhs, const typename T_nullable::value_type& rhs)
{ return lhs.has_value() && *lhs <= rhs; }

template<typename T_nullable>
inline bool operator<=(const typename T_nullable::value_type& lhs, const T_nullable& rhs)
{ return rhs.has_value() && lhs <= *rhs; }

template<typename T_nullable>
inline bool operator<=(const T_nullable& lhs, const T_nullable& rhs)
{ return lhs.has_value() && rhs.has_value() && *lhs <= *rhs; }

/* operator>= */

template<typename T_nullable>
inline bool operator>=(const T_nullable& lhs, const typename T_nullable::value_type& rhs)
{ return lhs.has_value() && *lhs >= rhs; }

template<typename T_nullable>
inline bool operator>=(const typename T_nullable::value_type& lhs, const T_nullable& rhs)
{ return rhs.has_value() && lhs >= *rhs; }

template<typename T_nullable>
inline bool operator>=(const T_nullable& lhs, const T_nullable& rhs)
{ return lhs.has_value() && rhs.has_value() && *lhs >= *rhs; }

}

+ 1
- 1
include/cppcore/misc/utils.h Vedi File

@@ -9,7 +9,7 @@ namespace cppcore
inline size_t bit_count(uint32_t u);

/**
* @breif Try to dynamic cast the passed value to the given type.
* @brief Try to dynamic cast the passed value to the given type.
*
* @tparam T Type to cast.
* @tparam S Type to cast to.


+ 1
- 1
include/cppcore/threading.h Vedi File

@@ -1,3 +1,3 @@
#pragma once

#include <cppcore/threading/cancellation_token.h>
#include "threading/cancellation_token.h"

+ 269
- 0
test/cppcore/misc/nullable_tests.cpp Vedi File

@@ -0,0 +1,269 @@
#include <gtest/gtest.h>
#include <cppcore/misc/nullable.h>

struct TestData
{
static int ctorCount;
static int dtorCount;

TestData()
{ ++ctorCount; }

~TestData()
{ ++dtorCount; }
};

struct NonCopyableTestData
{
int value;

NonCopyableTestData(int v) :
value(v)
{ }

NonCopyableTestData(NonCopyableTestData&& other) :
value(0)
{ std::swap(value, other.value); }

NonCopyableTestData(const NonCopyableTestData&) = delete;
};

using NullableInt = ::cppcore::nullable<int>;
using NullableIntRef = ::cppcore::nullable<int&>;
using NullableString = ::cppcore::nullable<std::string>;
using NullableTestData = ::cppcore::nullable<TestData>;
using NullableNonCopyableTestData = ::cppcore::nullable<NonCopyableTestData>;

int TestData::ctorCount = 0;
int TestData::dtorCount = 0;

using namespace ::cppcore;
using namespace ::testing;

TEST(nullable_tests, ctor_empty)
{
NullableInt n1;
NullableIntRef n2;
EXPECT_FALSE(static_cast<bool>(n1));
EXPECT_FALSE(static_cast<bool>(n2));
}

TEST(nullable_tests, ctor_value)
{
int i = 5;
NullableInt n1(i);
NullableIntRef n2(i);
EXPECT_TRUE(static_cast<bool>(n1));
EXPECT_TRUE(static_cast<bool>(n2));
EXPECT_EQ (5, n1());
EXPECT_EQ (&i, &n2());
}

TEST(nullable_tests, ctor_copy)
{
int i = 5;
NullableInt i1(i);
NullableIntRef i2(i);
NullableInt n1(i1);
NullableIntRef n2(i2);
EXPECT_TRUE(static_cast<bool>(n1));
EXPECT_TRUE(static_cast<bool>(n2));
EXPECT_EQ (5, n1());
EXPECT_EQ (&i, &n2());
}

TEST(nullable_tests, ctor_move)
{
NullableString i1("test");
NullableString n1(std::move(i1));
EXPECT_FALSE(static_cast<bool>(i1));
ASSERT_TRUE (static_cast<bool>(n1));
EXPECT_EQ (std::string("test"), n1());
}

TEST(nullable_tests, move_assignment)
{
NullableString i1("test");
NullableString n1;
n1 = std::move(i1);
EXPECT_FALSE(static_cast<bool>(i1));
ASSERT_TRUE (static_cast<bool>(n1));
EXPECT_EQ (std::string("test"), n1());
}

TEST(nullable_tests, movable_object)
{
NonCopyableTestData data(5);
NullableNonCopyableTestData tmp;
tmp = std::move(data);
ASSERT_TRUE ( tmp.has_value() );
ASSERT_EQ ( 5, tmp.value().value );
ASSERT_EQ ( 0, data.value );
}

TEST(nullable_tests, hasValue_operatorBool)
{
EXPECT_FALSE(static_cast<bool>(NullableInt()));
EXPECT_FALSE(NullableInt().has_value());
EXPECT_TRUE (static_cast<bool>(NullableInt(5)));
EXPECT_TRUE (NullableInt(5).has_value());
}

TEST(nullable_tests, reset)
{
NullableTestData n(TestData{});
EXPECT_TRUE (n.has_value());
int tmp = TestData::dtorCount;
n.reset();
EXPECT_FALSE(n.has_value());
EXPECT_EQ (tmp + 1, TestData::dtorCount);
}

TEST(nullable_tests, value_functor)
{
NullableInt n1(5);
NullableInt n2;

EXPECT_EQ (5, n1());
EXPECT_EQ (5, n1.value());
EXPECT_ANY_THROW(n2());
EXPECT_ANY_THROW(n2.value());
}

TEST(nullable_tests, equalityCompareOperator)
{
NullableInt n1(5);
NullableInt n2(7);
NullableInt n3;

EXPECT_FALSE(n2 == n1);
EXPECT_TRUE ( 5 == n1);
EXPECT_FALSE(n3 == n1);

EXPECT_FALSE(n1 == n2);
EXPECT_FALSE( 5 == n2);
EXPECT_FALSE(n3 == n2);

EXPECT_TRUE (n1 == 5);
EXPECT_FALSE(n2 == 5);
EXPECT_FALSE(n3 == 5);

EXPECT_FALSE(n1 == n3);
EXPECT_FALSE(n2 == n3);
EXPECT_FALSE( 5 == n3);
}

TEST(nullable_tests, unequalityCompareOperator)
{
NullableInt n1(5);
NullableInt n2(7);
NullableInt n3;

EXPECT_TRUE (n2 != n1);
EXPECT_FALSE( 5 != n1);
EXPECT_FALSE(n3 != n1);

EXPECT_TRUE (n1 != n2);
EXPECT_TRUE ( 5 != n2);
EXPECT_FALSE(n3 != n2);

EXPECT_FALSE(n1 != 5);
EXPECT_TRUE (n2 != 5);
EXPECT_FALSE(n3 != 5);

EXPECT_FALSE(n1 != n3);
EXPECT_FALSE(n2 != n3);
EXPECT_FALSE( 5 != n3);
}

TEST(nullable_tests, lessCompareOperator)
{
NullableInt n1(5);
NullableInt n2(7);
NullableInt n3;

EXPECT_FALSE(n2 < n1);
EXPECT_FALSE( 5 < n1);
EXPECT_FALSE(n3 < n1);

EXPECT_TRUE (n1 < n2);
EXPECT_TRUE ( 5 < n2);
EXPECT_FALSE(n3 < n2);

EXPECT_FALSE(n1 < 5);
EXPECT_FALSE(n2 < 5);
EXPECT_FALSE(n3 < 5);

EXPECT_FALSE(n1 < n3);
EXPECT_FALSE(n2 < n3);
EXPECT_FALSE( 5 < n3);
}

TEST(nullable_tests, lessEqualCompareOperator)
{
NullableInt n1(5);
NullableInt n2(7);
NullableInt n3;

EXPECT_FALSE(n2 <= n1);
EXPECT_TRUE ( 5 <= n1);
EXPECT_FALSE(n3 <= n1);

EXPECT_TRUE (n1 <= n2);
EXPECT_TRUE ( 5 <= n2);
EXPECT_FALSE(n3 <= n2);

EXPECT_TRUE (n1 <= 5);
EXPECT_FALSE(n2 <= 5);
EXPECT_FALSE(n3 <= 5);

EXPECT_FALSE(n1 <= n3);
EXPECT_FALSE(n2 <= n3);
EXPECT_FALSE( 5 <= n3);
}

TEST(nullable_tests, greaterCompareOperator)
{
NullableInt n1(5);
NullableInt n2(7);
NullableInt n3;

EXPECT_TRUE (n2 > n1);
EXPECT_FALSE( 5 > n1);
EXPECT_FALSE(n3 > n1);

EXPECT_FALSE(n1 > n2);
EXPECT_FALSE( 5 > n2);
EXPECT_FALSE(n3 > n2);

EXPECT_FALSE(n1 > 5);
EXPECT_TRUE (n2 > 5);
EXPECT_FALSE(n3 > 5);

EXPECT_FALSE(n1 > n3);
EXPECT_FALSE(n2 > n3);
EXPECT_FALSE( 5 > n3);
}

TEST(nullable_tests, greaterEqualCompareOperator)
{
NullableInt n1(5);
NullableInt n2(7);
NullableInt n3;

EXPECT_TRUE (n2 >= n1);
EXPECT_TRUE ( 5 >= n1);
EXPECT_FALSE(n3 >= n1);

EXPECT_FALSE(n1 >= n2);
EXPECT_FALSE( 5 >= n2);
EXPECT_FALSE(n3 >= n2);

EXPECT_TRUE (n1 >= 5);
EXPECT_TRUE (n2 >= 5);
EXPECT_FALSE(n3 >= 5);

EXPECT_FALSE(n1 >= n3);
EXPECT_FALSE(n2 >= n3);
EXPECT_FALSE( 5 >= n3);
}

Caricamento…
Annulla
Salva