Skip to content

Instantly share code, notes, and snippets.

@sneppy
Last active November 7, 2019 15:30
Show Gist options
  • Save sneppy/5225fa73ed2aeaa3fd344c0d93abfff9 to your computer and use it in GitHub Desktop.
Save sneppy/5225fa73ed2aeaa3fd344c0d93abfff9 to your computer and use it in GitHub Desktop.
A C++ replica of Python's tuple
/**
* @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__)
@sneppy
Copy link
Author

sneppy commented Nov 7, 2019

Example usage:

#include "tuple.h"

int main()
{
	srand(clock());
	
	auto tup = T(rand() & 0xf, rand() & 0xf);
	std::cout << tup << std::endl;
	
	auto bar = tup + 10;
	std::cout << bar << std::endl;
	
	auto foo = T(tup[1], tup[0]) + tup;
	std::cout << foo << std::endl;
	
	return 0;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment