/* metaprogramming.h -*- C++ -*- * * @copyright * Copyright (C) 2012-2013, Intel Corporation * All rights reserved. * * @copyright * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * @copyright * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** @file metaprogramming.h * * @brief Defines metaprogramming utility classes used in the Cilk library. * * @ingroup common */ #ifndef METAPROGRAMMING_H_INCLUDED #define METAPROGRAMMING_H_INCLUDED #ifdef __cplusplus #include #include #include #ifdef _WIN32 #include #endif #include namespace cilk { namespace internal { /** Test if a class is empty. * * If @a Class is an empty (and therefore necessarily stateless) class, then * the “empty base-class optimization” guarantees that * `sizeof(check_for_empty_class) == sizeof(char)`. Conversely, if * `sizeof(check_for_empty_class) > sizeof(char)`, then @a Class is not * empty, and we must discriminate distinct instances of @a Class. * * Typical usage: * * // General definition of A for non-empty B: * template ::value> > * class A { ... }; * * // Specialized definition of A for empty B: * template * class A { ... }; * * @tparam Class The class to be tested for emptiness. * * @result The `value` member will be `true` if @a Class is empty, * `false` otherwise. * * @ingroup common */ template class class_is_empty { class check_for_empty_class : public Class { char m_data; public: // Declared but not defined check_for_empty_class(); check_for_empty_class(const check_for_empty_class&); check_for_empty_class& operator=(const check_for_empty_class&); ~check_for_empty_class(); }; public: /** Constant is true if and only if @a Class is empty. */ static const bool value = (sizeof(check_for_empty_class) == sizeof(char)); }; /** Get the alignment of a type. * * For example: * * align_of::value == 8 * * @tparam Tp The type whose alignment is to be computed. * * @result The `value` member of an instantiation of this class template * will hold the integral alignment requirement of @a Tp. * * @pre @a Tp shall be a complete type. * * @ingroup common */ template struct align_of { private: struct imp { char m_padding; Tp m_val; // The following declarations exist to suppress compiler-generated // definitions, in case @a Tp does not have a public default // constructor, copy constructor, or destructor. imp(const imp&); // Declared but not defined ~imp(); // Declared but not defined }; public: /// The integral alignment requirement of @a Tp. static const std::size_t value = (sizeof(imp) - sizeof(Tp)); }; /** A class containing raw bytes with a specified alignment and size. * * An object of type `aligned_storage` will have alignment `A` and * size at least `S`. Its contents will be uninitialized bytes. * * @tparam Size The required minimum size of the resulting class. * @tparam Alignment The required alignment of the resulting class. * * @pre @a Alignment shall be a power of 2 no greater then 64. * * @note This is implemented using the `CILK_ALIGNAS` macro, which uses * the non-standard, implementation-specific features * `__declspec(align(N))` on Windows, and * `__attribute__((__aligned__(N)))` on Unix. The `gcc` implementation * of `__attribute__((__aligned__(N)))` requires a numeric literal `N` * (_not_ an arbitrary compile-time constant expression). Therefore, * this class is implemented using specialization on the required * alignment. * * @note The template class is specialized only for the supported * alignments. An attempt to instantiate it for an unsupported * alignment will result in a compilation error. */ template struct aligned_storage; template class aligned_storage { CILK_ALIGNAS( 1) char m_bytes[Size]; }; template class aligned_storage { CILK_ALIGNAS( 2) char m_bytes[Size]; }; template class aligned_storage { CILK_ALIGNAS( 4) char m_bytes[Size]; }; template class aligned_storage { CILK_ALIGNAS( 8) char m_bytes[Size]; }; template class aligned_storage { CILK_ALIGNAS(16) char m_bytes[Size]; }; template class aligned_storage { CILK_ALIGNAS(32) char m_bytes[Size]; }; template class aligned_storage { CILK_ALIGNAS(64) char m_bytes[Size]; }; /** A buffer of uninitialized bytes with the same size and alignment as a * specified type. * * The class `storage_for_object` will have the same size and alignment * properties as `Type`, but it will contain only raw (uninitialized) bytes. * This allows the definition of a data member which can contain a `Type` * object which is initialized explicitly under program control, rather * than implicitly as part of the initialization of the containing class. * For example: * * class C { * storage_for_object _member; * public: * C() ... // Does NOT initialize _member * void initialize(args) * { new (_member.pointer()) MemberClass(args); } * const MemberClass& member() const { return _member.object(); } * MemberClass& member() { return _member.object(); } * * @tparam Type The type whose size and alignment are to be reflected * by this class. */ template class storage_for_object : aligned_storage< sizeof(Type), align_of::value > { public: /// Return a typed reference to the buffer. const Type& object() const { return *reinterpret_cast(this); } Type& object() { return *reinterpret_cast(this); } }; /** Get the functor class corresponding to a binary function type. * * The `binary_functor` template class class can be instantiated with a binary * functor class or with a real binary function, and will yield an equivalent * binary functor class class in either case. * * @tparam F A binary functor class, a binary function type, or a pointer to * binary function type. * * @result `binary_functor::%type` will be the same as @a F if @a F is * a class. It will be a `std::pointer_to_binary_function` wrapper * if @a F is a binary function or binary function pointer type. * (It will _not_ necessarily be an `Adaptable Binary Function` * class, since @a F might be a non-adaptable binary functor * class.) * * @ingroup common */ template struct binary_functor { /// The binary functor class equivalent to @a F. typedef F type; }; /// @copydoc binary_functor /// Specialization for binary function. template struct binary_functor { /// The binary functor class equivalent to @a F. typedef std::pointer_to_binary_function type; }; /// @copydoc binary_functor /// Specialization for pointer to binary function. template struct binary_functor { /// The binary functor class equivalent to @a F. typedef std::pointer_to_binary_function type; }; /** Indirect binary function class with specified types. * * `typed_indirect_binary_function` is an `Adaptable Binary Function` class * based on an existing binary functor class or binary function type @a F. If * @a F is a stateless class, then this class will be empty, and its * `operator()` will invoke @a F’s `operator()`. Otherwise, an object of this * class will hold a pointer to an object of type @a F, and will refer its * `operator()` calls to the pointed-to @a F object. * * That is, suppose that we have the declarations: * * F *p; * typed_indirect_binary_function ibf(p); * * Then: * * - `ibf(x, y) == (*p)(x, y)`. * - `ibf(x, y)` will not do a pointer dereference if `F` is an empty class. * * @note Just to repeat: if `F` is an empty class, then * `typed_indirect_binary_function\' is also an empty class. * This is critical for its use in the @ref min_max::view_base * "min/max reducer view classes", where it allows the view to * call a comparison functor in the monoid without actually * having to allocate a pointer in the view class when the * comparison class is empty. * * @note If you have an `Adaptable Binary Function` class or a binary * function type, then you can use the * @ref indirect_binary_function class, which derives the * argument and result types parameter type instead of requiring * you to specify them as template arguments. * * @tparam F A binary functor class, a binary function type, or a pointer to * binary function type. * @param A1 The first argument type. * @param A2 The second argument type. * @param R The result type. * * @see min_max::comparator_base * @see indirect_binary_function * * @ingroup common */ template < typename F , typename A1 , typename A2 , typename R , typename Functor = typename binary_functor::type , bool FunctorIsEmpty = class_is_empty::value > class typed_indirect_binary_function : std::binary_function { const F* f; public: /// Constructor captures a pointer to the wrapped function. typed_indirect_binary_function(const F* f) : f(f) {} /// Return the comparator pointer, or `NULL` if the comparator is stateless. const F* pointer() const { return f; } /// Apply the pointed-to functor to the arguments. R operator()(const A1& a1, const A2& a2) const { return (*f)(a1, a2); } }; /// @copydoc typed_indirect_binary_function /// Specialization for an empty functor class. (This is only possible if @a F /// itself is an empty class. If @a F is a function or pointer-to-function /// type, then the functor will contain a pointer.) template class typed_indirect_binary_function : std::binary_function { public: /// Return `NULL` for the comparator pointer of a stateless comparator. const F* pointer() const { return 0; } /// Constructor discards the pointer to a stateless functor class. typed_indirect_binary_function(const F* f) {} /// Create an instance of the stateless functor class and apply it to the arguments. R operator()(const A1& a1, const A2& a2) const { return F()(a1, a2); } }; /** Indirect binary function class with inferred types. * * This is identical to @ref typed_indirect_binary_function, except that it * derives the binary function argument and result types from the parameter * type @a F instead of taking them as additional template parameters. If @a F * is a class type, then it must be an `Adaptable Binary Function`. * * @see typed_indirect_binary_function * * @ingroup common */ template ::type> class indirect_binary_function : typed_indirect_binary_function< F , typename Functor::first_argument_type , typename Functor::second_argument_type , typename Functor::result_type > { typedef typed_indirect_binary_function< F , typename Functor::first_argument_type , typename Functor::second_argument_type , typename Functor::result_type > base; public: indirect_binary_function(const F* f) : base(f) {} ///< Constructor }; /** Choose a type based on a boolean constant. * * This metafunction is identical to C++11’s condition metafunction. * It needs to be here until we can reasonably assume that users will be * compiling with C++11. * * @tparam Cond A boolean constant. * @tparam IfTrue A type. * @tparam IfFalse A type. * @result The `type` member will be a typedef of @a IfTrue if @a Cond * is true, and a typedef of @a IfFalse if @a Cond is false. * * @ingroup common */ template struct condition { typedef IfTrue type; ///< The type selected by the condition. }; /// @copydoc condition /// Specialization for @a Cond == `false`. template struct condition { typedef IfFalse type; ///< The type selected by the condition. }; /** @def __CILKRTS_STATIC_ASSERT * * @brief Compile-time assertion. * * Causes a compilation error if a compile-time constant expression is false. * * @par Usage example. * This assertion is used in reducer_min_max.h to avoid defining * legacy reducer classes that would not be binary-compatible with the * same classes compiled with earlier versions of the reducer library. * * __CILKRTS_STATIC_ASSERT( * internal::class_is_empty< internal::binary_functor >::value, * "cilk::reducer_max only works with an empty Compare class"); * * @note In a C++11 compiler, this is just the language predefined * `static_assert` macro. * * @note In a non-C++11 compiler, the @a Msg string is not directly included * in the compiler error message, but it may appear if the compiler * prints the source line that the error occurred on. * * @param Cond The expression to test. * @param Msg A string explaining the failure. * * @ingroup common */ #if defined(__INTEL_CXX11_MODE__) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define __CILKRTS_STATIC_ASSERT(Cond, Msg) static_assert(Cond, Msg) #else # define __CILKRTS_STATIC_ASSERT(Cond, Msg) \ typedef int __CILKRTS_STATIC_ASSERT_DUMMY_TYPE \ [::cilk::internal::static_assert_failure<(Cond)>::Success] /// @cond internal template struct static_assert_failure { }; template <> struct static_assert_failure { enum { Success = 1 }; }; # define __CILKRTS_STATIC_ASSERT_DUMMY_TYPE \ __CILKRTS_STATIC_ASSERT_DUMMY_TYPE1(__cilkrts_static_assert_, __LINE__) # define __CILKRTS_STATIC_ASSERT_DUMMY_TYPE1(a, b) \ __CILKRTS_STATIC_ASSERT_DUMMY_TYPE2(a, b) # define __CILKRTS_STATIC_ASSERT_DUMMY_TYPE2(a, b) a ## b /// @endcond #endif /// @cond internal /** @name Aligned heap management. */ //@{ /** Implementation-specific aligned memory allocation function. * * @param size The minimum number of bytes to allocate. * @param alignment The required alignment (must be a power of 2). * @return The address of a block of memory of at least @a size * bytes. The address will be a multiple of @a alignment. * `NULL` if the allocation fails. * * @see deallocate_aligned() */ inline void* allocate_aligned(std::size_t size, std::size_t alignment) { #ifdef _WIN32 return _aligned_malloc(size, alignment); #else #if defined(__ANDROID__) return memalign(std::max(alignment, sizeof(void*)), size); #else void* ptr; return (posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size) == 0) ? ptr : 0; #endif #endif } /** Implementation-specific aligned memory deallocation function. * * @param ptr A pointer which was returned by a call to alloc_aligned(). */ inline void deallocate_aligned(void* ptr) { #ifdef _WIN32 _aligned_free(ptr); #else std::free(ptr); #endif } /** Class to allocate and guard an aligned pointer. * * A new_aligned_pointer object allocates aligned heap-allocated memory when * it is created, and automatically deallocates it when it is destroyed * unless its `ok()` function is called. * * @tparam T The type of the object to allocate on the heap. The allocated * will have the size and alignment of an object of type T. */ template class new_aligned_pointer { void* m_ptr; public: /// Constructor allocates the pointer. new_aligned_pointer() : m_ptr(allocate_aligned(sizeof(T), internal::align_of::value)) {} /// Destructor deallocates the pointer. ~new_aligned_pointer() { if (m_ptr) deallocate_aligned(m_ptr); } /// Get the pointer. operator void*() { return m_ptr; } /// Return the pointer and release the guard. T* ok() { T* ptr = static_cast(m_ptr); m_ptr = 0; return ptr; } }; //@} /// @endcond } // namespace internal //@{ /** Allocate an aligned data structure on the heap. * * `cilk::aligned_new([args])` is equivalent to `new T([args])`, except * that it guarantees that the returned pointer will be at least as aligned * as the alignment requirements of type `T`. * * @ingroup common */ template T* aligned_new() { internal::new_aligned_pointer ptr; new (ptr) T(); return ptr.ok(); } template T* aligned_new(const T1& x1) { internal::new_aligned_pointer ptr; new (ptr) T(x1); return ptr.ok(); } template T* aligned_new(const T1& x1, const T2& x2) { internal::new_aligned_pointer ptr; new (ptr) T(x1, x2); return ptr.ok(); } template T* aligned_new(const T1& x1, const T2& x2, const T3& x3) { internal::new_aligned_pointer ptr; new (ptr) T(x1, x2, x3); return ptr.ok(); } template T* aligned_new(const T1& x1, const T2& x2, const T3& x3, const T4& x4) { internal::new_aligned_pointer ptr; new (ptr) T(x1, x2, x3, x4); return ptr.ok(); } template T* aligned_new(const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5) { internal::new_aligned_pointer ptr; new (ptr) T(x1, x2, x3, x4, x5); return ptr.ok(); } //@} /** Deallocate an aligned data structure on the heap. * * `cilk::aligned_delete(ptr)` is equivalent to `delete ptr`, except that it * operates on a pointer that was allocated by aligned_new(). * * @ingroup common */ template void aligned_delete(const T* ptr) { ptr->~T(); internal::deallocate_aligned((void*)ptr); } } // namespace cilk #endif // __cplusplus #endif // METAPROGRAMMING_H_INCLUDED