src/basics.h

changeset 206
654661eab7f3
parent 196
6bcb284679d4
child 207
5315358a7d91
--- a/src/basics.h	Wed Jun 08 20:41:21 2022 +0300
+++ b/src/basics.h	Wed Jun 08 22:29:44 2022 +0300
@@ -18,13 +18,13 @@
 
 #pragma once
 #include <algorithm>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
 #include <cmath>
+#include <compare>
+#include <memory>
 #include <optional>
 #include <type_traits>
-#include <QMatrix4x4>
+#include <QDataStream>
+#include <QDebug>
 #include <QObject>
 #include <QPointF>
 #include <QSet>
@@ -32,64 +32,24 @@
 #include <QStringList>
 #include <QVariant>
 #include <QVector>
-#include <QVector3D>
 #include <glm/glm.hpp>
-
-using GLRotationMatrix = QMatrix4x4;
-
-enum Axis
-{
-	X = 0,
-	Y = 1,
-	Z = 2
-};
+#include "geometry.h"
+#include "functional.h"
 
-enum Result
-{
-	Success = 0,
-	PartialSuccess,
-	Failure
-};
-
-constexpr bool failed(Result r)
-{
-	return r == Failure;
-}
+template<typename T>
+using opt = std::optional<T>;
 
-enum Winding
-{
-	NoWinding,
-	Anticlockwise,
-	Clockwise,
-};
+Q_DECLARE_METATYPE(glm::vec3)
+Q_DECLARE_METATYPE(glm::mat4)
 
-/*
- * Special operator definition that implements the XOR operator for windings.
- * However, if either winding is NoWinding, then this function returns NoWinding.
- */
-inline Winding operator^(Winding one, Winding other)
-{
-	if (one == NoWinding or other == NoWinding)
-		return NoWinding;
-	else
-		return static_cast<Winding>(static_cast<int>(one) ^ static_cast<int>(other));
-}
-
-inline Winding& operator^=(Winding& one, Winding other)
-{
-	one = one ^ other;
-	return one;
-}
-
+//! \brief count the amount of elements in a basic array
 template<typename T, int N>
-constexpr int countof(T const (&)[N])
+constexpr int countof(T(&)[N])
 {
 	return N;
 }
 
-/**
- * @brief casts @c x to a suitable unsigned integer
- */
+//! \brief casts @c x to a suitable unsigned integer
 template<typename T>
 constexpr auto unsigned_cast(T x)
 	-> std::enable_if_t<std::is_integral_v<T>, std::make_unsigned_t<T>>
@@ -97,9 +57,7 @@
 	return static_cast<std::make_unsigned_t<T>>(x);
 }
 
-/**
- * @brief casts @c x to a suitable signed integer
- */
+//! \brief casts @c x to a suitable signed integer
 template<typename T>
 constexpr auto signed_cast(T x)
 	-> std::enable_if_t<std::is_integral_v<T>, std::make_signed_t<T>>
@@ -107,86 +65,42 @@
 	return static_cast<std::make_signed_t<T>>(x);
 }
 
-
-/**
-* @brief casts floating point values to float, converting non-floating point values causes an error
-* @param[in] x floating point value to cast
-* @returns float
-*/
+//! \brief casts floating point values to float
 template<typename T>
-auto toFloat(T x) -> std::enable_if_t<std::is_floating_point_v<T>, float>
+constexpr auto float_cast(T x)
+	-> std::enable_if_t<std::is_floating_point_v<T>, float>
 {
 	return static_cast<float>(x);
 }
 
-/**
-* @brief casts floating point values to double, converting non-floating point values causes an error
-* @param[in] x floating point value to cast
-* @returns double
-*/
+//! \brief casts floating point values to double
 template<typename T>
-auto toDouble(T x) -> std::enable_if_t<std::is_floating_point_v<T>, double>
+constexpr auto double_cast(T x)
+	-> std::enable_if_t<std::is_floating_point_v<T>, double>
 {
 	return static_cast<double>(x);
 }
 
