├── CMakeLists.txt ├── .clang-format ├── format-all.py ├── README.md ├── .gitignore ├── .travis.yml ├── LICENSE ├── tests └── cometa_test.cpp └── include ├── cident.h ├── cometa └── string.hpp └── cometa.hpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016 D Levin (http://www.kfrlib.com) 2 | # This file is part of CoMeta (C++14 metaprogramming library created for KFR framework) 3 | # License: MIT 4 | 5 | cmake_minimum_required(VERSION 2.8) 6 | 7 | if (CMAKE_BUILD_TYPE_INITIALIZED_TO_DEFAULT) 8 | set(CMAKE_BUILD_TYPE Release) 9 | endif () 10 | 11 | project(cometa) 12 | 13 | include_directories(include) 14 | 15 | set(SRC 16 | include/cometa.hpp 17 | include/cident.h 18 | include/cometa/string.hpp 19 | ) 20 | 21 | add_compile_options(-std=c++1y -Wall -fno-exceptions -fno-rtti) 22 | 23 | add_executable(cometa_test tests/cometa_test.cpp ${SRC}) 24 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | UseTab: Never 2 | IndentWidth: 4 3 | Language : Cpp 4 | BreakBeforeBraces: Allman 5 | MaxEmptyLinesToKeep: 1 6 | IndentCaseLabels: false 7 | NamespaceIndentation: None 8 | AccessModifierOffset: -4 9 | SpacesInParentheses: false 10 | SpaceInEmptyParentheses: false 11 | SpacesInCStyleCastParentheses: false 12 | PointerAlignment: Left 13 | Cpp11BracedListStyle: false 14 | AllowShortIfStatementsOnASingleLine: false 15 | AllowShortFunctionsOnASingleLine : true 16 | AlignOperands: true 17 | Standard: Cpp11 18 | IndentCaseLabels: false 19 | AlignTrailingComments : false 20 | ConstructorInitializerAllOnOneLineOrOnePerLine : false 21 | ColumnLimit: 110 22 | BinPackParameters : true 23 | BinPackArguments : true 24 | AlwaysBreakTemplateDeclarations : true 25 | AlignConsecutiveAssignments : true 26 | PenaltyReturnTypeOnItsOwnLine: 50000 27 | CommentPragmas: '^ >>>' 28 | -------------------------------------------------------------------------------- /format-all.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | 4 | import fnmatch 5 | import os 6 | import subprocess 7 | import sys 8 | import glob 9 | 10 | path = os.path.dirname(os.path.realpath(__file__)) 11 | 12 | filenames = [] 13 | for root, dirnames, files in os.walk(path, path): 14 | for filename in fnmatch.filter(files, '*.hpp'): 15 | filenames.append(os.path.join(root, filename)) 16 | for filename in fnmatch.filter(files, '*.h'): 17 | filenames.append(os.path.join(root, filename)) 18 | for filename in fnmatch.filter(files, '*.cpp'): 19 | filenames.append(os.path.join(root, filename)) 20 | 21 | for filename in filenames: 22 | print( filename, '...' ) 23 | subprocess.call(['clang-format', '-i', filename]) 24 | # Fix clang-format bug: https://llvm.org/bugs/show_bug.cgi?id=26125 25 | for tmp_file in glob.glob(filename+'*.tmp'): 26 | os.remove(tmp_file) 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CoMeta 2 | 3 | [![Build Status](https://travis-ci.org/kfrlib/cometa.svg?branch=master)](https://travis-ci.org/kfrlib/cometa) 4 | 5 | Lightweight, header-only C++14 metaprogramming library. 6 | Created for [KFR framework](https://github.com/kfrlib/kfr). 7 | 8 | ## Features 9 | 10 | * Pattern matching 11 | * Compile-time arrays 12 | * Compile-time type information (CTTI) 13 | * Compile-time string manipulation 14 | * Compile-time operations on arrays and numbers 15 | * 'value-or-errorcode' union-like type 16 | * type for passing named arguments 17 | * function wrapper (lightweight replacement for std::function) 18 | * Useful constexpr functions and many more. 19 | 20 | ## Platform 21 | 22 | CoMeta is platform-independent but modern C++14 compiler is required. 23 | 24 | * AppleClang (XCode 7, 8) 25 | * Clang 3.7 or newer 26 | * GCC 5.1 or newer 27 | 28 | ## Tests 29 | 30 | See `tests/cometa_test.cpp` 31 | 32 | ## License 33 | MIT 34 | 35 | See LICENSE for details 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | 31 | # CMake files 32 | CMakeCache.txt 33 | CMakeFiles 34 | CMakeScripts 35 | Makefile 36 | cmake_install.cmake 37 | install_manifest.txt 38 | CTestTestfile.cmake 39 | 40 | # build directory 41 | build/ 42 | 43 | # test directory 44 | svg/ 45 | 46 | # Byte-compiled / optimized / DLL files 47 | __pycache__/ 48 | *.py[cod] 49 | *$py.class 50 | 51 | # Distribution / packaging 52 | .Python 53 | env/ 54 | build/ 55 | develop-eggs/ 56 | dist/ 57 | downloads/ 58 | eggs/ 59 | .eggs/ 60 | lib/ 61 | lib64/ 62 | parts/ 63 | sdist/ 64 | var/ 65 | *.egg-info/ 66 | .installed.cfg 67 | *.egg 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # CLion 73 | .idea/ 74 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | language: cpp 4 | 5 | matrix: 6 | include: 7 | - compiler: gcc 8 | addons: 9 | apt: 10 | sources: 11 | - ubuntu-toolchain-r-test 12 | packages: 13 | - g++-5 14 | env: COMPILER=g++-5 15 | - compiler: clang 16 | addons: 17 | apt: 18 | sources: 19 | - ubuntu-toolchain-r-test 20 | - llvm-toolchain-precise-3.7 21 | packages: 22 | - g++-5 23 | - clang-3.7 24 | env: COMPILER=clang++-3.7 25 | - compiler: clang 26 | addons: 27 | apt: 28 | sources: 29 | - ubuntu-toolchain-r-test 30 | - llvm-toolchain-precise-3.8 31 | packages: 32 | - g++-5 33 | - clang-3.8 34 | env: COMPILER=clang++-3.8 35 | 36 | before_install: 37 | - sudo apt-get update -qq 38 | script: 39 | - mkdir build 40 | - cd build 41 | - cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_BUILD_TYPE=Release .. && make 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/cometa_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace cometa; 5 | 6 | struct struct1 7 | { 8 | }; 9 | struct struct2 10 | { 11 | constexpr operator int() const { return 0; } 12 | }; 13 | 14 | enum enum1 15 | { 16 | }; 17 | enum class enumclass1 18 | { 19 | }; 20 | 21 | void func1() {} 22 | void func1(int) {} 23 | void func1(bool, float) {} 24 | 25 | CMT_FN(func1) 26 | 27 | struct struct3 28 | { 29 | int array[4]; 30 | }; 31 | 32 | void func(const struct3& s3) 33 | { 34 | constexpr size_t size = CMT_ARRAYSIZE(s3.array); 35 | static_assert(size == 4, ""); 36 | } 37 | 38 | int& ref_fn(int& x) { return x; } 39 | 40 | int main(int, char**) 41 | { 42 | static_assert(is_poweroftwo(1), ""); 43 | static_assert(is_poweroftwo(2), ""); 44 | static_assert(!is_poweroftwo(3), ""); 45 | static_assert(is_poweroftwo(4), ""); 46 | 47 | static_assert(gcd(6, 10) == 2, ""); 48 | static_assert(lcm(6, 10) == 30, ""); 49 | 50 | static_assert(next_poweroftwo(0) == 0, ""); 51 | static_assert(next_poweroftwo(1) == 1, ""); 52 | static_assert(next_poweroftwo(2) == 2, ""); 53 | static_assert(next_poweroftwo(3) == 4, ""); 54 | 55 | static_assert(prev_poweroftwo(0) == 0, ""); 56 | static_assert(prev_poweroftwo(1) == 1, ""); 57 | static_assert(prev_poweroftwo(2) == 2, ""); 58 | static_assert(prev_poweroftwo(3) == 2, ""); 59 | 60 | static_assert(ilog2(0) == 0, ""); 61 | static_assert(ilog2(1) == 0, ""); 62 | static_assert(ilog2(2) == 1, ""); 63 | static_assert(ilog2(3) == 1, ""); 64 | static_assert(ilog2(4) == 2, ""); 65 | 66 | static_assert(is_number::value, ""); 67 | static_assert(is_number::value, ""); 68 | static_assert(is_number::value, ""); 69 | static_assert(is_number::value, ""); 70 | static_assert(is_number::value, ""); 71 | static_assert(is_number::value, ""); 72 | static_assert(is_number::value, ""); 73 | static_assert(!is_number::value, ""); 74 | static_assert(!is_number::value, ""); 75 | static_assert(!is_number::value, ""); 76 | 77 | static_assert(is_callable::value, ""); 78 | static_assert(is_callable::value, ""); 79 | static_assert(is_callable::value, ""); 80 | static_assert(is_callable::value, ""); 81 | static_assert(is_callable::value, ""); 82 | static_assert(!is_callable::value, ""); 83 | static_assert(!is_callable::value, ""); 84 | static_assert(!is_callable::value, ""); 85 | 86 | static_assert(ctypeid() == ctypeid(), ""); 87 | static_assert(ctypeid() == ctypeid(), ""); 88 | 89 | static_assert(details::strlen("hello") == 5, ""); 90 | static_assert(make_cstring("abc") == make_cstring("abc"), ""); 91 | static_assert(ctype_name() == ctype_name(), ""); 92 | static_assert(ctype_name() != ctype_name(), ""); 93 | 94 | { 95 | function fn = ref_fn; 96 | 97 | int x; 98 | int& y = ref_fn(x); 99 | int& z = fn(x); 100 | (void)y; 101 | (void)z; 102 | function empty_fn; 103 | int d; 104 | int& a = fn.call(d, x); 105 | (void)a; 106 | } 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /include/cident.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 D Levin (http://www.kfrlib.com) 3 | * This file is part of CoMeta (C++14 metaprogramming library created for KFR framework) 4 | * License: MIT 5 | */ 6 | 7 | #pragma once 8 | 9 | #ifdef LIBC_WORKAROUND_GETS 10 | extern char* gets(char* __s); 11 | #endif 12 | 13 | #if defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__x86_64__) 14 | #define CMT_ARCH_X86 1 15 | #elif defined(__arm__) || defined(__arm64__) || defined(_M_ARM) || defined(__aarch64__) 16 | #define CMT_ARCH_ARM 1 17 | #endif 18 | 19 | #ifdef CMT_ARCH_X86 20 | #if defined(_M_X64) || defined(__x86_64__) 21 | #define CMT_ARCH_X64 1 22 | #else 23 | #define CMT_ARCH_X32 1 24 | #endif 25 | 26 | #if defined __AVX512F__ && !defined CMT_ARCH_AVX512 27 | #define CMT_ARCH_AVX512 1 28 | #define CMT_ARCH_AVX2 1 29 | #define CMT_ARCH_AVX 1 30 | #define CMT_ARCH_SSE42 1 31 | #define CMT_ARCH_SSE41 1 32 | #define CMT_ARCH_SSSE3 1 33 | #define CMT_ARCH_SSE3 1 34 | #define CMT_ARCH_SSE2 1 35 | #define CMT_ARCH_SSE 1 36 | #endif 37 | #if defined __AVX2__ && !defined CMT_ARCH_AVX2 38 | #define CMT_ARCH_AVX2 1 39 | #define CMT_ARCH_AVX 1 40 | #define CMT_ARCH_SSE42 1 41 | #define CMT_ARCH_SSE41 1 42 | #define CMT_ARCH_SSSE3 1 43 | #define CMT_ARCH_SSE3 1 44 | #define CMT_ARCH_SSE2 1 45 | #define CMT_ARCH_SSE 1 46 | #endif 47 | #if defined __AVX__ && !defined CMT_ARCH_AVX 48 | #define CMT_ARCH_AVX 1 49 | #define CMT_ARCH_SSE42 1 50 | #define CMT_ARCH_SSE41 1 51 | #define CMT_ARCH_SSSE3 1 52 | #define CMT_ARCH_SSE3 1 53 | #define CMT_ARCH_SSE2 1 54 | #define CMT_ARCH_SSE 1 55 | #endif 56 | #if defined __SSE4_2__ && !defined CMT_ARCH_SSE4_2 57 | #define CMT_ARCH_SSE4_2 1 58 | #define CMT_ARCH_SSE41 1 59 | #define CMT_ARCH_SSSE3 1 60 | #define CMT_ARCH_SSE3 1 61 | #define CMT_ARCH_SSE2 1 62 | #define CMT_ARCH_SSE 1 63 | #endif 64 | #if defined __SSE4_1__ && !defined CMT_ARCH_SSE4_1 65 | #define CMT_ARCH_SSE4_1 1 66 | #define CMT_ARCH_SSSE3 1 67 | #define CMT_ARCH_SSE3 1 68 | #define CMT_ARCH_SSE2 1 69 | #define CMT_ARCH_SSE 1 70 | #endif 71 | #if defined __SSSE3__ && !defined CMT_ARCH_SSSE3 72 | #define CMT_ARCH_SSSE3 1 73 | #define CMT_ARCH_SSE3 1 74 | #define CMT_ARCH_SSE2 1 75 | #define CMT_ARCH_SSE 1 76 | #endif 77 | #if defined __SSE3__ && !defined CMT_ARCH_SSE3 78 | #define CMT_ARCH_SSE3 1 79 | #define CMT_ARCH_SSE2 1 80 | #define CMT_ARCH_SSE 1 81 | #endif 82 | #if (defined CMT_ARCH_X64 || defined __SSE2__) && !defined CMT_ARCH_SSE2 83 | #define CMT_ARCH_SSE2 1 84 | #define CMT_ARCH_SSE 1 85 | #endif 86 | 87 | #if (defined CMT_ARCH_X64 || defined __SSE__) && !defined CMT_ARCH_SSE1 88 | #define CMT_ARCH_SSE 1 89 | #endif 90 | 91 | #if defined __FMA__ && !defined CMT_ARCH_FMA 92 | #define CMT_ARCH_FMA 1 93 | #endif 94 | 95 | #if defined __AES__ && !defined CMT_ARCH_AES 96 | #define CMT_ARCH_AES 1 97 | #endif 98 | 99 | #if defined __BMI__ && !defined CMT_ARCH_BMI 100 | #define CMT_ARCH_BMI 1 101 | #endif 102 | 103 | #if defined __BMI2__ && !defined CMT_ARCH_BMI2 104 | #define CMT_ARCH_BMI2 1 105 | #endif 106 | 107 | #if defined __LZCNT__ && !defined CMT_ARCH_LZCNT 108 | #define CMT_ARCH_LZCNT 1 109 | #endif 110 | 111 | #if defined CMT_ARCH_AVX512 112 | #define CMT_ARCH_NAME avx512 113 | #elif defined CMT_ARCH_AVX2 114 | #define CMT_ARCH_NAME avx2 115 | #elif defined CMT_ARCH_AVX 116 | #define CMT_ARCH_NAME avx 117 | #elif defined CMT_ARCH_SSE4_1 118 | #define CMT_ARCH_NAME sse41 119 | #elif defined CMT_ARCH_SSSE3 120 | #define CMT_ARCH_NAME ssse3 121 | #elif defined CMT_ARCH_SSE3 122 | #define CMT_ARCH_NAME sse3 123 | #elif defined CMT_ARCH_SSE2 124 | #define CMT_ARCH_NAME sse2 125 | #elif defined CMT_ARCH_SSE 126 | #define CMT_ARCH_NAME sse 127 | #endif 128 | 129 | #elif defined(CMT_ARCH_ARM) 130 | 131 | #if defined(__aarch64__) 132 | #define CMT_ARCH_X64 1 133 | #else 134 | #define CMT_ARCH_X32 1 135 | #endif 136 | 137 | #ifdef __ARM_NEON__ 138 | 139 | #if __ARM_ARCH >= 8 && defined(__aarch64__) 140 | #define CMT_ARCH_NEON64 1 141 | #define CMT_ARCH_NEON 1 142 | #define CMT_ARCH_NAME neon64 143 | #else 144 | #define CMT_ARCH_NEON 1 145 | #define CMT_ARCH_NAME neon 146 | #define KFR_NO_NATIVE_F64 1 147 | #endif 148 | #endif 149 | 150 | #endif 151 | 152 | #ifndef CMT_ARCH_NAME 153 | #define CMT_ARCH_NAME common 154 | #endif 155 | 156 | #ifndef KFR_NO_NATIVE_F64 157 | #define KFR_NATIVE_F64 1 158 | #endif 159 | 160 | #ifndef KFR_NO_NATIVE_I64 161 | #define KFR_NATIVE_I64 1 162 | #endif 163 | 164 | #define CMT_STRINGIFY2(x) #x 165 | #define CMT_STRINGIFY(x) CMT_STRINGIFY2(x) 166 | 167 | #if defined(_WIN32) // Windows 168 | #define CMT_OS_WIN 1 169 | #endif 170 | 171 | #if defined(__APPLE__) 172 | #include "TargetConditionals.h" 173 | #ifdef TARGET_OS_IPHONE 174 | #define CMT_OS_IOS 1 175 | #define CMT_OS_MOBILE 1 176 | #elif TARGET_IPHONE_SIMULATOR 177 | #define CMT_OS_IOS 1 178 | #define CMT_OS_IOS_SIMULATOR 1 179 | #define CMT_OS_MOBILE 1 180 | #elif TARGET_OS_MAC 181 | #define CMT_OS_MAC 1 182 | #define CMT_OS_MACOS 1 183 | #define CMT_OS_OSX 1 184 | #endif 185 | #define CMT_OS_POSIX 1 186 | #endif 187 | 188 | #if defined(__ANDROID__) 189 | #define CMT_OS_ANDROID 1 190 | #define CMT_OS_MOBILE 1 191 | #define CMT_OS_POSIX 1 192 | #endif 193 | 194 | #if defined(__linux__) 195 | #define CMT_OS_LINUX 1 196 | #define CMT_OS_POSIX 1 197 | #endif 198 | 199 | #if defined(_MSC_VER) // Visual C/C++ 200 | #define CMT_COMPILER_MSVC 1 201 | #define CMT_MSVC_ATTRIBUTES 1 202 | #define CMT_MSC_VER _MSC_VER 203 | #else 204 | #define CMT_MSC_VER 0 205 | #endif 206 | 207 | #if defined(__GNUC__) || defined(__clang__) // GCC, Clang 208 | #define CMT_COMPILER_GNU 1 209 | #define CMT_GNU_ATTRIBUTES 1 210 | #define CMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) 211 | #if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ 212 | #define CMT_HAS_GXX_CXX11 1 213 | #endif 214 | #else 215 | #define CMT_GCC_VERSION 0 216 | #endif 217 | 218 | #if defined(__INTEL_COMPILER) // Intel Compiler 219 | #define CMT_COMPILER_INTEL 1 220 | #define CMT_ICC_VERSION __INTEL_COMPILER 221 | #elif defined(__ICL) 222 | #define CMT_COMPILER_INTEL 1 223 | #define CMT_ICC_VERSION __ICL 224 | #else 225 | #define CMT_ICC_VERSION 0 226 | #endif 227 | 228 | #if defined(__clang__) // Clang 229 | #define CMT_COMPILER_CLANG 1 230 | #ifndef CMT_GNU_ATTRIBUTES 231 | #define CMT_GNU_ATTRIBUTES 1 232 | #endif 233 | #endif 234 | 235 | #if defined(CMT_GNU_ATTRIBUTES) 236 | 237 | #define CMT_NODEBUG 238 | // __attribute__((__nodebug__)) 239 | #ifdef NDEBUG 240 | #define CMT_ALWAYS_INLINE __attribute__((__always_inline__)) 241 | #else 242 | #define CMT_ALWAYS_INLINE 243 | #endif 244 | #define CMT_INLINE __inline__ CMT_ALWAYS_INLINE 245 | #define CMT_INTRIN CMT_INLINE CMT_NODEBUG 246 | #define CMT_INLINE_MEMBER CMT_ALWAYS_INLINE 247 | #define CMT_INLINE_LAMBDA CMT_INLINE_MEMBER 248 | #define CMT_NOINLINE __attribute__((__noinline__)) 249 | #define CMT_FLATTEN __attribute__((__flatten__)) 250 | #define CMT_RESTRICT __restrict__ 251 | 252 | #elif defined(CMT_MSVC_ATTRIBUTES) 253 | 254 | #define CMT_NODEBUG 255 | #define CMT_INLINE inline __forceinline 256 | #define CMT_INTRIN CMT_INLINE CMT_NODEBUG 257 | #define CMT_INLINE_MEMBER __forceinline 258 | #define CMT_INLINE_LAMBDA 259 | #define CMT_NOINLINE __declspec(noinline) 260 | #define CMT_FLATTEN 261 | #define CMT_RESTRICT __restrict 262 | 263 | #endif 264 | 265 | #define CMT_INLINE_STATIC CMT_INLINE static 266 | 267 | #define CMT_EXTERN_C extern "C" 268 | 269 | #define CMT_PUBLIC_C CMT_EXTERN_C CMT_NOINLINE 270 | 271 | #define CMT_ALWAYS_INLINE_STATIC CMT_ALWAYS_INLINE static 272 | 273 | #ifdef CMT_ARCH_x86 274 | #ifdef CMT_OS_WIN 275 | #define CMT_CDECL __cdecl 276 | #else 277 | #define CMT_CDECL __attribute__((cdecl)) 278 | #endif 279 | #else 280 | #define CMT_CDECL 281 | #endif 282 | 283 | #ifdef CMT_OS_WIN 284 | #if defined(CMT_MSVC_ATTRIBUTES) 285 | #define CMT_DLL_EXPORT __declspec(dllexport) 286 | #define CMT_DLL_IMPORT __declspec(dllimport) 287 | #else 288 | #define CMT_DLL_EXPORT __attribute__((dllexport)) 289 | #define CMT_DLL_IMPORT __attribute__((dllimport)) 290 | #endif 291 | #else 292 | #define CMT_DLL_EXPORT 293 | #define CMT_DLL_IMPORT 294 | #endif 295 | 296 | #ifdef __has_builtin 297 | #define CMT_HAS_BUILTIN(builtin) __has_builtin(builtin) 298 | #else 299 | #define CMT_HAS_BUILTIN(builtin) 0 300 | #endif 301 | 302 | #if CMT_HAS_BUILTIN(CMT_ASSUME) 303 | #define CMT_ASSUME(x) __builtin_assume(x) 304 | #else 305 | #define CMT_ASSUME(x) \ 306 | do \ 307 | { \ 308 | } while (0) 309 | #endif 310 | 311 | #if CMT_HAS_BUILTIN(CMT_ASSUME) 312 | #define CMT_ASSUME_ALIGNED(x, a) __builtin_assume_aligned(x, a) 313 | #else 314 | #define CMT_ASSUME_ALIGNED(x, a) x 315 | #endif 316 | 317 | #ifdef __has_feature 318 | #define CMT_HAS_FEATURE(feature) __has_feature(feature) 319 | #else 320 | #define CMT_HAS_FEATURE(feature) 0 321 | #endif 322 | 323 | #ifdef __has_extension 324 | #define CMT_HAS_EXTENSION(extension) __has_extension(extension) 325 | #else 326 | #define CMT_HAS_EXTENSION(extension) 0 327 | #endif 328 | 329 | #ifdef __has_attribute 330 | #define CMT_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) 331 | #else 332 | #define CMT_HAS_ATTRIBUTE(attribute) 0 333 | #endif 334 | 335 | #ifdef __has_warning 336 | #define CMT_HAS_WARNING(warning) __has_warning(warning) 337 | #else 338 | #define CMT_HAS_WARNING(warning) 0 339 | #endif 340 | 341 | #define CMT_HAS_VARIADIC_TEMPLATES \ 342 | (CMT_HAS_FEATURE(cxx_variadic_templates) || (CMT_GCC_VERSION >= 404 && CMT_HAS_GXX_CXX11) || \ 343 | CMT_MSC_VER >= 1800) 344 | 345 | #ifdef CMT_BUILDING_DLL 346 | #define CMT_C_API CMT_DLL_EXPORT 347 | #else 348 | #define CMT_C_API CMT_DLL_IMPORT 349 | #endif 350 | 351 | #if __cplusplus >= 201103L || CMT_MSC_VER >= 1900 || CMT_HAS_FEATURE(cxx_constexpr) 352 | #define CMT_HAS_CONSTEXPR 1 353 | #endif 354 | 355 | #if __cpp_constexpr >= 201304 || CMT_HAS_FEATURE(cxx_constexpr) 356 | #define CMT_HAS_FULL_CONSTEXPR 1 357 | #endif 358 | 359 | #if CMT_HAS_CONSTEXPR 360 | #define CMT_CONSTEXPR constexpr 361 | #else 362 | #define CMT_CONSTEXPR 363 | #endif 364 | 365 | #if CMT_HAS_FEATURE(cxx_noexcept) || (CMT_GCC_VERSION >= 408 && CMT_HAS_GXX_CXX11) || CMT_MSC_VER >= 1900 366 | #define CMT_HAS_NOEXCEPT 1 367 | #endif 368 | 369 | #if CMT_HAS_NOEXCEPT 370 | #define CMT_NOEXCEPT noexcept 371 | #else 372 | #define CMT_NOEXCEPT 373 | #endif 374 | 375 | #if CMT_COMPILER_GNU && !defined(__EXCEPTIONS) 376 | #define CMT_HAS_EXCEPTIONS 0 377 | #endif 378 | #if CMT_COMPILER_MSVC && !_HAS_EXCEPTIONS 379 | #define CMT_HAS_EXCEPTIONS 0 380 | #endif 381 | 382 | #ifndef CMT_HAS_EXCEPTIONS 383 | #define CMT_HAS_EXCEPTIONS 1 384 | #endif 385 | 386 | #if __has_include() 387 | #include 388 | #define CMT_HAS_ASSERT_H 1 389 | #endif 390 | 391 | #ifndef CMT_THROW 392 | #if CMT_HAS_EXCEPTIONS 393 | #define CMT_THROW(x) throw x 394 | #else 395 | #ifdef CMT_HAS_ASSERT_H 396 | #define CMT_THROW(x) assert(false) 397 | #else 398 | #define CMT_THROW(x) abort() 399 | #endif 400 | #endif 401 | #endif 402 | 403 | #ifdef CMT_COMPILER_MSVC 404 | #define CMT_FUNC_SIGNATURE __FUNCSIG__ 405 | #else 406 | #define CMT_FUNC_SIGNATURE __PRETTY_FUNCTION__ 407 | #endif 408 | 409 | #if CMT_COMPILER_CLANG 410 | #define CMT_LOOP_NOUNROLL \ 411 | _Pragma("clang loop vectorize( disable )") _Pragma("clang loop interleave( disable )") \ 412 | _Pragma("clang loop unroll( disable )") 413 | 414 | #define CMT_LOOP_UNROLL _Pragma("clang loop unroll( full )") 415 | #define CMT_VEC_CC __attribute__((vectorcall)) 416 | #else 417 | #define CMT_LOOP_NOUNROLL 418 | #define CMT_LOOP_UNROLL 419 | #ifdef CMT_COMPILER_MSVC 420 | #define CMT_VEC_CC __vectorcall 421 | #endif 422 | #endif 423 | 424 | #if defined(CMT_GNU_ATTRIBUTES) 425 | #define CMT_FAST_CC __attribute__((fastcall)) 426 | #else 427 | #define CMT_FAST_CC __fastcall 428 | #endif 429 | -------------------------------------------------------------------------------- /include/cometa/string.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 D Levin (http://www.kfrlib.com) 3 | * This file is part of CoMeta (C++14 metaprogramming library created for KFR framework) 4 | * License: MIT 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../cometa.hpp" 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #pragma GCC diagnostic push 16 | #if CMT_HAS_WARNING("-Wformat-security") 17 | #pragma GCC diagnostic ignored "-Wformat-security" 18 | #pragma GCC diagnostic ignored "-Wused-but-marked-unused" 19 | #endif 20 | 21 | namespace cometa 22 | { 23 | 24 | template 25 | CMT_INLINE std::string as_string(const Args&... args); 26 | 27 | template 28 | constexpr inline const T& repr(const T& value) 29 | { 30 | return value; 31 | } 32 | 33 | template 34 | inline std::string repr(const named_arg& value) 35 | { 36 | return std::string(value.name) + " = " + as_string(value.value); 37 | } 38 | 39 | template 40 | inline std::string repr(const std::pair& value) 41 | { 42 | return "(" + as_string(value.first) + "; " + as_string(value.second) + ")"; 43 | } 44 | 45 | template 46 | using repr_type = decay()))>; 47 | 48 | namespace details 49 | { 50 | template (-1), int width = -1, int prec = -1> 51 | struct fmt_t 52 | { 53 | const T& value; 54 | }; 55 | 56 | template = 0 && number < 10)> 57 | constexpr cstring<2> itoa() 58 | { 59 | return cstring<2>{ { static_cast(number + '0'), 0 } }; 60 | } 61 | template = 10)> 62 | constexpr auto itoa() 63 | { 64 | return concat_cstring(itoa(), itoa()); 65 | } 66 | template 67 | constexpr auto itoa() 68 | { 69 | return concat_cstring(make_cstring("-"), itoa<-number>()); 70 | } 71 | 72 | template = 0)> 73 | CMT_INLINE constexpr auto value_fmt_arg(ctype_t>) 74 | { 75 | return concat_cstring(make_cstring("%."), itoa()); 76 | } 77 | template = 0 && prec < 0)> 78 | CMT_INLINE constexpr auto value_fmt_arg(ctype_t>) 79 | { 80 | return itoa(); 81 | } 82 | template 83 | CMT_INLINE constexpr auto value_fmt_arg(ctype_t>) 84 | { 85 | return make_cstring(""); 86 | } 87 | template = 0 && prec >= 0)> 88 | CMT_INLINE constexpr auto value_fmt_arg(ctype_t>) 89 | { 90 | return concat_cstring(itoa(), make_cstring("."), itoa()); 91 | } 92 | 93 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%s"); } 94 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%s"); } 95 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%d"); } 96 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%d"); } 97 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%d"); } 98 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%d"); } 99 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%d"); } 100 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%d"); } 101 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%ld"); } 102 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%lld"); } 103 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%u"); } 104 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%lu"); } 105 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%llu"); } 106 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%g"); } 107 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%g"); } 108 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%Lg"); } 109 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%s"); } 110 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%s"); } 111 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%p"); } 112 | CMT_INLINE constexpr auto value_fmt(ctype_t) { return make_cstring("%p"); } 113 | 114 | template 115 | CMT_INLINE constexpr auto value_fmt(ctype_t>) 116 | { 117 | return concat_cstring(make_cstring("%s"), make_cstring(cchars)); 118 | } 119 | 120 | template 121 | CMT_INLINE constexpr auto value_fmt(ctype_t>) 122 | { 123 | return make_cstring("%s"); 124 | } 125 | 126 | template 127 | CMT_INLINE constexpr auto value_fmt(ctype_t(-1), width, prec>> fmt) 128 | { 129 | return concat_cstring(make_cstring("%"), value_fmt_arg(fmt), value_fmt(ctype>)); 130 | } 131 | template 132 | CMT_INLINE constexpr auto value_fmt(ctype_t> fmt) 133 | { 134 | return concat_cstring(make_cstring("%"), value_fmt_arg(fmt), cstring<2>{ { t, 0 } }); 135 | } 136 | 137 | template 138 | CMT_INLINE const char* pack_value(const cchars_t&) 139 | { 140 | return ""; 141 | } 142 | 143 | template 144 | CMT_INLINE const Arg& pack_value(const Arg& value) 145 | { 146 | return value; 147 | } 148 | CMT_INLINE double pack_value(float value) { return static_cast(value); } 149 | CMT_INLINE auto pack_value(bool value) { return value ? "true" : "false"; } 150 | CMT_INLINE auto pack_value(const std::string& value) { return value.c_str(); } 151 | 152 | template 153 | CMT_INLINE const char* pack_value(ctype_t) 154 | { 155 | return type_name(); 156 | } 157 | 158 | template 159 | CMT_INLINE auto pack_value(const fmt_t& value) 160 | { 161 | return pack_value(repr(value.value)); 162 | } 163 | 164 | template 165 | CMT_INLINE constexpr cstring fmt_replace_impl(const cstring& str, 166 | const cstring& newfmt, 167 | csizes_t) 168 | { 169 | size_t start = 0; 170 | size_t end = 0; 171 | cstring result; 172 | for (size_t i = 0; i < N1; i++) 173 | { 174 | if (str[i] == '{') 175 | start = i; 176 | else if (str[i] == '}') 177 | end = i; 178 | } 179 | 180 | if (end - start == 1) // {} 181 | { 182 | for (size_t i = 0; i < N1; i++) 183 | { 184 | if (i < start) 185 | result[i] = str[i]; 186 | else if (i == start) 187 | result[i] = '%'; 188 | else if (i > start && i - start - 1 < Nnew - 1) 189 | result[i] = newfmt[i - start - 1]; 190 | else if (i - Nnew + 3 < N1 - 1) 191 | result[i] = str[i - Nnew + 3]; 192 | else 193 | result[i] = 0; 194 | } 195 | } 196 | return result; 197 | } 198 | 199 | template 200 | CMT_INLINE constexpr cstring fmt_replace(const cstring& str, const cstring& newfmt) 201 | { 202 | return fmt_replace_impl(str, newfmt, csizeseq); 203 | } 204 | 205 | inline std::string replace_one(const std::string& str, const std::string& from, const std::string& to) 206 | { 207 | std::string r = str; 208 | size_t start_pos = 0; 209 | if ((start_pos = r.find(from, start_pos)) != std::string::npos) 210 | { 211 | r.replace(start_pos, from.size(), to); 212 | } 213 | return r; 214 | } 215 | 216 | CMT_INLINE const std::string& build_fmt(const std::string& str, ctypes_t<>) { return str; } 217 | 218 | template 219 | CMT_INLINE auto build_fmt(const std::string& str, ctypes_t) 220 | { 221 | constexpr auto fmt = value_fmt(ctype>); 222 | return build_fmt(replace_one(str, "{}", std::string(fmt.data())), ctypes); 223 | } 224 | } 225 | 226 | template 227 | CMT_INLINE details::fmt_t fmt(const T& value) 228 | { 229 | return { value }; 230 | } 231 | 232 | template 233 | CMT_INLINE details::fmt_t(-1), width, prec> fmtwidth(const T& value) 234 | { 235 | return { value }; 236 | } 237 | 238 | #pragma GCC diagnostic push 239 | #pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template" 240 | 241 | constexpr auto build_fmt_str(cchars_t<>, ctypes_t<>) { return make_cstring(""); } 242 | 243 | template 244 | constexpr auto build_fmt_str(cchars_t<'@', chars...>, ctypes_t) 245 | { 246 | return concat_cstring(details::value_fmt(ctype>), 247 | build_fmt_str(cchars, ctypes)); 248 | } 249 | 250 | template 251 | constexpr auto build_fmt_str(cchars_t, ctypes_t) 252 | { 253 | return concat_cstring(make_cstring(cchars), build_fmt_str(cchars, ctypes)); 254 | } 255 | 256 | template 257 | struct format_t 258 | { 259 | template 260 | inline std::string operator()(const Args&... args) 261 | { 262 | constexpr auto format_str = build_fmt_str(cchars, ctypes...>); 263 | 264 | std::string result; 265 | const int size = std::snprintf(nullptr, 0, format_str.data(), details::pack_value(args)...); 266 | if (size <= 0) 267 | return result; 268 | result.resize(size_t(size + 1)); 269 | result.resize(size_t(std::snprintf(&result[0], size_t(size + 1), format_str.data(), 270 | details::pack_value(repr(args))...))); 271 | return result; 272 | } 273 | }; 274 | 275 | template 276 | struct print_t 277 | { 278 | template 279 | CMT_INLINE void operator()(const Args&... args) 280 | { 281 | constexpr auto format_str = build_fmt_str(cchars, ctypes...>); 282 | 283 | std::printf(format_str.data(), details::pack_value(args)...); 284 | } 285 | }; 286 | 287 | template 288 | constexpr format_t operator""_format() 289 | { 290 | return {}; 291 | } 292 | 293 | template 294 | constexpr CMT_INLINE print_t operator""_print() 295 | { 296 | return {}; 297 | } 298 | 299 | #pragma GCC diagnostic pop 300 | 301 | template 302 | CMT_INLINE void printfmt(const std::string& fmt, const Args&... args) 303 | { 304 | const auto format_str = details::build_fmt(fmt, ctypes...>); 305 | std::printf(format_str.data(), details::pack_value(repr(args))...); 306 | } 307 | 308 | template 309 | CMT_INLINE void fprintfmt(FILE* f, const std::string& fmt, const Args&... args) 310 | { 311 | const auto format_str = details::build_fmt(fmt, ctypes...>); 312 | std::fprintf(f, format_str.data(), details::pack_value(repr(args))...); 313 | } 314 | 315 | template 316 | CMT_INLINE int snprintfmt(char* str, size_t size, const std::string& fmt, const Args&... args) 317 | { 318 | const auto format_str = details::build_fmt(fmt, ctypes...>); 319 | return std::snprintf(str, size, format_str.data(), details::pack_value(repr(args))...); 320 | } 321 | 322 | template 323 | CMT_INLINE std::string format(const std::string& fmt, const Args&... args) 324 | { 325 | std::string result; 326 | const auto format_str = details::build_fmt(fmt, ctypes...>); 327 | const int size = std::snprintf(nullptr, 0, format_str.data(), details::pack_value(repr(args))...); 328 | if (size <= 0) 329 | return result; 330 | result.resize(size_t(size + 1)); 331 | result.resize(size_t( 332 | std::snprintf(&result[0], size_t(size + 1), format_str.data(), details::pack_value(repr(args))...))); 333 | return result; 334 | } 335 | 336 | namespace details 337 | { 338 | template 339 | constexpr auto get_value_fmt() 340 | { 341 | return details::value_fmt(ctype>>); 342 | } 343 | } 344 | 345 | template 346 | CMT_INLINE void print(const Args&... args) 347 | { 348 | constexpr auto format_str = concat_cstring(details::get_value_fmt()...); 349 | std::printf(format_str.data(), details::pack_value(repr(args))...); 350 | } 351 | 352 | template 353 | CMT_INLINE void println(const Args&... args) 354 | { 355 | constexpr auto format_str = concat_cstring(details::get_value_fmt()..., make_cstring("\n")); 356 | std::printf(format_str.data(), details::pack_value(repr(args))...); 357 | } 358 | 359 | template 360 | CMT_INLINE std::string as_string(const Args&... args) 361 | { 362 | std::string result; 363 | constexpr auto format_str = concat_cstring(details::get_value_fmt()...); 364 | 365 | const int size = std::snprintf(nullptr, 0, format_str.data(), details::pack_value(repr(args))...); 366 | if (size <= 0) 367 | return result; 368 | result.resize(size_t(size + 1)); 369 | result.resize(size_t( 370 | std::snprintf(&result[0], size_t(size + 1), format_str.data(), details::pack_value(repr(args))...))); 371 | return result; 372 | } 373 | 374 | inline std::string padright(size_t size, const std::string& text, char character = ' ') 375 | { 376 | const size_t pad = size >= text.size() ? size - text.size() : 0; 377 | return std::string(pad, character) + text; 378 | } 379 | 380 | inline std::string padleft(size_t size, const std::string& text, char character = ' ') 381 | { 382 | const size_t pad = size >= text.size() ? size - text.size() : 0; 383 | return text + std::string(pad, character); 384 | } 385 | 386 | inline std::string padcenter(size_t size, const std::string& text, char character = ' ') 387 | { 388 | const size_t pad = size >= text.size() ? size - text.size() : 0; 389 | return std::string(pad / 2, character) + text + std::string(pad - pad / 2, character); 390 | } 391 | 392 | template 393 | inline std::string q(T x) 394 | { 395 | return "\"" + as_string(std::forward(x)) + "\""; 396 | } 397 | 398 | template 399 | inline std::string join(T x) 400 | { 401 | return as_string(std::forward(x)); 402 | } 403 | 404 | template 405 | inline std::string join(T x, U y, Ts... rest) 406 | { 407 | return format("{}, {}", x, join(std::forward(y), std::forward(rest)...)); 408 | } 409 | } 410 | 411 | #pragma GCC diagnostic pop 412 | -------------------------------------------------------------------------------- /include/cometa.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 D Levin (http://www.kfrlib.com) 3 | * This file is part of CoMeta (C++14 metaprogramming library created for KFR framework) 4 | * License: MIT 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "cident.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #pragma GCC diagnostic push 18 | #pragma GCC diagnostic ignored "-Wshadow" 19 | 20 | namespace cometa 21 | { 22 | 23 | using std::size_t; 24 | using std::ptrdiff_t; 25 | 26 | #if __cplusplus >= 201103L || CMT_MSC_VER >= 1900 || CMT_HAS_FEATURE(cxx_constexpr) 27 | 28 | template 29 | constexpr inline static size_t arraysize(const T (&)[N]) noexcept 30 | { 31 | return N; 32 | } 33 | 34 | template 35 | constexpr inline static std::integral_constant carraysize(const T (&)[N]) noexcept 36 | { 37 | return {}; 38 | } 39 | 40 | #define CMT_ARRAYSIZE(arr) decltype(carraysize(arr))::value 41 | #elif CMT_COMPILER_MSVC 42 | #define CMT_ARRAYSIZE(arr) _countof(arr) 43 | #elif __cplusplus >= 199711L && \ 44 | (defined(__INTEL_COMPILER) || defined(__clang__) || \ 45 | (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)))) 46 | template 47 | char (&COUNTOF_REQUIRES_ARRAY_ARGUMENT(T (&)[N]))[N]; 48 | #define CMT_ARRAYSIZE(x) sizeof(COUNTOF_REQUIRES_ARRAY_ARGUMENT(x)) 49 | #else 50 | #define CMT_ARRAYSIZE(arr) sizeof(arr) / sizeof(arr[0]) 51 | #endif 52 | 53 | using pvoid = void*; 54 | 55 | template 56 | using void_t = void; 57 | 58 | // Workaround for GCC 4.8 59 | template 60 | constexpr const T& const_max(const T& x, const T& y) 61 | { 62 | return x > y ? x : y; 63 | } 64 | template 65 | constexpr const T& const_min(const T& x, const T& y) 66 | { 67 | return x < y ? x : y; 68 | } 69 | 70 | namespace details 71 | { 72 | constexpr inline bool args_or() { return false; } 73 | template 74 | constexpr inline bool args_or(bool x, Ts... rest) 75 | { 76 | return x || args_or(rest...); 77 | } 78 | 79 | constexpr inline bool args_and() { return true; } 80 | template 81 | constexpr inline bool args_and(bool x, Ts... rest) 82 | { 83 | return x && args_and(rest...); 84 | } 85 | 86 | template 87 | struct is_pod_impl : std::false_type 88 | { 89 | }; 90 | 91 | template 92 | struct is_pod_impl> : std::integral_constant 93 | { 94 | }; 95 | } 96 | 97 | template 98 | struct or_t : std::integral_constant 99 | { 100 | }; 101 | 102 | template 103 | struct and_t : std::integral_constant 104 | { 105 | }; 106 | 107 | template 108 | struct not_t : std::integral_constant 109 | { 110 | }; 111 | 112 | constexpr size_t max_size_t = size_t(-1); 113 | 114 | template 115 | using common_type = typename std::common_type::type; 116 | 117 | template 118 | using result_of = typename std::result_of::type; 119 | 120 | template 121 | using enable_if = typename std::enable_if::type; 122 | 123 | template 124 | using conditional = typename std::conditional::type; 125 | 126 | template 127 | using remove_reference = typename std::remove_reference::type; 128 | 129 | template 130 | using remove_cv = typename std::remove_cv::type; 131 | 132 | template 133 | using remove_pointer = typename std::remove_pointer::type; 134 | 135 | template 136 | using remove_extent = typename std::remove_extent::type; 137 | 138 | template 139 | using remove_const = typename std::remove_const::type; 140 | 141 | template 142 | using underlying_type = typename std::underlying_type::type; 143 | 144 | template 145 | using is_pod = or_t, details::is_pod_impl>; 146 | 147 | template 148 | using is_class = std::is_class; 149 | 150 | template 151 | using is_const = std::is_const; 152 | 153 | template 154 | using is_pointer = std::is_pointer; 155 | 156 | template 157 | using is_array = std::is_array; 158 | 159 | template 160 | using is_void = std::is_void; 161 | 162 | template 163 | using is_same = std::is_same; 164 | 165 | template 166 | using is_template_arg = std::integral_constant::value || std::is_enum::value>; 167 | 168 | template 169 | using decay = typename std::decay::type; 170 | 171 | template 172 | using decay_common = decay>; 173 | 174 | template 175 | constexpr size_t typeindex() 176 | { 177 | return is_same() ? 0 : 1 + typeindex(); 178 | } 179 | 180 | template 181 | struct compound_type_traits 182 | { 183 | constexpr static size_t width = 1; 184 | constexpr static size_t deep_width = width; 185 | using subtype = T; 186 | using deep_subtype = T; 187 | constexpr static size_t depth = 0; 188 | constexpr static bool is_scalar = true; 189 | 190 | template 191 | using rebind = U; 192 | template 193 | using deep_rebind = U; 194 | 195 | CMT_INLINE static constexpr const subtype& at(const T& value, size_t /*index*/) { return value; } 196 | }; 197 | 198 | template 199 | using is_compound = std::integral_constant>::is_scalar>; 200 | 201 | template 202 | using subtype = typename compound_type_traits::subtype; 203 | 204 | template 205 | using deep_subtype = typename compound_type_traits::deep_subtype; 206 | 207 | template 208 | using rebind_subtype = typename compound_type_traits::template rebind; 209 | 210 | template 211 | using deep_rebind = typename compound_type_traits::template deep_rebind; 212 | 213 | template 214 | struct compound_type_traits> 215 | { 216 | constexpr static size_t width = 2; 217 | constexpr static size_t deep_width = width * compound_type_traits::width; 218 | using subtype = T; 219 | using deep_subtype = cometa::deep_subtype; 220 | constexpr static bool is_scalar = false; 221 | constexpr static size_t depth = cometa::compound_type_traits::depth + 1; 222 | 223 | template 224 | using rebind = std::pair; 225 | template 226 | using deep_rebind = std::pair, cometa::deep_rebind>; 227 | 228 | CMT_INLINE static constexpr const subtype& at(const std::pair& value, size_t index) 229 | { 230 | return index == 0 ? value.first : value.second; 231 | } 232 | }; 233 | 234 | namespace ops 235 | { 236 | struct empty 237 | { 238 | }; 239 | } 240 | 241 | template 242 | struct cval_t : ops::empty 243 | { 244 | constexpr static T value = val; 245 | constexpr cval_t() noexcept = default; 246 | constexpr cval_t(const cval_t&) noexcept = default; 247 | constexpr cval_t(cval_t&&) noexcept = default; 248 | typedef T value_type; 249 | typedef cval_t type; 250 | constexpr operator value_type() const { return value; } 251 | constexpr value_type operator()() const { return value; } 252 | }; 253 | 254 | template 255 | constexpr inline T val_of(cval_t) 256 | { 257 | return value; 258 | } 259 | 260 | template 261 | constexpr inline T val_of(T value) 262 | { 263 | return value; 264 | } 265 | 266 | template 267 | constexpr inline bool is_constant_val(T) 268 | { 269 | return false; 270 | } 271 | 272 | template 273 | constexpr inline bool is_constant_val(cval_t) 274 | { 275 | return true; 276 | } 277 | 278 | namespace details 279 | { 280 | 281 | template 282 | struct inherit : T 283 | { 284 | }; 285 | 286 | template 287 | struct is_inheritable_impl : std::false_type 288 | { 289 | }; 290 | 291 | template 292 | struct is_inheritable_impl>> : std::true_type 293 | { 294 | }; 295 | 296 | template 297 | struct is_val_impl : std::false_type 298 | { 299 | }; 300 | 301 | template 302 | struct is_val_impl> : std::true_type 303 | { 304 | }; 305 | } 306 | 307 | template 308 | using is_inheritable = typename details::is_inheritable_impl::type; 309 | 310 | template 311 | using is_val_t = typename details::is_val_impl::type; 312 | 313 | template 314 | using cbool_t = cval_t; 315 | 316 | template 317 | using cint_t = cval_t; 318 | 319 | template 320 | using cuint_t = cval_t; 321 | 322 | template 323 | using csize_t = cval_t; 324 | 325 | template 326 | constexpr cval_t cval{}; 327 | 328 | template 329 | constexpr cbool_t cbool{}; 330 | 331 | using cfalse_t = cbool_t; 332 | using ctrue_t = cbool_t; 333 | 334 | constexpr ctrue_t ctrue{}; 335 | constexpr cfalse_t cfalse{}; 336 | 337 | template 338 | constexpr cint_t cint{}; 339 | 340 | template 341 | constexpr cuint_t cuint{}; 342 | 343 | template 344 | constexpr csize_t csize{}; 345 | 346 | namespace details 347 | { 348 | template 349 | struct get_nth : get_nth 350 | { 351 | }; 352 | 353 | template 354 | struct get_nth<0, T, first, rest...> 355 | { 356 | constexpr static T value = first; 357 | }; 358 | 359 | template 360 | struct get_nth_type; 361 | 362 | template 363 | struct get_nth_type : get_nth_type 364 | { 365 | }; 366 | 367 | template 368 | struct get_nth_type<0, first, rest...> 369 | { 370 | using type = first; 371 | }; 372 | 373 | template 374 | struct get_nth_type 375 | { 376 | }; 377 | } 378 | 379 | template 380 | struct cvals_t : ops::empty 381 | { 382 | using type = cvals_t; 383 | constexpr static size_t size() { return sizeof...(values); } 384 | template 385 | constexpr T operator[](csize_t) 386 | { 387 | return get(csize); 388 | } 389 | template 390 | constexpr static T get(csize_t = csize_t()) 391 | { 392 | return details::get_nth::value; 393 | } 394 | constexpr static T front() { return get(csize<0>); } 395 | constexpr static T back() { return get(csize); } 396 | 397 | static const T* begin() { return array(); } 398 | static const T* end() { return array() + size(); } 399 | 400 | static const T* array() 401 | { 402 | static const T arr[] = { values... }; 403 | return &arr[0]; 404 | } 405 | template 406 | constexpr cvals_t::value...> operator[]( 407 | cvals_t) const 408 | { 409 | return {}; 410 | } 411 | }; 412 | 413 | template 414 | struct cvals_t : ops::empty 415 | { 416 | using type = cvals_t; 417 | constexpr static size_t size() { return 0; } 418 | }; 419 | 420 | template 421 | using cbools_t = cvals_t; 422 | 423 | template 424 | using cints_t = cvals_t; 425 | 426 | template 427 | using cchars_t = cvals_t; 428 | 429 | template 430 | using cuints_t = cvals_t; 431 | 432 | template 433 | using csizes_t = cvals_t; 434 | 435 | template 436 | using elements_t = cvals_t; 437 | 438 | template 439 | constexpr cvals_t cvals{}; 440 | 441 | template 442 | constexpr cbools_t cbools{}; 443 | 444 | constexpr cbools_t cfalse_true{}; 445 | 446 | template 447 | constexpr cints_t cints{}; 448 | 449 | template 450 | constexpr cchars_t cchars{}; 451 | 452 | template 453 | constexpr cuints_t cuints{}; 454 | 455 | template 456 | constexpr csizes_t csizes{}; 457 | 458 | template 459 | constexpr elements_t elements{}; 460 | 461 | template 462 | constexpr inline T csum(cvals_t) 463 | { 464 | return 0; 465 | } 466 | 467 | template 468 | constexpr inline T csum(cvals_t) 469 | { 470 | return first + csum(cvals); 471 | } 472 | 473 | template 474 | constexpr inline T cprod(cvals_t) 475 | { 476 | return 1; 477 | } 478 | 479 | template 480 | constexpr inline T cprod(cvals_t) 481 | { 482 | return first * cprod(cvals); 483 | } 484 | 485 | template 486 | struct ctype_t 487 | { 488 | using type = T; 489 | }; 490 | 491 | template 492 | using type_of = typename T::type; 493 | 494 | template 495 | constexpr ctype_t ctype{}; 496 | 497 | template 498 | struct ctypes_t 499 | { 500 | constexpr static size_t size() { return sizeof...(Types); } 501 | 502 | template 503 | using nth = typename details::get_nth_type::type; 504 | 505 | template 506 | constexpr static auto get(csize_t) -> ctype_t> 507 | { 508 | return {}; 509 | } 510 | }; 511 | 512 | template 513 | constexpr ctypes_t ctypes{}; 514 | namespace details 515 | { 516 | template 517 | struct concat_impl; 518 | 519 | template 520 | struct concat_impl, cvals_t> 521 | { 522 | using type = cvals_t; 523 | }; 524 | template 525 | struct concat_impl, ctypes_t> 526 | { 527 | using type = ctypes_t; 528 | }; 529 | } 530 | template 531 | using concat_lists = typename details::concat_impl::type; 532 | 533 | template 534 | constexpr inline concat_lists cconcat(T1, T2) 535 | { 536 | return {}; 537 | } 538 | 539 | namespace details 540 | { 541 | 542 | template 543 | struct function_arguments_impl; 544 | 545 | template 546 | struct function_arguments_impl 547 | { 548 | using result = Ret; 549 | using args = ctypes_t; 550 | }; 551 | 552 | template 553 | struct function_arguments_impl 554 | { 555 | using result = Ret; 556 | using args = ctypes_t; 557 | }; 558 | 559 | template 560 | struct function_arguments_impl 561 | { 562 | using result = Ret; 563 | using args = ctypes_t; 564 | }; 565 | 566 | template 567 | struct filter_impl; 568 | 569 | template 570 | struct filter_impl, cvals_t> 571 | { 572 | using type = cvals_t; 573 | }; 574 | 575 | template 576 | struct filter_impl, cvals_t> 577 | { 578 | using filtered = typename filter_impl, cvals_t>::type; 579 | using type = conditional, filtered>, filtered>; 580 | }; 581 | } 582 | 583 | template 584 | using function_arguments = typename details::function_arguments_impl::args; 585 | 586 | template 587 | using function_result = typename details::function_arguments_impl::result; 588 | 589 | template 590 | using cfilter_t = typename details::filter_impl::type; 591 | 592 | template , cvals_t>> 594 | constexpr inline Ret cfilter(cvals_t, cvals_t) 595 | { 596 | return Ret{}; 597 | } 598 | 599 | #define CMT_UN_OP(op) \ 600 | template ()), (op vals1)...>> \ 602 | constexpr inline Ret operator op(cvals_t) \ 603 | { \ 604 | return Ret{}; \ 605 | } \ 606 | template ()), (op val1)>> \ 607 | constexpr inline Ret operator op(cval_t) \ 608 | { \ 609 | return Ret{}; \ 610 | } 611 | 612 | #define CMT_BIN_OP(op) \ 613 | template () op std::declval()), (vals1 op vals2)...>> \ 616 | constexpr inline Ret operator op(cvals_t, cvals_t) \ 617 | { \ 618 | return Ret{}; \ 619 | } \ 620 | template () op std::declval()), (vals1 op val2)...>> \ 623 | constexpr inline Ret operator op(cvals_t, cval_t) \ 624 | { \ 625 | return Ret{}; \ 626 | } \ 627 | template () op std::declval()), (val1 op vals2)...>> \ 630 | constexpr inline Ret operator op(cval_t, cvals_t) \ 631 | { \ 632 | return Ret{}; \ 633 | } 634 | namespace ops 635 | { 636 | // clang-format off 637 | CMT_UN_OP(-) 638 | CMT_UN_OP(+) 639 | CMT_UN_OP(~) 640 | CMT_UN_OP(!) 641 | 642 | CMT_BIN_OP(&&) 643 | CMT_BIN_OP(||) 644 | CMT_BIN_OP(==) 645 | CMT_BIN_OP(!=) 646 | CMT_BIN_OP(<) 647 | CMT_BIN_OP(>) 648 | CMT_BIN_OP(<=) 649 | CMT_BIN_OP(>=) 650 | CMT_BIN_OP(+) 651 | CMT_BIN_OP(-) 652 | CMT_BIN_OP(*) 653 | CMT_BIN_OP(/) 654 | CMT_BIN_OP(%) 655 | CMT_BIN_OP(<<) 656 | CMT_BIN_OP(>>) 657 | CMT_BIN_OP(&) 658 | CMT_BIN_OP(|) 659 | CMT_BIN_OP(^) 660 | // clang-format on 661 | } 662 | 663 | namespace details 664 | { 665 | template 666 | struct cvalseq_impl; 667 | 668 | template 669 | using cgen_seq = typename cvalseq_impl::type; 670 | 671 | template 672 | struct cvalseq_impl : concat_impl, 673 | cgen_seq> 674 | { 675 | }; 676 | 677 | template 678 | struct cvalseq_impl : cvals_t 679 | { 680 | }; 681 | template 682 | struct cvalseq_impl : cvals_t(Nstart)> 683 | { 684 | }; 685 | } 686 | 687 | template 688 | using cvalseq_t = typename details::cvalseq_impl::type; 689 | 690 | template 691 | constexpr cvalseq_t cvalrange{}; 692 | 693 | template 694 | constexpr cvalseq_t csizerange{}; 695 | 696 | template 697 | constexpr cvalseq_t cintrange{}; 698 | 699 | template 700 | constexpr cvalseq_t cuintrange{}; 701 | 702 | template 703 | constexpr cvalseq_t cvalseq{}; 704 | 705 | template 706 | constexpr cvalseq_t csizeseq{}; 707 | 708 | template 709 | constexpr cvalseq_t cintseq{}; 710 | 711 | template 712 | constexpr cvalseq_t cuintseq{}; 713 | 714 | template 715 | using indicesfor_t = cvalseq_t; 716 | 717 | template 718 | constexpr indicesfor_t indicesfor{}; 719 | 720 | namespace details 721 | { 722 | 723 | template > 724 | struct is_returning_type_impl : std::false_type 725 | { 726 | }; 727 | 728 | template 729 | struct is_returning_type_impl>> 730 | : std::is_same> 731 | { 732 | }; 733 | 734 | template > 735 | struct is_callable_impl : std::false_type 736 | { 737 | }; 738 | 739 | template 740 | struct is_callable_impl, void_t>> : std::true_type 741 | { 742 | }; 743 | 744 | template > 745 | struct is_enabled_impl : std::true_type 746 | { 747 | }; 748 | 749 | template 750 | struct is_enabled_impl> : std::integral_constant 751 | { 752 | }; 753 | 754 | template 755 | struct unique_enum_impl 756 | { 757 | enum class type : size_t 758 | { 759 | value = N 760 | }; 761 | }; 762 | template 763 | using unique_enum = typename unique_enum_impl::type; 764 | 765 | #define CMT_ENABLE_IF_IMPL(N, ...) \ 766 | typename ::std::enable_if<(__VA_ARGS__), ::cometa::details::unique_enum>::type = \ 767 | ::cometa::details::unique_enum::value 768 | 769 | #define CMT_ENABLE_IF(...) CMT_ENABLE_IF_IMPL(__LINE__, __VA_ARGS__) 770 | } 771 | 772 | template 773 | struct is_enabled : details::is_enabled_impl 774 | { 775 | }; 776 | 777 | template 778 | struct is_callable : details::is_callable_impl> 779 | { 780 | }; 781 | 782 | template 783 | struct is_returning_type : details::is_returning_type_impl 784 | { 785 | }; 786 | 787 | namespace details 788 | { 789 | template ())> 790 | inline auto call_if_callable(Fn&& fn) 791 | { 792 | return fn(); 793 | } 794 | 795 | template ())> 796 | inline auto call_if_callable(Fn&& fn) 797 | { 798 | return std::forward(fn); 799 | } 800 | } 801 | 802 | template 803 | inline auto bind_func(Fn&& fn, Args&&... args) 804 | { 805 | return [=]() CMT_INLINE_LAMBDA { return fn(details::call_if_callable(std::forward(args))...); }; 806 | } 807 | 808 | template 809 | constexpr inline bool is_even(T x) 810 | { 811 | return (x % 2) == 0; 812 | } 813 | 814 | template 815 | constexpr inline bool is_odd(T x) 816 | { 817 | return !is_even(x); 818 | } 819 | 820 | template 821 | constexpr inline bool is_poweroftwo(T x) 822 | { 823 | return ((x != 0) && !(x & (x - 1))); 824 | } 825 | 826 | template 827 | constexpr inline unsigned ilog2(T n, unsigned p = 0) 828 | { 829 | return (n <= 1) ? p : ilog2(n / 2, p + 1); 830 | } 831 | 832 | template 833 | constexpr inline T next_poweroftwo(T n) 834 | { 835 | return n > 2 ? T(1) << (ilog2(n - 1) + 1) : n; 836 | } 837 | 838 | template 839 | constexpr inline T prev_poweroftwo(T n) 840 | { 841 | return n > 2 ? T(1) << (ilog2(n)) : n; 842 | } 843 | 844 | template 845 | constexpr inline bool is_divisible(T x, T divisor) 846 | { 847 | return x % divisor == 0; 848 | } 849 | 850 | template 851 | constexpr inline T gcd(T a) 852 | { 853 | return a; 854 | } 855 | 856 | template 857 | constexpr inline T gcd(T a, T b) 858 | { 859 | return a < b ? gcd(b, a) : ((a % b == 0) ? b : gcd(b, a % b)); 860 | } 861 | 862 | template 863 | constexpr inline T gcd(T a, T b, T c, Ts... rest) 864 | { 865 | return gcd(a, gcd(b, c, rest...)); 866 | } 867 | 868 | template 869 | constexpr inline T lcm(T a) 870 | { 871 | return a; 872 | } 873 | 874 | template 875 | constexpr inline T lcm(T a, T b) 876 | { 877 | return a * b / gcd(a, b); 878 | } 879 | 880 | template 881 | constexpr inline T lcm(T a, T b, T c, Ts... rest) 882 | { 883 | return lcm(a, lcm(b, c, rest...)); 884 | } 885 | 886 | namespace details 887 | { 888 | template 889 | struct findinttype_impl 890 | { 891 | }; 892 | template 893 | struct findinttype_impl 894 | { 895 | using type = conditional<(std::numeric_limits::min() <= min && std::numeric_limits::max() >= max), 896 | T, typename findinttype_impl::type>; 897 | }; 898 | template 899 | struct findinttype_impl 900 | { 901 | using type = void; 902 | }; 903 | 904 | template 905 | using is_number_impl = 906 | std::integral_constant::value) || (std::is_floating_point::value)) && 907 | !std::is_same::value>; 908 | } 909 | 910 | template 911 | using findinttype = typename details::findinttype_impl::type; 913 | 914 | template 915 | using is_number = details::is_number_impl>; 916 | 917 | template 918 | using is_numbers = and_t>...>; 919 | 920 | namespace details 921 | { 922 | template 923 | struct identity_impl 924 | { 925 | using type = T; 926 | }; 927 | 928 | template 929 | constexpr size_t elementsize = sizeof(T); 930 | 931 | template <> 932 | constexpr size_t elementsize = 1; 933 | } 934 | 935 | template 936 | using identity = typename details::identity_impl::type; 937 | 938 | struct swallow 939 | { 940 | template 941 | CMT_INTRIN constexpr swallow(T&&...) noexcept 942 | { 943 | } 944 | }; 945 | 946 | template 947 | struct carray; 948 | 949 | template 950 | struct carray 951 | { 952 | CMT_INTRIN constexpr carray() noexcept = default; 953 | CMT_INTRIN constexpr carray(T val) noexcept : val(val) {} 954 | 955 | template >::value)> 956 | CMT_INTRIN constexpr carray(Fn&& fn, csize_t = csize_t{}) noexcept 957 | : val(static_cast(fn(csize))) 958 | { 959 | } 960 | 961 | CMT_INTRIN constexpr carray(const carray&) noexcept = default; 962 | CMT_INTRIN constexpr carray(carray&&) noexcept = default; 963 | CMT_INTRIN static constexpr size_t size() noexcept { return 1; } 964 | 965 | template 966 | CMT_INTRIN constexpr T& get(csize_t) noexcept 967 | { 968 | static_assert(index == 0, "carray: Array index is out of range"); 969 | return val; 970 | } 971 | template 972 | CMT_INTRIN constexpr const T& get(csize_t) const noexcept 973 | { 974 | static_assert(index == 0, "carray: Array index is out of range"); 975 | return val; 976 | } 977 | template 978 | CMT_INTRIN constexpr T& get() noexcept 979 | { 980 | return get(csize); 981 | } 982 | template 983 | CMT_INTRIN constexpr const T& get() const noexcept 984 | { 985 | return get(csize); 986 | } 987 | CMT_INTRIN constexpr const T* front() const noexcept { return val; } 988 | CMT_INTRIN constexpr T* front() noexcept { return val; } 989 | CMT_INTRIN constexpr const T* back() const noexcept { return val; } 990 | CMT_INTRIN constexpr T* back() noexcept { return val; } 991 | CMT_INTRIN constexpr const T* begin() const noexcept { return &val; } 992 | CMT_INTRIN constexpr const T* end() const noexcept { return &val + 1; } 993 | CMT_INTRIN constexpr T* begin() noexcept { return &val; } 994 | CMT_INTRIN constexpr T* end() noexcept { return &val + 1; } 995 | CMT_INTRIN constexpr const T* data() const noexcept { return begin(); } 996 | CMT_INTRIN constexpr T* data() noexcept { return begin(); } 997 | CMT_INTRIN constexpr bool empty() const noexcept { return false; } 998 | T val; 999 | }; 1000 | 1001 | template 1002 | struct carray : carray 1003 | { 1004 | template 1005 | CMT_INTRIN constexpr carray(T first, Ts... list) noexcept : carray(list...), val(first) 1006 | { 1007 | static_assert(sizeof...(list) + 1 == N, "carray: Argument count is invalid"); 1008 | } 1009 | 1010 | template 1011 | CMT_INTRIN constexpr carray(Fn&& fn, csize_t = csize_t{}) noexcept 1012 | : carray(std::forward(fn), csize), 1013 | val(static_cast(fn(csize))) 1014 | { 1015 | } 1016 | 1017 | CMT_INTRIN constexpr carray() noexcept = default; 1018 | CMT_INTRIN constexpr carray(const carray&) noexcept = default; 1019 | CMT_INTRIN constexpr carray(carray&&) noexcept = default; 1020 | CMT_INTRIN static constexpr size_t size() noexcept { return N; } 1021 | CMT_INTRIN constexpr T& get(csize_t) noexcept { return val; } 1022 | template 1023 | CMT_INTRIN constexpr T& get(csize_t) noexcept 1024 | { 1025 | return carray::get(csize); 1026 | } 1027 | CMT_INTRIN constexpr const T& get(csize_t) const noexcept { return val; } 1028 | template 1029 | CMT_INTRIN constexpr const T& get(csize_t) const noexcept 1030 | { 1031 | return carray::get(csize); 1032 | } 1033 | template 1034 | CMT_INTRIN constexpr T& get() noexcept 1035 | { 1036 | return get(csize); 1037 | } 1038 | template 1039 | CMT_INTRIN constexpr const T& get() const noexcept 1040 | { 1041 | return get(csize); 1042 | } 1043 | CMT_INTRIN constexpr const T* front() const noexcept { return carray::front(); } 1044 | CMT_INTRIN constexpr T* front() noexcept { return carray::front(); } 1045 | CMT_INTRIN constexpr const T* back() const noexcept { return val; } 1046 | CMT_INTRIN constexpr T* back() noexcept { return val; } 1047 | CMT_INTRIN constexpr const T* begin() const noexcept { return carray::begin(); } 1048 | CMT_INTRIN constexpr const T* end() const noexcept { return &val + 1; } 1049 | CMT_INTRIN constexpr T* begin() noexcept { return carray::begin(); } 1050 | CMT_INTRIN constexpr T* end() noexcept { return &val + 1; } 1051 | CMT_INTRIN constexpr const T* data() const noexcept { return begin(); } 1052 | CMT_INTRIN constexpr T* data() noexcept { return begin(); } 1053 | CMT_INTRIN constexpr bool empty() const noexcept { return false; } 1054 | private: 1055 | T val; 1056 | }; 1057 | 1058 | #define CMT_FN(fn) \ 1059 | struct fn_##fn \ 1060 | { \ 1061 | template \ 1062 | CMT_INLINE_MEMBER decltype(fn(std::declval()...)) operator()(Args&&... args) const \ 1063 | { \ 1064 | return fn(std::forward(args)...); \ 1065 | } \ 1066 | }; 1067 | 1068 | #define CMT_ESC(...) __VA_ARGS__ 1069 | 1070 | #define CMT_FN_TPL(tpl_list, tpl_args, fn) \ 1071 | template \ 1072 | struct fn_##fn \ 1073 | { \ 1074 | template \ 1075 | CMT_INLINE_MEMBER decltype(fn(std::declval()...)) operator()( \ 1076 | Args&&... args) const \ 1077 | { \ 1078 | return fn(std::forward(args)...); \ 1079 | } \ 1080 | }; 1081 | 1082 | template 1083 | CMT_INTRIN auto pass_through(T&& x) noexcept 1084 | { 1085 | return x; 1086 | } 1087 | 1088 | template 1089 | CMT_INTRIN void noop(Ts...) noexcept 1090 | { 1091 | } 1092 | 1093 | template 1094 | CMT_INTRIN constexpr T1&& get_first(T1&& x, Ts...) noexcept 1095 | { 1096 | return std::forward(x); 1097 | } 1098 | 1099 | template 1100 | CMT_INTRIN constexpr T2&& get_second(T1, T2&& x, Ts...) noexcept 1101 | { 1102 | return std::forward(x); 1103 | } 1104 | 1105 | template 1106 | CMT_INTRIN constexpr T3&& get_third(T1, T2, T3&& x, Ts...) noexcept 1107 | { 1108 | return std::forward(x); 1109 | } 1110 | template 1111 | CMT_INTRIN constexpr T returns(Ts...) 1112 | { 1113 | return T(); 1114 | } 1115 | 1116 | CMT_FN(pass_through) 1117 | CMT_FN(noop) 1118 | CMT_FN(get_first) 1119 | CMT_FN(get_second) 1120 | CMT_FN(get_third) 1121 | CMT_FN_TPL((typename T), (T), returns) 1122 | 1123 | template 1124 | CMT_INTRIN bool is_equal(const T1& x, const T2& y) 1125 | { 1126 | return x == y; 1127 | } 1128 | template 1129 | CMT_INTRIN bool is_notequal(const T1& x, const T2& y) 1130 | { 1131 | return x != y; 1132 | } 1133 | template 1134 | CMT_INTRIN bool is_less(const T1& x, const T2& y) 1135 | { 1136 | return x < y; 1137 | } 1138 | template 1139 | CMT_INTRIN bool is_greater(const T1& x, const T2& y) 1140 | { 1141 | return x > y; 1142 | } 1143 | template 1144 | CMT_INTRIN bool is_lessorequal(const T1& x, const T2& y) 1145 | { 1146 | return x <= y; 1147 | } 1148 | template 1149 | CMT_INTRIN bool is_greaterorequal(const T1& x, const T2& y) 1150 | { 1151 | return x >= y; 1152 | } 1153 | CMT_FN(is_equal) 1154 | CMT_FN(is_notequal) 1155 | CMT_FN(is_less) 1156 | CMT_FN(is_greater) 1157 | CMT_FN(is_lessorequal) 1158 | CMT_FN(is_greaterorequal) 1159 | 1160 | namespace details 1161 | { 1162 | template 1163 | struct has_begin_end_impl : std::false_type 1164 | { 1165 | }; 1166 | 1167 | template 1168 | struct has_begin_end_impl().begin()), decltype(std::declval().end())>> 1169 | : std::true_type 1170 | { 1171 | }; 1172 | 1173 | template 1174 | struct has_value_type_impl : std::false_type 1175 | { 1176 | }; 1177 | 1178 | template 1179 | struct has_value_type_impl> : std::true_type 1180 | { 1181 | }; 1182 | 1183 | template 1184 | struct has_data_size_impl : std::false_type 1185 | { 1186 | }; 1187 | 1188 | template 1189 | struct has_data_size_impl().size()), decltype(std::declval().data())>> 1190 | : std::true_type 1191 | { 1192 | }; 1193 | 1194 | template 1195 | struct value_type_impl 1196 | { 1197 | using type = Fallback; 1198 | }; 1199 | 1200 | template 1201 | struct value_type_impl> 1202 | { 1203 | using type = typename T::value_type; 1204 | }; 1205 | } 1206 | 1207 | template 1208 | using has_begin_end = details::has_begin_end_impl>; 1209 | 1210 | template 1211 | using has_data_size = details::has_data_size_impl>; 1212 | 1213 | template 1214 | using value_type_of = typename decay::value_type; 1215 | 1216 | template 1217 | CMT_INTRIN void cforeach(cvals_t, Fn&& fn) 1218 | { 1219 | swallow{ (fn(cval), void(), 0)... }; 1220 | } 1221 | 1222 | template ::value)> 1223 | CMT_INTRIN void cforeach(T&& list, Fn&& fn) 1224 | { 1225 | for (const auto& v : list) 1226 | { 1227 | fn(v); 1228 | } 1229 | } 1230 | 1231 | template 1232 | CMT_INTRIN void cforeach(const T (&array)[N], Fn&& fn) 1233 | { 1234 | for (size_t i = 0; i < N; i++) 1235 | { 1236 | fn(array[i]); 1237 | } 1238 | } 1239 | 1240 | namespace details 1241 | { 1242 | template 1243 | CMT_INTRIN void cforeach_tuple_impl(const std::tuple& tuple, Fn&& fn, csizes_t) 1244 | { 1245 | swallow{ (fn(std::get(tuple)), void(), 0)... }; 1246 | } 1247 | 1248 | template 1249 | CMT_INTRIN auto get_type_arg(ctypes_t type_list) 1250 | { 1251 | return ctype>>; 1252 | } 1253 | 1254 | template 1255 | CMT_INTRIN void cforeach_types_impl(ctypes_t type_list, Fn&& fn, csizes_t) 1256 | { 1257 | swallow{ (fn(get_type_arg(type_list)), void(), 0)... }; 1258 | } 1259 | } 1260 | 1261 | template 1262 | CMT_INTRIN void cforeach(ctypes_t types, Fn&& fn) 1263 | { 1264 | details::cforeach_types_impl(types, std::forward(fn), csizeseq); 1265 | } 1266 | 1267 | template 1268 | CMT_INTRIN void cforeach(const std::tuple& tuple, Fn&& fn) 1269 | { 1270 | details::cforeach_tuple_impl(tuple, std::forward(fn), csizeseq); 1271 | } 1272 | 1273 | template 1274 | CMT_INTRIN void cforeach(A0&& a0, A1&& a1, Fn&& fn) 1275 | { 1276 | cforeach(std::forward(a0), 1277 | [&](auto v0) { cforeach(std::forward(a1), [&](auto v1) { fn(v0, v1); }); }); 1278 | } 1279 | 1280 | template 1281 | CMT_INTRIN void cforeach(A0&& a0, A1&& a1, A2&& a2, Fn&& fn) 1282 | { 1283 | cforeach(std::forward(a0), [&](auto v0) { 1284 | cforeach(std::forward(a1), 1285 | [&](auto v1) { cforeach(std::forward(a2), [&](auto v2) { fn(v0, v1, v2); }); }); 1286 | }); 1287 | } 1288 | template 1289 | CMT_INTRIN decltype(auto) cif(cbool_t, TrueFn&& truefn, FalseFn&& = FalseFn()) 1290 | { 1291 | return truefn(cbool); 1292 | } 1293 | 1294 | template 1295 | CMT_INTRIN decltype(auto) cif(cbool_t, TrueFn&&, FalseFn&& falsefn = FalseFn()) 1296 | { 1297 | return falsefn(cbool); 1298 | } 1299 | 1300 | template 1301 | CMT_INTRIN decltype(auto) cfor(cval_t, cval_t, BodyFn&& bodyfn) 1302 | { 1303 | return cforeach(cvalrange, std::forward(bodyfn)); 1304 | } 1305 | 1306 | template 1307 | void cswitch(cvals_t, const U& value, Function&& function, Fallback&& fallback = Fallback()) 1308 | { 1309 | bool result = false; 1310 | swallow{ (result = result || ((vs == value) ? (function(cval), void(), true) : false), void(), 1311 | 0)... }; 1312 | if (!result) 1313 | fallback(); 1314 | } 1315 | 1316 | template 1317 | CMT_INTRIN decltype(auto) cswitch(cvals_t, identity, Fn&&, DefFn&& deffn = DefFn(), CmpFn&& = CmpFn()) 1318 | { 1319 | return deffn(); 1320 | } 1321 | 1322 | template 1323 | CMT_INTRIN decltype(auto) cswitch(cvals_t, identity value, Fn&& fn, 1324 | DefFn&& deffn = DefFn(), CmpFn&& cmpfn = CmpFn()) 1325 | { 1326 | if (cmpfn(value, v0)) 1327 | { 1328 | return fn(cval); 1329 | } 1330 | else 1331 | { 1332 | return cswitch(cvals_t(), value, std::forward(fn), std::forward(deffn), 1333 | std::forward(cmpfn)); 1334 | } 1335 | } 1336 | 1337 | namespace details 1338 | { 1339 | 1340 | template 1341 | inline decltype(auto) cmatch_impl(T&& value, Fn1&& first, Fn2&& second, Fns&&... rest); 1342 | template 1343 | inline decltype(auto) cmatch_impl(T&& value, Fn&& last); 1344 | 1345 | template 1346 | inline decltype(auto) cmatch_impl2(cbool_t, T&& value, Fn&& fn, Fns&&...) 1347 | { 1348 | return fn(std::forward(value)); 1349 | } 1350 | 1351 | template 1352 | inline decltype(auto) cmatch_impl2(cbool_t, T&& value, Fn&&, Fns&&... rest) 1353 | { 1354 | return cmatch_impl(std::forward(value), std::forward(rest)...); 1355 | } 1356 | 1357 | template 1358 | inline decltype(auto) cmatch_impl(T&& value, Fn1&& first, Fn2&& second, Fns&&... rest) 1359 | { 1360 | using first_arg = typename function_arguments::template nth<0>; 1361 | constexpr bool is_same = std::is_same, decay>::value; 1362 | return cmatch_impl2(cbool, std::forward(value), std::forward(first), 1363 | std::forward(second), std::forward(rest)...); 1364 | } 1365 | 1366 | template 1367 | inline decltype(auto) cmatch_impl(T&& value, Fn&& last) 1368 | { 1369 | return last(std::forward(value)); 1370 | } 1371 | } 1372 | 1373 | template 1374 | inline decltype(auto) cmatch(T&& value, Fn&& fn, Args... args) 1375 | { 1376 | return details::cmatch_impl(std::forward(value), std::forward(fn), std::forward(args)...); 1377 | } 1378 | 1379 | namespace details 1380 | { 1381 | 1382 | template 1383 | struct virtual_function 1384 | { 1385 | virtual Result operator()(Args... args) = 0; 1386 | virtual virtual_function* make_copy() const = 0; 1387 | CMT_INTRIN virtual ~virtual_function() = default; 1388 | }; 1389 | 1390 | template 1391 | struct virtual_function_impl : virtual_function 1392 | { 1393 | public: 1394 | CMT_INTRIN virtual_function_impl(const Fn& fn) : fn(fn) {} 1395 | CMT_INTRIN Result operator()(Args... args) override final { return fn(args...); } 1396 | CMT_INTRIN virtual_function* make_copy() const override final 1397 | { 1398 | return new virtual_function_impl{ fn }; 1399 | } 1400 | CMT_INTRIN ~virtual_function_impl() {} 1401 | 1402 | private: 1403 | Fn fn; 1404 | }; 1405 | 1406 | template 1407 | struct func_filter 1408 | { 1409 | typedef Fn type; 1410 | }; 1411 | template 1412 | struct func_filter 1413 | { 1414 | typedef Result (*type)(Args...); 1415 | }; 1416 | 1417 | template 1418 | constexpr CMT_INTRIN T return_val() noexcept 1419 | { 1420 | return {}; 1421 | } 1422 | 1423 | template <> 1424 | constexpr CMT_INTRIN void return_val() noexcept 1425 | { 1426 | } 1427 | } 1428 | 1429 | template 1430 | struct function; 1431 | 1432 | /** 1433 | * @brief std::function-like lightweight function wrapper 1434 | * @code 1435 | * function f = []( float x ){ return static_cast( x ); }; 1436 | * CHECK( f( 3.4f ) == 3 ) 1437 | * @encode 1438 | */ 1439 | template 1440 | struct function 1441 | { 1442 | using this_t = function; 1443 | 1444 | function(function&& other) : fn(other.fn) { other.fn = nullptr; } 1445 | function& operator=(function&& other) 1446 | { 1447 | fn = other.fn; 1448 | other.fn = nullptr; 1449 | return *this; 1450 | } 1451 | 1452 | CMT_INTRIN function() : fn(nullptr) {} 1453 | CMT_INTRIN function(std::nullptr_t) : fn(nullptr) {} 1454 | template 1455 | CMT_INTRIN function(const Func& x) 1456 | : fn(new details::virtual_function_impl::type, Result, Args...>( 1457 | x)) 1458 | { 1459 | } 1460 | function(const this_t& other) : fn(other.fn ? other.fn->make_copy() : nullptr) {} 1461 | CMT_INTRIN function& operator=(const this_t& other) 1462 | { 1463 | if ((&other != this) && (other.fn)) 1464 | { 1465 | auto* temp = other.fn->make_copy(); 1466 | delete fn; 1467 | fn = temp; 1468 | } 1469 | return *this; 1470 | } 1471 | CMT_INTRIN function& operator=(std::nullptr_t) 1472 | { 1473 | delete fn; 1474 | fn = nullptr; 1475 | return *this; 1476 | } 1477 | template 1478 | CMT_INTRIN function& operator=(const Fn& x) 1479 | { 1480 | using FnImpl = 1481 | details::virtual_function_impl::type, Result, Args...>; 1482 | FnImpl* temp = new FnImpl(x); 1483 | delete fn; 1484 | fn = temp; 1485 | return *this; 1486 | } 1487 | CMT_INTRIN Result operator()(Args... args) const { return (*fn)(std::forward(args)...); } 1488 | template 1489 | CMT_INTRIN Result call(TResult&& default_result, Args... args) const 1490 | { 1491 | return fn ? (*fn)(std::forward(args)...) : std::forward(default_result); 1492 | } 1493 | CMT_INTRIN explicit operator bool() const noexcept { return !!fn; } 1494 | 1495 | CMT_INTRIN ~function() { delete fn; } 1496 | private: 1497 | details::virtual_function* fn; 1498 | }; 1499 | 1500 | template 1501 | CMT_INLINE function cdispatch(cvals_t, identity, Fn&&, DefFn&& deffn = DefFn()) 1502 | { 1503 | return [=](Args... args) CMT_INLINE_MEMBER -> Ret { return deffn(std::forward(args)...); }; 1504 | } 1505 | 1506 | template 1508 | inline function cdispatch(cvals_t, identity value, Fn&& fn, 1509 | DefFn&& deffn = DefFn()) 1510 | { 1511 | if (value == v0) 1512 | { 1513 | return [=](Args... args) 1514 | CMT_INLINE_MEMBER -> Ret { return fn(cval, std::forward(args)...); }; 1515 | } 1516 | else 1517 | { 1518 | return cdispatch(cvals_t(), value, std::forward(fn), 1519 | std::forward(deffn)); 1520 | } 1521 | } 1522 | 1523 | template 1524 | inline size_t cfind(cvals_t, identity value) 1525 | { 1526 | static const T temp[] = { values... }; 1527 | return static_cast( 1528 | std::distance(std::begin(temp), std::find(std::begin(temp), std::end(temp), value))); 1529 | } 1530 | 1531 | template 1532 | CMT_NOINLINE static result_of noinline(Fn&& fn, Args&&... args) 1533 | { 1534 | return fn(std::forward(args)...); 1535 | } 1536 | 1537 | template 1538 | struct fn_noinline 1539 | { 1540 | template 1541 | CMT_INTRIN result_of operator()(Args&&... args) const 1542 | { 1543 | return noinline(Fn{}, std::forward(args)...); 1544 | } 1545 | }; 1546 | 1547 | template ()(std::declval()...)), 1548 | typename NonMemFn = Ret (*)(Fn*, Args...)> 1549 | CMT_INTRIN NonMemFn make_nonmember(const Fn&) 1550 | { 1551 | return [](Fn* fn, Args... args) -> Ret { return fn->operator()(std::forward(args)...); }; 1552 | } 1553 | 1554 | template 1555 | struct array_ref 1556 | { 1557 | public: 1558 | using value_type = T; 1559 | using pointer = value_type*; 1560 | using const_pointer = const value_type*; 1561 | using reference = value_type&; 1562 | using const_reference = const value_type&; 1563 | using iterator = pointer; 1564 | using const_iterator = const_pointer; 1565 | using reverse_iterator = std::reverse_iterator; 1566 | using const_reverse_iterator = std::reverse_iterator; 1567 | using size_type = std::size_t; 1568 | using difference_type = std::ptrdiff_t; 1569 | 1570 | constexpr array_ref() noexcept : m_data(nullptr), m_size(0) {} 1571 | constexpr array_ref(const array_ref&) noexcept = default; 1572 | constexpr array_ref(array_ref&&) noexcept = default; 1573 | constexpr array_ref& operator=(const array_ref&) noexcept = default; 1574 | constexpr array_ref& operator=(array_ref&&) noexcept = default; 1575 | 1576 | template 1577 | constexpr array_ref(value_type (&arr)[N]) noexcept : m_data(arr), m_size(N) 1578 | { 1579 | } 1580 | template 1581 | constexpr array_ref(const std::array& arr) noexcept : m_data(arr.data()), m_size(N) 1582 | { 1583 | } 1584 | template 1585 | constexpr array_ref(std::array& arr) noexcept : m_data(arr.data()), m_size(N) 1586 | { 1587 | } 1588 | template 1589 | constexpr array_ref(const std::vector& vec) noexcept : m_data(vec.data()), m_size(vec.size()) 1590 | { 1591 | } 1592 | template ::value)> 1593 | constexpr array_ref(const std::vector, Ts...>& vec) noexcept : m_data(vec.data()), 1594 | m_size(vec.size()) 1595 | { 1596 | } 1597 | template 1598 | constexpr array_ref(std::vector& vec) noexcept : m_data(vec.data()), m_size(vec.size()) 1599 | { 1600 | } 1601 | template 1602 | constexpr array_ref(InputIter first, InputIter last) noexcept : m_data(std::addressof(*first)), 1603 | m_size(std::distance(first, last)) 1604 | { 1605 | } 1606 | constexpr array_ref(T* data, size_type size) noexcept : m_data(data), m_size(size) {} 1607 | 1608 | constexpr reference front() const noexcept { return m_data[0]; } 1609 | constexpr reference back() const noexcept { return m_data[m_size - 1]; } 1610 | constexpr iterator begin() const noexcept { return m_data; } 1611 | constexpr iterator end() const noexcept { return m_data + m_size; } 1612 | constexpr const_iterator cbegin() const noexcept { return m_data; } 1613 | constexpr const_iterator cend() const noexcept { return m_data + m_size; } 1614 | constexpr pointer data() const noexcept { return m_data; } 1615 | constexpr std::size_t size() const noexcept { return m_size; } 1616 | constexpr bool empty() const noexcept { return !m_size; } 1617 | constexpr reference operator[](std::size_t index) const { return m_data[index]; } 1618 | 1619 | private: 1620 | pointer m_data; 1621 | size_type m_size; 1622 | }; 1623 | 1624 | template 1625 | constexpr inline T choose_const() 1626 | { 1627 | static_assert(sizeof(T) != 0, "T not found in the list of template arguments"); 1628 | return T(); 1629 | } 1630 | 1631 | /** 1632 | * Selects constant of the specific type 1633 | * @code 1634 | * CHECK( choose_const( 32.0f, 64.0 ) == 32.0f ); 1635 | * CHECK( choose_const( 32.0f, 64.0 ) == 64.0 ); 1636 | * @endcode 1637 | */ 1638 | template 1639 | constexpr inline T choose_const(C1 c1, Cs... constants) 1640 | { 1641 | return std::is_same::value ? static_cast(c1) : choose_const(constants...); 1642 | } 1643 | 1644 | template 1645 | inline array_ref make_array_ref(T (&data)[size]) 1646 | { 1647 | return array_ref(data); 1648 | } 1649 | 1650 | template 1651 | inline array_ref make_array_ref(T* data, std::size_t size) 1652 | { 1653 | return array_ref(data, data + size); 1654 | } 1655 | 1656 | template ::value), 1657 | typename T = remove_pointer().data())>> 1658 | inline array_ref make_array_ref(Container& cont) 1659 | { 1660 | return array_ref(cont.data(), cont.size()); 1661 | } 1662 | 1663 | template ::value), 1664 | typename T = remove_pointer().data())>> 1665 | inline array_ref make_array_ref(const Container& cont) 1666 | { 1667 | return array_ref(cont.data(), cont.size()); 1668 | } 1669 | 1670 | template 1671 | inline array_ref make_array_ref(std::vector& cont) 1672 | { 1673 | return array_ref(cont.data(), cont.size()); 1674 | } 1675 | template 1676 | inline array_ref make_array_ref(const std::vector& cont) 1677 | { 1678 | return array_ref(cont.data(), cont.size()); 1679 | } 1680 | 1681 | template (0)> 1682 | struct result 1683 | { 1684 | using value_type = Type; 1685 | using reference = value_type&; 1686 | using const_reference = const value_type&; 1687 | using pointer = value_type*; 1688 | using const_pointer = const value_type*; 1689 | 1690 | using error_type = ErrEnum; 1691 | 1692 | constexpr static error_type ok_value = OkValue; 1693 | 1694 | constexpr result(const result&) = default; 1695 | constexpr result(result&&) noexcept = default; 1696 | 1697 | constexpr result(ErrEnum error) noexcept : m_error(error) {} 1698 | 1699 | template ::value)> 1700 | constexpr result(ValueInit&& value) noexcept : m_value(std::forward(value)), m_error(OkValue) 1701 | { 1702 | } 1703 | 1704 | constexpr result(const Type& value) noexcept : m_value(value), m_error(OkValue) {} 1705 | constexpr result(Type&& value) noexcept : m_value(std::move(value)), m_error(OkValue) {} 1706 | 1707 | constexpr explicit operator bool() const { return m_error == OkValue; } 1708 | constexpr const_reference operator*() const { return m_value; } 1709 | constexpr reference operator*() { return m_value; } 1710 | constexpr const_pointer operator->() const { return &m_value; } 1711 | constexpr pointer operator->() { return &m_value; } 1712 | 1713 | constexpr const_reference value() const { return m_value; } 1714 | constexpr reference value() { return m_value; } 1715 | constexpr ErrEnum error() const { return m_error; } 1716 | constexpr bool ok() const { return m_error == OkValue; } 1717 | private: 1718 | Type m_value; 1719 | ErrEnum m_error; 1720 | }; 1721 | 1722 | template 1723 | struct autocast_impl 1724 | { 1725 | const Tfrom value; 1726 | template 1727 | CMT_INTRIN constexpr operator T() const noexcept 1728 | { 1729 | return static_cast(value); 1730 | } 1731 | }; 1732 | 1733 | template 1734 | CMT_INTRIN constexpr autocast_impl autocast(const Tfrom& value) noexcept 1735 | { 1736 | return { value }; 1737 | } 1738 | 1739 | inline void stop_constexpr() {} 1740 | 1741 | namespace details 1742 | { 1743 | template 1744 | struct signed_type_impl 1745 | { 1746 | using type = T; 1747 | }; 1748 | template 1749 | struct signed_type_impl::value>>> 1750 | { 1751 | using type = findinttype::min(), std::numeric_limits::max()>; 1752 | }; 1753 | } 1754 | 1755 | template 1756 | using signed_type = typename details::signed_type_impl::type; 1757 | 1758 | template 1759 | struct range 1760 | { 1761 | using value_type = T; 1762 | using reference = T&; 1763 | using const_reference = const T&; 1764 | using pointer = T*; 1765 | using const_pointer = const T*; 1766 | using diff_type = decltype(std::declval() - std::declval()); 1767 | 1768 | constexpr range(value_type begin, value_type end, diff_type step) noexcept : value_begin(begin), 1769 | value_end(end), 1770 | step(step) 1771 | { 1772 | } 1773 | 1774 | struct iterator 1775 | { 1776 | value_type value; 1777 | diff_type step; 1778 | const_reference operator*() const { return value; } 1779 | const_pointer operator->() const { return &value; } 1780 | iterator& operator++() 1781 | { 1782 | value += step; 1783 | return *this; 1784 | } 1785 | iterator operator++(int) 1786 | { 1787 | iterator copy = *this; 1788 | ++(*this); 1789 | return copy; 1790 | } 1791 | bool operator!=(const iterator& other) const 1792 | { 1793 | return step > 0 ? value < other.value : value > other.value; 1794 | } 1795 | }; 1796 | value_type value_begin; 1797 | value_type value_end; 1798 | diff_type step; 1799 | iterator begin() const { return iterator{ value_begin, step }; } 1800 | iterator end() const { return iterator{ value_end, step }; } 1801 | }; 1802 | 1803 | template 1804 | range make_range(T begin, T end) 1805 | { 1806 | return range(begin, end, end > begin ? 1 : -1); 1807 | } 1808 | 1809 | template () - std::declval())> 1810 | range make_range(T begin, T end, diff_type step) 1811 | { 1812 | return range(begin, end, step); 1813 | } 1814 | 1815 | template 1816 | struct named_arg 1817 | { 1818 | T value; 1819 | const char* name; 1820 | }; 1821 | 1822 | struct named 1823 | { 1824 | constexpr named(const char* name) noexcept : name(name) {} 1825 | 1826 | template 1827 | CMT_INTRIN constexpr named_arg operator=(T&& value) 1828 | { 1829 | return named_arg{ std::forward(value), name }; 1830 | } 1831 | const char* name; 1832 | }; 1833 | 1834 | inline named operator""_arg(const char* name, size_t) { return name; } 1835 | 1836 | template 1837 | struct cstring 1838 | { 1839 | using value_type = char; 1840 | using size_type = size_t; 1841 | 1842 | constexpr const value_type* c_str() const noexcept { return value; } 1843 | constexpr const value_type* data() const noexcept { return value; } 1844 | 1845 | const value_type value[N]; 1846 | constexpr size_type length() const noexcept { return N - 1; } 1847 | constexpr size_type size() const noexcept { return N; } 1848 | 1849 | constexpr friend bool operator==(const cstring& left, const cstring& right) noexcept 1850 | { 1851 | for (size_t i = 0; i < 1; i++) 1852 | if (left.value[i] != right.value[i]) 1853 | return false; 1854 | return true; 1855 | } 1856 | constexpr friend bool operator!=(const cstring& left, const cstring& right) noexcept 1857 | { 1858 | return !(left == right); 1859 | } 1860 | 1861 | template 1862 | constexpr bool operator==(const cstring& other) const noexcept 1863 | { 1864 | return false; 1865 | } 1866 | template 1867 | constexpr bool operator!=(const cstring& other) const noexcept 1868 | { 1869 | return true; 1870 | } 1871 | constexpr char operator[](size_t index) const noexcept { return value[index]; } 1872 | }; 1873 | 1874 | namespace details 1875 | { 1876 | 1877 | template 1878 | CMT_INLINE constexpr cstring make_cstring_impl(const char (&str)[N], csizes_t) 1879 | { 1880 | return { { str[indices]..., 0 } }; 1881 | } 1882 | 1883 | template 1884 | CMT_INLINE constexpr cstring concat_str_impl(const cstring& str1, 1885 | const cstring& str2, 1886 | csizes_t) 1887 | { 1888 | constexpr size_t L1 = N1 - 1; 1889 | return { { (indices < L1 ? str1[indices] : str2[indices - L1])..., 0 } }; 1890 | } 1891 | template 1892 | CMT_INLINE constexpr cstring concat_str_impl(const cstring& str1, 1893 | const cstring& str2) 1894 | { 1895 | return concat_str_impl(str1, str2, csizeseq); 1896 | } 1897 | template 1898 | CMT_INTRIN cstring str_replace_impl(size_t pos, const cstring& str, 1899 | const cstring&, const cstring& to, 1900 | csizes_t) 1901 | { 1902 | if (pos == size_t(-1)) 1903 | stop_constexpr(); 1904 | return { { (indices < pos ? str[indices] : (indices < pos + Nto - 1) ? to[indices - pos] 1905 | : str[indices - Nto + Nfrom])..., 1906 | 0 } }; 1907 | } 1908 | } 1909 | 1910 | CMT_INTRIN constexpr cstring<1> concat_cstring() { return { { 0 } }; } 1911 | 1912 | template 1913 | CMT_INTRIN constexpr cstring concat_cstring(const cstring& str1) 1914 | { 1915 | return str1; 1916 | } 1917 | 1918 | template 1919 | CMT_INTRIN constexpr auto concat_cstring(const cstring& str1, const cstring& str2, 1920 | const Args&... args) 1921 | { 1922 | return details::concat_str_impl(str1, concat_cstring(str2, args...)); 1923 | } 1924 | 1925 | template 1926 | CMT_INTRIN constexpr cstring make_cstring(const char (&str)[N]) 1927 | { 1928 | return details::make_cstring_impl(str, csizeseq); 1929 | } 1930 | 1931 | template 1932 | CMT_INTRIN constexpr cstring make_cstring(cchars_t) 1933 | { 1934 | return { { chars..., 0 } }; 1935 | } 1936 | 1937 | template 1938 | CMT_INTRIN size_t str_find(const cstring& str, const cstring& needle) 1939 | { 1940 | size_t count = 0; 1941 | for (size_t i = 0; i < N1; i++) 1942 | { 1943 | if (str[i] == needle[count]) 1944 | count++; 1945 | else 1946 | count = 0; 1947 | if (count == Nneedle - 1) 1948 | return i + 1 - (Nneedle - 1); 1949 | } 1950 | return size_t(-1); 1951 | } 1952 | 1953 | template 1954 | CMT_INTRIN cstring str_replace(const cstring& str, const cstring& from, 1955 | const cstring& to) 1956 | { 1957 | return details::str_replace_impl(str_find(str, from), str, from, to, csizeseq); 1958 | } 1959 | 1960 | using pconstvoid = const void*; 1961 | 1962 | struct type_id_t 1963 | { 1964 | constexpr type_id_t(const void* id) noexcept : id(id) {} 1965 | constexpr bool operator==(type_id_t other) const { return id == other.id; } 1966 | constexpr bool operator!=(type_id_t other) const { return !(id == other.id); } 1967 | const void* const id; 1968 | }; 1969 | 1970 | namespace details 1971 | { 1972 | 1973 | constexpr inline size_t strlen(const char* str) { return *str ? 1 + cometa::details::strlen(str + 1) : 0; } 1974 | 1975 | template 1976 | constexpr inline type_id_t typeident_impl() noexcept 1977 | { 1978 | return type_id_t(pconstvoid(&typeident_impl)); 1979 | } 1980 | 1981 | template 1982 | constexpr cstring gettypename_impl(const char* str, csizes_t) noexcept 1983 | { 1984 | return cstring{ { (str[indices])..., 0 } }; 1985 | } 1986 | } 1987 | template 1988 | constexpr auto cfunc_sign() noexcept 1989 | { 1990 | constexpr size_t length = sizeof(CMT_FUNC_SIGNATURE) - 1; 1991 | return details::gettypename_impl(CMT_FUNC_SIGNATURE, csizeseq); 1992 | } 1993 | namespace details 1994 | { 1995 | constexpr size_t typename_prefix = sizeof(decltype(cfunc_sign())) - 1 - 5 - 1; 1996 | constexpr size_t typename_postfix = sizeof("]") - 1; 1997 | } 1998 | template 1999 | constexpr auto ctype_name() noexcept 2000 | { 2001 | constexpr size_t length = 2002 | sizeof(CMT_FUNC_SIGNATURE) - 1 > details::typename_prefix + details::typename_postfix ? 2003 | sizeof(CMT_FUNC_SIGNATURE) - 1 - details::typename_prefix - details::typename_postfix : 2004 | 0; 2005 | return length == 0 ? cstring{ { 0 } } : details::gettypename_impl(CMT_FUNC_SIGNATURE + details::typename_prefix, csizeseq); 2006 | } 2007 | 2008 | /** 2009 | * @brief Gets the fully qualified name of the type, including namespace and 2010 | * template parameters (if any) 2011 | * @tparam T type 2012 | * @return name of the type 2013 | */ 2014 | template 2015 | inline const char* type_name() noexcept 2016 | { 2017 | static const auto name = ctype_name(); 2018 | return name.c_str(); 2019 | } 2020 | 2021 | /** 2022 | * @brief Gets the fully qualified name of the type, including namespace and 2023 | * template parameters (if any) 2024 | * @param x value of specific type 2025 | * @return name of the type 2026 | */ 2027 | template 2028 | inline const char* type_name(T x) noexcept 2029 | { 2030 | (void)x; 2031 | return type_name(); 2032 | } 2033 | 2034 | /** 2035 | * @brief Gets unique value associated with the type 2036 | * @tparam T type 2037 | * @return value of type that supports operator== and operator!= 2038 | */ 2039 | template 2040 | constexpr inline type_id_t ctypeid() 2041 | { 2042 | return details::typeident_impl(); 2043 | } 2044 | /** 2045 | * @brief Gets unique value associated with the type 2046 | * @param x value of specific type 2047 | * @return value of type that supports operator== and operator!= 2048 | */ 2049 | template 2050 | constexpr inline type_id_t ctypeid(T x) 2051 | { 2052 | (void)x; 2053 | return details::typeident_impl(); 2054 | } 2055 | } 2056 | 2057 | #pragma GCC diagnostic pop 2058 | --------------------------------------------------------------------------------