Skip to content

Instantly share code, notes, and snippets.

@Redchards
Created May 8, 2016 22:27
Show Gist options
  • Select an option

  • Save Redchards/7f3375f7717a2cb8d608d6d6714b0e37 to your computer and use it in GitHub Desktop.

Select an option

Save Redchards/7f3375f7717a2cb8d608d6d6714b0e37 to your computer and use it in GitHub Desktop.
Simple constexpr assert hack.
#ifndef CONSTEXPR_ASSERT_HXX
#define CONSTEXPR_ASSERT_HXX
#include <cstdlib>
#include <cstdio>
#include <ConstString.hxx>
#include <Platform.hxx>
/* Little trick inspired by Eric Niebler's blog post :
* http://ericniebler.com/2014/09/27/assert-and-constexpr-in-cxx11/
* Slighty modified to be a bit more flexible.
* I still consider it, however, a hack. This is a shame that the C++ does not yet give us a clean
* way to express post and pre-conditions with optional constexpr.
* There is, however, some interesting proposals on the subject :
* https://www.google.fr/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&ved=0ahUKEwin9ZDnwMvMAhWJA8AKHc7fDJ0QFggvMAI&url=http%3A%2F%2Fwww.open-std.org%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2015%2Fn4415.pdf&usg=AFQjCNH06Us_FdCLUrqKYmvD7r4swtRT-w&sig2=Mhbs3WJfX7zobX6pFICAcw&cad=rja
* https://www.google.fr/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0ahUKEwin9ZDnwMvMAhWJA8AKHc7fDJ0QFggmMAE&url=http%3A%2F%2Fwww.open-std.org%2Fjtc1%2Fsc22%2Fwg21%2Fdocs%2Fpapers%2F2014%2Fn4293.pdf&usg=AFQjCNHRfOCc2KsD16oCJWg6KK3pClTp1Q&sig2=Rt6qGhRRtCW76YhxaturVQ
*/
#define CONSTEXPR_ASSERT(condition, msg) condition ? \
int{} : \
throw Details::ConstexprAssertFailure([](ConstString assertMsg){ \
std::fprintf(stderr, "Assertion failure: %s\n", static_cast<const char*>(assertMsg)); assert(!#condition); \
}, msg)
namespace Details
{
class ConstexprAssertFailure
{
public:
template<class Fn>
constexpr ConstexprAssertFailure(Fn&& fn, ConstString msg)
{
fn(msg);
std::quick_exit(EXIT_FAILURE);
}
};
}
#endif // CONSTEXPR_ASSERT_HXX
#ifndef CONST_STRING_HXX
#define CONST_STRING_HXX
#include <algorithm>
#include <cstddef>
#include <stdexcept>
#include <gsl_assert.h>
#include <ArrayIteratorPolicy.hxx>
#include <MetaUtils.hxx>
#include <Range.hxx>
#include <StringDetails.hxx>
class ConstString
{
using IterPolicy = ArrayIteratorPolicy<ConstString>;
public:
using iterator = typename IterPolicy::iterator;
using reverse_iterator = typename IterPolicy::reverse_iterator;
using const_iterator = typename IterPolicy::const_iterator;
using const_reverse_iterator = typename IterPolicy::const_reverse_iterator;
using value_type = const char;
using reference = const char&;
using pointer = const char*;
public:
// Serve for the sole purpose of begin able to be literal type even with default constructor
ConstString() = default;
constexpr ConstString(const ConstString& str) = default;
template<size_t size>
constexpr ConstString(const char(&cstr)[size]) noexcept : size_(size - 1), cstr_(cstr)
{}
constexpr char at(size_t index) const
{
return (index < size_ ? cstr_[index] : throw std::out_of_range("Attempt to access a non-existing index of a constant string"));
}
constexpr char operator[](size_t index) const
{
return at(index);
}
constexpr ConstString drop(size_t num) const
{
ConstString tmp{*this};
tmp.cstr_ += num;
tmp.size_ = size() - num;
return (num < size() ? tmp : throw std::out_of_range("Attempt to access a non-existing index of a constant string"));
}
constexpr ConstString drop(const_iterator it) const
{
size_t interval = it - begin();
ConstString tmp{*this};
tmp.cstr_ += interval;
tmp.size_ = end() - it;
return (it >= begin() && it < end() ? tmp : throw std::out_of_range("Attempt to access a non-existing index of a constant string"));
}
constexpr iterator find(char c) const noexcept
{
for(auto it = begin(); it != end(); ++it)
{
if(*it == c)
{
return it;
}
}
return end();
}
// Modified to build with visual studio. Gcc and clang do not need recursion, simple if branches and for loop are working.
friend constexpr bool operator==(const ConstString& lhs, const ConstString& rhs);
/* Alternative definition, working on GCC 5.2.0 and Clang 3.7
It also avoid the recursion depth problem with big strings
constexpr bool operator==(const ConstString& rhs) const
{
if(size_ != rhs.size()) return false;
for(uint8_t i = 0; i < size_; ++i)
{
if((*this)[i] != rhs[i])
{
return false;
}
}
return true;
}
*/
constexpr size_t size() const noexcept { return size_; }
constexpr pointer data() const noexcept { return cstr_; }
// With this operator, the class would be named ConstStringRef
/*ConstString operator=(const ConstString& other) noexcept
{
cstr_ = other.cstr_;
return *this;
}*/
constexpr operator const char*() const noexcept
{
return data();
}
constexpr iterator begin() const noexcept { return{ *this, 0 }; }
constexpr const_iterator cbegin() const noexcept { return begin(); }
constexpr iterator end() const noexcept { return{ *this, size() }; }
constexpr const_iterator cend() const noexcept { return end(); }
constexpr reverse_iterator rbegin() const noexcept { return end(); }
constexpr const_reverse_iterator crbegin() const noexcept { return end(); }
constexpr reverse_iterator rend() const noexcept { return begin(); }
constexpr const_reverse_iterator crend() const noexcept { return begin(); }
private:
size_t size_;
protected:
pointer cstr_;
};
constexpr bool operator==(const ConstString& lhs, const ConstString& rhs)
{
return lhs.size() != rhs.size() ? false : Details::equalAux(lhs.size(), lhs, rhs);
}
#endif // CONST_STRING_HXX
// This file is part of DAWN ( Do Anything With Nothing ) engine.
#ifndef CORE_PLATFORM
#define CORE_PLATFORM
/**@todo Remove useless lines, check if warning should be error, or remove the "try to compile" policy
@todo Test it on lot of platform in order to be sure all works as expected.
*/
///@note Early version, do not rely on it too much !
#define GCC_COMPILER 1
#define MVSC_COMPILER 2
#define ICC_COMPILER 3
#define BORLAND_COMPILER 4
#define LINUX 1
#define WINDOWS 2
#define MAC 3
#define UNKOWN "unknown"
#if defined( __STDC__ ) && !defined( __cplusplus )
# error "This project require a C++ compiler !"
#endif
#if defined( __cplusplus ) && ( __cplusplus == 199711L )
# error "This project require a C++11 compliant compiler in order to build properly!\
If your compiler support C++11, please turn C++11 support option on !"
#endif
#if defined( __GNUC__ ) || defined( __MINGW__ ) || defined ( __clang__ )
# define FUNCTION __PRETTY_FUNCTION__
# define restrict __restrict__
# define force_inline __attribute__((always_inline))
# define likely(x) __builtin_expect((x),1)
# define unlikely(x) __builtin_expect((x),0)
# if defined( __MINGW__ )
# define COMPILER_NAME "MinGW"
# else
# define COMPILER_NAME "gcc"
# endif
# define COMPILER GCC_COMPILER
# if defined( __GNUC_PATCHLEVEL__ )
# define COMPILER_VERSION ( __GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__ )
# else
# define COMPILER_VERSION ( __GNUC__ * 10000 \
+ __GNUC__ * 100 )
# endif
# if( COMPILER_VERSION < 40500 )
# define DEPRECATED(msg) __attribute__((deprecated))
# else
# define DEPRECATED(msg) __attribute__((deprecated(msg)))
# endif
# if(( COMPILER_VERSION >= 40700 ) || defined(__clang__))
# define override override
# define final final
# endif
# define naked __attribute__((naked))
#elif defined( _MSC_VER )
# define FUNCTION __FUNCSIG__
# define restrict __declspec(restrict)
# define force_inline __forceinline
# define likely(x)
# define unlikely(x)
# define COMPILE_NAME "Microsoft compiler"
# define COMPILER MVSC_COMPILER
# if( ( _MSC_VER <= 1200 ) )
# define COMPILER_VERSION _MSC_VER
# else
# define COMPILER_VERSION _MSC_FULL_VER
# endif
# if( COMPILER_VERSION >= 1400 )
# define override override
# define final sealed
# endif
# define naked __declspec(naked)
# define DEPRECATED(msg) __delcspec( deprecated(msg) )
#elif defined( __INTEL_COMPILER ) || defined( __ICL )
# define FUNCTION __PRETTY_FUNCTION__
# define restrict restrict
# define force_inline // Could be a way, but I don't know it yet
# define likely(x) // No support atm
# define unlikely(x)
# define COMPILER_NAME "Intel compiler"
# define COMPILER ICC_COMPILER
# define COMPILER_VERSION __INTEL_COMPILER
# if( COMPILER_VERSION >= 20130000 )
# define override override
# define final final
# else
# define override
# define final
# endif
# define DEPRECATED(msg) __attribute__( ( deprecated ) )
# define naked __attribute__ ((naked ))
#else
# warning "Unknown compiler, there might be some troubles during compilation, and some special features are disabled. \
This may lead to performance problems and/or debugging troubles! Please check list of supported compiler."
# ifdef( __func__ ) // standard since C++ 11 but compiler may not support it
# define FUNCTION __func__
# else
# warning "Compiler is not AINSI C99 standard, can't use __func__. Some debug functions will be disabled"
# endif
# define restrict
# define always_inline
# define COMPILER_NAME UNKNWON
# define COMPILER UNKNOWN
# define COMPILER_VERSION UNKNOWN
# warning "Compiler not recongnized, results may be unexpected"
# define DEPRECATED(t)
#endif
#if (!defined override && !defined final)
# define override
# define final
# warning "Keyword override and final are not defined by your compiler. This may lead to wrong result when using API. Please change your compiler to a supported compiler !"
#endif
#if defined( __gnu_linux__ ) || defined( __linux__ )
# define OS_NAME "Linux"
# define OS LINUX
#elif defined( macintosh ) || defined( Macintosh ) || ( defined( __APPLE__ ) && defined( __MACH__ ) )
# define OS_NAME "Mac"
# define OS MAC
#elif defined( _WIN32 )
# define OS_NAME "Windows"
# define OS WINDOWS
#else
# define OS_NAME UNKNOWN
# define OS UNKNOWN
# warning "Operating system not recognized. Unexpected results might happen"
#endif
#if( OS == LINUX || OS == MAC ) && \
COMPILER_VERSION >= 4000 && \
( COMPILER == ICC_COMPILER || COMPILER == GCC_COMPILER )
# define EXPORT __attribute__( ( visibility( "default" ) ) )
# define IMPORT __attribute__( ( visibility( "default" ) ) )
# define LOCAL __attribute__( ( visibility( "hidden" ) ) )
#elif( OS == WINDOWS )
# define EXPORT __declspec( dllexport )
# define IMPORT __declspec( dllimport )
# define LOCAL
#else
# define EXPORT
# define IMPORT
# define LOCAL
#endif
#if !defined( BUILD_STATIC ) && !defined( IMPORT_LIBRARY )
# define API EXPORT
#elif defined( IMPORT_LIBRARY )
# define API IMPORT
#else
# define API
#endif
#if defined( __amd64__ ) || defined( __x86_64__ ) || defined( _M_X64 ) || defined( _M_AMD64) || \
defined( _ia64__ ) || defined( _M_IA64 ) || defined( __itanium__ )
# define PLATFORM_X64
#else
# define PLATFORM_X86
#endif
#if defined(_DEBUG) || !defined(NDEBUG)
# define DEBUG true
#else
# define DEBUG false
#endif
#endif // CORE_PLATFORM
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment