├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .tgitconfig ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── appveyor.yml ├── cmake ├── bit-lite-config-version.cmake.in └── bit-lite-config.cmake.in ├── example ├── 01-basic.cpp └── CMakeLists.txt ├── include └── nonstd │ └── bit.hpp ├── script └── update-version.py └── test ├── CMakeLists.txt ├── bit-main.t.cpp ├── bit-main.t.hpp ├── bit.t.cpp ├── lest └── lest_cpp03.hpp ├── t.bat ├── tc-cl.bat ├── tc.bat ├── tg-all.bat └── tg.bat /.editorconfig: -------------------------------------------------------------------------------- 1 | # Configuration file for EditorConfig, see https://EditorConfig.org 2 | 3 | # Ignore any other files further up in the file system 4 | root = true 5 | 6 | # All files: 7 | [*] 8 | # Let git determine line ending: end_of_line = lf 9 | charset = utf-8 10 | indent_size = 4 11 | indent_style = space 12 | insert_final_newline = true 13 | trim_trailing_whitespace = true 14 | 15 | # Markdown files: keep trailing space-pair as line-break 16 | [*.md] 17 | trim_trailing_whitespace = false 18 | 19 | # Python scripts: 20 | [*.py] 21 | 22 | # YAML scripts: 23 | [*.yml] 24 | indent_size = 2 25 | 26 | # Makefiles: Tab indentation (no size specified) 27 | [Makefile] 28 | indent_style = tab 29 | 30 | # C, C++ source files: 31 | [*.{h,hpp,c,cpp}] 32 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for CodeBlocks 5 | *.cbp text eol=lf 6 | *.workspace text eol=lf 7 | 8 | # Custom for Visual Studio 9 | *.cs diff=csharp 10 | *.sln merge=union 11 | *.csproj merge=union 12 | *.vbproj merge=union 13 | *.fsproj merge=union 14 | *.dbproj merge=union 15 | 16 | # Standard to msysgit 17 | *.doc diff=astextplain 18 | *.DOC diff=astextplain 19 | *.docx diff=astextplain 20 | *.DOCX diff=astextplain 21 | *.dot diff=astextplain 22 | *.DOT diff=astextplain 23 | *.pdf diff=astextplain 24 | *.PDF diff=astextplain 25 | *.rtf diff=astextplain 26 | *.RTF diff=astextplain 27 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | env: 4 | PROJECT: BIT_LITE 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | 10 | pull_request: 11 | branches: [ master ] 12 | 13 | workflow_dispatch: 14 | 15 | jobs: 16 | gcc: 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | version: [9, 10, 11] 21 | 22 | runs-on: ubuntu-latest 23 | 24 | steps: 25 | - uses: actions/checkout@v4 26 | 27 | - name: Install GCC ${{ matrix.version }} 28 | run: sudo apt-get install -y gcc-${{ matrix.version }} g++-${{ matrix.version }} 29 | 30 | - name: Configure tests 31 | env: 32 | CXX: g++-${{ matrix.version }} 33 | run: cmake -S . -B build 34 | -D CMAKE_BUILD_TYPE:STRING=Release 35 | -D ${{ env.PROJECT }}_OPT_SELECT_NONSTD=ON 36 | -D ${{ env.PROJECT }}_OPT_BUILD_TESTS=ON 37 | -D ${{ env.PROJECT }}_OPT_BUILD_EXAMPLES=OFF 38 | 39 | - name: Build tests 40 | run: cmake --build build -j 4 41 | 42 | - name: Run tests 43 | working-directory: build 44 | run: ctest --output-on-failure -j 4 45 | 46 | clang: 47 | strategy: 48 | fail-fast: false 49 | matrix: 50 | version: [11, 12] 51 | 52 | runs-on: ubuntu-latest 53 | 54 | steps: 55 | - uses: actions/checkout@v4 56 | 57 | - name: Install Clang ${{ matrix.version }} 58 | run: sudo apt-get install -y clang-${{ matrix.version }} 59 | 60 | - name: Configure tests 61 | env: 62 | CXX: clang-${{ matrix.version }} 63 | run: cmake -S . -B build 64 | -D CMAKE_CXX_COMPILER=clang++ 65 | -D CMAKE_BUILD_TYPE:STRING=Release 66 | -D ${{ env.PROJECT }}_OPT_SELECT_NONSTD=ON 67 | -D ${{ env.PROJECT }}_OPT_BUILD_TESTS=ON 68 | -D ${{ env.PROJECT }}_OPT_BUILD_EXAMPLES=OFF 69 | 70 | - name: Build tests 71 | run: cmake --build build -j 4 72 | 73 | - name: Run tests 74 | working-directory: build 75 | run: ctest --output-on-failure -j 4 76 | 77 | msvc: 78 | strategy: 79 | fail-fast: false 80 | matrix: 81 | os: [windows-2019, windows-2022] 82 | 83 | runs-on: ${{ matrix.os }} 84 | 85 | steps: 86 | - uses: actions/checkout@v4 87 | 88 | - name: Configure tests 89 | run: cmake -S . -B build 90 | -D ${{ env.PROJECT }}_OPT_SELECT_NONSTD=ON 91 | -D ${{ env.PROJECT }}_OPT_BUILD_TESTS=ON 92 | -D ${{ env.PROJECT }}_OPT_BUILD_EXAMPLES=OFF 93 | 94 | - name: Build tests 95 | run: cmake --build build --config Release -j 4 96 | 97 | - name: Run tests 98 | working-directory: build 99 | run: ctest -C Release --output-on-failure -j 4 100 | -------------------------------------------------------------------------------- /.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 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | # Build folder 31 | /build/ 32 | 33 | # CodeBlocks IDE files 34 | *.layout 35 | 36 | # Visual Studio Code 37 | /.vscode/ 38 | 39 | # Visual Studio 40 | /.vs/ 41 | -------------------------------------------------------------------------------- /.tgitconfig: -------------------------------------------------------------------------------- 1 | [bugtraq] 2 | url = https://github.com/martinmoene/bit-lite/issues/%BUGID% 3 | number = true 4 | logregex = "(\\s*(,|and)?\\s*#\\d+)+\n(\\d+)" 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2020 by Martin Moene 2 | # 3 | # https://github.com/martinmoene/bit-lite 4 | # 5 | # Distributed under the Boost Software License, Version 1.0. 6 | # (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 | 8 | cmake_minimum_required( VERSION 3.5 FATAL_ERROR ) 9 | 10 | # bit-lite project and version, updated by script/update-version.py: 11 | 12 | project( 13 | bit_lite 14 | VERSION 0.1.0 15 | # DESCRIPTION "A C++20-like bit, bit operations for C++98 and later in a single-file header-only library. 16 | # HOMEPAGE_URL "https://github.com/martinmoene/bit-lite" 17 | LANGUAGES CXX ) 18 | 19 | # Package information: 20 | 21 | set( unit_name "bit" ) 22 | set( package_nspace "nonstd" ) 23 | set( package_name "${unit_name}-lite" ) 24 | set( package_version "${${PROJECT_NAME}_VERSION}" ) 25 | 26 | message( STATUS "Project '${PROJECT_NAME}', package '${package_name}' version: '${package_version}'") 27 | 28 | # Toplevel or subproject: 29 | 30 | if ( CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME ) 31 | set( bit_IS_TOPLEVEL_PROJECT TRUE ) 32 | else() 33 | set( bit_IS_TOPLEVEL_PROJECT FALSE ) 34 | endif() 35 | 36 | # If toplevel project, enable building and performing of tests, disable building of examples: 37 | 38 | option( BIT_LITE_OPT_BUILD_TESTS "Build and perform bit-lite tests" ${bit_IS_TOPLEVEL_PROJECT} ) 39 | option( BIT_LITE_OPT_BUILD_EXAMPLES "Build bit-lite examples" OFF ) 40 | 41 | option( BIT_LITE_OPT_SELECT_STD "Select std::bit" OFF ) 42 | option( BIT_LITE_OPT_SELECT_NONSTD "Select nonstd::bit" OFF ) 43 | 44 | # If requested, build and perform tests, build examples: 45 | 46 | if ( BIT_LITE_OPT_BUILD_TESTS ) 47 | enable_testing() 48 | add_subdirectory( test ) 49 | endif() 50 | 51 | if ( BIT_LITE_OPT_BUILD_EXAMPLES ) 52 | add_subdirectory( example ) 53 | endif() 54 | 55 | # 56 | # Interface, installation and packaging 57 | # 58 | 59 | # CMake helpers: 60 | 61 | include( GNUInstallDirs ) 62 | include( CMakePackageConfigHelpers ) 63 | 64 | # Interface library: 65 | 66 | add_library( 67 | ${package_name} INTERFACE ) 68 | 69 | add_library( 70 | ${package_nspace}::${package_name} ALIAS ${package_name} ) 71 | 72 | target_include_directories( 73 | ${package_name} 74 | INTERFACE 75 | "$" 76 | "$" ) 77 | 78 | # Package configuration: 79 | # Note: package_name and package_target are used in package_config_in 80 | 81 | set( package_folder "${package_name}" ) 82 | set( package_target "${package_name}-targets" ) 83 | set( package_config "${package_name}-config.cmake" ) 84 | set( package_config_in "${package_name}-config.cmake.in" ) 85 | set( package_config_version "${package_name}-config-version.cmake" ) 86 | 87 | configure_package_config_file( 88 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${package_config_in}" 89 | "${CMAKE_CURRENT_BINARY_DIR}/${package_config}" 90 | INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${package_folder}" 91 | ) 92 | 93 | configure_file( 94 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${package_config_version}.in" 95 | "${CMAKE_CURRENT_BINARY_DIR}/${package_config_version}" @ONLY 96 | ) 97 | 98 | # Installation: 99 | 100 | install( 101 | TARGETS ${package_name} 102 | EXPORT ${package_target} 103 | # INCLUDES DESTINATION "${...}" # already set via target_include_directories() 104 | ) 105 | 106 | install( 107 | EXPORT ${package_target} 108 | NAMESPACE ${package_nspace}:: 109 | DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${package_folder}" 110 | ) 111 | 112 | install( 113 | FILES "${CMAKE_CURRENT_BINARY_DIR}/${package_config}" 114 | "${CMAKE_CURRENT_BINARY_DIR}/${package_config_version}" 115 | DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${package_folder}" 116 | ) 117 | 118 | install( 119 | DIRECTORY "include/" 120 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" 121 | ) 122 | 123 | export( 124 | EXPORT ${package_target} 125 | NAMESPACE ${package_nspace}:: 126 | FILE "${CMAKE_CURRENT_BINARY_DIR}/${package_name}-targets.cmake" 127 | ) 128 | 129 | # end of file 130 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bit-lite - C++20 bit operations for C++98 and later in a single-file header-only library. 2 | 3 | [![Language](https://img.shields.io/badge/C%2B%2B-98/11/14/17/20-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) [![License](https://img.shields.io/badge/license-BSL-blue.svg)](https://opensource.org/licenses/BSL-1.0) [![Build Status](https://github.com/martinmoene/bit-lite/actions/workflows/ci.yml/badge.svg)](https://github.com/martinmoene/bit-lite/actions/workflows/ci.yml) [![Build status](https://ci.appveyor.com/api/projects/status/gpmw4gt271itoy2n?svg=true)](https://ci.appveyor.com/project/martinmoene/bit-lite) [![Version](https://badge.fury.io/gh/martinmoene%2Fbit-lite.svg)](https://github.com/martinmoene/bit-lite/releases) [![download](https://img.shields.io/badge/latest-download-blue.svg)](https://raw.githubusercontent.com/martinmoene/bit-lite/master/include/nonstd/bit.hpp) [![Conan](https://img.shields.io/badge/on-conan-blue.svg)](https://conan.io/center/bit-lite) [![Try it online](https://img.shields.io/badge/on-wandbox-blue.svg)](https://wandbox.org/permlink/ZwnY4c9dZUAynUac) [![Try it on godbolt online](https://img.shields.io/badge/on-godbolt-blue.svg)](https://godbolt.org/z/1IPvn7) 4 | 5 | **Contents** 6 | 7 | - [Example usage](#example-usage) 8 | - [In a nutshell](#in-a-nutshell) 9 | - [License](#license) 10 | - [Dependencies](#dependencies) 11 | - [Installation](#installation) 12 | - [Synopsis](#synopsis) 13 | - [Features](#features) 14 | - [Reported to work with](#reported-to-work-with) 15 | - [Building the tests](#building-the-tests) 16 | - [Other implementations of bit](#other-implementations-of-bit) 17 | - [Notes and references](#notes-and-references) 18 | - [Appendix](#appendix) 19 | 20 | ## Example usage 21 | 22 | ```Cpp 23 | #include "nonstd/bit.hpp" 24 | #include 25 | 26 | using namespace nonstd; 27 | 28 | int main() 29 | { 30 | std::cout 31 | << "Consecutive ones at the right in 0x17: " << countr_one( 0x17u ) 32 | << "\nBit width of 0x13: " << bit_width( 0x13u ) << '\n'; 33 | } 34 | ``` 35 | 36 | ### Compile and run 37 | 38 | ```Text 39 | prompt> g++ -Wall -I../include -o 01-basic.exe 01-basic.cpp && 01-basic.exe 40 | Consecutive ones at the right in 0x17: 3 41 | Bit width of 0x13: 5 42 | ``` 43 | 44 | ## In a nutshell 45 | 46 | **bit lite** is a single-file header-only library to provide the tools from the C++20 header [``](https://en.cppreference.com/w/cpp/header/bit) for use with C++98 and later. If available, the standard header is used, unless [configured](#configuration) otherwise. 47 | 48 | **Features and properties of bit lite** are ease of installation (single header), freedom of dependencies other than the standard library. 49 | 50 | **Limitations of bit lite** are ... . 51 | 52 | ## License 53 | 54 | *bit lite* is distributed under the [Boost Software License](https://github.com/martinmoene/bit-lite/blob/master/LICENSE.txt). 55 | 56 | ## Dependencies 57 | 58 | *bit lite* has no other dependencies than the [C++ standard library](http://en.cppreference.com/w/cpp/header). 59 | 60 | ## Installation 61 | 62 | *bit lite* is a single-file header-only library. Put `bit.hpp` in the [include](include) folder directly into the project source tree or somewhere reachable from your project. 63 | 64 | ## Synopsis 65 | 66 | **Contents** 67 | 68 | [Documentation of standard header ``](#documentation-of-stdbit) 69 | [Non-standard extensions](#non-standard-extensions) 70 | [Configuration](#configuration) 71 | 72 | ### Documentation of standard header `` 73 | 74 | Depending on the compiler and C++-standard used, *bit lite* behaves less or more like C++20 standard ``. To get an idea of the capabilities of *bit lite* with your configuration, look at the output of the [tests](test/bit.t.cpp), issuing `bit-main.t --pass @`. For C++20 standard ``, see its [documentation at cppreference](https://en.cppreference.com/w/cpp/header/bit). 75 | 76 | ### Non-standard extensions 77 | 78 | | Kind | Extension type or function | Notes | 79 | |--------------------|----------------------------|-------| 80 | | **Type** | **big_endian_type** | type based on endian::big | 81 | |   | **little_endian_type** | type based on endian::little | 82 | |   | **native_endian_type** | type based on endian::native | 83 | |   |   | | 84 | | **Free function** | template<class T>
T **to_big_endian**(T v) |
convert unconditionally | 85 | |   | template<class T, class EN>
T **to_big_endian**(T v, EN) | convert if EN is little_endian_type
*EN specifies endianness of v* | 86 | |   | template<class T>
T **to_little_endian**(T v) |
convert unconditionally | 87 | |   | template<class T, class EN>
T **to_little_endian**(T v, EN) | convert if EN is big_endian_type
*EN specifies endianness of v* | 88 | |   | template<class T>
T **to_native_endian**(T v) |
identity | 89 | |   | template<class T, class EN>
T **to_native_endian**(T v, EN) | convert if EN represents
non-native endianness for v | 90 | |   |   | | 91 | |   | template<class T>
T **as_big_endian**(T v) |
convert if native is little endian | 92 | |   | template<class T>
T **as_little_endian**(T v) |
convert if native is big endian | 93 | |   | template<class T>
T **as_native_endian**(T v) |
identity | 94 | 95 | ### Configuration 96 | 97 | #### Standard selection macro 98 | 99 | \-Dbit\_CPLUSPLUS=199711L 100 | Define this macro to override the auto-detection of the supported C++ standard, if your compiler does not set the `__cplusplus` macro correctly. 101 | 102 | #### Select C++20 standard `` or nonstd `` 103 | 104 | At default, *bit lite* uses the C++20 standard header `` if it is available and lets you use it via namespace `nonstd`. You can however override this default and explicitly request to use the standard C++20 header or *bit lite*'s header via the following macros. 105 | 106 | -Dbit\_CONFIG\_SELECT\_BIT=bit_BIT_DEFAULT 107 | Define this to `bit_BIT_STD` to select C++20 standard header ``. Define this to `bit_BIT_NONSTD` to select *bit lite*. Default is undefined, which has the same effect as defining to `bit_BIT_DEFAULT`. 108 | 109 | #### Strict C++20 mode 110 | 111 | -Dbit\_CONFIG\_STRICT=1 112 | Define this to `1` to omit the non C++20 standard extensions. Default is undefined, which has the same effect as `0`, non-strict mode. 113 | 114 | ## Reported to work with 115 | 116 | TBD 117 | 118 | ## Building the tests 119 | 120 | TBD 121 | 122 | ## Other implementations of `` 123 | 124 | TBD 125 | 126 | ## Notes and references 127 | 128 | *Interface and specification* 129 | 130 | - Cppreference. [Header <bit>](https://en.cppreference.com/w/cpp/header/bit) 131 | - Cppreference. [bit_cast](https://en.cppreference.com/w/cpp/numeric/bit_cast) 132 | - Cppreference. [enum class endian](https://en.cppreference.com/w/cpp/types/endian) 133 | 134 | *Proposals* 135 | 136 | - [p0463 - endendian, Just endian](https://wg21.link/P0463). Howard E. Hinnant. 2017. 137 | - [p0476 - Bit-casting object representations](https://wg21.link/P0476). JF Bastien. 2017. 138 | - [p0553 - Bit operations](https://wg21.link/P0553). Jens Maurer. 2019. 139 | 140 | *Articles* 141 | 142 | - Overload 160. [What is the Strict Aliasing Rule and Why Do We Care?](https://accu.org/journals/overload/28/160/anonymous/). Anonymous. December 2020. 143 | 144 | ## Appendix 145 | 146 | The [test program](test/bit.t.cpp) provides information on the compiler, the C++ language and library capabilities and the tests performed. 147 | 148 | ### A.1 Compile-time information 149 | 150 | The version of *bit lite* is available via tag `[.version]`. The following tags are available for information on the compiler and on the C++ standard library used: `[.compiler]`, `[.stdc++]`, `[.stdlanguage]` and `[.stdlibrary]`. 151 | 152 | ### A.2 Bit lite test specification 153 | 154 | ```Text 155 | bit_cast<>(): successfully roundtrips uint64_t via double [bit.cast] 156 | has_single_bit(): single bit yields false for no bits set [bit.pow.two] 157 | has_single_bit(): single bit yields true for single bits set [bit.pow.two] 158 | has_single_bit(): single bit yields false for multiple bits set [bit.pow.two] 159 | bit_ceil(): let N be the smallest power of 2 greater than or equal to x [bit.pow.two] 160 | bit_floor(): x == 0, 0; otherwise the maximal value y such that has_single_bit(y) is true and y <= x [bit.pow.two] 161 | bit_width: x == 0, 0; otherwise one plus the base-2 logarithm of x, with any fractional part discarded [bit.pow.two] 162 | rotl(): r is 0, x; if r is positive, (x << r) | (x >> (N - r)); if r is negative, rotr(x, -r) [bit.rotate] 163 | rotr(): r is 0, x; if r is positive, (x >> r) | (x << (N - r)); if r is negative, rotl(x, -r) [bit.rotate] 164 | countl_zero(): the number of consecutive 0 bits in the value of x, starting from the most significant bit [bit.count] 165 | countl_one(): the number of consecutive 1 bits in the value of x, starting from the most significant bit [bit.count] 166 | countr_zero(): the number of consecutive 0 bits in the value of x, starting from the least significant bit [bit.count] 167 | countr_one(): the number of consecutive 1 bits in the value of x, starting from the least significant bit [bit.count] 168 | popcount(): the number of 1 bits in the value of x [bit.count] 169 | endian: little differs from big (corner-case when all scalars have size of 1 byte) [bit.endian] 170 | to_big_endian(): convert native, or little or big endian specified unsigned to big endian [bit.endian.extension] 171 | to_little_endian(): convert native, or little or big endian specified unsigned to little endian [bit.endian.extension] 172 | to_native_endian(): convert native, or little or big endian specified unsigned to native endian [bit.endian.extension] 173 | as_big_endian(): provide native unsigned as big endian [bit.endian.extension] 174 | as_little_endian(): provide native unsigned as little endian [bit.endian.extension] 175 | as_native_endian(): provide native unsigned as native endian (identity) [bit.endian.extension] 176 | ``` 177 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: "{branch} #{build}" 2 | 3 | shallow_clone: true 4 | 5 | image: 6 | - Visual Studio 2017 7 | - Visual Studio 2015 8 | 9 | platform: 10 | - Win32 11 | - x64 12 | 13 | configuration: 14 | - Debug 15 | - Release 16 | 17 | environment: 18 | matrix: 19 | - generator: "Visual Studio 15 2017" 20 | - generator: "Visual Studio 14 2015" 21 | - generator: "Visual Studio 12 2013" 22 | - generator: "Visual Studio 11 2012" 23 | - generator: "Visual Studio 10 2010" 24 | 25 | matrix: 26 | fast_finish: true 27 | exclude: 28 | - image: Visual Studio 2015 29 | generator: "Visual Studio 15 2017" 30 | - image: Visual Studio 2017 31 | generator: "Visual Studio 14 2015" 32 | - image: Visual Studio 2017 33 | generator: "Visual Studio 12 2013" 34 | - image: Visual Studio 2017 35 | generator: "Visual Studio 11 2012" 36 | - image: Visual Studio 2017 37 | generator: "Visual Studio 10 2010" 38 | 39 | before_build: 40 | - mkdir build && cd build 41 | - cmake -A %platform% -G "%generator%" -DBIT_LITE_OPT_SELECT_NONSTD=ON -DBIT_LITE_OPT_BUILD_TESTS=ON -DBIT_LITE_OPT_BUILD_EXAMPLES=OFF .. 42 | 43 | build_script: 44 | - cmake --build . --config %configuration% 45 | 46 | test_script: 47 | - ctest --output-on-failure -C %configuration% 48 | -------------------------------------------------------------------------------- /cmake/bit-lite-config-version.cmake.in: -------------------------------------------------------------------------------- 1 | # Adapted from write_basic_package_version_file(... COMPATIBILITY SameMajorVersion) output 2 | # ARCH_INDEPENDENT is only present in cmake 3.14 and onwards 3 | 4 | set( PACKAGE_VERSION "@package_version@" ) 5 | 6 | if( PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION ) 7 | set( PACKAGE_VERSION_COMPATIBLE FALSE ) 8 | else() 9 | if( "@package_version@" MATCHES "^([0-9]+)\\." ) 10 | set( CVF_VERSION_MAJOR "${CMAKE_MATCH_1}" ) 11 | else() 12 | set( CVF_VERSION_MAJOR "@package_version@" ) 13 | endif() 14 | 15 | if( PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR ) 16 | set( PACKAGE_VERSION_COMPATIBLE TRUE ) 17 | else() 18 | set( PACKAGE_VERSION_COMPATIBLE FALSE ) 19 | endif() 20 | 21 | if( PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION ) 22 | set( PACKAGE_VERSION_EXACT TRUE ) 23 | endif() 24 | endif() 25 | -------------------------------------------------------------------------------- /cmake/bit-lite-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | # Only include targets once: 4 | 5 | if( NOT TARGET @package_nspace@::@package_name@ ) 6 | include( "${CMAKE_CURRENT_LIST_DIR}/@package_target@.cmake" ) 7 | endif() 8 | -------------------------------------------------------------------------------- /example/01-basic.cpp: -------------------------------------------------------------------------------- 1 | #include "nonstd/bit.hpp" 2 | #include 3 | 4 | using namespace nonstd; 5 | 6 | int main() 7 | { 8 | std::cout 9 | << "Consecutive ones at the right in 0x17: " << countr_one( 0x17u ) 10 | << "\nBit width of 0x13: " << bit_width( 0x13u ) << '\n'; 11 | } 12 | 13 | // g++ -Wall -I../include -o 01-basic.exe 01-basic.cpp && 01-basic.exe 14 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2020 by Martin Moene 2 | # 3 | # https://github.com/martinmoene/span-lite 4 | # 5 | # Distributed under the Boost Software License, Version 1.0. 6 | # (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 | 8 | if( NOT DEFINED CMAKE_MINIMUM_REQUIRED_VERSION ) 9 | cmake_minimum_required( VERSION 3.5 FATAL_ERROR ) 10 | endif() 11 | 12 | project( example LANGUAGES CXX ) 13 | 14 | # unit_name provided by toplevel CMakeLists.txt 15 | set( PACKAGE ${unit_name}-lite ) 16 | 17 | message( STATUS "Subproject '${PROJECT_NAME}'") 18 | 19 | # Target default options and definitions: 20 | 21 | set( OPTIONS "" ) 22 | #set( DEFINITIONS "" ) 23 | 24 | # Sources (.cpp) and their base names: 25 | 26 | set( SOURCES 27 | 01-basic.cpp 28 | ) 29 | 30 | set( SOURCES_NE 31 | ) 32 | 33 | string( REPLACE ".cpp" "" BASENAMES "${SOURCES}" ) 34 | string( REPLACE ".cpp" "" BASENAMES_NE "${SOURCES_NE}" ) 35 | 36 | # Determine options 37 | 38 | if( MSVC ) 39 | message( STATUS "Matched: MSVC") 40 | 41 | set( BASE_OPTIONS -W3 ) 42 | set( EXCEPTIONS_OPTIONS ${BASE_OPTIONS} -EHsc ) 43 | set( NO_EXCEPTIONS_OPTIONS ${BASE_OPTIONS} ) 44 | 45 | elseif( CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang" ) 46 | message( STATUS "CompilerId: '${CMAKE_CXX_COMPILER_ID}'") 47 | 48 | set( BASE_OPTIONS -Wall -Wextra -Wconversion -Wsign-conversion -Wno-missing-braces -fno-elide-constructors ) 49 | set( EXCEPTIONS_OPTIONS ${BASE_OPTIONS} ) 50 | set( NO_EXCEPTIONS_OPTIONS -fno-exceptions ) 51 | 52 | elseif( CMAKE_CXX_COMPILER_ID MATCHES "Intel" ) 53 | # as is 54 | message( STATUS "Matched: Intel") 55 | else() 56 | # as is 57 | message( STATUS "Matched: nothing") 58 | endif() 59 | 60 | # Function to emulate ternary operation `result = b ? x : y`: 61 | 62 | macro( ternary var boolean value1 value2 ) 63 | if( ${boolean} ) 64 | set( ${var} ${value1} ) 65 | else() 66 | set( ${var} ${value2} ) 67 | endif() 68 | endmacro() 69 | 70 | # Function to create a target: 71 | 72 | function( make_target name no_exceptions ) 73 | ternary( ne no_exceptions "-ne" "" ) 74 | 75 | add_executable ( ${PROGRAM}-${name}${ne} ${name}.cpp ) 76 | target_include_directories ( ${PROGRAM}-${name}${ne} PRIVATE ../include ) 77 | target_link_libraries ( ${PROGRAM}-${name}${ne} PRIVATE ${PACKAGE} ) 78 | if ( no_exceptions ) 79 | target_compile_options ( ${PROGRAM}-${name}${ne} PRIVATE ${NO_EXCEPTIONS_OPTIONS} ) 80 | else() 81 | target_compile_options ( ${PROGRAM}-${name}${ne} PRIVATE ${EXCEPTIONS_OPTIONS} ) 82 | endif() 83 | 84 | endfunction() 85 | 86 | # Create targets: 87 | 88 | foreach( target ${BASENAMES} ) 89 | make_target( ${target} FALSE ) 90 | endforeach() 91 | 92 | foreach( target ${BASENAMES_NE} ) 93 | make_target( ${target} TRUE ) 94 | endforeach() 95 | 96 | # end of file 97 | -------------------------------------------------------------------------------- /include/nonstd/bit.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020-2020 Martin Moene 3 | // 4 | // https://github.com/martinmoene/bit-lite 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 | 9 | #ifndef NONSTD_BIT_LITE_HPP 10 | #define NONSTD_BIT_LITE_HPP 11 | 12 | #define bit_lite_MAJOR 0 13 | #define bit_lite_MINOR 1 14 | #define bit_lite_PATCH 0 15 | 16 | #define bit_lite_VERSION bit_STRINGIFY(bit_lite_MAJOR) "." bit_STRINGIFY(bit_lite_MINOR) "." bit_STRINGIFY(bit_lite_PATCH) 17 | 18 | #define bit_STRINGIFY( x ) bit_STRINGIFY_( x ) 19 | #define bit_STRINGIFY_( x ) #x 20 | 21 | // bit-lite configuration: 22 | 23 | #define bit_BIT_DEFAULT 0 24 | #define bit_BIT_NONSTD 1 25 | #define bit_BIT_STD 2 26 | 27 | #if !defined( bit_CONFIG_SELECT_BIT ) 28 | # define bit_CONFIG_SELECT_BIT ( bit_HAVE_STD_BIT ? bit_BIT_STD : bit_BIT_NONSTD ) 29 | #endif 30 | 31 | #if !defined( bit_CONFIG_STRICT ) 32 | # define bit_CONFIG_STRICT 0 33 | #endif 34 | 35 | // C++ language version detection (C++23 is speculative): 36 | // Note: VC14.0/1900 (VS2015) lacks too much from C++14. 37 | 38 | #ifndef bit_CPLUSPLUS 39 | # if defined(_MSVC_LANG ) && !defined(__clang__) 40 | # define bit_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) 41 | # else 42 | # define bit_CPLUSPLUS __cplusplus 43 | # endif 44 | #endif 45 | 46 | #define bit_CPP98_OR_GREATER ( bit_CPLUSPLUS >= 199711L ) 47 | #define bit_CPP11_OR_GREATER ( bit_CPLUSPLUS >= 201103L ) 48 | #define bit_CPP14_OR_GREATER ( bit_CPLUSPLUS >= 201402L ) 49 | #define bit_CPP17_OR_GREATER ( bit_CPLUSPLUS >= 201703L ) 50 | #define bit_CPP20_OR_GREATER ( bit_CPLUSPLUS >= 202002L ) 51 | #define bit_CPP23_OR_GREATER ( bit_CPLUSPLUS >= 202300L ) 52 | 53 | // Use C++20 std bit operations if available and requested: 54 | 55 | #if bit_CPP20_OR_GREATER && defined(__has_include ) 56 | # if __has_include( ) 57 | # define bit_HAVE_STD_BIT 1 58 | # else 59 | # define bit_HAVE_STD_BIT 0 60 | # endif 61 | #else 62 | # define bit_HAVE_STD_BIT 0 63 | #endif 64 | 65 | #define bit_USES_STD_BIT ( (bit_CONFIG_SELECT_BIT == bit_BIT_STD) || ((bit_CONFIG_SELECT_BIT == bit_BIT_DEFAULT) && bit_HAVE_STD_BIT) ) 66 | 67 | // 68 | // Using std : 69 | // 70 | 71 | #if bit_USES_STD_BIT 72 | 73 | #include 74 | 75 | namespace nonstd 76 | { 77 | using std::bit_cast; 78 | 79 | using std::has_single_bit; 80 | using std::bit_ceil; 81 | using std::bit_floor; 82 | using std::bit_width; 83 | 84 | using std::rotl; 85 | using std::rotr; 86 | 87 | using std::countl_zero; 88 | using std::countl_one; 89 | using std::countr_zero; 90 | using std::countr_one; 91 | using std::popcount; 92 | 93 | using std::endian; 94 | } 95 | 96 | #else // bit_USES_STD_BIT 97 | 98 | // half-open range [lo..hi): 99 | #define bit_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) 100 | 101 | // Compiler versions: 102 | // 103 | // MSVC++ 6.0 _MSC_VER == 1200 bit_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) 104 | // MSVC++ 7.0 _MSC_VER == 1300 bit_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) 105 | // MSVC++ 7.1 _MSC_VER == 1310 bit_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) 106 | // MSVC++ 8.0 _MSC_VER == 1400 bit_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) 107 | // MSVC++ 9.0 _MSC_VER == 1500 bit_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) 108 | // MSVC++ 10.0 _MSC_VER == 1600 bit_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) 109 | // MSVC++ 11.0 _MSC_VER == 1700 bit_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) 110 | // MSVC++ 12.0 _MSC_VER == 1800 bit_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) 111 | // MSVC++ 14.0 _MSC_VER == 1900 bit_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) 112 | // MSVC++ 14.1 _MSC_VER >= 1910 bit_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) 113 | // MSVC++ 14.2 _MSC_VER >= 1920 bit_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) 114 | 115 | #if defined(_MSC_VER ) && !defined(__clang__) 116 | # define bit_COMPILER_MSVC_VER (_MSC_VER ) 117 | # define bit_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) 118 | #else 119 | # define bit_COMPILER_MSVC_VER 0 120 | # define bit_COMPILER_MSVC_VERSION 0 121 | #endif 122 | 123 | // Courtesy of https://github.com/gsl-lite/gsl-lite 124 | // AppleClang 7.0.0 __apple_build_version__ == 7000172 bit_COMPILER_APPLECLANG_VERSION == 700 (Xcode 7.0, 7.0.1) (LLVM 3.7.0) 125 | // AppleClang 7.0.0 __apple_build_version__ == 7000176 bit_COMPILER_APPLECLANG_VERSION == 700 (Xcode 7.1) (LLVM 3.7.0) 126 | // AppleClang 7.0.2 __apple_build_version__ == 7000181 bit_COMPILER_APPLECLANG_VERSION == 702 (Xcode 7.2, 7.2.1) (LLVM 3.7.0) 127 | // AppleClang 7.3.0 __apple_build_version__ == 7030029 bit_COMPILER_APPLECLANG_VERSION == 730 (Xcode 7.3) (LLVM 3.8.0) 128 | // AppleClang 7.3.0 __apple_build_version__ == 7030031 bit_COMPILER_APPLECLANG_VERSION == 730 (Xcode 7.3.1) (LLVM 3.8.0) 129 | // AppleClang 8.0.0 __apple_build_version__ == 8000038 bit_COMPILER_APPLECLANG_VERSION == 800 (Xcode 8.0) (LLVM 3.9.0) 130 | // AppleClang 8.0.0 __apple_build_version__ == 8000042 bit_COMPILER_APPLECLANG_VERSION == 800 (Xcode 8.1, 8.2, 8.2.1) (LLVM 3.9.0) 131 | // AppleClang 8.1.0 __apple_build_version__ == 8020038 bit_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3) (LLVM 3.9.0) 132 | // AppleClang 8.1.0 __apple_build_version__ == 8020041 bit_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3.1) (LLVM 3.9.0) 133 | // AppleClang 8.1.0 __apple_build_version__ == 8020042 bit_COMPILER_APPLECLANG_VERSION == 810 (Xcode 8.3.2, 8.3.3) (LLVM 3.9.0) 134 | // AppleClang 9.0.0 __apple_build_version__ == 9000037 bit_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.0) (LLVM 4.0.0?) 135 | // AppleClang 9.0.0 __apple_build_version__ == 9000038 bit_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.1) (LLVM 4.0.0?) 136 | // AppleClang 9.0.0 __apple_build_version__ == 9000039 bit_COMPILER_APPLECLANG_VERSION == 900 (Xcode 9.2) (LLVM 4.0.0?) 137 | // AppleClang 9.1.0 __apple_build_version__ == 9020039 bit_COMPILER_APPLECLANG_VERSION == 910 (Xcode 9.3, 9.3.1) (LLVM 5.0.2?) 138 | // AppleClang 9.1.0 __apple_build_version__ == 9020039 bit_COMPILER_APPLECLANG_VERSION == 910 (Xcode 9.4, 9.4.1) (LLVM 5.0.2?) 139 | // AppleClang 10.0.0 __apple_build_version__ == 10001145 bit_COMPILER_APPLECLANG_VERSION == 1000 (Xcode 10.0, 10.1) (LLVM 6.0.1?) 140 | // AppleClang 10.0.1 __apple_build_version__ == 10010046 bit_COMPILER_APPLECLANG_VERSION == 1001 (Xcode 10.2, 10.2.1, 10.3) (LLVM 7.0.0?) 141 | // AppleClang 11.0.0 __apple_build_version__ == 11000033 bit_COMPILER_APPLECLANG_VERSION == 1100 (Xcode 11.1, 11.2, 11.3) (LLVM 8.0.0?) 142 | 143 | #define bit_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) ) 144 | 145 | #if defined( __apple_build_version__ ) 146 | # define bit_COMPILER_APPLECLANG_VERSION bit_COMPILER_VERSION( __clang_major__, __clang_minor__, __clang_patchlevel__ ) 147 | # define bit_COMPILER_CLANG_VERSION 0 148 | #elif defined( __clang__ ) 149 | # define bit_COMPILER_APPLECLANG_VERSION 0 150 | # define bit_COMPILER_CLANG_VERSION bit_COMPILER_VERSION( __clang_major__, __clang_minor__, __clang_patchlevel__ ) 151 | #else 152 | # define bit_COMPILER_APPLECLANG_VERSION 0 153 | # define bit_COMPILER_CLANG_VERSION 0 154 | #endif 155 | 156 | #if defined(__GNUC__) && !defined(__clang__) 157 | # define bit_COMPILER_GNUC_VERSION bit_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) 158 | #else 159 | # define bit_COMPILER_GNUC_VERSION 0 160 | #endif 161 | 162 | // Presence of language and library features: 163 | 164 | #define bit_HAVE( feature ) ( bit_HAVE_##feature ) 165 | 166 | #ifdef _HAS_CPP0X 167 | # define bit_HAS_CPP0X _HAS_CPP0X 168 | #else 169 | # define bit_HAS_CPP0X 0 170 | #endif 171 | 172 | #define bit_CPP11_90 (bit_CPP11_OR_GREATER || bit_COMPILER_MSVC_VER >= 1500) 173 | #define bit_CPP11_100 (bit_CPP11_OR_GREATER || bit_COMPILER_MSVC_VER >= 1600) 174 | #define bit_CPP11_110 (bit_CPP11_OR_GREATER || bit_COMPILER_MSVC_VER >= 1700) 175 | #define bit_CPP11_120 (bit_CPP11_OR_GREATER || bit_COMPILER_MSVC_VER >= 1800) 176 | #define bit_CPP11_140 (bit_CPP11_OR_GREATER || bit_COMPILER_MSVC_VER >= 1900) 177 | 178 | #define bit_CPP14_000 (bit_CPP14_OR_GREATER) 179 | #define bit_CPP17_000 (bit_CPP17_OR_GREATER) 180 | 181 | // Presence of C++11 language features: 182 | 183 | #define bit_HAVE_CONSTEXPR_11 bit_CPP11_140 184 | #define bit_HAVE_ENUM_CLASS bit_CPP11_110 185 | #define bit_HAVE_NOEXCEPT bit_CPP11_140 186 | #define bit_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG bit_CPP11_120 187 | #define bit_HAVE_STATIC_ASSERT bit_CPP11_90 188 | 189 | // Presence of C++11 library features: 190 | 191 | #define bit_HAVE_IS_TRIVIAL bit_CPP11_110 192 | #define bit_HAVE_IS_TRIVIALLY_COPYABLE bit_CPP11_110 && !bit_BETWEEN(bit_COMPILER_GNUC_VERSION, 1, 500) // GCC >= 5 193 | #define bit_HAVE_IS_COPY_CONSTRUCTIBLE bit_CPP11_110 194 | #define bit_HAVE_IS_MOVE_CONSTRUCTIBLE bit_CPP11_110 195 | 196 | #define bit_HAVE_TYPE_TRAITS bit_CPP11_90 197 | #define bit_HAVE_TR1_TYPE_TRAITS (!! bit_COMPILER_GNUC_VERSION ) 198 | 199 | #define bit_HAVE_IS_UNSIGNED bit_HAVE_TYPE_TRAITS 200 | #define bit_HAVE_IS_SAME bit_HAVE_TYPE_TRAITS 201 | #define bit_HAVE_IS_SAME_TR1 bit_HAVE_TR1_TYPE_TRAITS 202 | 203 | #define bit_HAVE_CSTDINT bit_CPP11_90 204 | 205 | // Presence of C++14 language features: 206 | 207 | #define bit_HAVE_CONSTEXPR_14 bit_CPP14_000 208 | 209 | // Presence of C++17 language features: 210 | 211 | #define bit_HAVE_NODISCARD bit_CPP17_000 212 | 213 | // Presence of C++ language features: 214 | 215 | #if bit_HAVE_CONSTEXPR_11 216 | # define bit_constexpr constexpr 217 | #else 218 | # define bit_constexpr /*constexpr*/ 219 | #endif 220 | 221 | #if bit_HAVE_CONSTEXPR_14 222 | # define bit_constexpr14 constexpr 223 | #else 224 | # define bit_constexpr14 /*constexpr*/ 225 | #endif 226 | 227 | #if bit_HAVE_NOEXCEPT 228 | # define bit_noexcept noexcept 229 | #else 230 | # define bit_noexcept /*noexcept*/ 231 | #endif 232 | 233 | #if bit_HAVE_NODISCARD 234 | # define bit_nodiscard [[nodiscard]] 235 | #else 236 | # define bit_nodiscard /*[[nodiscard]]*/ 237 | #endif 238 | 239 | // Additional includes: 240 | 241 | #include // std::memcpy() 242 | #include // CHAR_BIT 243 | #include // std::numeric_limits<> 244 | 245 | #if bit_HAVE_TYPE_TRAITS 246 | # include 247 | #elif bit_HAVE_TR1_TYPE_TRAITS 248 | # include 249 | #endif 250 | 251 | // Method enabling (return type): 252 | 253 | #if bit_HAVE( TYPE_TRAITS ) 254 | # define bit_ENABLE_IF_R_(R, VA) typename std::enable_if< (VA), R >::type 255 | #else 256 | # define bit_ENABLE_IF_R_(R, VA) R 257 | #endif 258 | 259 | // Method enabling (function template argument): 260 | 261 | #if bit_HAVE( TYPE_TRAITS ) && bit_HAVE( DEFAULT_FUNCTION_TEMPLATE_ARG ) 262 | // VS 2013 seems to have trouble with SFINAE for default non-type arguments: 263 | # if !bit_BETWEEN( bit_COMPILER_MSVC_VERSION, 1, 140 ) 264 | # define bit_ENABLE_IF_(VA) , typename std::enable_if< ( VA ), int >::type = 0 265 | # else 266 | # define bit_ENABLE_IF_(VA) , typename = typename std::enable_if< ( VA ), ::nonstd::bit::enabler >::type 267 | # endif 268 | #else 269 | # define bit_ENABLE_IF_(VA) 270 | #endif 271 | 272 | namespace nonstd { 273 | namespace bit { 274 | 275 | // for bit_ENABLE_IF_(): 276 | 277 | /*enum*/ class enabler{}; 278 | 279 | template< typename T > 280 | bit_constexpr T bitmask( int i ) 281 | { 282 | #if bit_CPP11_OR_GREATER 283 | return static_cast( T{1} << i ); 284 | #else 285 | return static_cast( T(1) << i ); 286 | #endif 287 | } 288 | 289 | // C++11 emulation: 290 | 291 | namespace std11 { 292 | 293 | template< class T, T v > struct integral_constant { enum { value = v }; }; 294 | typedef integral_constant< bool, true > true_type; 295 | typedef integral_constant< bool, false > false_type; 296 | 297 | #if bit_HAVE( IS_TRIVIAL ) 298 | using std::is_trivial; 299 | #else 300 | template< class T > struct is_trivial : std11::true_type{}; 301 | #endif 302 | 303 | #if bit_HAVE( IS_TRIVIALLY_COPYABLE ) 304 | using std::is_trivially_copyable; 305 | #else 306 | template< class T > struct is_trivially_copyable : std11::true_type{}; 307 | #endif 308 | 309 | #if bit_HAVE( IS_COPY_CONSTRUCTIBLE ) 310 | using std::is_copy_constructible; 311 | #else 312 | template< class T > struct is_copy_constructible : std11::true_type{}; 313 | #endif 314 | 315 | #if bit_HAVE( IS_MOVE_CONSTRUCTIBLE ) 316 | using std::is_move_constructible; 317 | #else 318 | template< class T > struct is_move_constructible : std11::true_type{}; 319 | #endif 320 | 321 | #if bit_HAVE( IS_UNSIGNED ) 322 | using std::is_unsigned; 323 | #else 324 | template< class T > struct is_unsigned : std11::true_type{}; 325 | #endif 326 | 327 | #if bit_HAVE( IS_SAME ) 328 | using std::is_same; 329 | #elif bit_HAVE( IS_SAME_TR1 ) 330 | using std::tr1::is_same; 331 | #else 332 | template< class T, class U > struct is_same : std11::true_type{}; 333 | #endif 334 | 335 | } // namespace std11 336 | 337 | // C++20 emulation: 338 | 339 | namespace std20 { 340 | 341 | template< class T, class U > 342 | struct same_as : std11::integral_constant::value && std11::is_same::value> {}; 343 | 344 | } // namespace std20 345 | 346 | // 347 | // For reference: 348 | // 349 | 350 | #if 0 351 | 352 | // 26.5.3, bit_cast 353 | 354 | template< class To, class From > constexpr To bit_cast( From const & from ) noexcept; 355 | 356 | // 26.5.4, integral powers of 2 357 | 358 | template< class T > constexpr bool has_single_bit(T x) noexcept; 359 | template< class T > constexpr T bit_ceil(T x); 360 | template< class T > constexpr T bit_floor(T x) noexcept; 361 | template< class T > constexpr T bit_width(T x) noexcept; 362 | 363 | // 26.5.5, rotating 364 | 365 | template< class T > [[nodiscard]] constexpr T rotl(T x, int s) noexcept; 366 | template< class T > [[nodiscard]] constexpr T rotr(T x, int s) noexcept; 367 | 368 | // 26.5.6, counting 369 | 370 | template< class T > constexpr int countl_zero(T x) noexcept; 371 | template< class T > constexpr int countl_one(T x) noexcept; 372 | template< class T > constexpr int countr_zero(T x) noexcept; 373 | template< class T > constexpr int countr_one(T x) noexcept; 374 | template< class T > constexpr int popcount(T x) noexcept; 375 | 376 | #endif // 0: For reference 377 | 378 | // 379 | // Implementation: 380 | // 381 | 382 | // 26.5.3, bit_cast 383 | 384 | // constexpr support needs compiler magic 385 | 386 | template< class To, class From > 387 | /*constexpr*/ 388 | bit_ENABLE_IF_R_( 389 | To, 390 | ( (sizeof(To) == sizeof(From)) 391 | && std11::is_trivially_copyable::value 392 | && std11::is_trivial::value 393 | && (std11::is_copy_constructible::value || std11::is_move_constructible::value) 394 | ) 395 | ) 396 | bit_cast( From const & src ) bit_noexcept 397 | { 398 | To dst; 399 | std::memcpy( &dst, &src, sizeof(To) ); 400 | return dst; 401 | } 402 | 403 | // 26.5.5, rotating 404 | 405 | // clang 3.5 - 3.8: Infinite recursive template instantiation when using Clang while GCC works fine? 406 | // https://stackoverflow.com/questions/37931284/infinite-recursive-template-instantiation-when-using-clang-while-gcc-works-fine 407 | 408 | #if bit_BETWEEN( bit_COMPILER_CLANG_VERSION, 1, 390 ) || bit_BETWEEN( bit_COMPILER_APPLECLANG_VERSION, 1, 900 ) 409 | # define bit_constexpr_rot /*constexpr*/ 410 | #else 411 | # define bit_constexpr_rot bit_constexpr14 412 | #endif 413 | 414 | template< class T > 415 | bit_nodiscard bit_constexpr_rot T rotr_impl(T x, int s) bit_noexcept; 416 | 417 | template< class T > 418 | bit_nodiscard bit_constexpr_rot T rotl_impl(T x, int s) bit_noexcept 419 | { 420 | bit_constexpr14 int N = std::numeric_limits::digits; 421 | const int r = s % N; 422 | 423 | if ( r == 0 ) 424 | return x; 425 | else if ( r > 0 ) 426 | return static_cast( (x << r) | (x >> (N - r)) ); 427 | else /*if ( r < 0 )*/ 428 | return rotr_impl( x, -r ); 429 | } 430 | 431 | template< class T > 432 | bit_nodiscard bit_constexpr_rot T rotr_impl(T x, int s) bit_noexcept 433 | { 434 | bit_constexpr14 int N = std::numeric_limits::digits; 435 | const int r = s % N; 436 | 437 | if ( r == 0 ) 438 | return x; 439 | else if ( r > 0 ) 440 | return static_cast( (x >> r) | (x << (N - r)) ); 441 | else /*if ( r < 0 )*/ 442 | return rotl_impl( x, -r ); 443 | } 444 | 445 | template< class T 446 | bit_ENABLE_IF_( 447 | std11::is_unsigned::value 448 | ) 449 | > 450 | bit_nodiscard bit_constexpr14 T rotl(T x, int s) bit_noexcept 451 | { 452 | return rotl_impl( x, s ); 453 | } 454 | 455 | template< class T 456 | bit_ENABLE_IF_( 457 | std11::is_unsigned::value 458 | ) 459 | > 460 | bit_nodiscard bit_constexpr14 T rotr(T x, int s) bit_noexcept 461 | { 462 | return rotr_impl( x, s ); 463 | } 464 | 465 | // 26.5.6, counting 466 | 467 | template< class T 468 | bit_ENABLE_IF_( 469 | std11::is_unsigned::value 470 | ) 471 | > 472 | bit_constexpr14 int countl_zero(T x) bit_noexcept 473 | { 474 | bit_constexpr14 int N1 = CHAR_BIT * sizeof(T) - 1; 475 | 476 | int result = 0; 477 | for( int i = N1; i >= 0; --i, ++result ) 478 | { 479 | if ( 0 != (x & bitmask(i)) ) 480 | break; 481 | } 482 | return result; 483 | } 484 | 485 | template< class T 486 | bit_ENABLE_IF_( 487 | std11::is_unsigned::value 488 | ) 489 | > 490 | bit_constexpr14 int countl_one(T x) bit_noexcept 491 | { 492 | bit_constexpr14 int N1 = CHAR_BIT * sizeof(T) - 1; 493 | 494 | int result = 0; 495 | for( int i = N1; i >= 0; --i, ++result ) 496 | { 497 | if ( 0 == (x & bitmask(i)) ) 498 | break; 499 | } 500 | return result; 501 | } 502 | 503 | template< class T 504 | bit_ENABLE_IF_( 505 | std11::is_unsigned::value 506 | ) 507 | > 508 | bit_constexpr14 int countr_zero(T x) bit_noexcept 509 | { 510 | bit_constexpr14 int N = CHAR_BIT * sizeof(T); 511 | 512 | int result = 0; 513 | for( int i = 0; i < N; ++i, ++result ) 514 | { 515 | if ( 0 != (x & bitmask(i)) ) 516 | break; 517 | } 518 | return result; 519 | } 520 | 521 | template< class T 522 | bit_ENABLE_IF_( 523 | std11::is_unsigned::value 524 | ) 525 | > 526 | bit_constexpr14 int countr_one(T x) bit_noexcept 527 | { 528 | bit_constexpr14 int N = CHAR_BIT * sizeof(T); 529 | 530 | int result = 0; 531 | for( int i = 0; i < N; ++i, ++result ) 532 | { 533 | if ( 0 == (x & bitmask(i)) ) 534 | break; 535 | } 536 | return result; 537 | } 538 | 539 | template< class T 540 | bit_ENABLE_IF_( 541 | std11::is_unsigned::value 542 | ) 543 | > 544 | bit_constexpr14 int popcount(T x) bit_noexcept 545 | { 546 | bit_constexpr14 int N = CHAR_BIT * sizeof(T); 547 | 548 | int result = 0; 549 | for( int i = 0; i < N; ++i ) 550 | { 551 | if ( 0 != (x & bitmask(i)) ) 552 | ++result; 553 | } 554 | return result; 555 | } 556 | 557 | // 26.5.4, integral powers of 2 558 | 559 | template< class T 560 | bit_ENABLE_IF_( 561 | std11::is_unsigned::value 562 | ) 563 | > 564 | bit_constexpr bool has_single_bit(T x) bit_noexcept 565 | { 566 | return x != 0 && ( x & (x - 1) ) == 0; 567 | // return std::popcount(x) == 1; 568 | } 569 | 570 | template< class T 571 | bit_ENABLE_IF_( 572 | std11::is_unsigned::value 573 | ) 574 | > 575 | bit_constexpr T bit_width(T x) bit_noexcept 576 | { 577 | return static_cast(std::numeric_limits::digits - countl_zero(x) ); 578 | } 579 | 580 | template< class T > 581 | bit_constexpr T bit_ceil_impl( T x, std11::true_type /*case: same type*/) 582 | { 583 | #if bit_CPP11_OR_GREATER 584 | return T{1} << bit_width( T{x - 1} ); 585 | #else 586 | return T(1) << bit_width( T(x - 1) ); 587 | #endif 588 | } 589 | 590 | template< class T > 591 | bit_constexpr14 T bit_ceil_impl( T x, std11::false_type /*case: integral promotion*/ ) 592 | { 593 | bit_constexpr T offset_for_ub = 594 | static_cast( std::numeric_limits::digits - std::numeric_limits::digits ); 595 | 596 | #if 0 // bit_CPP14_OR_GREATER 597 | return T{ 1u << ( bit_width(T{x - 1}) + offset_for_ub ) >> offset_for_ub }; 598 | #else 599 | return T( 1u << ( bit_width(T(x - 1)) + offset_for_ub ) >> offset_for_ub ); 600 | #endif 601 | } 602 | 603 | // ToDo: pre-C++11 behaviour for types subject to integral promotion. 604 | 605 | template< class T 606 | bit_ENABLE_IF_( 607 | std11::is_unsigned::value 608 | ) 609 | > 610 | bit_constexpr T bit_ceil(T x) 611 | { 612 | return ( x <= 1u ) 613 | #if bit_CPP11_OR_GREATER 614 | ? T{1} : bit_ceil_impl( x, std20::same_as{} ); 615 | #else 616 | ? T(1) : bit_ceil_impl( x, std11::true_type() ); 617 | #endif 618 | } 619 | 620 | template< class T 621 | bit_ENABLE_IF_( 622 | std11::is_unsigned::value 623 | ) 624 | > 625 | bit_constexpr T bit_floor(T x) bit_noexcept 626 | { 627 | return (x != 0) 628 | #if bit_CPP11_OR_GREATER 629 | ? T{1} << (bit_width(x) - 1) 630 | #else 631 | ? T(1) << (bit_width(x) - 1) 632 | #endif 633 | : 0; 634 | } 635 | 636 | // 26.5.7, endian 637 | 638 | #if bit_HAVE( ENUM_CLASS ) 639 | 640 | enum class endian 641 | { 642 | #ifdef _WIN32 643 | little = 0, 644 | big = 1, 645 | native = little 646 | #else 647 | little = __ORDER_LITTLE_ENDIAN__, 648 | big = __ORDER_BIG_ENDIAN__, 649 | native = __BYTE_ORDER__ 650 | #endif 651 | }; 652 | 653 | #else // enum class 654 | 655 | class endian 656 | { 657 | public: 658 | enum endian_ 659 | { 660 | #ifdef _WIN32 661 | little = 0, 662 | big = 1, 663 | native = little 664 | #else 665 | little = __ORDER_LITTLE_ENDIAN__, 666 | big = __ORDER_BIG_ENDIAN__, 667 | native = __BYTE_ORDER__ 668 | #endif 669 | }; 670 | 671 | endian( endian_ v ) 672 | : value( v ) {} 673 | 674 | friend inline bool operator==( endian a, endian b ) { return a.value == b.value; } 675 | friend inline bool operator!=( endian a, endian b ) { return a.value != b.value; } 676 | 677 | private: 678 | endian_ value; 679 | }; 680 | 681 | #endif 682 | 683 | } // namespace bit 684 | } // namespace nonstd 685 | 686 | // 687 | // Extensions: endian conversions 688 | // 689 | 690 | #if !bit_CONFIG_STRICT 691 | 692 | #ifdef _MSC_VER 693 | # include 694 | # define bit_byteswap16 _byteswap_ushort 695 | # define bit_byteswap32 _byteswap_ulong 696 | # define bit_byteswap64 _byteswap_uint64 697 | #else 698 | # define bit_byteswap16 __builtin_bswap16 699 | # define bit_byteswap32 __builtin_bswap32 700 | # define bit_byteswap64 __builtin_bswap64 701 | #endif 702 | 703 | #if bit_HAVE( CSTDINT ) 704 | # include 705 | #endif 706 | 707 | namespace nonstd { 708 | namespace bit { 709 | 710 | // endianness selection types: 711 | 712 | typedef std11::integral_constant(endian::big )> big_endian_type; 713 | typedef std11::integral_constant(endian::little)> little_endian_type; 714 | typedef std11::integral_constant(endian::native)> native_endian_type; 715 | 716 | // make sure all unsigned types are covered, see 717 | // http://ithare.com/c-on-using-int_t-as-overload-and-template-parameters/ 718 | 719 | namespace std11 { 720 | 721 | #if bit_HAVE( CSTDINT ) 722 | using std::uint8_t; 723 | using std::uint16_t; 724 | using std::uint32_t; 725 | using std::uint64_t; 726 | #else 727 | typedef unsigned char uint8_t; 728 | typedef unsigned short int uint16_t; 729 | typedef unsigned int uint32_t; 730 | typedef unsigned long long uint64_t; 731 | #endif 732 | } // namespace std11 733 | 734 | template< size_t N > struct uint_by_size; 735 | template<> struct uint_by_size< 8> { typedef std11::uint8_t type; }; 736 | template<> struct uint_by_size<16> { typedef std11::uint16_t type; }; 737 | template<> struct uint_by_size<32> { typedef std11::uint32_t type; }; 738 | template<> struct uint_by_size<64> { typedef std11::uint64_t type; }; 739 | 740 | template< typename T > 741 | struct normalized_uint_type 742 | { 743 | typedef typename uint_by_size< CHAR_BIT * sizeof( T ) >::type type; 744 | 745 | #if bit_HAVE( STATIC_ASSERT ) 746 | static_assert( sizeof( type ) == sizeof( T ), ""); 747 | static_assert( std::is_integral::value, ""); 748 | static_assert( std11::is_unsigned::value, ""); 749 | #endif 750 | }; 751 | 752 | // to big endian (implementation): 753 | 754 | inline std11::uint8_t to_big_endian_( std11::uint8_t v, little_endian_type ) 755 | { 756 | return v; 757 | } 758 | 759 | inline std11::uint16_t to_big_endian_( std11::uint16_t v, little_endian_type ) 760 | { 761 | return bit_byteswap16( v ); 762 | } 763 | 764 | inline std11::uint32_t to_big_endian_( std11::uint32_t v, little_endian_type ) 765 | { 766 | return bit_byteswap32( v ); 767 | } 768 | 769 | inline std11::uint64_t to_big_endian_( std11::uint64_t v, little_endian_type ) 770 | { 771 | return bit_byteswap64( v ); 772 | } 773 | 774 | template< typename T > 775 | inline T to_big_endian_( T v, big_endian_type ) 776 | { 777 | return v; 778 | } 779 | 780 | // to little endian (implementation): 781 | 782 | inline std11::uint8_t to_little_endian_( std11::uint8_t v, big_endian_type ) 783 | { 784 | return v; 785 | } 786 | 787 | inline std11::uint16_t to_little_endian_( std11::uint16_t v, big_endian_type ) 788 | { 789 | return bit_byteswap16( v ); 790 | } 791 | 792 | inline std11::uint32_t to_little_endian_( std11::uint32_t v, big_endian_type ) 793 | { 794 | return bit_byteswap32( v ); 795 | } 796 | 797 | inline std11::uint64_t to_little_endian_( std11::uint64_t v, big_endian_type ) 798 | { 799 | return bit_byteswap64( v ); 800 | } 801 | 802 | template< typename T > 803 | inline T to_little_endian_( T v, little_endian_type ) 804 | { 805 | return v; 806 | } 807 | 808 | // to native endian (implementation): 809 | 810 | template< typename T > 811 | inline T to_native_endian_( T v, native_endian_type ) 812 | { 813 | return v; 814 | } 815 | 816 | template< typename T, typename EN > 817 | inline T to_native_endian_( T v, EN ) 818 | { 819 | // force conversion: 820 | return to_big_endian_( v, little_endian_type() ); 821 | } 822 | 823 | // 824 | // to_{endian}: convert unconditionally (default), or depending in given endianness. 825 | // Note: avoid C++11 default function template arguments. 826 | // 827 | 828 | template< typename T > 829 | inline T to_big_endian( T v ) 830 | { 831 | return to_big_endian_( static_cast< typename normalized_uint_type::type >( v ), little_endian_type() ); 832 | } 833 | 834 | template< typename T, typename EN > 835 | inline T to_big_endian( T v, EN ) 836 | { 837 | return to_big_endian_( static_cast< typename normalized_uint_type::type >( v ), EN() ); 838 | } 839 | 840 | template< typename T > 841 | inline T to_little_endian( T v ) 842 | { 843 | return to_little_endian_( static_cast< typename normalized_uint_type::type >( v ), big_endian_type() ); 844 | } 845 | 846 | template< typename T, typename EN > 847 | inline T to_little_endian( T v, EN ) 848 | { 849 | return to_little_endian_( static_cast< typename normalized_uint_type::type >( v ), EN() ); 850 | } 851 | 852 | template< typename T > 853 | inline T to_native_endian( T v ) 854 | { 855 | return to_native_endian_( static_cast< typename normalized_uint_type::type >( v ), native_endian_type() ); 856 | } 857 | 858 | template< typename T, typename EN > 859 | inline T to_native_endian( T v, EN ) 860 | { 861 | return to_native_endian_( static_cast< typename normalized_uint_type::type >( v ), EN() ); 862 | } 863 | 864 | // 865 | // as_{endian}: convert if different from native_endian_type. 866 | // 867 | 868 | template< typename T > 869 | inline T as_big_endian( T v ) 870 | { 871 | return to_big_endian( v, native_endian_type() ); 872 | } 873 | 874 | template< typename T > 875 | inline T as_little_endian( T v ) 876 | { 877 | return to_little_endian( v, native_endian_type() ); 878 | } 879 | 880 | template< typename T > 881 | inline T as_native_endian( T v ) 882 | { 883 | return to_native_endian( v, native_endian_type() ); 884 | } 885 | 886 | }} // namespace nonstd::bit 887 | 888 | #endif // !bit_CONFIG_STRICT 889 | 890 | // 891 | // Make type available in namespace nonstd: 892 | // 893 | 894 | namespace nonstd 895 | { 896 | using bit::bit_cast; 897 | 898 | using bit::has_single_bit; 899 | using bit::bit_ceil; 900 | using bit::bit_floor; 901 | using bit::bit_width; 902 | 903 | using bit::rotl; 904 | using bit::rotr; 905 | 906 | using bit::countl_zero; 907 | using bit::countl_one; 908 | using bit::countr_zero; 909 | using bit::countr_one; 910 | using bit::popcount; 911 | 912 | using bit::endian; 913 | } 914 | 915 | #if !bit_CONFIG_STRICT 916 | 917 | namespace nonstd 918 | { 919 | using bit::big_endian_type; 920 | using bit::little_endian_type; 921 | using bit::native_endian_type; 922 | 923 | using bit::to_big_endian; 924 | using bit::to_little_endian; 925 | using bit::to_native_endian; 926 | 927 | using bit::as_big_endian; 928 | using bit::as_little_endian; 929 | using bit::as_native_endian; 930 | } 931 | 932 | #endif // !bit_CONFIG_STRICT 933 | 934 | #endif // bit_USES_STD_BIT 935 | 936 | #endif // NONSTD_BIT_LITE_HPP 937 | -------------------------------------------------------------------------------- /script/update-version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright 2020-2020 by Martin Moene 4 | # 5 | # Distributed under the Boost Software License, Version 1.0. 6 | # (See accompbiting file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 | # 8 | # script/update-version.py 9 | # 10 | 11 | from __future__ import print_function 12 | 13 | import argparse 14 | import os 15 | import re 16 | import sys 17 | 18 | # Configuration: 19 | 20 | table = ( 21 | # path, substitute find, substitute format 22 | ( 'CMakeLists.txt' 23 | , r'\W{2,4}VERSION\W+([0-9]+\.[0-9]+\.[0-9]+)\W*$' 24 | , ' VERSION {major}.{minor}.{patch}' ) 25 | 26 | , ( 'CMakeLists.txt' 27 | , r'set\W+bit_lite_version\W+"([0-9]+\.[0-9]+\.[0-9]+)"\W+$' 28 | , 'set( bit_lite_version "{major}.{minor}.{patch}" )\n' ) 29 | 30 | # , ( 'example/cmake-pkg/CMakeLists.txt' 31 | # , r'set\W+bit_lite_version\W+"([0-9]+\.[0-9]+(\.[0-9]+)?)"\W+$' 32 | # , 'set( bit_lite_version "{major}.{minor}" )\n' ) 33 | # 34 | # , ( 'script/install-xxx-pkg.py' 35 | # , r'\bit_lite_version\s+=\s+"([0-9]+\.[0-9]+\.[0-9]+)"\s*$' 36 | # , 'bit_lite_version = "{major}.{minor}.{patch}"\n' ) 37 | 38 | # , ( 'conanfile.py' 39 | # , r'version\s+=\s+"([0-9]+\.[0-9]+\.[0-9]+)"\s*$' 40 | # , 'version = "{major}.{minor}.{patch}"' ) 41 | 42 | , ( 'include/nonstd/bit.hpp' 43 | , r'\#define\s+bit_lite_MAJOR\s+[0-9]+\s*$' 44 | , '#define bit_lite_MAJOR {major}' ) 45 | 46 | , ( 'include/nonstd/bit.hpp' 47 | , r'\#define\s+bit_lite_MINOR\s+[0-9]+\s*$' 48 | , '#define bit_lite_MINOR {minor}' ) 49 | 50 | , ( 'include/nonstd/bit.hpp' 51 | , r'\#define\s+bit_lite_PATCH\s+[0-9]+\s*$' 52 | , '#define bit_lite_PATCH {patch}\n' ) 53 | ) 54 | 55 | # End configuration. 56 | 57 | def readFile( in_path ): 58 | """Return content of file at given path""" 59 | with open( in_path, 'r' ) as in_file: 60 | contents = in_file.read() 61 | return contents 62 | 63 | def writeFile( out_path, contents ): 64 | """Write contents to file at given path""" 65 | with open( out_path, 'w' ) as out_file: 66 | out_file.write( contents ) 67 | 68 | def replaceFile( output_path, input_path ): 69 | # prevent race-condition (Python 3.3): 70 | if sys.version_info >= (3, 3): 71 | os.replace( output_path, input_path ) 72 | else: 73 | os.remove( input_path ) 74 | os.rename( output_path, input_path ) 75 | 76 | def editFileToVersion( version, info, verbose ): 77 | """Update version given file path, version regexp and new version format in info""" 78 | major, minor, patch = version.split('.') 79 | in_path, ver_re, ver_fmt = info 80 | out_path = in_path + '.tmp' 81 | new_text = ver_fmt.format( major=major, minor=minor, patch=patch ) 82 | 83 | if verbose: 84 | print( "- {path} => '{text}':".format( path=in_path, text=new_text.strip('\n') ) ) 85 | 86 | writeFile( 87 | out_path, 88 | re.sub( 89 | ver_re, new_text, readFile( in_path ) 90 | , count=0, flags=re.MULTILINE 91 | ) 92 | ) 93 | replaceFile( out_path, in_path ) 94 | 95 | def editFilesToVersion( version, table, verbose ): 96 | if verbose: 97 | print( "Editing files to version {v}:".format(v=version) ) 98 | for item in table: 99 | editFileToVersion( version, item, verbose ) 100 | 101 | def editFilesToVersionFromCommandLine(): 102 | """Update version number given on command line in paths from configuration table.""" 103 | 104 | parser = argparse.ArgumentParser( 105 | description='Update version number in files.', 106 | epilog="""""", 107 | formatter_class=argparse.RawTextHelpFormatter) 108 | 109 | parser.add_argument( 110 | 'version', 111 | metavar='version', 112 | type=str, 113 | nargs=1, 114 | help='new version number, like 1.2.3') 115 | 116 | parser.add_argument( 117 | '-v', '--verbose', 118 | action='store_true', 119 | help='report the name of the file being processed') 120 | 121 | args = parser.parse_args() 122 | 123 | editFilesToVersion( args.version[0], table, args.verbose ) 124 | 125 | 126 | if __name__ == '__main__': 127 | editFilesToVersionFromCommandLine() 128 | 129 | # end of file 130 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2022 by Martin Moene 2 | # 3 | # https://github.com/martinmoene/bit-lite 4 | # 5 | # Distributed under the Boost Software License, Version 1.0. 6 | # (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 | 8 | if( NOT DEFINED CMAKE_MINIMUM_REQUIRED_VERSION ) 9 | cmake_minimum_required( VERSION 3.5 FATAL_ERROR ) 10 | endif() 11 | 12 | project( test LANGUAGES CXX ) 13 | 14 | # unit_name provided by toplevel CMakeLists.txt [set( unit_name "xxx" )] 15 | set( PACKAGE ${unit_name}-lite ) 16 | set( PROGRAM ${unit_name}-lite ) 17 | set( SOURCES ${unit_name}-main.t.cpp ${unit_name}.t.cpp ) 18 | set( TWEAKD "." ) 19 | 20 | message( STATUS "Subproject '${PROJECT_NAME}', programs '${PROGRAM}-*'") 21 | 22 | # Configure bit-lite for testing: 23 | 24 | set( DEFCMN "" ) 25 | set( OPTIONS "" ) 26 | 27 | set( HAS_STD_FLAGS FALSE ) 28 | set( HAS_CPP98_FLAG FALSE ) 29 | set( HAS_CPP11_FLAG FALSE ) 30 | set( HAS_CPP14_FLAG FALSE ) 31 | set( HAS_CPP17_FLAG FALSE ) 32 | set( HAS_CPP20_FLAG FALSE ) 33 | set( HAS_CPPLATEST_FLAG FALSE ) 34 | 35 | if( MSVC ) 36 | message( STATUS "Matched: MSVC") 37 | 38 | set( HAS_STD_FLAGS TRUE ) 39 | 40 | set( OPTIONS -W3 -EHsc ) 41 | set( DEFINITIONS -D_SCL_SECURE_NO_WARNINGS ${DEFCMN} ) 42 | 43 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.00 ) 44 | set( HAS_CPP14_FLAG TRUE ) 45 | set( HAS_CPPLATEST_FLAG TRUE ) 46 | endif() 47 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.11 ) 48 | set( HAS_CPP17_FLAG TRUE ) 49 | endif() 50 | 51 | elseif( CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang" ) 52 | message( STATUS "CompilerId: '${CMAKE_CXX_COMPILER_ID}'") 53 | 54 | set( HAS_STD_FLAGS TRUE ) 55 | set( HAS_CPP98_FLAG TRUE ) 56 | 57 | set( OPTIONS -Wall -Wextra -Wconversion -Wsign-conversion -Wno-missing-braces -fno-elide-constructors ) 58 | set( DEFINITIONS ${DEFCMN} ) 59 | 60 | # GNU: available -std flags depends on version 61 | if( CMAKE_CXX_COMPILER_ID MATCHES "GNU" ) 62 | message( STATUS "Matched: GNU") 63 | 64 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8.0 ) 65 | set( HAS_CPP11_FLAG TRUE ) 66 | endif() 67 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9.2 ) 68 | set( HAS_CPP14_FLAG TRUE ) 69 | endif() 70 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.1.0 ) 71 | set( HAS_CPP17_FLAG TRUE ) 72 | endif() 73 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0.0 ) 74 | set( HAS_CPP20_FLAG TRUE ) 75 | endif() 76 | 77 | # AppleClang: available -std flags depends on version 78 | elseif( CMAKE_CXX_COMPILER_ID MATCHES "AppleClang" ) 79 | message( STATUS "Matched: AppleClang") 80 | 81 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0.0 ) 82 | set( HAS_CPP11_FLAG TRUE ) 83 | endif() 84 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1.0 ) 85 | set( HAS_CPP14_FLAG TRUE ) 86 | endif() 87 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.2.0 ) 88 | set( HAS_CPP17_FLAG TRUE ) 89 | endif() 90 | # if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS x.x.x ) 91 | # set( HAS_CPP20_FLAG TRUE ) 92 | # endif() 93 | 94 | # Clang: available -std flags depends on version 95 | elseif( CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) 96 | message( STATUS "Matched: Clang") 97 | 98 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.3.0 ) 99 | set( HAS_CPP11_FLAG TRUE ) 100 | endif() 101 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4.0 ) 102 | set( HAS_CPP14_FLAG TRUE ) 103 | endif() 104 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0.0 ) 105 | set( HAS_CPP17_FLAG TRUE ) 106 | endif() 107 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0.0 ) 108 | set( HAS_CPP20_FLAG TRUE ) 109 | endif() 110 | endif() 111 | 112 | elseif( CMAKE_CXX_COMPILER_ID MATCHES "Intel" ) 113 | # as is 114 | message( STATUS "Matched: Intel") 115 | else() 116 | # as is 117 | message( STATUS "Matched: nothing") 118 | endif() 119 | 120 | # enable MS C++ Core Guidelines checker if MSVC: 121 | 122 | function( enable_msvs_guideline_checker target ) 123 | if( MSVC ) 124 | set_target_properties( ${target} PROPERTIES 125 | VS_GLOBAL_EnableCppCoreCheck true 126 | VS_GLOBAL_CodeAnalysisRuleSet CppCoreCheckRules.ruleset 127 | VS_GLOBAL_RunCodeAnalysis true ) 128 | endif() 129 | endfunction() 130 | 131 | # make target, compile for given standard if specified: 132 | 133 | function( make_target target std ) 134 | message( STATUS "Make target: '${std}'" ) 135 | 136 | add_executable ( ${target} ${SOURCES} ) 137 | target_include_directories( ${target} SYSTEM PRIVATE lest ) 138 | target_include_directories( ${target} PRIVATE ${TWEAKD} ) 139 | target_link_libraries ( ${target} PRIVATE ${PACKAGE} ) 140 | target_compile_options ( ${target} PRIVATE ${OPTIONS} ) 141 | target_compile_definitions( ${target} PRIVATE ${DEFINITIONS} ) 142 | 143 | if( std ) 144 | if( MSVC ) 145 | target_compile_options( ${target} PRIVATE -std:c++${std} ) 146 | else() 147 | # Necessary for clang 3.x: 148 | target_compile_options( ${target} PRIVATE -std=c++${std} ) 149 | # Ok for clang 4 and later: 150 | # set( CMAKE_CXX_STANDARD ${std} ) 151 | # set( CMAKE_CXX_STANDARD_REQUIRED ON ) 152 | # set( CMAKE_CXX_EXTENSIONS OFF ) 153 | endif() 154 | endif() 155 | endfunction() 156 | 157 | # add generic executable, unless -std flags can be specified: 158 | 159 | if( NOT HAS_STD_FLAGS ) 160 | make_target( ${PROGRAM}.t "" ) 161 | else() 162 | # unconditionally add C++98 variant as MSVC has no option for it: 163 | if( HAS_CPP98_FLAG ) 164 | make_target( ${PROGRAM}-cpp98.t 98 ) 165 | else() 166 | make_target( ${PROGRAM}-cpp98.t "" ) 167 | endif() 168 | 169 | if( HAS_CPP11_FLAG ) 170 | make_target( ${PROGRAM}-cpp11.t 11 ) 171 | endif() 172 | 173 | if( HAS_CPP14_FLAG ) 174 | make_target( ${PROGRAM}-cpp14.t 14 ) 175 | endif() 176 | 177 | if( HAS_CPP17_FLAG ) 178 | set( std17 17 ) 179 | if( CMAKE_CXX_COMPILER_ID MATCHES "AppleClang" ) 180 | set( std17 1z ) 181 | endif() 182 | make_target( ${PROGRAM}-cpp17.t ${std17} ) 183 | enable_msvs_guideline_checker( ${PROGRAM}-cpp17.t ) 184 | endif() 185 | 186 | if( HAS_CPP20_FLAG ) 187 | make_target( ${PROGRAM}-cpp20.t 20 ) 188 | endif() 189 | 190 | if( HAS_CPPLATEST_FLAG ) 191 | make_target( ${PROGRAM}-cpplatest.t latest ) 192 | endif() 193 | endif() 194 | 195 | # with C++17 and later, honour explicit request for std::bit or nonstd::bit: 196 | 197 | if( HAS_CPP17_FLAG OR HAS_CPP20_FLAG ) 198 | set( WHICH bit_BIT_DEFAULT ) 199 | 200 | if( BIT_LITE_OPT_SELECT_STD ) 201 | set( WHICH bit_BIT_STD ) 202 | elseif( BIT_LITE_OPT_SELECT_NONSTD ) 203 | set( WHICH bit_BIT_NONSTD ) 204 | endif() 205 | 206 | message( STATUS "Subproject '${PROJECT_NAME}', C++17 and later using '${WHICH}'") 207 | 208 | if( HAS_CPP17_FLAG ) 209 | target_compile_definitions( ${PROGRAM}-cpp17.t PRIVATE bit_CONFIG_SELECT_BIT=${WHICH} ) 210 | endif() 211 | 212 | if( HAS_CPP20_FLAG ) 213 | target_compile_definitions( ${PROGRAM}-cpp20.t PRIVATE bit_CONFIG_SELECT_BIT=${WHICH} ) 214 | endif() 215 | 216 | if( HAS_CPPLATEST_FLAG ) 217 | target_compile_definitions( ${PROGRAM}-cpplatest.t PRIVATE bit_CONFIG_SELECT_BIT=${WHICH} ) 218 | endif() 219 | endif() 220 | 221 | # configure unit tests via CTest: 222 | 223 | if( HAS_STD_FLAGS ) 224 | # unconditionally add C++98 variant for MSVC: 225 | add_test( NAME test-cpp98 COMMAND ${PROGRAM}-cpp98.t ) 226 | 227 | if( HAS_CPP11_FLAG ) 228 | add_test( NAME test-cpp11 COMMAND ${PROGRAM}-cpp11.t ) 229 | endif() 230 | if( HAS_CPP14_FLAG ) 231 | add_test( NAME test-cpp14 COMMAND ${PROGRAM}-cpp14.t ) 232 | endif() 233 | if( HAS_CPP17_FLAG ) 234 | add_test( NAME test-cpp17 COMMAND ${PROGRAM}-cpp17.t ) 235 | endif() 236 | if( HAS_CPP20_FLAG ) 237 | add_test( NAME test-cpp20 COMMAND ${PROGRAM}-cpp20.t ) 238 | endif() 239 | if( HAS_CPPLATEST_FLAG ) 240 | add_test( NAME test-cpplatest COMMAND ${PROGRAM}-cpplatest.t ) 241 | endif() 242 | else() 243 | add_test( NAME test COMMAND ${PROGRAM}.t --pass ) 244 | add_test( NAME list_version COMMAND ${PROGRAM}.t --version ) 245 | add_test( NAME list_tags COMMAND ${PROGRAM}.t --list-tags ) 246 | add_test( NAME list_tests COMMAND ${PROGRAM}.t --list-tests ) 247 | endif() 248 | 249 | # end of file 250 | -------------------------------------------------------------------------------- /test/bit-main.t.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020-2020 Martin Moene 3 | // 4 | // https://github.com/martinmoene/bit-lite 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 | 9 | #include "bit-main.t.hpp" 10 | 11 | #define bit_PRESENT( x ) \ 12 | std::cout << #x << ": " << (x) << "\n" 13 | 14 | #define bit_ABSENT( x ) \ 15 | std::cout << #x << ": (undefined)\n" 16 | 17 | lest::tests & specification() 18 | { 19 | static lest::tests tests; 20 | return tests; 21 | } 22 | 23 | CASE( "bit-lite version" "[.bit][.version]" ) 24 | { 25 | bit_PRESENT( bit_lite_MAJOR ); 26 | bit_PRESENT( bit_lite_MINOR ); 27 | bit_PRESENT( bit_lite_PATCH ); 28 | bit_PRESENT( bit_lite_VERSION ); 29 | } 30 | 31 | CASE( "bit-lite configuration" "[.bit][.config]" ) 32 | { 33 | bit_PRESENT( bit_HAVE_STD_BIT ); 34 | bit_PRESENT( bit_USES_STD_BIT ); 35 | bit_PRESENT( bit_BIT_DEFAULT ); 36 | bit_PRESENT( bit_BIT_NONSTD ); 37 | bit_PRESENT( bit_BIT_STD ); 38 | bit_PRESENT( bit_CONFIG_SELECT_BIT ); 39 | // bit_PRESENT( bit_CONFIG_NO_EXCEPTIONS ); 40 | bit_PRESENT( bit_CPLUSPLUS ); 41 | } 42 | 43 | CASE( "__cplusplus" "[.stdc++]" ) 44 | { 45 | bit_PRESENT( __cplusplus ); 46 | 47 | #ifdef _MSVC_LANG 48 | bit_PRESENT( _MSVC_LANG ); 49 | #else 50 | bit_ABSENT( _MSVC_LANG ); 51 | #endif 52 | } 53 | 54 | CASE( "Compiler version" "[.compiler]" ) 55 | { 56 | #if bit_USES_STD_BIT 57 | std::cout << "(Compiler version not available: using standard )\n"; 58 | #else 59 | bit_PRESENT( bit_COMPILER_CLANG_VERSION ); 60 | bit_PRESENT( bit_COMPILER_GNUC_VERSION ); 61 | bit_PRESENT( bit_COMPILER_MSVC_VERSION ); 62 | #endif 63 | } 64 | 65 | CASE( "Presence of C++ language features" "[.stdlanguage]" ) 66 | { 67 | #if bit_USES_STD_BIT 68 | std::cout << "(Presence of C++ language features not available: using standard )\n"; 69 | #else 70 | // bit_PRESENT( bit_HAVE_AUTO ); 71 | // bit_PRESENT( bit_HAVE_NULLPTR ); 72 | // bit_PRESENT( bit_HAVE_STATIC_ASSERT ); 73 | // bit_PRESENT( bit_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG ); 74 | // bit_PRESENT( bit_HAVE_ALIAS_TEMPLATE ); 75 | bit_PRESENT( bit_HAVE_CONSTEXPR_11 ); 76 | bit_PRESENT( bit_HAVE_CONSTEXPR_14 ); 77 | bit_PRESENT( bit_HAVE_ENUM_CLASS ); 78 | // bit_PRESENT( bit_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE ); 79 | // bit_PRESENT( bit_HAVE_EXPLICIT_CONVERSION ); 80 | // bit_PRESENT( bit_HAVE_INITIALIZER_LIST ); 81 | // bit_PRESENT( bit_HAVE_IS_DEFAULT ); 82 | // bit_PRESENT( bit_HAVE_IS_DELETE ); 83 | bit_PRESENT( bit_HAVE_NOEXCEPT ); 84 | #endif 85 | } 86 | 87 | CASE( "Presence of C++ library features" "[.stdlibrary]" ) 88 | { 89 | #if bit_USES_STD_BIT 90 | std::cout << "(Presence of C++ library features not available: using standard )\n"; 91 | #else 92 | bit_PRESENT( bit_HAVE_TYPE_TRAITS ); 93 | bit_PRESENT( bit_HAVE_TR1_TYPE_TRAITS ); 94 | bit_PRESENT( bit_HAVE_IS_TRIVIAL ); 95 | bit_PRESENT( bit_HAVE_IS_TRIVIALLY_COPYABLE ); 96 | bit_PRESENT( bit_HAVE_IS_COPY_CONSTRUCTIBLE ); 97 | bit_PRESENT( bit_HAVE_IS_MOVE_CONSTRUCTIBLE ); 98 | #endif 99 | 100 | #if defined _HAS_CPP0X 101 | bit_PRESENT( _HAS_CPP0X ); 102 | #else 103 | bit_ABSENT( _HAS_CPP0X ); 104 | #endif 105 | } 106 | 107 | int main( int argc, char * argv[] ) 108 | { 109 | return lest::run( specification(), argc, argv ); 110 | } 111 | 112 | #if 0 113 | g++ -I../include -o bit-lite.t.exe bit-main.t.cpp && bit-lite.t.exe --pass 114 | g++ -std=c++98 -I../include -o bit-lite.t.exe bit-main.t.cpp && bit-lite.t.exe --pass 115 | g++ -std=c++03 -I../include -o bit-lite.t.exe bit-main.t.cpp && bit-lite.t.exe --pass 116 | g++ -std=c++0x -I../include -o bit-lite.t.exe bit-main.t.cpp && bit-lite.t.exe --pass 117 | g++ -std=c++11 -I../include -o bit-lite.t.exe bit-main.t.cpp && bit-lite.t.exe --pass 118 | g++ -std=c++14 -I../include -o bit-lite.t.exe bit-main.t.cpp && bit-lite.t.exe --pass 119 | g++ -std=c++17 -I../include -o bit-lite.t.exe bit-main.t.cpp && bit-lite.t.exe --pass 120 | 121 | cl -EHsc -I../include -Febit-lite.t.exe bit-main.t.cpp && bit-lite.t.exe --pass 122 | #endif 123 | 124 | // end of file 125 | -------------------------------------------------------------------------------- /test/bit-main.t.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020-2020 Martin Moene 3 | // 4 | // https://github.com/martinmoene/bit-lite 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 | 9 | #ifndef TEST_BIT_LITE_H_INCLUDED 10 | #define TEST_BIT_LITE_H_INCLUDED 11 | 12 | #include "nonstd/bit.hpp" 13 | 14 | // Compiler warning suppression for usage of lest: 15 | 16 | #ifdef __clang__ 17 | # pragma clang diagnostic ignored "-Wstring-conversion" 18 | # pragma clang diagnostic ignored "-Wunused-parameter" 19 | # pragma clang diagnostic ignored "-Wunused-template" 20 | # pragma clang diagnostic ignored "-Wunused-function" 21 | # pragma clang diagnostic ignored "-Wunused-member-function" 22 | #elif defined __GNUC__ 23 | # pragma GCC diagnostic ignored "-Wunused-parameter" 24 | # pragma GCC diagnostic ignored "-Wunused-function" 25 | #endif 26 | 27 | #include "lest_cpp03.hpp" 28 | 29 | #define CASE( name ) lest_CASE( specification(), name ) 30 | 31 | // Attribute externally visible for -fwhole-program: 32 | 33 | #if defined(__GNUC__) && !defined(__clang__) 34 | # define bit_ATTRIBUTE_EXT_VIS __attribute__((externally_visible)) 35 | #else 36 | # define bit_ATTRIBUTE_EXT_VIS 37 | #endif 38 | 39 | extern lest::tests & specification() bit_ATTRIBUTE_EXT_VIS; 40 | 41 | #endif // TEST_BIT_LITE_H_INCLUDED 42 | 43 | // end of file 44 | -------------------------------------------------------------------------------- /test/bit.t.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020-2020 Martin Moene 3 | // 4 | // https://github.com/martinmoene/bit-lite 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 | 9 | #include "bit-main.t.hpp" 10 | 11 | #include // CHAR_BIT, when bit_USES_STD_BIT 12 | #include 13 | 14 | #define dimension_of(a) ( sizeof(a) / sizeof(0[a]) ) 15 | 16 | #if bit_CPP11_90 17 | # include 18 | using std::uint8_t; 19 | using std::uint16_t; 20 | using std::uint32_t; 21 | using std::uint64_t; 22 | #else 23 | typedef unsigned char uint8_t; 24 | typedef unsigned short int uint16_t; 25 | typedef unsigned int uint32_t; 26 | typedef unsigned long long uint64_t; 27 | #endif 28 | 29 | #if bit_USES_STD_BIT 30 | namespace std { 31 | #else 32 | namespace nonstd { namespace bit { 33 | #endif 34 | 35 | inline std::string to_string( endian const & e ) 36 | { 37 | using nonstd::endian; 38 | 39 | if ( e == endian::little ) 40 | return "[little endian]"; 41 | else if ( e == endian::big ) 42 | return "[big endian]"; 43 | else if ( e == endian::native ) 44 | return "[native endian (distinct)]"; 45 | else 46 | return "[??? endian]"; 47 | } 48 | 49 | inline std::ostream & operator<<( std::ostream & os, endian const & e ) 50 | { 51 | return os << to_string( e ); 52 | } 53 | 54 | #if bit_USES_STD_BIT 55 | } // namespace std 56 | #else 57 | }} // namespace nonstd::bit 58 | #endif 59 | 60 | template< typename T > 61 | inline T bitmask( int i ) 62 | { 63 | return static_cast( T(1) << i ); 64 | } 65 | 66 | using namespace nonstd; 67 | 68 | // 69 | // bit_cast<>() 70 | // 71 | 72 | // nonstd::bit_cast is not const_expr: 73 | 74 | #define no_constexpr /*constexpr*/ 75 | 76 | CASE( "bit_cast<>(): successfully roundtrips uint64_t via double" " [bit.cast]" ) 77 | { 78 | const uint64_t v = 0x3fe9000000000000ull; 79 | 80 | EXPECT( v == bit_cast( bit_cast(v) ) ); 81 | } 82 | 83 | CASE( "has_single_bit(): single bit yields false for no bits set" " [bit.pow.two]" ) 84 | { 85 | EXPECT_NOT( has_single_bit( 0u ) ); 86 | } 87 | 88 | CASE( "has_single_bit(): single bit yields true for single bits set" " [bit.pow.two]" ) 89 | { 90 | typedef unsigned long type; 91 | const int N = CHAR_BIT * sizeof(type); 92 | 93 | for( int i = 0; i < N; ++i ) 94 | { 95 | // std::cout << "i:" << i << " mask:" << std::hex << bitmask(i) << std::dec << '\n'; 96 | EXPECT( has_single_bit( bitmask(i) ) ); 97 | } 98 | } 99 | 100 | CASE( "has_single_bit(): single bit yields false for multiple bits set" " [bit.pow.two]" ) 101 | { 102 | typedef unsigned long type; 103 | const int N = CHAR_BIT * sizeof(type); 104 | 105 | for( int i = 0; i < N; ++i ) 106 | { 107 | const int Ni1 = N-i-1; 108 | 109 | if ( i != Ni1 ) 110 | { 111 | EXPECT_NOT( has_single_bit( static_cast(bitmask(i) | bitmask(Ni1)) ) ); 112 | } 113 | } 114 | } 115 | 116 | #include 117 | 118 | // avoid ambiguous overload resolution for VS2010 (VC10): 119 | 120 | template< typename T > 121 | std::bitset<8> bin( T v ) 122 | { 123 | #if defined( _MSC_VER ) && _MSC_VER <= 1600 124 | return std::bitset<8>( static_cast(v) ); 125 | #else 126 | return std::bitset<8>( v ); 127 | #endif 128 | } 129 | 130 | CASE( "bit_ceil(): let N be the smallest power of 2 greater than or equal to x" " [bit.pow.two]" ) 131 | { 132 | EXPECT( bin( bit_ceil( 0u ) ) == bin( 1u ) ); 133 | EXPECT( bin( bit_ceil( 1u ) ) == bin( 1u ) ); 134 | EXPECT( bin( bit_ceil( 2u ) ) == bin( 2u ) ); 135 | EXPECT( bin( bit_ceil( 3u ) ) == bin( 4u ) ); 136 | EXPECT( bin( bit_ceil( 4u ) ) == bin( 4u ) ); 137 | EXPECT( bin( bit_ceil( 5u ) ) == bin( 8u ) ); 138 | EXPECT( bin( bit_ceil( 6u ) ) == bin( 8u ) ); 139 | EXPECT( bin( bit_ceil( 7u ) ) == bin( 8u ) ); 140 | EXPECT( bin( bit_ceil( 8u ) ) == bin( 8u ) ); 141 | EXPECT( bin( bit_ceil( 9u ) ) == bin(16u ) ); 142 | } 143 | 144 | CASE( "bit_floor(): x == 0, 0; otherwise the maximal value y such that has_single_bit(y) is true and y <= x" " [bit.pow.two]" ) 145 | { 146 | EXPECT( bin( bit_floor( 0u ) ) == bin( 0u ) ); 147 | EXPECT( bin( bit_floor( 1u ) ) == bin( 1u ) ); 148 | EXPECT( bin( bit_floor( 2u ) ) == bin( 2u ) ); 149 | EXPECT( bin( bit_floor( 3u ) ) == bin( 2u ) ); 150 | EXPECT( bin( bit_floor( 4u ) ) == bin( 4u ) ); 151 | EXPECT( bin( bit_floor( 5u ) ) == bin( 4u ) ); 152 | EXPECT( bin( bit_floor( 6u ) ) == bin( 4u ) ); 153 | EXPECT( bin( bit_floor( 7u ) ) == bin( 4u ) ); 154 | EXPECT( bin( bit_floor( 8u ) ) == bin( 8u ) ); 155 | EXPECT( bin( bit_floor( 9u ) ) == bin( 8u ) ); 156 | } 157 | 158 | CASE( "bit_width: x == 0, 0; otherwise one plus the base-2 logarithm of x, with any fractional part discarded" " [bit.pow.two]" ) 159 | { 160 | EXPECT( bit_width( 0u ) == 0u ); 161 | EXPECT( bit_width( 1u ) == 1u ); 162 | EXPECT( bit_width( 2u ) == 2u ); 163 | EXPECT( bit_width( 3u ) == 2u ); 164 | EXPECT( bit_width( 4u ) == 3u ); 165 | EXPECT( bit_width( 5u ) == 3u ); 166 | EXPECT( bit_width( 6u ) == 3u ); 167 | EXPECT( bit_width( 7u ) == 3u ); 168 | EXPECT( bit_width( 8u ) == 4u ); 169 | } 170 | 171 | CASE( "rotl(): r is 0, x; if r is positive, (x << r) | (x >> (N - r)); if r is negative, rotr(x, -r)" " [bit.rotate]" ) 172 | { 173 | uint8_t i = 29; // 0b00011101; 174 | 175 | EXPECT( bin( i ) == bin( i ) ); 176 | EXPECT( bin( rotl(i, 0) ) == bin( 29u) ); 177 | EXPECT( bin( rotl(i, 1) ) == bin( 58u) ); 178 | EXPECT( bin( rotl(i, 4) ) == bin(209u) ); 179 | EXPECT( bin( rotl(i, 9) ) == bin( 58u) ); 180 | EXPECT( bin( rotl(i,-1) ) == bin(142u) ); 181 | } 182 | 183 | CASE( "rotr(): r is 0, x; if r is positive, (x >> r) | (x << (N - r)); if r is negative, rotl(x, -r)" " [bit.rotate]" ) 184 | { 185 | uint8_t i = 29; // 0b00011101; 186 | 187 | EXPECT( bin( i ) == bin( i ) ); 188 | EXPECT( bin( rotr(i, 0) ) == bin( 29u) ); 189 | EXPECT( bin( rotr(i, 1) ) == bin(142u) ); 190 | EXPECT( bin( rotr(i, 4) ) == bin(209u) ); 191 | EXPECT( bin( rotr(i, 9) ) == bin(142u) ); 192 | EXPECT( bin( rotr(i,-1) ) == bin( 58u) ); 193 | 194 | } 195 | 196 | CASE( "countl_zero(): the number of consecutive 0 bits in the value of x, starting from the most significant bit" " [bit.count]" ) 197 | { 198 | EXPECT( countl_zero( uint8_t(0x80u) ) == 0 ); 199 | EXPECT( countl_zero( uint8_t(0x40u) ) == 1 ); 200 | EXPECT( countl_zero( uint8_t(0x20u) ) == 2 ); 201 | EXPECT( countl_zero( uint8_t(0x10u) ) == 3 ); 202 | EXPECT( countl_zero( uint8_t(0x08u) ) == 4 ); 203 | EXPECT( countl_zero( uint8_t(0x04u) ) == 5 ); 204 | EXPECT( countl_zero( uint8_t(0x02u) ) == 6 ); 205 | EXPECT( countl_zero( uint8_t(0x01u) ) == 7 ); 206 | 207 | EXPECT( countl_zero( uint8_t( 0u) ) == 8 ); 208 | EXPECT( countl_zero( uint16_t( 0u) ) == 16 ); 209 | EXPECT( countl_zero( uint32_t( 0u) ) == 32 ); 210 | EXPECT( countl_zero( uint64_t( 0u) ) == 64 ); 211 | 212 | EXPECT( countl_zero( 0u ) == static_cast( CHAR_BIT * sizeof(unsigned) ) ); 213 | } 214 | 215 | CASE( "countl_one(): the number of consecutive 1 bits in the value of x, starting from the most significant bit" " [bit.count]" ) 216 | { 217 | EXPECT( countl_one( uint8_t(0x00u) ) == 0 ); 218 | EXPECT( countl_one( uint8_t(0x80u) ) == 1 ); 219 | EXPECT( countl_one( uint8_t(0xc0u) ) == 2 ); 220 | EXPECT( countl_one( uint8_t(0xe0u) ) == 3 ); 221 | EXPECT( countl_one( uint8_t(0xf0u) ) == 4 ); 222 | EXPECT( countl_one( uint8_t(0xf8u) ) == 5 ); 223 | EXPECT( countl_one( uint8_t(0xfcu) ) == 6 ); 224 | EXPECT( countl_one( uint8_t(0xfeu) ) == 7 ); 225 | EXPECT( countl_one( uint8_t(0xffu) ) == 8 ); 226 | 227 | EXPECT( countl_one( uint8_t( -1) ) == 8 ); 228 | EXPECT( countl_one( uint16_t( -1) ) == 16 ); 229 | EXPECT( countl_one( uint32_t( -1) ) == 32 ); 230 | EXPECT( countl_one( uint64_t( -1) ) == 64 ); 231 | 232 | EXPECT( countl_one( unsigned(-1) ) == static_cast( CHAR_BIT * sizeof(unsigned) ) ); 233 | } 234 | 235 | CASE( "countr_zero(): the number of consecutive 0 bits in the value of x, starting from the least significant bit" " [bit.count]" ) 236 | { 237 | EXPECT( countr_zero( uint8_t(0x01u) ) == 0 ); 238 | EXPECT( countr_zero( uint8_t(0x02u) ) == 1 ); 239 | EXPECT( countr_zero( uint8_t(0x04u) ) == 2 ); 240 | EXPECT( countr_zero( uint8_t(0x08u) ) == 3 ); 241 | EXPECT( countr_zero( uint8_t(0x10u) ) == 4 ); 242 | EXPECT( countr_zero( uint8_t(0x20u) ) == 5 ); 243 | EXPECT( countr_zero( uint8_t(0x40u) ) == 6 ); 244 | EXPECT( countr_zero( uint8_t(0x80u) ) == 7 ); 245 | 246 | EXPECT( countr_zero( uint8_t( 0u) ) == 8 ); 247 | EXPECT( countr_zero( uint16_t( 0u) ) == 16 ); 248 | EXPECT( countr_zero( uint32_t( 0u) ) == 32 ); 249 | EXPECT( countr_zero( uint64_t( 0u) ) == 64 ); 250 | 251 | EXPECT( countr_zero( 0u ) == static_cast( CHAR_BIT * sizeof(unsigned) ) ); 252 | } 253 | 254 | CASE( "countr_one(): the number of consecutive 1 bits in the value of x, starting from the least significant bit" " [bit.count]" ) 255 | { 256 | EXPECT( countr_one( uint8_t(0x00u) ) == 0 ); 257 | EXPECT( countr_one( uint8_t(0x01u) ) == 1 ); 258 | EXPECT( countr_one( uint8_t(0x03u) ) == 2 ); 259 | EXPECT( countr_one( uint8_t(0x07u) ) == 3 ); 260 | EXPECT( countr_one( uint8_t(0x0fu) ) == 4 ); 261 | EXPECT( countr_one( uint8_t(0x1fu) ) == 5 ); 262 | EXPECT( countr_one( uint8_t(0x3fu) ) == 6 ); 263 | EXPECT( countr_one( uint8_t(0x7fu) ) == 7 ); 264 | EXPECT( countr_one( uint8_t(0xffu) ) == 8 ); 265 | 266 | EXPECT( countr_one( uint8_t( -1) ) == 8 ); 267 | EXPECT( countr_one( uint16_t( -1) ) == 16 ); 268 | EXPECT( countr_one( uint32_t( -1) ) == 32 ); 269 | EXPECT( countr_one( uint64_t( -1) ) == 64 ); 270 | 271 | EXPECT( countr_one( unsigned(-1) ) == static_cast( CHAR_BIT * sizeof(unsigned) ) ); 272 | } 273 | 274 | CASE( "popcount(): the number of 1 bits in the value of x" " [bit.count]" ) 275 | { 276 | EXPECT( popcount( uint8_t(0x00u) ) == 0 ); 277 | EXPECT( popcount( uint8_t(0x01u) ) == 1 ); 278 | EXPECT( popcount( uint8_t(0x81u) ) == 2 ); 279 | EXPECT( popcount( uint8_t(0x83u) ) == 3 ); 280 | EXPECT( popcount( uint8_t(0xc3u) ) == 4 ); 281 | EXPECT( popcount( uint8_t(0xc7u) ) == 5 ); 282 | EXPECT( popcount( uint8_t(0xe7u) ) == 6 ); 283 | EXPECT( popcount( uint8_t(0xefu) ) == 7 ); 284 | EXPECT( popcount( uint8_t(0xffu) ) == 8 ); 285 | 286 | EXPECT( popcount( unsigned(-1) ) == static_cast( CHAR_BIT * sizeof(unsigned) ) ); 287 | } 288 | 289 | CASE( "endian: little differs from big (corner-case when all scalars have size of 1 byte)" " [bit.endian]" ) 290 | { 291 | EXPECT( nonstd::endian::little != nonstd::endian::big ); 292 | } 293 | 294 | // 295 | // Extensions: endian conversions 296 | // 297 | 298 | CASE( "to_big_endian(): convert native, or little or big endian specified unsigned to big endian" " [bit.endian.extension]" ) 299 | { 300 | #if bit_USES_STD_BIT 301 | EXPECT( !!"Extension to_big_endian() not available (bit_USES_STD_BIT)" ); 302 | #elif bit_CONFIG_STRICT 303 | EXPECT( !!"Extension to_big_endian() not available (bit_CONFIG_STRICT)" ); 304 | #else 305 | EXPECT( to_big_endian( uint8_t(0x5eu) ) == 0x5eu ); 306 | EXPECT( to_big_endian( uint8_t(0x5eu), little_endian_type() ) == 0x5eu ); 307 | EXPECT( to_big_endian( uint8_t(0x5eu), big_endian_type() ) == 0x5eu ); 308 | 309 | EXPECT( to_big_endian( uint16_t(0xabcdu) ) == 0xcdabu ); 310 | EXPECT( to_big_endian( uint16_t(0xabcdu), little_endian_type() ) == 0xcdabu ); 311 | EXPECT( to_big_endian( uint16_t(0xabcdu), big_endian_type() ) == 0xabcdu ); 312 | 313 | EXPECT( to_big_endian( uint32_t(0xabcdu) ) == 0xcdab0000u ); 314 | EXPECT( to_big_endian( uint32_t(0xabcdu), little_endian_type() ) == 0xcdab0000u ); 315 | EXPECT( to_big_endian( uint32_t(0xabcdu), big_endian_type() ) == 0xabcdu ); 316 | #endif 317 | } 318 | 319 | CASE( "to_little_endian(): convert native, or little or big endian specified unsigned to little endian" " [bit.endian.extension]" ) 320 | { 321 | #if bit_USES_STD_BIT 322 | EXPECT( !!"Extension to_little_endian() not available (bit_USES_STD_BIT)" ); 323 | #elif bit_CONFIG_STRICT 324 | EXPECT( !!"Extension to_little_endian() not available (bit_CONFIG_STRICT)" ); 325 | #else 326 | EXPECT( to_little_endian( uint8_t(0x5eu) ) == 0x5eu ); 327 | EXPECT( to_little_endian( uint8_t(0x5eu), little_endian_type() ) == 0x5eu ); 328 | EXPECT( to_little_endian( uint8_t(0x5eu), big_endian_type() ) == 0x5eu ); 329 | 330 | EXPECT( to_little_endian( uint16_t(0xabcdu) ) == 0xcdabu ); 331 | EXPECT( to_little_endian( uint16_t(0xabcdu), little_endian_type() ) == 0xabcdu ); 332 | EXPECT( to_little_endian( uint16_t(0xabcdu), big_endian_type() ) == 0xcdabu ); 333 | 334 | EXPECT( to_little_endian( uint32_t(0xabcdu) ) == 0xcdab0000u ); 335 | EXPECT( to_little_endian( uint32_t(0xabcdu), little_endian_type() ) == 0xabcdu ); 336 | EXPECT( to_little_endian( uint32_t(0xabcdu), big_endian_type() ) == 0xcdab0000u ); 337 | #endif 338 | } 339 | 340 | CASE( "to_native_endian(): convert native, or little or big endian specified unsigned to native endian" " [bit.endian.extension]" ) 341 | { 342 | #if bit_USES_STD_BIT 343 | EXPECT( !!"Extension to_native_endian() not available (bit_USES_STD_BIT)" ); 344 | #elif bit_CONFIG_STRICT 345 | EXPECT( !!"Extension to_native_endian() not available (bit_CONFIG_STRICT)" ); 346 | #else 347 | EXPECT( to_native_endian( uint8_t(0x5eu) ) == 0x5eu ); 348 | EXPECT( to_native_endian( uint8_t(0x5eu), little_endian_type() ) == 0x5eu ); 349 | EXPECT( to_native_endian( uint8_t(0x5eu), big_endian_type() ) == 0x5eu ); 350 | 351 | if ( endian::native == endian::big ) 352 | { 353 | EXPECT( to_native_endian( uint16_t(0xabcdu) ) == 0xabcdu ); 354 | EXPECT( to_native_endian( uint16_t(0xabcdu), little_endian_type() ) == 0xcdabu ); 355 | EXPECT( to_native_endian( uint16_t(0xabcdu), big_endian_type() ) == 0xabcdu ); 356 | 357 | EXPECT( to_native_endian( uint32_t(0xabcdu) ) == 0xabcdu ); 358 | EXPECT( to_native_endian( uint32_t(0xabcdu), little_endian_type() ) == 0xcdab0000u ); 359 | EXPECT( to_native_endian( uint32_t(0xabcdu), big_endian_type() ) == 0xabcdu ); 360 | } 361 | else if ( endian::native == endian::little ) 362 | { 363 | EXPECT( to_native_endian( uint16_t(0xabcdu) ) == 0xabcdu ); 364 | EXPECT( to_native_endian( uint16_t(0xabcdu), little_endian_type() ) == 0xabcdu ); 365 | EXPECT( to_native_endian( uint16_t(0xabcdu), big_endian_type() ) == 0xcdabu ); 366 | 367 | EXPECT( to_native_endian( uint32_t(0xabcdu) ) == 0xabcdu ); 368 | EXPECT( to_native_endian( uint32_t(0xabcdu), little_endian_type() ) == 0xabcdu ); 369 | EXPECT( to_native_endian( uint32_t(0xabcdu), big_endian_type() ) == 0xcdab0000u ); 370 | } 371 | else 372 | { 373 | EXPECT( !!"endian::native is big nor little" ); 374 | } 375 | 376 | #endif 377 | } 378 | 379 | CASE( "as_big_endian(): provide native unsigned as big endian" " [bit.endian.extension]" ) 380 | { 381 | #if bit_USES_STD_BIT 382 | EXPECT( !!"Extension as_big_endian() not available (bit_USES_STD_BIT)" ); 383 | #elif bit_CONFIG_STRICT 384 | EXPECT( !!"Extension as_big_endian() not available (bit_CONFIG_STRICT)" ); 385 | #else 386 | if ( endian::native == endian::big ) 387 | { 388 | EXPECT( as_big_endian( uint8_t (0x5eu ) ) == 0x5eu ); 389 | EXPECT( as_big_endian( uint16_t(0xabcdu) ) == 0xabcdu ); 390 | EXPECT( as_big_endian( uint32_t(0xabcdu) ) == 0xabcdu ); 391 | } 392 | else if ( endian::native == endian::little ) 393 | { 394 | EXPECT( as_big_endian( uint8_t (0x5eu ) ) == 0x5eu ); 395 | EXPECT( as_big_endian( uint16_t(0xabcdu) ) == 0xcdabu ); 396 | EXPECT( as_big_endian( uint32_t(0xabcdu) ) == 0xcdab0000u ); 397 | } 398 | else 399 | { 400 | EXPECT( !!"endian::native is big nor little" ); 401 | } 402 | #endif 403 | } 404 | 405 | CASE( "as_little_endian(): provide native unsigned as little endian" " [bit.endian.extension]" ) 406 | { 407 | #if bit_USES_STD_BIT 408 | EXPECT( !!"Extension as_little_endian() not available (bit_USES_STD_BIT)" ); 409 | #elif bit_CONFIG_STRICT 410 | EXPECT( !!"Extension as_little_endian() not available (bit_CONFIG_STRICT)" ); 411 | #else 412 | if ( endian::native == endian::big ) 413 | { 414 | EXPECT( as_little_endian( uint8_t (0x5eu ) ) == 0x5eu ); 415 | EXPECT( as_little_endian( uint16_t(0xabcdu) ) == 0xcdabu ); 416 | EXPECT( as_little_endian( uint32_t(0xabcdu) ) == 0xcdab0000u ); 417 | } 418 | else if ( endian::native == endian::little ) 419 | { 420 | EXPECT( as_little_endian( uint8_t (0x5eu ) ) == 0x5eu ); 421 | EXPECT( as_little_endian( uint16_t(0xabcdu) ) == 0xabcdu ); 422 | EXPECT( as_little_endian( uint32_t(0xabcdu) ) == 0xabcdu ); 423 | } 424 | else 425 | { 426 | EXPECT( !!"endian::native is big nor little" ); 427 | } 428 | #endif 429 | } 430 | 431 | CASE( "as_native_endian(): provide native unsigned as native endian (identity)" " [bit.endian.extension]" ) 432 | { 433 | #if bit_USES_STD_BIT 434 | EXPECT( !!"Extension as_native_endian() not available (bit_USES_STD_BIT)" ); 435 | #elif bit_CONFIG_STRICT 436 | EXPECT( !!"Extension as_native_endian() not available (bit_CONFIG_STRICT)" ); 437 | #else 438 | EXPECT( as_native_endian( uint8_t (0x5eu ) ) == 0x5eu ); 439 | EXPECT( as_native_endian( uint16_t(0xabcdu) ) == 0xabcdu ); 440 | EXPECT( as_native_endian( uint32_t(0xabcdu) ) == 0xabcdu ); 441 | #endif 442 | } 443 | 444 | // g++ -std=c++11 -I../include -o bit.t.exe bit.t.cpp && bit.t.exe 445 | // cl -EHsc -I../include bit.t.cpp && bit.t.exe 446 | -------------------------------------------------------------------------------- /test/lest/lest_cpp03.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2013-2018 by Martin Moene 2 | // 3 | // lest is based on ideas by Kevlin Henney, see video at 4 | // http://skillsmatter.com/podcast/agile-testing/kevlin-henney-rethinking-unit-testing-in-c-plus-plus 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 7 | // file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 | 9 | #ifndef LEST_LEST_HPP_INCLUDED 10 | #define LEST_LEST_HPP_INCLUDED 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #define lest_MAJOR 1 31 | #define lest_MINOR 35 32 | #define lest_PATCH 1 33 | 34 | #define lest_VERSION lest_STRINGIFY(lest_MAJOR) "." lest_STRINGIFY(lest_MINOR) "." lest_STRINGIFY(lest_PATCH) 35 | 36 | #ifndef lest_FEATURE_COLOURISE 37 | # define lest_FEATURE_COLOURISE 0 38 | #endif 39 | 40 | #ifndef lest_FEATURE_LITERAL_SUFFIX 41 | # define lest_FEATURE_LITERAL_SUFFIX 0 42 | #endif 43 | 44 | #ifndef lest_FEATURE_REGEX_SEARCH 45 | # define lest_FEATURE_REGEX_SEARCH 0 46 | #endif 47 | 48 | #ifndef lest_FEATURE_TIME 49 | # define lest_FEATURE_TIME 1 50 | #endif 51 | 52 | #ifndef lest_FEATURE_TIME_PRECISION 53 | #define lest_FEATURE_TIME_PRECISION 0 54 | #endif 55 | 56 | #ifdef _WIN32 57 | # define lest_PLATFORM_IS_WINDOWS 1 58 | #else 59 | # define lest_PLATFORM_IS_WINDOWS 0 60 | #endif 61 | 62 | #if lest_FEATURE_REGEX_SEARCH 63 | # include 64 | #endif 65 | 66 | #if lest_FEATURE_TIME 67 | # if lest_PLATFORM_IS_WINDOWS 68 | # include 69 | # include 70 | # else 71 | # include 72 | # include 73 | # endif 74 | #endif 75 | 76 | // Compiler warning suppression: 77 | 78 | #if defined (__clang__) 79 | # pragma clang diagnostic ignored "-Waggregate-return" 80 | # pragma clang diagnostic ignored "-Woverloaded-shift-op-parentheses" 81 | # pragma clang diagnostic push 82 | # pragma clang diagnostic ignored "-Wdate-time" 83 | #elif defined (__GNUC__) 84 | # pragma GCC diagnostic ignored "-Waggregate-return" 85 | # pragma GCC diagnostic push 86 | #endif 87 | 88 | // Suppress shadow and unused-value warning for sections: 89 | 90 | #if defined (__clang__) 91 | # define lest_SUPPRESS_WSHADOW _Pragma( "clang diagnostic push" ) \ 92 | _Pragma( "clang diagnostic ignored \"-Wshadow\"" ) 93 | # define lest_SUPPRESS_WUNUSED _Pragma( "clang diagnostic push" ) \ 94 | _Pragma( "clang diagnostic ignored \"-Wunused-value\"" ) 95 | # define lest_RESTORE_WARNINGS _Pragma( "clang diagnostic pop" ) 96 | 97 | #elif defined (__GNUC__) 98 | # define lest_SUPPRESS_WSHADOW _Pragma( "GCC diagnostic push" ) \ 99 | _Pragma( "GCC diagnostic ignored \"-Wshadow\"" ) 100 | # define lest_SUPPRESS_WUNUSED _Pragma( "GCC diagnostic push" ) \ 101 | _Pragma( "GCC diagnostic ignored \"-Wunused-value\"" ) 102 | # define lest_RESTORE_WARNINGS _Pragma( "GCC diagnostic pop" ) 103 | #else 104 | # define lest_SUPPRESS_WSHADOW /*empty*/ 105 | # define lest_SUPPRESS_WUNUSED /*empty*/ 106 | # define lest_RESTORE_WARNINGS /*empty*/ 107 | #endif 108 | 109 | // Stringify: 110 | 111 | #define lest_STRINGIFY( x ) lest_STRINGIFY_( x ) 112 | #define lest_STRINGIFY_( x ) #x 113 | 114 | // Compiler versions: 115 | 116 | #if defined( _MSC_VER ) && !defined( __clang__ ) 117 | # define lest_COMPILER_MSVC_VERSION ( _MSC_VER / 10 - 10 * ( 5 + ( _MSC_VER < 1900 ) ) ) 118 | #else 119 | # define lest_COMPILER_MSVC_VERSION 0 120 | #endif 121 | 122 | #define lest_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * major + minor ) + patch ) 123 | 124 | #if defined (__clang__) 125 | # define lest_COMPILER_CLANG_VERSION lest_COMPILER_VERSION( __clang_major__, __clang_minor__, __clang_patchlevel__ ) 126 | #else 127 | # define lest_COMPILER_CLANG_VERSION 0 128 | #endif 129 | 130 | #if defined (__GNUC__) 131 | # define lest_COMPILER_GNUC_VERSION lest_COMPILER_VERSION( __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ ) 132 | #else 133 | # define lest_COMPILER_GNUC_VERSION 0 134 | #endif 135 | 136 | // C++ language version detection (C++20 is speculative): 137 | // Note: VC14.0/1900 (VS2015) lacks too much from C++14. 138 | 139 | #ifndef lest_CPLUSPLUS 140 | # if defined(_MSVC_LANG ) && !defined(__clang__) 141 | # define lest_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) 142 | # else 143 | # define lest_CPLUSPLUS __cplusplus 144 | # endif 145 | #endif 146 | 147 | #define lest_CPP98_OR_GREATER ( lest_CPLUSPLUS >= 199711L ) 148 | #define lest_CPP11_OR_GREATER ( lest_CPLUSPLUS >= 201103L || lest_COMPILER_MSVC_VERSION >= 120 ) 149 | #define lest_CPP14_OR_GREATER ( lest_CPLUSPLUS >= 201402L ) 150 | #define lest_CPP17_OR_GREATER ( lest_CPLUSPLUS >= 201703L ) 151 | #define lest_CPP20_OR_GREATER ( lest_CPLUSPLUS >= 202000L ) 152 | 153 | #define lest_CPP11_100 (lest_CPP11_OR_GREATER || lest_COMPILER_MSVC_VERSION >= 100) 154 | 155 | #ifndef __has_cpp_attribute 156 | # define __has_cpp_attribute(name) 0 157 | #endif 158 | 159 | // Indicate argument as possibly unused, if possible: 160 | 161 | #if __has_cpp_attribute(maybe_unused) && lest_CPP17_OR_GREATER 162 | # define lest_MAYBE_UNUSED(ARG) [[maybe_unused]] ARG 163 | #elif defined (__GNUC__) 164 | # define lest_MAYBE_UNUSED(ARG) ARG __attribute((unused)) 165 | #else 166 | # define lest_MAYBE_UNUSED(ARG) ARG 167 | #endif 168 | 169 | // Presence of language and library features: 170 | 171 | #define lest_HAVE(FEATURE) ( lest_HAVE_##FEATURE ) 172 | 173 | // Presence of C++11 language features: 174 | 175 | #define lest_HAVE_NOEXCEPT ( lest_CPP11_100 ) 176 | #define lest_HAVE_NULLPTR ( lest_CPP11_100 ) 177 | 178 | // C++ feature usage: 179 | 180 | #if lest_HAVE( NULLPTR ) 181 | # define lest_nullptr nullptr 182 | #else 183 | # define lest_nullptr NULL 184 | #endif 185 | 186 | // Additional includes and tie: 187 | 188 | #if lest_CPP11_100 189 | 190 | # include 191 | # include 192 | # include 193 | 194 | namespace lest 195 | { 196 | using std::tie; 197 | } 198 | 199 | #else 200 | 201 | # if !defined(__clang__) && defined(__GNUC__) 202 | # pragma GCC diagnostic push 203 | # pragma GCC diagnostic ignored "-Weffc++" 204 | # endif 205 | 206 | namespace lest 207 | { 208 | // tie: 209 | 210 | template< typename T1, typename T2 > 211 | struct Tie 212 | { 213 | Tie( T1 & first_, T2 & second_) 214 | : first( first_), second( second_) {} 215 | 216 | std::pair const & 217 | operator=( std::pair const & rhs ) 218 | { 219 | first = rhs.first; 220 | second = rhs.second; 221 | return rhs; 222 | } 223 | 224 | private: 225 | void operator=( Tie const & ); 226 | 227 | T1 & first; 228 | T2 & second; 229 | }; 230 | 231 | template< typename T1, typename T2 > 232 | inline Tie tie( T1 & first, T2 & second ) 233 | { 234 | return Tie( first, second ); 235 | } 236 | } 237 | 238 | # if !defined(__clang__) && defined(__GNUC__) 239 | # pragma GCC diagnostic pop 240 | # endif 241 | 242 | #endif // lest_CPP11_100 243 | 244 | namespace lest 245 | { 246 | using std::abs; 247 | using std::min; 248 | using std::strtol; 249 | using std::rand; 250 | using std::srand; 251 | } 252 | 253 | #if ! defined( lest_NO_SHORT_MACRO_NAMES ) && ! defined( lest_NO_SHORT_ASSERTION_NAMES ) 254 | # define SETUP lest_SETUP 255 | # define SECTION lest_SECTION 256 | 257 | # define EXPECT lest_EXPECT 258 | # define EXPECT_NOT lest_EXPECT_NOT 259 | # define EXPECT_NO_THROW lest_EXPECT_NO_THROW 260 | # define EXPECT_THROWS lest_EXPECT_THROWS 261 | # define EXPECT_THROWS_AS lest_EXPECT_THROWS_AS 262 | 263 | # define SCENARIO lest_SCENARIO 264 | # define GIVEN lest_GIVEN 265 | # define WHEN lest_WHEN 266 | # define THEN lest_THEN 267 | # define AND_WHEN lest_AND_WHEN 268 | # define AND_THEN lest_AND_THEN 269 | #endif 270 | 271 | #define lest_SCENARIO( specification, sketch ) \ 272 | lest_CASE( specification, lest::text("Scenario: ") + sketch ) 273 | #define lest_GIVEN( context ) lest_SETUP( lest::text(" Given: ") + context ) 274 | #define lest_WHEN( story ) lest_SECTION( lest::text(" When: ") + story ) 275 | #define lest_THEN( story ) lest_SECTION( lest::text(" Then: ") + story ) 276 | #define lest_AND_WHEN( story ) lest_SECTION( lest::text("And then: ") + story ) 277 | #define lest_AND_THEN( story ) lest_SECTION( lest::text("And then: ") + story ) 278 | 279 | #define lest_CASE( specification, proposition ) \ 280 | static void lest_FUNCTION( lest::env & ); \ 281 | namespace { lest::add_test lest_REGISTRAR( specification, lest::test( proposition, lest_FUNCTION ) ); } \ 282 | static void lest_FUNCTION( lest_MAYBE_UNUSED( lest::env & lest_env ) ) 283 | 284 | #define lest_ADD_TEST( specification, test ) \ 285 | specification.push_back( test ) 286 | 287 | #define lest_SETUP( context ) \ 288 | for ( int lest__section = 0, lest__count = 1; lest__section < lest__count; lest__count -= 0==lest__section++ ) \ 289 | for ( lest::ctx lest__ctx_setup( lest_env, context ); lest__ctx_setup; ) 290 | 291 | #define lest_SECTION( proposition ) \ 292 | lest_SUPPRESS_WSHADOW \ 293 | static int lest_UNIQUE( id ) = 0; \ 294 | if ( lest::guard( lest_UNIQUE( id ), lest__section, lest__count ) ) \ 295 | for ( int lest__section = 0, lest__count = 1; lest__section < lest__count; lest__count -= 0==lest__section++ ) \ 296 | for ( lest::ctx lest__ctx_section( lest_env, proposition ); lest__ctx_section; ) \ 297 | lest_RESTORE_WARNINGS 298 | 299 | #define lest_EXPECT( expr ) \ 300 | do { \ 301 | try \ 302 | { \ 303 | if ( lest::result score = lest_DECOMPOSE( expr ) ) \ 304 | throw lest::failure( lest_LOCATION, #expr, score.decomposition ); \ 305 | else if ( lest_env.pass() ) \ 306 | lest::report( lest_env.os, lest::passing( lest_LOCATION, #expr, score.decomposition, lest_env.zen() ), lest_env.context() ); \ 307 | } \ 308 | catch(...) \ 309 | { \ 310 | lest::inform( lest_LOCATION, #expr ); \ 311 | } \ 312 | } while ( lest::is_false() ) 313 | 314 | #define lest_EXPECT_NOT( expr ) \ 315 | do { \ 316 | try \ 317 | { \ 318 | if ( lest::result score = lest_DECOMPOSE( expr ) ) \ 319 | { \ 320 | if ( lest_env.pass() ) \ 321 | lest::report( lest_env.os, lest::passing( lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ), lest_env.zen() ), lest_env.context() ); \ 322 | } \ 323 | else \ 324 | throw lest::failure( lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) ); \ 325 | } \ 326 | catch(...) \ 327 | { \ 328 | lest::inform( lest_LOCATION, lest::not_expr( #expr ) ); \ 329 | } \ 330 | } while ( lest::is_false() ) 331 | 332 | #define lest_EXPECT_NO_THROW( expr ) \ 333 | do \ 334 | { \ 335 | try \ 336 | { \ 337 | lest_SUPPRESS_WUNUSED \ 338 | expr; \ 339 | lest_RESTORE_WARNINGS \ 340 | } \ 341 | catch (...) { lest::inform( lest_LOCATION, #expr ); } \ 342 | if ( lest_env.pass() ) \ 343 | lest::report( lest_env.os, lest::got_none( lest_LOCATION, #expr ), lest_env.context() ); \ 344 | } while ( lest::is_false() ) 345 | 346 | #define lest_EXPECT_THROWS( expr ) \ 347 | do \ 348 | { \ 349 | try \ 350 | { \ 351 | lest_SUPPRESS_WUNUSED \ 352 | expr; \ 353 | lest_RESTORE_WARNINGS \ 354 | } \ 355 | catch (...) \ 356 | { \ 357 | if ( lest_env.pass() ) \ 358 | lest::report( lest_env.os, lest::got( lest_LOCATION, #expr ), lest_env.context() ); \ 359 | break; \ 360 | } \ 361 | throw lest::expected( lest_LOCATION, #expr ); \ 362 | } \ 363 | while ( lest::is_false() ) 364 | 365 | #define lest_EXPECT_THROWS_AS( expr, excpt ) \ 366 | do \ 367 | { \ 368 | try \ 369 | { \ 370 | lest_SUPPRESS_WUNUSED \ 371 | expr; \ 372 | lest_RESTORE_WARNINGS \ 373 | } \ 374 | catch ( excpt & ) \ 375 | { \ 376 | if ( lest_env.pass() ) \ 377 | lest::report( lest_env.os, lest::got( lest_LOCATION, #expr, lest::of_type( #excpt ) ), lest_env.context() ); \ 378 | break; \ 379 | } \ 380 | catch (...) {} \ 381 | throw lest::expected( lest_LOCATION, #expr, lest::of_type( #excpt ) ); \ 382 | } \ 383 | while ( lest::is_false() ) 384 | 385 | #define lest_DECOMPOSE( expr ) ( lest::expression_decomposer() << expr ) 386 | 387 | #define lest_STRING( name ) lest_STRING2( name ) 388 | #define lest_STRING2( name ) #name 389 | 390 | #define lest_UNIQUE( name ) lest_UNIQUE2( name, __LINE__ ) 391 | #define lest_UNIQUE2( name, line ) lest_UNIQUE3( name, line ) 392 | #define lest_UNIQUE3( name, line ) name ## line 393 | 394 | #define lest_LOCATION lest::location(__FILE__, __LINE__) 395 | 396 | #define lest_FUNCTION lest_UNIQUE(__lest_function__ ) 397 | #define lest_REGISTRAR lest_UNIQUE(__lest_registrar__ ) 398 | 399 | #define lest_DIMENSION_OF( a ) ( sizeof(a) / sizeof(0[a]) ) 400 | 401 | namespace lest { 402 | 403 | const int exit_max_value = 255; 404 | 405 | typedef std::string text; 406 | typedef std::vector texts; 407 | 408 | struct env; 409 | 410 | struct test 411 | { 412 | text name; 413 | void (* behaviour)( env & ); 414 | 415 | test( text name_, void (* behaviour_)( env & ) ) 416 | : name( name_), behaviour( behaviour_) {} 417 | }; 418 | 419 | typedef std::vector tests; 420 | typedef tests test_specification; 421 | 422 | struct add_test 423 | { 424 | add_test( tests & specification, test const & test_case ) 425 | { 426 | specification.push_back( test_case ); 427 | } 428 | }; 429 | 430 | struct result 431 | { 432 | const bool passed; 433 | const text decomposition; 434 | 435 | template< typename T > 436 | result( T const & passed_, text decomposition_) 437 | : passed( !!passed_), decomposition( decomposition_) {} 438 | 439 | operator bool() { return ! passed; } 440 | }; 441 | 442 | struct location 443 | { 444 | const text file; 445 | const int line; 446 | 447 | location( text file_, int line_) 448 | : file( file_), line( line_) {} 449 | }; 450 | 451 | struct comment 452 | { 453 | const text info; 454 | 455 | comment( text info_) : info( info_) {} 456 | operator bool() { return ! info.empty(); } 457 | }; 458 | 459 | struct message : std::runtime_error 460 | { 461 | const text kind; 462 | const location where; 463 | const comment note; 464 | 465 | #if ! lest_CPP11_OR_GREATER 466 | ~message() throw() {} 467 | #endif 468 | 469 | message( text kind_, location where_, text expr_, text note_ = "" ) 470 | : std::runtime_error( expr_), kind( kind_), where( where_), note( note_) {} 471 | }; 472 | 473 | struct failure : message 474 | { 475 | failure( location where_, text expr_, text decomposition_) 476 | : message( "failed", where_, expr_ + " for " + decomposition_) {} 477 | }; 478 | 479 | struct success : message 480 | { 481 | success( text kind_, location where_, text expr_, text note_ = "" ) 482 | : message( kind_, where_, expr_, note_) {} 483 | }; 484 | 485 | struct passing : success 486 | { 487 | passing( location where_, text expr_, text decomposition_, bool zen ) 488 | : success( "passed", where_, expr_ + (zen ? "":" for " + decomposition_) ) {} 489 | }; 490 | 491 | struct got_none : success 492 | { 493 | got_none( location where_, text expr_) 494 | : success( "passed: got no exception", where_, expr_) {} 495 | }; 496 | 497 | struct got : success 498 | { 499 | got( location where_, text expr_) 500 | : success( "passed: got exception", where_, expr_) {} 501 | 502 | got( location where_, text expr_, text excpt_) 503 | : success( "passed: got exception " + excpt_, where_, expr_) {} 504 | }; 505 | 506 | struct expected : message 507 | { 508 | expected( location where_, text expr_, text excpt_ = "" ) 509 | : message( "failed: didn't get exception", where_, expr_, excpt_) {} 510 | }; 511 | 512 | struct unexpected : message 513 | { 514 | unexpected( location where_, text expr_, text note_ = "" ) 515 | : message( "failed: got unexpected exception", where_, expr_, note_) {} 516 | }; 517 | 518 | struct guard 519 | { 520 | int & id; 521 | int const & section; 522 | 523 | guard( int & id_, int const & section_, int & count ) 524 | : id( id_ ), section( section_ ) 525 | { 526 | if ( section == 0 ) 527 | id = count++ - 1; 528 | } 529 | operator bool() { return id == section; } 530 | }; 531 | 532 | class approx 533 | { 534 | public: 535 | explicit approx ( double magnitude ) 536 | : epsilon_ ( 100.0 * static_cast( std::numeric_limits::epsilon() ) ) 537 | , scale_ ( 1.0 ) 538 | , magnitude_( magnitude ) {} 539 | 540 | static approx custom() { return approx( 0 ); } 541 | 542 | approx operator()( double new_magnitude ) 543 | { 544 | approx appr( new_magnitude ); 545 | appr.epsilon( epsilon_ ); 546 | appr.scale ( scale_ ); 547 | return appr; 548 | } 549 | 550 | double magnitude() const { return magnitude_; } 551 | 552 | approx & epsilon( double epsilon ) { epsilon_ = epsilon; return *this; } 553 | approx & scale ( double scale ) { scale_ = scale; return *this; } 554 | 555 | friend bool operator == ( double lhs, approx const & rhs ) 556 | { 557 | // Thanks to Richard Harris for his help refining this formula. 558 | return lest::abs( lhs - rhs.magnitude_ ) < rhs.epsilon_ * ( rhs.scale_ + (lest::min)( lest::abs( lhs ), lest::abs( rhs.magnitude_ ) ) ); 559 | } 560 | 561 | friend bool operator == ( approx const & lhs, double rhs ) { return operator==( rhs, lhs ); } 562 | friend bool operator != ( double lhs, approx const & rhs ) { return !operator==( lhs, rhs ); } 563 | friend bool operator != ( approx const & lhs, double rhs ) { return !operator==( rhs, lhs ); } 564 | 565 | friend bool operator <= ( double lhs, approx const & rhs ) { return lhs < rhs.magnitude_ || lhs == rhs; } 566 | friend bool operator <= ( approx const & lhs, double rhs ) { return lhs.magnitude_ < rhs || lhs == rhs; } 567 | friend bool operator >= ( double lhs, approx const & rhs ) { return lhs > rhs.magnitude_ || lhs == rhs; } 568 | friend bool operator >= ( approx const & lhs, double rhs ) { return lhs.magnitude_ > rhs || lhs == rhs; } 569 | 570 | private: 571 | double epsilon_; 572 | double scale_; 573 | double magnitude_; 574 | }; 575 | 576 | inline bool is_false( ) { return false; } 577 | inline bool is_true ( bool flag ) { return flag; } 578 | 579 | inline text not_expr( text message ) 580 | { 581 | return "! ( " + message + " )"; 582 | } 583 | 584 | inline text with_message( text message ) 585 | { 586 | return "with message \"" + message + "\""; 587 | } 588 | 589 | inline text of_type( text type ) 590 | { 591 | return "of type " + type; 592 | } 593 | 594 | inline void inform( location where, text expr ) 595 | { 596 | try 597 | { 598 | throw; 599 | } 600 | catch( failure const & ) 601 | { 602 | throw; 603 | } 604 | catch( std::exception const & e ) 605 | { 606 | throw unexpected( where, expr, with_message( e.what() ) ); \ 607 | } 608 | catch(...) 609 | { 610 | throw unexpected( where, expr, "of unknown type" ); \ 611 | } 612 | } 613 | 614 | // Expression decomposition: 615 | 616 | inline bool unprintable( char c ) { return 0 <= c && c < ' '; } 617 | 618 | inline std::string to_hex_string(char c) 619 | { 620 | std::ostringstream os; 621 | os << "\\x" << std::hex << std::setw(2) << std::setfill('0') << static_cast( static_cast(c) ); 622 | return os.str(); 623 | } 624 | 625 | inline std::string transformed( char chr ) 626 | { 627 | struct Tr { char chr; char const * str; } table[] = 628 | { 629 | {'\\', "\\\\" }, 630 | {'\r', "\\r" }, {'\f', "\\f" }, 631 | {'\n', "\\n" }, {'\t', "\\t" }, 632 | }; 633 | 634 | for ( Tr * pos = table; pos != table + lest_DIMENSION_OF( table ); ++pos ) 635 | { 636 | if ( chr == pos->chr ) 637 | return pos->str; 638 | } 639 | 640 | return unprintable( chr ) ? to_hex_string( chr ) : std::string( 1, chr ); 641 | } 642 | 643 | inline std::string make_tran_string( std::string const & txt ) 644 | { 645 | std::ostringstream os; 646 | for( std::string::const_iterator pos = txt.begin(); pos != txt.end(); ++pos ) 647 | os << transformed( *pos ); 648 | return os.str(); 649 | } 650 | 651 | template< typename T > 652 | inline std::string to_string( T const & value ); 653 | 654 | #if lest_CPP11_OR_GREATER || lest_COMPILER_MSVC_VERSION >= 100 655 | inline std::string to_string( std::nullptr_t const & ) { return "nullptr"; } 656 | #endif 657 | inline std::string to_string( std::string const & txt ) { return "\"" + make_tran_string( txt ) + "\""; } 658 | inline std::string to_string( char const * const & txt ) { return "\"" + make_tran_string( txt ) + "\""; } 659 | inline std::string to_string( char const & chr ) { return "'" + make_tran_string( std::string( 1, chr ) ) + "'"; } 660 | 661 | inline std::string to_string( signed char const & chr ) { return to_string( static_cast( chr ) ); } 662 | inline std::string to_string( unsigned char const & chr ) { return to_string( static_cast( chr ) ); } 663 | 664 | inline std::ostream & operator<<( std::ostream & os, approx const & appr ) 665 | { 666 | return os << appr.magnitude(); 667 | } 668 | 669 | template< typename T > 670 | inline std::string make_string( T const * ptr ) 671 | { 672 | // Note showbase affects the behavior of /integer/ output; 673 | std::ostringstream os; 674 | os << std::internal << std::hex << std::showbase << std::setw( 2 + 2 * sizeof(T*) ) << std::setfill('0') << reinterpret_cast( ptr ); 675 | return os.str(); 676 | } 677 | 678 | template< typename C, typename R > 679 | inline std::string make_string( R C::* ptr ) 680 | { 681 | std::ostringstream os; 682 | os << std::internal << std::hex << std::showbase << std::setw( 2 + 2 * sizeof(R C::* ) ) << std::setfill('0') << ptr; 683 | return os.str(); 684 | } 685 | 686 | template< typename T > 687 | struct string_maker 688 | { 689 | static std::string to_string( T const & value ) 690 | { 691 | std::ostringstream os; os << std::boolalpha << value; 692 | return os.str(); 693 | } 694 | }; 695 | 696 | template< typename T > 697 | struct string_maker< T* > 698 | { 699 | static std::string to_string( T const * ptr ) 700 | { 701 | return ! ptr ? lest_STRING( lest_nullptr ) : make_string( ptr ); 702 | } 703 | }; 704 | 705 | template< typename C, typename R > 706 | struct string_maker< R C::* > 707 | { 708 | static std::string to_string( R C::* ptr ) 709 | { 710 | return ! ptr ? lest_STRING( lest_nullptr ) : make_string( ptr ); 711 | } 712 | }; 713 | 714 | template< typename T > 715 | inline std::string to_string( T const & value ) 716 | { 717 | return string_maker::to_string( value ); 718 | } 719 | 720 | template< typename T1, typename T2 > 721 | std::string to_string( std::pair const & pair ) 722 | { 723 | std::ostringstream oss; 724 | oss << "{ " << to_string( pair.first ) << ", " << to_string( pair.second ) << " }"; 725 | return oss.str(); 726 | } 727 | 728 | #if lest_CPP11_OR_GREATER 729 | 730 | template< typename TU, std::size_t N > 731 | struct make_tuple_string 732 | { 733 | static std::string make( TU const & tuple ) 734 | { 735 | std::ostringstream os; 736 | os << to_string( std::get( tuple ) ) << ( N < std::tuple_size::value ? ", ": " "); 737 | return make_tuple_string::make( tuple ) + os.str(); 738 | } 739 | }; 740 | 741 | template< typename TU > 742 | struct make_tuple_string 743 | { 744 | static std::string make( TU const & ) { return ""; } 745 | }; 746 | 747 | template< typename ...TS > 748 | auto to_string( std::tuple const & tuple ) -> std::string 749 | { 750 | return "{ " + make_tuple_string, sizeof...(TS)>::make( tuple ) + "}"; 751 | } 752 | 753 | #endif // lest_CPP11_OR_GREATER 754 | 755 | template< typename L, typename R > 756 | std::string to_string( L const & lhs, std::string op, R const & rhs ) 757 | { 758 | std::ostringstream os; os << to_string( lhs ) << " " << op << " " << to_string( rhs ); return os.str(); 759 | } 760 | 761 | template< typename L > 762 | struct expression_lhs 763 | { 764 | L lhs; 765 | 766 | expression_lhs( L lhs_) : lhs( lhs_) {} 767 | 768 | operator result() { return result( !!lhs, to_string( lhs ) ); } 769 | 770 | template< typename R > result operator==( R const & rhs ) { return result( lhs == rhs, to_string( lhs, "==", rhs ) ); } 771 | template< typename R > result operator!=( R const & rhs ) { return result( lhs != rhs, to_string( lhs, "!=", rhs ) ); } 772 | template< typename R > result operator< ( R const & rhs ) { return result( lhs < rhs, to_string( lhs, "<" , rhs ) ); } 773 | template< typename R > result operator<=( R const & rhs ) { return result( lhs <= rhs, to_string( lhs, "<=", rhs ) ); } 774 | template< typename R > result operator> ( R const & rhs ) { return result( lhs > rhs, to_string( lhs, ">" , rhs ) ); } 775 | template< typename R > result operator>=( R const & rhs ) { return result( lhs >= rhs, to_string( lhs, ">=", rhs ) ); } 776 | }; 777 | 778 | struct expression_decomposer 779 | { 780 | template< typename L > 781 | expression_lhs operator<< ( L const & operand ) 782 | { 783 | return expression_lhs( operand ); 784 | } 785 | }; 786 | 787 | // Reporter: 788 | 789 | #if lest_FEATURE_COLOURISE 790 | 791 | inline text red ( text words ) { return "\033[1;31m" + words + "\033[0m"; } 792 | inline text green( text words ) { return "\033[1;32m" + words + "\033[0m"; } 793 | inline text gray ( text words ) { return "\033[1;30m" + words + "\033[0m"; } 794 | 795 | inline bool starts_with( text words, text with ) 796 | { 797 | return 0 == words.find( with ); 798 | } 799 | 800 | inline text replace( text words, text from, text to ) 801 | { 802 | size_t pos = words.find( from ); 803 | return pos == std::string::npos ? words : words.replace( pos, from.length(), to ); 804 | } 805 | 806 | inline text colour( text words ) 807 | { 808 | if ( starts_with( words, "failed" ) ) return replace( words, "failed", red ( "failed" ) ); 809 | else if ( starts_with( words, "passed" ) ) return replace( words, "passed", green( "passed" ) ); 810 | 811 | return replace( words, "for", gray( "for" ) ); 812 | } 813 | 814 | inline bool is_cout( std::ostream & os ) { return &os == &std::cout; } 815 | 816 | struct colourise 817 | { 818 | const text words; 819 | 820 | colourise( text words ) 821 | : words( words ) {} 822 | 823 | // only colourise for std::cout, not for a stringstream as used in tests: 824 | 825 | std::ostream & operator()( std::ostream & os ) const 826 | { 827 | return is_cout( os ) ? os << colour( words ) : os << words; 828 | } 829 | }; 830 | 831 | inline std::ostream & operator<<( std::ostream & os, colourise words ) { return words( os ); } 832 | #else 833 | inline text colourise( text words ) { return words; } 834 | #endif 835 | 836 | inline text pluralise( text word,int n ) 837 | { 838 | return n == 1 ? word : word + "s"; 839 | } 840 | 841 | inline std::ostream & operator<<( std::ostream & os, comment note ) 842 | { 843 | return os << (note ? " " + note.info : "" ); 844 | } 845 | 846 | inline std::ostream & operator<<( std::ostream & os, location where ) 847 | { 848 | #ifdef __GNUG__ 849 | return os << where.file << ":" << where.line; 850 | #else 851 | return os << where.file << "(" << where.line << ")"; 852 | #endif 853 | } 854 | 855 | inline void report( std::ostream & os, message const & e, text test ) 856 | { 857 | os << e.where << ": " << colourise( e.kind ) << e.note << ": " << test << ": " << colourise( e.what() ) << std::endl; 858 | } 859 | 860 | // Test runner: 861 | 862 | #if lest_FEATURE_REGEX_SEARCH 863 | inline bool search( text re, text line ) 864 | { 865 | return std::regex_search( line, std::regex( re ) ); 866 | } 867 | #else 868 | inline bool case_insensitive_equal( char a, char b ) 869 | { 870 | return tolower( a ) == tolower( b ); 871 | } 872 | 873 | inline bool search( text part, text line ) 874 | { 875 | return std::search( 876 | line.begin(), line.end(), 877 | part.begin(), part.end(), case_insensitive_equal ) != line.end(); 878 | } 879 | #endif 880 | 881 | inline bool match( texts whats, text line ) 882 | { 883 | for ( texts::iterator what = whats.begin(); what != whats.end() ; ++what ) 884 | { 885 | if ( search( *what, line ) ) 886 | return true; 887 | } 888 | return false; 889 | } 890 | 891 | inline bool hidden( text name ) 892 | { 893 | #if lest_FEATURE_REGEX_SEARCH 894 | texts skipped; skipped.push_back( "\\[\\.\\]" ); skipped.push_back( "\\[hide\\]" ); 895 | #else 896 | texts skipped; skipped.push_back( "[." ); skipped.push_back( "[hide]" ); 897 | #endif 898 | return match( skipped, name ); 899 | } 900 | 901 | inline bool none( texts args ) 902 | { 903 | return args.size() == 0; 904 | } 905 | 906 | inline bool select( text name, texts include ) 907 | { 908 | if ( none( include ) ) 909 | { 910 | return ! hidden( name ); 911 | } 912 | 913 | bool any = false; 914 | for ( texts::reverse_iterator pos = include.rbegin(); pos != include.rend(); ++pos ) 915 | { 916 | text & part = *pos; 917 | 918 | if ( part == "@" || part == "*" ) 919 | return true; 920 | 921 | if ( search( part, name ) ) 922 | return true; 923 | 924 | if ( '!' == part[0] ) 925 | { 926 | any = true; 927 | if ( search( part.substr(1), name ) ) 928 | return false; 929 | } 930 | else 931 | { 932 | any = false; 933 | } 934 | } 935 | return any && ! hidden( name ); 936 | } 937 | 938 | inline int indefinite( int repeat ) { return repeat == -1; } 939 | 940 | #if lest_CPP11_OR_GREATER 941 | typedef std::mt19937::result_type seed_t; 942 | #else 943 | typedef unsigned int seed_t; 944 | #endif 945 | 946 | struct options 947 | { 948 | options() 949 | : help(false), abort(false), count(false), list(false), tags(false), time(false) 950 | , pass(false), zen(false), lexical(false), random(false), verbose(false), version(false), repeat(1), seed(0) {} 951 | 952 | bool help; 953 | bool abort; 954 | bool count; 955 | bool list; 956 | bool tags; 957 | bool time; 958 | bool pass; 959 | bool zen; 960 | bool lexical; 961 | bool random; 962 | bool verbose; 963 | bool version; 964 | int repeat; 965 | seed_t seed; 966 | }; 967 | 968 | struct env 969 | { 970 | std::ostream & os; 971 | options opt; 972 | text testing; 973 | std::vector< text > ctx; 974 | 975 | env( std::ostream & out, options option ) 976 | : os( out ), opt( option ), testing(), ctx() {} 977 | 978 | env & operator()( text test ) 979 | { 980 | clear(); testing = test; return *this; 981 | } 982 | 983 | bool abort() { return opt.abort; } 984 | bool pass() { return opt.pass; } 985 | bool zen() { return opt.zen; } 986 | 987 | void clear() { ctx.clear(); } 988 | void pop() { ctx.pop_back(); } 989 | void push( text proposition ) { ctx.push_back( proposition ); } 990 | 991 | text context() { return testing + sections(); } 992 | 993 | text sections() 994 | { 995 | if ( ! opt.verbose ) 996 | return ""; 997 | 998 | text msg; 999 | for( size_t i = 0; i != ctx.size(); ++i ) 1000 | { 1001 | msg += "\n " + ctx[i]; 1002 | } 1003 | return msg; 1004 | } 1005 | }; 1006 | 1007 | struct ctx 1008 | { 1009 | env & environment; 1010 | bool once; 1011 | 1012 | ctx( env & environment_, text proposition_ ) 1013 | : environment( environment_), once( true ) 1014 | { 1015 | environment.push( proposition_); 1016 | } 1017 | 1018 | ~ctx() 1019 | { 1020 | #if lest_CPP17_OR_GREATER 1021 | if ( std::uncaught_exceptions() == 0 ) 1022 | #else 1023 | if ( ! std::uncaught_exception() ) 1024 | #endif 1025 | { 1026 | environment.pop(); 1027 | } 1028 | } 1029 | 1030 | operator bool() { bool result = once; once = false; return result; } 1031 | }; 1032 | 1033 | struct action 1034 | { 1035 | std::ostream & os; 1036 | 1037 | action( std::ostream & out ) : os( out ) {} 1038 | 1039 | operator int() { return 0; } 1040 | bool abort() { return false; } 1041 | action & operator()( test ) { return *this; } 1042 | 1043 | private: 1044 | action( action const & ); 1045 | void operator=( action const & ); 1046 | }; 1047 | 1048 | struct print : action 1049 | { 1050 | print( std::ostream & out ) : action( out ) {} 1051 | 1052 | print & operator()( test testing ) 1053 | { 1054 | os << testing.name << "\n"; return *this; 1055 | } 1056 | }; 1057 | 1058 | inline texts tags( text name, texts result = texts() ) 1059 | { 1060 | size_t none = std::string::npos; 1061 | size_t lb = name.find_first_of( "[" ); 1062 | size_t rb = name.find_first_of( "]" ); 1063 | 1064 | if ( lb == none || rb == none ) 1065 | return result; 1066 | 1067 | result.push_back( name.substr( lb, rb - lb + 1 ) ); 1068 | 1069 | return tags( name.substr( rb + 1 ), result ); 1070 | } 1071 | 1072 | struct ptags : action 1073 | { 1074 | std::set result; 1075 | 1076 | ptags( std::ostream & out ) : action( out ), result() {} 1077 | 1078 | ptags & operator()( test testing ) 1079 | { 1080 | texts tags_( tags( testing.name ) ); 1081 | for ( texts::iterator pos = tags_.begin(); pos != tags_.end() ; ++pos ) 1082 | result.insert( *pos ); 1083 | 1084 | return *this; 1085 | } 1086 | 1087 | ~ptags() 1088 | { 1089 | std::copy( result.begin(), result.end(), std::ostream_iterator( os, "\n" ) ); 1090 | } 1091 | }; 1092 | 1093 | struct count : action 1094 | { 1095 | int n; 1096 | 1097 | count( std::ostream & out ) : action( out ), n( 0 ) {} 1098 | 1099 | count & operator()( test ) { ++n; return *this; } 1100 | 1101 | ~count() 1102 | { 1103 | os << n << " selected " << pluralise("test", n) << "\n"; 1104 | } 1105 | }; 1106 | 1107 | #if lest_FEATURE_TIME 1108 | 1109 | #if lest_PLATFORM_IS_WINDOWS 1110 | # if ! lest_CPP11_OR_GREATER && ! lest_COMPILER_MSVC_VERSION 1111 | typedef unsigned long uint64_t; 1112 | # elif lest_COMPILER_MSVC_VERSION >= 60 && lest_COMPILER_MSVC_VERSION < 100 1113 | typedef /*un*/signed __int64 uint64_t; 1114 | # else 1115 | using ::uint64_t; 1116 | # endif 1117 | #else 1118 | # if ! lest_CPP11_OR_GREATER 1119 | typedef unsigned long long uint64_t; 1120 | # endif 1121 | #endif 1122 | 1123 | #if lest_PLATFORM_IS_WINDOWS 1124 | inline uint64_t current_ticks() 1125 | { 1126 | static LARGE_INTEGER hz = {{ 0,0 }}, hzo = {{ 0,0 }}; 1127 | if ( ! hz.QuadPart ) 1128 | { 1129 | QueryPerformanceFrequency( &hz ); 1130 | QueryPerformanceCounter ( &hzo ); 1131 | } 1132 | LARGE_INTEGER t = {{ 0,0 }}; QueryPerformanceCounter( &t ); 1133 | 1134 | return uint64_t( ( ( t.QuadPart - hzo.QuadPart ) * 1000000 ) / hz.QuadPart ); 1135 | } 1136 | #else 1137 | inline uint64_t current_ticks() 1138 | { 1139 | timeval t; gettimeofday( &t, lest_nullptr ); 1140 | return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); 1141 | } 1142 | #endif 1143 | 1144 | struct timer 1145 | { 1146 | const uint64_t start_ticks; 1147 | 1148 | timer() : start_ticks( current_ticks() ) {} 1149 | 1150 | double elapsed_seconds() const 1151 | { 1152 | return static_cast( current_ticks() - start_ticks ) / 1e6; 1153 | } 1154 | }; 1155 | 1156 | struct times : action 1157 | { 1158 | env output; 1159 | int selected; 1160 | int failures; 1161 | 1162 | timer total; 1163 | 1164 | times( std::ostream & out, options option ) 1165 | : action( out ), output( out, option ), selected( 0 ), failures( 0 ), total() 1166 | { 1167 | os << std::setfill(' ') << std::fixed << std::setprecision( lest_FEATURE_TIME_PRECISION ); 1168 | } 1169 | 1170 | operator int() { return failures; } 1171 | 1172 | bool abort() { return output.abort() && failures > 0; } 1173 | 1174 | times & operator()( test testing ) 1175 | { 1176 | timer t; 1177 | 1178 | try 1179 | { 1180 | testing.behaviour( output( testing.name ) ); 1181 | } 1182 | catch( message const & ) 1183 | { 1184 | ++failures; 1185 | } 1186 | 1187 | os << std::setw(5) << ( 1000 * t.elapsed_seconds() ) << " ms: " << testing.name << "\n"; 1188 | 1189 | return *this; 1190 | } 1191 | 1192 | ~times() 1193 | { 1194 | os << "Elapsed time: " << std::setprecision(1) << total.elapsed_seconds() << " s\n"; 1195 | } 1196 | }; 1197 | #else 1198 | struct times : action { times( std::ostream & out, options ) : action( out ) {} }; 1199 | #endif 1200 | 1201 | struct confirm : action 1202 | { 1203 | env output; 1204 | int selected; 1205 | int failures; 1206 | 1207 | confirm( std::ostream & out, options option ) 1208 | : action( out ), output( out, option ), selected( 0 ), failures( 0 ) {} 1209 | 1210 | operator int() { return failures; } 1211 | 1212 | bool abort() { return output.abort() && failures > 0; } 1213 | 1214 | confirm & operator()( test testing ) 1215 | { 1216 | try 1217 | { 1218 | ++selected; testing.behaviour( output( testing.name ) ); 1219 | } 1220 | catch( message const & e ) 1221 | { 1222 | ++failures; report( os, e, output.context() ); 1223 | } 1224 | return *this; 1225 | } 1226 | 1227 | ~confirm() 1228 | { 1229 | if ( failures > 0 ) 1230 | { 1231 | os << failures << " out of " << selected << " selected " << pluralise("test", selected) << " " << colourise( "failed.\n" ); 1232 | } 1233 | else if ( output.pass() ) 1234 | { 1235 | os << "All " << selected << " selected " << pluralise("test", selected) << " " << colourise( "passed.\n" ); 1236 | } 1237 | } 1238 | }; 1239 | 1240 | template< typename Action > 1241 | bool abort( Action & perform ) 1242 | { 1243 | return perform.abort(); 1244 | } 1245 | 1246 | template< typename Action > 1247 | Action & for_test( tests specification, texts in, Action & perform, int n = 1 ) 1248 | { 1249 | for ( int i = 0; indefinite( n ) || i < n; ++i ) 1250 | { 1251 | for ( tests::iterator pos = specification.begin(); pos != specification.end() ; ++pos ) 1252 | { 1253 | test & testing = *pos; 1254 | 1255 | if ( select( testing.name, in ) ) 1256 | if ( abort( perform( testing ) ) ) 1257 | return perform; 1258 | } 1259 | } 1260 | return perform; 1261 | } 1262 | 1263 | inline bool test_less( test const & a, test const & b ) { return a.name < b.name; } 1264 | 1265 | inline void sort( tests & specification ) 1266 | { 1267 | std::sort( specification.begin(), specification.end(), test_less ); 1268 | } 1269 | 1270 | // Use struct to avoid VC6 error C2664 when using free function: 1271 | 1272 | struct rng { int operator()( int n ) { return lest::rand() % n; } }; 1273 | 1274 | inline void shuffle( tests & specification, options option ) 1275 | { 1276 | #if lest_CPP11_OR_GREATER 1277 | std::shuffle( specification.begin(), specification.end(), std::mt19937( option.seed ) ); 1278 | #else 1279 | lest::srand( option.seed ); 1280 | 1281 | rng generator; 1282 | std::random_shuffle( specification.begin(), specification.end(), generator ); 1283 | #endif 1284 | } 1285 | 1286 | inline int stoi( text num ) 1287 | { 1288 | return static_cast( lest::strtol( num.c_str(), lest_nullptr, 10 ) ); 1289 | } 1290 | 1291 | inline bool is_number( text arg ) 1292 | { 1293 | const text digits = "0123456789"; 1294 | return text::npos != arg.find_first_of ( digits ) 1295 | && text::npos == arg.find_first_not_of( digits ); 1296 | } 1297 | 1298 | inline seed_t seed( text opt, text arg ) 1299 | { 1300 | // std::time_t: implementation dependent 1301 | 1302 | if ( arg == "time" ) 1303 | return static_cast( time( lest_nullptr ) ); 1304 | 1305 | if ( is_number( arg ) ) 1306 | return static_cast( lest::stoi( arg ) ); 1307 | 1308 | throw std::runtime_error( "expecting 'time' or positive number with option '" + opt + "', got '" + arg + "' (try option --help)" ); 1309 | } 1310 | 1311 | inline int repeat( text opt, text arg ) 1312 | { 1313 | const int num = lest::stoi( arg ); 1314 | 1315 | if ( indefinite( num ) || num >= 0 ) 1316 | return num; 1317 | 1318 | throw std::runtime_error( "expecting '-1' or positive number with option '" + opt + "', got '" + arg + "' (try option --help)" ); 1319 | } 1320 | 1321 | inline std::pair 1322 | split_option( text arg ) 1323 | { 1324 | text::size_type pos = arg.rfind( '=' ); 1325 | 1326 | return pos == text::npos 1327 | ? std::make_pair( arg, text() ) 1328 | : std::make_pair( arg.substr( 0, pos ), arg.substr( pos + 1 ) ); 1329 | } 1330 | 1331 | inline std::pair 1332 | split_arguments( texts args ) 1333 | { 1334 | options option; texts in; 1335 | 1336 | bool in_options = true; 1337 | 1338 | for ( texts::iterator pos = args.begin(); pos != args.end() ; ++pos ) 1339 | { 1340 | text opt, val, arg = *pos; 1341 | tie( opt, val ) = split_option( arg ); 1342 | 1343 | if ( in_options ) 1344 | { 1345 | if ( opt[0] != '-' ) { in_options = false; } 1346 | else if ( opt == "--" ) { in_options = false; continue; } 1347 | else if ( opt == "-h" || "--help" == opt ) { option.help = true; continue; } 1348 | else if ( opt == "-a" || "--abort" == opt ) { option.abort = true; continue; } 1349 | else if ( opt == "-c" || "--count" == opt ) { option.count = true; continue; } 1350 | else if ( opt == "-g" || "--list-tags" == opt ) { option.tags = true; continue; } 1351 | else if ( opt == "-l" || "--list-tests" == opt ) { option.list = true; continue; } 1352 | else if ( opt == "-t" || "--time" == opt ) { option.time = true; continue; } 1353 | else if ( opt == "-p" || "--pass" == opt ) { option.pass = true; continue; } 1354 | else if ( opt == "-z" || "--pass-zen" == opt ) { option.zen = true; continue; } 1355 | else if ( opt == "-v" || "--verbose" == opt ) { option.verbose = true; continue; } 1356 | else if ( "--version" == opt ) { option.version = true; continue; } 1357 | else if ( opt == "--order" && "declared" == val ) { /* by definition */ ; continue; } 1358 | else if ( opt == "--order" && "lexical" == val ) { option.lexical = true; continue; } 1359 | else if ( opt == "--order" && "random" == val ) { option.random = true; continue; } 1360 | else if ( opt == "--random-seed" ) { option.seed = seed ( "--random-seed", val ); continue; } 1361 | else if ( opt == "--repeat" ) { option.repeat = repeat( "--repeat" , val ); continue; } 1362 | else throw std::runtime_error( "unrecognised option '" + opt + "' (try option --help)" ); 1363 | } 1364 | in.push_back( arg ); 1365 | } 1366 | option.pass = option.pass || option.zen; 1367 | 1368 | return std::make_pair( option, in ); 1369 | } 1370 | 1371 | inline int usage( std::ostream & os ) 1372 | { 1373 | os << 1374 | "\nUsage: test [options] [test-spec ...]\n" 1375 | "\n" 1376 | "Options:\n" 1377 | " -h, --help this help message\n" 1378 | " -a, --abort abort at first failure\n" 1379 | " -c, --count count selected tests\n" 1380 | " -g, --list-tags list tags of selected tests\n" 1381 | " -l, --list-tests list selected tests\n" 1382 | " -p, --pass also report passing tests\n" 1383 | " -z, --pass-zen ... without expansion\n" 1384 | #if lest_FEATURE_TIME 1385 | " -t, --time list duration of selected tests\n" 1386 | #endif 1387 | " -v, --verbose also report passing or failing sections\n" 1388 | " --order=declared use source code test order (default)\n" 1389 | " --order=lexical use lexical sort test order\n" 1390 | " --order=random use random test order\n" 1391 | " --random-seed=n use n for random generator seed\n" 1392 | " --random-seed=time use time for random generator seed\n" 1393 | " --repeat=n repeat selected tests n times (-1: indefinite)\n" 1394 | " --version report lest version and compiler used\n" 1395 | " -- end options\n" 1396 | "\n" 1397 | "Test specification:\n" 1398 | " \"@\", \"*\" all tests, unless excluded\n" 1399 | " empty all tests, unless tagged [hide] or [.optional-name]\n" 1400 | #if lest_FEATURE_REGEX_SEARCH 1401 | " \"re\" select tests that match regular expression\n" 1402 | " \"!re\" omit tests that match regular expression\n" 1403 | #else 1404 | " \"text\" select tests that contain text (case insensitive)\n" 1405 | " \"!text\" omit tests that contain text (case insensitive)\n" 1406 | #endif 1407 | ; 1408 | return 0; 1409 | } 1410 | 1411 | inline text compiler() 1412 | { 1413 | std::ostringstream os; 1414 | #if defined (__clang__ ) 1415 | os << "clang " << __clang_version__; 1416 | #elif defined (__GNUC__ ) 1417 | os << "gcc " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__; 1418 | #elif defined ( _MSC_VER ) 1419 | os << "MSVC " << lest_COMPILER_MSVC_VERSION << " (" << _MSC_VER << ")"; 1420 | #else 1421 | os << "[compiler]"; 1422 | #endif 1423 | return os.str(); 1424 | } 1425 | 1426 | inline int version( std::ostream & os ) 1427 | { 1428 | os << "lest version " << lest_VERSION << "\n" 1429 | << "Compiled with " << compiler() << " on " << __DATE__ << " at " << __TIME__ << ".\n" 1430 | << "For more information, see https://github.com/martinmoene/lest.\n"; 1431 | return 0; 1432 | } 1433 | 1434 | inline int run( tests specification, texts arguments, std::ostream & os = std::cout ) 1435 | { 1436 | try 1437 | { 1438 | options option; texts in; 1439 | tie( option, in ) = split_arguments( arguments ); 1440 | 1441 | if ( option.lexical ) { sort( specification ); } 1442 | if ( option.random ) { shuffle( specification, option ); } 1443 | 1444 | if ( option.help ) { return usage ( os ); } 1445 | if ( option.version ) { return version( os ); } 1446 | if ( option.count ) { count count_( os ); return for_test( specification, in, count_ ); } 1447 | if ( option.list ) { print print_( os ); return for_test( specification, in, print_ ); } 1448 | if ( option.tags ) { ptags ptags_( os ); return for_test( specification, in, ptags_ ); } 1449 | if ( option.time ) { times times_( os, option ); return for_test( specification, in, times_ ); } 1450 | 1451 | { confirm confirm_( os, option ); return for_test( specification, in, confirm_, option.repeat ); } 1452 | } 1453 | catch ( std::exception const & e ) 1454 | { 1455 | os << "Error: " << e.what() << "\n"; 1456 | return 1; 1457 | } 1458 | } 1459 | 1460 | // VC6: make(first,last) replaces cont(first,last) 1461 | 1462 | template< typename C, typename T > 1463 | C make( T const * first, T const * const last ) 1464 | { 1465 | C result; 1466 | for ( ; first != last; ++first ) 1467 | { 1468 | result.push_back( *first ); 1469 | } 1470 | return result; 1471 | } 1472 | 1473 | inline tests make_tests( test const * first, test const * const last ) 1474 | { 1475 | return make( first, last ); 1476 | } 1477 | 1478 | inline texts make_texts( char const * const * first, char const * const * last ) 1479 | { 1480 | return make( first, last ); 1481 | } 1482 | 1483 | // Traversal of test[N] (test_specification[N]) set up to also work with MSVC6: 1484 | 1485 | template< typename C > test const * test_begin( C const & c ) { return &*c; } 1486 | template< typename C > test const * test_end( C const & c ) { return test_begin( c ) + lest_DIMENSION_OF( c ); } 1487 | 1488 | template< typename C > char const * const * text_begin( C const & c ) { return &*c; } 1489 | template< typename C > char const * const * text_end( C const & c ) { return text_begin( c ) + lest_DIMENSION_OF( c ); } 1490 | 1491 | template< typename C > tests make_tests( C const & c ) { return make_tests( test_begin( c ), test_end( c ) ); } 1492 | template< typename C > texts make_texts( C const & c ) { return make_texts( text_begin( c ), text_end( c ) ); } 1493 | 1494 | inline int run( tests const & specification, int argc, char ** argv, std::ostream & os = std::cout ) 1495 | { 1496 | return run( specification, make_texts( argv + 1, argv + argc ), os ); 1497 | } 1498 | 1499 | inline int run( tests const & specification, std::ostream & os = std::cout ) 1500 | { 1501 | std::cout.sync_with_stdio( false ); 1502 | return (min)( run( specification, texts(), os ), exit_max_value ); 1503 | } 1504 | 1505 | template< typename C > 1506 | int run( C const & specification, texts args, std::ostream & os = std::cout ) 1507 | { 1508 | return run( make_tests( specification ), args, os ); 1509 | } 1510 | 1511 | template< typename C > 1512 | int run( C const & specification, int argc, char ** argv, std::ostream & os = std::cout ) 1513 | { 1514 | return run( make_tests( specification ), argv, argc, os ); 1515 | } 1516 | 1517 | template< typename C > 1518 | int run( C const & specification, std::ostream & os = std::cout ) 1519 | { 1520 | return run( make_tests( specification ), os ); 1521 | } 1522 | 1523 | } // namespace lest 1524 | 1525 | #if defined (__clang__) 1526 | # pragma clang diagnostic pop 1527 | #elif defined (__GNUC__) 1528 | # pragma GCC diagnostic pop 1529 | #endif 1530 | 1531 | #endif // LEST_LEST_HPP_INCLUDED 1532 | -------------------------------------------------------------------------------- /test/t.bat: -------------------------------------------------------------------------------- 1 | @echo off & setlocal enableextensions enabledelayedexpansion 2 | :: 3 | :: t.bat - compile & run tests (MSVC). 4 | :: 5 | 6 | set unit=bit 7 | 8 | :: if no std is given, use compiler default 9 | 10 | set std=%1 11 | if not "%std%"=="" set std=-std:%std% 12 | 13 | call :CompilerVersion version 14 | echo VC%version%: %args% 15 | 16 | set UCAP=%unit% 17 | call :toupper UCAP 18 | 19 | set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_DEFAULT 20 | ::set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_NONSTD 21 | ::set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_STD 22 | 23 | set unit_config= 24 | 25 | set msvc_defines=^ 26 | -D_CRT_SECURE_NO_WARNINGS ^ 27 | -D_SCL_SECURE_NO_WARNINGS 28 | 29 | set CppCoreCheckInclude=%VCINSTALLDIR%\Auxiliary\VS\include 30 | 31 | cl -nologo -W3 -EHsc %std% %unit_select% %unit_config% %msvc_defines% -I"%CppCoreCheckInclude%" -Ilest -I../include -I. %unit%-main.t.cpp %unit%.t.cpp && %unit%-main.t.exe 32 | endlocal & goto :EOF 33 | 34 | :: subroutines: 35 | 36 | :CompilerVersion version 37 | @echo off & setlocal enableextensions 38 | set tmpprogram=_getcompilerversion.tmp 39 | set tmpsource=%tmpprogram%.c 40 | 41 | echo #include ^ >%tmpsource% 42 | echo int main(){printf("%%d\n",_MSC_VER);} >>%tmpsource% 43 | 44 | cl /nologo %tmpsource% >nul 45 | for /f %%x in ('%tmpprogram%') do set version=%%x 46 | del %tmpprogram%.* >nul 47 | set offset=0 48 | if %version% LSS 1900 set /a offset=1 49 | set /a version="version / 10 - 10 * ( 5 + offset )" 50 | endlocal & set %1=%version%& goto :EOF 51 | 52 | :: toupper; makes use of the fact that string 53 | :: replacement (via SET) is not case sensitive 54 | :toupper 55 | for %%L IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET %1=!%1:%%L=%%L! 56 | goto :EOF 57 | -------------------------------------------------------------------------------- /test/tc-cl.bat: -------------------------------------------------------------------------------- 1 | @echo off & setlocal enableextensions enabledelayedexpansion 2 | :: 3 | :: tc-cl.bat - compile & run tests (clang-cl). 4 | :: 5 | 6 | set unit=bit 7 | set unit_file=%unit% 8 | 9 | :: if no std is given, use c++14 10 | 11 | set std=c++14 12 | if NOT "%1" == "" set std=%1 & shift 13 | 14 | set UCAP=%unit% 15 | call :toupper UCAP 16 | 17 | set unit_select=%unit%_%UCAP%_NONSTD 18 | ::set unit_select=%unit%_CONFIG_SELECT_%UCAP%_NONSTD 19 | if NOT "%1" == "" set unit_select=%1 & shift 20 | 21 | set args=%1 %2 %3 %4 %5 %6 %7 %8 %9 22 | 23 | set clang=clang-cl 24 | 25 | call :CompilerVersion version 26 | echo %clang% %version%: %std% %unit_select% %args% 27 | 28 | set unit_config=^ 29 | -D%unit%_%UCAP%_HEADER=\"nonstd/%unit%.hpp\" ^ 30 | -D%unit%_TEST_NODISCARD=0 ^ 31 | -D%unit%_CONFIG_SELECT_%UCAP%=%unit_select% 32 | 33 | rem -flto / -fwhole-program 34 | set optflags=-O2 35 | set warnflags=-Wall -Wextra -Wpedantic -Weverything -Wshadow -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-missing-noreturn -Wno-documentation-unknown-command -Wno-documentation-deprecated-sync -Wno-documentation -Wno-weak-vtables -Wno-missing-prototypes -Wno-missing-variable-declarations -Wno-exit-time-destructors -Wno-global-constructors -Wno-sign-conversion -Wno-sign-compare -Wno-implicit-int-conversion -Wno-deprecated-declarations -Wno-date-time 36 | 37 | "%clang%" -EHsc -std:%std% %optflags% %warnflags% %unit_config% -fms-compatibility-version=19.00 /imsvc lest -I../include -Ics_string -I. -o %unit_file%-main.t.exe %unit_file%-main.t.cpp %unit_file%.t.cpp && %unit_file%-main.t.exe 38 | endlocal & goto :EOF 39 | 40 | :: subroutines: 41 | 42 | :CompilerVersion version 43 | echo off & setlocal enableextensions 44 | set tmpprogram=_getcompilerversion.tmp 45 | set tmpsource=%tmpprogram%.c 46 | 47 | echo #include ^ > %tmpsource% 48 | echo int main(){printf("%%d.%%d.%%d\n",__clang_major__,__clang_minor__,__clang_patchlevel__);} >> %tmpsource% 49 | 50 | "%clang%" -m32 -o %tmpprogram% %tmpsource% >nul 51 | for /f %%x in ('%tmpprogram%') do set version=%%x 52 | del %tmpprogram%.* >nul 53 | endlocal & set %1=%version%& goto :EOF 54 | 55 | :: toupper; makes use of the fact that string 56 | :: replacement (via SET) is not case sensitive 57 | :toupper 58 | for %%L IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET %1=!%1:%%L=%%L! 59 | goto :EOF 60 | -------------------------------------------------------------------------------- /test/tc.bat: -------------------------------------------------------------------------------- 1 | @echo off & setlocal enableextensions enabledelayedexpansion 2 | :: 3 | :: tc.bat - compile & run tests (clang). 4 | :: 5 | 6 | set unit=bit 7 | 8 | :: if no std is given, use c++14 9 | 10 | set std=%1 11 | if "%std%"=="" set std=c++14 12 | 13 | set clang=clang 14 | 15 | call :CompilerVersion version 16 | echo %clang% %version%: %std% 17 | 18 | set UCAP=%unit% 19 | call :toupper UCAP 20 | 21 | set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_DEFAULT 22 | ::set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_NONSTD 23 | ::set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_STD 24 | 25 | set unit_config= 26 | 27 | rem -flto / -fwhole-program 28 | set optflags=-O2 29 | set warnflags=-Wall -Wextra -Wpedantic -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-missing-noreturn -Wno-documentation-unknown-command -Wno-documentation-deprecated-sync -Wno-documentation -Wno-weak-vtables -Wno-missing-prototypes -Wno-missing-variable-declarations -Wno-exit-time-destructors -Wno-global-constructors 30 | 31 | "%clang%" -m32 -std=%std% %optflags% %warnflags% %unit_select% %unit_config% -fms-compatibility-version=19.00 -isystem "%VCInstallDir%include" -isystem "%WindowsSdkDir_71A%include" -isystem lest -I../include -o %unit%-main.t.exe %unit%-main.t.cpp %unit%.t.cpp && %unit%-main.t.exe 32 | endlocal & goto :EOF 33 | 34 | :: subroutines: 35 | 36 | :CompilerVersion version 37 | echo off & setlocal enableextensions 38 | set tmpprogram=_getcompilerversion.tmp 39 | set tmpsource=%tmpprogram%.c 40 | 41 | echo #include ^ > %tmpsource% 42 | echo int main(){printf("%%d.%%d.%%d\n",__clang_major__,__clang_minor__,__clang_patchlevel__);} >> %tmpsource% 43 | 44 | "%clang%" -m32 -o %tmpprogram% %tmpsource% >nul 45 | for /f %%x in ('%tmpprogram%') do set version=%%x 46 | del %tmpprogram%.* >nul 47 | endlocal & set %1=%version%& goto :EOF 48 | 49 | :: toupper; makes use of the fact that string 50 | :: replacement (via SET) is not case sensitive 51 | :toupper 52 | for %%L IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET %1=!%1:%%L=%%L! 53 | goto :EOF 54 | -------------------------------------------------------------------------------- /test/tg-all.bat: -------------------------------------------------------------------------------- 1 | @for %%s in ( c++98 c++03 c++11 c++14 c++17 c++2a ) do ( 2 | call tg.bat %%s 3 | ) 4 | -------------------------------------------------------------------------------- /test/tg.bat: -------------------------------------------------------------------------------- 1 | @echo off & setlocal enableextensions enabledelayedexpansion 2 | :: 3 | :: tg.bat - compile & run tests (GNUC). 4 | :: 5 | 6 | set unit=bit 7 | 8 | :: if no std is given, use c++11 9 | 10 | set std=%1 11 | set args=%2 %3 %4 %5 %6 %7 %8 %9 12 | if "%1" == "" set std=c++11 13 | 14 | set gpp=g++ 15 | 16 | call :CompilerVersion version 17 | echo %gpp% %version%: %std% %args% 18 | 19 | set UCAP=%unit% 20 | call :toupper UCAP 21 | 22 | set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_DEFAULT 23 | ::set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_NONSTD 24 | ::set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_STD 25 | 26 | set unit_config= 27 | 28 | rem -flto / -fwhole-program 29 | set optflags=-O2 30 | set warnflags=-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wno-padded -Wno-missing-noreturn 31 | 32 | %gpp% -std=%std% %optflags% %warnflags% %unit_select% %unit_config% -o %unit%-main.t.exe -isystem lest -I../include %unit%-main.t.cpp %unit%.t.cpp && %unit%-main.t.exe 33 | 34 | endlocal & goto :EOF 35 | 36 | :: subroutines: 37 | 38 | :CompilerVersion version 39 | echo off & setlocal enableextensions 40 | set tmpprogram=_getcompilerversion.tmp 41 | set tmpsource=%tmpprogram%.c 42 | 43 | echo #include ^ > %tmpsource% 44 | echo int main(){printf("%%d.%%d.%%d\n",__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__);} >> %tmpsource% 45 | 46 | %gpp% -o %tmpprogram% %tmpsource% >nul 47 | for /f %%x in ('%tmpprogram%') do set version=%%x 48 | del %tmpprogram%.* >nul 49 | endlocal & set %1=%version%& goto :EOF 50 | 51 | :: toupper; makes use of the fact that string 52 | :: replacement (via SET) is not case sensitive 53 | :toupper 54 | for %%L IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET %1=!%1:%%L=%%L! 55 | goto :EOF 56 | --------------------------------------------------------------------------------