diff --git a/CHANGELOG.md b/CHANGELOG.md index d626b6a3..75167293 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to stdex library project will be documented in this file. visit https://github.com/oktonion/stdex for the latest version of stdex library +## [0.1.2] - ... +### Added + - is_union implementation with bug for detecting class as union + - Mac OS build added to CI (with xcode9 and clang-900.0.37) + - Mac OS implementation for thread::hardware_concurrency and chrono + ## [0.1.1] - 2018-08-07 ### Added - is_enum implementation diff --git a/README.md b/README.md index e0b1e513..4c4ea584 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ The library is portable for any compiler that supports C++98 but as we all know * g++ 4.4.2, 4.4, 4.6; * g++ 4.8, 4.9, 5.0 with c++98 option; * clang 3.5, 5.0 with c++98 option; +* clang-900.0.37 with c++98 option (Mac OS); * Visual Studio 2008, 2010, 2013, 2015; ...and thats it. If you use other compilers and decide to include this library in your project there is no guarantee that it will compile without errors. In case you will be able to fix the errors without breaking existing code for already supported compilers I would really appreciate your pull requests. @@ -36,14 +37,16 @@ Build process is simple: * In Unix - either run a 'build_lib.sh' script (works with g++ and clang if environment variable $COMPILER is set to compiler name, f.e. to 'clang++-3.5') or build by yourself static library from 'stdex/src' directory sources. * In Windows - either run a 'build_lib.bat' script (works with Visual Studio if environment variables are set by 'vsvars32.bat' script that is being shipped with your Visual Studio distributive) or build by yourself the static library from 'stdex/src' and 'pthreads-win32' directories sources. * In QNX 6.x.x - either run a 'build_lib_qnx.sh' (using qcc compiler) or build by yourself the static library from 'stdex/src' directory sources (do not forget to link with 'stdlib' library). +* In Mac OS - either run a 'build_lib.sh' script (works with clang if environment variable $COMPILER is set to compiler name, f.e. to 'clang++-3.5') or build by yourself static library from 'stdex/src' directory sources. # how to include in your project In your project: 1. include sources of the library or link with prebuilded static library ('.a'/'.lib' file, f.e. 'libstdex.a'/'stdex.lib') 2. link with system libraries for POSIX-threads and realtime clocks: -* 'librt.lib' and 'libpthread.lib' in UNIX; +* 'librt.lib' and 'libpthread.lib' in UNIX; * 'ntdll.lib' and [POSIX-threads lib](https://github.com/GerHobbelt/pthread-win32 "I'm using this implementation") in Windows (if you have built stdex static library with 'pthreads-win32' sources then you have no need to link with pthreads anymore - it's already in 'stdex.lib'); * 'm.lib' in QNX 6.x.x; +* 'libpthread.lib' in Mac OS; 3. enjoy example script build for Ubuntu (with g++ installed): @@ -66,4 +69,10 @@ COMPILER=qcc $COMPILER main.cpp -L./stdex/lib/ -lstdex -lm -o "./bin/main" ``` +example script build for Mac OS (with clang installed): +``` +COMPILER=clang++ +$COMPILER main.cpp -L./stdex/lib/ -lstdex -lpthread -o "./bin/main" +``` + visit https://github.com/oktonion/stdex for the latest version of stdex library diff --git a/stdex/include/core.h b/stdex/include/core.h index c506391c..87ead3ba 100644 --- a/stdex/include/core.h +++ b/stdex/include/core.h @@ -6,14 +6,17 @@ #endif // _MSC_VER > 1000 -#ifndef __has_feature - #define __has_feature(x) 0 // Compatibility with non-clang compilers. +#ifndef __has_feature // Optional of course. + #define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif +#ifndef __has_extension + #define __has_extension __has_feature // Compatibility with pre-3.0 compilers. #endif //#define STDEX_FORCE_CPP11_TYPES_SUPPORT //uncomment to force support of char16_t and char32_t in C++03 // Any compiler claiming C++11 supports, Visual C++ 2015 and Clang version supporting constexpr -#if ((__cplusplus >= 201103L) || (_MSC_VER >= 1900) || (__has_feature(cxx_constexpr))) // C++ 11 implementation +#if ((__cplusplus >= 201103L) || (_MSC_VER >= 1900) || (__has_feature(cxx_constexpr) || (__has_extension(cxx_constexpr)))) // C++ 11 implementation #define _STDEX_NATIVE_CPP11_SUPPORT #define _STDEX_NATIVE_CPP11_TYPES_SUPPORT @@ -22,19 +25,60 @@ #if !defined(_STDEX_NATIVE_CPP11_TYPES_SUPPORT) - #if ((__cplusplus > 199711L) || defined(__CODEGEARC__)) + #if ((__cplusplus > 199711L) || defined(__CODEGEARC__) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__cpp_unicode_characters) || __has_feature(cxx_unicode_literals)) #define _STDEX_NATIVE_CPP11_TYPES_SUPPORT #endif + #if (defined(__apple_build_version__) && (__clang_major__ >= 3)) + #ifndef _STDEX_NATIVE_CPP11_TYPES_SUPPORT + #define _STDEX_NATIVE_CPP11_TYPES_SUPPORT + #endif + #endif + #endif #if ((!defined(_MSC_VER) || _MSC_VER < 1600) && !defined(_STDEX_NATIVE_CPP11_SUPPORT)) - #define _STDEX_IMPLEMENTS_NULLPTR_SUPPORT + #if (__has_feature(cxx_nullptr) || __has_extension(cxx_nullptr)) + #define _STDEX_NATIVE_NULLPTR_SUPPORT + #else + #if !defined(nullptr) + #define _STDEX_IMPLEMENTS_NULLPTR_SUPPORT + #else + #define STRINGIZE_HELPER(x) #x + #define STRINGIZE(x) STRINGIZE_HELPER(x) + #define WARNING(desc) message(__FILE__ "(" STRINGIZE(__LINE__) ") : warning: " desc) + + #pragma WARNING("stdex library - macro 'nullptr' was previously defined by user; ignoring stdex macro definition") + + #undef STRINGIZE_HELPER + #undef STRINGIZE + #undef WARNING + #endif + #endif + + #if (__has_feature(cxx_static_assert) || __has_extension(cxx_static_assert)) + #define _STDEX_NATIVE_STATIC_ASSERT_SUPPORT + #else + #if !defined(static_assert) + #define _STDEX_IMPLEMENTS_STATIC_ASSERT_SUPPORT + #else + #define STRINGIZE_HELPER(x) #x + #define STRINGIZE(x) STRINGIZE_HELPER(x) + #define WARNING(desc) message(__FILE__ "(" STRINGIZE(__LINE__) ") : warning: " desc) + + #pragma WARNING("stdex library - macro 'static_assert' was previously defined by user; ignoring stdex macro definition") + + #undef STRINGIZE_HELPER + #undef STRINGIZE + #undef WARNING + #endif + #endif #else #define _STDEX_NATIVE_NULLPTR_SUPPORT + #define _STDEX_NATIVE_STATIC_ASSERT_SUPPORT #endif @@ -127,14 +171,14 @@ #else //no C++11 support // nullptr and nullptr_t implementation - #ifndef _STDEX_NATIVE_NULLPTR_SUPPORT + #ifdef _STDEX_IMPLEMENTS_NULLPTR_SUPPORT #include "nullptr.h" #else namespace stdex { typedef std::nullptr_t nullptr_t; } - #endif // _STDEX_NATIVE_NULLPTR_SUPPORT + #endif // _STDEX_IMPLEMENTS_NULLPTR_SUPPORT namespace stdex { @@ -166,7 +210,7 @@ };\ typedef stdex::detail::StaticAssertionTest CONCATENATE(__static_assertion_test_at_line_, __LINE__) -#ifndef _STDEX_NATIVE_NULLPTR_SUPPORT +#ifdef _STDEX_IMPLEMENTS_STATIC_ASSERT_SUPPORT #define static_assert(expression, message) STATIC_ASSERT(expression, ERROR_MESSAGE_STRING) #endif diff --git a/stdex/include/type_traits.hpp b/stdex/include/type_traits.hpp index 53fe4485..29aa47eb 100644 --- a/stdex/include/type_traits.hpp +++ b/stdex/include/type_traits.hpp @@ -1361,14 +1361,14 @@ namespace stdex template - _yes_type _can_be_parent_tester(_Tp*); + _yes_type _enum_can_be_parent_tester(_Tp*); template - _no_type _can_be_parent_tester(...); + _no_type _enum_can_be_parent_tester(...); template - struct _can_be_parent + struct _enum_can_be_parent { - static const bool value = sizeof(_can_be_parent_tester<_Tp>(_is_enum_bug_internal::_can_be_parent_tester_helper<_Tp>(0))) == sizeof(_yes_type); + static const bool value = sizeof(_enum_can_be_parent_tester<_Tp>(_is_enum_bug_internal::_can_be_parent_tester_helper<_Tp>(0))) == sizeof(_yes_type); }; template @@ -1380,7 +1380,7 @@ namespace stdex template struct _is_enum_helper1<_Tp, true> { - static const bool value = !(_can_be_parent<_Tp>::value); + static const bool value = !(_enum_can_be_parent<_Tp>::value); }; template @@ -1457,6 +1457,47 @@ namespace stdex public detail::_is_member_pointer_helper::type>::type { }; + namespace detail + { + template + struct _is_union_helper + { + typedef integral_constant type; + }; + + + /*template + _derived_dummy<_Tp>* _union_can_be_parent_tester_helper(int); + template + char _union_can_be_parent_tester_helper(...); + + + _yes_type _union_can_be_parent_tester(void*); + char _union_can_be_parent_tester(...); + + template + struct _union_can_be_parent + { + static const bool value = sizeof(_union_can_be_parent_tester(_union_can_be_parent_tester_helper<_Tp>(0))) == sizeof(_yes_type); + };*/ + + template + struct _is_union_helper<_Tp, false> + { + typedef integral_constant::value == bool(false)) + && (_has_member_pointer_impl<_Tp>::value == bool(true)) + //&& (_union_can_be_parent<_Tp>::value == bool(false)) + > type; + }; + } + + // is_union + template + struct is_union : + public detail::_is_union_helper::type, detail::_or_, is_pointer<_Tp>, is_function<_Tp>, is_member_pointer<_Tp>, is_array<_Tp>, is_reference<_Tp> >::value>::type + { }; + namespace detail { template @@ -1470,7 +1511,7 @@ namespace stdex { typedef integral_constant::value == bool(false)) - //&& !is_union<_Tp>::value >::value + //&& (is_union<_Tp>::value == bool(false)) && (is_array<_Tp>::value == bool(false)) && (is_void<_Tp>::value == bool(false)) && (is_function<_Tp>::value == bool(false))> type; diff --git a/stdex/src/chrono.cpp b/stdex/src/chrono.cpp index 21107e48..8101ffd9 100644 --- a/stdex/src/chrono.cpp +++ b/stdex/src/chrono.cpp @@ -179,7 +179,80 @@ const bool steady_clock::is_steady = false; #define CLOCK_REALTIME 0 int(*clock_gettime_func_pointer)(int X, mytimespec *tv) = &clock_gettime_impl::clock_gettime; +#elif defined(__MACH__) +#include +#include /* gettimeofday */ +#include /* mach_absolute_time */ + +#define BILLION 1000000000L +#define MILLION 1000000L + +#define NORMALISE_TIMESPEC( ts, uint_milli ) \ + { \ + ts.tv_sec += uint_milli / 1000u; \ + ts.tv_nsec += (uint_milli % 1000u) * MILLION; \ + ts.tv_sec += ts.tv_nsec / BILLION; \ + ts.tv_nsec = ts.tv_nsec % BILLION; \ + } + +static mach_timebase_info_data_t timebase = { 0, 0 }; /* numer = 0, denom = 0 */ +static struct timespec inittime = { 0, 0 }; /* nanoseconds since 1-Jan-1970 to init() */ +static uint64_t initclock; /* ticks since boot to init() */ + +void init() +{ + struct timeval micro; /* microseconds since 1 Jan 1970 */ + + if (mach_timebase_info(&timebase) != 0) + abort(); /* very unlikely error */ + + if (gettimeofday(µ, NULL) != 0) + abort(); /* very unlikely error */ + + initclock = mach_absolute_time(); + + inittime.tv_sec = micro.tv_sec; + inittime.tv_nsec = micro.tv_usec * 1000; +} + +static struct _init_inittime +{ + _init_inittime() + { + init(); + } +} init_inittime; + +struct timespec get_abs_future_time_fine(unsigned milli) +{ + struct timespec future; /* ns since 1 Jan 1970 to 1500 ms in future */ + uint64_t clock; /* ticks since init */ + uint64_t nano; /* nanoseconds since init */ + + clock = mach_absolute_time() - initclock; + nano = clock * (uint64_t)timebase.numer / (uint64_t)timebase.denom; + future = inittime; + future.tv_sec += nano / BILLION; + future.tv_nsec += nano % BILLION; + NORMALISE_TIMESPEC( future, milli ); + return future; +} +struct mytimespec: + public timespec +{}; + +const bool system_clock::is_steady = true; +const bool steady_clock::is_steady = true; + +int clock_gettime(int X, timespec *tv) +{ + *tv = get_abs_future_time_fine(1500); + + return (0); +} +int(*clock_gettime_func_pointer)(int X, timespec *tv) = &clock_gettime; #else + struct mytimespec: public timespec {}; diff --git a/stdex/src/thread.cpp b/stdex/src/thread.cpp index 9dd13708..f061b77f 100644 --- a/stdex/src/thread.cpp +++ b/stdex/src/thread.cpp @@ -14,6 +14,9 @@ #ifdef __GLIBC__ #include +#elif defined(__APPLE__) || defined(__FreeBSD__) +#include +#include #endif #if defined(__QNXNTO__) || defined(__QNX__) @@ -384,6 +387,10 @@ unsigned thread::hardware_concurrency() NOEXCEPT_FUNCTION return get_nprocs(); #elif defined(SYSPAGE_CPU_ENTRY) return _syspage_ptr->num_cpu; +#elif defined(__APPLE__) || defined(__FreeBSD__) + int count; + size_t size=sizeof(count); + return sysctlbyname("hw.ncpu", &count, &size, NULL, 0) ? 0 : count; #else // The standard requires this function to return zero if the number of // hardware cores could not be determined.