blob: 20e35ec5a5f066b6b447015853969685b086febf [file] [log] [blame]
// -*- C++ -*-
/***************************************************************************
*
* 20.meta.trans.other.cpp - test exercising meta.trans.other
*
* $Id$
*
***************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 1999-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
#include <rw_driver.h>
#include <rw/_defs.h>
// compile out all test code if extensions disabled
#ifndef _RWSTD_NO_EXT_CXX_0X
#include <type_traits>
#include <rw_printf.h> // for rwsprintfa()
#include <stdlib.h> // for free()
#include <stddef.h> // for size_t
/**************************************************************************/
template <class T>
struct is_char
{
enum { val = 0 };
};
_RWSTD_SPECIALIZED_CLASS
struct is_char<char>
{
enum { val = 1 };
};
// this function should available _only_ if T is char
template <class T>
int
enabled_if_char (typename std::enable_if<is_char<T>::val>::type* = 0)
{
return 1;
}
// this function should be available if T is _not_ char
template <class T>
int
enabled_if_char (typename std::enable_if<!is_char<T>::val>::type* = 0)
{
return 0;
}
// must have external linkage
int _cond_if_char (void*)
{
return 0;
}
// must have external linkage
int _cond_if_char (long*)
{
return 1;
}
template <class T>
int cond_if_char ()
{
typedef typename
std::conditional<is_char<T>::val, long, void>::type selector;
return _cond_if_char ((selector*)0);
}
/**************************************************************************/
void test_trait (int line,
bool select,
const char* trait,
const char* typeT,
const char* typeU,
bool success)
{
rw_assert (success, 0, line,
"%s<%b, %s, %s>::type is%{?}n't%{;} %s as expected",
trait, select, typeT, typeU, !success, select ? typeT : typeU);
}
void test_trait (int line, const char* trait,
const char* typeT, const char* typeU,
bool success)
{
rw_assert (success, 0, line,
"%s<%s>::type is%{?}n't%{;} %s as expected",
trait, typeT, !success, typeU);
}
void test_enable_if (int line, const char* typeT, int got, int exp)
{
const bool success = got == exp;
rw_assert (success, 0, line, "%s is%{?}n't%{;} %b as expected",
typeT, !success, exp);
}
void test_aligned_storage(int line,
size_t exp_sz, size_t got_sz,
size_t exp_al, size_t got_al)
{
//
rw_assert (exp_sz <= got_sz, 0, line,
"std::aligned_storage<%zu, %zu>::type size is %zu; "
"expected %zu or more", exp_sz, exp_al, got_sz, exp_sz);
if (exp_al != 0) {
// alignment should be greater than or equal to expected
rw_assert (exp_al <= got_al, 0, line,
"std::aligned_storage<%zu, %zu>::type alignment is %zu; "
"expected %zu or more", exp_sz, exp_al, got_al, exp_al);
}
else {
// alignment should be less than or equal to the size of
// the object
rw_assert (got_al <= exp_sz, 0, line,
"std::aligned_storage<%zu, %zu>::type alignment is %zu; "
"expected %zu or less", exp_sz, exp_al, got_al, exp_sz);
}
const bool is_pow_2 = (got_al & (got_al - 1)) == 0;
rw_assert (is_pow_2, 0, line,
"std::aligned_storage<%zu, %zu>::type alignment expected "
"to be a power-of-two; got %zu", exp_sz, exp_al, got_al);
}
/**************************************************************************/
static void test_aligned_storage ()
{
#ifdef _RWSTD_NO_ALIGN_TRAITS
rw_warn (0, 0, __LINE__,
"test_aligned_storage disabled because "
"_RWSTD_NO_ALIGN_TRAITS is defined");
#else
#define TEST(Size,Align) \
{ \
typedef std::aligned_storage<Size, Align>::type storage_t; \
test_aligned_storage(__LINE__, \
Size, sizeof (storage_t), Align, \
std::alignment_of<storage_t>::value); \
} typedef void __dummy
TEST (1, 1);
TEST (1, 2);
TEST (1, 4);
TEST (1, 8);
TEST (9, 1);
TEST (9, 2);
TEST (9, 4);
TEST (9, 8);
TEST (55, 1);
TEST (23, 2);
TEST (17, 4);
TEST (19, 8);
#undef TEST
#define TEST(Size) \
{ \
typedef std::aligned_storage<Size>::type storage_t; \
test_aligned_storage(__LINE__, \
Size, sizeof (storage_t), 0, \
std::alignment_of<storage_t>::value); \
} typedef void __dummy
// test default alignment
TEST (1);
TEST (2);
TEST (4);
TEST (8);
TEST (3);
TEST (5);
TEST (7);
TEST (9);
TEST (55);
TEST (23);
TEST (17);
TEST (19);
#undef TEST
#endif // _RWSTD_NO_ALIGN_TRAITS
}
/**************************************************************************/
#ifndef _RWSTD_NO_ALIGN_TRAITS
struct null_t { };
// get the maximum of 8 values
size_t max8(size_t a1, size_t a2, size_t a3, size_t a4,
size_t a5, size_t a6, size_t a7, size_t a8)
{
size_t r = a1;
if (r < a2) r = a2;
if (r < a3) r = a3;
if (r < a4) r = a4;
if (r < a5) r = a5;
if (r < a6) r = a6;
if (r < a7) r = a7;
if (r < a8) r = a8;
return r;
}
template <size_t Len,
class T1 , class T2 = null_t,
class T3 = null_t, class T4 = null_t,
class T5 = null_t, class T6 = null_t,
class T7 = null_t, class T8 = null_t>
struct aligned_union_tester
{
static void test (int line,
const char* t1 , const char* t2 = 0,
const char* t3 = 0, const char* t4 = 0,
const char* t5 = 0, const char* t6 = 0,
const char* t7 = 0, const char* t8 = 0)
{
const char* arr[] = {
t1, t2, t3, t4, t5, t6, t7, t8
};
char* pbuf = 0;
size_t bufsz = 0;
// get the list of template arguments in one buffer
rw_asnprintf(&pbuf, &bufsz, "%zu", Len);
for (size_t i = 0; i < sizeof (arr) / sizeof (*arr); ++i)
{
if (!arr [i])
break;
rw_asnprintf (&pbuf, &bufsz, "%{+}, %s", arr [i]);
}
typedef std::aligned_union<Len,T1,T2,T3,T4,T5,T6,T7,T8> aligned_t;
typedef typename aligned_t::type aligned_type_t;
const bool pass1 = std::alignment_of<aligned_type_t>::value
== aligned_t::alignment_value;
rw_assert (pass1, 0, line,
"std::aligned_union<%s>::alignment_value is %zu; "
"expected %zu",
pbuf, aligned_t::alignment_value,
std::alignment_of<aligned_type_t>::value);
const size_t exp_al = max8(std::alignment_of<T1>::value,
std::alignment_of<T2>::value,
std::alignment_of<T3>::value,
std::alignment_of<T4>::value,
std::alignment_of<T5>::value,
std::alignment_of<T6>::value,
std::alignment_of<T7>::value,
std::alignment_of<T8>::value);
const size_t got_al = std::alignment_of<aligned_type_t>::value;
const bool pass2 = exp_al == got_al;
rw_assert (pass2, 0, line,
"std::aligned_union<%s>::type alignment is %zu; "
"expected %zu",
pbuf, got_al, exp_al);
const size_t min_sz = Len;
const size_t got_sz = sizeof (aligned_type_t);
const bool pass3 = min_sz <= got_sz;
rw_assert (pass3, 0, __LINE__,
"std::aligned_union<%s>::type size is %zu; expected "
"at least %zu",
pbuf, got_sz, min_sz);
free (pbuf);
}
};
struct struct_t { };
#endif // !_RWSTD_NO_ALIGN_TRAITS
static void test_aligned_union ()
{
#ifdef _RWSTD_NO_ALIGN_TRAITS
rw_warn (0, 0, __LINE__,
"test_aligned_union disabled because "
"_RWSTD_NO_ALIGN_TRAITS is defined");
#else
#define TEST(Len,T1) \
aligned_union_tester<Len,T1>::test(__LINE__,#T1)
TEST (1, char);
TEST (1, long);
TEST (1, void*);
TEST (1, void (struct_t::*)());
TEST (2, char);
TEST (2, long);
TEST (2, void*);
TEST (2, void (struct_t::*)());
TEST (12, char);
TEST (12, long);
TEST (12, void*);
TEST (12, void (struct_t::*)());
#undef TEST
#define TEST(Len,T1,T2) \
aligned_union_tester<Len,T1,T2>::test(__LINE__,#T1,#T2)
TEST (11, char, long);
TEST (134, long, long);
TEST (7, void*, long);
TEST (1, void (struct_t::*)(), long);
TEST (2, char, long);
TEST (2, long, long);
TEST (2, void*, long);
TEST (2, void (struct_t::*)(), long);
#undef TEST
#define TEST(Len,T1,T2,T3,T4,T5) \
aligned_union_tester<Len,T1,T2,T3,T4,T5>::test(__LINE__,#T1,#T2,#T3,#T4,#T5)
TEST (12, char, short, int, long, void*);
TEST (13, void*, long, long, long, int);
TEST (17, void (struct_t::*)(), long, int, void*, char);
#undef TEST
#endif // _RWSTD_NO_ALIGN_TRAITS
}
/**************************************************************************/
static void test_decay ()
{
#define TEST(Trait,TypeT,TypeU) \
test_trait(__LINE__, #Trait, #TypeT, #TypeU, \
std::is_same<Trait<TypeT>::type, TypeU>::value)
// equal to remove_extent<remove_reference<T>::type>::type* for arrays
TEST (std::decay, int[ ], int*);
TEST (std::decay, int[2], int*);
TEST (std::decay, int[2][2], int (*)[2]);
// equal to add_pointer<remove_reference<U>::type>::type for functions
TEST (std::decay, int(), int (*)());
TEST (std::decay, int(char, long), int (*)(char, long));
TEST (std::decay, int(&)(), int (*)());
TEST (std::decay, int(&)(char, long), int (*)(char, long));
// otherwise equal to remove_cv<remove_reference<U>::type>::type
TEST (std::decay, int, int);
TEST (std::decay, const int, int);
TEST (std::decay, volatile int, int);
TEST (std::decay, const volatile int, int);
TEST (std::decay, int&, int);
TEST (std::decay, const int&, int);
TEST (std::decay, volatile int&, int);
TEST (std::decay, const volatile int&, int);
#undef TEST
}
/**************************************************************************/
enum enum_t { E_a = 1 };
static void test_enable_if ()
{
typedef std::enable_if<true, int>::type int_type;
#define TEST(Cond,Expect) \
test_enable_if(__LINE__, #Cond, Cond, Expect)
TEST (enabled_if_char< char>(), 1);
TEST (enabled_if_char< signed char>(), 0);
TEST (enabled_if_char<unsigned char>(), 0);
TEST (enabled_if_char< short>(), 0);
TEST (enabled_if_char< signed short>(), 0);
TEST (enabled_if_char<unsigned short>(), 0);
TEST (enabled_if_char< int>(), 0);
TEST (enabled_if_char< signed int>(), 0);
TEST (enabled_if_char<unsigned int>(), 0);
TEST (enabled_if_char< long>(), 0);
TEST (enabled_if_char< signed long>(), 0);
TEST (enabled_if_char<unsigned long>(), 0);
// miscellaneous other stuff to try and expose problems
TEST (enabled_if_char<char ()>(), 0);
TEST (enabled_if_char<char (*)()>(), 0);
TEST (enabled_if_char<char (&)()>(), 0);
TEST (enabled_if_char<char [1]>(), 0);
TEST (enabled_if_char<char (*)[1]>(), 0);
TEST (enabled_if_char<char (&)[1]>(), 0);
TEST (enabled_if_char<enum_t>(), 0);
#undef TEST
}
/**************************************************************************/
static void test_conditional ()
{
#define TEST(Cond,Expect) \
test_enable_if(__LINE__, #Cond, Cond, Expect)
TEST (cond_if_char<void>(), 0);
TEST (cond_if_char<char>(), 1);
#undef TEST
#define TEST(Trait,Select,TypeT,TypeU,TypeV) \
test_trait(__LINE__, Select, #Trait, #TypeT, #TypeU, \
std::is_same<Trait<Select,TypeT,TypeU>::type, TypeV>::value)
TEST (std::conditional, true, char, long, char);
TEST (std::conditional, false, char, long, long);
#undef TEST
}
/**************************************************************************/
static int run_test (int, char*[])
{
test_aligned_storage ();
test_aligned_union ();
test_decay ();
test_enable_if ();
test_conditional ();
return 0;
}
/**************************************************************************/
#else // _RWSTD_NO_EXT_CXX_0X
/**************************************************************************/
static int run_test (int, char*[])
{
rw_warn (0, 0, __LINE__,
"test disabled because _RWSTD_NO_EXT_CXX_0X is defined");
return 0;
}
#endif // !_RWSTD_NO_EXT_CXX_0X
/**************************************************************************/
int main (int argc, char *argv[])
{
return rw_test (argc, argv, __FILE__,
"meta.trans.other",
0 /* no comment */,
run_test,
0);
}