-/**
-* @brief casts floating point values to qreal, converting non-floating point values causes an error
-* @param[in] x floating point value to cast
-* @returns qreal
-*/
+//! \brief casts floating point values to qreal
 template<typename T>
-auto toQreal(T x) -> std::enable_if_t<std::is_floating_point_v<T>, qreal>
+constexpr auto qreal_cast(T x)
+	-> std::enable_if_t<std::is_floating_point_v<T>, qreal>
 {
 	return static_cast<qreal>(x);
 }
 
 template<int N, typename T, glm::qualifier Q>
-inline QPoint toQPoint(const glm::vec<N, T, Q>& vec)
+constexpr QPointF toQPointF(const glm::vec<N, T, Q>& vec)
 {
-	return {static_cast<int>(vec.x), static_cast<int>(vec.y)};
+	return {double_cast(vec.x), double_cast(vec.y)};
 }
 
-template<int N, typename T, glm::qualifier Q>
-inline QPointF toQPointF(const glm::vec<N, T, Q>& vec)
-{
-	return {toDouble(vec.x), toDouble(vec.y)};
-}
-
-inline glm::vec2 toVec2(const QPoint& point)
-{
-	return {point.x(), point.y()};
-}
-
-inline glm::vec2 toVec2(const QPointF& point)
+constexpr glm::vec2 toVec2(const QPointF& point)
 {
 	return {point.x(), point.y()};
 }
 
-/*
- * coalesce(arg1, arg2, ..., argn)
- * Returns the first of the given arguments that evaluates to true.
- */
-template<typename T>
-T coalesce(T&& arg)
-{
-	// recursion base: 1 argument
-	return arg;
-}
 
-template<typename T, typename... Rest>
-std::common_type_t<T, Rest...> coalesce(T&& arg, Rest&&... rest)
-{
-	// general case: n arguments
-	return arg ? arg : coalesce(rest...);
-}
-
-/**
- * @brief Finds an element in a map and possibly returns a reference to it if find
- * @param map
- * @param key
- * @returns the value or nullptr if not found
- */
 template<typename T, typename R, typename K>
 const R* findInMap(const std::map<T, R>& map, K&& key)
 {
@@ -201,12 +115,6 @@
 	}
 }
 
-/**
- * @brief Finds an element in a map and possibly returns a reference to it if find
- * @param map
- * @param key
- * @returns the value or no value if not found
- */
 template<typename T, typename R, typename K>
 R* findInMap(std::map<T, R>& map, K&& key)
 {
@@ -221,10 +129,178 @@
 	}
 }
 
+template<typename T, typename R>
+void removeFromMap(std::map<T, R>& map, T&& key)
+{
+	const auto it = map.find(key);
+	if (it != map.end()) {
+		map.erase(it);
+	}
+}
+
 template<typename T = float>
 constexpr std::enable_if_t<std::is_floating_point_v<T>, T> pi = static_cast<T>(M_PIl);
-constexpr double infinity = std::numeric_limits<double>::infinity();
+
+inline QSizeF sizeToSizeF(const QSize& size)
+{
+	return {static_cast<qreal>(size.width()), static_cast<qreal>(size.height())};
+}
+
+//! \brief Hints to the specified vector that a certain amount of new elements
+//! are going to be added.
+template<typename T>
+void reserveMore(std::vector<T>& vector, std::size_t amount)
+{
+	vector.reserve(vector.size() + amount);
+}
+
+inline QString vectorToString(const glm::vec2& vec)
+{
+	return QStringLiteral("(%1, %2)")
+		.arg(double_cast(vec.x))
+		.arg(double_cast(vec.y));
+}
+
+inline QString vectorToString(const glm::vec3& vec)
+{
+	return QStringLiteral("(%1, %2, %3)")
+		.arg(double_cast(vec.x))
+		.arg(double_cast(vec.y))
+		.arg(double_cast(vec.z));
+}
+
+inline QString vectorToString(const glm::vec4& vec)
+{
+	return QStringLiteral("%1, %2, %3, %4)")
+		.arg(double_cast(vec.x))
+		.arg(double_cast(vec.y))
+		.arg(double_cast(vec.z))
+		.arg(double_cast(vec.w));
+}
 
+template<typename T, typename IdentifierType>
+struct TypeValue
+{
+	T value;
+	auto operator<=>(TypeValue other) const = default;
+};
+
+template<typename T, typename R>
+int qHash(TypeValue<T, R> value)
+{
+	return qHash(value.value);
+}
+
+/**
+ * Iterates a @c glm::mat
+ */
+template<int X, int Y, typename T, glm::qualifier Q, typename Fn>
+void iter_matrix(const glm::mat<X, Y, T, Q>& matrix, Fn&& fn)
+{
+	for (int i = 0; i < X; ++i)
+	{
+		for (int j = 0; j < Y; ++j)
+		{
+			fn(i, j, matrix[i][j]);
+		}
+	}
+}
+
+inline QDataStream& operator<<(QDataStream& stream, const glm::vec3& vec)
+{
+	return stream << vec.x << vec.y << vec.z;
+}
+
+inline QDataStream& operator>>(QDataStream& stream, glm::vec3& vec)
+{
+	return stream >> vec.x >> vec.y >> vec.z;
+}
 
-Q_DECLARE_METATYPE(glm::vec3)
-Q_DECLARE_METATYPE(glm::mat4)
+template<int X, int Y, typename T, glm::qualifier Q>
+QDataStream& operator<<(QDataStream& stream, const glm::mat<X, Y, T, Q>& mat)
+{
+	iter_matrix(mat, [&stream](int, int, float x)
+	{
+		stream << x;
+	});
+	return stream;
+}
+
+template<int X, int Y, typename T, glm::qualifier Q>
+QDataStream& operator>>(QDataStream& stream, glm::mat<X, Y, T, Q>& mat)
+{
+	iter_matrix(mat, [&stream](int, int, float x)
+	{
+		stream >> x;
+	});
+	return stream;
+}
+
+//! \brief Converts a pointer value to an \c std::optional value. If p has a
+//! value, it will be copied into the result value.
+template<typename T>
+std::optional<T> pointerToOptional(const T* p)
+{
+	std::optional<T> result;
+	if (p != nullptr) {
+		result = *p;
+	}
+	return result;
+}
+
+// some magic code from https://en.cppreference.com/w/cpp/utility/variant/visit
+// for use with std::visit
+template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
+template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
+
+// http://stackoverflow.com/a/18204188/3629665
+template<typename T>
+constexpr T rotl10(T x)
+{
+	return (x << 10) | ((x >> 22) & 0x000000ff);
+}
+
+template<typename T>
+constexpr T rotl20(T x)
+{
+	return (x << 20) | ((x >> 12) & 0x000000ff);
+}
+
+inline QString quoted(QString string)
+{
+	if (string.contains("'"))
+	{
+		string.replace("\"", "\\\"");
+		string = "\"" + string + "\"";
+	}
+	else
+	{
+		string = "'" + string + "'";
+	}
+	return string;
+}
+
+inline QString vertexToString(const glm::vec3& vertex)
+{
+	return QStringLiteral("%1 %2 %3").arg(vertex.x).arg(vertex.y).arg(vertex.z);
+}
+
+inline QString vertexToStringParens(const glm::vec3& vertex)
+{
+	return QStringLiteral("(%1 %2 %3)").arg(vertex.x).arg(vertex.y).arg(vertex.z);
+}
+
+inline QString transformToString(const glm::mat4& matrix)
+{
+	return QStringLiteral("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12")
+		.arg(matrix[3][0], matrix[3][1], matrix[3][2])
+		.arg(matrix[0][0], matrix[1][0], matrix[2][0])
+		.arg(matrix[0][1], matrix[1][1], matrix[2][1])
+		.arg(matrix[0][2], matrix[1][2], matrix[2][2]);
+}
+
+template<typename T, glm::qualifier Q>
+constexpr unsigned int qHash(const glm::vec<3, T, Q>& key)
+{
+	return qHash(key.x) ^ rotl10(qHash(key.y)) ^ rotl20(qHash(key.z));
+}

mercurial