util.hpp 4.36 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
#ifndef CVVISUAL_UTIL_HPP
#define CVVISUAL_UTIL_HPP

// required for utilities
#include <initializer_list>
#include <memory>
#include <utility>
#include <type_traits>

// included for convinience of others:
#include <cstddef>   //size_t
#include <cstdint>   // [u]intXX_t
#include <algorithm> // since some people like to forget that one

namespace cvv
{
namespace util
{

/**
 * @brief Creates a new Object of type T on the heap, managed by a
 *std::unique_ptr.
 *
 * This function uses the naming-conventions of the STL instead of cvv because
 *it actually
 * is a backported function from C++14 that is intended to be in harmony with
 *std::make_shared.
 */
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args &&... args)
{
	return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

/**
 * @brief Check whether a value compares equal to any value inside a container
 * of comparable types.
 */
template <typename ValueType, typename Container>
bool isAnyOf(const ValueType &value, const Container &set)
{
	return std::find(set.begin(), set.end(), value) != set.end();
}

/**
 * @brief Overload for intializer-lists to enable usage like this: isAnyOf(3,
 * {1,2,3})
 */
template <typename ValueType, typename Comparable>
bool isAnyOf(const ValueType &value,
             const std::initializer_list<Comparable> &set)
{
	return std::find(set.begin(), set.end(), value) != set.end();
}

// just forward-declarations:
template <typename T> class Reference;
template <typename T> Reference<T> makeRef(T &val);

/**
 * Reference-class to signal that a type is neither owned nor NULL.
 *
 * Note that const Reference<Foo> does not mean that the pointed to Foo is
 *const. If that is what
 * you want use Reference<const Foo>
 */
template <typename T> class Reference
{
      public:
	// there is no reasonable default-value, so:
	Reference() = delete;

	// these are all just the defaults but it is nice to see them explicitly
	Reference(const Reference &) = default;
	Reference(Reference &&) = default;
	Reference &operator=(const Reference &) = default;
	Reference &operator=(Reference &&) = default;

	// Constructing only works from references
	Reference(T &pointee) : ptr{ &pointee }
	{
	}

	// there is no point in having a Reference to a temporary object:
	Reference(T &&) = delete;

	/**
	 * @brief Creates a Ref from a Reference to a type that inherits T.
	 *
	 * Trying to pass in any other type results in a compiler-error.
	 */
	template <typename Derived>
	Reference(const Reference<Derived> other)
	    : ptr{ other.getPtr() }
	{
		static_assert(
		    std::is_base_of<T, Derived>::value,
		    "Reference<T> can only be constructed from Reference<U> if "
		    "T is either equal to U or a base-class of U");
	}

	/**
	 * @brief Get a reference to the referenced object.
	 */
	T &operator*() const
	{
		return *ptr;
	}

	T *operator->() const
	{
		return ptr;
	}

	/**
	 * @brief Get a reference to the referenced object.
	 */
	T &get() const
	{
		return *ptr;
	}

	/**
	 * @brief Get a pointer to the referenced object.
	 */
	T *getPtr() const
	{
		return ptr;
	}

	/**
	 * @brief Tries to create a Reference to a type that inherits T.
	 *
	 * If the target-type does not inherit T, a compiler-error is created.
	 * @throws std::bad_cast if the pointee is not of the requested type.
	 */
	template <typename TargetType> Reference<TargetType> castTo() const
	{
		static_assert(std::is_base_of<T, TargetType>::value,
		              "Reference<Base>::castTo<>() can only cast to "
		              "Reference<Derived>, "
		              "where Derived inherits from Base");
		return makeRef(dynamic_cast<TargetType &>(*ptr));
	}

	/**
	 * @brief Compare to references for identity of the referenced object.
	 *
	 * @note identity != equality: two references to two different ints that
	 *both happen to have
	 * the value 1, will still compare unequal.
	 */
	bool friend operator==(const Reference &l, const Reference &r)
	{
		return l.ptr == r.ptr;
	}

	/**
	 * Dito.
	 */
	bool friend operator!=(const Reference &l, const Reference &r)
	{
		return l.ptr != r.ptr;
	}

      private:
	T *ptr;
};

/**
 * Create a cvv::util::Reference to an object. This is intended to be used for
 * template-argument-deduction, so explicitly passing the template-argument
 * should be considered
 * undefined behaviour.
 */
template <typename T> Reference<T> makeRef(T &val)
{
	return Reference<T>{ val };
}
}
} // namespaces

#endif