├── tests ├── catch.cpp ├── memory-resource.cpp ├── propagate-const.cpp ├── array.cpp ├── utility.cpp ├── type-traits.cpp ├── iterator.cpp ├── functional.cpp ├── numeric.cpp ├── any.cpp ├── CMakeLists.txt └── variant.cpp ├── .gitattributes ├── package ├── banner.bmp ├── dialog.bmp ├── mnmlstc.ico ├── pkg.json ├── distribution.xml.in ├── core-config.cmake.in ├── License.rtf └── CMakeLists.txt ├── codecov.yml ├── .gitignore ├── appveyor.yml ├── scripts ├── travis-install ├── travis-configure ├── travis-before-install ├── pkgbuild.py └── Copying.rst ├── docs ├── CMakeLists.txt ├── propagate-const.rst ├── conf.py ├── index.rst ├── array.rst ├── numeric.rst ├── utility.rst ├── type-traits.rst ├── any.rst ├── iterator.rst ├── variant.rst └── usage.rst ├── .clang-format ├── include └── core │ ├── vector.hpp │ ├── regex.hpp │ ├── list.hpp │ ├── deque.hpp │ ├── forward_list.hpp │ ├── set.hpp │ ├── array.hpp │ ├── string.hpp │ ├── map.hpp │ ├── unordered_set.hpp │ ├── unordered_map.hpp │ ├── typeinfo.hpp │ ├── internal.hpp │ ├── utility.hpp │ ├── numeric.hpp │ ├── iterator.hpp │ ├── memory_resource.hpp │ ├── type_traits.hpp │ ├── any.hpp │ ├── meta.hpp │ ├── range.hpp │ └── propagate_const.hpp ├── License.rst ├── Readme.rst ├── .travis.yml └── CMakeLists.txt /tests/catch.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include "catch.hpp" 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.png binary 2 | *.ico binary 3 | *.bmp binary 4 | *.rtf binary 5 | -------------------------------------------------------------------------------- /package/banner.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mnmlstc/core/HEAD/package/banner.bmp -------------------------------------------------------------------------------- /package/dialog.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mnmlstc/core/HEAD/package/dialog.bmp -------------------------------------------------------------------------------- /package/mnmlstc.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mnmlstc/core/HEAD/package/mnmlstc.ico -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | ignore: 3 | - scripts 4 | - package 5 | - tests 6 | - docs 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.swp 4 | *~ 5 | 6 | build-clang/ 7 | build-gcc/ 8 | build/ 9 | bii/ 10 | bin/ 11 | -------------------------------------------------------------------------------- /tests/memory-resource.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "catch.hpp" 4 | 5 | TEST_CASE("dummy") { 6 | CHECK(true); 7 | } 8 | -------------------------------------------------------------------------------- /tests/propagate-const.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "catch.hpp" 5 | 6 | TEST_CASE("default-constructor", "[constructors]") { 7 | core::propagate_const> value { }; 8 | 9 | CHECK_FALSE(value); 10 | } 11 | -------------------------------------------------------------------------------- /package/pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "MNMLSTC Core", 3 | "organization": "com.mnmlstc", 4 | "license": "License.rtf", 5 | "identifier": "com.mnmlstc.core", 6 | "template": "distribution.xml.in", 7 | "package": "core", 8 | "version": "2.0.0", 9 | "description": "C++14 (and beyond) library features implemented in C++11" 10 | } 11 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | platform: 2 | - x86 3 | - x64 4 | configuration: 5 | - Debug 6 | - Release 7 | 8 | branches: 9 | only: master 10 | skip_tags: true 11 | os: 12 | - Visual Studio 2015 13 | 14 | build: 15 | parallel: true 16 | verbosity: normal 17 | 18 | install: 19 | - C:\"Program Files (x86)"\"Microsoft Visual Studio 14.0"\VC\vcvarsall.bat 20 | - 21 | 22 | build_script: 23 | - cmake --build build --target check 24 | -------------------------------------------------------------------------------- /scripts/travis-install: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # travis-install - build-script 3 | 4 | if [[ "osx" = ${TRAVIS_OS_NAME} ]]; then 5 | brew ls | grep -wq cmake || brew install --without-docs cmake 6 | brew outdated cmake || brew upgrade cmake 7 | fi 8 | 9 | if [[ "linux" = ${TRAVIS_OS_NAME} ]]; then 10 | sudo apt-get install ${CC}-${VERSION} 11 | sudo apt-get install ${CXX}-${VERSION} 12 | sudo apt-get install libc++-dev libc++abi-dev 13 | fi 14 | -------------------------------------------------------------------------------- /docs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_program(SPHINX_EXECUTABLE 2 | NAMES sphinx-build 3 | DOC "Sphinx Documentation Generator" 4 | ) 5 | 6 | if (NOT SPHINX_EXECUTABLE) 7 | message(FATAL_ERROR "Cannot build documentation without Sphinx!") 8 | endif () 9 | mark_as_advanced(SPHINX_EXECUTABLE) 10 | 11 | add_custom_target(docs 12 | COMMAND ${SPHINX_EXECUTABLE} ${DOCS_SOURCE_DIR} ${DOCS_BINARY_DIR} 13 | COMMENT "Generating Sphinx Documentation" VERBATIM 14 | ) 15 | 16 | set_property( 17 | DIRECTORY APPEND PROPERTY 18 | ADDITIONAL_MAKE_CLEAN_FILES ${DOCS_BINARY_DIR}) 19 | -------------------------------------------------------------------------------- /docs/propagate-const.rst: -------------------------------------------------------------------------------- 1 | Propagating Const 2 | ================= 3 | 4 | .. namespace:: core 5 | 6 | The :any:`propagate_const` component was added in the C++ Library Fundamentals 7 | V2 specification. It is a const-propagating wrapper for pointers and pointer 8 | like types. This type solves the issue where a ``std::unique_ptr`` would 9 | return a ``T*``, *even* if the ``std::unique_ptr`` were ``const`` in a 10 | given context. 11 | 12 | This component resides in :file:`` 13 | 14 | .. class:: template propagate_const 15 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | Standard: Cpp11 2 | Language: Cpp 3 | AccessModifierOffset: 0 4 | IndentWidth: 2 5 | UseTab: Never 6 | BinPackParameters: true 7 | PointerAlignment: Left 8 | AllowShortIfStatementsOnASingleLine: true 9 | AllowShortLoopsOnASingleLine: true 10 | AllowShortBlocksOnASingleLine: true 11 | AllowShortFunctionsOnASingleLine: true 12 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 13 | AlwaysBreakTemplateDeclarations: false 14 | NamespaceIndentation: None 15 | PointerBindsToType: true 16 | SpaceInParentheses: false 17 | BreakBeforeBraces: Attach 18 | ColumnLimit: 80 19 | Cpp11BracedListStyle: true 20 | SpaceBeforeTrailingComments: 1 21 | SpaceBeforeParens: ControlStatements 22 | -------------------------------------------------------------------------------- /include/core/vector.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_VECTOR_HPP 2 | #define CORE_VECTOR_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace core { 10 | inline namespace v2 { 11 | 12 | template 13 | void erase_if (::std::vector& v, Predicate pred) { 14 | v.erase(::core::remove_if(v, pred), end(v)); 15 | } 16 | 17 | }} /* namespace core::v2 */ 18 | 19 | namespace core { 20 | inline namespace v2 { 21 | namespace pmr { 22 | 23 | template using vector = ::std::vector>; 24 | 25 | }}} /* namespace core::v2::pmr */ 26 | 27 | #endif /* CORE_VECTOR_HPP */ 28 | -------------------------------------------------------------------------------- /License.rst: -------------------------------------------------------------------------------- 1 | .. |copy| unicode:: U+000A9 2 | .. _License: http://www.apache.org/licenses/LICENSE-2.0 3 | 4 | Copyright |copy| 2013 - 2015 MNMLSTC 5 | 6 | Licensed under the Apache License_, Version 2.0 (the "License"); you may not 7 | use this software except in compliance with the License_. You may obtain a 8 | copy of the License_ at http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software distributed 11 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | specific language governing permissions and limitations under the License. 14 | -------------------------------------------------------------------------------- /include/core/regex.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_REGEX_HPP 2 | #define CORE_REGEX_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace core { 10 | inline namespace v2 { 11 | namespace pmr { 12 | 13 | template 14 | using match_results = ::std::match_results< 15 | BidirIt, 16 | polymorphic_allocator<::std:::sub_match> 17 | >; 18 | 19 | using wsmatch = match_results; 20 | using wcmatch = match_results; 21 | using smatch = match_results; 22 | using cmatch = match_results; 23 | 24 | }}} /* namespace core::v2::pmr */ 25 | 26 | #endif /* CORE_REGEX_HPP */ 27 | -------------------------------------------------------------------------------- /tests/array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "catch.hpp" 4 | 5 | TEST_CASE("array-make-array") { 6 | auto const number = 420l; 7 | auto character = 's'; 8 | auto make_array = core::make_array(number, character, 0); 9 | CHECK((std::is_same::value)); 10 | CHECK(make_array.size() == 3); 11 | 12 | auto make_array_2 = core::make_array(1337, 100U); 13 | CHECK((std::is_same::value)); 14 | CHECK(make_array_2.size() == 2); 15 | } 16 | 17 | TEST_CASE("array-to-array") { 18 | auto to_array = core::to_array("deadbeef"); 19 | CHECK((std::is_same::value)); 20 | CHECK(to_array.size() == 9); 21 | } 22 | -------------------------------------------------------------------------------- /package/distribution.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | ${title} 4 | ${organization} 5 | 6 | 7 | 8 | 9 | ${package}-${version}.pkg 10 | 11 | 12 | 13 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /include/core/list.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_LIST_HPP 2 | #define CORE_LIST_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace core { 10 | inline namespace v2 { 11 | 12 | template 13 | void erase_if (::std::list& l, Predicate pred) { l.remove_if(pred); } 14 | 15 | template 16 | void erase (::std::list& l, U const& value) { 17 | using ::std::placeholders::_1; 18 | l.remove_if(::std::bind(equal<>, _1, ::std::cref(value))); 19 | } 20 | 21 | }} /* namespace core::v2 */ 22 | 23 | namespace core { 24 | inline namespace v2 { 25 | namespace pmr { 26 | 27 | template using list = ::std::list>; 28 | 29 | }}} /* namespace core::v2::pmr */ 30 | 31 | #endif /* CORE_LIST_HPP */ 32 | -------------------------------------------------------------------------------- /include/core/deque.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_DEQUE_HPP 2 | #define CORE_DEQUE_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace core { 10 | inline namespace v2 { 11 | 12 | template 13 | void erase_if (::std::deque& deq, Predicate pred) { 14 | deq.erase(::core::remove_if(deq, pred), end(deq)); 15 | } 16 | 17 | template 18 | void erase (::std::deque& deq, U const& value) { 19 | deq.erase(::core::remove(deq, value), end(deq)); 20 | } 21 | 22 | }} /* namespace core::v2 */ 23 | 24 | namespace core { 25 | inline namespace v2 { 26 | namespace pmr { 27 | 28 | template using deque = ::std::deque>; 29 | 30 | }}} /* namespace core::v2::pmr */ 31 | 32 | #endif /* CORE_DEQUE_HPP */ 33 | -------------------------------------------------------------------------------- /scripts/travis-configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # travis-configure - build-script 3 | 4 | CURRENT=$(pwd) 5 | if [[ ! -z ${VERSION} ]]; then 6 | CXX=${CXX}-${VERSION} 7 | CC=${CC}-${VERSION} 8 | fi 9 | 10 | if [[ ! -z ${CXX_STANDARD} ]]; then 11 | CXXFLAGS=-std=${CXX_STANDARD} 12 | STANDARD_REQUIRED=OFF 13 | fi 14 | 15 | echo Using $(cmake --version | head -n1) 16 | echo CXX=${CXX} 17 | 18 | mkdir build && cd build || exit 1 19 | 20 | cmake $CURRENT \ 21 | -DCMAKE_CXX_FLAGS:STRING=${CXXFLAGS} \ 22 | -DCMAKE_CXX_COMPILER:STRING=${CXX} \ 23 | -DCMAKE_BUILD_TYPE:STRING=${BUILD:-Debug} \ 24 | -DCMAKE_CXX_STANDARD_REQUIRED=${STANDARD_REQUIRED:-ON} \ 25 | -DBUILD_WITH_COVERAGE:BOOL=ON \ 26 | -DBUILD_WITH_LIBCXX:BOOL=${LIBCXX:-OFF} \ 27 | -DBUILD_TESTING:BOOL=ON || \ 28 | { cat ./CMakeFiles/CMakeOutput.log ./CMakeFiles/CMakeError.log && exit 1; } 29 | -------------------------------------------------------------------------------- /package/core-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | set(CORE_VERSION_MAJOR @PROJECT_VERSION_MAJOR@) 4 | set(CORE_VERSION_MINOR @PROJECT_VERSION_MINOR@) 5 | set(CORE_VERSION_PATCH @PROJECT_VERSION_PATCH@) 6 | set(CORE_VERSION @PROJECT_VERSION@) 7 | 8 | if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/core-targets.cmake") 9 | include("${CMAKE_CURRENT_LIST_DIR}/core-targets.cmake") 10 | elseif (EXISTS "${CMAKE_CURRENT_LIST_DIR}/core-export.cmake") 11 | include("${CMAKE_CURRENT_LIST_DIR}/core-export.cmake") 12 | endif () 13 | 14 | # Provided for backwards compatibility 15 | get_target_property(CORE_DIR mnmlstc::core INTERFACE_INCLUDE_DIRECTORIES) 16 | 17 | set_and_check(CORE_INCLUDE_DIR ${CORE_DIR}) 18 | set_and_check(CORE_INCLUDE_DIRS ${CORE_INCLUDE_DIR}) 19 | set_and_check(core_INCLUDE_DIRS ${CORE_INCLUDE_DIR}) 20 | 21 | unset(CORE_DIR) # This shouldn't be exported 22 | 23 | check_required_components(core) 24 | -------------------------------------------------------------------------------- /scripts/travis-before-install: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # travis-before-install - build-script 3 | 4 | # This is apparently an expected approach in the event brew update fails on 5 | # the first try. Wat. 6 | if [[ "osx" = ${TRAVIS_OS_NAME} ]]; then 7 | brew update || brew update || exit 1 8 | brew upgrade 9 | fi 10 | 11 | if [[ "linux" = ${TRAVIS_OS_NAME} ]]; then 12 | LLVM37="deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.7 main" 13 | LLVM38="deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.8 main" 14 | LLVM39="deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.9 main" 15 | curl http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - 16 | sudo add-apt-repository -y "${LLVM37}" 17 | sudo add-apt-repository -y "${LLVM38}" 18 | sudo add-apt-repository -y "${LLVM39}" 19 | sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test 20 | sudo add-apt-repository 21 | sudo apt-get -qq update 22 | fi 23 | -------------------------------------------------------------------------------- /include/core/forward_list.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_FORWARD_LIST_HPP 2 | #define CORE_FORWARD_LIST_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace core { 10 | inline namespace v2 { 11 | 12 | template 13 | void erase_if (::std::forward_list& f, Predicate pred) { 14 | f.remove_if(pred); 15 | } 16 | 17 | template 18 | void erase (::std::forward_list& f, U const& value) { 19 | using ::std::placeholders::_1; 20 | f.remove_if(::std::bind(equal<>, _1, ::std::cref(value))); 21 | } 22 | 23 | }} /* namespace core::v2 */ 24 | 25 | namespace core { 26 | inline namespace v2 { 27 | namespace pmr { 28 | 29 | template 30 | using forward_list = ::std::forward_list>; 31 | 32 | }}} /* namespace core::v2::pmr */ 33 | 34 | #endif /* CORE_FORWARD_LIST_HPP */ 35 | -------------------------------------------------------------------------------- /tests/utility.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "catch.hpp" 4 | 5 | TEST_CASE("scope-guard", "[scope-guard]") { 6 | SECTION("value-constructor") { 7 | bool value { false }; 8 | { auto scope = core::make_scope_guard([&]{ value = true; }); } 9 | CHECK(value); 10 | } 11 | 12 | SECTION("dismiss") { 13 | bool value { false }; 14 | { 15 | auto scope = core::make_scope_guard([&] { value = true; }); 16 | scope.dismiss(); 17 | } 18 | CHECK_FALSE(value); 19 | } 20 | } 21 | 22 | TEST_CASE("value-at") { 23 | SECTION("runtime") { 24 | auto value = core::value_at<3>(1, 2, 3, 4); 25 | CHECK(value == 4); 26 | } 27 | 28 | SECTION("compile-time") { 29 | constexpr auto value = core::value_at<3>(1, 2, 3, 4); 30 | constexpr auto second = core::value_at<2>(1, 2, 4.0f, ""); 31 | static_assert(value == 4, ""); 32 | static_assert(second > 3.9f, ""); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /package/License.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1347\cocoasubrtf490 2 | {\fonttbl\f0\fnil\fcharset0 Verdana;} 3 | {\colortbl;\red255\green255\blue255;\red0\green0\blue255;} 4 | \vieww12000\viewh14980\viewkind0 5 | \deftab720 6 | \pard\pardeftab720\sl276\slmult1\sa200 7 | 8 | \f0\fs22 \cf0 Copyright \'a9 2013 \'97 2015 MNMLSTC\ 9 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this software except in compliance with the License. You may obtain a copy of the License at:\ 10 | {\field{\*\fldinst{HYPERLINK "http://www.apache.org/licenses/LICENSE-2.0"}}{\fldrslt \cf2 \ul \ulc2 http://www.apache.org/licenses/LICENSE-2.0}}\ 11 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\ 12 | } -------------------------------------------------------------------------------- /include/core/set.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_SET_HPP 2 | #define CORE_SET_HPP 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace core { 9 | inline namespace v1 { 10 | 11 | template 12 | void erase_if (::std::multiset& s, Predicate pred) { 13 | for (auto iter = begin(s); iter != end(s);) { 14 | invoke(pred, *iter) ? iter = s.erase(iter) : ++iter; 15 | } 16 | } 17 | 18 | template 19 | void erase_if (::std::set& s, Predicate pred) { 20 | for (auto iter = begin(s); iter != end(s);) { 21 | invoke(pred, *iter) ? iter = s.erase(iter) : ++iter; 22 | } 23 | } 24 | 25 | }} /* namespace core::v1 */ 26 | 27 | namespace core { 28 | inline namespace v2 { 29 | namespace pmr { 30 | 31 | template > 32 | using multiset = ::std::multiset>; 33 | 34 | template > 35 | using set = ::std::set>; 36 | 37 | }}} /* namespace core::v2::pmr */ 38 | 39 | #endif /* CORE_SET_HPP */ 40 | -------------------------------------------------------------------------------- /include/core/array.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_ARRAY_HPP 2 | #define CORE_ARRAY_HPP 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace core { 12 | inline namespace v2 { 13 | 14 | template 15 | constexpr auto make_array (Args&&... args) -> ::std::array< 16 | meta::either< 17 | meta::all< 18 | ::std::is_void::value, 19 | meta::none_of, is_reference_wrapper>() 20 | >(), 21 | common_type_t, 22 | V 23 | >, 24 | sizeof...(Args) 25 | > { return {{ core::forward(args)... }}; } 26 | 27 | template 28 | constexpr auto to_array (T (&array)[N], index_sequence) -> ::std::array< 29 | remove_cv_t, N 30 | > { return {{ array[Is]... }}; } 31 | 32 | template 33 | constexpr auto to_array (T (&array)[N]) -> ::std::array, N> { 34 | return (to_array)(array, make_index_sequence { }); 35 | } 36 | 37 | }} /* namespace core::v2 */ 38 | 39 | #endif /* CORE_ARRAY_HPP */ 40 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import guzzle_sphinx_theme 3 | import os 4 | 5 | project = 'MNMLSTC Core' 6 | copyright = 'MNMLSTC' 7 | 8 | version = '2.0' 9 | release = '2.0' 10 | 11 | needs_sphinx = '1.3' 12 | 13 | html_translate_class = 'guzzle_sphinx_theme.HTMLTranslator' 14 | html_theme_path = guzzle_sphinx_theme.html_theme_path() 15 | html_theme = 'guzzle_sphinx_theme' 16 | html_theme_options = dict(project_nav_name='MNMLSTC Core') 17 | 18 | highlight_language = 'cpp' 19 | primary_domain = 'cpp' 20 | 21 | pygments_style = 'manni' 22 | 23 | exclude_patterns = ['_build'] 24 | #templates_path = ['templates'] 25 | source_suffix = '.rst' 26 | master_doc = 'index' 27 | 28 | rst_prolog = ''' 29 | .. role:: cxx(code) 30 | :language: cpp 31 | 32 | .. role:: cmake(code) 33 | :language: cmake 34 | 35 | ''' 36 | 37 | extlinks = { 38 | 'wg21': ('https://wg21.link/%s', ''), 39 | 'issue': ('https://github.com/mnmlstc/core/issues/%s', 'issue') 40 | } 41 | 42 | extensions = [ 43 | 'sphinx.ext.todo', 44 | 'sphinx.ext.githubpages', 45 | 'sphinx.ext.extlinks', 46 | # 'sphinxcontrib.inlinesyntaxhighlight', 47 | # 'sphinxcontrib.versioning' 48 | ] 49 | 50 | todo_include_todos = True 51 | -------------------------------------------------------------------------------- /include/core/string.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_STRING_HPP 2 | #define CORE_STRING_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace core { 10 | inline namespace v2 { 11 | 12 | template 13 | void erase_if (::std::basic_string& str, Predicate pred) { 14 | s.erase(::core::remove_if(str, pred), ::std::end(str)); 15 | } 16 | 17 | template 18 | void erase (::std::basic_string& str, U const& value) { 19 | s.erase(::core::remove(str, value), ::std::end(str)); 20 | } 21 | 22 | }} /* namespace core::v2 */ 23 | 24 | namespace core { 25 | inline namespace v2 { 26 | namespace pmr { 27 | 28 | template > 29 | using basic_string = ::std::basic_string< 30 | CharT, 31 | Traits, 32 | polymorphic_allocator 33 | >; 34 | 35 | using u32string = basic_string; 36 | using u16string = basic_string; 37 | using wstring = basic_string; 38 | using string = basic_string; 39 | 40 | }}} /* namespace core::v2::pmr */ 41 | 42 | #endif /* CORE_STRING_HPP */ 43 | -------------------------------------------------------------------------------- /tests/type-traits.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "catch.hpp" 4 | 5 | namespace { 6 | 7 | struct A { A (A const&); }; 8 | struct B { }; 9 | struct C { }; 10 | struct D { 11 | D (D const&) noexcept; 12 | D& operator = (D const&) noexcept; 13 | }; 14 | 15 | struct E { 16 | E (E const&) = delete; 17 | E (E&&) = delete; 18 | E& operator = (E const&) = delete; 19 | E& operator = (E&&) = delete; 20 | }; 21 | 22 | void swap (B&, B&); 23 | void swap (C&, C&) noexcept; 24 | 25 | } /* nameless namespace */ 26 | 27 | TEST_CASE("type-traits") { 28 | SECTION("is-null-pointer") { 29 | using null = std::nullptr_t; 30 | 31 | CHECK(core::is_null_pointer::value); 32 | CHECK(core::is_null_pointer::value); 33 | CHECK(core::is_null_pointer::value); 34 | CHECK(core::is_null_pointer::value); 35 | } 36 | 37 | SECTION("is-nothrow-swappable") { 38 | CHECK(core::is_nothrow_swappable::value); 39 | CHECK_FALSE(core::is_nothrow_swappable::value); 40 | CHECK_FALSE(core::is_nothrow_swappable::value); 41 | CHECK(core::is_nothrow_swappable::value); 42 | CHECK(core::is_nothrow_swappable::value); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Overview 2 | ======== 3 | 4 | MNMLSTC Core is a C++11 library that adds several library features that are to 5 | be included in C++14 and beyond. A majority of the components of MNMLSTC Core 6 | can also be found in Boost. However, there are distinct behaviorial differences 7 | that are outlined and discussed in this documentation. 8 | 9 | It is recommended that new users read :doc:`usage`. The documentation is 10 | ordered according to the augmented library components, rather than by feature. 11 | 12 | For those who are looking for a specific section in the documentation, having a 13 | glance at the :ref:`Generated Index` might be of assistance. 14 | 15 | A :ref:`search` feature is also available. 16 | 17 | .. toctree:: 18 | :maxdepth: 2 19 | :hidden: 20 | 21 | Using MNMLSTC Core 22 | Type Traits 23 | Functional Utilities 24 | Algorithms 25 | Arrays 26 | Iterator Utilities 27 | Optional Types 28 | Numeric Algorithms 29 | Variant Type 30 | Uncategorized Utilities 31 | Metatemplate Programming 32 | Propagating Const 33 | Memory 34 | String Utilities 35 | Range Type 36 | Any Type 37 | 38 | -------------------------------------------------------------------------------- /include/core/map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_MAP_HPP 2 | #define CORE_MAP_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace core { 10 | inline namespace v2 { 11 | 12 | template 13 | void erase_if (::std::multimap& m, Predicate pred) { 14 | for (auto iter = begin(m); iter != end(m);) { 15 | invoke(pred, *iter) ? iter = m.erase(iter) : ++iter; 16 | } 17 | } 18 | 19 | template 20 | void erase_if (::std::map& m, Predicate pred) { 21 | for (auto iter = begin(m); iter != end(m);) { 22 | invoke(pred, *iter) ? iter = m.erase(iter) : ++iter; 23 | } 24 | } 25 | 26 | }} /* namespace core::v2 */ 27 | 28 | namespace core { 29 | inline namespace v2 { 30 | namespace pmr { 31 | 32 | template > 33 | using multimap = ::std::multimap< 34 | Key, 35 | T, 36 | Compare, 37 | polymorphic_allocator<::std::pair> 38 | >; 39 | 40 | template > 41 | using map = ::std::map< 42 | Key, 43 | T, 44 | Compare, 45 | polymorphic_allocator<::std::pair> 46 | >; 47 | 48 | }}} /* namespace core::v2::pmr */ 49 | 50 | #endif /* CORE_MAP_HPP */ 51 | -------------------------------------------------------------------------------- /include/core/unordered_set.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_UNORDERED_SET_HPP 2 | #define CORE_UNORDERED_SET_HPP 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace core { 9 | inline namespace v2 { 10 | 11 | template 12 | void erase_if (::std::unordered_multiset& m, Predicate pred) { 13 | for (auto iter = begin(m); iter != end(m);) { 14 | invoke(pred, *iter) ? iter = m.erase(iter) : ++iter; 15 | } 16 | } 17 | 18 | template 19 | void erase_if (::std::unordered_set& m, Predicate pred) { 20 | for (auto iter = begin(m); iter != end(m);) { 21 | invoke(pred, *iter) ? iter = m.erase(iter) : ++iter; 22 | } 23 | } 24 | 25 | }} /* namespace core::v2 */ 26 | 27 | namespace core { 28 | inline namespace v2 { 29 | namespace pmr { 30 | 31 | template < 32 | class Key, 33 | class Hash=::std::hash, 34 | class Pred=::std::equal_to 35 | > using unordered_multiset = ::std::unordered_multiset< 36 | Key, 37 | Hash, 38 | Pred, 39 | polymorphic_allocator 40 | >; 41 | 42 | template < 43 | class Key, 44 | class Hash=::std::hash, 45 | class Pred=::std::equal_to 46 | > using unordered_set = ::std::unordered_set< 47 | Key, 48 | Hash, 49 | Pred, 50 | polymorphic_allocator> 51 | >; 52 | 53 | }}} /* namespace core::v2::pmr */ 54 | 55 | #endif /* CORE_UNORDERED_SET_HPP */ 56 | -------------------------------------------------------------------------------- /docs/array.rst: -------------------------------------------------------------------------------- 1 | Array Component 2 | =============== 3 | 4 | .. namespace:: core 5 | 6 | .. index:: array 7 | 8 | The array component currently provides two helper functions for working with 9 | :cxx:`std::array` in the C++ standard library. Specifically, this component 10 | provides an implementation of :wg21:`N4315`. This component can be found in the 11 | :file:`` header. 12 | 13 | .. index:: array; functions 14 | 15 | .. function:: constexpr std::array make_array (Args&&... args) 16 | 17 | Given a parameter pack :samp:`{args}`, return a :cxx:`std::array` with the 18 | :samp:`common_type_t<{Args}...>`. Additionally, a type can be given 19 | explicitly. This function is *does not* participate in overload resolution 20 | if any of the elements in :samp:`{args}` are a 21 | :cxx:`std::reference_wrapper`. 22 | 23 | :example: 24 | 25 | .. code-block:: cpp 26 | 27 | auto a1 = make_array(1, 2, 3, 4); 28 | using type1 = decltype(a1)::value_type; 29 | static_assert(std::is_same::value, ""); 30 | 31 | auto a2 = make_array(1, 2L, 3L, 4); 32 | using type2 = decltype(a2)::value_type; 33 | static_assert(std::is_same::value, ""); 34 | 35 | .. function:: constexpr std::array to_array (T (&array)[N]) 36 | 37 | Given a C array of type :samp:`{T}` with a defined length of :samp:`{N}`, 38 | creates a :cxx:`std::array` with the same length and size. 39 | 40 | This function will copy initialize each :samp:`{T}` 41 | -------------------------------------------------------------------------------- /include/core/unordered_map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_UNORDERED_MAP_HPP 2 | #define CORE_UNORDERED_MAP_HPP 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace core { 9 | inline namespace v2 { 10 | 11 | template 12 | void erase_if (::std::unordered_multimap& m, Predicate pred) { 13 | for (auto iter = begin(m); iter != end(m);) { 14 | invoke(pred, *iter) ? iter = m.erase(iter) : ++iter; 15 | } 16 | } 17 | 18 | template 19 | void erase_if (::std::unordered_map& m, Predicate pred) { 20 | for (auto iter = begin(m); iter != end(m);) { 21 | invoke(pred, *iter) ? iter = m.erase(iter) : ++iter; 22 | } 23 | } 24 | 25 | }} /* namespace core::v2 */ 26 | 27 | namespace core { 28 | inline namespace v2 { 29 | namespace pmr { 30 | 31 | template < 32 | class Key, 33 | class T, 34 | class Hash=::std::hash, 35 | class Pred=::std::equal_to 36 | > using unordered_multimap = ::std::unordered_multimap< 37 | Key, 38 | T, 39 | Hash, 40 | Pred, 41 | polymorphic_allocator<::std::pair> 42 | >; 43 | 44 | template < 45 | class Key, 46 | class T, 47 | class Hash=::std::hash, 48 | class Pred=::std::equal_to 49 | > using unordered_map = ::std::unordered_map< 50 | Key, 51 | T, 52 | Hash, 53 | Pred, 54 | polymorphic_allocator<::std::pair> 55 | >; 56 | 57 | }}} /* namespace core::v2::pmr */ 58 | 59 | #endif /* CORE_UNORDERED_MAP_HPP */ 60 | -------------------------------------------------------------------------------- /tests/iterator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "catch.hpp" 10 | 11 | template 12 | std::ostream& operator << (std::ostream& os, std::vector const& vec) { 13 | os << "["; 14 | std::copy( 15 | core::cbegin(vec), 16 | core::cend(vec), 17 | core::make_ostream_joiner(os, ",") 18 | ); 19 | return os << "]"; 20 | } 21 | 22 | TEST_CASE("iterator") { 23 | std::vector value = { 1, 2, 3, 4, 5 }; 24 | 25 | SECTION("size") { 26 | int array[5]; 27 | CHECK(core::size(value) == value.size()); 28 | static_assert(core::size(array) == 5, "core::size"); 29 | } 30 | 31 | SECTION("empty") { 32 | int array[5]; 33 | CHECK_FALSE(core::empty(value)); 34 | static_assert(not core::empty(array), "core::empty"); 35 | } 36 | 37 | SECTION("front") { 38 | constexpr int array[5] { 0, 1, 2, 3, 4 }; 39 | CHECK(core::front(value) == value.front()); 40 | static_assert(core::front(array) == 0, "core::front"); 41 | } 42 | 43 | SECTION("back") { 44 | constexpr int array[5] { 0, 1, 2, 3, 4 }; 45 | CHECK(core::back(value) == value.back()); 46 | static_assert(core::back(array) == 4, "core::back"); 47 | } 48 | 49 | SECTION("data") { 50 | int array[5] { 1, 2, 3, 4, 5 }; 51 | CHECK(core::data(value) == value.data()); 52 | CHECK(core::data(array) == std::addressof(array[0])); 53 | } 54 | 55 | SECTION("cbegin") { CHECK(core::cbegin(value) == value.begin()); } 56 | SECTION("cend") { CHECK(core::cend(value) == value.end()); } 57 | 58 | SECTION("infix-ostream-iterator") { 59 | std::ostringstream stream; 60 | stream << value; 61 | CHECK(stream.str() == "[1,2,3,4,5]"); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /include/core/typeinfo.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_TYPEINFO_HPP 2 | #define CORE_TYPEINFO_HPP 3 | 4 | #include 5 | #include 6 | 7 | #ifndef CORE_NO_RTTI 8 | #include 9 | #include 10 | #endif /* CORE_NO_RTTI */ 11 | 12 | namespace core { 13 | inline namespace v2 { 14 | 15 | #ifndef CORE_NO_RTTI 16 | using type_info = ::std::type_info; 17 | 18 | template 19 | type_info const& type_of () noexcept { return typeid(T); } 20 | #else /* CORE_NO_RTTI */ 21 | struct type_info final { 22 | 23 | type_info (type_info const&) = delete; 24 | type_info () = delete; 25 | virtual ~type_info () = default; 26 | 27 | type_info& operator = (type_info const&) = delete; 28 | 29 | /* If we had C++14 template variables, this would actually be easier */ 30 | template 31 | friend type_info const& type_of () noexcept { 32 | return type_info::cref>>(); 33 | } 34 | 35 | bool operator == (type_info const& that) const noexcept { 36 | return this->id == that.id; 37 | } 38 | 39 | bool operator != (type_info const& that) const noexcept { 40 | return this->id != that.id; 41 | } 42 | 43 | bool before (type_info const& that) const noexcept { 44 | return this->id < that.id; 45 | } 46 | 47 | ::std::size_t hash_code () const noexcept { return this->id; } 48 | 49 | private: 50 | type_info (::std::uintptr_t id) noexcept : id { id } { } 51 | 52 | template 53 | static type_info const& cref () noexcept { 54 | static ::std::uintptr_t const value { }; 55 | static type_info const instance { as_int(::std::addressof(value)) }; 56 | return instance; 57 | } 58 | 59 | ::std::uintptr_t const id; 60 | }; 61 | 62 | #endif /* CORE_NO_RTTI */ 63 | 64 | }} /* namespace core::v2 */ 65 | 66 | #endif /* CORE_TYPEINFO_HPP */ 67 | -------------------------------------------------------------------------------- /tests/functional.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include "catch.hpp" 13 | 14 | TEST_CASE("apply", "[functional]") { 15 | SECTION("tuple") { 16 | auto result = core::apply( 17 | [] (int x, std::string const& y) { return std::to_string(x) + y; }, 18 | std::forward_as_tuple(4, "apply")); 19 | CHECK(result == "4apply"); 20 | } 21 | 22 | SECTION("array") { 23 | std::array values {{ 1, 2, 3 }}; 24 | auto result = core::apply( 25 | [] (int x, int y, int z) { return x + y + z; }, 26 | values); 27 | CHECK(result == 6); 28 | } 29 | 30 | SECTION("pair") { 31 | auto result = core::apply( 32 | [] (int x, std::string y) { return std::to_string(x) + y; }, 33 | std::make_pair(7, "apply")); 34 | CHECK(result == "7apply"); 35 | } 36 | } 37 | 38 | TEST_CASE("functional") { 39 | SECTION("function-traits") { 40 | auto empty_lambda = []{}; 41 | auto empty_arity = core::function_traits::arity; 42 | auto mem_fn_arity = core::function_traits< 43 | decltype(&std::string::size) 44 | >::arity; 45 | 46 | static_assert( 47 | std::is_same< 48 | std::string const&, 49 | core::function_traits::argument<0> 50 | >::value, 51 | "function-traits-arity incorrect size" 52 | ); 53 | CHECK(mem_fn_arity == 1u); 54 | CHECK(empty_arity == 0u); 55 | } 56 | 57 | SECTION("issue-40") { 58 | struct A { }; 59 | struct B { }; 60 | struct C { }; 61 | 62 | using fun = core::add_pointer_t; 63 | using first_argument = core::function_traits::argument<0>; 64 | using second_argument = core::function_traits::argument<1>; 65 | 66 | static_assert(std::is_same::value, "Type Mismatch"); 67 | static_assert(std::is_same::value, "Type Mismatch"); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Readme.rst: -------------------------------------------------------------------------------- 1 | Overview 2 | ======== 3 | 4 | MNMLSTC Core is a small and easy to use C++11 library that adds a functionality 5 | set that will be available in C++14 and later, as well as some useful 6 | additions, or some proposals that have not been completely approved yet. 7 | 8 | Information on installing and using MNMLSTC Core can be found in its 9 | `documentation `_. 10 | 11 | MNMLSTC Core is released under the Apache 2.0 License. 12 | Build scripts provided by MNMLSTC Core are released under the CC0 1.0 Universal 13 | License. 14 | 15 | .. image:: https://travis-ci.org/mnmlstc/core.svg 16 | :target: https://travis-ci.org/mnmlstc/core 17 | 18 | .. image:: https://codecov.io/gh/mnmlstc/core/branch/master/graph/badge.svg 19 | :target: https://codecov.io/gh/mnmlstc/core 20 | 21 | Components 22 | ---------- 23 | 24 | Some components provided by MNMLSTC Core are: 25 | 26 | * ``variant`` 27 | * ``optional`` 28 | * ``expected`` 29 | * ``deep_ptr`` 30 | * ``poly_ptr`` 31 | * ``string_view`` 32 | * ``range`` 33 | * ``any`` 34 | 35 | Details on each component can be found in MNMLSTC Core's documentation. All of 36 | the MNMLSTC Core components reside in the ``core`` namespace. The library is 37 | organized equivalent to the standard library e.g., components related to memory 38 | are in the memory header, functional components in the functional header, etc. 39 | 40 | Requirements 41 | ------------ 42 | 43 | There are several requirements to fully use MNMLSTC Core: 44 | 45 | * A C++11 compliant compiler (GCC 4.8.1 or Clang 3.4 meet the minimum feature 46 | set required to build and use MNMLSTC Core) 47 | * `CMake 3.0.0 `_ 48 | 49 | Additionally, to develop or package MNMLSTC Core, the following are required: 50 | 51 | * `Sphinx Documentation Generator `_ 52 | * `Guzzle Sphinx Theme `_ 53 | * `WiX Toolset `_ 54 | 55 | Sphinx and the Guzzle Sphinx Theme are only necessary if generating 56 | documentation manually to be included with the package. 57 | 58 | WiX Toolset is only required if building packages for Windows. 59 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Matrix Build Declaration 2 | language: cpp 3 | sudo: required 4 | dist: trusty 5 | branches: 6 | except: 7 | - gh_pages 8 | 9 | before_install: bash ./scripts/travis-before-install 10 | before_script: bash ./scripts/travis-configure 11 | install: bash ./scripts/travis-install 12 | script: cmake --build build --target check -- CTEST_OUTPUT_ON_FAILURE=1 VERBOSE=1 13 | after_success: bash <(curl -s https://codecov.io/bash) 14 | 15 | matrix: 16 | include: 17 | - os: linux 18 | compiler: gcc 19 | env: BUILD=Release VERSION=5 20 | - os: linux 21 | compiler: gcc 22 | env: BUILD=Debug VERSION=5 23 | - os: linux 24 | compiler: gcc 25 | env: BUILD=Release VERSION=6 26 | - os: linux 27 | compiler: gcc 28 | env: BUILD=Debug VERSION=6 29 | - os: linux 30 | compiler: clang 31 | env: BUILD=Release VERSION=3.7 32 | - os: linux 33 | compiler: clang 34 | env: BUILD=Debug VERSION=3.7 35 | - os: linux 36 | compiler: clang 37 | env: BUILD=Release VERSION=3.8 38 | - os: linux 39 | compiler: clang 40 | env: BUILD=Debug VERSION=3.8 41 | - os: linux 42 | compiler: clang 43 | env: BUILD=Release VERSION=3.9 44 | - os: linux 45 | compiler: clang 46 | env: BUILD=Debug VERSION=3.9 47 | - os: linux 48 | compiler: clang 49 | env: BUILD=Release VERSION=3.7 LIBCXX=ON 50 | - os: linux 51 | compiler: clang 52 | env: BUILD=Release VERSION=3.7 LIBCXX=ON 53 | - os: linux 54 | compiler: clang 55 | env: BUILD=Release VERSION=3.8 LIBCXX=ON 56 | - os: linux 57 | compiler: clang 58 | env: BUILD=Debug VERSION=3.8 LIBCXX=ON 59 | - os: linux 60 | compiler: clang 61 | env: BUILD=Release VERSION=3.9 LIBCXX=ON 62 | - os: linux 63 | compiler: clang 64 | env: BUILD=Debug VERSION=3.9 LIBCXX=ON 65 | - os: osx 66 | osx_image: xcode6.4 67 | compiler: clang 68 | env: BUILD=Release 69 | - os: osx 70 | osx_image: xcode6.4 71 | compiler: clang 72 | env: BUILD=Debug 73 | - os: osx 74 | osx_image: xcode7.3 75 | compiler: clang 76 | env: BUILD=Release 77 | - os: osx 78 | osx_image: xcode7.3 79 | compiler: clang 80 | env: BUILD=Debug 81 | - os: osx 82 | osx_image: xcode8 83 | compiler: clang 84 | env: BUILD=Release 85 | - os: osx 86 | osx_image: xcode8 87 | compiler: clang 88 | env: BUILD=Debug 89 | - os: osx 90 | osx_image: xcode8 91 | compiler: clang 92 | env: BUILD=Release, CXX_STANDARD=c++1z 93 | - os: osx 94 | osx_image: xcode8 95 | compiler: clang 96 | env: BUILD=Debug, CXX_STANDARD=c++1z 97 | -------------------------------------------------------------------------------- /tests/numeric.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include "catch.hpp" 7 | 8 | TEST_CASE("numeric") { 9 | SECTION("iota") { 10 | std::vector values = { 0, 0, 0, 0, 0 }; 11 | core::iota(values, 0); 12 | CHECK(values[0] == 0); 13 | CHECK(values[1] == 1); 14 | CHECK(values[2] == 2); 15 | CHECK(values[3] == 3); 16 | CHECK(values[4] == 4); 17 | } 18 | 19 | SECTION("accumulate") { 20 | std::vector values = { 1, 2, 3, 4 }; 21 | auto result = core::accumulate(values, 0); 22 | CHECK(result == 10); 23 | result = core::accumulate(values, 1, std::multiplies { }); 24 | CHECK(result == 24); 25 | } 26 | 27 | SECTION("inner-product") { 28 | std::vector value_one { 0, 1, 2, 3, 4 }; 29 | std::vector value_two { 5, 4, 3, 2, 1 }; 30 | auto result = core::inner_product(value_one, ::std::begin(value_two), 0); 31 | CHECK(result == 20); 32 | result = core::inner_product( 33 | value_one, 34 | std::begin(value_two), 35 | 1, 36 | std::multiplies { }, 37 | std::plus { } 38 | ); 39 | CHECK(result == 3125); 40 | } 41 | 42 | SECTION("adjacent-difference") { 43 | std::vector values { 2, 4, 6, 8, 10 }; 44 | auto result = std::vector(values.size()); 45 | core::adjacent_difference(values, std::begin(result)); 46 | CHECK(result[0] == 2); 47 | CHECK(result[1] == 2); 48 | CHECK(result[2] == 2); 49 | CHECK(result[3] == 2); 50 | CHECK(result[4] == 2); 51 | 52 | core::adjacent_difference(values, std::begin(result), std::plus { }); 53 | CHECK(result[0] == 2); 54 | CHECK(result[1] == 6); 55 | CHECK(result[2] == 10); 56 | CHECK(result[3] == 14); 57 | CHECK(result[4] == 18); 58 | } 59 | 60 | SECTION("partial-sum") { 61 | std::vector values { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; 62 | auto result = std::vector(values.size()); 63 | 64 | core::partial_sum(values, std::begin(result)); 65 | CHECK(result[0] == 2); 66 | CHECK(result[1] == 4); 67 | CHECK(result[2] == 6); 68 | CHECK(result[3] == 8); 69 | CHECK(result[4] == 10); 70 | CHECK(result[5] == 12); 71 | CHECK(result[6] == 14); 72 | CHECK(result[7] == 16); 73 | CHECK(result[8] == 18); 74 | CHECK(result[9] == 20); 75 | 76 | core::partial_sum(values, std::begin(result), std::multiplies { }); 77 | CHECK(result[0] == 2); 78 | CHECK(result[1] == 4); 79 | CHECK(result[2] == 8); 80 | CHECK(result[3] == 16); 81 | CHECK(result[4] == 32); 82 | CHECK(result[5] == 64); 83 | CHECK(result[6] == 128); 84 | CHECK(result[7] == 256); 85 | CHECK(result[8] == 512); 86 | CHECK(result[9] == 1024); 87 | 88 | 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /docs/numeric.rst: -------------------------------------------------------------------------------- 1 | Numeric Component 2 | ================= 3 | 4 | .. namespace:: core 5 | 6 | .. index:: numeric 7 | 8 | The numeric component is a wrapper around the C++ stdlib :file:`<{numeric}>` 9 | header. The functions contained within this header take a range of values. 10 | However, as is common in the C++ standard library, it requires the user to 11 | provide a begin and end to the range of elements. Because MNMLSTC Core provides 12 | a :any:`range` type, there is no logical reason a version of these functions 13 | that take a range are not provided. 14 | 15 | The numeric component resides in the :file:`` header. 16 | 17 | .. note:: Several functions in this component take a range as its input, and 18 | an output iterator for output. These functions *do not* change the output 19 | to also be a range. An iterator *must* be passed to them (This reduces the 20 | number of overloads needed while also allowing the continued use of 21 | :cxx:`std::back_insert_iterator` and friends. 22 | 23 | .. index:: numeric; functions 24 | 25 | .. function:: void iota (Range&& range, T&& value) 26 | 27 | Fills :samp:`{range}` with sequentially increasing values, starting with 28 | :samp:`{value}`. While :samp:`{range}` is treated as a forwarding reference, 29 | its lifetime should extend past that of the call to :any:`iota`, in the 30 | event that :samp:`{range}` is an rvalue reference. The :samp:`{value}` is 31 | simply perfectly forwarded to the underlying :cxx:`std::iota` call. 32 | 33 | :requires: :samp:`{range}` must provide ForwardIterators 34 | 35 | .. function:: decay_t accumulate (Range&& range, T&& init) 36 | decay_t accumulate (Range&& range, T&&, BinaryOp&& op) 37 | 38 | Computes the sum of the given value :samp:`{init}` and the elements in 39 | :samp:`{range}`. The first version uses :cxx:`operator +`, while the second 40 | version uses :samp:`{op}`. Both :samp:`{init}` and :samp:`{op}` are 41 | perfectly forwarded. The lifetime of :samp:`{range}` may end with the call 42 | to this function. 43 | 44 | :requires: :samp:`{range}` must provide InputIterators. 45 | 46 | .. function:: decay_t inner_product (Range&& range, InputIt&& it, T&& value) 47 | decay_t inner_product (\ 48 | Range&& range, \ 49 | InputIt&& it, \ 50 | T&& value, \ 51 | BinaryOp&& op, \ 52 | BinaryOp2&& op2) 53 | 54 | Computes the inner product (that is, the sum of products of the elements in 55 | :samp:`{range}`). The first version uses ``operator *`` to compute the 56 | product of element pairs and :cxx:`operator +` to sum the products. The 57 | second version uses :samp:`{op}` and :samp:`{op2}` for these tasks 58 | respectively. 59 | 60 | :requires: :samp:`{range}` must provide InputIterators 61 | 62 | .. function:: decay_t adjacent_difference (\ 63 | Range&& range, \ 64 | OutputIt&& it) 65 | decay_t adjacent_difference (\ 66 | Range&& range, \ 67 | OutputIt&& it, \ 68 | BinaryOp&& op) 69 | 70 | Computes the differences between the second and the first of each adjacent 71 | pair of elements in :samp:`{range}`, and writes them to the range beginning 72 | at :samp:`{it} + 1`. The first version uses ``operator -``, while the second 73 | uses :samp:`{op}`. These parameters are perfectly forwarded to the 74 | underlying call to ``std::adjacent_difference``. 75 | 76 | :requires: :samp:`{range}` must provide InputIterators. 77 | 78 | .. function:: decay_t partial_sum (Range&& range, OutputIt&& it) 79 | decay_t partial_sum (\ 80 | Range&& range, \ 81 | OutputIt&& it, \ 82 | BinaryOp&& op) 83 | 84 | Computes the partial sum of the slemenets in the subranges of 85 | :samp:`{range}`. It then writes these values to the range beginning at 86 | :samp:`{it}`. The first version uses ``operator +``, while the second uses 87 | the binary operation :samp:`{op}`. 88 | 89 | :requires: :samp:`{range}` must provide InputIterators. 90 | -------------------------------------------------------------------------------- /package/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | list(APPEND SOURCE_GENERATORS TBZ2) 2 | list(APPEND SOURCE_GENERATORS TGZ) 3 | list(APPEND SOURCE_GENERATORS TXZ) 4 | list(APPEND SOURCE_GENERATORS ZIP) 5 | list(APPEND SOURCE_GENERATORS 7Z) 6 | 7 | if (NOT WIN32) 8 | list(APPEND BINARY_GENERATORS STGZ) 9 | endif () 10 | 11 | if (BUILD_PACKAGE_MSI) 12 | list(APPEND BINARY_GENERATORS "WIX") 13 | endif () 14 | 15 | if (BUILD_PACKAGE_RPM) 16 | list(APPEND BINARY_GENERATORS "RPM") 17 | endif () 18 | 19 | #------------------------------------------------------------------------------ 20 | # Generic Package Settings 21 | #------------------------------------------------------------------------------ 22 | set(CPACK_OUTPUT_FILE_PREFIX ${PACK_BINARY_DIR}) 23 | 24 | set(CPACK_GENERATOR ${BINARY_GENERATORS}) 25 | set(CPACK_SOURCE_GENERATOR ${SOURCE_GENERATORS}) 26 | 27 | set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) 28 | set(CPACK_PACKAGE_VENDOR MNMLSTC) 29 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "C++14 library features for C++11") 30 | set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/Readme.rst") 31 | 32 | set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/License.rst") 33 | 34 | set(CPACK_PACKAGE_VERSION_MAJOR ${CORE_VERSION_MAJOR}) 35 | set(CPACK_PACKAGE_VERSION_MINOR ${CORE_VERSION_MINOR}) 36 | set(CPACK_PACKAGE_VERSION_PATCH ${CORE_VERSION_PATCH}) 37 | 38 | set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${PROJECT_VERSION}") 39 | set(CPACK_SOURCE_PACKAGE_FILE_NAME ${CPACK_PACKAGE_FILE_NAME}) 40 | 41 | # Intended for installers such as NSIS or WIX 42 | set(CPACK_PACKAGE_INSTALL_DIRECTORY "mnmlstc/${PROJECT_NAME}") 43 | 44 | list(APPEND CPACK_SOURCE_IGNORE_FILES "/build-clang/") 45 | list(APPEND CPACK_SOURCE_IGNORE_FILES "/build-msvc/") 46 | list(APPEND CPACK_SOURCE_IGNORE_FILES "/build-gcc/") 47 | list(APPEND CPACK_SOURCE_IGNORE_FILES "/build/") 48 | list(APPEND CPACK_SOURCE_IGNORE_FILES "/.git/") 49 | 50 | list(APPEND CPACK_SOURCE_IGNORE_FILES ".gitattributes") 51 | list(APPEND CPACK_SOURCE_IGNORE_FILES ".travis.yml") 52 | list(APPEND CPACK_SOURCE_IGNORE_FILES ".gitignore") 53 | list(APPEND CPACK_SOURCE_IGNORE_FILES ".DS_Store") 54 | 55 | list(APPEND CPACK_SOURCE_IGNORE_FILES "appveyor.yml") 56 | #------------------------------------------------------------------------------ 57 | # Wix Configuration 58 | #------------------------------------------------------------------------------ 59 | set(CPACK_WIX_CMAKE_PACKAGE_REGISTRY ${PROJECT_NAME}) 60 | set(CPACK_WIX_UPGRADE_GUID "AE6C6986-200F-464C-83EF-C3A94C6C9995") 61 | set(CPACK_WIX_PRODUCT_GUID "*") 62 | set(CPACK_WIX_PRODUCT_ICON "${PACK_SOURCE_DIR}/mnmlstc.ico") 63 | set(CPACK_WIX_LICENSE_RTF "${PACK_SOURCE_DIR}/License.rtf") 64 | set(CPACK_WIX_UI_BANNER "${PACK_SOURCE_DIR}/banner.bmp") 65 | set(CPACK_WIX_UI_DIALOG "${PACK_SOURCE_DIR}/dialog.bmp") 66 | 67 | #------------------------------------------------------------------------------ 68 | # RPM Configuration 69 | #------------------------------------------------------------------------------ 70 | set(CPACK_RPM_PACKAGE_ARCHITECTURE noarch) 71 | set(CPACK_RPM_PACKAGE_RELEASE 1) 72 | set(CPACK_RPM_PACKAGE_LICENSE "ASL 2.0") 73 | set(CPACK_RPM_PACKAGE_GROUP "Development/Libraries") 74 | 75 | # Prevents CPack from generating file conflicts 76 | set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/usr/share/doc/mnmlstc") 77 | list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/usr/share/cmake") 78 | 79 | #------------------------------------------------------------------------------ 80 | # Finalize 81 | #------------------------------------------------------------------------------ 82 | include(CPack) 83 | 84 | # Create some custom commands to piggy back off of CPack 85 | # If not on OS X, we create an "empty" command for 'dist' 86 | if (APPLE AND BUILD_PACKAGE_PKG) 87 | find_package(PythonInterp REQUIRED) 88 | add_custom_target(pkgbuild 89 | COMMAND ${PYTHON_EXECUTABLE} 90 | ${PROJECT_SOURCE_DIR}/scripts/pkgbuild.py 91 | -b ${CMAKE_BINARY_DIR} 92 | -r ${PACK_SOURCE_DIR} 93 | COMMENT "Run pkgbuild.py packaging script" 94 | VERBATIM) 95 | else () 96 | add_custom_target(pkgbuild COMMAND ${CMAKE_COMMAND} -E sleep 0 VERBATIM) 97 | endif () 98 | 99 | # A 'nice' 100 | add_custom_target(source 101 | COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target package_source 102 | VERBATIM) 103 | add_custom_target(dist 104 | COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target package 105 | COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target source 106 | COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target pkgbuild 107 | VERBATIM) 108 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0.0) 2 | project(core VERSION 2.0.0 LANGUAGES CXX) 3 | 4 | #------------------------------------------------------------------------------ 5 | # Modules, Variables, and Options 6 | #------------------------------------------------------------------------------ 7 | include(CMakePackageConfigHelpers) 8 | include(CMakeDependentOption) 9 | include(CTest) 10 | 11 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 12 | 13 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 14 | 15 | if (NOT DEFINED CMAKE_CXX_STANDARD_REQUIRED OR CMAKE_CXX_STANDARD_REQUIRED) 16 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 17 | set(CMAKE_CXX_STANDARD 11) 18 | set(CMAKE_CXX_EXTENSIONS OFF) # would enable -std=gnu++11 19 | endif() 20 | 21 | set(INCLUDE_INSTALL_DIR "include" CACHE INTERNAL "Header Files") 22 | set(CMAKE_INSTALL_DIR "share/cmake/core" CACHE INTERNAL "CMake Files") 23 | set(DOCS_INSTALL_DIR "share/doc/mnmlstc/core" CACHE INTERNAL "Documentation") 24 | 25 | set(TEST_SOURCE_DIR "${PROJECT_SOURCE_DIR}/tests") 26 | set(TEST_BINARY_DIR "${PROJECT_BINARY_DIR}/tests") 27 | 28 | set(DOCS_SOURCE_DIR "${PROJECT_SOURCE_DIR}/docs") 29 | set(DOCS_BINARY_DIR "${PROJECT_BINARY_DIR}/docs") 30 | 31 | set(PACK_SOURCE_DIR "${PROJECT_SOURCE_DIR}/package") 32 | set(PACK_BINARY_DIR "${PROJECT_BINARY_DIR}/package") 33 | 34 | # Used by cmake-dependent-option 35 | list(APPEND RPM_DEP "UNIX" "NOT APPLE" "BUILD_PACKAGE") 36 | list(APPEND PKG_DEP "APPLE" "BUILD_PACKAGE") 37 | list(APPEND MSI_DEP "WIN32" "BUILD_PACKAGE") 38 | 39 | option(BUILD_WITH_LIBCXX "Use libc++ as stdlib (affects unittests)" OFF) 40 | option(BUILD_PACKAGE "Build package with CPack" OFF) 41 | option(BUILD_DOCS "Build documentation with Sphinx Documentation Generator" OFF) 42 | 43 | option(DISABLE_EXCEPTIONS "Configures Core to not use exceptions" OFF) 44 | option(DISABLE_RTTI "Configures Core to not use RTTI" OFF) 45 | 46 | cmake_dependent_option(BUILD_PACKAGE_MSI "Create an MSI" ON "${MSI_DEP}" OFF) 47 | cmake_dependent_option(BUILD_PACKAGE_RPM "Create an RPM" ON "${RPM_DEP}" OFF) 48 | cmake_dependent_option(BUILD_PACKAGE_PKG "Create a PKG" ON "${PKG_DEP}" OFF) 49 | cmake_dependent_option(BUILD_WITH_LIBCXX "Use libc++" OFF "BUILD_TESTING" OFF) 50 | cmake_dependent_option(BUILD_WITH_COVERAGE "Use GCov" OFF "BUILD_TESTING" OFF) 51 | 52 | #------------------------------------------------------------------------------ 53 | # Configuration 54 | #------------------------------------------------------------------------------ 55 | add_library(core INTERFACE) 56 | 57 | write_basic_package_version_file( 58 | "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake" 59 | COMPATIBILITY SameMajorVersion) 60 | 61 | configure_package_config_file( 62 | "${PACK_SOURCE_DIR}/${PROJECT_NAME}-config.cmake.in" 63 | "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" 64 | INSTALL_DESTINATION "${CMAKE_INSTALL_DIR}") 65 | 66 | target_include_directories(core INTERFACE 67 | $ 68 | $) 69 | target_compile_definitions(core INTERFACE 70 | $<$:CORE_NO_EXCEPTIONS> 71 | $<$:CORE_NO_RTTI>) 72 | 73 | export(TARGETS core NAMESPACE mnmlstc:: FILE core-export.cmake) 74 | export(PACKAGE core) 75 | 76 | if (BUILD_TESTING) 77 | set(CMAKE_TEST_COMMAND ctest) 78 | add_subdirectory("${TEST_SOURCE_DIR}" "${TEST_BINARY_DIR}") 79 | endif () 80 | 81 | if (BUILD_DOCS) 82 | add_subdirectory("${DOCS_SOURCE_DIR}" "${DOCS_BINARY_DIR}" EXCLUDE_FROM_ALL) 83 | endif () 84 | 85 | if (BUILD_PACKAGE) 86 | add_subdirectory("${PACK_SOURCE_DIR}" "${PACK_BINARY_DIR}" EXCLUDE_FROM_ALL) 87 | endif () 88 | 89 | #------------------------------------------------------------------------------ 90 | # Install 91 | #------------------------------------------------------------------------------ 92 | install(FILES 93 | ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake 94 | ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake 95 | DESTINATION ${CMAKE_INSTALL_DIR}) 96 | 97 | install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/core" 98 | DESTINATION ${INCLUDE_INSTALL_DIR} 99 | FILES_MATCHING PATTERN "*.hpp") 100 | 101 | install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets) 102 | install( 103 | EXPORT ${PROJECT_NAME}-targets 104 | NAMESPACE mnmlstc:: 105 | DESTINATION ${CMAKE_INSTALL_DIR}) 106 | 107 | if (BUILD_DOCS) 108 | install(DIRECTORY "${DOCS_BINARY_DIR}/" 109 | DESTINATION ${DOCS_INSTALL_DIR} 110 | FILES_MATCHING 111 | PATTERN ".buildinfo" EXCLUDE 112 | PATTERN "CMakeFiles" EXCLUDE 113 | PATTERN ".doctrees" EXCLUDE 114 | PATTERN "Makefile" EXCLUDE 115 | PATTERN "*.cmake" EXCLUDE 116 | PATTERN "*" 117 | ) 118 | endif () 119 | -------------------------------------------------------------------------------- /include/core/internal.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_INTERNAL_HPP 2 | #define CORE_INTERNAL_HPP 3 | 4 | /* This is a header containing common implementation specific code, to 5 | * reduce the complexity of the other headers, especially those that are 6 | * closely intertwined, such as and 7 | * 8 | * Additionally, some of this code is duplicated elsewhere (such as class_of, 9 | * and meta::identity), but aliases are placed to lessen any impact that this 10 | * might have. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | namespace core { 21 | inline namespace v2 { 22 | namespace impl { 23 | 24 | template class, class...> 25 | struct make_detect : meta::identity { using value_t = ::std::false_type; }; 26 | template class U, class... Args> 27 | struct make_detect>, U, Args...> : 28 | meta::identity> 29 | { using value_t = ::std::true_type; }; 30 | 31 | /* extremely useful custom type traits */ 32 | template struct class_of : meta::identity { }; 33 | template 34 | struct class_of : meta::identity { }; 35 | 36 | /* aliases */ 37 | template using class_of_t = typename class_of::type; 38 | template using decay_t = typename ::std::decay::type; 39 | template 40 | using remove_reference_t = typename ::std::remove_reference::type; 41 | template 42 | using enable_if_t = typename ::std::enable_if::type; 43 | 44 | /* is_nothrow_swappable plumbing */ 45 | using ::std::declval; 46 | using ::std::swap; 47 | 48 | // MSVC 2015 workaround 49 | template 50 | struct is_swappable_with { 51 | template 52 | static auto test (void*) noexcept(true) -> decltype( 53 | swap(declval(), declval()) 54 | ); 55 | 56 | template 57 | static void test (...) noexcept(false); 58 | 59 | static constexpr bool value = noexcept(test(nullptr)); 60 | }; 61 | 62 | // MSVC 2015 workaround 63 | template 64 | struct is_noexcept_swappable_with { 65 | template < 66 | class X, 67 | class Y, 68 | bool B=noexcept(swap(declval(), declval())) 69 | > static void test (enable_if_t*) noexcept(true); 70 | 71 | template 72 | static void test (...) noexcept(false); 73 | 74 | static constexpr bool value = noexcept(test(nullptr)); 75 | }; 76 | 77 | template 78 | struct is_swappable : ::std::false_type { }; 79 | 80 | template 81 | struct is_swappable< 82 | T, 83 | U, 84 | meta::deduce< 85 | is_swappable_with, 86 | is_swappable_with 87 | > 88 | > : ::std::true_type { }; 89 | 90 | template 91 | struct is_nothrow_swappable : meta::all_t< 92 | is_swappable::value, 93 | is_noexcept_swappable_with::value, 94 | is_noexcept_swappable_with::value 95 | > { }; 96 | 97 | /* 98 | * If I can't amuse myself when working with C++ templates, then life isn't 99 | * worth living. Bury me with my chevrons. 100 | */ 101 | template 102 | constexpr T&& pass (remove_reference_t& t) noexcept { 103 | return static_cast(t); 104 | } 105 | 106 | template 107 | constexpr T&& pass (remove_reference_t&& t) noexcept { 108 | return static_cast(t); 109 | } 110 | 111 | /* INVOKE pseudo-expression plumbing, *much* more simplified than previous 112 | * versions of Core 113 | */ 114 | struct undefined { constexpr undefined (...) noexcept { } }; 115 | 116 | /* We get some weird warnings under clang, so we actually give these functions 117 | * a body to get rid of it. 118 | */ 119 | template 120 | constexpr undefined INVOKE (undefined, Args&&...) noexcept { 121 | return undefined { }; 122 | } 123 | 124 | template 125 | constexpr auto INVOKE (Functor&& f, Args&&... args) -> enable_if_t< 126 | not ::std::is_member_pointer>::value, 127 | decltype(pass(f)(pass(args)...)) 128 | > { return pass(f)(pass(args)...); } 129 | 130 | template 131 | auto INVOKE (Functor&& f, Args&&... args) -> enable_if_t< 132 | ::std::is_member_pointer>::value, 133 | decltype(::std::mem_fn(pass(f))(pass(args)...)) 134 | > { return ::std::mem_fn(pass(f))(pass(args)...); } 135 | 136 | template struct invoke_of { }; 137 | template struct invoke_of : 138 | meta::identity()...))> 139 | { }; 140 | 141 | }}} /* namespace core::v2::impl */ 142 | 143 | #endif /* CORE_INTERNAL_HPP */ 144 | -------------------------------------------------------------------------------- /scripts/pkgbuild.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # pkgbuild.py - generate .pkg files on OS X 4 | # Written in 2015 by MNMLSTC 5 | # To the extent possible under law, the author(s) have dedicated all copyright 6 | # and related and neighboring rights to this software to the public domain 7 | # worldwide. This software is distributed without any warranty. You should have 8 | # received a copy of the CC0 Public Domain Dedication along with this software. 9 | # If not, see . 10 | 11 | # This file exists until CPack gets support for pkg files on OS X once more 12 | 13 | # Example usage from 'root' project directory: 14 | # python scripts/pkgbuild.py -r package -b build-clang 15 | # From inside build directory: 16 | # python ../scripts/pkgbuild.py -r ../package -b . 17 | # NOTE: This script is run as part of 'make dist' within the MNMLSTC Core 18 | # build system. 19 | 20 | from __future__ import print_function 21 | from contextlib import contextmanager 22 | from argparse import ArgumentDefaultsHelpFormatter 23 | from argparse import ArgumentParser 24 | import subprocess 25 | import shutil 26 | import string 27 | import json 28 | import sys 29 | import os 30 | 31 | class LocateError(Exception): 32 | def __init__ (self, path): self.path = path 33 | def __str__ (self): return 'Could not locate {}'.format(self.path) 34 | 35 | def exit (error): sys.exit(str(error)) 36 | 37 | @contextmanager 38 | def pushd (directory): 39 | if not os.path.exists(directory): raise LocateError(directory) 40 | old = os.getcwd() 41 | os.chdir(directory) 42 | yield 43 | os.chdir(old) 44 | 45 | def execute(*command): 46 | proc = subprocess.Popen(command, universal_newlines=True) 47 | _, _ = proc.communicate() 48 | code = proc.returncode 49 | if not code: return code 50 | sys.exit(code) 51 | 52 | def which (name): 53 | path, _ = os.path.split(name) 54 | if path and os.access(path, os.X_OK): return name 55 | for path in os.environ['PATH'].split(os.pathsep): 56 | test = os.path.join(path, name) 57 | if os.access(test, os.X_OK): return test 58 | raise LocateError(name) 59 | 60 | # sets up all our program arguments 61 | # placed here for easy reading 62 | def parser (): 63 | p = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter) 64 | add = p.add_argument 65 | add('-r', '--resource', help='resource directory', required=True, type=str) 66 | add('-b', '--build', help='cmake build directory', required=True, type=str) 67 | 68 | add('--prefix', help='installation prefix', default='/usr/local', type=str) 69 | return p 70 | 71 | def read (path): 72 | with open(path) as f: return f.read() 73 | 74 | def template (path): return string.Template(read(path)) 75 | def load (path): return json.loads(read(path)) 76 | 77 | PKG_ROOT = '_CPack_Packages/Darwin/PKG' 78 | SRC_ROOT = '_CPack_Packages/Darwin/STGZ' 79 | 80 | if __name__ == '__main__': 81 | productbuild = which('productbuild') 82 | pkgbuild = which('pkgbuild') 83 | 84 | p = parser() 85 | args = p.parse_args() 86 | 87 | resource = os.path.abspath(args.resource) 88 | 89 | config_file = os.path.join(resource, 'pkg.json') 90 | try: data = load(config_file) 91 | except Exception as e: exit(e) 92 | 93 | template_file = os.path.join(resource, data['template']) 94 | try: distribution = template(template_file) 95 | except Exception as e: exit(e) 96 | 97 | # Don't care if we error with an exception here 98 | pkg_identifier = data['identifier'] 99 | pkg_version = data['version'] 100 | pkg_name = '{}-{}'.format(data['package'], pkg_version) 101 | 102 | license_file = os.path.join(resource, data['license']) 103 | 104 | build_dir = os.path.join(os.getcwd(), args.build) 105 | package_dir = os.path.join(build_dir, 'package') 106 | distribution_xml = os.path.join(PKG_ROOT, 'distribution.xml') 107 | resources_dir = os.path.join(PKG_ROOT, 'resources') 108 | 109 | pkgbuild_args = [ 110 | pkgbuild, 111 | '--quiet', 112 | '--root', os.path.join(PKG_ROOT, pkg_name), 113 | '--identifier', pkg_identifier, 114 | '--install-location', args.prefix, 115 | '--version', pkg_version, 116 | os.path.join(PKG_ROOT, '{}.pkg'.format(pkg_name)) 117 | ] 118 | 119 | productbuild_args = [ 120 | productbuild, 121 | '--quiet', 122 | '--distribution', distribution_xml, 123 | '--resource', resources_dir, 124 | '--package-path', PKG_ROOT, 125 | '--version', pkg_version, 126 | os.path.join(package_dir, '{}.pkg'.format(pkg_name)) 127 | ] 128 | 129 | with pushd(build_dir): 130 | if os.path.exists(PKG_ROOT): shutil.rmtree(PKG_ROOT) 131 | os.makedirs(PKG_ROOT) 132 | os.makedirs(resources_dir) 133 | shutil.copytree( 134 | os.path.join(SRC_ROOT, pkg_name), 135 | os.path.join(PKG_ROOT, pkg_name)) 136 | shutil.copy(license_file, resources_dir) 137 | with open(distribution_xml, 'w') as dist: 138 | dist.write(distribution.safe_substitute(data)) 139 | execute(*pkgbuild_args) 140 | execute(*productbuild_args) 141 | -------------------------------------------------------------------------------- /include/core/utility.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_UTILITY_HPP 2 | #define CORE_UTILITY_HPP 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | namespace core { 11 | inline namespace v2 { 12 | 13 | template 14 | constexpr T&& forward (remove_reference_t& t) noexcept { 15 | return static_cast(t); 16 | } 17 | 18 | template 19 | constexpr T&& forward (remove_reference_t&& t) noexcept { 20 | return static_cast(t); 21 | } 22 | 23 | template 24 | constexpr auto move (T&& t) noexcept -> decltype( 25 | static_cast&&>(t) 26 | ) { return static_cast&&>(t); } 27 | 28 | 29 | template 30 | using integer_sequence = meta::integer_sequence; 31 | 32 | template <::std::size_t... I> 33 | using index_sequence = integer_sequence<::std::size_t, I...>; 34 | 35 | template 36 | using make_integer_sequence = typename meta::iota::type; 37 | 38 | template <::std::size_t N> 39 | using make_index_sequence = make_integer_sequence<::std::size_t, N>; 40 | 41 | template 42 | using index_sequence_for = make_index_sequence; 43 | 44 | template <::std::size_t N, class T, class... Ts> 45 | constexpr auto value_at (T&& value, Ts&&...) -> enable_if_t< 46 | N == 0 and N < (sizeof...(Ts) + 1), 47 | decltype(::core::forward(value)) 48 | > { return ::core::forward(value); } 49 | 50 | template <::std::size_t N, class T, class... Ts> 51 | constexpr auto value_at (T&&, Ts&&... values) -> enable_if_t< 52 | N != 0 and N < (sizeof...(Ts) + 1), 53 | meta::get, N> 54 | > { return value_at(::core::forward(values)...); } 55 | 56 | template 57 | struct scope_guard final { 58 | 59 | static_assert( 60 | ::std::is_nothrow_move_constructible::value, 61 | "Given type must be nothrow move constructible" 62 | ); 63 | 64 | explicit scope_guard (Callable callable) noexcept : 65 | callable { ::core::move(callable) }, 66 | dismissed { false } 67 | { } 68 | 69 | scope_guard (scope_guard const&) = delete; 70 | scope_guard (scope_guard&&) = default; 71 | scope_guard () = delete; 72 | ~scope_guard () noexcept { if (not this->dismissed) { callable(); } } 73 | 74 | scope_guard& operator = (scope_guard const&) = delete; 75 | scope_guard& operator = (scope_guard&&) = default; 76 | 77 | void dismiss () noexcept { this->dismissed = true; } 78 | 79 | private: 80 | Callable callable; 81 | bool dismissed; 82 | }; 83 | 84 | template 85 | auto make_scope_guard(Callable&& callable) -> scope_guard> { 86 | return scope_guard> { 87 | ::core::forward(callable) 88 | }; 89 | } 90 | 91 | template 92 | T exchange (T& obj, U&& value) noexcept( 93 | meta::all< 94 | ::std::is_nothrow_move_constructible, 95 | ::std::is_nothrow_assignable, U> 96 | >() 97 | ) { 98 | T old = ::core::move(obj); 99 | obj = ::core::forward(value); 100 | return old; 101 | } 102 | 103 | inline ::std::uintptr_t as_int (void const* ptr) noexcept { 104 | return reinterpret_cast<::std::uintptr_t>(ptr); 105 | } 106 | 107 | template 108 | void const* as_void (T const* ptr) { return static_cast(ptr); } 109 | 110 | template 111 | void* as_void (T* ptr) { return static_cast(ptr); } 112 | 113 | template 114 | void const* as_void (T const& ref) { return as_void(::std::addressof(ref)); } 115 | 116 | template 117 | void* as_void (T& ref) { return as_void(::std::addressof(ref)); } 118 | 119 | template 120 | constexpr auto as_under(E e) noexcept -> meta::when< 121 | std::is_enum::value, 122 | underlying_type_t 123 | > { return static_cast>(e); } 124 | 125 | template 126 | struct capture final { 127 | static_assert(::std::is_move_constructible::value, "T must be movable"); 128 | using value_type = T; 129 | using reference = add_lvalue_reference_t; 130 | using pointer = add_pointer_t; 131 | 132 | capture (T&& data) : data { core::move(data) } { } 133 | 134 | capture (capture&&) = default; 135 | capture (capture& that) : data { core::move(that.data) } { } 136 | capture () = delete; 137 | 138 | capture& operator = (capture const&) = delete; 139 | capture& operator = (capture&&) = delete; 140 | 141 | operator reference () const noexcept { return this->get(); } 142 | reference operator * () const noexcept { return this->get(); } 143 | pointer operator -> () const noexcept { 144 | return ::std::addressof(this->get()); 145 | } 146 | 147 | reference get () const noexcept { return this->data; } 148 | 149 | private: 150 | value_type data; 151 | }; 152 | 153 | template 154 | auto make_capture (remove_reference_t& ref) -> capture { 155 | return capture { core::move(ref) }; 156 | } 157 | 158 | template 159 | auto make_capture (remove_reference_t&& ref) -> capture { 160 | return capture { core::move(ref) }; 161 | } 162 | 163 | struct erased_type { }; 164 | 165 | }} /* namespace core::v2 */ 166 | 167 | #endif /* CORE_UTILITY_HPP */ 168 | -------------------------------------------------------------------------------- /docs/utility.rst: -------------------------------------------------------------------------------- 1 | Utility Component 2 | ================= 3 | 4 | .. namespace:: core 5 | 6 | The utility component provides additional functions and meta templates that 7 | cannot be categorized. Most of the utilities provided are for working with 8 | type lists. 9 | 10 | The utility component can be found in the :file:`` header. 11 | 12 | .. class:: template integer_sequence 13 | 14 | Meta template to generate a series of :samp:`{T}` to allow easier unpacking. 15 | 16 | .. class:: template index_sequence 17 | 18 | A shortcut for :any:`integer_sequence`. 19 | 20 | .. class:: template make_index_sequence 21 | 22 | Used to generate the :any:`index_sequence`, with :samp:`{N}` numbers. 23 | 24 | .. class:: template type_at 25 | 26 | .. type:: type 27 | 28 | When accessed, provides the type at the index :samp:`{N}` in the type 29 | list :samp:`{Ts}` 30 | 31 | .. function:: template constexpr auto value_at(Ts&&...) noexcept 32 | 33 | :returns: The value located at the index :samp:`{N}` in the type list 34 | :samp:`{Ts}`. 35 | :requires: :samp:`{N}` may not be >= :samp:`sizeof...({Ts})` 36 | 37 | .. class:: template scope_guard 38 | 39 | Scope guard acts much like the Boost.ScopeExit library. It is non-copyable, 40 | but movable. It can be constructed with any callable type 41 | :samp:`{Callable}`. The type :samp:`{Callable}` must be move assignable and 42 | move constructible, and marked :cxx:`noexcept`. :samp:`{Callable}` must have 43 | a function arity of 0 (that is, it takes no arguments). It does not matter 44 | whether or not :samp:`{Callable}` returns a value, as it will be ignored. 45 | To easily construct a :any:`scope_guard`, a function named 46 | :any:`make_scope_guard` is provided for type inference. This can easily be 47 | used to give a :any:`scope_guard` a lambda. As an example:: 48 | 49 | int x = new int { 4 } 50 | auto scope_guard = core::make_scope_guard([x] { delete x; }); 51 | 52 | .. function:: void dismiss () noexcept 53 | 54 | Calling :any:`dismiss` on a :any:`scope_guard` will result in its 55 | :samp:`{Callable}` never being invoked. This can be seen as a way to 56 | *rollback* bookkeeping code. 57 | 58 | .. class:: template capture 59 | 60 | This is used to provide a way to emulate C++14 move captures. It holds a 61 | value, and can only be move constructed or copy constructed from a non-const 62 | reference. A function named :any:`make_capture` is provided for type 63 | inference. 64 | 65 | .. type:: value_type 66 | 67 | An alias for :samp:`{T}`. 68 | 69 | .. type:: reference 70 | 71 | An alias for :samp:`{value_type}&` 72 | 73 | .. type:: pointer 74 | 75 | An alias for :samp:`{value_type}*` 76 | 77 | .. function:: capture (capture& that) 78 | 79 | Moves the value managed by :samp:`{that}` when constructing. 80 | 81 | .. function:: operator reference () const noexcept 82 | 83 | Allows the :any:`capture` to implicitly convert to an lvalue reference 84 | to its underlying data. 85 | 86 | .. function:: reference operator * () const noexcept 87 | 88 | Provided for shorthand of :any:`get` 89 | 90 | :returns: A :any:`reference` to the stored value. 91 | 92 | .. function:: pointer operator -> () const noexcept 93 | 94 | Provided for convenient access to the underlying value owned by a 95 | :any:`capture`. 96 | 97 | .. function:: reference get () const noexcept 98 | 99 | :returns: A :any:`reference` to the value owned by the :any:`capture` 100 | 101 | .. function:: capture make_capture (remove_reference_t&& ref) 102 | capture make_capture (remove_reference_t& ref) 103 | 104 | Constructs a :any:`capture` from the given :samp:`{ref}`. 105 | 106 | :note: :samp:`{T}` must be move constructible. 107 | 108 | .. function:: auto make_scope_guard(Callable&& callable) noexcept 109 | 110 | Constructs a :any:`scope_guard` from the given :samp:`{callable}`. 111 | 112 | .. function:: T exchange (T& obj, U&& value) 113 | 114 | Replaces the value stored in :samp:`{obj}` with :samp:`{value}`. 115 | 116 | :returns: The old value stored in :samp:`{obj}`. 117 | 118 | :requires: :samp:`{T}` must be move constructible. 119 | :samp:`{T}` must be able to accept objects of type :samp:`{U}` 120 | via move assignment. 121 | 122 | :noexcept: :samp:`is_nothrow_move_constructible<{T}>` 123 | :samp:`is_nothrow_assignable, {U}>` 124 | 125 | .. function:: constexpr auto to_integral (E e) noexcept 126 | 127 | Converts an :cxx:`enum` or :cxx:`enum class` to its underlying type. 128 | 129 | :requires: :samp:`{E}` must satisfy :cxx:`std::is_enum`. 130 | :returns: :samp:`underlying_type_t<{E}>` 131 | 132 | .. function:: constexpr T&& forward (remove_reference_t&&) noexcept 133 | constexpr T&& forward (remove_reference_t&) noexcept 134 | 135 | ``constexpr`` versions of ``std::forward``. 136 | 137 | .. function:: constexpr remove_reference_t&& move (T&&) noexcept 138 | 139 | ``constexpr`` version of ``std::move``. 140 | -------------------------------------------------------------------------------- /include/core/numeric.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CORE_NUMERIC_HPP 2 | #define CORE_NUMERIC_HPP 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace core { 9 | inline namespace v2 { 10 | 11 | template 12 | auto iota (Range&& rng, T&& value) -> enable_if_t::value> { 13 | auto range = make_range(::std::forward(rng)); 14 | constexpr auto is_forward = decltype(range)::is_forward; 15 | static_assert(is_forward, "iota requires ForwardIterators"); 16 | return ::std::iota( 17 | ::std::begin(range), 18 | ::std::end(range), 19 | ::std::forward(value) 20 | ); 21 | } 22 | 23 | template 24 | auto accumulate (Range&& rng, T&& init) -> enable_if_t< 25 | is_range::value, 26 | decay_t 27 | > { 28 | auto range = make_range(::std::forward(rng)); 29 | constexpr auto is_input = decltype(range)::is_input; 30 | static_assert(is_input, "accumulate requires InputIterators"); 31 | return ::std::accumulate( 32 | ::std::begin(range), 33 | ::std::end(range), 34 | ::std::forward(init) 35 | ); 36 | } 37 | 38 | template 39 | auto accumulate (Range&& rng, T&& init, BinaryOp&& op) -> enable_if_t< 40 | is_range::value, 41 | decay_t 42 | > { 43 | auto range = make_range(::std::forward(rng)); 44 | constexpr auto is_input = decltype(range)::is_input; 45 | static_assert(is_input, "accumulate requires InputIterators"); 46 | return ::std::accumulate( 47 | ::std::begin(range), 48 | ::std::end(range), 49 | ::std::forward(init), 50 | ::std::forward(op) 51 | ); 52 | } 53 | 54 | template 55 | auto inner_product (Range&& rng, InputIt&& it, T&& value) -> enable_if_t< 56 | is_range::value, 57 | decay_t 58 | > { 59 | auto range = make_range(::std::forward(rng)); 60 | constexpr auto is_input = decltype(range)::is_input; 61 | static_assert(is_input, "inner_product requires InputIterators"); 62 | return ::std::inner_product( 63 | ::std::begin(range), 64 | ::std::end(range), 65 | ::std::forward(it), 66 | ::std::forward(value) 67 | ); 68 | } 69 | 70 | template 71 | auto inner_product ( 72 | Range&& rng, 73 | InputIt&& it, 74 | T&& value, 75 | BinaryOp&& op, 76 | BinaryOp2&& op2 77 | ) -> enable_if_t::value, decay_t> { 78 | auto range = make_range(::std::forward(rng)); 79 | constexpr auto is_input = decltype(range)::is_input; 80 | static_assert(is_input, "inner_product requires InputIterators"); 81 | return ::std::inner_product( 82 | ::std::begin(range), 83 | ::std::end(range), 84 | ::std::forward(it), 85 | ::std::forward(value), 86 | ::std::forward(op), 87 | ::std::forward(op2) 88 | ); 89 | } 90 | 91 | template 92 | auto adjacent_difference (Range&& rng, OutputIt&& it) -> enable_if_t< 93 | is_range::value, 94 | decay_t 95 | > { 96 | auto range = make_range(::std::forward(rng)); 97 | constexpr auto is_input = decltype(range)::is_input; 98 | static_assert(is_input, "adjacent_difference requires InputIterators"); 99 | return ::std::adjacent_difference( 100 | ::std::begin(range), 101 | ::std::end(range), 102 | ::std::forward(it) 103 | ); 104 | } 105 | 106 | template 107 | auto adjacent_difference ( 108 | Range&& rng, 109 | OutputIt&& it, 110 | BinaryOp&& op 111 | ) -> enable_if_t::value, decay_t> { 112 | auto range = make_range(::std::forward(rng)); 113 | constexpr auto is_input = decltype(range)::is_input; 114 | static_assert(is_input, "adjacent_difference requires InputIterators"); 115 | return ::std::adjacent_difference( 116 | ::std::begin(range), 117 | ::std::end(range), 118 | ::std::forward(it), 119 | ::std::forward(op) 120 | ); 121 | } 122 | 123 | template 124 | auto partial_sum (Range&& rng, OutputIt&& it) -> enable_if_t< 125 | is_range::value, 126 | decay_t 127 | > { 128 | auto range = make_range(::std::forward(rng)); 129 | constexpr auto is_input = decltype(range)::is_input; 130 | static_assert(is_input, "partial_sum requires InputIterators"); 131 | return ::std::partial_sum( 132 | ::std::begin(range), 133 | ::std::end(range), 134 | ::std::forward(it) 135 | ); 136 | } 137 | 138 | template 139 | auto partial_sum (Range&& rng, OutputIt&& it, BinaryOp&& op) -> enable_if_t< 140 | is_range::value, 141 | decay_t 142 | > { 143 | auto range = make_range(::std::forward(rng)); 144 | constexpr auto is_input = decltype(range)::is_input; 145 | static_assert(is_input, "partial_sum requires InputIterators"); 146 | return ::std::partial_sum( 147 | ::std::begin(range), 148 | ::std::end(range), 149 | ::std::forward(it), 150 | ::std::forward(op) 151 | ); 152 | } 153 | 154 | /* Because they need to be constexpr, these are EXTREMELY ineffecient */ 155 | template 156 | constexpr auto gcd (M m, N n) -> meta::when< 157 | meta::all_of, ::std::is_integral>(), 158 | common_type_t 159 | > { return m % n ? gcd(m, m % n) : n; } 160 | 161 | template 162 | constexpr auto lcm (M m, N n) -> meta::when< 163 | meta::all_of, std::is_integral>(), 164 | common_type_t 165 | > { return m / gcd(m, n) * n; } 166 | 167 | }} /* namespace core::v2 */ 168 | 169 | #endif /* CORE_NUMERIC_HPP */ 170 | -------------------------------------------------------------------------------- /docs/type-traits.rst: -------------------------------------------------------------------------------- 1 | Type Traits Component 2 | ===================== 3 | 4 | .. namespace:: core 5 | 6 | The type traits component contains many utilities that are available in C++14, 7 | as well as a few custom types. Such as, :any:`is_nothrow_swappable` and 8 | :any:`is_swappable`. *Most* of the types provided within this component are 9 | in fact simple type aliases defined for C++14. e.g., 10 | ``typename std::decay::type`` is aliased to :cxx:`core::decay_t`. All 11 | types that are used as type *modifiers* (rather than type *properties*) have 12 | the equivalent alias available. 13 | 14 | Only type traits not provided by the C++11 standard are documented. If a 15 | type trait provided by MNMLSTC Core differs from the standard in any way, it is 16 | also documented here. 17 | 18 | The type traits component can be found in the :file:`` 19 | header. 20 | 21 | .. type:: template is_null_pointer 22 | 23 | An alias for ``std::true_type`` if :samp:`{T}` is any form of the type 24 | ``std::nullptr_t``. This includes its *const* and *volatile* qualified 25 | counterparts. 26 | 27 | .. type:: template class_of_t 28 | 29 | Given a member function pointer type :samp:`{T}`, it extracts the underlying 30 | class type. 31 | 32 | :example: 33 | 34 | .. code-block:: cpp 35 | 36 | struct A { void empty () { } }; 37 | 38 | using type = class_of_t; 39 | static_assert(std::is_same::value, ""); 40 | 41 | .. type:: template invokable 42 | 43 | .. deprecated:: 2.0 44 | 45 | Given a typelist :samp:`{Args}...`, checks if the first type in 46 | :samp:`{Args}...` may be invoked with the rest of the arguments in 47 | :samp:`{Args}`. The rule for deciding if :samp:`{Args}...` is invokable 48 | follows the *INVOKE* pseudo expression. 49 | 50 | .. class:: template invoke_of 51 | 52 | .. deprecated:: 2.0 53 | 54 | Given a typelist :samp:`{Args}...`, the member typedef :cxx:`type` will 55 | represent the return type if :samp:`{Args}` is invoked according to the 56 | *INVOKE* pseudo-expression. 57 | 58 | .. class:: template result_of 59 | 60 | This is an SFINAE capable version of :cxx:`std::result_of`. It relies on 61 | :any:`invoke_of` to work correctly. 62 | 63 | .. class:: template common_type 64 | 65 | A more compiler agnostic version of ``std::common_type<{Ts}...>``. This was 66 | implemented to workaround an issue with Clang's ``std::common_type`` 67 | attempting to discover the common type of two ``void&&``. Additionally, 68 | this type trait follows the C++14 rules of decaying the common type. 69 | 70 | .. type:: template is_nothrow_swappable 71 | 72 | A type trait that is ``std::true_type`` if a given swap call on a type is 73 | actually marked as *noexcept*, and ``std::false_type`` otherwise. This trait 74 | is comparable to libc++'s internal ``__is_nothrow_swappable``. 75 | 76 | This is also, oddly enough, an implementation of the 77 | :cxx:`is_nothrow_swappable` trait proposed in :wg21:`N4426`, and was added 78 | to MNMLSTC Core before the proposal was submitted. 79 | 80 | .. class:: template aligned_union 81 | 82 | This is an implementation of :cxx:`std::aligned_union`, and is provided 83 | for a certain compiler whose library implementations may not have added it 84 | until 2015-APR-22 and whose colloqiual pronunciation rhymes with 85 | "Pre Free Tea". That's "Free as in Tea", not "Free as in Speech" ;) 86 | 87 | .. type:: template bool_constant 88 | 89 | An alias of :cxx:`std::integral_constant`. This is a implementation 90 | of :wg21:`N4389`. 91 | 92 | .. type:: template tuple_element_t 93 | template tuple_size_t 94 | 95 | These two type aliases are provided as they are missing from C++11. They 96 | are simply type aliases for :cxx:`std::tuple_element` and 97 | :cxx:`std::tuple_size`. 98 | 99 | The Detection Idiom 100 | ------------------- 101 | 102 | The detection idiom is a set of powerful meta templates that obviate the need 103 | for the 'old' approach to detecting if a member function, member, or function 104 | call would work for SFINAE purposes. It was originally started with 105 | Walter E. Brown's :any:`void_t`, but has since grown to include several 106 | additional types such as :any:`is_detected`, :any:`detected_or`, etc. 107 | 108 | To give users a better idea, each entry has an example of how each part of 109 | the detection idiom would be used. 110 | 111 | .. type:: template void_t 112 | 113 | The infamous :any:`void_t` is a powerful SFINAE metaprogramming tool 114 | discovered by Walter E. Brown. It is used as the basis for 115 | :any:`is_detected`, as well as other detection pieces. 116 | 117 | :example: 118 | 119 | .. code-block:: cpp 120 | 121 | // detect if class has a T::size() member function, but ignore the 122 | // return type. 123 | template 124 | struct has_size_mem_fn : std::false_type { }; 125 | 126 | template 127 | struct has_size_mem_fn< 128 | T, 129 | void_t().size())> 130 | > : std::true_type { }; 131 | 132 | static_assert(has_size_mem_fn::value, ""); 133 | static_assert(not has_size_mem_fn::value, ""); 134 | 135 | .. type:: template