├── .buckconfig
├── CHANGES.txt
├── test
├── tg-all.bat
├── BUCK
├── byte-main.t.hpp
├── tg.bat
├── t.bat
├── tc.bat
├── tc-cl.bat
├── byte-main.t.cpp
├── byte.t.cpp
├── CMakeLists.txt
└── lest
│ └── lest_cpp03.hpp
├── .tgitconfig
├── example
├── BUCK
├── 01-basic.cpp
└── CMakeLists.txt
├── cmake
├── byte-lite-config.cmake.in
└── byte-lite-config-version.cmake.in
├── project
└── CodeBlocks
│ ├── byte-lite.workspace
│ └── byte-lite.cbp
├── BUCK
├── .gitignore
├── .gitattributes
├── .editorconfig
├── conanfile.py
├── LICENSE.txt
├── .github
└── workflows
│ └── ci.yml
├── script
├── upload-conan.py
├── create-cov-rpt.py
├── update-version.py
└── create-vcpkg.py
├── CMakeLists.txt
├── README.md
└── include
└── nonstd
└── byte.hpp
/.buckconfig:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/CHANGES.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nonstd-lite/byte-lite/HEAD/CHANGES.txt
--------------------------------------------------------------------------------
/test/tg-all.bat:
--------------------------------------------------------------------------------
1 | @for %%s in ( c++98 c++03 c++11 c++14 c++17 ) do (
2 | call tg.bat %%s
3 | )
4 |
--------------------------------------------------------------------------------
/.tgitconfig:
--------------------------------------------------------------------------------
1 | [bugtraq]
2 | url = https://github.com/martinmoene/byte-lite/issues/%BUGID%
3 | number = true
4 | logregex = "(\\s*(,|and)?\\s*#\\d+)+\n(\\d+)"
5 |
--------------------------------------------------------------------------------
/example/BUCK:
--------------------------------------------------------------------------------
1 | cxx_binary(
2 | name = '01-basic',
3 | srcs = [
4 | '01-basic.cpp',
5 | ],
6 | compiler_flags = [
7 | '-std=c++11',
8 | ],
9 | deps = [
10 | '//:byte-lite',
11 | ],
12 | )
13 |
--------------------------------------------------------------------------------
/cmake/byte-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 |
--------------------------------------------------------------------------------
/project/CodeBlocks/byte-lite.workspace:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/test/BUCK:
--------------------------------------------------------------------------------
1 | cxx_binary(
2 | name = 'test',
3 | header_namespace = '',
4 | headers = glob([
5 | '*.h',
6 | ]),
7 | srcs = glob([
8 | '*.cpp',
9 | ]),
10 | compiler_flags = [
11 | '-std=c++11',
12 | ],
13 | deps = [
14 | '//:byte-lite',
15 | ],
16 | )
17 |
--------------------------------------------------------------------------------
/BUCK:
--------------------------------------------------------------------------------
1 | prebuilt_cxx_library(
2 | name = 'byte-lite',
3 | header_only = True,
4 | header_namespace = '',
5 | exported_headers = subdir_glob([
6 | ('include/nonstd', '**/*.hpp'),
7 | ]),
8 | licenses = [
9 | 'LICENSE',
10 | ],
11 | visibility = [
12 | 'PUBLIC',
13 | ],
14 | )
15 |
--------------------------------------------------------------------------------
/example/01-basic.cpp:
--------------------------------------------------------------------------------
1 | #include "nonstd/byte.hpp"
2 |
3 | #include
4 |
5 | using namespace nonstd;
6 |
7 | int main()
8 | {
9 | byte b1 = to_byte( 0x5a ); // to_byte() is non-standard, needed for pre-C++17
10 | byte b2 = to_byte( 0xa5 );
11 |
12 | byte r1 = b1 ^ b2; assert( 0xff == to_integer( r1 ) ); // not (yet) standard, needs C++11
13 | byte r2 = b1 ^ b2; assert( 0xff == to_integer( r2 ) );
14 | }
15 |
16 | // cl -nologo -EHsc -I../include 01-basic.cpp && 01-basic
17 | // g++ -std=c++11 -Wall -I../include -o 01-basic 01-basic.cpp && 01-basic
18 |
--------------------------------------------------------------------------------
/.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 | # Buck
31 | /buck-out/
32 | /.buckd/
33 | /buckaroo/
34 | .buckconfig.local
35 | BUCKAROO_DEPS
36 |
37 | # Build folder
38 | /build/
39 |
40 | # CodeBlocks IDE files
41 | *.layout
42 |
43 | # Visual Studio Code
44 | /.vscode/
45 |
46 | # Visual Studio
47 | /.vs/
48 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/cmake/byte-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 |
--------------------------------------------------------------------------------
/conanfile.py:
--------------------------------------------------------------------------------
1 | from conans import ConanFile, CMake
2 |
3 | class ByteLiteConan(ConanFile):
4 | version = "0.3.0"
5 | name = "byte-lite"
6 | description = "byte"
7 | license = "Boost Software License - Version 1.0. http://www.boost.org/LICENSE_1_0.txt"
8 | url = "https://github.com/martinmoene/byte-lite.git"
9 | exports_sources = "include/nonstd/*", "CMakeLists.txt", "cmake/*", "LICENSE.txt"
10 | settings = "compiler", "build_type", "arch"
11 | build_policy = "missing"
12 | author = "Martin Moene"
13 |
14 | def build(self):
15 | """Avoid warning on build step"""
16 | pass
17 |
18 | def package(self):
19 | """Run CMake install"""
20 | cmake = CMake(self)
21 | cmake.definitions["BYTE_LITE_OPT_BUILD_TESTS"] = "OFF"
22 | cmake.definitions["BYTE_LITE_OPT_BUILD_EXAMPLES"] = "OFF"
23 | cmake.configure()
24 | cmake.install()
25 |
26 | def package_info(self):
27 | self.info.header_only()
28 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/test/byte-main.t.hpp:
--------------------------------------------------------------------------------
1 | // Copyright 2017-2019 Martin Moene
2 | //
3 | // https://github.com/martinmoene/byte-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 | #pragma once
9 |
10 | #ifndef TEST_byte_LITE_H_INCLUDED
11 | #define TEST_byte_LITE_H_INCLUDED
12 |
13 | #include "nonstd/byte.hpp"
14 |
15 | // Compiler warning suppression for usage of lest:
16 |
17 | #ifdef __clang__
18 | # pragma clang diagnostic ignored "-Wstring-conversion"
19 | # pragma clang diagnostic ignored "-Wunused-parameter"
20 | # pragma clang diagnostic ignored "-Wunused-template"
21 | # pragma clang diagnostic ignored "-Wunused-function"
22 | # pragma clang diagnostic ignored "-Wunused-member-function"
23 | #elif defined __GNUC__
24 | # pragma GCC diagnostic ignored "-Wunused-parameter"
25 | # pragma GCC diagnostic ignored "-Wunused-function"
26 | #endif
27 |
28 | #include
29 |
30 | namespace nonstd {
31 |
32 | // use oparator<< instead of to_string() overload;
33 | // see http://stackoverflow.com/a/10651752/437272
34 |
35 | inline std::ostream & operator<<( std::ostream & os, byte const & v )
36 | {
37 | return os << "[byte:" << std::hex << "0x" << to_integer( v ) << "]";
38 | }
39 |
40 | }
41 |
42 | namespace lest {
43 |
44 | using ::nonstd::operator<<;
45 |
46 | } // namespace lest
47 |
48 | #include "lest_cpp03.hpp"
49 |
50 | extern lest::tests & specification();
51 |
52 | #define CASE( name ) lest_CASE( specification(), name )
53 |
54 | #endif // TEST_byte_LITE_H_INCLUDED
55 |
56 | // end of file
57 |
--------------------------------------------------------------------------------
/test/tg.bat:
--------------------------------------------------------------------------------
1 | @echo off & setlocal enableextensions enabledelayedexpansion
2 | ::
3 | :: tg.bat - compile & run tests (GNUC).
4 | ::
5 |
6 | set unit=byte
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 |
--------------------------------------------------------------------------------
/test/t.bat:
--------------------------------------------------------------------------------
1 | @echo off & setlocal enableextensions enabledelayedexpansion
2 | ::
3 | :: t.bat - compile & run tests (MSVC).
4 | ::
5 |
6 | set unit=byte
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.bat:
--------------------------------------------------------------------------------
1 | @echo off & setlocal enableextensions enabledelayedexpansion
2 | ::
3 | :: tc.bat - compile & run tests (clang).
4 | ::
5 |
6 | set unit=byte
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 |
--------------------------------------------------------------------------------
/project/CodeBlocks/byte-lite.cbp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/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=byte
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 |
--------------------------------------------------------------------------------
/example/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright 2021-2021 by Martin Moene
2 | #
3 | # https://github.com/martinmoene/byte-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.15 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 | set( PROGRAM ${unit_name}-lite )
17 |
18 | message( STATUS "Subproject '${PROJECT_NAME}', examples '${PROGRAM}-*'")
19 |
20 | # Target default options and definitions:
21 |
22 | set( OPTIONS "" )
23 | #set( DEFINITIONS "" )
24 |
25 | # Sources (.cpp), normal and no-exception, and their base names:
26 |
27 | set( SOURCES
28 | 01-basic.cpp
29 | )
30 |
31 | set( SOURCES_NE
32 | )
33 |
34 | string( REPLACE ".cpp" "" BASENAMES "${SOURCES}" )
35 | string( REPLACE ".cpp" "" BASENAMES_NE "${SOURCES_NE}" )
36 |
37 | # Determine options:
38 |
39 | if( MSVC )
40 | message( STATUS "Matched: MSVC")
41 |
42 | set( BASE_OPTIONS -W3 )
43 | set( EXCEPTIONS_OPTIONS ${BASE_OPTIONS} -EHsc )
44 | set( NO_EXCEPTIONS_OPTIONS ${BASE_OPTIONS} )
45 |
46 | elseif( CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang" )
47 | message( STATUS "CompilerId: '${CMAKE_CXX_COMPILER_ID}'")
48 |
49 | set( BASE_OPTIONS -Wall -Wextra -Wconversion -Wsign-conversion -Wno-missing-braces -fno-elide-constructors )
50 | set( EXCEPTIONS_OPTIONS ${BASE_OPTIONS} )
51 | set( NO_EXCEPTIONS_OPTIONS -fno-exceptions )
52 |
53 | elseif( CMAKE_CXX_COMPILER_ID MATCHES "Intel" )
54 | # as is
55 | message( STATUS "Matched: Intel")
56 | else()
57 | # as is
58 | message( STATUS "Matched: nothing")
59 | endif()
60 |
61 | # Function to emulate ternary operation `result = b ? x : y`:
62 |
63 | macro( ternary var boolean value1 value2 )
64 | if( ${boolean} )
65 | set( ${var} ${value1} )
66 | else()
67 | set( ${var} ${value2} )
68 | endif()
69 | endmacro()
70 |
71 | # Function to create a target:
72 |
73 | function( make_target name no_exceptions )
74 | ternary( ne no_exceptions "-ne" "" )
75 |
76 | add_executable ( ${PROGRAM}-${name}${ne} ${name}.cpp )
77 | target_include_directories ( ${PROGRAM}-${name}${ne} PRIVATE ../include )
78 | target_link_libraries ( ${PROGRAM}-${name}${ne} PRIVATE ${PACKAGE} )
79 | if ( no_exceptions )
80 | target_compile_options ( ${PROGRAM}-${name}${ne} PRIVATE ${NO_EXCEPTIONS_OPTIONS} )
81 | else()
82 | target_compile_options ( ${PROGRAM}-${name}${ne} PRIVATE ${EXCEPTIONS_OPTIONS} )
83 | endif()
84 |
85 | endfunction()
86 |
87 | # Create targets:
88 |
89 | foreach( target ${BASENAMES} )
90 | make_target( ${target} FALSE )
91 | endforeach()
92 |
93 | foreach( target ${BASENAMES_NE} )
94 | make_target( ${target} TRUE )
95 | endforeach()
96 |
97 | # end of file
98 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | env:
4 | PROJECT: BYTE_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@v6
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 | include:
51 | - version: 11
52 | os: 'ubuntu-22.04'
53 | - version: 12
54 | os: 'ubuntu-22.04'
55 | - version: 19
56 | os: 'ubuntu-24.04'
57 |
58 | runs-on: ${{ matrix.os }}
59 |
60 | steps:
61 | - uses: actions/checkout@v6
62 |
63 | - name: Install Clang ${{ matrix.version }}
64 | run: sudo apt-get install -y clang-${{ matrix.version }}
65 |
66 | - name: Configure tests
67 | env:
68 | CXX: clang-${{ matrix.version }}
69 | run: cmake -S . -B build
70 | -D CMAKE_CXX_COMPILER=clang++-${{ matrix.version }}
71 | -D CMAKE_BUILD_TYPE:STRING=Release
72 | -D ${{ env.PROJECT }}_OPT_SELECT_NONSTD=ON
73 | -D ${{ env.PROJECT }}_OPT_BUILD_TESTS=ON
74 | -D ${{ env.PROJECT }}_OPT_BUILD_EXAMPLES=OFF
75 |
76 | - name: Build tests
77 | run: cmake --build build -j 4
78 |
79 | - name: Run tests
80 | working-directory: build
81 | run: ctest --output-on-failure -j 4
82 |
83 | msvc:
84 | strategy:
85 | fail-fast: false
86 | matrix:
87 | os: [windows-2022, windows-2025]
88 |
89 | runs-on: ${{ matrix.os }}
90 |
91 | steps:
92 | - uses: actions/checkout@v6
93 |
94 | - name: Configure tests
95 | run: cmake -S . -B build
96 | -D ${{ env.PROJECT }}_OPT_SELECT_NONSTD=ON
97 | -D ${{ env.PROJECT }}_OPT_BUILD_TESTS=ON
98 | -D ${{ env.PROJECT }}_OPT_BUILD_EXAMPLES=OFF
99 |
100 | - name: Build tests
101 | run: cmake --build build --config Release -j 4
102 |
103 | - name: Run tests
104 | working-directory: build
105 | run: ctest -C Release --output-on-failure -j 4
106 |
--------------------------------------------------------------------------------
/test/byte-main.t.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 2017-2019 Martin Moene
2 | //
3 | // https://github.com/martinmoene/byte-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 | #include "byte-main.t.hpp"
9 |
10 | #define byte_PRESENT( x ) \
11 | std::cout << #x << ": " << x << "\n"
12 |
13 | #define byte_ABSENT( x ) \
14 | std::cout << #x << ": (undefined)\n"
15 |
16 | lest::tests & specification()
17 | {
18 | static lest::tests tests;
19 | return tests;
20 | }
21 |
22 | CASE( "byte-lite version" "[.byte][.version]" )
23 | {
24 | byte_PRESENT( byte_lite_MAJOR );
25 | byte_PRESENT( byte_lite_MINOR );
26 | byte_PRESENT( byte_lite_PATCH );
27 | byte_PRESENT( byte_lite_VERSION );
28 | }
29 |
30 | CASE( "byte configuration" "[.byte][.config]" )
31 | {
32 | byte_PRESENT( byte_HAVE_STD_BYTE );
33 | byte_PRESENT( byte_USES_STD_BYTE );
34 | byte_PRESENT( byte_BYTE_DEFAULT );
35 | byte_PRESENT( byte_BYTE_NONSTD );
36 | byte_PRESENT( byte_BYTE_STD );
37 | byte_PRESENT( byte_CONFIG_SELECT_BYTE );
38 | byte_PRESENT( byte_CPLUSPLUS );
39 | }
40 |
41 | CASE( "__cplusplus" "[.stdc++]" )
42 | {
43 | byte_PRESENT( __cplusplus );
44 | }
45 |
46 | CASE( "compiler version" "[.compiler]" )
47 | {
48 | #if byte_USES_STD_BYTE
49 | std::cout << "(Compiler version not available: using std::byte)\n";
50 | #else
51 | byte_PRESENT( byte_COMPILER_CLANG_VERSION );
52 | byte_PRESENT( byte_COMPILER_GNUC_VERSION );
53 | byte_PRESENT( byte_COMPILER_MSVC_VERSION );
54 | #endif
55 | }
56 |
57 | CASE( "Presence of C++ language features" "[.stdlanguage]" )
58 | {
59 | #if byte_USES_STD_BYTE
60 | std::cout << "(Presence of C++ language features not available: using std::byte)\n";
61 | #else
62 | byte_PRESENT( byte_HAVE_CONSTEXPR_11 );
63 | byte_PRESENT( byte_HAVE_CONSTEXPR_14 );
64 | byte_PRESENT( byte_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG );
65 | byte_PRESENT( byte_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE );
66 | byte_PRESENT( byte_HAVE_NOEXCEPT );
67 | #endif
68 | }
69 |
70 | CASE( "Presence of C++ library features" "[.stdlibrary]" )
71 | {
72 | #if byte_USES_STD_BYTE
73 | std::cout << "(Presence of C++ library features not available: using std::byte)\n";
74 | #else
75 | byte_PRESENT( byte_HAVE_TYPE_TRAITS );
76 | #endif
77 |
78 | #if defined _HAS_CPP0X
79 | byte_PRESENT( _HAS_CPP0X );
80 | #else
81 | byte_ABSENT( _HAS_CPP0X );
82 | #endif
83 | }
84 |
85 | int main( int argc, char * argv[] )
86 | {
87 | return lest::run( specification(), argc, argv );
88 | }
89 |
90 | #if 0
91 | g++ -I../include -o byte-main.t.exe byte-main.t.cpp byte.t.cpp && byte-main.t.exe --pass
92 | g++ -std=c++98 -I../include -o byte-main.t.exe byte-main.t.cpp byte.t.cpp && byte-main.t.exe --pass
93 | g++ -std=c++03 -I../include -o byte-main.t.exe byte-main.t.cpp byte.t.cpp && byte-main.t.exe --pass
94 | g++ -std=c++0x -I../include -o byte-main.t.exe byte-main.t.cpp byte.t.cpp && byte-main.t.exe --pass
95 | g++ -std=c++11 -I../include -o byte-main.t.exe byte-main.t.cpp byte.t.cpp && byte-main.t.exe --pass
96 | g++ -std=c++14 -I../include -o byte-main.t.exe byte-main.t.cpp byte.t.cpp && byte-main.t.exe --pass
97 | g++ -std=c++17 -I../include -o byte-main.t.exe byte-main.t.cpp byte.t.cpp && byte-main.t.exe --pass
98 |
99 | cl -EHsc -I../include byte-main.t.cpp byte.t.cpp && byte-main.t.exe --pass
100 | #endif
101 |
102 | // end of file
103 |
--------------------------------------------------------------------------------
/script/upload-conan.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright 2019-2019 by Martin Moene
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 | # script/upload-conan.py
9 | #
10 |
11 | from __future__ import print_function
12 |
13 | import argparse
14 | import os
15 | import re
16 | import sys
17 | import subprocess
18 |
19 | # Configuration:
20 |
21 | def_conan_project = 'byte-lite'
22 | def_conan_user = 'nonstd-lite'
23 | def_conan_channel = 'stable'
24 | cfg_conanfile = 'conanfile.py'
25 |
26 | tpl_conan_create = 'conan create . {usr}/{chn}'
27 | tpl_conan_upload = 'conan upload --remote {usr} {prj}/{ver}@{usr}/{chn}'
28 |
29 | # End configuration.
30 |
31 | def versionFrom( filename ):
32 | """Obtain version from conanfile.py"""
33 | with open( filename ) as f:
34 | content = f.read()
35 | version = re.search(r'version\s=\s"(.*)"', content).group(1)
36 | return version
37 |
38 | def createConanPackage( args ):
39 | """Create conan package and upload it."""
40 | cmd = tpl_conan_create.format(usr=args.user, chn=args.channel)
41 | if args.verbose:
42 | print( "> {}".format(cmd) )
43 | if not args.dry_run:
44 | subprocess.call( cmd, shell=False )
45 |
46 | def uploadConanPackage( args ):
47 | """Create conan package and upload it."""
48 | cmd = tpl_conan_upload.format(prj=args.project, usr=args.user, chn=args.channel, ver=args.version)
49 | if args.verbose:
50 | print( "> {}".format(cmd) )
51 | if not args.dry_run:
52 | subprocess.call( cmd, shell=False )
53 |
54 | def uploadToConan( args ):
55 | """Create conan package and upload it."""
56 | print( "Updating project '{prj}' to user '{usr}', channel '{chn}', version {ver}:".
57 | format(prj=args.project, usr=args.user, chn=args.channel, ver=args.version) )
58 | createConanPackage( args )
59 | uploadConanPackage( args )
60 |
61 | def uploadToConanFromCommandLine():
62 | """Collect arguments from the commandline and create conan package and upload it."""
63 |
64 | parser = argparse.ArgumentParser(
65 | description='Create conan package and upload it to conan.',
66 | epilog="""""",
67 | formatter_class=argparse.ArgumentDefaultsHelpFormatter)
68 |
69 | parser.add_argument(
70 | '-n', '--dry-run',
71 | action='store_true',
72 | help='do not execute conan commands')
73 |
74 | parser.add_argument(
75 | '-v', '--verbose',
76 | action='count',
77 | default=0,
78 | help='level of progress reporting')
79 |
80 | parser.add_argument(
81 | '--project',
82 | metavar='p',
83 | type=str,
84 | default=def_conan_project,
85 | help='conan project')
86 |
87 | parser.add_argument(
88 | '--user',
89 | metavar='u',
90 | type=str,
91 | default=def_conan_user,
92 | help='conan user')
93 |
94 | parser.add_argument(
95 | '--channel',
96 | metavar='c',
97 | type=str,
98 | default=def_conan_channel,
99 | help='conan channel')
100 |
101 | parser.add_argument(
102 | '--version',
103 | metavar='v',
104 | type=str,
105 | default=versionFrom( cfg_conanfile ),
106 | help='version number [from conanfile.py]')
107 |
108 | uploadToConan( parser.parse_args() )
109 |
110 |
111 | if __name__ == '__main__':
112 | uploadToConanFromCommandLine()
113 |
114 | # end of file
115 |
--------------------------------------------------------------------------------
/script/create-cov-rpt.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright 2019-2019 by Martin Moene
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 | # script/create-cov-rpt.py, Python 3.4 and later
9 | #
10 |
11 | import argparse
12 | import os
13 | import re
14 | import sys
15 | import subprocess
16 |
17 | # Configuration:
18 |
19 | cfg_github_project = 'byte-lite'
20 | cfg_github_user = 'martinmoene'
21 | cfg_prj_folder_level = 3
22 |
23 | tpl_coverage_cmd = 'opencppcoverage --no_aggregate_by_file --sources {src} -- {exe}'
24 |
25 | # End configuration.
26 |
27 | def project_folder( f, args ):
28 | """Project root"""
29 | if args.prj_folder:
30 | return args.prj_folder
31 | return os.path.normpath( os.path.join( os.path.dirname( os.path.abspath(f) ), '../' * args.prj_folder_level ) )
32 |
33 | def executable_folder( f ):
34 | """Folder where the xecutable is"""
35 | return os.path.dirname( os.path.abspath(f) )
36 |
37 | def executable_name( f ):
38 | """Folder where the executable is"""
39 | return os.path.basename( f )
40 |
41 | def createCoverageReport( f, args ):
42 | print( "Creating coverage report for project '{usr}/{prj}', '{file}':".
43 | format( usr=args.user, prj=args.project, file=f ) )
44 | cmd = tpl_coverage_cmd.format( folder=executable_folder(f), src=project_folder(f, args), exe=executable_name(f) )
45 | if args.verbose:
46 | print( "> {}".format(cmd) )
47 | if not args.dry_run:
48 | os.chdir( executable_folder(f) )
49 | subprocess.call( cmd, shell=False )
50 | os.chdir( project_folder(f, args) )
51 |
52 | def createCoverageReports( args ):
53 | for f in args.executable:
54 | createCoverageReport( f, args )
55 |
56 | def createCoverageReportFromCommandLine():
57 | """Collect arguments from the commandline and create coverage report."""
58 | parser = argparse.ArgumentParser(
59 | description='Create coverage report.',
60 | epilog="""""",
61 | formatter_class=argparse.ArgumentDefaultsHelpFormatter)
62 |
63 | parser.add_argument(
64 | 'executable',
65 | metavar='executable',
66 | type=str,
67 | nargs=1,
68 | help='executable to report on')
69 |
70 | parser.add_argument(
71 | '-n', '--dry-run',
72 | action='store_true',
73 | help='do not execute conan commands')
74 |
75 | parser.add_argument(
76 | '-v', '--verbose',
77 | action='count',
78 | default=0,
79 | help='level of progress reporting')
80 |
81 | parser.add_argument(
82 | '--user',
83 | metavar='u',
84 | type=str,
85 | default=cfg_github_user,
86 | help='github user name')
87 |
88 | parser.add_argument(
89 | '--project',
90 | metavar='p',
91 | type=str,
92 | default=cfg_github_project,
93 | help='github project name')
94 |
95 | parser.add_argument(
96 | '--prj-folder',
97 | metavar='f',
98 | type=str,
99 | default=None,
100 | help='project root folder')
101 |
102 | parser.add_argument(
103 | '--prj-folder-level',
104 | metavar='n',
105 | type=int,
106 | default=cfg_prj_folder_level,
107 | help='project root folder level from executable')
108 |
109 | createCoverageReports( parser.parse_args() )
110 |
111 | if __name__ == '__main__':
112 | createCoverageReportFromCommandLine()
113 |
114 | # end of file
115 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright 2017-2019 by Martin Moene
2 | #
3 | # https://github.com/martinmoene/byte-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.15 FATAL_ERROR )
9 |
10 | # byte-lite project and version, updated by script/update-version.py:
11 |
12 | project(
13 | byte_lite
14 | VERSION 0.3.0
15 | # DESCRIPTION "A C++17-like byte type for C++98, C++11 and later in a single-file header-only library"
16 | # HOMEPAGE_URL "https://github.com/martinmoene/byte-lite"
17 | LANGUAGES CXX )
18 |
19 | # Package information:
20 |
21 | set( unit_name "byte" )
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( byte_IS_TOPLEVEL_PROJECT TRUE )
32 | else()
33 | set( byte_IS_TOPLEVEL_PROJECT FALSE )
34 | endif()
35 |
36 | # If toplevel project, enable building and performing of tests, disable building of examples:
37 |
38 | option( BYTE_LITE_OPT_BUILD_TESTS "Build and perform byte-lite tests" ${byte_IS_TOPLEVEL_PROJECT} )
39 | option( BYTE_LITE_OPT_BUILD_EXAMPLES "Build byte-lite examples" OFF )
40 |
41 | option( BYTE_LITE_OPT_SELECT_STD "Select std::byte" OFF )
42 | option( BYTE_LITE_OPT_SELECT_NONSTD "Select nonstd::byte" OFF )
43 |
44 | # If requested, build and perform tests, build examples:
45 |
46 | if ( BYTE_LITE_OPT_BUILD_TESTS )
47 | enable_testing()
48 | add_subdirectory( test )
49 | endif()
50 |
51 | if ( BYTE_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 |
--------------------------------------------------------------------------------
/script/update-version.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright 2017-2019 by Martin Moene
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 | # 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+byte_lite_version\W+"([0-9]+\.[0-9]+\.[0-9]+)"\W+$'
28 | , 'set( byte_lite_version "{major}.{minor}.{patch}" )\n' )
29 |
30 | # , ( 'example/cmake-pkg/CMakeLists.txt'
31 | # , r'set\W+byte_lite_version\W+"([0-9]+\.[0-9]+(\.[0-9]+)?)"\W+$'
32 | # , 'set( byte_lite_version "{major}.{minor}" )\n' )
33 | #
34 | # , ( 'script/install-xxx-pkg.py'
35 | # , r'\byte_lite_version\s+=\s+"([0-9]+\.[0-9]+\.[0-9]+)"\s*$'
36 | # , 'byte_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/byte.hpp'
43 | , r'\#define\s+byte_lite_MAJOR\s+[0-9]+\s*$'
44 | , '#define byte_lite_MAJOR {major}' )
45 |
46 | , ( 'include/nonstd/byte.hpp'
47 | , r'\#define\s+byte_lite_MINOR\s+[0-9]+\s*$'
48 | , '#define byte_lite_MINOR {minor}' )
49 |
50 | , ( 'include/nonstd/byte.hpp'
51 | , r'\#define\s+byte_lite_PATCH\s+[0-9]+\s*$'
52 | , '#define byte_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 |
--------------------------------------------------------------------------------
/script/create-vcpkg.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright 2019-2019 by Martin Moene
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 | # script/upload-conan.py, Python 3.4 and later
9 | #
10 |
11 | import argparse
12 | import os
13 | import re
14 | import sys
15 | import subprocess
16 |
17 | # Configuration:
18 |
19 | cfg_github_project = 'byte-lite'
20 | cfg_github_user = 'martinmoene'
21 | cfg_description = '(unused)'
22 |
23 | cfg_cmakelists = 'CMakeLists.txt'
24 | cfg_readme = 'Readme.md'
25 | cfg_license = 'LICENSE.txt'
26 | cfg_ref_prefix = 'v'
27 |
28 | cfg_sha512 = 'dadeda'
29 | cfg_vcpkg_description = '(no description found)'
30 | cfg_vcpkg_root = os.environ['VCPKG_ROOT']
31 |
32 | cfg_cmake_optpfx = "BYTE_LITE"
33 |
34 | # End configuration.
35 |
36 | # vcpkg control and port templates:
37 |
38 | tpl_path_vcpkg_control = '{vcpkg}/ports/{prj}/CONTROL'
39 | tpl_path_vcpkg_portfile = '{vcpkg}/ports/{prj}/portfile.cmake'
40 |
41 | tpl_vcpkg_control =\
42 | """Source: {prj}
43 | Version: {ver}
44 | Description: {desc}"""
45 |
46 | tpl_vcpkg_portfile =\
47 | """include(vcpkg_common_functions)
48 |
49 | vcpkg_from_github(
50 | OUT_SOURCE_PATH SOURCE_PATH
51 | REPO {usr}/{prj}
52 | REF {ref}
53 | SHA512 {sha}
54 | )
55 |
56 | vcpkg_configure_cmake(
57 | SOURCE_PATH ${{SOURCE_PATH}}
58 | PREFER_NINJA
59 | OPTIONS
60 | -D{optpfx}_OPT_BUILD_TESTS=OFF
61 | -D{optpfx}_OPT_BUILD_EXAMPLES=OFF
62 | )
63 |
64 | vcpkg_install_cmake()
65 |
66 | vcpkg_fixup_cmake_targets(
67 | CONFIG_PATH lib/cmake/${{PORT}}
68 | )
69 |
70 | file(REMOVE_RECURSE
71 | ${{CURRENT_PACKAGES_DIR}}/debug
72 | ${{CURRENT_PACKAGES_DIR}}/lib
73 | )
74 |
75 | file(INSTALL
76 | ${{SOURCE_PATH}}/{lic} DESTINATION ${{CURRENT_PACKAGES_DIR}}/share/${{PORT}} RENAME copyright
77 | )"""
78 |
79 | tpl_vcpkg_note_sha =\
80 | """
81 | Next actions:
82 | - Obtain package SHA: 'vcpkg install {prj}', copy SHA mentioned in 'Actual hash: [...]'
83 | - Add SHA to package: 'script\create-vcpkg --sha={sha}'
84 | - Install package : 'vcpkg install {prj}'"""
85 |
86 | tpl_vcpkg_note_install =\
87 | """
88 | Next actions:
89 | - Install package: 'vcpkg install {prj}'"""
90 |
91 | # End of vcpkg templates
92 |
93 | def versionFrom( filename ):
94 | """Obtain version from CMakeLists.txt"""
95 | with open( filename, 'r' ) as f:
96 | content = f.read()
97 | version = re.search(r'VERSION\s(\d+\.\d+\.\d+)', content).group(1)
98 | return version
99 |
100 | def descriptionFrom( filename ):
101 | """Obtain description from CMakeLists.txt"""
102 | with open( filename, 'r' ) as f:
103 | content = f.read()
104 | description = re.search(r'DESCRIPTION\s"(.*)"', content).group(1)
105 | return description if description else cfg_vcpkg_description
106 |
107 | def vcpkgRootFrom( path ):
108 | return path if path else './vcpkg'
109 |
110 | def to_ref( version ):
111 | """Add prefix to version/tag, like v1.2.3"""
112 | return cfg_ref_prefix + version
113 |
114 | def control_path( args ):
115 | """Create path like vcpks/ports/_project_/CONTROL"""
116 | return tpl_path_vcpkg_control.format( vcpkg=args.vcpkg_root, prj=args.project )
117 |
118 | def portfile_path( args ):
119 | """Create path like vcpks/ports/_project_/portfile.cmake"""
120 | return tpl_path_vcpkg_portfile.format( vcpkg=args.vcpkg_root, prj=args.project )
121 |
122 | def createControl( args ):
123 | """Create vcpkg CONTROL file"""
124 | output = tpl_vcpkg_control.format(
125 | prj=args.project, ver=args.version, desc=args.description )
126 | if args.verbose:
127 | print( "Creating control file '{f}':".format( f=control_path( args ) ) )
128 | if args.verbose > 1:
129 | print( output )
130 | os.makedirs( os.path.dirname( control_path( args ) ), exist_ok=True )
131 | with open( control_path( args ), 'w') as f:
132 | print( output, file=f )
133 |
134 | def createPortfile( args ):
135 | """Create vcpkg portfile"""
136 | output = tpl_vcpkg_portfile.format(
137 | optpfx=cfg_cmake_optpfx, usr=args.user, prj=args.project, ref=to_ref(args.version), sha=args.sha, lic=cfg_license )
138 | if args.verbose:
139 | print( "Creating portfile '{f}':".format( f=portfile_path( args ) ) )
140 | if args.verbose > 1:
141 | print( output )
142 | os.makedirs( os.path.dirname( portfile_path( args ) ), exist_ok=True )
143 | with open( portfile_path( args ), 'w') as f:
144 | print( output, file=f )
145 |
146 | def printNotes( args ):
147 | if args.sha == cfg_sha512:
148 | print( tpl_vcpkg_note_sha.
149 | format( prj=args.project, sha='...' ) )
150 | else:
151 | print( tpl_vcpkg_note_install.
152 | format( prj=args.project ) )
153 |
154 | def createVcpkg( args ):
155 | print( "Creating vcpkg for '{usr}/{prj}', version '{ver}' in folder '{vcpkg}':".
156 | format( usr=args.user, prj=args.project, ver=args.version, vcpkg=args.vcpkg_root, ) )
157 | createControl( args )
158 | createPortfile( args )
159 | printNotes( args )
160 |
161 | def createVcpkgFromCommandLine():
162 | """Collect arguments from the commandline and create vcpkg."""
163 |
164 | parser = argparse.ArgumentParser(
165 | description='Create microsoft vcpkg.',
166 | epilog="""""",
167 | formatter_class=argparse.ArgumentDefaultsHelpFormatter)
168 |
169 | parser.add_argument(
170 | '-v', '--verbose',
171 | action='count',
172 | default=0,
173 | help='level of progress reporting')
174 |
175 | parser.add_argument(
176 | '--user',
177 | metavar='u',
178 | type=str,
179 | default=cfg_github_user,
180 | help='github user name')
181 |
182 | parser.add_argument(
183 | '--project',
184 | metavar='p',
185 | type=str,
186 | default=cfg_github_project,
187 | help='github project name')
188 |
189 | parser.add_argument(
190 | '--description',
191 | metavar='d',
192 | type=str,
193 | # default=cfg_description,
194 | default=descriptionFrom( cfg_cmakelists ),
195 | help='vcpkg description [from ' + cfg_cmakelists + ']')
196 |
197 | parser.add_argument(
198 | '--version',
199 | metavar='v',
200 | type=str,
201 | default=versionFrom( cfg_cmakelists ),
202 | help='version number [from ' + cfg_cmakelists + ']')
203 |
204 | parser.add_argument(
205 | '--sha',
206 | metavar='s',
207 | type=str,
208 | default=cfg_sha512,
209 | help='sha of package')
210 |
211 | parser.add_argument(
212 | '--vcpkg-root',
213 | metavar='r',
214 | type=str,
215 | default=vcpkgRootFrom( cfg_vcpkg_root ),
216 | help='parent folder containing ports to write files to')
217 |
218 | createVcpkg( parser.parse_args() )
219 |
220 | if __name__ == '__main__':
221 | createVcpkgFromCommandLine()
222 |
223 | # end of file
224 |
--------------------------------------------------------------------------------
/test/byte.t.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // byte-lite, a C++17-like byte type for C++98 and later.
3 | // For more information see https://github.com/martinmoene/gsl-lite
4 | //
5 | // Copyright 2017-2019 Martin Moene
6 | //
7 | // Distributed under the Boost Software License, Version 1.0.
8 | // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 |
10 | #include "byte-main.t.hpp"
11 |
12 | // Use nonstd::byte instead of plain byte to prevent collisions with
13 | // other byte declarations, such as in rpcndr.h (Windows kit).
14 |
15 | // We have a chicken & egg problem here:
16 | // verifying operations via to_integer() that has yet to verified itself...
17 |
18 | using namespace nonstd;
19 |
20 | CASE( "byte: Allows to construct from integral via static cast (C++17)" )
21 | {
22 | #if byte_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
23 | nonstd::byte b = static_cast( 4 );
24 | EXPECT( static_cast(b) == 4 );
25 | EXPECT( to_integer( b ) == 4 );
26 | #else
27 | EXPECT( !!"enum class is not constructible from underlying type (no C++17)" );
28 | #endif
29 | }
30 |
31 | CASE( "byte: Allows to construct from integral via byte() (C++17)" )
32 | {
33 | #if byte_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
34 | nonstd::byte b = nonstd::byte( 4 );
35 | EXPECT( to_integer( b ) == 4 );
36 | #else
37 | EXPECT( !!"enum class is not constructible from underlying type (no C++17)" );
38 | #endif
39 | }
40 |
41 | CASE( "byte: Allows to construct from integral via to_byte()" )
42 | {
43 | nonstd::byte b = to_byte( 4 );
44 | EXPECT( to_integer( b ) == 4 );
45 | }
46 |
47 | CASE( "byte: Allows to convert to integral via to_integer()" )
48 | {
49 | nonstd::byte b = to_byte( 4 );
50 | EXPECT( to_integer( b ) == 4 );
51 | }
52 |
53 | CASE( "byte: Allows to convert to integral via to_integer(), using default type" )
54 | {
55 | #if byte_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG
56 | nonstd::byte b = to_byte( 4 );
57 | EXPECT( to_integer( b ) == 4 );
58 | #else
59 | EXPECT( !!"No default function template argument (no C++11)" );
60 | #endif
61 | }
62 |
63 | CASE( "byte: Allows comparison operations" )
64 | {
65 | nonstd::byte a = to_byte( 3 );
66 | nonstd::byte b = to_byte( 7 );
67 |
68 | EXPECT( a == a );
69 | EXPECT( a != b );
70 |
71 | EXPECT( a < b );
72 | EXPECT( a <= a );
73 | EXPECT( a <= b );
74 |
75 | EXPECT( b > a );
76 | EXPECT( b >= a );
77 | EXPECT( b >= b );
78 |
79 | EXPECT_NOT( a == b );
80 | EXPECT_NOT( a != a );
81 | EXPECT_NOT( b < a );
82 | EXPECT_NOT( a > b );
83 | }
84 |
85 | CASE( "byte: Allows bitwise or operation" )
86 | {
87 | nonstd::byte const b = to_byte( 0xa5 );
88 |
89 | EXPECT( ( b | b ) == b );
90 | EXPECT( ( b | to_byte( 0x00 ) ) == b );
91 | EXPECT( ( b | to_byte( 0xff ) ) == to_byte( 0xff ) );
92 | }
93 |
94 | CASE( "byte: Allows bitwise and operation" )
95 | {
96 | nonstd::byte const b = to_byte( 0xa5 );
97 |
98 | EXPECT( ( b & b ) == b );
99 | EXPECT( ( b & to_byte( 0xff ) ) == b );
100 | EXPECT( ( b & to_byte( 0x00 ) ) == to_byte( 0x00 ) );
101 | }
102 |
103 | CASE( "byte: Allows bitwise x-or operation" )
104 | {
105 | nonstd::byte const b = to_byte( 0xa5 );
106 |
107 | EXPECT( ( b ^ b ) == to_byte( 0 ) );
108 | EXPECT( ( b ^ to_byte( 0x00 ) ) == b );
109 | EXPECT( ( b ^ to_byte( 0xff ) ) == ~b );
110 | }
111 |
112 | CASE( "byte: Allows bitwise or assignment" )
113 | {
114 | SETUP("") {
115 |
116 | nonstd::byte const b_org = to_byte( 0xa5 );
117 | nonstd::byte b = b_org;
118 |
119 | SECTION("Identity") { EXPECT( ( b |= b ) == b_org ); }
120 | SECTION("Identity") { EXPECT( ( b |= to_byte( 0x00 ) ) == b_org ); }
121 | SECTION("Saturate") { EXPECT( ( b |= to_byte( 0xff ) ) == to_byte( 0xff ) ); }
122 | }
123 | }
124 |
125 | CASE( "byte: Allows bitwise and assignment" )
126 | {
127 | SETUP("") {
128 |
129 | nonstd::byte const b_org = to_byte( 0xa5 );
130 | nonstd::byte b = b_org;
131 |
132 | SECTION("Identity") { EXPECT( ( b &= b ) == b_org ); }
133 | SECTION("Identity") { EXPECT( ( b &= to_byte( 0xff ) ) == b_org ); }
134 | SECTION("Clear" ) { EXPECT( ( b &= to_byte( 0x00 ) ) == to_byte( 0x00 ) ); }
135 | }
136 | }
137 |
138 | CASE( "byte: Allows bitwise x-or assignment" )
139 | {
140 | SETUP("") {
141 |
142 | nonstd::byte const b_org = to_byte( 0xa5 );
143 | nonstd::byte b = b_org;
144 |
145 | SECTION("Identity") { EXPECT( ( b ^= b ) == to_byte( 0 ) ); }
146 | SECTION("Identity") { EXPECT( ( b ^= to_byte( 0x00 ) ) == b_org ); }
147 | SECTION("Invert" ) { EXPECT( ( b ^= to_byte( 0xff ) ) == ~b_org ); }
148 | }
149 | }
150 |
151 | CASE( "byte: Allows shift-left operation" )
152 | {
153 | nonstd::byte const b = to_byte( 0xa5 );
154 |
155 | EXPECT( ( b << 3 ) == to_byte( to_uchar( b ) << 3 ) );
156 | }
157 |
158 | CASE( "byte: Allows shift-right operation" )
159 | {
160 | nonstd::byte const b = to_byte( 0xa5 );
161 |
162 | EXPECT( ( b >> 3 ) == to_byte( to_uchar( b ) >> 3 ) );
163 | }
164 |
165 | CASE( "byte: Allows shift-left assignment" )
166 | {
167 | nonstd::byte const b_org = to_byte( 0xa5 );
168 | nonstd::byte b = b_org;
169 |
170 | EXPECT( ( b <<= 3 ) == to_byte( to_uchar( b_org ) << 3 ) );
171 | }
172 |
173 | CASE( "byte: Allows shift-right assignment" )
174 | {
175 | nonstd::byte const b_org = to_byte( 0xa5 );
176 | nonstd::byte b = b_org;
177 |
178 | EXPECT( ( b >>= 3 ) == to_byte( to_uchar( b_org ) >> 3 ) );
179 | }
180 |
181 | CASE( "byte: Allows strict aliasing" )
182 | {
183 | struct F {
184 | static int f( int & i, nonstd::byte & r )
185 | {
186 | r <<= 1;
187 | return i;
188 | }
189 | };
190 |
191 | // Allow for both little and big endianness:
192 |
193 | int i = 7;
194 |
195 | unsigned char & first = reinterpret_cast( i );
196 | unsigned char & last = *( reinterpret_cast( &i ) + sizeof(int) - 1 );
197 |
198 | const bool big = first == 0 && last == 7;
199 | const bool little = first == 7 && last == 0;
200 |
201 | unsigned char & lsb = little ? first : last;
202 |
203 | EXPECT( big != little );
204 | EXPECT( 14 == F::f( i, reinterpret_cast( lsb ) ) );
205 | }
206 |
207 | CASE( "byte: Provides constexpr non-assignment operations (C++11)" )
208 | {
209 | #if byte_HAVE_CONSTEXPR_11
210 | static_assert( to_byte( 0xa5 ) == to_byte( 0xa5 ) , "" );
211 | static_assert( 0xa5 == to_integer( to_byte( 0xa5 ) ), "" );
212 |
213 | static_assert( to_byte( 0x02 ) == ( to_byte( 0x01 ) << 1 ), "" );
214 | static_assert( to_byte( 0x01 ) == ( to_byte( 0x02 ) >> 1 ), "" );
215 |
216 | static_assert( to_byte( 0x01 ) == ( to_byte( 0x03 ) & to_byte( 0x01 ) ), "" );
217 | static_assert( to_byte( 0x01 ) == ( to_byte( 0x00 ) | to_byte( 0x01 ) ), "" );
218 | static_assert( to_byte( 0x00 ) == ( to_byte( 0x01 ) ^ to_byte( 0x01 ) ), "" );
219 |
220 | static_assert( to_byte( 0xff ) == ~to_byte( 0x00 ), "" );
221 | #endif
222 | }
223 |
224 | CASE( "byte: Provides constexpr assignment operations (C++14)" )
225 | {
226 | #if byte_HAVE_CONSTEXPR_14
227 | // ...
228 | #endif
229 | }
230 |
231 | // end of file
232 |
--------------------------------------------------------------------------------
/test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright 2017-2022 by Martin Moene
2 | #
3 | # https://github.com/martinmoene/byte-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.15 FATAL_ERROR )
10 | endif()
11 |
12 | # byte-lite version, updated by script/update-version.py:
13 |
14 | project( test LANGUAGES CXX )
15 |
16 | # unit_name provided by toplevel CMakeLists.txt [set( unit_name "xxx" )]
17 | set( PACKAGE ${unit_name}-lite )
18 | set( PROGRAM ${unit_name}-lite )
19 | set( SOURCES ${unit_name}-main.t.cpp ${unit_name}.t.cpp )
20 | set( TWEAKD "." )
21 |
22 | message( STATUS "Subproject '${PROJECT_NAME}', programs '${PROGRAM}-*'")
23 |
24 | # Configure byte-lite for testing:
25 |
26 | set( DEFCMN "" )
27 | set( OPTIONS "" )
28 |
29 | set( HAS_STD_FLAGS FALSE )
30 | set( HAS_CPP98_FLAG FALSE )
31 | set( HAS_CPP11_FLAG FALSE )
32 | set( HAS_CPP14_FLAG FALSE )
33 | set( HAS_CPP17_FLAG FALSE )
34 | set( HAS_CPP20_FLAG FALSE )
35 | set( HAS_CPPLATEST_FLAG FALSE )
36 |
37 | if( MSVC )
38 | message( STATUS "Matched: MSVC")
39 |
40 | set( HAS_STD_FLAGS TRUE )
41 |
42 | set( OPTIONS -W3 -EHsc )
43 | set( DEFINITIONS -D_SCL_SECURE_NO_WARNINGS ${DEFCMN} )
44 |
45 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.00 )
46 | set( HAS_CPP14_FLAG TRUE )
47 | set( HAS_CPPLATEST_FLAG TRUE )
48 | endif()
49 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.11 )
50 | set( HAS_CPP17_FLAG TRUE )
51 | endif()
52 |
53 | elseif( CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang" )
54 | message( STATUS "CompilerId: '${CMAKE_CXX_COMPILER_ID}'")
55 |
56 | set( HAS_STD_FLAGS TRUE )
57 | set( HAS_CPP98_FLAG TRUE )
58 |
59 | set( OPTIONS
60 | -O2
61 | -Wall
62 | -Wno-missing-braces
63 | -Wconversion
64 | -Wsign-conversion
65 | # -Wno-string-conversion
66 | -fno-elide-constructors
67 | -fstrict-aliasing -Wstrict-aliasing=2
68 | )
69 | set( DEFINITIONS ${DEFCMN} )
70 |
71 | # GNU: available -std flags depends on version
72 | if( CMAKE_CXX_COMPILER_ID MATCHES "GNU" )
73 | message( STATUS "Matched: GNU")
74 |
75 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8.0 )
76 | set( HAS_CPP11_FLAG TRUE )
77 | endif()
78 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9.2 )
79 | set( HAS_CPP14_FLAG TRUE )
80 | endif()
81 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.1.0 )
82 | set( HAS_CPP17_FLAG TRUE )
83 | endif()
84 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0.0 )
85 | set( HAS_CPP20_FLAG TRUE )
86 | endif()
87 |
88 | # AppleClang: available -std flags depends on version
89 | elseif( CMAKE_CXX_COMPILER_ID MATCHES "AppleClang" )
90 | message( STATUS "Matched: AppleClang")
91 |
92 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0.0 )
93 | set( HAS_CPP11_FLAG TRUE )
94 | endif()
95 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1.0 )
96 | set( HAS_CPP14_FLAG TRUE )
97 | endif()
98 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.2.0 )
99 | set( HAS_CPP17_FLAG TRUE )
100 | endif()
101 | # if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS x.x.x )
102 | # set( HAS_CPP20_FLAG TRUE )
103 | # endif()
104 |
105 | # Clang: available -std flags depends on version
106 | elseif( CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
107 | message( STATUS "Matched: Clang")
108 |
109 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.3.0 )
110 | set( HAS_CPP11_FLAG TRUE )
111 | endif()
112 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4.0 )
113 | set( HAS_CPP14_FLAG TRUE )
114 | endif()
115 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0.0 )
116 | set( HAS_CPP17_FLAG TRUE )
117 | endif()
118 | if( NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0.0 )
119 | set( HAS_CPP20_FLAG TRUE )
120 | endif()
121 | endif()
122 |
123 | elseif( CMAKE_CXX_COMPILER_ID MATCHES "Intel" )
124 | # as is
125 | message( STATUS "Matched: Intel")
126 | else()
127 | # as is
128 | message( STATUS "Matched: nothing")
129 | endif()
130 |
131 | # enable MS C++ Core Guidelines checker if MSVC:
132 |
133 | function( enable_msvs_guideline_checker target )
134 | if( MSVC )
135 | set_target_properties( ${target} PROPERTIES
136 | VS_GLOBAL_EnableCppCoreCheck true
137 | VS_GLOBAL_CodeAnalysisRuleSet CppCoreCheckRules.ruleset
138 | VS_GLOBAL_RunCodeAnalysis true )
139 | endif()
140 | endfunction()
141 |
142 | # make target, compile for given standard if specified:
143 |
144 | function( make_target target std )
145 | message( STATUS "Make target: '${std}'" )
146 |
147 | add_executable ( ${target} ${SOURCES} )
148 | target_include_directories( ${target} SYSTEM PRIVATE lest )
149 | target_include_directories( ${target} PRIVATE ${TWEAKD} )
150 | target_link_libraries ( ${target} PRIVATE ${PACKAGE} )
151 | target_compile_options ( ${target} PRIVATE ${OPTIONS} )
152 | target_compile_definitions( ${target} PRIVATE ${DEFINITIONS} )
153 |
154 | if( std )
155 | if( MSVC )
156 | target_compile_options( ${target} PRIVATE -std:c++${std} )
157 | else()
158 | # Necessary for clang 3.x:
159 | target_compile_options( ${target} PRIVATE -std=c++${std} )
160 | # Ok for clang 4 and later:
161 | # set( CMAKE_CXX_STANDARD ${std} )
162 | # set( CMAKE_CXX_STANDARD_REQUIRED ON )
163 | # set( CMAKE_CXX_EXTENSIONS OFF )
164 | endif()
165 | endif()
166 | endfunction()
167 |
168 | # add generic executable, unless -std flags can be specified:
169 |
170 | if( NOT HAS_STD_FLAGS )
171 | make_target( ${PROGRAM}.t "" )
172 | else()
173 | # unconditionally add C++98 variant as MSVC has no option for it:
174 | if( HAS_CPP98_FLAG )
175 | make_target( ${PROGRAM}-cpp98.t 98 )
176 | else()
177 | make_target( ${PROGRAM}-cpp98.t "" )
178 | endif()
179 |
180 | if( HAS_CPP11_FLAG )
181 | make_target( ${PROGRAM}-cpp11.t 11 )
182 | endif()
183 |
184 | if( HAS_CPP14_FLAG )
185 | make_target( ${PROGRAM}-cpp14.t 14 )
186 | endif()
187 |
188 | if( HAS_CPP17_FLAG )
189 | set( std17 17 )
190 | if( CMAKE_CXX_COMPILER_ID MATCHES "AppleClang" )
191 | set( std17 1z )
192 | endif()
193 | make_target( ${PROGRAM}-cpp17.t ${std17} )
194 | enable_msvs_guideline_checker( ${PROGRAM}-cpp17.t )
195 | endif()
196 |
197 | if( HAS_CPP20_FLAG )
198 | make_target( ${PROGRAM}-cpp20.t 20 )
199 | endif()
200 |
201 | if( HAS_CPPLATEST_FLAG )
202 | make_target( ${PROGRAM}-cpplatest.t latest )
203 | endif()
204 | endif()
205 |
206 | # with C++17 and later, honour explicit request for std::xxx or nonstd::xxx:
207 |
208 | if( HAS_CPP17_FLAG OR HAS_CPP20_FLAG )
209 | set( WHICH byte_BYTE_DEFAULT )
210 |
211 | if( BYTE_LITE_OPT_SELECT_STD )
212 | set( WHICH byte_BYTE_STD )
213 | elseif( BYTE_LITE_OPT_SELECT_NONSTD )
214 | set( WHICH byte_BYTE_NONSTD )
215 | endif()
216 |
217 | message( STATUS "Subproject '${PROJECT_NAME}', C++17 and later using '${WHICH}'")
218 |
219 | if( HAS_CPP17_FLAG )
220 | target_compile_definitions( ${PROGRAM}-cpp17.t PRIVATE byte_CONFIG_SELECT_BYTE=${WHICH} )
221 | endif()
222 |
223 | if( HAS_CPP20_FLAG )
224 | target_compile_definitions( ${PROGRAM}-cpp20.t PRIVATE byte_CONFIG_SELECT_BYTE=${WHICH} )
225 | endif()
226 |
227 | if( HAS_CPPLATEST_FLAG )
228 | target_compile_definitions( ${PROGRAM}-cpplatest.t PRIVATE byte_CONFIG_SELECT_BYTE=${WHICH} )
229 | endif()
230 | endif()
231 |
232 | # configure unit tests via CTest:
233 |
234 | if( HAS_STD_FLAGS )
235 | # unconditionally add C++98 variant for MSVC:
236 | add_test( NAME test-cpp98 COMMAND ${PROGRAM}-cpp98.t )
237 |
238 | if( HAS_CPP11_FLAG )
239 | add_test( NAME test-cpp11 COMMAND ${PROGRAM}-cpp11.t )
240 | endif()
241 | if( HAS_CPP14_FLAG )
242 | add_test( NAME test-cpp14 COMMAND ${PROGRAM}-cpp14.t )
243 | endif()
244 | if( HAS_CPP17_FLAG )
245 | add_test( NAME test-cpp17 COMMAND ${PROGRAM}-cpp17.t )
246 | endif()
247 | if( HAS_CPP20_FLAG )
248 | add_test( NAME test-cpp20 COMMAND ${PROGRAM}-cpp20.t )
249 | endif()
250 | if( HAS_CPPLATEST_FLAG )
251 | add_test( NAME test-cpplatest COMMAND ${PROGRAM}-cpplatest.t )
252 | endif()
253 | else()
254 | add_test( NAME test COMMAND ${PROGRAM}.t --pass )
255 | add_test( NAME list_version COMMAND ${PROGRAM}.t --version )
256 | add_test( NAME list_tags COMMAND ${PROGRAM}.t --list-tags )
257 | add_test( NAME list_tests COMMAND ${PROGRAM}.t --list-tests )
258 | endif()
259 |
260 | # end of file
261 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # byte lite: A single-file header-only C++17-like byte type for C++98, C++11 and later
2 |
3 | [](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) [](https://opensource.org/licenses/BSL-1.0) [](https://github.com/martinmoene/byte-lite/actions/workflows/ci.yml) [](https://github.com/martinmoene/byte-lite/releases) [](https://raw.githubusercontent.com/martinmoene/byte-lite/master/include/nonstd/byte.hpp) [](https://conan.io/center/byte-lite) [](https://vcpkg.link/ports/byte-lite) [](https://wandbox.org/permlink/6wTFn0svYP4dQYhV) [](https://godbolt.org/z/xjekHR)
4 |
5 | **Contents**
6 | - [Example usage](#example-usage)
7 | - [In a nutshell](#in-a-nutshell)
8 | - [License](#license)
9 | - [Dependencies](#dependencies)
10 | - [Installation](#installation)
11 | - [Synopsis](#synopsis)
12 | - [Features](#features)
13 | - [Reported to work with](#reported-to-work-with)
14 | - [Building the tests](#building-the-tests)
15 | - [Other implementations of byte](#other-implementations-of-byte)
16 | - [Notes and References](#notes-and-references)
17 | - [Appendix](#appendix)
18 |
19 |
20 | Example usage
21 | -------------
22 |
23 | ```Cpp
24 | #include "nonstd/byte.hpp"
25 |
26 | #include
27 |
28 | using namespace nonstd;
29 |
30 | int main()
31 | {
32 | byte b1 = to_byte( 0x5a ); // to_byte() is non-standard, needed for pre-C++17
33 | byte b2 = to_byte( 0xa5 );
34 |
35 | byte r1 = b1 ^ b2; assert( 0xff == to_integer( r1 ) ); // not (yet) standard, needs C++11
36 | byte r2 = b1 ^ b2; assert( 0xff == to_integer( r2 ) );
37 | }
38 | ```
39 |
40 | ### Compile and run
41 |
42 | ```
43 | prompt> g++ -std=c++11 -Wall -I../include -o 01-basic 01-basic.cpp && 01-basic
44 | ```
45 |
46 | Or to run with [Buck](https://buckbuild.com/):
47 |
48 | ```
49 | prompt> buck run example:01-basic
50 | ```
51 |
52 | In a nutshell
53 | -------------
54 | **byte lite** is a single-file header-only library to provide a [C++17-like distinct byte type](http://en.cppreference.com/w/cpp/types/byte) for use with C++98 and later.
55 |
56 | **Features and properties of byte lite** are are ease of installation (single header), freedom of dependencies other than the standard library.
57 |
58 | **A limitation of byte lite** is that you need to use function `to_byte(v)` to construct a `byte` from an integral value `v`, when C++17's relaxation of the enum value construction rule is not available.
59 |
60 | License
61 | -------
62 | *byte lite* is distributed under the [Boost Software License](https://github.com/martinmoene/XXXX-lite/blob/master/LICENSE.txt).
63 |
64 |
65 | Dependencies
66 | ------------
67 | *byte lite* has no other dependencies than the [C++ standard library](http://en.cppreference.com/w/cpp/header).
68 |
69 |
70 | Installation
71 | ------------
72 | *byte lite* is a single-file header-only library. Put `byte.hpp` in the [include](include) folder directly into the project source tree or somewhere reachable from your project.
73 |
74 |
75 | Synopsis
76 | --------
77 |
78 | **Contents**
79 | - [Types in namespace nonstd](#types-in-namespace-nonstd)
80 | - [Algorithms for *byte lite*](#algorithms-for-byte-lite)
81 | - [Configuration macros](#configuration-macros)
82 |
83 | ### Types in namespace nonstd
84 |
85 | | Purpose | Type | Std | Notes |
86 | |--------------------|:--------------------|:-------:|:-------|
87 | | Distinct byte type | enum class **byte** | >=C++17 | |
88 | | | struct **byte** | < C++17 | |
89 |
90 | ### Algorithms for *byte lite*
91 |
92 | | Kind | Std | Function | Result |
93 | |-------------------|:-------:|----------|--------|
94 | | Shift-assign | | template< class IntegerType >
constexpr byte & **operator<<=**( byte & b, IntegerType shift ) noexcept | left-shifted b |
95 | | | | template< class IntegerType >
constexpr byte & **operator>>=**( byte & b, IntegerType shift ) noexcept | right-shifted b |
96 | | Shift | | template< class IntegerType >
constexpr byte **operator<<**( byte b, IntegerType shift ) noexcept | left-shifted byte |
97 | | | | template< class IntegerType >
constexpr byte **operator>>**( byte b, IntegerType shift ) noexcept | right-shifted byte |
98 | | Bitwise-op-assign | | template< class IntegerType >
constexpr byte & **operator¦=**( byte & l, byte r ) noexcept | bitwise-or-ed b |
99 | | | | template< class IntegerType >
constexpr byte & **operator&=**( byte & l, byte r ) noexcept | bitwise-xor-ed b |
100 | | | | template< class IntegerType >
constexpr byte & **operator^=**( byte & l, byte r ) noexcept | bitwise-and-ed b |
101 | | Bitwise-op | | template< class IntegerType >
constexpr byte & **operator¦**( byte l, byte r ) noexcept | bitwise-or-ed byte |
102 | | | | template< class IntegerType >
constexpr byte & **operator&**( byte l, byte r ) noexcept | bitwise-xor-ed byte |
103 | | | | template< class IntegerType >
constexpr byte & **operator^**( byte l, byte r ) noexcept | bitwise-and-ed byte|
104 | | Conversion | non-std | template< class IntegerType >
constexpr byte **to_byte**( IntegerType v ) | byte with value v|
105 | | | >=C++11 | template< class IntegerType = *underlying-type* >
constexpr IntegerType **to_integer**( byte b ) | byte's value, note 2, 3|
106 | | | < C++11 | template< class IntegerType >
constexpr IntegerType **to_integer**( byte b ) | byte's value, note 3 |
107 |
108 | **Note 1**: the algorithms use an extra level of casting to prevent undefined behaviour, as mentioned by Thomas Köppe on mailing list isocpp-lib, subject "std::byte operations are hard to use correctly", on 16 March 2017.
109 |
110 | **Note 2**: default template parameter as suggested by Zhihao Yuan on mailing list isocpp-lib, subject "std::byte to_integer<>", on 10 March 2017.
111 |
112 | **Note 3**: use `to_integer()` to compute a byte's hash value.
113 |
114 | ### Configuration macros
115 |
116 | #### Standard selection macro
117 | \-Dbyte\_CPLUSPLUS=199711L
118 | Define this macro to override the auto-detection of the supported C++ standard, if your compiler does not set the `__cpluplus` macro correctly.
119 |
120 | #### Select `std::byte` or `nonstd::byte`
121 | At default, *byte lite* uses `std::byte` if it is available and lets you use it via namespace `nonstd`. You can however override this default and explicitly request to use `std::byte` or byte lite's `nonstd::byte` as `nonstd::byte` via the following macros.
122 |
123 | -Dbyte\_CONFIG\_SELECT\_BYTE=byte_BYTE_DEFAULT
124 | Define this to `byte_BYTE_STD` to select `std::byte` as `nonstd::byte`. Define this to `byte_BYTE_NONSTD` to select `nonstd::byte` as `nonstd::byte`. Default is undefined, which has the same effect as defining to `byte_BYTE_DEFAULT`.
125 |
126 |
127 | Reported to work with
128 | ---------------------
129 | The table below mentions the compiler versions *byte lite* is reported to work with.
130 |
131 | OS | Compiler | Versions |
132 | ---------:|:-----------|:---------|
133 | Windows | Clang/LLVM | ? |
134 | | GCC | 5.2.0 |
135 | | Visual C++
(Visual Studio)| 6 (6), 8 (2005), 9 (2008), 10 (2010),
11 (2012), 12 (2013), 14 (2015), 15 (2017) |
136 | GNU/Linux | Clang/LLVM | 3.5 - 6.0 |
137 | | GCC | 4.8 - 8 |
138 | OS X | Clang/LLVM | Xcode 6, Xcode 7, Xcode 8, Xcode 9 |
139 |
140 |
141 | Building the tests
142 | ------------------
143 | To build the tests you need:
144 |
145 | - [CMake](http://cmake.org), version 2.8.12 or later to be installed and in your PATH.
146 | - A [suitable compiler](#reported-to-work-with).
147 |
148 | The [*lest* test framework](https://github.com/martinmoene/lest) is included in the [test folder](test).
149 |
150 | The following steps assume that the [*byte lite* source code](https://github.com/martinmoene/byte-lite) has been cloned into a directory named `c:\byte-lite`.
151 |
152 | 1. Create a directory for the build outputs for a particular architecture.
153 | Here we use c:\byte-lite\build-win-x86-vc10.
154 |
155 | cd c:\byte-lite
156 | md build-win-x86-vc10
157 | cd build-win-x86-vc10
158 |
159 | 2. Configure CMake to use the compiler of your choice (run `cmake --help` for a list).
160 |
161 | cmake -G "Visual Studio 10 2010" -DBYTE_LITE_OPT_BUILD_TESTS=ON ..
162 |
163 | 3. Build the test suite in the Debug configuration (alternatively use Release).
164 |
165 | cmake --build . --config Debug
166 |
167 | 4. Run the test suite.
168 |
169 | ctest -V -C Debug
170 |
171 | All tests should pass, indicating your platform is supported and you are ready to use *byte lite*.
172 |
173 |
174 | Other implementations of byte
175 | ----------------------------
176 | - Martin Moene. [gsl lite](https://github.com/martinmoene/gsl-lite). C++98 and later.
177 | - Microsoft. [Guideline Support Library (GSL)](https://github.com/microsoft/gsl). C++14 (supports MSVC 2013 and 2015).
178 |
179 |
180 | Notes and References
181 | --------------------
182 | [1] CppReference. [byte](http://en.cppreference.com/w/cpp/types/byte).
183 |
184 | [2] ISO/IEC WG21. [N4659, section 21.2.1, Header synopsis](http://wg21.link/n4659#page=492). March 2017.
185 |
186 | [3] Neil MacIntosh. [P0298: A byte type definition (Revision 3)](http://wg21.link/p0298). March 2017.
187 |
188 |
189 | Appendix
190 | --------
191 |
192 | ### A.1 Compile-time information
193 |
194 | The version of *byte 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]`.
195 |
196 | ### A.2 Byte lite test specification
197 |
198 | ```
199 | byte: Allows to construct from integral via static cast (C++17)
200 | byte: Allows to construct from integral via byte() (C++17)
201 | byte: Allows to construct from integral via to_byte()
202 | byte: Allows to convert to integral via to_integer()
203 | byte: Allows to convert to integral via to_integer(), using default type
204 | byte: Allows comparison operations
205 | byte: Allows bitwise or operation
206 | byte: Allows bitwise and operation
207 | byte: Allows bitwise x-or operation
208 | byte: Allows bitwise or assignment
209 | byte: Allows bitwise and assignment
210 | byte: Allows bitwise x-or assignment
211 | byte: Allows shift-left operation
212 | byte: Allows shift-right operation
213 | byte: Allows shift-left assignment
214 | byte: Allows shift-right assignment
215 | byte: Allows strict aliasing
216 | byte: Provides constexpr non-assignment operations (C++11)
217 | byte: Provides constexpr assignment operations (C++14)
218 | ```
219 |
--------------------------------------------------------------------------------
/include/nonstd/byte.hpp:
--------------------------------------------------------------------------------
1 | //
2 | // byte-lite, a C++17-like byte type for C++98 and later.
3 | // For more information see https://github.com/martinmoene/byte-lite
4 | //
5 | // Copyright 2017-2019 Martin Moene
6 | //
7 | // Distributed under the Boost Software License, Version 1.0.
8 | // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 |
10 | #pragma once
11 |
12 | #ifndef NONSTD_BYTE_LITE_HPP
13 | #define NONSTD_BYTE_LITE_HPP
14 |
15 | #define byte_lite_MAJOR 0
16 | #define byte_lite_MINOR 3
17 | #define byte_lite_PATCH 0
18 |
19 | #define byte_lite_VERSION byte_STRINGIFY(byte_lite_MAJOR) "." byte_STRINGIFY(byte_lite_MINOR) "." byte_STRINGIFY(byte_lite_PATCH)
20 |
21 | #define byte_STRINGIFY( x ) byte_STRINGIFY_( x )
22 | #define byte_STRINGIFY_( x ) #x
23 |
24 | // byte-lite configuration:
25 |
26 | #define byte_BYTE_DEFAULT 0
27 | #define byte_BYTE_NONSTD 1
28 | #define byte_BYTE_STD 2
29 |
30 | #if !defined( byte_CONFIG_SELECT_BYTE )
31 | # define byte_CONFIG_SELECT_BYTE ( byte_HAVE_STD_BYTE ? byte_BYTE_STD : byte_BYTE_NONSTD )
32 | #endif
33 |
34 | // C++ language version detection (C++23 is speculative):
35 | // Note: VC14.0/1900 (VS2015) lacks too much from C++14.
36 |
37 | #ifndef byte_CPLUSPLUS
38 | # if defined(_MSVC_LANG ) && !defined(__clang__)
39 | # define byte_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )
40 | # else
41 | # define byte_CPLUSPLUS __cplusplus
42 | # endif
43 | #endif
44 |
45 | #define byte_CPP98_OR_GREATER ( byte_CPLUSPLUS >= 199711L )
46 | #define byte_CPP11_OR_GREATER ( byte_CPLUSPLUS >= 201103L )
47 | #define byte_CPP11_OR_GREATER_ ( byte_CPLUSPLUS >= 201103L )
48 | #define byte_CPP14_OR_GREATER ( byte_CPLUSPLUS >= 201402L )
49 | #define byte_CPP17_OR_GREATER ( byte_CPLUSPLUS >= 201703L )
50 | #define byte_CPP20_OR_GREATER ( byte_CPLUSPLUS >= 202002L )
51 | #define byte_CPP23_OR_GREATER ( byte_CPLUSPLUS >= 202300L )
52 |
53 | // use C++17 std::byte if available and requested:
54 |
55 | #if byte_CPP17_OR_GREATER
56 | # define byte_HAVE_STD_BYTE 1
57 | #else
58 | # define byte_HAVE_STD_BYTE 0
59 | #endif
60 |
61 | #define byte_USES_STD_BYTE ( (byte_CONFIG_SELECT_BYTE == byte_BYTE_STD) || ((byte_CONFIG_SELECT_BYTE == byte_BYTE_DEFAULT) && byte_HAVE_STD_BYTE) )
62 |
63 | //
64 | // Using std::byte:
65 | //
66 |
67 | #if byte_USES_STD_BYTE
68 |
69 | #include
70 | #include
71 |
72 | namespace nonstd {
73 |
74 | using std::byte;
75 | using std::to_integer;
76 |
77 | // Provide compatibility with nonstd::byte:
78 |
79 | template
80 | <
81 | class IntegerType
82 | , class = typename std::enable_if::value>::type
83 | >
84 | inline constexpr byte to_byte( IntegerType v ) noexcept
85 | {
86 | return static_cast( v );
87 | }
88 |
89 | inline constexpr unsigned char to_uchar( byte b ) noexcept
90 | {
91 | return to_integer( b );
92 | }
93 |
94 | } // namespace nonstd
95 |
96 | #else // byte_USES_STD_BYTE
97 |
98 | // half-open range [lo..hi):
99 | #define byte_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) )
100 |
101 | // Compiler versions:
102 | //
103 | // MSVC++ 6.0 _MSC_VER == 1200 byte_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0)
104 | // MSVC++ 7.0 _MSC_VER == 1300 byte_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002)
105 | // MSVC++ 7.1 _MSC_VER == 1310 byte_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003)
106 | // MSVC++ 8.0 _MSC_VER == 1400 byte_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005)
107 | // MSVC++ 9.0 _MSC_VER == 1500 byte_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008)
108 | // MSVC++ 10.0 _MSC_VER == 1600 byte_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010)
109 | // MSVC++ 11.0 _MSC_VER == 1700 byte_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012)
110 | // MSVC++ 12.0 _MSC_VER == 1800 byte_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013)
111 | // MSVC++ 14.0 _MSC_VER == 1900 byte_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015)
112 | // MSVC++ 14.1 _MSC_VER >= 1910 byte_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017)
113 | // MSVC++ 14.2 _MSC_VER >= 1920 byte_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019)
114 |
115 | #if defined(_MSC_VER ) && !defined(__clang__)
116 | # define byte_COMPILER_MSVC_VER (_MSC_VER )
117 | # define byte_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) )
118 | #else
119 | # define byte_COMPILER_MSVC_VER 0
120 | # define byte_COMPILER_MSVC_VERSION 0
121 | #endif
122 |
123 | #define byte_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) )
124 |
125 | #if defined(__clang__)
126 | # define byte_COMPILER_CLANG_VERSION byte_COMPILER_VERSION( __clang_major__, __clang_minor__, __clang_patchlevel__ )
127 | #else
128 | # define byte_COMPILER_CLANG_VERSION 0
129 | #endif
130 |
131 | #if defined(__GNUC__) && !defined(__clang__)
132 | # define byte_COMPILER_GNUC_VERSION byte_COMPILER_VERSION( __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ )
133 | #else
134 | # define byte_COMPILER_GNUC_VERSION 0
135 | #endif
136 |
137 | #if byte_BETWEEN( byte_COMPILER_MSVC_VER, 1300, 1900 )
138 | # pragma warning( push )
139 | # pragma warning( disable: 4345 ) // initialization behavior changed
140 | #endif
141 |
142 | // Compiler non-strict aliasing:
143 |
144 | #if defined(__clang__) || defined(__GNUC__)
145 | # define byte_may_alias __attribute__((__may_alias__))
146 | #else
147 | # define byte_may_alias
148 | #endif
149 |
150 | // Presence of language and library features:
151 |
152 | #ifdef _HAS_CPP0X
153 | # define byte_HAS_CPP0X _HAS_CPP0X
154 | #else
155 | # define byte_HAS_CPP0X 0
156 | #endif
157 |
158 | // Unless defined otherwise below, consider VC14 as C++11 for variant-lite:
159 |
160 | #if byte_COMPILER_MSVC_VER >= 1900
161 | # undef byte_CPP11_OR_GREATER
162 | # define byte_CPP11_OR_GREATER 1
163 | #endif
164 |
165 | #define byte_CPP11_90 (byte_CPP11_OR_GREATER_ || byte_COMPILER_MSVC_VER >= 1500)
166 | #define byte_CPP11_100 (byte_CPP11_OR_GREATER_ || byte_COMPILER_MSVC_VER >= 1600)
167 | #define byte_CPP11_110 (byte_CPP11_OR_GREATER_ || byte_COMPILER_MSVC_VER >= 1700)
168 | #define byte_CPP11_120 (byte_CPP11_OR_GREATER_ || byte_COMPILER_MSVC_VER >= 1800)
169 | #define byte_CPP11_140 (byte_CPP11_OR_GREATER_ || byte_COMPILER_MSVC_VER >= 1900)
170 | #define byte_CPP11_141 (byte_CPP11_OR_GREATER_ || byte_COMPILER_MSVC_VER >= 1910)
171 |
172 | #define byte_CPP14_000 (byte_CPP14_OR_GREATER)
173 | #define byte_CPP17_000 (byte_CPP17_OR_GREATER)
174 |
175 | // Presence of C++11 language features:
176 |
177 | #define byte_HAVE_CONSTEXPR_11 byte_CPP11_140
178 | #define byte_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG byte_CPP11_120
179 | #define byte_HAVE_NOEXCEPT byte_CPP11_140
180 |
181 | // Presence of C++14 language features:
182 |
183 | #define byte_HAVE_CONSTEXPR_14 byte_CPP14_000
184 |
185 | // Presence of C++17 language features:
186 |
187 | #define byte_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE byte_CPP17_000
188 |
189 | // Presence of C++ library features:
190 |
191 | #define byte_HAVE_TYPE_TRAITS byte_CPP11_90
192 |
193 | // C++ feature usage:
194 |
195 | #if byte_HAVE_CONSTEXPR_11
196 | # define byte_constexpr constexpr
197 | #else
198 | # define byte_constexpr /*constexpr*/
199 | #endif
200 |
201 | #if byte_HAVE_CONSTEXPR_14
202 | # define byte_constexpr14 constexpr
203 | #else
204 | # define byte_constexpr14 /*constexpr*/
205 | #endif
206 |
207 | #if byte_HAVE_NOEXCEPT
208 | # define byte_noexcept noexcept
209 | #else
210 | # define byte_noexcept /*noexcept*/
211 | #endif
212 |
213 | // additional includes:
214 |
215 | #if byte_HAVE_TYPE_TRAITS
216 | # include
217 | #endif
218 |
219 | // conditionally enabling:
220 |
221 | #if byte_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG
222 | # define byte_ENABLE_IF_INTEGRAL_T(T) \
223 | , class = typename std::enable_if::value>::type
224 | #else
225 | # define byte_ENABLE_IF_INTEGRAL_T(T)
226 | #endif
227 |
228 | #if byte_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG
229 | # define byte_DEFAULT_TEMPLATE_ARG(T) \
230 | = T
231 | #else
232 | # define byte_DEFAULT_TEMPLATE_ARG(T)
233 | #endif
234 |
235 | namespace nonstd {
236 |
237 | namespace detail {
238 | }
239 |
240 | #if byte_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
241 | enum class byte_may_alias byte : unsigned char {};
242 | #else
243 | struct byte_may_alias byte { typedef unsigned char type; type v; };
244 | #endif
245 |
246 | template<
247 | class IntegerType
248 | byte_ENABLE_IF_INTEGRAL_T( IntegerType )
249 | >
250 | inline byte_constexpr byte to_byte( IntegerType v ) byte_noexcept
251 | {
252 | #if byte_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
253 | return static_cast( v );
254 | #elif byte_HAVE_CONSTEXPR_11
255 | return { static_cast( v ) };
256 | #else
257 | byte b = { static_cast( v ) }; return b;
258 | #endif
259 | }
260 |
261 | #if byte_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
262 |
263 | template<
264 | class IntegerType = typename std::underlying_type::type
265 | byte_ENABLE_IF_INTEGRAL_T( IntegerType )
266 | >
267 | inline byte_constexpr IntegerType to_integer( byte b ) byte_noexcept
268 | {
269 | return static_cast( b );
270 | }
271 |
272 | #elif byte_CPP11_OR_GREATER
273 |
274 | template<
275 | class IntegerType
276 | byte_DEFAULT_TEMPLATE_ARG(typename byte::type) byte_ENABLE_IF_INTEGRAL_T( IntegerType )
277 | >
278 | inline byte_constexpr IntegerType to_integer( byte b ) byte_noexcept
279 | {
280 | return b.v;
281 | }
282 |
283 | #else // for C++98:
284 |
285 | template<
286 | class IntegerType
287 | >
288 | inline byte_constexpr IntegerType to_integer( byte b ) byte_noexcept
289 | {
290 | return b.v;
291 | }
292 |
293 | inline byte_constexpr unsigned char to_integer( byte b ) byte_noexcept
294 | {
295 | return to_integer( b );
296 | }
297 |
298 | #endif
299 |
300 | inline byte_constexpr unsigned char to_uchar( byte b ) byte_noexcept
301 | {
302 | return to_integer( b );
303 | }
304 |
305 | inline byte_constexpr unsigned char to_uchar( int i ) byte_noexcept
306 | {
307 | return static_cast( i );
308 | }
309 |
310 | #if ! byte_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
311 |
312 | inline byte_constexpr bool operator==( byte l, byte r ) byte_noexcept
313 | {
314 | return l.v == r.v;
315 | }
316 |
317 | inline byte_constexpr bool operator!=( byte l, byte r ) byte_noexcept
318 | {
319 | return !( l == r );
320 | }
321 |
322 | inline byte_constexpr bool operator< ( byte l, byte r ) byte_noexcept
323 | {
324 | return l.v < r.v;
325 | }
326 |
327 | inline byte_constexpr bool operator<=( byte l, byte r ) byte_noexcept
328 | {
329 | return !( r < l );
330 | }
331 |
332 | inline byte_constexpr bool operator> ( byte l, byte r ) byte_noexcept
333 | {
334 | return ( r < l );
335 | }
336 |
337 | inline byte_constexpr bool operator>=( byte l, byte r ) byte_noexcept
338 | {
339 | return !( l < r );
340 | }
341 |
342 | #endif
343 |
344 | template<
345 | class IntegerType
346 | byte_ENABLE_IF_INTEGRAL_T( IntegerType )
347 | >
348 | inline byte_constexpr14 byte & operator<<=( byte & b, IntegerType shift ) byte_noexcept
349 | {
350 | #if byte_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
351 | return b = to_byte( to_uchar( b ) << shift );
352 | #else
353 | b.v = to_uchar( b.v << shift ); return b;
354 | #endif
355 | }
356 |
357 | template<
358 | class IntegerType
359 | byte_ENABLE_IF_INTEGRAL_T( IntegerType )
360 | >
361 | inline byte_constexpr14 byte & operator>>=( byte & b, IntegerType shift ) byte_noexcept
362 | {
363 | #if byte_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
364 | return b = to_byte( to_uchar( b ) >> shift );
365 | #else
366 | b.v = to_uchar( b.v >> shift ); return b;
367 | #endif
368 | }
369 |
370 | template<
371 | class IntegerType
372 | byte_ENABLE_IF_INTEGRAL_T( IntegerType )
373 | >
374 | inline byte_constexpr byte operator<<( byte b, IntegerType shift ) byte_noexcept
375 | {
376 | return to_byte( to_uchar( b ) << shift );
377 | }
378 |
379 | template<
380 | class IntegerType
381 | byte_ENABLE_IF_INTEGRAL_T( IntegerType )
382 | >
383 | inline byte_constexpr byte operator>>( byte b, IntegerType shift ) byte_noexcept
384 | {
385 | return to_byte( to_uchar( b ) >> shift );
386 | }
387 |
388 | inline byte_constexpr14 byte & operator|=( byte & l, byte r ) byte_noexcept
389 | {
390 | #if byte_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
391 | return l = to_byte( to_uchar( l ) | to_uchar( r ) );
392 | #else
393 | l.v = to_uchar( l ) | to_uchar( r ); return l;
394 | #endif
395 | }
396 |
397 | inline byte_constexpr14 byte & operator&=( byte & l, byte r ) byte_noexcept
398 | {
399 | #if byte_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
400 | return l = to_byte( to_uchar( l ) & to_uchar( r ) );
401 | #else
402 | l.v = to_uchar( l ) & to_uchar( r ); return l;
403 | #endif
404 | }
405 |
406 | inline byte_constexpr14 byte & operator^=( byte & l, byte r ) byte_noexcept
407 | {
408 | #if byte_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE
409 | return l = to_byte( to_uchar( l ) ^ to_uchar (r ) );
410 | #else
411 | l.v = to_uchar( l ) ^ to_uchar (r ); return l;
412 | #endif
413 | }
414 |
415 | inline byte_constexpr byte operator|( byte l, byte r ) byte_noexcept
416 | {
417 | return to_byte( to_uchar( l ) | to_uchar( r ) );
418 | }
419 |
420 | inline byte_constexpr byte operator&( byte l, byte r ) byte_noexcept
421 | {
422 | return to_byte( to_uchar( l ) & to_uchar( r ) );
423 | }
424 |
425 | inline byte_constexpr byte operator^( byte l, byte r ) byte_noexcept
426 | {
427 | return to_byte( to_uchar( l ) ^ to_uchar( r ) );
428 | }
429 |
430 | inline byte_constexpr byte operator~( byte b ) byte_noexcept
431 | {
432 | return to_byte( ~to_uchar( b ) );
433 | }
434 |
435 | } // namespace nonstd
436 |
437 | #endif // byte_USES_STD_BYTE
438 |
439 | #endif // NONSTD_BYTE_LITE_HPP
440 |
441 | // end of file
442 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------