diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a16bc82 --- /dev/null +++ b/.gitignore @@ -0,0 +1,343 @@ +## DBJ added +*.filters +*.user +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- Backup*.rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..89a82b0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "crt_proxy_app/dbj--simplelog"] + path = crt_proxy_app/dbj--simplelog + url = https://github.com/dbj-systems/dbj--simplelog.git diff --git a/LICENSE_1_0.txt b/LICENSE similarity index 100% rename from LICENSE_1_0.txt rename to LICENSE diff --git a/LICENSE_DBJ b/LICENSE_DBJ new file mode 100644 index 0000000..a86afb4 --- /dev/null +++ b/LICENSE_DBJ @@ -0,0 +1,28 @@ + +# License DBJ + +### Copyright © 2019-2020, Dusan B. Jovanovic (dbj@dbj.org) + +*All rights reserved.* + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +1. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +1. Neither the name of Dusan B. Jovanovic nor the names of the contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +## Caveat Emptor + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. + +IN NO EVENT SHALL Dusan B. Jovanovic BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/Makefile.gcc b/Makefile.gcc deleted file mode 100644 index 8a5e82f..0000000 --- a/Makefile.gcc +++ /dev/null @@ -1,57 +0,0 @@ -# -# Makefile.gcc -# -# Provide error checked version of various functions from std C library. -# -# Created on 3 July 2011, by Martin Moene -# -# Copyright 2011 Universiteit Leiden -# -# Distributed under the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -# - -#CC set on commandline as CC = gcc, or CC=g++ -CFLAGS = -Wall -VPATH = src:lib:test:doc/src -SHELL = bash # requires bash to be in path; needed for ( cmd1; cmd2 ) - -.c.o: - $(CC) $(CFLAGS) -Isrc -c $^ -o lib/$@ - -all: lib test doc - -clean: - -rm *.bak *.o lib/*.o test/*.o doc/src/*.o - -distclean: clean - -rm doc/*.chm test/ecore.exe test/emalloc.exe test/estdio.exe lib/libstdc-error.a - -rm -rf doc/html - -lib: lib/libstdc-error.a - -test: ecore.exe emalloc.exe estdio.exe - -doc: examples doc/libstdc-error.chm - -examples: ex-ecore.o ex-emalloc.o ex-estdio.o - -lib/libstdc-error.a: ecore.o emalloc.o estdio.o - $(AR) rcs lib/libstdc-error.a lib/ecore.o lib/emalloc.o lib/estdio.o - -ecore.exe: ecore.c ecore.h - $(CC) $(CFLAGS) -DTEST_ERROR -o test/ecore.exe $^ -L lib -l stdc-error - -emalloc.exe: ecore.c ecore.h emalloc.c emalloc.h - $(CC) $(CFLAGS) -DTEST_EMALLOC -o test/emalloc.exe $^ -L lib -l stdc-error - -estdio.exe: ecore.c ecore.h estdio.c estdio.h - $(CC) $(CFLAGS) -DTEST_ESTDIO -o test/estdio.exe $^ -L lib -l stdc-error - -doc/libstdc-error.chm: ecore.c ecore.h emalloc.c emalloc.h estdio.c estdio.h \ - ex-ecore.c ex-emalloc.c ex-estdio.c - ( cd doc; doxygen ) - -# -# End of file -# diff --git a/Makefile.vc b/Makefile.vc deleted file mode 100644 index 0e1c430..0000000 --- a/Makefile.vc +++ /dev/null @@ -1,72 +0,0 @@ -# -# Makefile.vc -# -# Provide error checked version of various functions from std C library. -# -# Created on 3 July 2011, by Martin Moene -# -# Copyright 2011 Universiteit Leiden -# -# Distributed under the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -# - -CFLAGS = -nologo -W4 -D_CRT_SECURE_NO_WARNINGS $(LANOPT) - -{src}.c{lib}.obj: - $(CC) $(CFLAGS) -c -Fo$* $< - -{doc\src}.c{test}.obj: - $(CC) $(CFLAGS) -Isrc -c -Fo$* $< - -all: lib test doc - -clean: - -del *.bak - -del *.obj - -del lib\*.obj - -del src\*.bak - -del test\*.obj - -del doc\src\*.bak - -del doc\src\*.obj - -distclean: clean - -del doc\*.chm - -del test\ecore.exe - -del test\emalloc.exe - -del test\estdio.exe - -del lib\libstdc-error.lib - -lib: lib/libstdc-error.lib - -test: test\ecore.exe test\emalloc.exe test\estdio.exe - -doc: examples doc/libstdc-error.chm - -examples: test\ex-ecore.obj test\ex-emalloc.obj test\ex-estdio.obj - -test\ex-ecore.obj: doc\src\ex-ecore.c -test\ex-emalloc.obj: doc\src\ex-emalloc.c -test\ex-estdio.obj: doc\src\ex-estdio.c - -lib/libstdc-error.lib: lib\ecore.obj lib\emalloc.obj lib\estdio.obj - lib /out:lib\libstdc-error.lib lib\ecore.obj lib\emalloc.obj lib\estdio.obj - -test\ecore.exe: src\ecore.c src\ecore.h - $(CC) $(CFLAGS) -DTEST_ERROR -Fetest\ecore.exe src\ecore.c /link lib\libstdc-error.lib - -test\emalloc.exe: src\ecore.c src\ecore.h src\emalloc.c src\emalloc.h - $(CC) $(CFLAGS) -DTEST_EMALLOC -Fetest\emalloc.exe src\emalloc.c /link lib\libstdc-error.lib - -test\estdio.exe: src\ecore.c src\ecore.h src\estdio.c src\estdio.h - $(CC) $(CFLAGS) -DTEST_ESTDIO -Fetest\estdio.exe src\estdio.c /link lib\libstdc-error.lib - -doc\libstdc-error.chm: src\ecore.c src\ecore.h src\emalloc.c src\emalloc.h src\estdio.c src\estdio.h \ - ex-ecore.c ex-emalloc.c ex-estdio.c - cd doc - doxygen - cd .. - -# -# End of file -# diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..79e8906 --- /dev/null +++ b/Readme.md @@ -0,0 +1,28 @@ + +# What is this repository "doing" ? + +It is also doing what the original repo has done. Namely "Provide error checked version of various functions from std C library." But actually delivering much more. + +Please see [the post associated](https://dbj.org/what-is-your-error-handling-policy/) with this repository. + +--- + +Created 2020 August by dbj@dbj.org (Dusan B. Jovanovic) + +(c) 2020 by dbj@dbj.org + +Distributed under the 'LICENSE_DBJ' https://dbj.org/license_dbj/ + +--- +## Original readme + +Provide error checked version of various functions from std C library. + +Created on 3 July 2011, by Martin Moene + +Copyright 2011 Universiteit Leiden + +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +For more information, see the documentation in ./doc. Generate with 'make doc'. diff --git a/Readme.txt b/Readme.txt deleted file mode 100644 index d65aff2..0000000 --- a/Readme.txt +++ /dev/null @@ -1,10 +0,0 @@ -Provide error checked version of various functions from std C library. - -Created on 3 July 2011, by Martin Moene - -Copyright 2011 Universiteit Leiden - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -For more information, see the documentation in ./doc. Generate with 'make doc'. diff --git a/crt_proxy_app/crt_proxy_app.cpp b/crt_proxy_app/crt_proxy_app.cpp new file mode 100644 index 0000000..80819c0 --- /dev/null +++ b/crt_proxy_app/crt_proxy_app.cpp @@ -0,0 +1,50 @@ +/* (c) 2019-2020 by dbj.org -- LICENSE DBJ -- https://dbj.org/license_dbj/ */ + +#include "crt_proxy_app.h" + +#define SX_FMT(fmt_, x_) log_info("%s : " fmt_, #x_, x_ ) + +static inline void test_string_h_proxy() +{ + namespace cpl = crt_proxy_lib; + + const char* input_ = "ABRA\v\n\f\r\t CA DABRA"; + + metatest( cpl::strlen(input_) ); + + metatest( cpl::strlen("ABRA\v\n\f\r\t CA DABRA") ); + + metatest( cpl::strlen("") ); + + const char* nullstr{}; + + metatest( cpl::strlen(nullstr) ) ; + + metatest( cpl::strcmp("", "OK") ); + metatest( cpl::strcmp(0, "OK") ); + + metatest( cpl::strcmp("NOT", "OK") ); + metatest( cpl::strcmp("OK", "OK") ); + +} + +struct dbj_simplelog_finalizer final { + ~dbj_simplelog_finalizer() { + dbj_log_finalize(); + } +}; + +static dbj_simplelog_finalizer dsf_ ; + +int main( const int argc, char * argv[] ) +{ + if (EXIT_SUCCESS != dbj_simple_log_startup(argv[0])) + return EXIT_FAILURE; + + test_string_h_proxy() ; + + printf("\n\n"); + + return EXIT_SUCCESS ; +} + diff --git a/crt_proxy_app/crt_proxy_app.h b/crt_proxy_app/crt_proxy_app.h new file mode 100644 index 0000000..4bb173d --- /dev/null +++ b/crt_proxy_app/crt_proxy_app.h @@ -0,0 +1,128 @@ +#pragma once + +// #define _CRT_SECURE_NO_WARNINGS 1 + +#include "../crt_proxy_lib/crt_proxy_lib.h" + +//#ifdef _DEBUG +//#define DBJ_LOG_TESTING +//#endif + +/* we want console while in debug builds */ +//#ifdef _DEBUG +//#define DBJ_LOG_DEFAULT_SETUP DBJ_LOG_DEFAULT_WITH_CONSOLE +//#endif + +#include "dbj--simplelog/dbj_simple_log.h" + +#pragma region dbj pico testing + +//#include +//#include +#include +//#include +//#include +//#include +//#include + +// Show eXpression +// innocent loking but saves a lot of typing and rezults saving +#undef SX +#define SX(x_) do { std::cout << "\n" #x_ " : " << (x_); } while(0) + + +namespace dbj::picotest { + + // aim is to produce comma delimited output aka CSV + constexpr auto delimiter_char = ','; + +#ifndef VT100_ESC + +#define VT100_ESC "\x1b[" +#define VT100_RESET VT100_ESC "0m" +#define VT100_LIGHT_GRAY VT100_ESC "90m" +#define VT100_LIGHT_BLUE VT100_ESC "94m" +#define VT100_LIGHT_CYAN VT100_ESC "36m" +#define VT100_LIGHT_YELLOW VT100_ESC "33m" +#define VT100_LIGHT_GREEN VT100_ESC "32m" +#define VT100_LIGHT_RED VT100_ESC "31m" +#define VT100_LIGHT_MAGENTA VT100_ESC "35m" + +#endif // VT100_ESC + + // ERRR funy synbol name is because of 'ERROR' name clash with god knows what ... + enum class levels { TRACE, DEBUG, INFO, WARN, ERRR, FATAL } ; + + + static const char* level_colors[] = { + /* TRACE */ VT100_LIGHT_BLUE, + /* DEBUG */ VT100_LIGHT_CYAN, + /* INFO */ VT100_LIGHT_GREEN, + /* WARN */ VT100_LIGHT_YELLOW, + /* ERRR */ VT100_LIGHT_RED, + /* FATAL */ VT100_LIGHT_MAGENTA + }; + + + using std::cout; + + namespace { + inline auto initialize_once = []() { cout << std::boolalpha; return true; } (); + } + + // return false on empty + inline auto show_option = [](const char* prompt_, auto opt_) ->bool + { + assert(prompt_); + cout << delimiter_char << prompt_ << " "; + if (opt_.has_value()) { + cout << opt_.value(); + return true; + } + cout << "empty"; + return false; + }; + + inline auto show_status = [](const char* prompt_, const char* stat_) ->bool + { + cout << delimiter_char << prompt_ << " "; + if (stat_) { + cout << stat_; + return true; + } + cout << "empty"; + return false; + }; + + // not generic but for crt proxy lib tests where we know + // status is always const char * + inline auto show_metastate = [](const char* prompt_, auto val_, const char* stat_) { + + cout << "\n" << (prompt_ ? prompt_ : ""); + + bool value_state = val_.has_value(); + bool status_state = stat_ != nullptr; + + cout << delimiter_char << " " ; // "\nmetastate: "; + if (value_state && status_state) { cout << VT100_LIGHT_BLUE << "info"; } + if (value_state && !status_state) { cout << VT100_LIGHT_GREEN << "ok"; } + if (!value_state && status_state) { cout << VT100_LIGHT_RED << "error"; } + if (!value_state && !status_state) { cout << VT100_LIGHT_YELLOW << "empty"; } + cout << VT100_RESET ; + show_option(" ", val_); + show_status(" ", stat_); +// cout << "\n"; + }; + + // for this to work we must send + // crt_proxy_lib::valstat instances +#undef metatest +#define metatest( CALL_ ) do { \ + auto [val_,stat_] = CALL_ ;\ + dbj::picotest::show_metastate(#CALL_, val_, stat_) ; \ +} while(0) + +} // dbj +#pragma endregion dbj pico testing + + diff --git a/crt_proxy_app/crt_proxy_app.sln b/crt_proxy_app/crt_proxy_app.sln new file mode 100644 index 0000000..2773892 --- /dev/null +++ b/crt_proxy_app/crt_proxy_app.sln @@ -0,0 +1,33 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30406.217 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crt_proxy_app", "crt_proxy_app.vcxproj", "{E19B86D2-AEFA-40B1-85DF-B64DB914B661}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3DDF4E8A-F074-4781-AB54-731412B7CFA7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E19B86D2-AEFA-40B1-85DF-B64DB914B661}.Debug|x64.ActiveCfg = Debug|x64 + {E19B86D2-AEFA-40B1-85DF-B64DB914B661}.Debug|x64.Build.0 = Debug|x64 + {E19B86D2-AEFA-40B1-85DF-B64DB914B661}.Debug|x86.ActiveCfg = Debug|Win32 + {E19B86D2-AEFA-40B1-85DF-B64DB914B661}.Debug|x86.Build.0 = Debug|Win32 + {E19B86D2-AEFA-40B1-85DF-B64DB914B661}.Release|x64.ActiveCfg = Release|x64 + {E19B86D2-AEFA-40B1-85DF-B64DB914B661}.Release|x64.Build.0 = Release|x64 + {E19B86D2-AEFA-40B1-85DF-B64DB914B661}.Release|x86.ActiveCfg = Release|Win32 + {E19B86D2-AEFA-40B1-85DF-B64DB914B661}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0B144378-7308-46A3-AA8D-27626F12618F} + EndGlobalSection +EndGlobal diff --git a/crt_proxy_app/crt_proxy_app.vcxproj b/crt_proxy_app/crt_proxy_app.vcxproj new file mode 100644 index 0000000..44dc592 --- /dev/null +++ b/crt_proxy_app/crt_proxy_app.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {e19b86d2-aefa-40b1-85df-b64db914b661} + crtproxyapp + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + stdcpp17 + /kernel %(AdditionalOptions) + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + stdcpp17 + /kernel %(AdditionalOptions) + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + stdcpp17 + /kernel %(AdditionalOptions) + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + stdcpp17 + /kernel %(AdditionalOptions) + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/crt_proxy_app/crt_proxy_app.vcxproj.filters b/crt_proxy_app/crt_proxy_app.vcxproj.filters new file mode 100644 index 0000000..c87071d --- /dev/null +++ b/crt_proxy_app/crt_proxy_app.vcxproj.filters @@ -0,0 +1,55 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {98bfc55c-cd9d-43bf-907f-e03641a2d077} + + + + + crt_proxy_lib + + + Source Files + + + Source Files + + + + + Header Files + + + crt_proxy_lib + + + crt_proxy_lib + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + crt_proxy_lib + + + \ No newline at end of file diff --git a/crt_proxy_app/dbj--simplelog b/crt_proxy_app/dbj--simplelog new file mode 160000 index 0000000..37d903e --- /dev/null +++ b/crt_proxy_app/dbj--simplelog @@ -0,0 +1 @@ +Subproject commit 37d903e9451857d367899a94da870ace851e6b1c diff --git a/crt_proxy_lib/crt_proxy_lib.cpp b/crt_proxy_lib/crt_proxy_lib.cpp new file mode 100644 index 0000000..eab536c --- /dev/null +++ b/crt_proxy_lib/crt_proxy_lib.cpp @@ -0,0 +1,173 @@ +/* (c) 2019-2020 by dbj.org -- LICENSE DBJ -- https://dbj.org/license_dbj/ */ + +#include "crt_proxy_lib.h" + +#ifdef __STDC_ALLOC_LIB__ +#define __STDC_WANT_LIB_EXT2__ 1 +#else +#define _POSIX_C_SOURCE 200809L +#endif + +#include +#include +#include +#include +#include +#include +#include +/* + crt on winows +------------------------------------------------------------------------------ +Each and every crt function on windows is implemented by calling WIN32 +Using crt is just a shortcut to WIN32 API. + +win console is win32 app with std streams created and attached +C/C++ real life apps are not console apps. and very likely are not GUI apps +they are just server side apps. invisible. + +Policy for apps and components not having a console +------------------------------------------------------------------------------ +windows app (service or whatever) initially has no associated streams +simple and good policy is to redirect the stderr (on startup) +to the "stderr log" file + + app_full_path + "stderr.log" + +Each data center or just simply server side app will have some logging used. +This is usually not a log file. There might be runtime situtations when it is not +possible to create this file. Do not exit or crash in such a event. + + *use functions not macros* + +Global Macro Functional Equivalents +------------------------------------------------------------------------------ +_doserrno _get_doserrno, _set_doserrno +errno _get_errno, _set_errno +_sys_errlist, _sys_nerr strerror_s, _strerror_s, _wcserror_s, __wcserror_s + +*/ + +#undef DBJ_PERROR +#ifdef _DEBUG +#define DBJ_PERROR (perror(__FILE__ " # " _CRT_STRINGIZE(__LINE__))) +#else +#define DBJ_PERROR +#endif // _DEBUG + +#undef DBJ_FERROR +#ifdef _DEBUG +#define DBJ_FERROR( FP_) \ +do { \ +if (ferror(FP_) != 0) {\ + DBJ_PERROR ;\ + clearerr_s(FP_);\ +} \ +} while(0) +#else +#define DBJ_FERROR( FP_ ) +#endif // _DEBUG + +namespace crt_proxy_lib +{ +valstat strlen ( const char * & input_ ) noexcept +{ + CRT_PROXY_LIB_PADLOCK; + + if (nullptr == input_) + // ERROR metastate + // same message is loged and returned + return { {}, CRT_PROXY_LIB_LOG_ERROR(" null argument") }; +/* +MS DOCS are saying: + +Always clear errno by calling _set_errno(0) immediately before a call that may set it, +and check it immediately after the call. + +Because we use valstat to pass the metastate we can allways return INFO metastate +with the errno obtained immediately after the call + + _set_errno(0); + // INFO metastate + return { ::strlen(input_), errno }; + +But that puts the burden on the callers. And in reality most of the CRT funtions do not set +errno on proper arguments given, which we check here anyway. +*/ + _set_errno(0); + // OK metastate + return { ::strlen(input_), {} }; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// strcmp proxy begins here +// returned valstat is defined here, not before +valstat< int > +strcmp(const char* lhs_, const char* rhs_) +{ + CRT_PROXY_LIB_PADLOCK; + + if (!lhs_ || !rhs_) + // ERROR metastate return + // value is empty, status is not + return { {}, CRT_PROXY_LIB_LOG_ERROR("null pointer argument received") }; + + if (is_empty(lhs_) || is_empty(rhs_)) + // ERROR metastate return + return { {}, CRT_PROXY_LIB_LOG_ERROR("empty argument received") }; + + // OK metastate return + // value is not empty, status is + return { ::strcmp(lhs_, rhs_) , {} }; +} +////////////////////////////////////////////////////////////////////////////////////////// +valstat< void* > memccpy(void* CRT_PROXY_LIB_RESTRICT, const void* CRT_PROXY_LIB_RESTRICT, int, size_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +valstat< void* > memchr(const void*, int, size_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< int > memcmp(const void*, const void*, size_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< void* > memcpy(void* CRT_PROXY_LIB_RESTRICT, const void* CRT_PROXY_LIB_RESTRICT, size_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< void* > memmove(void*, const void*, size_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< void* > memset(void*, int, size_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +valstat< char* > stpcpy(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< char* > stpncpy(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT, size_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +valstat< char* > strcat(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< char* > strchr(const char*, int){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< int > strcoll(const char*, const char*){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +valstat< int > strcoll_l(const char*, const char*, _locale_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +valstat< char* > strcpy(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< size_t > strcspn(const char*, const char*){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +valstat< char* > strdup(const char*){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +valstat< char* > strerror(int){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +valstat< char* > strerror_l(int, _locale_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< int > strerror_r(int, char*, size_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +// see above -- valstat< size_t > strlen(const char*){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< char* > strncat(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT, size_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< int > strncmp(const char*, const char*, size_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< char* > strncpy(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT, size_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +valstat< char* > strndup(const char*, size_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< size_t > strnlen(const char*, size_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +valstat< char* > strpbrk(const char*, const char*){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< char* > strrchr(const char*, int){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +valstat< char* > strsignal(int){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +valstat< size_t > strspn(const char*, const char*){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< char* > strstr(const char*, const char*){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } +valstat< char* > strtok(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +valstat< char* > strtok_r(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT, char** CRT_PROXY_LIB_RESTRICT){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +valstat< size_t > strxfrm(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT, size_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +valstat< size_t > strxfrm_l(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT, size_t, _locale_t){ CRT_PROXY_LIB_PADLOCK ; return { {} , CRT_PROXY_LIB_LOG_ERROR("not yet implemented") }; } + +} // namespace crt_proxy_lib \ No newline at end of file diff --git a/crt_proxy_lib/crt_proxy_lib.h b/crt_proxy_lib/crt_proxy_lib.h new file mode 100644 index 0000000..16f40da --- /dev/null +++ b/crt_proxy_lib/crt_proxy_lib.h @@ -0,0 +1,304 @@ +#ifndef CRT_PROXY_LIB_INC_ +#define CRT_PROXY_LIB_INC_ + +/* (c) 2019-2020 by dbj.org -- LICENSE DBJ -- https://dbj.org/license_dbj/ */ + +#ifndef _MSC_VER +#error Sorry ... Windows only. +#endif + +#define CRT_PROXY_LIB_VERSION "0.7.0" + +#ifndef CRT_PROXY_LIB_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define CRT_PROXY_LIB_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define CRT_PROXY_LIB_CPLUSPLUS __cplusplus +# endif +#endif + +#define CRT_PROXY_LIB_CPP98_OR_GREATER ( CRT_PROXY_LIB_CPLUSPLUS >= 199711L ) +#define CRT_PROXY_LIB_CPP11_OR_GREATER ( CRT_PROXY_LIB_CPLUSPLUS >= 201103L ) +#define CRT_PROXY_LIB_CPP14_OR_GREATER ( CRT_PROXY_LIB_CPLUSPLUS >= 201402L ) +#define CRT_PROXY_LIB_CPP17_OR_GREATER ( CRT_PROXY_LIB_CPLUSPLUS >= 201703L ) +#define CRT_PROXY_LIB_CPP20_OR_GREATER ( CRT_PROXY_LIB_CPLUSPLUS >= 202000L ) + +#if ! CRT_PROXY_LIB_CPP17_OR_GREATER +#error crt proxy lib requires C++17 or better +#endif + +#undef CRT_PROXY_LIB_NDEBUG +#ifndef _DEBUG +#define CRT_PROXY_LIB_NDEBUG +#endif // !_DEBUG + +////////////////////////////////////////////////////////////////////////////////////////////////// + +// default lock/unlock is no lock / no unlock +// user defined padlock type releases semaphore/mutex/critical section in destructor +// grabs in constructor +// crt_proxy_lib_lock.h, must define CRT_PROXY_LIB_PADLOCK + +#if __has_include("crt_proxy_lib_lock.h") + #include "crt_proxy_lib_lock.h" +#ifndef CRT_PROXY_LIB_PADLOCK +#error CRT_PROXY_LIB_PADLOCK is not defined? +#endif // ! CRT_PROXY_LIB_LOCK +#else +// defualt is no locking + #ifndef CRT_PROXY_LIB_PADLOCK + #define CRT_PROXY_LIB_PADLOCK + #endif // ! CRT_PROXY_LIB_LOCK +#endif // + +/* +Users of crt proxy lib need to deliver header named crt_proxy_lib_log.h with actual logging implementation +Macros to be defined are: + + CRT_PROXY_LIB_LOG_TRACE(...) + CRT_PROXY_LIB_LOG_DEBUG(...) + CRT_PROXY_LIB_LOG_INFO(...) + CRT_PROXY_LIB_LOG_WARN(...) + CRT_PROXY_LIB_LOG_ERROR(...) + CRT_PROXY_LIB_LOG_FATAL(...) + + Syntax is same as for the printf. + +if this header is not defined crt_proxy_lib_log_default.h is used which +defines macros that print to stderr. +*/ +#if __has_include("crt_proxy_lib_log.h") +#include "crt_proxy_lib_log.h" +#else +#include "crt_proxy_lib_log_default.h" +#endif // + + +////////////////////////////////////////////////////////////////////////////////////////////////// + +/* until std::valstat we use dbj::valstat*/ +// valstat is not (yet) in the std namespace +namespace dbj { + template + struct valstat final { + using type = valstat ; + using value_type = T_; + using status_type = S_; + + value_type value ; + status_type status ; + }; // valstat +} // dbj + +// CRT_PROXY_LIB bare requires types handled to be +// defualt constructible and copyable +// in the context of CRT types that should work +// as they are all fundamental types +// probably the best requirement would be to demand +// T to yield true from std::is_standard_layout +#include "optional_bare.h" + +namespace crt_proxy_lib +{ + // CRT uses only fundamental types , besides pointers and few trivial layout structs + // T is any fundamental type used. nonstd bare CRT_PROXY_LIB permitting. + template + using valstat = dbj::valstat< + // value type + nonstd::optional , + // status message + const char * + > ; + +////////////////////////////////////////////////////////////////////////////////////////////////// +// +// crt proxy functions begin here +// +////////////////////////////////////////////////////////////////////////////////////////////////// +#ifndef __cplusplus + #define CRT_PROXY_LIB_RESTRICT restrict +#else + #define CRT_PROXY_LIB_RESTRICT __restrict +#endif // __cplusplus + +// NOTE: we do use CRT names in this namespace and that compiles +// These names can not be used without namespace prefix +// One can and will do something like +// namespace cpl = crt_proxy_lib; + +// this overload uses crt strlen and is thus hidden inside the cpp +// instead of crashing the app we return ERROR metastate +// on null argument used +valstat strlen ( const char * & ) noexcept; + +// unlike CRT we can use overloads here +// notice the argument type required so overloads bellow are captured +template +constexpr inline +// we always return a valstat for the uniformity of calling algorithms +// in this case we do not need our valstat alias +// we do not use nonstd optional here +// notice how we treat valstat as literal here +valstat +strlen ( const char (*str)[N] ) noexcept +{ + return { N, {} }; // OK metastate +} + +template +constexpr inline +valstat +strlen ( const char (&str)[N] ) noexcept +{ + return { N, {} }; // OK metastate +} + +////////////////////////////////////////////////////////////////////////////////////////// +/// neither CRT or std lib have the paradigm of "empty" properly grasped ... yet +/// here we will provide is_empty overloads that operate on values +/// not on types like std::empty() does + +/// empty string +constexpr bool is_empty(const char* const s_) noexcept { + return (s_ && (s_[0] == '\0')); +} + +// empty char array +template +constexpr bool is_empty(const char(&s_) [N]) noexcept { + return (s_[0] == '\0') ; +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +// proxys for +// +valstat< int > strcmp(const char* lhs_, const char* rhs_); +valstat< void* > memccpy(void* CRT_PROXY_LIB_RESTRICT, const void* CRT_PROXY_LIB_RESTRICT, int, size_t); + +valstat< void* > memchr(const void*, int, size_t); +valstat< int > memcmp(const void*, const void*, size_t); +valstat< void* > memcpy(void* CRT_PROXY_LIB_RESTRICT, const void* CRT_PROXY_LIB_RESTRICT, size_t); +valstat< void* > memmove(void*, const void*, size_t); +valstat< void* > memset(void*, int, size_t); + +valstat< char* > stpcpy(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT); +valstat< char* > stpncpy(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT, size_t); + +valstat< char* > strcat(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT); +valstat< char* > strchr(const char*, int); +valstat< int > strcmp(const char*, const char*); +valstat< int > strcoll(const char*, const char*); + +valstat< int > strcoll_l(const char*, const char*, _locale_t); + +valstat< char* > strcpy(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT); +valstat< size_t > strcspn(const char*, const char*); + +valstat< char* > strdup(const char*); + +valstat< char* > strerror(int); + +valstat< char* > strerror_l(int, _locale_t); +valstat< int > strerror_r(int, char*, size_t); + +// valstat< size_t > strlen(const char*); +valstat< char* > strncat(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT, size_t); +valstat< int > strncmp(const char*, const char*, size_t); +valstat< char* > strncpy(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT, size_t); + +valstat< char* > strndup(const char*, size_t); +valstat< size_t > strnlen(const char*, size_t); + +valstat< char* > strpbrk(const char*, const char*); +valstat< char* > strrchr(const char*, int); + +valstat< char* > strsignal(int); + +valstat< size_t > strspn(const char*, const char*); +valstat< char* > strstr(const char*, const char*); +valstat< char* > strtok(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT); + +valstat< char* > strtok_r(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT, char** CRT_PROXY_LIB_RESTRICT); + +valstat< size_t > strxfrm(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT, size_t); + +valstat< size_t > strxfrm_l(char* CRT_PROXY_LIB_RESTRICT, const char* CRT_PROXY_LIB_RESTRICT, size_t, _locale_t); + +////////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace crt_proxy_lib + +/* + +in this release we shall implement string.h functions + +string.h synopsis +https://pubs.opengroup.org/onlinepubs/9699919799/ + + +The header shall define NULL and size_t as described in . + + The header shall define the locale_t type as described in . + +The following shall be declared as functions and may also be defined as macros. +Function prototypes shall be provided for use with ISO C standard compilers. + + +void *memccpy(void *restrict, const void *restrict, int, size_t); + +void *memchr(const void *, int, size_t); +int memcmp(const void *, const void *, size_t); +void *memcpy(void *restrict, const void *restrict, size_t); +void *memmove(void *, const void *, size_t); +void *memset(void *, int, size_t); + +char *stpcpy(char *restrict, const char *restrict); +char *stpncpy(char *restrict, const char *restrict, size_t); + +char *strcat(char *restrict, const char *restrict); +char *strchr(const char *, int); +int strcmp(const char *, const char *); +int strcoll(const char *, const char *); + +int strcoll_l(const char *, const char *, locale_t); + +char *strcpy(char *restrict, const char *restrict); +size_t strcspn(const char *, const char *); + +char *strdup(const char *); + +char *strerror(int); + +char *strerror_l(int, locale_t); +int strerror_r(int, char *, size_t); + +size_t strlen(const char *); +char *strncat(char *restrict, const char *restrict, size_t); +int strncmp(const char *, const char *, size_t); +char *strncpy(char *restrict, const char *restrict, size_t); + +char *strndup(const char *, size_t); +size_t strnlen(const char *, size_t); + +char *strpbrk(const char *, const char *); +char *strrchr(const char *, int); + +char *strsignal(int); + +size_t strspn(const char *, const char *); +char *strstr(const char *, const char *); +char *strtok(char *restrict, const char *restrict); + +char *strtok_r(char *restrict, const char *restrict, char **restrict); + +size_t strxfrm(char *restrict, const char *restrict, size_t); + +size_t strxfrm_l(char *restrict, const char *restrict, + size_t, locale_t); + +*/ + +#endif // CRT_PROXY_LIB_INC_ + + + diff --git a/crt_proxy_lib/crt_proxy_lib_lock.h b/crt_proxy_lib/crt_proxy_lib_lock.h new file mode 100644 index 0000000..43dc296 --- /dev/null +++ b/crt_proxy_lib/crt_proxy_lib_lock.h @@ -0,0 +1,34 @@ +#ifndef crt_proxy_lib_lock_h_ +#define crt_proxy_lib_lock_h_ + +/* (c) 2019-2020 by dbj.org -- LICENSE DBJ -- https://dbj.org/license_dbj/ */ + +#define STRICT 1 +#define WIN32_LEAN_AND_MEAN +#include + +// user defined padlock type releases semaphore/mutex/critical section in destructor +// grabs in constructor +// crt_proxy_lib_lock.h, must define CRT_PROXY_LIB_PADLOCK + +#undef CRT_PROXY_LIB_PADLOCK +#define CRT_PROXY_LIB_PADLOCK crt_proxy_lib_padlock crt_proxy_lib_padlock_instance__ + +struct crt_proxy_lib_padlock final +{ + // this is one per instance of this type + CRITICAL_SECTION CS_ ; + + explicit crt_proxy_lib_padlock() + { + InitializeCriticalSection(&CS_); + EnterCriticalSection(&CS_); + } + ~crt_proxy_lib_padlock() + { + LeaveCriticalSection(&CS_); + DeleteCriticalSection(&CS_); + } +} ; + +#endif // crt_proxy_lib_lock_h_ \ No newline at end of file diff --git a/crt_proxy_lib/crt_proxy_lib_log.h b/crt_proxy_lib/crt_proxy_lib_log.h new file mode 100644 index 0000000..078f4ee --- /dev/null +++ b/crt_proxy_lib/crt_proxy_lib_log.h @@ -0,0 +1,106 @@ +#ifndef CRT_PROXY_LIB_LOG_INC_ +#define CRT_PROXY_LIB_LOG_INC_ + +/* (c) 2019-2020 by dbj.org -- LICENSE DBJ -- https://dbj.org/license_dbj/ + +Users of crt proxy lib need to deliver header named crt_proxy_lib_log.h with actual logging implementation +Macros to be defined are: + + CRT_PROXY_LIB_LOG_TRACE(...) + CRT_PROXY_LIB_LOG_DEBUG(...) + CRT_PROXY_LIB_LOG_INFO(...) + CRT_PROXY_LIB_LOG_WARN(...) + CRT_PROXY_LIB_LOG_ERROR(...) + CRT_PROXY_LIB_LOG_FATAL(...) + + Syntax is same as for the printf. + +if this header is not defined crt_proxy_lib_log_default.h is used which prints to stderr. + +--------------------------------------------------------------------------------------------------- + +In WIN32 parlance module is a component. + +Logging is important + +Win console is win32 app with std streams created and attached +C/C++ real life apps are not console apps. And (very likely) are not GUI apps +they are just server side apps. Invisible. + +Each data center or just simply server side component will have to have some logging used. +Without logging in place admins can not see what is going on with your component. + +Very basic and very default policy is to redirect stderr to a file. + +What about stdout? + +In win32 modules stdout simply leads to nowhere. be carefull and vigilant not to use stdout in standard win modules. +sometimes in very rare (legacy usage) situations one redirects stdout to another file, on startup. + +crt poxy lib loging + +The requirement is: log the string message and return what have you logged. + +WG21 C++20 wisdom + +Who care about UTF-8? The whole internet cares. Logging mesages are not unicode. why not? because C++20 brings char8_t into play. +and that "boson" is implemented as char, +that is utf8 string is coded into char *, not wchar_t * ... that means + +// C++20 ... or before, it depends +// Windows is wchar_t default executable char set +char * hiragana = u8"平仮名" ; + +Your system and modules will send and receive JSON messages coded in UTF-8. +And Linux/Mac code simply does: + +// Linux/Unix OS +// UTF-8 is the executable char set by default +char * hiragana = "平仮名" ; + +So we better stick to char * + +*/ + +/* +This is a header delivered by users who use dbj--simplelog +https://github.com/dbj-systems/dbj--simplelog +*/ + +// all eventually goes in here +extern "C" { +#ifndef DBJ_LOG_LEVELS_ENUM_DEFINED +#define DBJ_LOG_LEVELS_ENUM_DEFINED + typedef enum DBJ_LOG_LEVELS_ENUM { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL } DBJ_LOG_LEVELS_ENUM; +#endif // DBJ_LOG_LEVELS_ENUM_DEFINED + + void log_log(int /*level*/, const char* /*file*/, int /*line*/, const char* /*fmt*/, ...); +} + + // log and return +// file and line are logged but not returned +#undef CRT_PROXY_LIB_LOG_TRACE +#define CRT_PROXY_LIB_LOG_TRACE(...) \ +(log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__), #__VA_ARGS__ ) + +#undef CRT_PROXY_LIB_LOG_DEBUG +#define CRT_PROXY_LIB_LOG_DEBUG(...) \ +(log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__), #__VA_ARGS__ ) + +#undef CRT_PROXY_LIB_LOG_INFO +#define CRT_PROXY_LIB_LOG_INFO(...) \ +(log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__), #__VA_ARGS__ ) + +#undef CRT_PROXY_LIB_LOG_WARN +#define CRT_PROXY_LIB_LOG_WARN(...) \ +(log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__), #__VA_ARGS__ ) + +#undef CRT_PROXY_LIB_LOG_ERROR +#define CRT_PROXY_LIB_LOG_ERROR(...) \ +(log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__), #__VA_ARGS__ ) + +#undef CRT_PROXY_LIB_LOG_FATAL +#define CRT_PROXY_LIB_LOG_FATAL(...) \ +(log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__), #__VA_ARGS__ ) + +#endif // CRT_PROXY_LIB_LOG_INC_ diff --git a/crt_proxy_lib/crt_proxy_lib_log_default.h b/crt_proxy_lib/crt_proxy_lib_log_default.h new file mode 100644 index 0000000..10b6d1a --- /dev/null +++ b/crt_proxy_lib/crt_proxy_lib_log_default.h @@ -0,0 +1,80 @@ +#ifndef CRT_PROXY_LIB_LOG_DEFAULT_INC_ +#define CRT_PROXY_LIB_LOG_DEFAULT_INC_ + +/* (c) 2019-2020 by dbj.org -- LICENSE DBJ -- https://dbj.org/license_dbj/ + +Users of crt proxy lib need to deliver header named crt_proxy_lib_log.h with actual logging implementation +Macros to be defined are: + + CRT_PROXY_LIB_LOG_TRACE(...) + CRT_PROXY_LIB_LOG_DEBUG(...) + CRT_PROXY_LIB_LOG_INFO(...) + CRT_PROXY_LIB_LOG_WARN(...) + CRT_PROXY_LIB_LOG_ERROR(...) + CRT_PROXY_LIB_LOG_FATAL(...) + + Syntax is same as for the printf. + +if this header is not defined crt_proxy_lib_log_default.h is used which prints to stderr. + + +*/ + +#include // +#include // _snprintf_s + +template +inline auto crt_proxy_lib_log_default ( + const char* file, + const long line, + const char * level_tag , + Args ... args +) +{ + // the part without a file and line prefix + char bufy_[1024]{ 0 }; + int rez = _snprintf_s(bufy_, 1024, _TRUNCATE, args ...); + assert(rez > 0); + // + char file_line_prefix[1024]{ 0 }; + rez = _snprintf_s(file_line_prefix, 1024, _TRUNCATE, "%s : %d : %10s", file, line, level_tag); + assert(rez > 0); + + static char rezult_buffer[2048 + 1]{ 0 }; + // append the two and send out + rez = _snprintf_s(rezult_buffer, 2048, _TRUNCATE, "%s : %s ", file_line_prefix, bufy_ ); + assert(rez > 0); + + rez = fprintf(stderr, "\n%s", rezult_buffer); + assert(rez > 0); + + return rezult_buffer; // use immediately +} + + // log and return +// file and line are logged but not returned +#undef CRT_PROXY_LIB_LOG_TRACE +#define CRT_PROXY_LIB_LOG_TRACE(...) \ +crt_proxy_lib_log_default( __FILE__, __LINE__ , "LOG_TRACE" , __VA_ARGS__ ) + +#undef CRT_PROXY_LIB_LOG_DEBUG +#define CRT_PROXY_LIB_LOG_DEBUG(...) \ +crt_proxy_lib_log_default( __FILE__, __LINE__ , "LOG_DEBUG" , __VA_ARGS__ ) + +#undef CRT_PROXY_LIB_LOG_INFO +#define CRT_PROXY_LIB_LOG_INFO(...) \ +crt_proxy_lib_log_default( __FILE__, __LINE__ , "LOG_INFO" , __VA_ARGS__ ) + +#undef CRT_PROXY_LIB_LOG_WARN +#define CRT_PROXY_LIB_LOG_WARN(...) \ +crt_proxy_lib_log_default( __FILE__, __LINE__ , "LOG_WARN" , __VA_ARGS__ ) + +#undef CRT_PROXY_LIB_LOG_ERROR +#define CRT_PROXY_LIB_LOG_ERROR(...) \ +crt_proxy_lib_log_default( __FILE__, __LINE__ , "LOG_ERROR" , __VA_ARGS__ ) + +#undef CRT_PROXY_LIB_LOG_FATAL +#define CRT_PROXY_LIB_LOG_FATAL(...) \ +crt_proxy_lib_log_default( __FILE__, __LINE__ , "LOG_FATAL" , __VA_ARGS__ ) + +#endif // CRT_PROXY_LIB_LOG_DEFAULT_INC_ diff --git a/crt_proxy_lib/optional_bare.h b/crt_proxy_lib/optional_bare.h new file mode 100644 index 0000000..74d2c8e --- /dev/null +++ b/crt_proxy_lib/optional_bare.h @@ -0,0 +1,516 @@ +#ifndef NONSTD_OPTIONAL_BARE_HPP +#define NONSTD_OPTIONAL_BARE_HPP + +// Copyright 2020 by Dusan Jovanovic +// Martin's bare optional stripped down to nanoptional +// no std and no exceptions +// Motivation: narrow usage exclusively for valstat types + +// convince nonstd::optional we are on C++03 +// so it is decoupled from the std lib completely +#define optional_CPLUSPLUS 199711L +// use nonstd optional +#define optional_CONFIG_SELECT_OPTIONAL optional_OPTIONAL_NONSTD +// no exceptions +#define optional_CONFIG_NO_EXCEPTIONS 1 + +// +// Copyright 2017-2019 by Martin Moene +// +// https://github.com/martinmoene/optional-bare +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#define optional_bare_MAJOR 1 +#define optional_bare_MINOR 1 +#define optional_bare_PATCH 0 + +#define optional_bare_VERSION optional_STRINGIFY(optional_bare_MAJOR) "." optional_STRINGIFY(optional_bare_MINOR) "." optional_STRINGIFY(optional_bare_PATCH) + +#define optional_STRINGIFY( x ) optional_STRINGIFY_( x ) +#define optional_STRINGIFY_( x ) #x + +// optional-bare configuration: + +#define optional_OPTIONAL_DEFAULT 0 +#define optional_OPTIONAL_NONSTD 1 +#define optional_OPTIONAL_STD 2 + +#if !defined( optional_CONFIG_SELECT_OPTIONAL ) +# define optional_CONFIG_SELECT_OPTIONAL ( optional_HAVE_STD_OPTIONAL ? optional_OPTIONAL_STD : optional_OPTIONAL_NONSTD ) +#endif + +// Control presence of exception handling (try and auto discover): + +#ifndef optional_CONFIG_NO_EXCEPTIONS +# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) +# define optional_CONFIG_NO_EXCEPTIONS 0 +# else +# define optional_CONFIG_NO_EXCEPTIONS 1 +# endif +#endif + +// C++ language version detection (C++20 is speculative): +// Note: VC14.0/1900 (VS2015) lacks too much from C++14. + +#ifndef optional_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define optional_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define optional_CPLUSPLUS __cplusplus +# endif +#endif + +#define optional_CPP98_OR_GREATER ( optional_CPLUSPLUS >= 199711L ) +#define optional_CPP11_OR_GREATER ( optional_CPLUSPLUS >= 201103L ) +#define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L ) +#define optional_CPP17_OR_GREATER ( optional_CPLUSPLUS >= 201703L ) +#define optional_CPP20_OR_GREATER ( optional_CPLUSPLUS >= 202000L ) + +// C++ language version (represent 98 as 3): + +#define optional_CPLUSPLUS_V ( optional_CPLUSPLUS / 100 - (optional_CPLUSPLUS > 200000 ? 2000 : 1994) ) + +// Use C++17 std::optional if available and requested: + +#if optional_CPP17_OR_GREATER && defined(__has_include ) +# if __has_include( ) +# define optional_HAVE_STD_OPTIONAL 1 +# else +# define optional_HAVE_STD_OPTIONAL 0 +# endif +#else +# define optional_HAVE_STD_OPTIONAL 0 +#endif + +#define optional_USES_STD_OPTIONAL ( (optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_STD) || ((optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_DEFAULT) && optional_HAVE_STD_OPTIONAL) ) + +// +// Using std::optional: +// + +#if optional_USES_STD_OPTIONAL + +#include +#include + +namespace nonstd { + + using std::in_place; + using std::in_place_type; + using std::in_place_index; + using std::in_place_t; + using std::in_place_type_t; + using std::in_place_index_t; + + using std::optional; + using std::bad_optional_access; + using std::hash; + + using std::nullopt; + using std::nullopt_t; + + using std::operator==; + using std::operator!=; + using std::operator<; + using std::operator<=; + using std::operator>; + using std::operator>=; + using std::make_optional; + using std::swap; +} + +#else // optional_USES_STD_OPTIONAL + +#include + +#if ! optional_CONFIG_NO_EXCEPTIONS +# include +#endif + +namespace nonstd { namespace optional_bare { + +// type for nullopt + +struct nullopt_t +{ + struct init{}; + nullopt_t( init ) {} +}; + +// extra parenthesis to prevent the most vexing parse: + +const nullopt_t nullopt(( nullopt_t::init() )); + +// optional access error. + +#if ! optional_CONFIG_NO_EXCEPTIONS + +class bad_optional_access : public std::logic_error +{ +public: + explicit bad_optional_access() + : logic_error( "bad optional access" ) {} +}; + +#endif // optional_CONFIG_NO_EXCEPTIONS + +// Simplistic optional: requires T to be default constructible, copyable. + +template< typename T > +class optional +{ +private: + typedef void (optional::*safe_bool)() const; + +public: + typedef T value_type; + + optional() + : has_value_( false ) + {} + + optional( nullopt_t ) + : has_value_( false ) + {} + + optional( T const & arg ) + : has_value_( true ) + , value_ ( arg ) + {} + + template< class U > + optional( optional const & other ) + : has_value_( other.has_value() ) + , value_ ( other.value() ) + {} + + optional & operator=( nullopt_t ) + { + reset(); + return *this; + } + + template< class U > + optional & operator=( optional const & other ) + { + has_value_ = other.has_value(); + value_ = other.value(); + return *this; + } + + void swap( optional & rhs ) + { + //DBJ removed -- using std::swap; + if ( has_value() == true && rhs.has_value() == true ) { swap( **this, *rhs ); } + else if ( has_value() == false && rhs.has_value() == true ) { initialize( *rhs ); rhs.reset(); } + else if ( has_value() == true && rhs.has_value() == false ) { rhs.initialize( **this ); reset(); } + } + + // observers + + value_type const * operator->() const + { + return assert( has_value() ), + &value_; + } + + value_type * operator->() + { + return assert( has_value() ), + &value_; + } + + value_type const & operator*() const + { + return assert( has_value() ), + value_; + } + + value_type & operator*() + { + return assert( has_value() ), + value_; + } + +#if optional_CPP11_OR_GREATER + explicit operator bool() const + { + return has_value(); + } +#else + operator safe_bool() const + { + return has_value() ? &optional::this_type_does_not_support_comparisons : 0; + } +#endif + + bool has_value() const + { + return has_value_; + } + + value_type const & value() const + { +#if optional_CONFIG_NO_EXCEPTIONS + assert( has_value() ); +#else + if ( ! has_value() ) + throw bad_optional_access(); +#endif + return value_; + } + + value_type & value() + { +#if optional_CONFIG_NO_EXCEPTIONS + assert( has_value() ); +#else + if ( ! has_value() ) + throw bad_optional_access(); +#endif + return value_; + } + + template< class U > + value_type value_or( U const & v ) const + { + return has_value() ? value() : static_cast( v ); + } + + // modifiers + + void reset() + { + has_value_ = false; + } + +private: + void this_type_does_not_support_comparisons() const {} + + template< typename V > + void initialize( V const & value ) + { + assert( ! has_value() ); + value_ = value; + has_value_ = true; + } + +private: + + bool has_value_{ /* DBJ added initializers */}; + value_type value_{}; +}; + +// Relational operators + +template< typename T, typename U > +inline bool operator==( optional const & x, optional const & y ) +{ + return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; +} + +template< typename T, typename U > +inline bool operator!=( optional const & x, optional const & y ) +{ + return !(x == y); +} + +template< typename T, typename U > +inline bool operator<( optional const & x, optional const & y ) +{ + return (!y) ? false : (!x) ? true : *x < *y; +} + +template< typename T, typename U > +inline bool operator>( optional const & x, optional const & y ) +{ + return (y < x); +} + +template< typename T, typename U > +inline bool operator<=( optional const & x, optional const & y ) +{ + return !(y < x); +} + +template< typename T, typename U > +inline bool operator>=( optional const & x, optional const & y ) +{ + return !(x < y); +} + +// Comparison with nullopt + +template< typename T > +inline bool operator==( optional const & x, nullopt_t ) +{ + return (!x); +} + +template< typename T > +inline bool operator==( nullopt_t, optional const & x ) +{ + return (!x); +} + +template< typename T > +inline bool operator!=( optional const & x, nullopt_t ) +{ + return bool(x); +} + +template< typename T > +inline bool operator!=( nullopt_t, optional const & x ) +{ + return bool(x); +} + +template< typename T > +inline bool operator<( optional const &, nullopt_t ) +{ + return false; +} + +template< typename T > +inline bool operator<( nullopt_t, optional const & x ) +{ + return bool(x); +} + +template< typename T > +inline bool operator<=( optional const & x, nullopt_t ) +{ + return (!x); +} + +template< typename T > +inline bool operator<=( nullopt_t, optional const & ) +{ + return true; +} + +template< typename T > +inline bool operator>( optional const & x, nullopt_t ) +{ + return bool(x); +} + +template< typename T > +inline bool operator>( nullopt_t, optional const & ) +{ + return false; +} + +template< typename T > +inline bool operator>=( optional const &, nullopt_t ) +{ + return true; +} + +template< typename T > +inline bool operator>=( nullopt_t, optional const & x ) +{ + return (!x); +} + +// Comparison with T + +template< typename T, typename U > +inline bool operator==( optional const & x, U const & v ) +{ + return bool(x) ? *x == v : false; +} + +template< typename T, typename U > +inline bool operator==( U const & v, optional const & x ) +{ + return bool(x) ? v == *x : false; +} + +template< typename T, typename U > +inline bool operator!=( optional const & x, U const & v ) +{ + return bool(x) ? *x != v : true; +} + +template< typename T, typename U > +inline bool operator!=( U const & v, optional const & x ) +{ + return bool(x) ? v != *x : true; +} + +template< typename T, typename U > +inline bool operator<( optional const & x, U const & v ) +{ + return bool(x) ? *x < v : true; +} + +template< typename T, typename U > +inline bool operator<( U const & v, optional const & x ) +{ + return bool(x) ? v < *x : false; +} + +template< typename T, typename U > +inline bool operator<=( optional const & x, U const & v ) +{ + return bool(x) ? *x <= v : true; +} + +template< typename T, typename U > +inline bool operator<=( U const & v, optional const & x ) +{ + return bool(x) ? v <= *x : false; +} + +template< typename T, typename U > +inline bool operator>( optional const & x, U const & v ) +{ + return bool(x) ? *x > v : false; +} + +template< typename T, typename U > +inline bool operator>( U const & v, optional const & x ) +{ + return bool(x) ? v > *x : true; +} + +template< typename T, typename U > +inline bool operator>=( optional const & x, U const & v ) +{ + return bool(x) ? *x >= v : false; +} + +template< typename T, typename U > +inline bool operator>=( U const & v, optional const & x ) +{ + return bool(x) ? v >= *x : true; +} + +// Specialized algorithms + +template< typename T > +void swap( optional & x, optional & y ) +{ + x.swap( y ); +} + +// Convenience function to create an optional. + +template< typename T > +inline optional make_optional( T const & v ) +{ + return optional( v ); +} + +} // namespace optional-bare + +using namespace optional_bare; + +} // namespace nonstd + +#endif // optional_USES_STD_OPTIONAL + +#endif // NONSTD_OPTIONAL_BARE_HPP diff --git a/crt_proxy_lib/readme.md b/crt_proxy_lib/readme.md new file mode 100644 index 0000000..96cb604 --- /dev/null +++ b/crt_proxy_lib/readme.md @@ -0,0 +1,294 @@ + +

crt proxy lib

+ +> Copyright © 2019-2020, Dusan B. Jovanovic (dbj@dbj.org) +> +> LICENSE_DBJ -- https://dbj.org/license_dbj/ + + +- [1. motivation](#1-motivation) + - [1.1. The Windows, CL and Kernel Mode](#11-the-windows-cl-and-kernel-mode) +- [2. design](#2-design) + - [2.1. returns handling is new error handling policy](#21-returns-handling-is-new-error-handling-policy) + - [2.2. Built For Standard C++ users](#22-built-for-standard-c-users) + - [2.2.1. True noexcept issue](#221-true-noexcept-issue) + - [2.3. Repeat: Logging is important](#23-repeat-logging-is-important) +- [3. Implementation details](#3-implementation-details) + - [3.1. Locking](#31-locking) + - [3.2. Code structure details](#32-code-structure-details) + - [3.3. Our benchmarking attitude](#33-our-benchmarking-attitude) + - [3.4. Dependencies](#34-dependencies) + +## 1. motivation + +Circa 2020, C++ is very rarely, if ever, used for application programming. In the Cloud reality, C++ is used for systems programming. + +Who this library is for? Teams wishing to code in standard C++ but who are under limitations, grouped as follows. + +1. Limitations of run-time requirements + - specifically **not allowed to use** any of the following + - std lib + - throw/try/catch + - "special" return values + - arguments for returns + - special globals + - magical constants + +Very often heap allocation is added to the list above. These limitations often leave no choice but using C Run Time aka CRT. But, CRT has issues too. + +2. Limitation imposed by crt legacy issues. + - Non exhaustive list + 1. errno based error handling aka using globals + - pure function can not use globals + 2. crashing on wrong input + - example: null arguments + 3. not crashing but returning wrong results + - example: empty strings as arguments + +Thus all of the above are limiting the design decisions and directly shaping the implementation. All raising the level of design complexity and lowering the level of feasibility of the whole solutions. + +### 1.1. The Windows, CL and Kernel Mode + +This library is for the people who use Windows **and** standard C++ **and** are building using CL /kernel switch. +Here is the key table from [further reading](https://docs.microsoft.com/en-us/cpp/build/reference/kernel-create-kernel-mode-binary?view=vs-2019) on-line: + +| Behavior Type | /kernel Behavior | +|---------------|------------------| +|C++ Exception Handling |Disabled. All instances of the throw and try keywords emit a compiler error (except for the exception specification throw()). No /EH options are compatible with /kernel, except for /EH-. +|RTTI | Disabled. All instances of the dynamic_cast and typeid keywords emit a compiler error, unless dynamic_cast is used statically. +| new and delete | You must explicitly define the new() or delete() operator; neither the compiler nor the runtime will supply a default definition. + +NOTE: Console app, part of this repository, is indeed built with the `/kernel` switch in use. + +## 2. design + +### 2.1. returns handling is new error handling policy + +- based on the metastate paradigm -- [P2192](https://gitlab.com/dbjdbj/valstat/-/blob/07ce13ab26f662c7301a463fee55dc21cbd7a585/P2192R2.md) +- no runtime exit, abort or crash +- null input, empty input or logically wrong input will provoke different responses + - API consuming functions will have to capture that +- no special return types + - no special return structures beside valstat definitions + +This one template is all that is needed to adopt the metastate paradigm. +```cpp +// valstat is not (yet) in the std namespace +namespace your_company_name_here { + template + [[nodiscard]] + struct valstat final { + using type = valstat ; + using value_type = T_; + using status_type = S_; + + value_type value ; + status_type status ; + }; // valstat +} +``` +- reminder + - template given parameters is a definition + - template definition is a type + - template alias is still a template +- in this library status returned is always `const char *` message + - decoupling users from crt error handling + - when it arrives to the caller message is already logged +- **future extension**: status returned as handle to the message logged + - that handle will be GUID inside a `const char *` string + - that will allow programmatic querying of the log + - that will raise the complexity, thus it might be not implemented. It depends on the future requirements of large adopters. + +### 2.2. Built For Standard C++ users + +- standard C++ (17 or better) core language + - no classes + - no inheritance + - overloads are ok and are in use inside. Example: +```cpp +template +constexpr inline size_t strlen ( const char (*str)[N] ) noexcept +{ + return N; +} + +template +constexpr inline size_t strlen ( const char (&str)[N] ) noexcept +{ + return N; +} +``` +- compile time assertions are used + - `static_assert()` + +#### 2.2.1. True noexcept issue + +Issue with C++ and `noexcept` and LLVM and GCC is they implement some key CRT functions as throwing exceptions, like for example malloc. + +Known [way around that](https://compiler-explorer.com/z/rco9eh) is to cast to `noexcept` function pointer. + +Teams using CL do not need that. But we know about it and we might use it if necessary. + +### 2.3. Repeat: Logging is important + +Win console is just an win32 app with std streams created and attached. +C/C++ real life apps are not console apps. And (very likely) are not GUI apps +they are server side apps. Invisible. + +Each data center or simply server side component will have to have some logging used. Without logging in place admins can not see what is going on with your component. Neither can you. + +Users of crt proxy lib need to deliver header named `crt_proxy_lib_log.h` with actual logging implementation. Macros to be defined are: +```cpp +// Same syntax as for the printf +CRT_PROXY_LIB_LOG_TRACE(...); +CRT_PROXY_LIB_LOG_DEBUG(...); +CRT_PROXY_LIB_LOG_INFO(...); +CRT_PROXY_LIB_LOG_WARN(...); +CRT_PROXY_LIB_LOG_ERROR(...); +CRT_PROXY_LIB_LOG_FATAL(...); +``` +If this header is not delivered by the users, `crt_proxy_lib_log_default.h` is used which +defines macros that print to stderr. + +```cpp +#if __has_include("crt_proxy_lib_log.h") +// user defied logging +#include "crt_proxy_lib_log.h" +#else +// default logging, to stderr +#include "crt_proxy_lib_log_default.h" +#endif +``` +## 3. Implementation details + +### 3.1. Locking + +This library users may provide resilience in the presence of threads. Either users provide lock/unlock type or there is no locking by default: +```cpp +// default lock/unlock is no lock / no unlock +// user defined padlock type releases semaphore/mutex/critical section in destructor +// grabs in constructor +// crt_proxy_lib_lock.h, must define CRT_PROXY_LIB_PADLOCK + +#if __has_include("crt_proxy_lib_lock.h") + #include "crt_proxy_lib_lock.h" +#ifndef CRT_PROXY_LIB_PADLOCK +#error CRT_PROXY_LIB_PADLOCK is not defined? +#endif // ! CRT_PROXY_LIB_LOCK +#else +// default is no locking + #ifndef CRT_PROXY_LIB_PADLOCK + #define CRT_PROXY_LIB_PADLOCK + #endif // ! CRT_PROXY_LIB_LOCK +#endif // +``` +Therefore for MT resilience, users need to provide `crt_proxy_lib_lock.h`. Each proxy function implementation start in this manner: +```cpp +// standard prologue example +valstat strlen +( const char * & input_ ) +noexcept +{ + CRT_PROXY_LIB_PADLOCK; + + // ... the rest goes here ... +} +``` +### 3.2. Code structure details + +- one header and one cpp file + - just include and use + - no lib or dll + - recommendation: use as git sub-module +- Windows only but not using WIN32 API +- Visual Studio 2019 using both CL and CLANG + - 64 bit builds only +- SEMVER + - starting from 0.0.1 + - 1.0.0 is first release +- top level namespace: `crt_proxy_lib` +- macros prefix: `CRT_PROXY_LIB_` +- user provides + - logging + - locking + - if no user provided **defaults** are used + - no locking + - stderr as a log target +- **Which version of C99?** +- it is a "cat and mouse" game one has to play with CL.exe to find out which C99 features are enabled or not + - that might change with each visual studio update. + - even some C11 features are in +- we will not use deprecated crt function, whatever that means. + - we will always try and use so called 'safe' versions +- we will [use the following](https://en.cppreference.com/w/c/experimental/dynamic) without knowing for sure if it has effect or not, while using CL. +```cpp +#ifdef __STDC_ALLOC_LIB__ +#define __STDC_WANT_LIB_EXT2__ 1 +#else +#define _POSIX_C_SOURCE 200809L +#endif +``` + +Of course users of this lib is protected also from the issue of every compile vendor having CRT `extension`, mixed with various levels of [POSIX](https://en.wikipedia.org/wiki/POSIX) conformance. + +An illustrative citation from that link: + +*Windows C Runtime Library and Windows Sockets API implement commonly used POSIX API functions for file, time, environment, and socket access, although the support remains largely incomplete and not fully interoperable with POSIX-compliant implementations...* + +### 3.3. Our benchmarking attitude + +- to benchmark use equivalent of linux time command +- comparing code is artificial benchmarking +- comparing applications delivers true results for: + - performance + - size +- Windows Task Manager (WTM) results are part of benchmarking results + - did you know WTM has the "energy" column? + +### 3.4. Dependencies + +We use Martin Moene's non [standard bare optional](https://github.com/martinmoene/optional-bare). +It allows us to have the optional, minus std lib, minus exceptions. + +The limitations are: the handled value is required to be copyable and default constructible. + +```cpp +// we make sure bare optional is used and +// there are no exceptions thrown from it +// nonstd optional +#define optional_CONFIG_SELECT_OPTIONAL optional_OPTIONAL_NONSTD +// no exceptions +#define optional_CONFIG_NO_EXCEPTIONS 1 + +#include + +namespace crt_proxy_lib +{ + // any type used. nonstd::optional permitting. + template + using valstat = dbj::valstat< + // value type + nonstd::optional , + // status type + const char * + > ; +} +``` +Now we can readily ask the occupancy state; on both value and status. For any value type used. bare optional permitting. +```cpp +// val type is int inside bare optional +// status_msg is const char * +auto [ val, status_msg ] = crt_proxy_lib::atoi( "42" ) ; + +// the occupancy of the val returned +// empty +if ( ! val ) + // not 'empty', type is const char * + if ( status_msg ) + log ( status_msg ) ; +// not empty +if ( val ) + // use the int value returned + log ( "OK return: %d" , *val ) ; +``` +Bare optional limitations for types handled, are irrelevant in the context of this library because CRT arguments and return values are almost always fundamental types or pointers to them. \ No newline at end of file diff --git a/mkg++.bat b/mkg++.bat deleted file mode 100644 index e30b3e2..0000000 --- a/mkg++.bat +++ /dev/null @@ -1 +0,0 @@ -mingw32-make -f Makefile.gcc CC=g++ %* diff --git a/mkgcc.bat b/mkgcc.bat deleted file mode 100644 index bf12b77..0000000 --- a/mkgcc.bat +++ /dev/null @@ -1 +0,0 @@ -mingw32-make -f Makefile.gcc CC=gcc %* diff --git a/mkvc++.bat b/mkvc++.bat deleted file mode 100644 index 7ead6a8..0000000 --- a/mkvc++.bat +++ /dev/null @@ -1 +0,0 @@ -nmake -f Makefile.vc LANOPT=-TP %* diff --git a/mkvc.bat b/mkvc.bat deleted file mode 100644 index 105d8a5..0000000 --- a/mkvc.bat +++ /dev/null @@ -1 +0,0 @@ -nmake -f Makefile.vc LANOPT=-TC %* diff --git a/notinuse/optional.h b/notinuse/optional.h new file mode 100644 index 0000000..e4921d0 --- /dev/null +++ b/notinuse/optional.h @@ -0,0 +1,1715 @@ +// +// Copyright (c) 2014-2018 Martin Moene +// +// https://github.com/martinmoene/optional-lite +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#pragma once + +#ifndef NONSTD_OPTIONAL_LITE_HPP +#define NONSTD_OPTIONAL_LITE_HPP + +#define optional_lite_MAJOR 3 +#define optional_lite_MINOR 2 +#define optional_lite_PATCH 0 + +#define optional_lite_VERSION optional_STRINGIFY(optional_lite_MAJOR) "." optional_STRINGIFY(optional_lite_MINOR) "." optional_STRINGIFY(optional_lite_PATCH) + +#define optional_STRINGIFY( x ) optional_STRINGIFY_( x ) +#define optional_STRINGIFY_( x ) #x + +// optional-lite configuration: + +#define optional_OPTIONAL_DEFAULT 0 +#define optional_OPTIONAL_NONSTD 1 +#define optional_OPTIONAL_STD 2 + +#if !defined( optional_CONFIG_SELECT_OPTIONAL ) +# define optional_CONFIG_SELECT_OPTIONAL ( optional_HAVE_STD_OPTIONAL ? optional_OPTIONAL_STD : optional_OPTIONAL_NONSTD ) +#endif + +// Control presence of exception handling (try and auto discover): + +#ifndef optional_CONFIG_NO_EXCEPTIONS +# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) +# define optional_CONFIG_NO_EXCEPTIONS 0 +# else +# define optional_CONFIG_NO_EXCEPTIONS 1 +# endif +#endif + +// C++ language version detection (C++20 is speculative): +// Note: VC14.0/1900 (VS2015) lacks too much from C++14. + +#ifndef optional_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define optional_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define optional_CPLUSPLUS __cplusplus +# endif +#endif + +#define optional_CPP98_OR_GREATER ( optional_CPLUSPLUS >= 199711L ) +#define optional_CPP11_OR_GREATER ( optional_CPLUSPLUS >= 201103L ) +#define optional_CPP11_OR_GREATER_ ( optional_CPLUSPLUS >= 201103L ) +#define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L ) +#define optional_CPP17_OR_GREATER ( optional_CPLUSPLUS >= 201703L ) +#define optional_CPP20_OR_GREATER ( optional_CPLUSPLUS >= 202000L ) + +// C++ language version (represent 98 as 3): + +#define optional_CPLUSPLUS_V ( optional_CPLUSPLUS / 100 - (optional_CPLUSPLUS > 200000 ? 2000 : 1994) ) + +// Use C++17 std::optional if available and requested: + +#if optional_CPP17_OR_GREATER && defined(__has_include ) +# if __has_include( ) +# define optional_HAVE_STD_OPTIONAL 1 +# else +# define optional_HAVE_STD_OPTIONAL 0 +# endif +#else +# define optional_HAVE_STD_OPTIONAL 0 +#endif + +#define optional_USES_STD_OPTIONAL ( (optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_STD) || ((optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_DEFAULT) && optional_HAVE_STD_OPTIONAL) ) + +// +// in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite: +// + +#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES +#define nonstd_lite_HAVE_IN_PLACE_TYPES 1 + +// C++17 std::in_place in : + +#if optional_CPP17_OR_GREATER + +#include + +namespace nonstd { + +using std::in_place; +using std::in_place_type; +using std::in_place_index; +using std::in_place_t; +using std::in_place_type_t; +using std::in_place_index_t; + +#define nonstd_lite_in_place_t( T) std::in_place_t +#define nonstd_lite_in_place_type_t( T) std::in_place_type_t +#define nonstd_lite_in_place_index_t(K) std::in_place_index_t + +#define nonstd_lite_in_place( T) std::in_place_t{} +#define nonstd_lite_in_place_type( T) std::in_place_type_t{} +#define nonstd_lite_in_place_index(K) std::in_place_index_t{} + +} // namespace nonstd + +#else // optional_CPP17_OR_GREATER + +#include + +namespace nonstd { +namespace detail { + +template< class T > +struct in_place_type_tag {}; + +template< std::size_t K > +struct in_place_index_tag {}; + +} // namespace detail + +struct in_place_t {}; + +template< class T > +inline in_place_t in_place( detail::in_place_type_tag /*unused*/ = detail::in_place_type_tag() ) +{ + return in_place_t(); +} + +template< std::size_t K > +inline in_place_t in_place( detail::in_place_index_tag /*unused*/ = detail::in_place_index_tag() ) +{ + return in_place_t(); +} + +template< class T > +inline in_place_t in_place_type( detail::in_place_type_tag /*unused*/ = detail::in_place_type_tag() ) +{ + return in_place_t(); +} + +template< std::size_t K > +inline in_place_t in_place_index( detail::in_place_index_tag /*unused*/ = detail::in_place_index_tag() ) +{ + return in_place_t(); +} + +// mimic templated typedef: + +#define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) +#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) +#define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag ) + +#define nonstd_lite_in_place( T) nonstd::in_place_type +#define nonstd_lite_in_place_type( T) nonstd::in_place_type +#define nonstd_lite_in_place_index(K) nonstd::in_place_index + +} // namespace nonstd + +#endif // optional_CPP17_OR_GREATER +#endif // nonstd_lite_HAVE_IN_PLACE_TYPES + +// +// Using std::optional: +// + +#if optional_USES_STD_OPTIONAL + +#include + +namespace nonstd { + + using std::optional; + using std::bad_optional_access; + using std::hash; + + using std::nullopt; + using std::nullopt_t; + + using std::operator==; + using std::operator!=; + using std::operator<; + using std::operator<=; + using std::operator>; + using std::operator>=; + using std::make_optional; + using std::swap; +} + +#else // optional_USES_STD_OPTIONAL + +#include +#include + +// optional-lite alignment configuration: + +#ifndef optional_CONFIG_MAX_ALIGN_HACK +# define optional_CONFIG_MAX_ALIGN_HACK 0 +#endif + +#ifndef optional_CONFIG_ALIGN_AS +// no default, used in #if defined() +#endif + +#ifndef optional_CONFIG_ALIGN_AS_FALLBACK +# define optional_CONFIG_ALIGN_AS_FALLBACK double +#endif + +// Compiler warning suppression: + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wundef" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wundef" +#elif defined(_MSC_VER ) +# pragma warning( push ) +#endif + +// half-open range [lo..hi): +#define optional_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) + +// Compiler versions: +// +// MSVC++ 6.0 _MSC_VER == 1200 optional_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) +// MSVC++ 7.0 _MSC_VER == 1300 optional_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) +// MSVC++ 7.1 _MSC_VER == 1310 optional_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) +// MSVC++ 8.0 _MSC_VER == 1400 optional_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) +// MSVC++ 9.0 _MSC_VER == 1500 optional_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) +// MSVC++ 10.0 _MSC_VER == 1600 optional_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) +// MSVC++ 11.0 _MSC_VER == 1700 optional_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) +// MSVC++ 12.0 _MSC_VER == 1800 optional_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) +// MSVC++ 14.0 _MSC_VER == 1900 optional_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) +// MSVC++ 14.1 _MSC_VER >= 1910 optional_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) +// MSVC++ 14.2 _MSC_VER >= 1920 optional_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) + +#if defined(_MSC_VER ) && !defined(__clang__) +# define optional_COMPILER_MSVC_VER (_MSC_VER ) +# define optional_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) +#else +# define optional_COMPILER_MSVC_VER 0 +# define optional_COMPILER_MSVC_VERSION 0 +#endif + +#define optional_COMPILER_VERSION( major, minor, patch ) ( 10 * (10 * (major) + (minor) ) + (patch) ) + +#if defined(__GNUC__) && !defined(__clang__) +# define optional_COMPILER_GNUC_VERSION optional_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#else +# define optional_COMPILER_GNUC_VERSION 0 +#endif + +#if defined(__clang__) +# define optional_COMPILER_CLANG_VERSION optional_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) +#else +# define optional_COMPILER_CLANG_VERSION 0 +#endif + +#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 140 ) +# pragma warning( disable: 4345 ) // initialization behavior changed +#endif + +#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 150 ) +# pragma warning( disable: 4814 ) // in C++14 'constexpr' will not imply 'const' +#endif + +// Presence of language and library features: + +#define optional_HAVE(FEATURE) ( optional_HAVE_##FEATURE ) + +#ifdef _HAS_CPP0X +# define optional_HAS_CPP0X _HAS_CPP0X +#else +# define optional_HAS_CPP0X 0 +#endif + +// Unless defined otherwise below, consider VC14 as C++11 for optional-lite: + +#if optional_COMPILER_MSVC_VER >= 1900 +# undef optional_CPP11_OR_GREATER +# define optional_CPP11_OR_GREATER 1 +#endif + +#define optional_CPP11_90 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1500) +#define optional_CPP11_100 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1600) +#define optional_CPP11_110 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1700) +#define optional_CPP11_120 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1800) +#define optional_CPP11_140 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1900) +#define optional_CPP11_141 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1910) + +#define optional_CPP11_140_490 ((optional_CPP11_OR_GREATER_ && optional_COMPILER_GNUC_VERSION >= 490) || (optional_COMPILER_MSVC_VER >= 1910)) + +#define optional_CPP14_000 (optional_CPP14_OR_GREATER) +#define optional_CPP17_000 (optional_CPP17_OR_GREATER) + +// Presence of C++11 language features: + +#define optional_HAVE_CONSTEXPR_11 optional_CPP11_140 +#define optional_HAVE_IS_DEFAULT optional_CPP11_140 +#define optional_HAVE_NOEXCEPT optional_CPP11_140 +#define optional_HAVE_NULLPTR optional_CPP11_100 +#define optional_HAVE_REF_QUALIFIER optional_CPP11_140_490 +#define optional_HAVE_INITIALIZER_LIST optional_CPP11_140 + +// Presence of C++14 language features: + +#define optional_HAVE_CONSTEXPR_14 optional_CPP14_000 + +// Presence of C++17 language features: + +#define optional_HAVE_NODISCARD optional_CPP17_000 + +// Presence of C++ library features: + +#define optional_HAVE_CONDITIONAL optional_CPP11_120 +#define optional_HAVE_REMOVE_CV optional_CPP11_120 +#define optional_HAVE_TYPE_TRAITS optional_CPP11_90 + +#define optional_HAVE_TR1_TYPE_TRAITS (!! optional_COMPILER_GNUC_VERSION ) +#define optional_HAVE_TR1_ADD_POINTER (!! optional_COMPILER_GNUC_VERSION ) + +// C++ feature usage: + +#if optional_HAVE( CONSTEXPR_11 ) +# define optional_constexpr constexpr +#else +# define optional_constexpr /*constexpr*/ +#endif + +#if optional_HAVE( IS_DEFAULT ) +# define optional_is_default = default; +#else +# define optional_is_default {} +#endif + +#if optional_HAVE( CONSTEXPR_14 ) +# define optional_constexpr14 constexpr +#else +# define optional_constexpr14 /*constexpr*/ +#endif + +#if optional_HAVE( NODISCARD ) +# define optional_nodiscard [[nodiscard]] +#else +# define optional_nodiscard /*[[nodiscard]]*/ +#endif + +#if optional_HAVE( NOEXCEPT ) +# define optional_noexcept noexcept +#else +# define optional_noexcept /*noexcept*/ +#endif + +#if optional_HAVE( NULLPTR ) +# define optional_nullptr nullptr +#else +# define optional_nullptr NULL +#endif + +#if optional_HAVE( REF_QUALIFIER ) +// NOLINTNEXTLINE( bugprone-macro-parentheses ) +# define optional_ref_qual & +# define optional_refref_qual && +#else +# define optional_ref_qual /*&*/ +# define optional_refref_qual /*&&*/ +#endif + +// additional includes: + +#if optional_CONFIG_NO_EXCEPTIONS +// already included: +#else +# include +#endif + +#if optional_CPP11_OR_GREATER +# include +#endif + +#if optional_HAVE( INITIALIZER_LIST ) +# include +#endif + +#if optional_HAVE( TYPE_TRAITS ) +# include +#elif optional_HAVE( TR1_TYPE_TRAITS ) +# include +#endif + +// Method enabling + +#if optional_CPP11_OR_GREATER + +#define optional_REQUIRES_0(...) \ + template< bool B = (__VA_ARGS__), typename std::enable_if::type = 0 > + +#define optional_REQUIRES_T(...) \ + , typename std::enable_if< (__VA_ARGS__), int >::type = 0 + +#define optional_REQUIRES_R(R, ...) \ + typename std::enable_if< (__VA_ARGS__), R>::type + +#define optional_REQUIRES_A(...) \ + , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr + +#endif + +// +// optional: +// + +namespace nonstd { namespace optional_lite { + +namespace std11 { + +#if optional_CPP11_OR_GREATER + using std::move; +#else + template< typename T > T & move( T & t ) { return t; } +#endif + +#if optional_HAVE( CONDITIONAL ) + using std::conditional; +#else + template< bool B, typename T, typename F > struct conditional { typedef T type; }; + template< typename T, typename F > struct conditional { typedef F type; }; +#endif // optional_HAVE_CONDITIONAL + +// gcc < 5: +#if optional_CPP11_OR_GREATER +#if optional_BETWEEN( optional_COMPILER_GNUC_VERSION, 1, 500 ) + template< typename T > struct is_trivially_copy_constructible : std::true_type{}; + template< typename T > struct is_trivially_move_constructible : std::true_type{}; +#else + using std::is_trivially_copy_constructible; + using std::is_trivially_move_constructible; +#endif +#endif +} // namespace std11 + +#if optional_CPP11_OR_GREATER + +/// type traits C++17: + +namespace std17 { + +#if optional_CPP17_OR_GREATER + +using std::is_swappable; +using std::is_nothrow_swappable; + +#elif optional_CPP11_OR_GREATER + +namespace detail { + +using std::swap; + +struct is_swappable +{ + template< typename T, typename = decltype( swap( std::declval(), std::declval() ) ) > + static std::true_type test( int /*unused*/ ); + + template< typename > + static std::false_type test(...); +}; + +struct is_nothrow_swappable +{ + // wrap noexcept(expr) in separate function as work-around for VC140 (VS2015): + + template< typename T > + static constexpr bool satisfies() + { + return noexcept( swap( std::declval(), std::declval() ) ); + } + + template< typename T > + static auto test( int /*unused*/ ) -> std::integral_constant()>{} + + template< typename > + static auto test(...) -> std::false_type; +}; + +} // namespace detail + +// is [nothow] swappable: + +template< typename T > +struct is_swappable : decltype( detail::is_swappable::test(0) ){}; + +template< typename T > +struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test(0) ){}; + +#endif // optional_CPP17_OR_GREATER + +} // namespace std17 + +/// type traits C++20: + +namespace std20 { + +template< typename T > +struct remove_cvref +{ + typedef typename std::remove_cv< typename std::remove_reference::type >::type type; +}; + +} // namespace std20 + +#endif // optional_CPP11_OR_GREATER + +/// class optional + +template< typename T > +class optional; + +namespace detail { + +// C++11 emulation: + +struct nulltype{}; + +template< typename Head, typename Tail > +struct typelist +{ + typedef Head head; + typedef Tail tail; +}; + +#if optional_CONFIG_MAX_ALIGN_HACK + +// Max align, use most restricted type for alignment: + +#define optional_UNIQUE( name ) optional_UNIQUE2( name, __LINE__ ) +#define optional_UNIQUE2( name, line ) optional_UNIQUE3( name, line ) +#define optional_UNIQUE3( name, line ) name ## line + +#define optional_ALIGN_TYPE( type ) \ + type optional_UNIQUE( _t ); struct_t< type > optional_UNIQUE( _st ) + +template< typename T > +struct struct_t { T _; }; + +union max_align_t +{ + optional_ALIGN_TYPE( char ); + optional_ALIGN_TYPE( short int ); + optional_ALIGN_TYPE( int ); + optional_ALIGN_TYPE( long int ); + optional_ALIGN_TYPE( float ); + optional_ALIGN_TYPE( double ); + optional_ALIGN_TYPE( long double ); + optional_ALIGN_TYPE( char * ); + optional_ALIGN_TYPE( short int * ); + optional_ALIGN_TYPE( int * ); + optional_ALIGN_TYPE( long int * ); + optional_ALIGN_TYPE( float * ); + optional_ALIGN_TYPE( double * ); + optional_ALIGN_TYPE( long double * ); + optional_ALIGN_TYPE( void * ); + +#ifdef HAVE_LONG_LONG + optional_ALIGN_TYPE( long long ); +#endif + + struct Unknown; + + Unknown ( * optional_UNIQUE(_) )( Unknown ); + Unknown * Unknown::* optional_UNIQUE(_); + Unknown ( Unknown::* optional_UNIQUE(_) )( Unknown ); + + struct_t< Unknown ( * )( Unknown) > optional_UNIQUE(_); + struct_t< Unknown * Unknown::* > optional_UNIQUE(_); + struct_t< Unknown ( Unknown::* )(Unknown) > optional_UNIQUE(_); +}; + +#undef optional_UNIQUE +#undef optional_UNIQUE2 +#undef optional_UNIQUE3 + +#undef optional_ALIGN_TYPE + +#elif defined( optional_CONFIG_ALIGN_AS ) // optional_CONFIG_MAX_ALIGN_HACK + +// Use user-specified type for alignment: + +#define optional_ALIGN_AS( unused ) \ + optional_CONFIG_ALIGN_AS + +#else // optional_CONFIG_MAX_ALIGN_HACK + +// Determine POD type to use for alignment: + +#define optional_ALIGN_AS( to_align ) \ + typename type_of_size< alignment_types, alignment_of< to_align >::value >::type + +template< typename T > +struct alignment_of; + +template< typename T > +struct alignment_of_hack +{ + char c; + T t; + alignment_of_hack(); +}; + +template< size_t A, size_t S > +struct alignment_logic +{ + enum { value = A < S ? A : S }; +}; + +template< typename T > +struct alignment_of +{ + enum { value = alignment_logic< + sizeof( alignment_of_hack ) - sizeof(T), sizeof(T) >::value }; +}; + +template< typename List, size_t N > +struct type_of_size +{ + typedef typename std11::conditional< + N == sizeof( typename List::head ), + typename List::head, + typename type_of_size::type >::type type; +}; + +template< size_t N > +struct type_of_size< nulltype, N > +{ + typedef optional_CONFIG_ALIGN_AS_FALLBACK type; +}; + +template< typename T> +struct struct_t { T _; }; + +#define optional_ALIGN_TYPE( type ) \ + typelist< type , typelist< struct_t< type > + +struct Unknown; + +typedef + optional_ALIGN_TYPE( char ), + optional_ALIGN_TYPE( short ), + optional_ALIGN_TYPE( int ), + optional_ALIGN_TYPE( long ), + optional_ALIGN_TYPE( float ), + optional_ALIGN_TYPE( double ), + optional_ALIGN_TYPE( long double ), + + optional_ALIGN_TYPE( char *), + optional_ALIGN_TYPE( short * ), + optional_ALIGN_TYPE( int * ), + optional_ALIGN_TYPE( long * ), + optional_ALIGN_TYPE( float * ), + optional_ALIGN_TYPE( double * ), + optional_ALIGN_TYPE( long double * ), + + optional_ALIGN_TYPE( Unknown ( * )( Unknown ) ), + optional_ALIGN_TYPE( Unknown * Unknown::* ), + optional_ALIGN_TYPE( Unknown ( Unknown::* )( Unknown ) ), + + nulltype + > > > > > > > > > > > > > > + > > > > > > > > > > > > > > + > > > > > > + alignment_types; + +#undef optional_ALIGN_TYPE + +#endif // optional_CONFIG_MAX_ALIGN_HACK + +/// C++03 constructed union to hold value. + +template< typename T > +union storage_t +{ +//private: +// template< typename > friend class optional; + + typedef T value_type; + + storage_t() optional_is_default + + explicit storage_t( value_type const & v ) + { + construct_value( v ); + } + + void construct_value( value_type const & v ) + { + ::new( value_ptr() ) value_type( v ); + } + +#if optional_CPP11_OR_GREATER + + explicit storage_t( value_type && v ) + { + construct_value( std::move( v ) ); + } + + void construct_value( value_type && v ) + { + ::new( value_ptr() ) value_type( std::move( v ) ); + } + + template< class... Args > + void emplace( Args&&... args ) + { + ::new( value_ptr() ) value_type( std::forward(args)... ); + } + + template< class U, class... Args > + void emplace( std::initializer_list il, Args&&... args ) + { + ::new( value_ptr() ) value_type( il, std::forward(args)... ); + } + +#endif + + void destruct_value() + { + value_ptr()->~T(); + } + + optional_nodiscard value_type const * value_ptr() const + { + return as(); + } + + value_type * value_ptr() + { + return as(); + } + + optional_nodiscard value_type const & value() const optional_ref_qual + { + return * value_ptr(); + } + + value_type & value() optional_ref_qual + { + return * value_ptr(); + } + +#if optional_HAVE( REF_QUALIFIER ) + + optional_nodiscard value_type const && value() const optional_refref_qual + { + return std::move( value() ); + } + + value_type && value() optional_refref_qual + { + return std::move( value() ); + } + +#endif + +#if optional_CPP11_OR_GREATER + + using aligned_storage_t = typename std::aligned_storage< sizeof(value_type), alignof(value_type) >::type; + aligned_storage_t data; + +#elif optional_CONFIG_MAX_ALIGN_HACK + + typedef struct { unsigned char data[ sizeof(value_type) ]; } aligned_storage_t; + + max_align_t hack; + aligned_storage_t data; + +#else + typedef optional_ALIGN_AS(value_type) align_as_type; + + typedef struct { align_as_type data[ 1 + ( sizeof(value_type) - 1 ) / sizeof(align_as_type) ]; } aligned_storage_t; + aligned_storage_t data; + +# undef optional_ALIGN_AS + +#endif // optional_CONFIG_MAX_ALIGN_HACK + + optional_nodiscard void * ptr() optional_noexcept + { + return &data; + } + + optional_nodiscard void const * ptr() const optional_noexcept + { + return &data; + } + + template + optional_nodiscard U * as() + { + return reinterpret_cast( ptr() ); + } + + template + optional_nodiscard U const * as() const + { + return reinterpret_cast( ptr() ); + } +}; + +} // namespace detail + +/// disengaged state tag + +struct nullopt_t +{ + struct init{}; + explicit optional_constexpr nullopt_t( init /*unused*/ ) optional_noexcept {} +}; + +#if optional_HAVE( CONSTEXPR_11 ) +constexpr nullopt_t nullopt{ nullopt_t::init{} }; +#else +// extra parenthesis to prevent the most vexing parse: +const nullopt_t nullopt(( nullopt_t::init() )); +#endif + +/// optional access error + +#if ! optional_CONFIG_NO_EXCEPTIONS + +class bad_optional_access : public std::logic_error +{ +public: + explicit bad_optional_access() + : logic_error( "bad optional access" ) {} +}; + +#endif //optional_CONFIG_NO_EXCEPTIONS + +/// optional + +template< typename T> +class optional +{ +private: + template< typename > friend class optional; + + typedef void (optional::*safe_bool)() const; + +public: + typedef T value_type; + + // x.x.3.1, constructors + + // 1a - default construct + optional_constexpr optional() optional_noexcept + : has_value_( false ) + , contained() + {} + + // 1b - construct explicitly empty + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + optional_constexpr optional( nullopt_t /*unused*/ ) optional_noexcept + : has_value_( false ) + , contained() + {} + + // 2 - copy-construct +#if optional_CPP11_OR_GREATER + // template< typename U = T + // optional_REQUIRES_T( + // std::is_copy_constructible::value + // || std11::is_trivially_copy_constructible::value + // ) + // > +#endif + optional_constexpr14 optional( optional const & other ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( other.contained.value() ); + } + } + +#if optional_CPP11_OR_GREATER + + // 3 (C++11) - move-construct from optional + template< typename U = T + optional_REQUIRES_T( + std::is_move_constructible::value + || std11::is_trivially_move_constructible::value + ) + > + optional_constexpr14 optional( optional && other ) + // NOLINTNEXTLINE( performance-noexcept-move-constructor ) + noexcept( std::is_nothrow_move_constructible::value ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( std::move( other.contained.value() ) ); + } + } + + // 4a (C++11) - explicit converting copy-construct from optional + template< typename U + optional_REQUIRES_T( + std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && !std::is_convertible< U const & , T>::value /*=> explicit */ + ) + > + explicit optional( optional const & other ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( T{ other.contained.value() } ); + } + } +#endif // optional_CPP11_OR_GREATER + + // 4b (C++98 and later) - non-explicit converting copy-construct from optional + template< typename U +#if optional_CPP11_OR_GREATER + optional_REQUIRES_T( + std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && std::is_convertible< U const & , T>::value /*=> non-explicit */ + ) +#endif // optional_CPP11_OR_GREATER + > + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + /*non-explicit*/ optional( optional const & other ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( other.contained.value() ); + } + } + +#if optional_CPP11_OR_GREATER + + // 5a (C++11) - explicit converting move-construct from optional + template< typename U + optional_REQUIRES_T( + std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && !std::is_convertible< U &&, T>::value /*=> explicit */ + ) + > + explicit optional( optional && other + ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( T{ std::move( other.contained.value() ) } ); + } + } + + // 5a (C++11) - non-explicit converting move-construct from optional + template< typename U + optional_REQUIRES_T( + std::is_constructible::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && std::is_convertible< U &&, T>::value /*=> non-explicit */ + ) + > + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + /*non-explicit*/ optional( optional && other ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( std::move( other.contained.value() ) ); + } + } + + // 6 (C++11) - in-place construct + template< typename... Args + optional_REQUIRES_T( + std::is_constructible::value + ) + > + optional_constexpr explicit optional( nonstd_lite_in_place_t(T), Args&&... args ) + : has_value_( true ) + , contained( T( std::forward(args)...) ) + {} + + // 7 (C++11) - in-place construct, initializer-list + template< typename U, typename... Args + optional_REQUIRES_T( + std::is_constructible&, Args&&...>::value + ) + > + optional_constexpr explicit optional( nonstd_lite_in_place_t(T), std::initializer_list il, Args&&... args ) + : has_value_( true ) + , contained( T( il, std::forward(args)...) ) + {} + + // 8a (C++11) - explicit move construct from value + template< typename U = T + optional_REQUIRES_T( + std::is_constructible::value + && !std::is_same::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same::type, optional>::value + && !std::is_convertible::value /*=> explicit */ + ) + > + optional_constexpr explicit optional( U && value ) + : has_value_( true ) + , contained( T{ std::forward( value ) } ) + {} + + // 8b (C++11) - non-explicit move construct from value + template< typename U = T + optional_REQUIRES_T( + std::is_constructible::value + && !std::is_same::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same::type, optional>::value + && std::is_convertible::value /*=> non-explicit */ + ) + > + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + optional_constexpr /*non-explicit*/ optional( U && value ) + : has_value_( true ) + , contained( std::forward( value ) ) + {} + +#else // optional_CPP11_OR_GREATER + + // 8 (C++98) + optional( value_type const & value ) + : has_value_( true ) + , contained( value ) + {} + +#endif // optional_CPP11_OR_GREATER + + // x.x.3.2, destructor + + ~optional() + { + if ( has_value() ) + { + contained.destruct_value(); + } + } + + // x.x.3.3, assignment + + // 1 (C++98and later) - assign explicitly empty + optional & operator=( nullopt_t /*unused*/) optional_noexcept + { + reset(); + return *this; + } + + // 2 (C++98and later) - copy-assign from optional +#if optional_CPP11_OR_GREATER + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional &, + true +// std::is_copy_constructible::value +// && std::is_copy_assignable::value + ) + operator=( optional const & other ) + noexcept( + std::is_nothrow_move_assignable::value + && std::is_nothrow_move_constructible::value + ) +#else + optional & operator=( optional const & other ) +#endif + { + if ( (has_value() == true ) && (other.has_value() == false) ) { reset(); } + else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( *other ); } + else if ( (has_value() == true ) && (other.has_value() == true ) ) { contained.value() = *other; } + return *this; + } + +#if optional_CPP11_OR_GREATER + + // 3 (C++11) - move-assign from optional + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional &, + true +// std::is_move_constructible::value +// && std::is_move_assignable::value + ) + operator=( optional && other ) noexcept + { + if ( (has_value() == true ) && (other.has_value() == false) ) { reset(); } + else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( std::move( *other ) ); } + else if ( (has_value() == true ) && (other.has_value() == true ) ) { contained.value() = std::move( *other ); } + return *this; + } + + // 4 (C++11) - move-assign from value + template< typename U = T > + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional &, + std::is_constructible::value + && std::is_assignable::value + && !std::is_same::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same::type, optional>::value + && !(std::is_scalar::value && std::is_same::type>::value) + ) + operator=( U && value ) + { + if ( has_value() ) + { + contained.value() = std::forward( value ); + } + else + { + initialize( T( std::forward( value ) ) ); + } + return *this; + } + +#else // optional_CPP11_OR_GREATER + + // 4 (C++98) - copy-assign from value + template< typename U /*= T*/ > + optional & operator=( U const & value ) + { + if ( has_value() ) contained.value() = value; + else initialize( T( value ) ); + return *this; + } + +#endif // optional_CPP11_OR_GREATER + + // 5 (C++98 and later) - converting copy-assign from optional + template< typename U > +#if optional_CPP11_OR_GREATER + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional&, + std::is_constructible< T , U const &>::value + && std::is_assignable< T&, U const &>::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && !std::is_assignable< T&, optional & >::value + && !std::is_assignable< T&, optional && >::value + && !std::is_assignable< T&, optional const & >::value + && !std::is_assignable< T&, optional const && >::value + ) +#else + optional& +#endif // optional_CPP11_OR_GREATER + operator=( optional const & other ) + { + return *this = optional( other ); + } + +#if optional_CPP11_OR_GREATER + + // 6 (C++11) - converting move-assign from optional + template< typename U > + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional&, + std::is_constructible< T , U>::value + && std::is_assignable< T&, U>::value + && !std::is_constructible & >::value + && !std::is_constructible && >::value + && !std::is_constructible const & >::value + && !std::is_constructible const && >::value + && !std::is_convertible< optional & , T>::value + && !std::is_convertible< optional && , T>::value + && !std::is_convertible< optional const & , T>::value + && !std::is_convertible< optional const &&, T>::value + && !std::is_assignable< T&, optional & >::value + && !std::is_assignable< T&, optional && >::value + && !std::is_assignable< T&, optional const & >::value + && !std::is_assignable< T&, optional const && >::value + ) + operator=( optional && other ) + { + return *this = optional( std::move( other ) ); + } + + // 7 (C++11) - emplace + template< typename... Args + optional_REQUIRES_T( + std::is_constructible::value + ) + > + T& emplace( Args&&... args ) + { + *this = nullopt; + contained.emplace( std::forward(args)... ); + has_value_ = true; + return contained.value(); + } + + // 8 (C++11) - emplace, initializer-list + template< typename U, typename... Args + optional_REQUIRES_T( + std::is_constructible&, Args&&...>::value + ) + > + T& emplace( std::initializer_list il, Args&&... args ) + { + *this = nullopt; + contained.emplace( il, std::forward(args)... ); + has_value_ = true; + return contained.value(); + } + +#endif // optional_CPP11_OR_GREATER + + // x.x.3.4, swap + + void swap( optional & other ) +#if optional_CPP11_OR_GREATER + noexcept( + std::is_nothrow_move_constructible::value + && std17::is_nothrow_swappable::value + ) +#endif + { + using std::swap; + if ( (has_value() == true ) && (other.has_value() == true ) ) { swap( **this, *other ); } + else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( std11::move(*other) ); other.reset(); } + else if ( (has_value() == true ) && (other.has_value() == false) ) { other.initialize( std11::move(**this) ); reset(); } + } + + // x.x.3.5, observers + + optional_constexpr value_type const * operator ->() const + { + return assert( has_value() ), + contained.value_ptr(); + } + + optional_constexpr14 value_type * operator ->() + { + return assert( has_value() ), + contained.value_ptr(); + } + + optional_constexpr value_type const & operator *() const optional_ref_qual + { + return assert( has_value() ), + contained.value(); + } + + optional_constexpr14 value_type & operator *() optional_ref_qual + { + return assert( has_value() ), + contained.value(); + } + +#if optional_HAVE( REF_QUALIFIER ) + + optional_constexpr value_type const && operator *() const optional_refref_qual + { + return std::move( **this ); + } + + optional_constexpr14 value_type && operator *() optional_refref_qual + { + return std::move( **this ); + } + +#endif + +#if optional_CPP11_OR_GREATER + optional_constexpr explicit operator bool() const optional_noexcept + { + return has_value(); + } +#else + optional_constexpr operator safe_bool() const optional_noexcept + { + return has_value() ? &optional::this_type_does_not_support_comparisons : 0; + } +#endif + + // NOLINTNEXTLINE( modernize-use-nodiscard ) + /*optional_nodiscard*/ optional_constexpr bool has_value() const optional_noexcept + { + return has_value_; + } + + // NOLINTNEXTLINE( modernize-use-nodiscard ) + /*optional_nodiscard*/ optional_constexpr14 value_type const & value() const optional_ref_qual + { +#if optional_CONFIG_NO_EXCEPTIONS + assert( has_value() ); +#else + if ( ! has_value() ) + { + throw bad_optional_access(); + } +#endif + return contained.value(); + } + + optional_constexpr14 value_type & value() optional_ref_qual + { +#if optional_CONFIG_NO_EXCEPTIONS + assert( has_value() ); +#else + if ( ! has_value() ) + { + throw bad_optional_access(); + } +#endif + return contained.value(); + } + +#if optional_HAVE( REF_QUALIFIER ) && ( !optional_COMPILER_GNUC_VERSION || optional_COMPILER_GNUC_VERSION >= 490 ) + + // NOLINTNEXTLINE( modernize-use-nodiscard ) + /*optional_nodiscard*/ optional_constexpr value_type const && value() const optional_refref_qual + { + return std::move( value() ); + } + + optional_constexpr14 value_type && value() optional_refref_qual + { + return std::move( value() ); + } + +#endif + +#if optional_CPP11_OR_GREATER + + template< typename U > + optional_constexpr value_type value_or( U && v ) const optional_ref_qual + { + return has_value() ? contained.value() : static_cast(std::forward( v ) ); + } + + template< typename U > + optional_constexpr14 value_type value_or( U && v ) optional_refref_qual + { + return has_value() ? std::move( contained.value() ) : static_cast(std::forward( v ) ); + } + +#else + + template< typename U > + optional_constexpr value_type value_or( U const & v ) const + { + return has_value() ? contained.value() : static_cast( v ); + } + +#endif // optional_CPP11_OR_GREATER + + // x.x.3.6, modifiers + + void reset() optional_noexcept + { + if ( has_value() ) + { + contained.destruct_value(); + } + + has_value_ = false; + } + +private: + void this_type_does_not_support_comparisons() const {} + + template< typename V > + void initialize( V const & value ) + { + assert( ! has_value() ); + contained.construct_value( value ); + has_value_ = true; + } + +#if optional_CPP11_OR_GREATER + template< typename V > + void initialize( V && value ) + { + assert( ! has_value() ); + contained.construct_value( std::move( value ) ); + has_value_ = true; + } + +#endif + +private: + bool has_value_; + detail::storage_t< value_type > contained; + +}; + +// Relational operators + +template< typename T, typename U > +inline optional_constexpr bool operator==( optional const & x, optional const & y ) +{ + return bool(x) != bool(y) ? false : !bool( x ) ? true : *x == *y; +} + +template< typename T, typename U > +inline optional_constexpr bool operator!=( optional const & x, optional const & y ) +{ + return !(x == y); +} + +template< typename T, typename U > +inline optional_constexpr bool operator<( optional const & x, optional const & y ) +{ + return (!y) ? false : (!x) ? true : *x < *y; +} + +template< typename T, typename U > +inline optional_constexpr bool operator>( optional const & x, optional const & y ) +{ + return (y < x); +} + +template< typename T, typename U > +inline optional_constexpr bool operator<=( optional const & x, optional const & y ) +{ + return !(y < x); +} + +template< typename T, typename U > +inline optional_constexpr bool operator>=( optional const & x, optional const & y ) +{ + return !(x < y); +} + +// Comparison with nullopt + +template< typename T > +inline optional_constexpr bool operator==( optional const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return (!x); +} + +template< typename T > +inline optional_constexpr bool operator==( nullopt_t /*unused*/, optional const & x ) optional_noexcept +{ + return (!x); +} + +template< typename T > +inline optional_constexpr bool operator!=( optional const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +inline optional_constexpr bool operator!=( nullopt_t /*unused*/, optional const & x ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +inline optional_constexpr bool operator<( optional const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept +{ + return false; +} + +template< typename T > +inline optional_constexpr bool operator<( nullopt_t /*unused*/, optional const & x ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +inline optional_constexpr bool operator<=( optional const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return (!x); +} + +template< typename T > +inline optional_constexpr bool operator<=( nullopt_t /*unused*/, optional const & /*unused*/ ) optional_noexcept +{ + return true; +} + +template< typename T > +inline optional_constexpr bool operator>( optional const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +inline optional_constexpr bool operator>( nullopt_t /*unused*/, optional const & /*unused*/ ) optional_noexcept +{ + return false; +} + +template< typename T > +inline optional_constexpr bool operator>=( optional const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept +{ + return true; +} + +template< typename T > +inline optional_constexpr bool operator>=( nullopt_t /*unused*/, optional const & x ) optional_noexcept +{ + return (!x); +} + +// Comparison with T + +template< typename T, typename U > +inline optional_constexpr bool operator==( optional const & x, U const & v ) +{ + return bool(x) ? *x == v : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator==( U const & v, optional const & x ) +{ + return bool(x) ? v == *x : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator!=( optional const & x, U const & v ) +{ + return bool(x) ? *x != v : true; +} + +template< typename T, typename U > +inline optional_constexpr bool operator!=( U const & v, optional const & x ) +{ + return bool(x) ? v != *x : true; +} + +template< typename T, typename U > +inline optional_constexpr bool operator<( optional const & x, U const & v ) +{ + return bool(x) ? *x < v : true; +} + +template< typename T, typename U > +inline optional_constexpr bool operator<( U const & v, optional const & x ) +{ + return bool(x) ? v < *x : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator<=( optional const & x, U const & v ) +{ + return bool(x) ? *x <= v : true; +} + +template< typename T, typename U > +inline optional_constexpr bool operator<=( U const & v, optional const & x ) +{ + return bool(x) ? v <= *x : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator>( optional const & x, U const & v ) +{ + return bool(x) ? *x > v : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator>( U const & v, optional const & x ) +{ + return bool(x) ? v > *x : true; +} + +template< typename T, typename U > +inline optional_constexpr bool operator>=( optional const & x, U const & v ) +{ + return bool(x) ? *x >= v : false; +} + +template< typename T, typename U > +inline optional_constexpr bool operator>=( U const & v, optional const & x ) +{ + return bool(x) ? v >= *x : true; +} + +// Specialized algorithms + +template< typename T +#if optional_CPP11_OR_GREATER + optional_REQUIRES_T( + std::is_move_constructible::value + && std17::is_swappable::value ) +#endif +> +void swap( optional & x, optional & y ) +#if optional_CPP11_OR_GREATER + noexcept( noexcept( x.swap(y) ) ) +#endif +{ + x.swap( y ); +} + +#if optional_CPP11_OR_GREATER + +template< typename T > +optional_constexpr optional< typename std::decay::type > make_optional( T && value ) +{ + return optional< typename std::decay::type >( std::forward( value ) ); +} + +template< typename T, typename...Args > +optional_constexpr optional make_optional( Args&&... args ) +{ + return optional( nonstd_lite_in_place(T), std::forward(args)...); +} + +template< typename T, typename U, typename... Args > +optional_constexpr optional make_optional( std::initializer_list il, Args&&... args ) +{ + return optional( nonstd_lite_in_place(T), il, std::forward(args)...); +} + +#else + +template< typename T > +optional make_optional( T const & value ) +{ + return optional( value ); +} + +#endif // optional_CPP11_OR_GREATER + +} // namespace optional_lite + +using optional_lite::optional; +using optional_lite::nullopt_t; +using optional_lite::nullopt; + +#if ! optional_CONFIG_NO_EXCEPTIONS +using optional_lite::bad_optional_access; +#endif + +using optional_lite::make_optional; + +} // namespace nonstd + +#if optional_CPP11_OR_GREATER + +// specialize the std::hash algorithm: + +namespace std { + +template< class T > +struct hash< nonstd::optional > +{ +public: + std::size_t operator()( nonstd::optional const & v ) const optional_noexcept + { + return bool( v ) ? std::hash{}( *v ) : 0; + } +}; + +} //namespace std + +#endif // optional_CPP11_OR_GREATER + +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#elif defined(_MSC_VER ) +# pragma warning( pop ) +#endif + +#endif // optional_USES_STD_OPTIONAL + +#endif // NONSTD_OPTIONAL_LITE_HPP \ No newline at end of file diff --git a/notinuse/optional_readme.md b/notinuse/optional_readme.md new file mode 100644 index 0000000..cbb8f08 --- /dev/null +++ b/notinuse/optional_readme.md @@ -0,0 +1,479 @@ + +> DBJ NOTE: this is nonstd::optional **not** nonstd bare optional which is currently in use by `crt_proxy_lib` +# optional lite +> An single-file header-only version of a C++17-like optional, a nullable object for C++98, C++11 and later + +[![Language](https://img.shields.io/badge/C%2B%2B-98/11-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) + + [![License](https://img.shields.io/badge/license-BSL-blue.svg)](https://opensource.org/licenses/BSL-1.0) + + [![Build Status](https://travis-ci.org/martinmoene/optional-lite.svg?branch=master)](https://travis-ci.org/martinmoene/optional-lite) [![Build status](https://ci.appveyor.com/api/projects/status/1oq5gjm7bufrv6ib?svg=true)](https://ci.appveyor.com/project/martinmoene/optional-lite) + + [![Version](https://badge.fury.io/gh/martinmoene%2Foptional-lite.svg)](https://github.com/martinmoene/optional-lite/releases) + + [![download](https://img.shields.io/badge/latest-download-blue.svg)](https://raw.githubusercontent.com/martinmoene/optional-lite/master/include/nonstd/optional.hpp) [![Conan](https://img.shields.io/badge/on-conan-blue.svg)](https://bintray.com/conan/conan-center/optional-lite%3A_) [![Try it online](https://img.shields.io/badge/on-wandbox-blue.svg)](https://wandbox.org/permlink/bfZdDT4WerPNZi6b) [![Try it on godbolt online](https://img.shields.io/badge/on-godbolt-blue.svg)](https://godbolt.org/z/3tecRa) + +**Contents** +- [optional lite](#optional-lite) + - [Example usage](#example-usage) + - [Compile and run](#compile-and-run) + - [In a nutshell](#in-a-nutshell) + - [License](#license) + - [Dependencies](#dependencies) + - [Installation](#installation) + - [Synopsis](#synopsis) + - [Types and values in namespace nonstd](#types-and-values-in-namespace-nonstd) + - [Interface of *optional lite*](#interface-of-optional-lite) + - [Algorithms for *optional lite*](#algorithms-for-optional-lite) + - [Configuration](#configuration) + - [Standard selection macro](#standard-selection-macro) + - [Select `std::optional` or `nonstd::optional`](#select-stdoptional-or-nonstdoptional) + - [Disable exceptions](#disable-exceptions) + - [Macros to control alignment](#macros-to-control-alignment) + - [Comparison of std::optional, optional lite and Boost.Optional](#comparison-of-stdoptional-optional-lite-and-boostoptional) + - [Reported to work with](#reported-to-work-with) + - [Building the tests](#building-the-tests) + - [Implementation notes](#implementation-notes) + - [Object allocation and alignment](#object-allocation-and-alignment) + - [Other implementations of optional](#other-implementations-of-optional) + - [Notes and references](#notes-and-references) + - [Appendix](#appendix) + - [A.1 Compile-time information](#a1-compile-time-information) + - [A.2 Optional Lite test specification](#a2-optional-lite-test-specification) + + +Example usage +------------- + +```Cpp +#include "nonstd/optional.hpp" + +#include +#include + +using nonstd::optional; +using nonstd::nullopt; + +optional to_int( char const * const text ) +{ + char * pos = NULL; + const int value = strtol( text, &pos, 0 ); + + return pos == text ? nullopt : optional( value ); +} + +int main( int argc, char * argv[] ) +{ + char * text = argc > 1 ? argv[1] : "42"; + + optional oi = to_int( text ); + + if ( oi ) std::cout << "'" << text << "' is " << *oi; + else std::cout << "'" << text << "' isn't a number"; +} +``` +### Compile and run +``` +prompt>g++ -Wall -Wextra -std=c++03 -I../include -o 01-to_int.exe 01-to_int.cpp && 01-to_int x1 +'x1' isn't a number +``` + +In a nutshell +--------------- +**optional lite** is a single-file header-only library to represent optional (nullable) objects and pass them by value. The library aims to provide a [C++17-like optional](http://en.cppreference.com/w/cpp/utility/optional) for use with C++98 and later. If available, std::optional is used. There's also a simpler version, [*optional bare*](https://github.com/martinmoene/optional-bare). Unlike *optional lite*, *optional bare* is limited to default-constructible and copyable types. + +**Features and properties of optional lite** are ease of installation (single header), freedom of dependencies other than the standard library and control over object alignment (if needed). *optional lite* shares the approach to in-place tags with [any-lite](https://github.com/martinmoene/any-lite), [expected-lite](https://github.com/martinmoene/expected-lite) and with [variant-lite](https://github.com/martinmoene/variant-lite) and these libraries can be used together. + +**Not provided** are reference-type optionals. *optional lite* doesn't handle overloaded *address of* operators. + +For more examples, see [this answer on StackOverflow](http://stackoverflow.com/a/16861022) [8] and the [quick start guide](http://www.boost.org/doc/libs/1_57_0/libs/optional/doc/html/boost_optional/quick_start.html) [9] of Boost.Optional (note that its interface differs from *optional lite*). + + +License +------- +*optional lite* is distributed under the [Boost Software License](LICENSE.txt). + + +Dependencies +------------ +*optional lite* has no other dependencies than the [C++ standard library](http://en.cppreference.com/w/cpp/header). + + +Installation +------------ + +*optional lite* is a single-file header-only library. Put `optional.hpp` in the [include](include) folder directly into the project source tree or somewhere reachable from your project. + +Or, if you use the [conan package manager](https://www.conan.io/), follow these steps: + +1. Add *nonstd-lite* to the conan remotes: + + conan remote add nonstd-lite https://api.bintray.com/conan/martinmoene/nonstd-lite + +2. Add a reference to *optional-lite* to the *requires* section of your project's `conanfile.txt` file: + + [requires] + optional-lite/3.1.1@nonstd-lite/testing + +3. Run conan's install command: + + conan install + + +Synopsis +-------- + +**Contents** +[Types in namespace nonstd](#types-in-namespace-nonstd) +[Interface of *optional lite*](#interface-of-optional-lite) +[Algorithms for *optional lite*](#algorithms-for-optional-lite) +[Configuration](#configuration) + +### Types and values in namespace nonstd + +| Purpose | Type / value | Object | +|-----------------------|--------------|--------| +| To be, or not | template< typename T >
class **optional**; | | +| Disengaging | struct **nullopt_t**; | nullopt_t nullopt; | +| Error reporting | class **bad_optional_access**; |  | +| In-place construction | struct **in_place_tag** |   | +|   | **in_place** | select type or index for in-place construction | +|   | **in_place_type** | select type for in-place construction | +|  (variant) | **in_place_index** | select index for in-place construction | +|   | **nonstd_lite_in_place_type_t**( T) | macro for alias template in_place_type_t<T> | +|  (variant) | **nonstd_lite_in_place_index_t**( T )| macro for alias template in_place_index_t<T> | + +### Interface of *optional lite* + +| Kind | Std | Method | Result | +|--------------|------|---------------------------------------------|--------| +| Construction | | **optional**() noexcept | default construct a nulled object | +|   | | **optional**( nullopt_t ) noexcept | explicitly construct a nulled object | +|   | | **optional**( optional const & rhs ) | move-construct from an other optional | +|   | C++11| **optional**( optional && rhs ) noexcept(...) | move-construct from an other optional | +|   | | **optional**( value_type const & value ) | copy-construct from a value | +|   | C++11| **optional**( value_type && value ) | move-construct from a value | +|   | C++11| **explicit optional**( in_place_type_t<T>, Args&&... args ) | in-place-construct type T | +|   | C++11| **explicit optional**( in_place_type_t<T>, std::initializer_list<U> il, Args&&... args ) | in-place-construct type T | +| Destruction | | **~optional**() | destruct current content, if any | +| Assignment | | optional & **operator=**( nullopt_t ) | null the object;
destruct current content, if any | +|   | | optional & **operator=**( optional const & rhs ) | copy-assign from other optional;
destruct current content, if any | +|   | C++11| optional & **operator=**( optional && rhs ) | move-assign from other optional;
destruct current content, if any | +|   | C++11| template< class U, ...>
**optional & operator=( U && v ) | move-assign from a value;
destruct current content, if any | +|   | C++11| template< class... Args >
T & **emplace**( Args&&... args ) | emplace type T | +|   | C++11| template< class U, class... Args >
T & **emplace**( std::initializer_list<U> il, Args&&... args ) | emplace type T | +| Swap | | void **swap**( optional & rhs ) noexcept(...) | swap with rhs | +| Content | | value_type const \* **operator ->**() const | pointer to current content (const);
must contain value | +|   | | value_type \* **operator ->**() | pointer to current content (non-const);
must contain value | +|   | | value_type const & **operator \***() & | the current content (const ref);
must contain value | +|   | | value_type & **operator \***() & | the current content (non-const ref);
must contain value | +|   | C++11| value_type const & **operator \***() && | the current content (const ref);
must contain value | +|   | C++11| value_type & **operator \***() && | the current content (non-const ref);
must contain value | +| State | | operator **bool**() const | true if content is present | +|   | | bool **has_value**() const | true if content is present | +|   | | value_type const & **value**() & | the current content (const ref);
throws bad_optional_access if nulled | +|   | | value_type & **value**() & | the current content (non-const ref);
throws bad_optional_access if nulled | +|   | C++11| value_type const & **value**() && | the current content (const ref);
throws bad_optional_access if nulled | +|   | C++11| value_type & **value**() && | the current content (non-const ref);
throws bad_optional_access if nulled | +|   |value_type must be copy-constructible | +|   | C++11| value_type **value_or**( value_type && default_value ) & | the value, or default_value if nulled
value_type must be copy-constructible | +|   | C++11| value_type **value_or**( value_type && default_value ) && | the value, or default_value if nulled
value_type must be copy-constructible | +| Modifiers | | void **reset**() noexcept | make empty | + + +### Algorithms for *optional lite* + +| Kind | Std | Function | +|--------------------------|------|----------| +| Relational operators | |   | +| == | | template< typename T >
bool **operator==**( optional const & x, optional const & y ) | +| != | | template< typename T >
bool **operator!=**( optional const & x, optional const & y ) | +| < | | template< typename T >
bool **operator<**( optional const & x, optional const & y ) | +| > | | template< typename T >
bool **operator>**( optional const & x, optional const & y ) | +| <= | | template< typename T >
bool **operator<=*( optional const & x, optional const & y ) | +| >= | | template< typename T >
bool **operator>=*( optional const & x, optional const & y ) | +| Comparison with nullopt | |   | +| == | | template< typename T >
bool **operator==**( optional const & x, nullopt_t ) noexcept | +|   | | template< typename T >
bool **operator==**( nullopt_t, optional const & x ) noexcept | +| != | | template< typename T >
bool **operator!=**( optional const & x, nullopt_t ) noexcept | +|   | | template< typename T >
bool **operator!=**( nullopt_t, optional const & x ) noexcept | +| < | | template< typename T >
bool **operator<**( optional const &, nullopt_t ) noexcept | +|   | | template< typename T >
bool **operator<**( nullopt_t, optional const & x ) noexcept | +| <= | | template< typename T >
bool **operator<=**( optional const & x, nullopt_t ) noexcept | +|   | | template< typename T >
bool **operator<=**( nullopt_t, optional const & ) noexcept | +| > | | template< typename T >
bool **operator>**( optional const & x, nullopt_t ) noexcept | +|   | | template< typename T >
bool **operator>**( nullopt_t, optional const & ) noexcept | +| >= | | template< typename T >
bool **operator>=**( optional const &, nullopt_t ) noexcept | +|   | | template< typename T >
bool **operator>=**( nullopt_t, optional const & x ) noexcept | +| Comparison with T | |   | +| == | | template< typename T >
bool **operator==**( optional const & x, const T& v ) | +|   | | template< typename T >
bool **operator==**( T const & v, optional const & x ) | +| != | | template< typename T >
bool **operator!=**( optional const & x, const T& v ) | +|   | | template< typename T >
bool **operator!=**( T const & v, optional const & x ) | +| < | | template< typename T >
bool **operator<**( optional const & x, const T& v ) | +|   | | template< typename T >
bool **operator<**( T const & v, optional const & x ) | +| <= | | template< typename T >
bool **operator<=**( optional const & x, const T& v ) | +|   | | template< typename T >
bool **operator<=**( T const & v, optional const & x ) | +| > | | template< typename T >
bool **operator>**( optional const & x, const T& v ) | +|   | | template< typename T >
bool **operator>**( T const & v, optional const & x ) | +| >= | | template< typename T >
bool **operator>=**( optional const & x, const T& v ) | +|   | | template< typename T >
bool **operator>=**( T const & v, optional const & x ) | +| Specialized algorithms | |   | +| swap | | template< typename T >
void **swap**( optional & x, optional & y ) noexcept(...) | +| create |
optional<T> **make_optional**( T const & v ) | +|   | C++11| template< class T >
optional< typename std::decay<T>::type > **make_optional**( T && v ) | +|   | C++11| template< class T, class...Args >
optional<T> **make_optional**( Args&&... args ) | +|   | C++11| template< class T, class U, class... Args >
optional<T> **make_optional**( std::initializer_list<U> il, Args&&... args ) | +| hash | C++11| template< class T >
class **hash**< nonstd::optional<T> > | + + +### Configuration + +#### Standard selection macro +\-Doptional\_CPLUSPLUS=199711L +Define this macro to override the auto-detection of the supported C++ standard, if your compiler does not set the `__cplusplus` macro correctly. + +#### Select `std::optional` or `nonstd::optional` +At default, *optional lite* uses `std::optional` if it is available and lets you use it via namespace `nonstd`. You can however override this default and explicitly request to use `std::optional` or optional lite's `nonstd::optional` as `nonstd::optional` via the following macros. + +-Doptional\_CONFIG\_SELECT\_OPTIONAL=optional_OPTIONAL_DEFAULT +Define this to `optional_OPTIONAL_STD` to select `std::optional` as `nonstd::optional`. Define this to `optional_OPTIONAL_NONSTD` to select `nonstd::optional` as `nonstd::optional`. Default is undefined, which has the same effect as defining to `optional_OPTIONAL_DEFAULT`. + +#### Disable exceptions +-Doptional_CONFIG_NO_EXCEPTIONS=0 +Define this to 1 if you want to compile without exceptions. If not defined, the header tries and detect if exceptions have been disabled (e.g. via `-fno-exceptions`). Default is undefined. + +#### Macros to control alignment + +If *optional lite* is compiled as C++11 or later, C++11 alignment facilities are used for storage of the underlying object. When compiled as pre-C++11, *optional lite* tries to determine proper alignment itself. If this doesn't work out, you can control alignment via the following macros. See also section [Implementation notes](#implementation-notes). + +-Doptional_CONFIG_MAX_ALIGN_HACK=0 +Define this to 1 to use the *max align hack* for alignment. Default is 0. + +-Doptional_CONFIG_ALIGN_AS=*pod-type* +Define this to the *pod-type* you want to align to (no default). + +-Doptional_CONFIG_ALIGN_AS_FALLBACK=*pod-type* +Define this to the *pod-type* to use for alignment if the algorithm of *optional lite* cannot find a suitable POD type to use for alignment. Default is double. + + +Comparison of std::optional, optional lite and Boost.Optional +------------------------------------------------------------- + +*optional lite* is inspired on std::optional, which in turn is inspired on Boost.Optional. Here are the significant differences. + +| Aspect | std::optional | optional lite | Boost.Optional | +|-----------------------------------|-----------------------|----------------------|----------------| +| Move semantics | yes | C++11 | no | +| noexcept | yes | C++11 | no | +| Hash support | yes | C++11 | no | +| Throwing value accessor | yes | yes | no | +| Literal type | partially | C++11/14 | no | +| In-place construction | emplace, tag in_place | emplace, tag in_place| utility in_place_factory | +| Disengaged state tag | nullopt | nullopt | none | +| optional references | no | no | yes | +| Conversion from optional<U\>
to optional<T\> | no | no | yes | +| Duplicated interface functions 1) | no | no | yes | +| Explicit convert to ptr (get_ptr) | no | no | yes | + +1) is_initialized(), reset(), get(). + + +Reported to work with +--------------------- +The table below mentions the compiler versions *optional lite* is reported to work with. + +OS | Compiler | Versions | +---------:|:-----------|:---------| +Windows | Clang/LLVM | ? | +  | GCC | 5.2.0 | +  | Visual C++
(Visual Studio)| 8 (2005), 10 (2010), 11 (2012),
12 (2013), 14 (2015), 14 (2017) | +GNU/Linux | Clang/LLVM | 3.5.0, 3.6.0, 7.0.0 | +  | GCC | 4.8.4, 5, 6, 8 | +  | ICC | 19 | +macOS | Xcode | 8.3, 9, 10, 11 | + + +Building the tests +------------------ +To build the tests you need: + +- [CMake](http://cmake.org), version 2.8.12 or later to be installed and in your PATH. +- A [suitable compiler](#reported-to-work-with). + +The [*lest* test framework](https://github.com/martinmoene/lest) is included in the [test folder](test). + +The following steps assume that the [*optional lite* source code](https://github.com/martinmoene/optional-lite) has been cloned into a directory named `c:\optional-lite`. + +1. Create a directory for the build outputs for a particular architecture. +Here we use c:\optional-lite\build-win-x86-vc10. + + cd c:\optional-lite + md build-win-x86-vc10 + cd build-win-x86-vc10 + +2. Configure CMake to use the compiler of your choice (run `cmake --help` for a list). + + cmake -G "Visual Studio 10 2010" -DOPTIONAL_LITE_OPT_BUILD_TESTS=ON .. + +3. Build the test suite in the Debug configuration (alternatively use Release). + + cmake --build . --config Debug + +4. Run the test suite. + + ctest -V -C Debug + +All tests should pass, indicating your platform is supported and you are ready to use *optional lite*. + + +Implementation notes +-------------------- + +### Object allocation and alignment + +*optional lite* reserves POD-type storage for an object of the underlying type inside a union to prevent unwanted construction and uses placement new to construct the object when required. Using non-placement new (malloc) to obtain storage, ensures that the memory is properly aligned for the object's type, whereas that's not the case with placement new. + +If you access data that's not properly aligned, it 1) may take longer than when it is properly aligned (on x86 processors), or 2) it may terminate the program immediately (many other processors). + +Although the C++ standard does not guarantee that all user-defined types have the alignment of some POD type, in practice it's likely they do [8, part 2]. + +If *optional lite* is compiled as C++11 or later, C++11 alignment facilities are used for storage of the underlying object. When compiling as pre-C++11, *optional lite* tries to determine proper alignment using meta programming. If this doesn't work out, you can control alignment via three macros. + +*optional lite* uses the following rules for alignment: + +1. If the program compiles as C++11 or later, C++11 alignment facilities are used. + +2. If you define -Doptional_CONFIG_MAX_ALIGN_HACK=1 the underlying type is aligned as the most restricted type in `struct max_align_t`. This potentially wastes many bytes per optional if the actually required alignment is much less, e.g. 24 bytes used instead of the 2 bytes required. + +3. If you define -Doptional_CONFIG_ALIGN_AS=*pod-type* the underlying type is aligned as *pod-type*. It's your obligation to specify a type with proper alignment. + +4. If you define -Doptional_CONFIG_ALIGN_AS_FALLBACK=*pod-type* the fallback type for alignment of rule 5 below becomes *pod-type*. It's your obligation to specify a type with proper alignment. + +5. At default, *optional lite* tries to find a POD type with the same alignment as the underlying type. + + The algorithm for alignment of 5. is: + - Determine the alignment A of the underlying type using `alignment_of<>`. + - Find a POD type from the list `alignment_types` with exactly alignment A. + - If no such POD type is found, use a type with a relatively strict alignment requirement such as double; this type is specified in `optional_CONFIG_ALIGN_AS_FALLBACK` (default double). + +Note that the algorithm of 5. differs from the one Andrei Alexandrescu uses in [8, part 2]. + +The class template `alignment_of<>` is gleaned from [Boost.TypeTraits, alignment_of](http://www.boost.org/doc/libs/1_57_0/libs/type_traits/doc/html/boost_typetraits/reference/alignment_of.html) [11]. The storage type `storage_t<>` is adapted from the one I created for [spike-expected, expected lite](https://github.com/martinmoene/spike-expected) [13]. + +For more information on constructed unions and alignment, see [8-12]. + + +Other implementations of optional +--------------------------------- +- Isabella Muerte. [MNMLSTC Core](https://github.com/mnmlstc/core) (C++11). +- Andrzej Krzemieński. [optional (nullable) objects for C++14](https://github.com/akrzemi1/Optional). Reference implementation. +- Simon Brand. [C++11/14/17 std::optional with functional-style extensions](https://github.com/TartanLlama/optional). + +Notes and references +-------------------- +[1] CppReference. [Optional](http://en.cppreference.com/w/cpp/utility/optional). + +[2] ISO/IEC WG21. [N4606, section 20.6 Optional objects](http://wg21.link/n4606). July 2016. + +[3] Fernando Cacciola, Andrzej Krzemieński. [A proposal to add a utility class to represent optional objects (Revision 5)](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3793.html). + +[4] Andrzej Krzemieński. [optional (nullable) objects for C++14](https://github.com/akrzemi1/Optional). Reference implementation on GitHub. + +[5] Simon Brand. [P0798R0: Monadic operations for std::optional](https://wg21.tartanllama.xyz/monadic-optional). + +[6] Simon Brand. [C++11/14/17 std::optional with functional-style extensions ](https://github.com/TartanLlama/optional). Reference implementation on GitHub. + +[7] Fernando Cacciola. [Boost.Optional library](http://www.boost.org/doc/libs/1_49_0/libs/optional/doc/html/index.html). + +[8] StackOverflow. [How should one use std::optional?](http://stackoverflow.com/a/16861022). Answer by Timothy Shields. 31 May 2013. + +[9] Fernando Cacciola. [Boost.Optional Quick start guide](http://www.boost.org/doc/libs/1_57_0/libs/optional/doc/html/boost_optional/quick_start.html). + +[10] Andrei Alexandrescu. [Generic: Discriminated Unions part 1](http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/CUJ/2002/cexp2004/alexandr/alexandr.htm), [part 2](http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/CUJ/2002/cexp2006/alexandr/alexandr.htm), [part 3](http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/CUJ/2002/cexp2008/alexandr/alexandr.htm). April 2002. + +[11] Herb Sutter. [Style Case Study #3: Construction Unions](http://www.gotw.ca/gotw/085.htm). GotW #85. 2009 + +[12] Kevin T. Manley. [Using Constructed Types in C++ Unions](http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/CUJ/2002/0208/manley/manley.htm). C/C++ Users Journal, 20(8), August 2002. + +[13] StackOverflow. [Determining maximum possible alignment in C++](http://stackoverflow.com/a/3126992). + +[14] [Boost.TypeTraits, alignment_of](http://www.boost.org/doc/libs/1_57_0/libs/type_traits/doc/html/boost_typetraits/reference/alignment_of.html) ( [code](http://www.boost.org/doc/libs/1_57_0/boost/type_traits/alignment_of.hpp) ). + +[15] Martin Moene. [spike-expected](https://github.com/martinmoene/spike-expected) ([expected-lite.hpp](https://github.com/martinmoene/spike-expected/blob/master/exception_ptr_lite.hpp)). + + +Appendix +-------- + +### A.1 Compile-time information + +The version of *optional 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]`. + +### A.2 Optional Lite test specification + +``` +union: A C++03 union can only contain POD types +optional: Allows to default construct an empty optional (1a) +optional: Allows to explicitly construct a disengaged, empty optional via nullopt (1b) +optional: Allows to default construct an empty optional with a non-default-constructible (1a) +optional: Allows to copy-construct from empty optional (2) +optional: Allows to move-construct from empty optional (C++11, 3) +optional: Allows to copy-construct from empty optional, explicit converting (C++11, 4a) +optional: Allows to copy-construct from empty optional, non-explicit converting (4b) +optional: Allows to move-construct from empty optional, explicit converting (C++11, 5a) +optional: Allows to move-construct from empty optional, non-explicit converting (C++11, 5a) +optional: Allows to copy-construct from non-empty optional (2) +optional: Allows to copy-construct from non-empty optional, explicit converting (C++11, 4a) +optional: Allows to copy-construct from non-empty optional, non-explicit converting (4b) +optional: Allows to move-construct from non-empty optional (C++11, 3) +optional: Allows to move-construct from non-empty optional, explicit converting (C++11, 5a) +optional: Allows to move-construct from non-empty optional, non-explicit converting (C++11, 5b) +optional: Allows to copy-construct from literal value (8) +optional: Allows to copy-construct from literal value, converting (8) +optional: Allows to copy-construct from value (8) +optional: Allows to copy-construct from value, converting (8) +optional: Allows to move-construct from value (C++11, 8b) +optional: Allows to move-construct from value, explicit converting (C++11, 8a) +optional: Allows to move-construct from value, non-explicit converting (C++11, 8b) +optional: Allows to in-place construct from literal value (C++11, 6) +optional: Allows to in-place copy-construct from value (C++11, 6) +optional: Allows to in-place move-construct from value (C++11, 6) +optional: Allows to in-place copy-construct from initializer-list (C++11, 7) +optional: Allows to in-place move-construct from initializer-list (C++11, 7) +optional: Allows to assign nullopt to disengage (1) +optional: Allows to copy-assign from/to engaged and disengaged optionals (2) +optional: Allows to move-assign from/to engaged and disengaged optionals (C++11, 3) +optional: Allows to copy-assign from/to engaged and disengaged optionals, converting, (5) +optional: Allows to move-assign from/to engaged and disengaged optionals, converting (C++11, 6) +optional: Allows to copy-assign from literal value (4) +optional: Allows to copy-assign from value (4) +optional: Allows to move-assign from value (C++11, 4) +optional: Allows to copy-emplace content from arguments (C++11, 7) +optional: Allows to move-emplace content from arguments (C++11, 7) +optional: Allows to copy-emplace content from intializer-list and arguments (C++11, 8) +optional: Allows to move-emplace content from intializer-list and arguments (C++11, 8) +optional: Allows to swap with other optional (member) +optional: Allows to obtain value via operator->() +optional: Allows to obtain moved-value via operator->() (C++11) +optional: Allows to obtain value via operator*() +optional: Allows to obtain moved-value via operator*() (C++11) +optional: Allows to obtain has_value() via operator bool() +optional: Allows to obtain value via value() +optional: Allows to obtain moved-value via value() (C++11) +optional: Allows to obtain value or default via value_or() +optional: Allows to obtain moved-value or moved-default via value_or() (C++11) +optional: Throws bad_optional_access at disengaged access +optional: Throws bad_optional_access with non-empty what() +optional: Allows to reset content +optional: Allows to swaps engage state and values (non-member) +optional: Provides relational operators +optional: Provides mixed-type relational operators +make_optional: Allows to copy-construct optional +make_optional: Allows to move-construct optional (C++11) +make_optional: Allows to in-place copy-construct optional from arguments (C++11) +make_optional: Allows to in-place move-construct optional from arguments (C++11) +make_optional: Allows to in-place copy-construct optional from initializer-list and arguments (C++11) +make_optional: Allows to in-place move-construct optional from initializer-list and arguments (C++11) +std::hash<>: Allows to obtain hash (C++11) +``` \ No newline at end of file diff --git a/projects/CodeBlocks/Code.cbp b/projects/CodeBlocks/Code.cbp deleted file mode 100644 index 9d35c3b..0000000 --- a/projects/CodeBlocks/Code.cbp +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - diff --git a/projects/CodeBlocks/Code.workspace b/projects/CodeBlocks/Code.workspace deleted file mode 100644 index 377eea8..0000000 --- a/projects/CodeBlocks/Code.workspace +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/ecore.c b/src/ecore.c deleted file mode 100644 index 8633c73..0000000 --- a/src/ecore.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * ecore.c - * - * Provide error message functions for OS-related errors and non-OS-related errors. - * - * Created on 1 July 2011, by Martin Moene - * - * Copyright 2011 Universiteit Leiden - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ - -// header -#include "ecore.h" // header first to check if it's self-contained. - -// system headers -#include // errno -#include // vfprintf() -#include // va_arg() -#include // free() -#include // strdup(), strerror() -//#include // va_arg(), not needed for Win32/gcc/g++, Win32/MSVC8 C/C++ - -// other own headers (none): here, after system headers, to prevent errors in -// our headers to show in the context of system headers. - -// Workaround for gcc -std=c99 -// http://stackoverflow.com/questions/5573775/strdup-error-on-g-with-c0x -#if defined( __GNUC__ ) && (__STDC_VERSION__ >= 199901L ) -extern _CRTIMP char* __cdecl __MINGW_NOTHROW _strdup (const char*) __MINGW_ATTRIB_MALLOC; -#endif - -/** - * local function to encapsulate program path string; - * initializes with dynamic string so that handling (free/dup) is the same everywhere. - */ -static char const * * program_path_ptr( void ) -{ - static const char * program_path = NULL; - - if ( NULL == program_path ) - { - program_path = _strdup( "(program name not set)" ); - } - - return &program_path; -} - -/** - * the program path as set, or default "(...)" if not set. - */ -char const * const error_program_path( void ) -{ - return *program_path_ptr(); -} - -/** - * set program path (filename) for error message prefix; - * return true on error. - */ -int set_error_program_path( char const * const path ) -{ - free( (void*) *program_path_ptr() ); - *program_path_ptr() = _strdup( path ); - - return NULL == *program_path_ptr(); -} - -/** - * format error message, return status; - * for errors from functions that set errno, use os_error(). - * - * Example message: "progname: filename(line): non-numeric line content 'content'". - * - * Usage: exit( error( EXIT_FAILURE, "%s(%d): non-numeric line content '%s'", filename, lineno, content ) ); - */ -int error( int const status, char const * const fmt, ... ) -{ - va_list argptr; - va_start( argptr, fmt ); - (void) fprintf( stderr, "%s: ", error_program_path() ); - (void) vfprintf( stderr, fmt, argptr ); - (void) fprintf( stderr, "\n" ); - va_end( argptr ); - - return status; -} - -/** - * format error message, return status; - * use for errors from functions that set errno; see also error(). - * - * Example message: "progname: cannot open file 'filename': file does not exist". - * - * Usage: exit( error( EXIT_FAILURE, "cannot open file '%s'", path ) ); - */ -int os_error( int const status, char const * const fmt, ... ) -{ - va_list argptr; - va_start( argptr, fmt ); - (void) fprintf( stderr, "%s: ", error_program_path() ); - (void) vfprintf( stderr, fmt, argptr ); - (void) fprintf( stderr, ": %s\n", strerror( errno ) ); - va_end( argptr ); - - return status; -} - -/* - * Compilation and quick functional test. - */ -#ifdef TEST_ERROR - -// -Wall for VC8 generates warnings for system headers :( -// MSVC8-C : cl -W4 -DTEST_ERROR -D_CRT_SECURE_NO_WARNINGS -TC ecore.c -// MSVC8-C++: cl -W4 -DTEST_ERROR -D_CRT_SECURE_NO_WARNINGS -TP ecore.c -// GNU C : gcc -Wall -DTEST_ERROR -std=c99 ecore.c -// GNU C++ : g++ -Wall -DTEST_ERROR ecore.c - -#include "ecore.h" // include guard check - -#ifndef UNUSED -#define UNUSED(x) ((void)(x)) -#endif - -/** - * exercise error(), os_error(). - */ -int main( int argc, char *argv[] ) -{ - UNUSED( argc ); - - (void) error( EXIT_FAILURE, - "this is an error message from funtion '%s()' in file '%s'.", - __FUNCTION__, __FILE__ ); - - (void) set_error_program_path( argv[0] ); - - { - char const * const filename = "non-existing-file.$$$"; - - (void) fopen( filename , "r"); - - return os_error( EXIT_FAILURE, - "in funtion '%s()', failed to open file '%s'", - __FUNCTION__, filename ); - } - - return EXIT_SUCCESS; -} -#endif - -/* - * end of file - */ diff --git a/src/ecore.h b/src/ecore.h deleted file mode 100644 index 6f7b023..0000000 --- a/src/ecore.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * ecore.h - * - * Provide error message functions for OS-related errors and non-OS-related errors. - * - * Created on 1 July 2011, by Martin Moene - * - * Copyright 2011 Universiteit Leiden - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ - -#ifndef UL_STDCLIB_CORE_H_INCLUDED -#define UL_STDCLIB_CORE_H_INCLUDED - -/** - * \mainpage Error handling for standard C library functions - * \copydoc ul_stdclib_error_main - */ - -/** - * \addtogroup ul_stdclib_error Error handling for standard C library functions - * @{ - * \addtogroup ul_stdclib_error_core ecore - * \addtogroup ul_stdclib_error_malloc emalloc - * \addtogroup ul_stdclib_error_stdio estdio - * @} - */ - -/** - * \addtogroup ul_stdclib_error_main Error handling for standard C library functions - * - * This module provides macro's and functions that add error handling to - * standard functions, such as malloc(), fopen(), fprintf(). - * - * The ruling assumption is that a program is exited when an error occurs. - * - * The idea was gleaned from: - * - Brian W. Kernighan and Rob Pike. The Practice of Programming. AddisonWesley, 1999. ISBN 0-201-61586-X. - * - * Currently the module consists of the following submodules: - * - \ref ul_stdclib_error_core - basic error functions - * - \ref ul_stdclib_error_malloc - error handling for functions such as malloc(), realloc() and free() - * - \ref ul_stdclib_error_stdio - error handling for functions such as fopen(), fclose() and fprintf() - * - *
- * Created on 1 July 2011, by Martin Moene - * - * Copyright 2011 Universiteit Leiden - * - * This software is distributed under the Boost Software License, Version 1.0. - * See http://www.boost.org/LICENSE_1_0.txt - */ - -/** - * \file - * \addtogroup ul_stdclib_error_core - * - * This module provides macro's and functions to simplify the addition of - * error handling to standard functions, such as malloc(), fopen(), fprintf(). - * - * The ruling assumption is that a program is exited when an error occurs. - * - * The idea was gleaned from: - * - Brian W. Kernighan and Rob Pike. The Practice of Programming. AddisonWesley, 1999. ISBN 020161586X. - * - * ecore.h provides that basic tools to create error functions. See estdio.h and - * emalloc.h for function-specific solutions. - * - * Basic usage is as follows. - * \include ex-ecore.c - * - * @{ - */ - -#if defined ( __cplusplus ) -extern "C" { -#endif - -/** - * the program path as set, or default "(...)" if not set. - */ -char const * const error_program_path( void ); - -/** - * set program path (filename) for error message prefix; - * return true on error. - */ -int set_error_program_path( char const * const path ); - -/** - * format error message, return status; - * for errors from functions that set errno, use os_error(). - * - * Example message: "progname: filename(line): non-numeric line content 'content'". - * - * Usage: exit( error( EXIT_FAILURE, "%s(%d): non-numeric line content '%s'", filename, lineno, content ) ); - */ -int error( int const status, char const * const fmt, ... ); - -/** - * format error message, return status; - * use for errors from functions that set errno; see also error(). - * - * Example message: "progname: cannot open file 'filename': file does not exist". - * - * Usage: exit( error( EXIT_FAILURE, "cannot open file '%s'", path ) ); - */ -int os_error( int const status, char const * const fmt, ... ); - -/** @} */ - -#if defined ( __cplusplus ) -} // extern "C" { -#endif - -#endif // UL_STDCLIB_CORE_H_INCLUDED - -/* - * end of file - */ diff --git a/src/emalloc.c b/src/emalloc.c deleted file mode 100644 index dd1aa38..0000000 --- a/src/emalloc.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * emalloc.c - * - * Provide error checked version of function from malloc.h. - * - * Created on 3 July 2011, by Martin Moene - * - * Copyright 2011 Universiteit Leiden - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ - -// header -#include "emalloc.h" - -// system include files -#include // errno -#include // malloc(), free() - -// other own include files -#include "ecore.h" - -/** - * malloc with error handling (no error location); exit on error. - */ -void * emalloc( size_t bytes, char const * const var ) -{ - void * p = malloc( bytes ); - - if ( NULL == p ) - { - exit( os_error( EXIT_FAILURE, "failed to allocate %u bytes for variable '%s'", bytes, var ) ); - } - - return p; -} - -/** - * realloc with error handling (no error location); exit on error. - */ -void * erealloc( void * p, size_t bytes, char const * const var ) -{ - void * p_new = realloc( p, bytes ); - - if ( NULL == p_new ) - { - exit( os_error( EXIT_FAILURE, "failed to reallocate %u bytes for variable '%s'", bytes, var ) ); - } - - return p_new; -} - -/** - * free with error handling (no error location); exit on error. - */ -void efree( void * p, char const * const var ) -{ - free( p ); - - if ( errno ) - { - exit( os_error( EXIT_FAILURE, "failed to free memory for variable '%s'", var ) ); - } -} - -/** - * malloc with error handling (includes error location); exit on error. - */ -void * emalloc_loc( size_t bytes, char const * const var, char const * const filename, char const * const function, int const line ) -{ - void * p = malloc( bytes ); - - if ( NULL == p ) - { - exit( os_error( EXIT_FAILURE, "%s(%i): in function '%s()' failed to allocate %u bytes for variable '%s'", filename, line, function, bytes, var ) ); - } - - return p; -} - -/** - * realloc with error handling (includes error location); exit on error. - */ -void * erealloc_loc( void * p, size_t bytes, char const * const var, char const * const filename, char const * const function, int const line ) -{ - void * p_new = realloc( p, bytes ); - - if ( NULL == p_new ) - { - exit( os_error( EXIT_FAILURE, "%s(%i): in function '%s()' failed to reallocate %u bytes for variable '%s'", filename, line, function, bytes, var ) ); - } - - return p_new; -} - -/** - * free with error handling (includes error location); exit on error. - */ -void efree_loc( void * p, char const * const var, char const * const filename, char const * const function, int const line ) -{ - free( p ); - - if ( errno ) - { - exit( os_error( EXIT_FAILURE, "%s(%i): in function '%s()' failed to free memory for variable '%s'", filename, line, function, var ) ); - } -} - - -#ifdef TEST_EMALLOC -// -Wall for VC8 generates warnings for system headers :( -// MSVC8-C : cl -W4 -DTEST_EMALLOC -D_CRT_SECURE_NO_WARNINGS -TC emalloc.c ecore.c -// MSVC8-C++: cl -W4 -DTEST_EMALLOC -D_CRT_SECURE_NO_WARNINGS -TP emalloc.c ecore.c -// GNU C : gcc -Wall -DTEST_EMALLOC -std=c99 emalloc.c ecore.c -// GNU C++ : g++ -Wall -DTEST_EMALLOC emalloc.c ecore.c - -#include "emalloc.h" // include guard check - -#ifndef UNUSED -#define UNUSED(x) ((void)(x)) -#endif - -/** - * exercise EMALLOC(), EREALLOC(), EFREE(). - */ -int main( int argc, char *argv[] ) -{ - UNUSED( argc ); - - set_error_program_path( argv[0] ); - - { - void * p = EMALLOC( 123, p ); - p = EREALLOC( p, 512 ); - EFREE( p ); - } - - return EXIT_SUCCESS; -} - -#endif diff --git a/src/emalloc.h b/src/emalloc.h deleted file mode 100644 index 7d4655c..0000000 --- a/src/emalloc.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * emalloc.h - * - * Provide error checked version of function from malloc.h. - * - * Created on 3 July 2011, by Martin Moene - * - * Copyright 2011 Universiteit Leiden - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ - -#ifndef UL_STDCLIB_EMALLOC_H_INCLUDED -#define UL_STDCLIB_EMALLOC_H_INCLUDED - -#include // size_t - -/** - * \file - * \addtogroup ul_stdclib_error_malloc - * - * This module provides macro's and functions that add error handling to the - * standard memory allocation functions, such as malloc(), realloc() and free(). - * - * The ruling assumption is that a program is exited when an error occurs. - * - * Example error message: - * \verbatim emalloc.exe: emalloc.c(86): in function 'main()' failed to reallocate 512 bytes for variable 'p': Not enough space\endverbatim - * - * Basic usage is as follows. - * \include ex-emalloc.c - * - * Note: instead of including ecore.h and emalloc.h, you can also include the - * header file error.h to declare all there is in the error module. - * - * @{ - */ - -#if defined ( __cplusplus ) -extern "C" { -#endif - -/** - * malloc with error handling (includes error location); uses emalloc_loc(), exits on error. - */ -#define EMALLOC( size, var ) \ - emalloc_loc( size, #var, __FILE__, __FUNCTION__, __LINE__ ) - -/** - * erealloc with error handling (includes error location); uses erealloc_loc(), exits on error. - */ -#define EREALLOC( var, newsize ) \ - erealloc_loc( var, newsize, #var, __FILE__, __FUNCTION__, __LINE__ ) - -/** - * free with error handling (includes error location); uses efree_loc(), exits on error. - */ -#define EFREE( var ) \ - efree_loc( var, #var, __FILE__, __FUNCTION__, __LINE__ ) - -/** - * malloc with error handling (no error location); exit on error. - */ -void * emalloc( size_t bytes, char const * const var ); - -/** - * realloc with error handling (no error location); exit on error. - */ -void * erealloc( void * p, size_t bytes, char const * const var ); - -/** - * free with error handling (no error location); exit on error. - */ -void efree( void * p, char const * const var ); - -/** - * malloc with error handling (includes error location); exit on error. - */ -void * emalloc_loc( size_t bytes, char const * const var, char const * const filename, char const * const function, int const line ); - -/** - * realloc with error handling (includes error location); exit on error. - */ -void * erealloc_loc( void * p, size_t bytes, char const * const var, char const * const filename, char const * const function, int const line ); - -/** - * free with error handling (includes error location); exit on error. - */ -void efree_loc( void * p, char const * const var, char const * const filename, char const * const function, int const line ); - -/** @} */ - -#if defined ( __cplusplus ) -} // extern "C" { -#endif - -#endif // UL_STDCLIB_EMALLOC_H_INCLUDED - -/* - * end of file - */ - diff --git a/src/error.h b/src/error.h deleted file mode 100644 index 7e44731..0000000 --- a/src/error.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * error.h - * - * Provide error message functions for OS-related errors and non-OS-related errors. - * - * Created on 1 July 2011, by Martin Moene - * - * Copyright 2011 Universiteit Leiden - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ - -#ifndef UL_STDCLIB_ERROR_H_INCLUDED -#define UL_STDCLIB_ERROR_H_INCLUDED - -/** - * \file - * \addtogroup ul_stdclib_error - */ - -#include "ecore.h" -#include "emalloc.h" -#include "estdio.h" - -#endif // UL_STDCLIB_ERROR_H_INCLUDED - -/* - * end of file - */ diff --git a/src/estdio.c b/src/estdio.c deleted file mode 100644 index 26a89fb..0000000 --- a/src/estdio.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * estdio.c - * - * Provide error checked version of function from stdio.h. - * - * Created on 2 July 2011, by Martin Moene - * - * Copyright 2011 Universiteit Leiden - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ - -// header -#include "estdio.h" - -// system include files -#include // va_arg() -#include // EXIT_FAILURE -//#include // va_arg(), not needed for Win32/gcc/g++, Win32/MSVC8 C/C++ - -// other own include files -#include "ecore.h" - -/** - * fopen with error handling; exit on error. - */ -FILE * efopen( char const * const path, char const * const mode ) -{ - FILE * fp = fopen( path, mode ); - - if ( NULL == fp ) - { - exit( os_error( EXIT_FAILURE, "cannot open file '%s', mode '%s'", path, mode ) ); - } - - return fp; -} - -/** - * fclose with error handling; exit on error. - */ -void efclose( FILE * fp, char const * const path ) -{ - if ( EOF == fclose( fp ) ) - { - exit( os_error( EXIT_FAILURE, "cannot close file '%s'", path ) ); - } -} - -/** - * fprintf with error handling; exit on error. - */ -void efprintf( FILE * fp, char const * const filename, char const * const fmt, ... ) -{ - va_list argptr; - va_start( argptr, fmt ); - - if ( 0 > vfprintf( fp, fmt, argptr ) ) - { - exit( os_error( EXIT_FAILURE, "error while writing to file '%s'", filename ) ); - } - - va_end( argptr ); -} - -/** - * fopen with error handling (includes error location); exit on error. - */ -FILE * efopen_loc( char const * const path, char const * const mode, char const * const filename, char const * const function, int const line ) -{ - FILE * fp = fopen( path, mode ); - - if ( NULL == fp ) - { - exit( os_error( EXIT_FAILURE, "%s(%i): in function '%s()' failed to open file '%s', mode '%s'", filename, line, function, path, mode ) ); - } - - return fp; -} - -/** - * fclose with error handling (includes error location); exit on error. - */ -void efclose_loc( FILE * fp, char const * const path, char const * const filename, char const * const function, int const line ) -{ - if ( EOF == fclose( fp ) ) - { - exit( os_error( EXIT_FAILURE, "%s(%i): in function '%s()' failed to close file '%s'", filename, line, function, path ) ); - } -} - -/** - * fprintf with error handling (includes error location); exit on error. - */ -void efprintf_loc( FILE * fp, char const * const path, char const * const filename, char const * const function, int const line , char const * const fmt, ... ) -{ - va_list argptr; - va_start( argptr, fmt ); - - if ( 0 > vfprintf( fp, fmt, argptr ) ) - { - exit( os_error( EXIT_FAILURE, "%s(%i): in function '%s()' failed to write to file '%s'", filename, line, function, path ) ); - } - - va_end( argptr ); -} - - -#ifdef TEST_ESTDIO -// -Wall for VC8 generates warnings for system headers :( -// MSVC8-C : cl -W4 -DTEST_ESTDIO -D_CRT_SECURE_NO_WARNINGS -TC estdio.c ecore.c -// MSVC8-C++: cl -W4 -DTEST_ESTDIO -D_CRT_SECURE_NO_WARNINGS -TP estdio.c ecore.c -// GNU C : gcc -Wall -DTEST_ESTDIO -std=c99 estdio.c ecore.c -// GNU C++ : g++ -Wall -DTEST_ESTDIO estdio.c ecore.c - -#include "estdio.h" // include guard check - -#ifndef UNUSED -#define UNUSED(x) ((void)(x)) -#endif - -/** - * exercise efopen(), efprintf(), efclose(). - */ -int main( int argc, char *argv[] ) -{ - UNUSED( argc ); - - set_error_program_path( argv[0] ); - - EPRINTF0 ( "EPRINTF0: a string without parameters expecting to succeed.\n" ); - EPRINTF ( "EPRINTF: report of N (%i) expecting to succeed.\n", 22 ); - EFPRINTF0( stdout, "stdout", "EFPRINTF0: a string without parameters expecting to succeed.\n" ); - EFPRINTF ( stdout, "stdout", "EFPRINTF: report of N (%i) expecting to succeed.\n", 22 ); - - efprintf ( stdout, "stdout", "efprintf: report of N (%i) expecting to succeed.\n", 33 ); - - // create file namd below as read only to test write-failure: -// { -// char const * const ro_filename = "estdio-test-ro.tmp"; -// -// FILE * ro_fp = efopen( ro_filename, "w" ); -// efprintf( ro_fp, ro_filename, "expecting to fail to report to ro_fp filepointer"); -// efclose( ro_fp, ro_filename ); -// } - - // create file namd below as read only to test write-failure: - { - char const * const ro_filename = "estdio-test-ro.tmp"; - - FILE * ro_fp = EFOPEN( ro_filename, "w" ); - EFPRINTF( ro_fp, ro_filename, "expecting to fail to report to ro_fp filepointer", 0); - EFCLOSE( ro_fp, ro_filename ); - } - - efopen( "estdio-test-non-existing-file.tmp", "r"); - - return EXIT_SUCCESS; -} - -#endif diff --git a/src/estdio.h b/src/estdio.h deleted file mode 100644 index 8e52d19..0000000 --- a/src/estdio.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * estdio.h - * - * Created on 2 July 2011, by Martin Moene - * - * Copyright 2011 Universiteit Leiden - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ - -#ifndef UL_STDCLIB_ESTDIO_H_INCLUDED -#define UL_STDCLIB_ESTDIO_H_INCLUDED - -#include // FILE - -/** - * \file - * \addtogroup ul_stdclib_error_stdio - * - * This module provides macro's and functions that add error handling to several - * standard file functions, such as fopen(), fclose() and fprintf(). - * - * The ruling assumption is that a program is exited when an error occurs. - * - * Example error message: - * \verbatim estdio.exe: estdio.c(147): in function 'main()' failed to open file 'estdio-test-ro.tmp', mode 'w': Permission denied \endverbatim - * - * Basic usage is as follows. - * \include ex-estdio.c - * - * Note: instead of including ecore.h and emalloc.h, you can also include the - * header file error.h to declare all there is in the error module. - * - * @{ - */ - -#if defined ( __cplusplus ) -extern "C" { -#endif - -/** - * fopen with error handling (includes error location); uses efopen_loc(), exits on error. - */ -#define EFOPEN( path, mode ) \ - efopen_loc( path, mode, __FILE__, __FUNCTION__, __LINE__ ) - -/** - * fclose with error handling (includes error location); uses efclose_loc(), exits on error. - */ -#define EFCLOSE( fp, path ) \ - efclose_loc( fp, path, __FILE__, __FUNCTION__, __LINE__ ) - -/** - * fprintf with error handling (includes error location); uses efprintf_loc(), exits on error; - * for printing of string only, see EPRINTF0. - */ -#define EPRINTF( fmt, ... ) \ - efprintf_loc( stdout, "(stdout)", __FILE__, __FUNCTION__, __LINE__, fmt, __VA_ARGS__ ) - -/** - * fprintf with error handling to print a string only (includes error location); uses efprintf_loc(), exits on error; see also EFPRINTF0(). - */ -#define EPRINTF0( fmt ) \ - efprintf_loc( stdout, "(stdout)", __FILE__, __FUNCTION__, __LINE__, fmt ) - -/** - * fprintf with error handling (includes error location); uses efprintf_loc(), exits on error; - * for printing of string only, see EFPRINTF0. - */ -#define EFPRINTF( fp, path, fmt, ... ) \ - efprintf_loc( fp, path, __FILE__, __FUNCTION__, __LINE__, fmt, __VA_ARGS__ ) - -/** - * fprintf with error handling to print a string only (includes error location); uses efprintf_loc(), exits on error. - * - * In standard C, you are not allowed to leave the macro's variable argument out - * entirely; but you are allowed to pass an empty argument. For example, this - * invocation is invalid in ISO C, because there is no comma after the string: - * \code - * #define debug(format, ...) fprintf (stderr, format, __VA_ARGS__) - * debug ("A message") - * \endcode - * See http://gcc.gnu.org/onlinedocs/gcc/Variadic-Macros.html - */ -#define EFPRINTF0( fp, path, fmt ) \ - efprintf_loc( fp, path, __FILE__, __FUNCTION__, __LINE__, fmt ) - -/** - * fopen with error handling (no error location); exit on error. - */ -FILE * efopen( char const * const path, char const * const mode ); - -/** - * fclose with error handling (no error location); exit on error. - */ -void efclose( FILE * fp, char const * const path ); - -/** - * fprintf with error handling (no error location); exit on error. - */ -void efprintf( FILE * fp, char const * const path, char const * const fmt, ... ); - -/** - * fopen with error handling (includes error location); exit on error. - */ -FILE * efopen_loc( char const * const path, char const * const mode, char const * const filename, char const * const function, int const line ); - -/** - * fclose with error handling (includes error location); exit on error. - */ -void efclose_loc( FILE * fp, char const * const path, char const * const filename, char const * const function, int const line ); - -/** - * fprintf with error handling (includes error location); exit on error. - */ -void efprintf_loc( FILE * fp, char const * const path, char const * const filename, char const * const function, int const line , char const * const fmt, ... ); - -/** @} */ - -#if defined ( __cplusplus ) -} // extern "C" { -#endif - -#endif // UL_STDCLIB_ESTDIO_H_INCLUDED - -/* - * end of file - */ - diff --git a/test/estdio-test-ro.tmp b/test/estdio-test-ro.tmp deleted file mode 100644 index 3f931a0..0000000 --- a/test/estdio-test-ro.tmp +++ /dev/null @@ -1 +0,0 @@ -expecting to fail to report to ro_fp filepointer \ No newline at end of file