Your IP : 216.73.216.48
/*
* templates.h
* Copyright 2014 John Lindgren
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions, and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions, and the following disclaimer in the documentation
* provided with the distribution.
*
* This software is provided "as is" and without any warranty, express or
* implied. In no event shall the authors be liable for any damages arising from
* the use of this software.
*/
#ifndef LIBAUDCORE_TEMPLATES_H
#define LIBAUDCORE_TEMPLATES_H
#include <new>
#include <type_traits>
#include <utility>
#ifdef _WIN32
#undef min
#undef max
#endif
namespace aud {
// Utility functions
// =================
// minimum of two numbers
template<class T>
constexpr T min (T a, T b)
{ return a < b ? a : b; }
// maximum of two numbers
template<class T>
constexpr T max (T a, T b)
{ return a > b ? a : b; }
// make sure a number is within the given range
template<class T>
constexpr T clamp (T x, T low, T high)
{ return min (max (x, low), high); }
// absolute value
template<class T>
constexpr T abs (T x)
{ return x < 0 ? -x : x; }
// change the sign of x to the sign of s
template<class T>
constexpr T chsign (T x, T s)
{ return (x < 0) ^ (s < 0) ? -x : x; }
// integer division with rounding
template<class T>
constexpr T rdiv (T x, T y)
{ return (x + chsign (y / 2, x)) / y; }
// convert integer from one scale to another, with rounding
template<class T>
constexpr T rescale (T x, T old_scale, T new_scale)
{ return rdiv (x * new_scale, old_scale); }
// number of characters needed to represent an integer (including minus sign)
template<class T>
constexpr T n_digits (T x)
{ return x < 0 ? 1 + n_digits (-x) : x < 10 ? 1 : 1 + n_digits (x / 10); }
// number of elements in an array
template<class T, int N>
constexpr int n_elems (const T (&) [N])
{ return N; }
// Casts for storing various data in a void pointer
// ================================================
template<class T>
inline void * to_ptr (T t)
{
union { void * v; T t; } u = {nullptr};
static_assert (sizeof u == sizeof (void *), "Type cannot be stored in a pointer");
u.t = t; return u.v;
}
template<class T>
inline T from_ptr (void * v)
{
union { void * v; T t; } u = {v};
static_assert (sizeof u == sizeof (void *), "Type cannot be stored in a pointer");
return u.t;
}
// Wrapper class allowing enumerations to be used as array indexes;
// the enumeration must begin with zero and have a "count" constant
// ================================================================
template<class T, class V>
struct array
{
// cannot use std::forward here; it is not constexpr until C++14
template<class ... Args>
constexpr array (Args && ... args) :
vals { static_cast<Args &&> (args) ...} {}
constexpr const V & operator[] (T t) const
{ return vals[(int) t]; }
constexpr const V * begin () const
{ return vals; }
constexpr const V * end () const
{ return vals + (int) T::count; }
V & operator[] (T t)
{ return vals[(int) t]; }
V * begin ()
{ return vals; }
V * end ()
{ return vals + (int) T::count; }
private:
V vals[(int) T::count];
};
// Wrapper class allowing enumerations to be used in range-based for loops
// =======================================================================
template<class T, T first = (T) 0, T last = (T) ((int) T::count - 1)>
struct range
{
struct iter {
T v;
constexpr T operator* () const
{ return v; }
constexpr bool operator!= (iter other) const
{ return v != other.v; }
void operator++ ()
{ v = (T) ((int) v + 1); }
};
static constexpr iter begin ()
{ return {first}; }
static constexpr iter end ()
{ return {(T) ((int) last + 1)}; }
};
// Replacement for std::allocator::construct, which also supports aggregate
// initialization. For background, see:
// http://cplusplus.github.io/LWG/lwg-active.html#2089
// ========================================================================
// class constructor proxy
template<class T, bool aggregate>
struct construct_base {
template<class ... Args>
static T * make (void * loc, Args && ... args)
{ return new (loc) T (std::forward<Args> (args) ...); }
};
// aggregate constructor proxy
template<class T>
struct construct_base<T, true> {
template<class ... Args>
static T * make (void * loc, Args && ... args)
{ return new (loc) T {std::forward<Args> (args) ...}; }
};
// generic constructor proxy
template<class T>
struct construct {
template<class ... Args>
static T * make (void * loc, Args && ... args)
{
constexpr bool aggregate = ! std::is_constructible<T, Args && ...>::value;
return construct_base<T, aggregate>::make (loc, std::forward<Args> (args) ...);
}
};
// Convert an integer constant to a string at compile-time; can be used for
// #defines, enums, constexpr calculations, etc.
// ========================================================================
// "metaprogramming" string type: each different string is a unique type
template<char... args>
struct metastring {
char data[sizeof... (args) + 1] = {args..., '\0'};
};
// recursive number-printing template, general case (three or more digits)
template<int size, int x, char... args>
struct numeric_builder {
typedef typename numeric_builder<size - 1, x / 10, '0' + abs (x) % 10, args...>::type type;
};
// special case for two digits; minus sign is handled here
template<int x, char... args>
struct numeric_builder<2, x, args...> {
typedef metastring<x < 0 ? '-' : '0' + x / 10, '0' + abs (x) % 10, args...> type;
};
// special case for one digit (positive numbers only)
template<int x, char... args>
struct numeric_builder<1, x, args...> {
typedef metastring<'0' + x, args...> type;
};
// convenience wrapper for numeric_builder
template<int x>
class numeric_string
{
private:
// generate a unique string type representing this number
typedef typename numeric_builder<n_digits (x), x>::type type;
// declare a static string of that type (instantiated later at file scope)
static constexpr type value {};
public:
// pointer to the instantiated string
static constexpr const char * str = value.data;
};
// instantiate numeric_string::value as needed for different numbers
template<int x>
constexpr typename numeric_string<x>::type numeric_string<x>::value;
// Functions for creating/copying/destroying objects en masse;
// these will be nullptr for basic types (use memset/memcpy instead)
// =================================================================
typedef void (* FillFunc) (void * data, int len);
typedef void (* CopyFunc) (const void * from, void * to, int len);
typedef void (* EraseFunc) (void * data, int len);
template<class T>
static constexpr FillFunc fill_func ()
{
return std::is_trivial<T>::value ? (FillFunc) nullptr :
[] (void * data, int len) {
T * iter = (T *) data;
T * end = (T *) ((char *) data + len);
while (iter < end)
new (iter ++) T ();
};
}
template<class T>
static constexpr CopyFunc copy_func ()
{
return std::is_trivial<T>::value ? (CopyFunc) nullptr :
[] (const void * from, void * to, int len) {
const T * src = (const T *) from;
T * dest = (T *) to;
T * end = (T *) ((char *) to + len);
while (dest < end)
new (dest ++) T (* src ++);
};
}
template<class T>
static constexpr EraseFunc erase_func ()
{
return std::is_trivial<T>::value ? (EraseFunc) nullptr :
[] (void * data, int len) {
T * iter = (T *) data;
T * end = (T *) ((char *) data + len);
while (iter < end)
(* iter ++).~T ();
};
}
} // namespace aud
#endif // LIBAUDCORE_TEMPLATES_H