Created
December 17, 2015 21:06
-
-
Save Redchards/9bcdca8f42dcc02fb758 to your computer and use it in GitHub Desktop.
Straightforward CTTI (compile time type information) implementation, based on the Eric Niebler's one, using my string classes (C++14)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma once | |
| #include <cstddef> | |
| #include <stdexcept> | |
| //#include <Configuration.h> | |
| #include "Platform.hxx" | |
| // There's a warning about "multiple copy constructor specified", due to partial visual studio | |
| // SFINAE implementation. | |
| // We can safely silence them out, as it should not be like this. | |
| // The warning is due to the fact that a non-const iterator can be copied to a const iterator, but not | |
| // the other way. So, a non-const iterator has a copy constructor AND a constructor accepting a const | |
| // iterator argument. But for const iterator class, this constructor is disabled. | |
| // It does work as expected in clang and gcc, but not un visual studio yet. At least, this is only | |
| // a warning and not an error (constructor implementations are the same anyway). | |
| #if(COMPILER == MVSC_COMPILER) | |
| #pragma warning(push) | |
| #pragma warning(disable : 4521) | |
| #endif | |
| template<class ArrayClass> | |
| class ArrayIteratorPolicy | |
| { | |
| protected: | |
| template<bool constFlag> | |
| class BaseIterator | |
| { | |
| friend BaseIterator<!constFlag>; | |
| protected: | |
| using indexType = typename std::conditional<constFlag, const size_t, size_t>::type; | |
| public: | |
| using value_type = typename ArrayClass::value_type; | |
| using reference = typename std::conditional<constFlag, const typename std::remove_cv<value_type>::type&, value_type&>::type; | |
| using pointer = typename std::conditional<constFlag, const typename std::remove_cv<value_type>::type*, value_type*>::type; | |
| using difference = ptrdiff_t; | |
| public: | |
| constexpr BaseIterator() = delete; | |
| constexpr BaseIterator(const ArrayClass& rhs, indexType index) : it_(rhs), index_(index) {} | |
| constexpr BaseIterator(const BaseIterator& other) : it_(other.it_), | |
| index_(other.index_) | |
| {} | |
| template<bool TconstFlag = constFlag, | |
| typename std::enable_if<TconstFlag == true, bool>::type = false> | |
| constexpr BaseIterator(const BaseIterator<false>& other) : it_(other.it_), | |
| index_(other.index_) | |
| {} | |
| template<bool TconstFlag> | |
| constexpr bool operator==(const BaseIterator<TconstFlag>& rhs) const noexcept { return ((index_ == rhs.index_) && (it_ == rhs.it_)); } | |
| template<bool TconstFlag> | |
| constexpr bool operator!=(const BaseIterator<TconstFlag>& rhs) const noexcept { return !(*this == rhs); } | |
| constexpr typename std::remove_cv<value_type>::type operator*() const { return it_[index_]; } | |
| constexpr pointer operator->() const { return &(it_[index_]); } | |
| constexpr operator BaseIterator<true>() const noexcept | |
| { | |
| return{ it_, index_ }; | |
| } | |
| template<bool constFlag1, bool constFlag2> | |
| friend constexpr ptrdiff_t operator-(const BaseIterator<constFlag1>& lhs, const BaseIterator<constFlag2>& rhs) | |
| { | |
| return (&(lhs.it_[lhs.index_]) - &(rhs.it_[rhs.index_])); | |
| } | |
| protected: | |
| const ArrayClass& it_; | |
| indexType index_; | |
| }; | |
| template<bool constFlag> | |
| class ReverseIterator; | |
| template<bool constFlag> | |
| class Iterator : public BaseIterator<constFlag> | |
| { | |
| protected: | |
| using Base = BaseIterator<constFlag>; | |
| using indexType = typename Base::indexType; | |
| friend Iterator<!constFlag>; | |
| public: | |
| using value_type = typename Base::value_type; | |
| using reference = typename Base::reference; | |
| using pointer = typename Base::pointer; | |
| public: | |
| constexpr Iterator(const ArrayClass& rhs, indexType index) noexcept : Base(rhs, index) | |
| {} | |
| constexpr Iterator(const Iterator& other) noexcept : Base(other) | |
| {} | |
| template<bool TconstFlag = constFlag, | |
| typename std::enable_if<TconstFlag == true, bool>::type = false> | |
| constexpr Iterator(const Iterator<false>& other) noexcept : Base(other) | |
| {} | |
| constexpr Iterator(const ReverseIterator<constFlag>& other) noexcept : Base(other) | |
| {} | |
| template<bool TconstFlag = constFlag, | |
| typename std::enable_if<TconstFlag == true, bool>::type = false> | |
| constexpr Iterator(const ReverseIterator<false>& other) noexcept : Base(other) | |
| {} | |
| constexpr Iterator& operator++() noexcept | |
| { | |
| ++(this->index_); | |
| return *this; | |
| } | |
| constexpr Iterator operator++(int) noexcept | |
| { | |
| Iterator tmp{ *this }; | |
| ++(this->index_); | |
| return tmp; | |
| } | |
| constexpr Iterator& operator--() noexcept | |
| { | |
| --(this->index_); | |
| return *this; | |
| } | |
| constexpr Iterator operator--(int) noexcept | |
| { | |
| Iterator tmp{ *this }; | |
| --(this->index_); | |
| return tmp; | |
| } | |
| constexpr Iterator& operator+(size_t n) noexcept | |
| { | |
| this->index_ += n; | |
| return *this; | |
| } | |
| constexpr Iterator& operator-(size_t n) noexcept | |
| { | |
| this->index_ -= n; | |
| return this; | |
| } | |
| }; | |
| template<bool constFlag> | |
| class ReverseIterator : public Iterator<constFlag> | |
| { | |
| protected: | |
| using Base = Iterator<constFlag>; | |
| using indexType = typename Base::indexType; | |
| friend ReverseIterator<!constFlag>; | |
| public: | |
| using value_type = typename Base::value_type; | |
| using reference = typename Base::reference; | |
| using pointer = typename Base::pointer; | |
| public: | |
| // Right now, this constructor do not work (visual studio 2015 update 1). I guess it's again the bad implementation of templates | |
| // and two pass lookup that do not play in our favor | |
| //constexpr ReverseIterator(const ArrayClass& rhs, indexType index) noexcept : Base(rhs, index) {} | |
| constexpr ReverseIterator(const ReverseIterator& other) noexcept : Base(other) | |
| {} | |
| template<bool TconstFlag = constFlag, | |
| typename std::enable_if<TconstFlag == true, bool>::type = false> | |
| constexpr ReverseIterator(const ReverseIterator<false>& other) noexcept : Base(other.it_, other.index_) | |
| {} | |
| constexpr ReverseIterator(const Iterator<constFlag>& other) noexcept : Base(other) | |
| {} | |
| template<bool TconstFlag = constFlag, | |
| typename std::enable_if<TconstFlag == true, bool>::type = false> | |
| constexpr ReverseIterator(const Iterator<false>& other) noexcept : Base(other) | |
| {} | |
| constexpr ReverseIterator& operator++() noexcept | |
| { | |
| return static_cast<ReverseIterator&>(Base::operator--()); | |
| } | |
| constexpr ReverseIterator operator++(int) noexcept | |
| { | |
| return Base::operator--(0); | |
| } | |
| constexpr ReverseIterator& operator--() noexcept | |
| { | |
| return static_cast<ReverseIterator&>(Base::operator++()); | |
| } | |
| constexpr ReverseIterator operator--(int) noexcept | |
| { | |
| return Base::operator++(0); | |
| } | |
| constexpr ReverseIterator& operator+(size_t n) noexcept | |
| { | |
| return static_cast<ReverseIterator&>(static_cast<Base&>(this) - n); | |
| } | |
| constexpr ReverseIterator& operator-(size_t n) noexcept | |
| { | |
| return static_cast<ReverseIterator&>(static_cast<Base&>(this) + n); | |
| } | |
| constexpr typename std::remove_cv<value_type>::type operator*() const { return this->it_[this->index_ - 1]; } | |
| constexpr pointer operator->() const { return &(this->it_[this->index_ - 1]); } | |
| }; | |
| public: | |
| using iterator = Iterator<false>; | |
| using reverse_iterator = ReverseIterator<false>; | |
| using const_iterator = Iterator<true>; | |
| using const_reverse_iterator = ReverseIterator<true>; | |
| }; | |
| #if(COMPILER == MVSC_COMPILER) | |
| #pragma warning(pop) | |
| #endif | |
| class ConstString | |
| { | |
| using IterPolicy = ArrayIteratorPolicy<ConstString>; | |
| public: | |
| 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); | |
| } | |
| // 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) | |
| { | |
| return lhs.size() != rhs.size() ? false : equalAux(lhs.size(), lhs, 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_; } | |
| constexpr operator const char*() const noexcept | |
| { | |
| return data(); | |
| } | |
| 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; | |
| 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(); } | |
| friend constexpr bool equalAux(const size_t size, const ConstString lhs, const ConstString rhs) | |
| { | |
| return size != 0 ? ((lhs[size - 1] == rhs[size - 1] && equalAux(size - 1, lhs, rhs))) : true; | |
| } | |
| private: | |
| size_t size_; | |
| pointer cstr_; | |
| }; | |
| /*class ConstStringSpan : ConstString | |
| { | |
| constexpr ConstStringSpan(ConstString str, iterator first, iterator last) noexcept | |
| : ConstString(str) | |
| { | |
| // assert that last - first >= 0 | |
| } | |
| constexpr ConstStringSpan(ConstString str, size_t firstIndex, size_t lastIndex) noexcept | |
| : ConstString(str), | |
| first_(str.begin() + firstIndex), | |
| last_(str.begin() + lastIndex) | |
| { | |
| // assert that lastIndex - firstIndex > 0 and lastIndex < size | |
| } | |
| constexpr size_t size() const noexcept | |
| { | |
| return last_ - first_; | |
| } | |
| constexpr | |
| private: | |
| iterator first_; | |
| iterator last_; | |
| };*/ | |
| template<size_t Tsize> | |
| class StaticString | |
| { | |
| using IterPolicy = ArrayIteratorPolicy<StaticString<Tsize>>; | |
| public: | |
| 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 | |
| constexpr StaticString() : cstr_("") | |
| {} | |
| template<size_t otherSize> | |
| constexpr StaticString(const char(&cstr)[otherSize]) : cstr_(cstr) | |
| {} | |
| constexpr char operator[](size_t index) const | |
| { | |
| return (index < Tsize ? cstr_[index] : throw std::out_of_range("Attempt to access a non-existing index of a constant string")); | |
| } | |
| constexpr operator const char*() const noexcept | |
| { | |
| return cstr_; | |
| } | |
| template<size_t TSize1, size_t TSize2> | |
| friend constexpr bool operator==(StaticString<TSize1>& lhs, StaticString<TSize2> rhs) | |
| { | |
| return TSize1 != TSize2 ? false : equalAux(TSize1, lhs, rhs); | |
| } | |
| /* Alternative definition, working on GCC 5.2.0 and Clang 3.6 | |
| constexpr bool operator==(StaticString<Tsize> rhs) const | |
| { | |
| for(uint8_t i = 0; i < size(); ++i) | |
| { | |
| if((*this)[i] != rhs[i]) | |
| { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| */ | |
| template<size_t otherSize> | |
| constexpr bool operator==(StaticString<otherSize>) const | |
| { | |
| return false; | |
| } | |
| constexpr size_t size() const noexcept { return Tsize; } | |
| 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; | |
| 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(); } | |
| template<size_t TSize1, size_t TSize2> | |
| friend constexpr bool equalAux(const size_t size, const StaticString<TSize1> lhs, const StaticString<TSize2> rhs) | |
| { | |
| return TSize1 != 0 ? ((lhs[TSize1 - 1] == rhs[TSize1 - 1] && equalAux(size - 1, lhs, rhs))) : true; | |
| } | |
| private: | |
| pointer cstr_; | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| namespace CTTI | |
| { | |
| template<class T> | |
| static const char* GetTypeName() | |
| { | |
| static constexpr size_t typeNameLength = sizeof(FUNCTION) - (exprBegin.size() + exprEnd.size()); | |
| static constexpr ConstString functionName = FUNCTION; | |
| static StackString<typeNameLength + 1> typeName(functionName.data() + exprBegin.size(), typeNameLength); | |
| return typeName; | |
| } | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef STACK_STRING_HXX | |
| #define STACK_STRING_HXX | |
| #include <algorithm> | |
| #include <cstring> | |
| #include <utility> | |
| //#include "span.h" | |
| // A holder for a string, safer than the raw "const char*", at least for construction | |
| // As the underlying type is a std::array, the string is not movable, and generally allocated on the stack. | |
| // In other words, it's nice when you need small strings in general, that could be copied better than taken by reference | |
| // or moved. | |
| // CAVEHEAT : You can't use operator= for assignement, because of the way they work, the assignement operators in | |
| // the class are not copy operator (copy operator must be non-template functions) | |
| // From the standard : | |
| // §12.8/9: | |
| // A user-declared copy assignment operator X::operator= is a non-static non-template member function of class X with | |
| // exactly one parameter of type X, X&, const X&, volatile X& or const volatile X&. | |
| //template<class ... Containers> | |
| constexpr size_t strlength(const char* cstr) | |
| { | |
| size_t size = 0; | |
| for(char c = cstr[0]; c != '\0'; ++c, ++size); | |
| return size; | |
| } | |
| template<size_t size, | |
| bool safeFlag = false> | |
| class StackString final | |
| { | |
| using storage_type = std::array<char, size + 1>; | |
| public: | |
| StackString() = default; | |
| // Not correct ! | |
| template<size_t otherSize> | |
| constexpr explicit StackString(const StackString<otherSize>& sstr) noexcept : StackString(sstr, std::integral_constant<bool, (otherSize <= size)>{}) | |
| {} | |
| template<size_t otherSize> | |
| constexpr StackString(const char(&cstr)[otherSize]) : str_{buildStr(cstr, std::make_index_sequence<otherSize>{})} | |
| {} | |
| template<size_t otherSize> | |
| constexpr StackString(const char* cstr, std::integral_constant<size_t, otherSize>) : str_{build_str(cstr, std::make_index_sequence<otherSize>{})} | |
| {} | |
| StackString(const char* cstr, size_t n) | |
| { | |
| std::copy_n(cstr, n, str_.data()); | |
| } | |
| template<class InputIterator> | |
| StackString(InputIterator first, InputIterator last) | |
| { | |
| auto it = begin(); | |
| for(auto elem : itSpan) | |
| { | |
| *it = elem; | |
| ++it; | |
| } | |
| } | |
| // Removed the GSL (Guideline Support Library) dependency for this example | |
| /*explicit StackString(gsl::span<char> itSpan) | |
| { | |
| auto it = begin(); | |
| for(auto elem : itSpan) | |
| { | |
| *it = elem; | |
| ++it; | |
| } | |
| }*/ | |
| explicit StackString(const std::string& str) : str_{} | |
| { | |
| copyStr(str); | |
| } | |
| template<size_t otherSize> | |
| constexpr typename std::enable_if<(otherSize <= size), StackString>::type& operator=(const StackString<otherSize>& sstr) noexcept | |
| { | |
| std::strcpy(str_.data(), sstr.data()); | |
| return *this; | |
| } | |
| template<size_t otherSize> | |
| constexpr typename std::enable_if<(otherSize > size)>::type operator=(const StackString<otherSize>&) noexcept | |
| { | |
| static_assert(otherSize <= size, "Can't initialize StackString with a string bigger than it's size"); | |
| } | |
| StackString& operator=(const char* cstr) | |
| { | |
| copyStr(cstr); | |
| return *this; | |
| } | |
| StackString& operator=(const std::string& str) | |
| { | |
| copyStr(str); | |
| return *this; | |
| } | |
| char* operator[](size_t index) const noexcept(!safeFlag) | |
| { | |
| return bracketAccess(index, std::integral_constant<bool, safeFlag>{}); | |
| } | |
| void clear() noexcept | |
| { | |
| str_ = {}; | |
| } | |
| const char* data() const noexcept | |
| { | |
| return str_.data(); | |
| } | |
| operator const char*() const noexcept | |
| { | |
| return data(); | |
| } | |
| auto begin() noexcept { return str_.begin(); } | |
| auto cbegin() const noexcept { return str_.cbegin(); } | |
| auto rbegin() noexcept { return str_.rbegin(); } | |
| auto crbegin() const noexcept { return str_.crbegin(); } | |
| auto end() noexcept { return str_.end(); } | |
| auto cend() const noexcept { return str_.cend(); } | |
| auto rend() noexcept { return str_.rend(); } | |
| auto crend() const noexcept { return str_.crend(); } | |
| private: | |
| template<size_t otherSize> | |
| explicit StackString(const StackString<otherSize>& sstr, std::true_type) noexcept : str_{} | |
| { | |
| std::strcpy(str_.data(), sstr); | |
| } | |
| template<size_t otherSize> | |
| explicit StackString(const StackString<otherSize>&, std::false_type) noexcept | |
| { | |
| static_assert(otherSize <= size, "Can't initialize StackString with a string bigger than it's size"); | |
| } | |
| template<size_t otherSize, | |
| size_t stringSize = size, | |
| size_t ... Indices> | |
| constexpr std::enable_if_t<(otherSize <= stringSize), storage_type> buildStr(const char (&cstr)[otherSize], std::index_sequence<Indices...>) noexcept | |
| { | |
| return {{cstr[Indices]...}}; | |
| } | |
| template<size_t otherSize, | |
| size_t stringSize = size, | |
| size_t ... Indices> | |
| constexpr std::enable_if_t<(otherSize > stringSize), storage_type> buildStr(const char (&)[otherSize], std::index_sequence<Indices...>) noexcept | |
| { | |
| static_assert(otherSize <= size, "Can't initialize StackString with a string bigger than it's size"); | |
| return {}; | |
| } | |
| /*template<class InputIterator, size_t ... Indices> | |
| constexpr sotrage_type build_str_from_iterators(const InputIterator first, std::index_sequence<Indices>) | |
| { | |
| return {{(*(first + Indices))...}}; | |
| }*/ | |
| void copyStr(const std::string& str) | |
| { | |
| if(str.length() <= size) | |
| { | |
| std::strcpy(str_.data(), str.data()); | |
| } | |
| else | |
| { | |
| throw std::out_of_range("Attempt to construct StackString with a string bigger than allowed by the type !"); | |
| } | |
| } | |
| void copyStr(const char* cstr) | |
| { | |
| if(strlen(cstr) <= size) | |
| { | |
| std::strcpy(str_.data(), cstr); | |
| } | |
| else | |
| { | |
| throw std::out_of_range("Attempt to construct StackString with a string bigger than allowed by the type !"); | |
| } | |
| } | |
| char* bracketAccess(size_t index, std::true_type) | |
| { | |
| if(!(index >= size)) | |
| { | |
| return str_ + index; | |
| } | |
| throw std::out_of_range("Invalid access of StackString"); | |
| } | |
| char* bracketAccess(size_t index, std::false_type) noexcept | |
| { | |
| return str_ + index; | |
| } | |
| private: | |
| storage_type str_; | |
| }; | |
| #endif // STACK_STRING_HXX |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment