Last active
November 7, 2019 15:30
-
-
Save sneppy/5225fa73ed2aeaa3fd344c0d93abfff9 to your computer and use it in GitHub Desktop.
A C++ replica of Python's tuple
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @copyright | |
*/ | |
#pragma once | |
/** | |
* Compute min between two numbers | |
*/ | |
template<typename T> | |
constexpr const T & min(const T & a, const T & b) | |
{ | |
return a < b ? a : b; | |
} | |
/** | |
* A vector of immutable length, similar | |
* to Python's tuple | |
* | |
* @param T elements type | |
* @param n tuple length | |
*/ | |
template<typename T, int n> | |
struct Tuple | |
{ | |
/// Tuple data | |
T data[n]; | |
/// Tuple length | |
constexpr static int len = n; | |
/** | |
* Default constructor, default. | |
*/ | |
constexpr inline Tuple() = default; | |
/** | |
* Copy constructor, default. | |
* @{ | |
*/ | |
constexpr inline Tuple(const Tuple & other) = default; | |
constexpr inline Tuple(Tuple & other) = default; | |
/// @} | |
/** | |
* Move constructor, default. | |
*/ | |
constexpr inline Tuple(Tuple && other) = default; | |
/** | |
* Copy operator, default. | |
*/ | |
constexpr inline Tuple & operator=(const Tuple & other) = default; | |
/** | |
* Move operator, default. | |
*/ | |
constexpr inline Tuple & operator=(Tuple && other) = default; | |
/** | |
* List constructor. | |
*/ | |
template<typename ...Args> | |
constexpr inline Tuple(Args && ...args) | |
: data{std::forward<Args>(args)...} | |
{ | |
// | |
} | |
/** | |
* Copy constructor from tuple | |
* with different size. | |
*/ | |
template<int m> | |
constexpr inline Tuple(const Tuple<T, m> & other) | |
{ | |
// TODO: Complex types require construction | |
memcpy(data, other.data, min(n, m) * sizeof(T)); | |
} | |
/** | |
* Indexing operator. | |
* @{ | |
*/ | |
constexpr inline const T & operator[](int i) const | |
{ | |
return data[i]; | |
} | |
constexpr inline T & operator[](int i) | |
{ | |
return data[i]; | |
} | |
/// @} | |
/** | |
* Returns true if tuples have the | |
* same length and all elements are | |
* equal, false otherwise. | |
* @{ | |
*/ | |
constexpr inline bool sameAs(const Tuple & other) const | |
{ | |
// TODO: complex types require custom comparison | |
return memcmp(data, other.data, sizeof(data)) == 0; | |
} | |
template<int m> | |
constexpr inline bool sameAs(const Tuple<T, m> & other) const | |
{ | |
return false; | |
} | |
/// @} | |
/** | |
* Append tuple to tuple. | |
* | |
* @param other tuple to append | |
* @return newly created tuple | |
*/ | |
template<int m> | |
inline Tuple<T, n + m> operator+(const Tuple<T, m> & other) const | |
{ | |
// Create empty tuple first | |
auto out = Tuple<T, n + m>(); | |
// TODO: complex types require construction | |
memcpy(out.data, data, sizeof(data)); | |
memcpy(out.data + n, other.data, sizeof(other.data)); | |
return out; | |
} | |
/** | |
* Append element to tuple. | |
* | |
* @param other element of type T to append | |
*/ | |
template<typename TT> | |
inline typename std::enable_if<std::is_same<T, TT>::value, Tuple<T, n + 1>>::type operator+(TT && other) const | |
{ | |
auto out = Tuple<T, n + 1>(*this); | |
out.data[n] = std::forward<TT>(other); | |
return out; | |
} | |
/** | |
* Prints tuple to output stream. | |
*/ | |
friend std::ostream & operator<<(std::ostream & out, const Tuple<T, n> & t) | |
{ | |
out << '('; | |
if (t.len) | |
{ | |
// Output all values | |
int i = 0; for (; i < t.len - 1; ++i) | |
out << t.data[i] << ", "; | |
// Print last value | |
out << t.data[i]; | |
} | |
return out << ')'; | |
} | |
}; | |
/** | |
* Strip reference from type. | |
* We need this because C++ does | |
* not allow arrays of references. | |
* @{ | |
*/ | |
template<typename T> | |
struct RemoveReference { using Type = T; }; | |
template<typename T> | |
struct RemoveReference<T&> { using Type = T; }; | |
/// @} | |
/** | |
* Create a tuple from list of arguments. | |
* The type of the first argument | |
* stripped of any reference determines | |
* tuple type. | |
*/ | |
template<typename T, typename ...Args> | |
constexpr Tuple<typename RemoveReference<T>::Type, 1 + sizeof ...(Args)> __make_tuple(T && a, Args && ... bc) | |
{ | |
return Tuple<typename RemoveReference<T>::Type, 1 + sizeof ...(Args)>(std::forward<T>(a), std::forward<Args>(bc) ...); | |
} | |
/** | |
* Handy shorthand for creating tuples. | |
*/ | |
#define T(...) __make_tuple(__VA_ARGS__) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example usage: