From 69ac9afcbe367f9bf7a514e2f8a4f13769a88ace Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Tue, 18 Aug 2020 00:17:50 +0200 Subject: [PATCH 01/27] branch started --- .gitattributes | 63 +++++++++ .gitignore | 340 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 403 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore 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..4ce6fdd --- /dev/null +++ b/.gitignore @@ -0,0 +1,340 @@ +## 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 From 3014de027990cfde3db759205a75ce3eebcd2a9e Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Tue, 18 Aug 2020 00:17:58 +0200 Subject: [PATCH 02/27] branch started --- LICENSE_1_0.txt => LICENSE | 0 Makefile.gcc | 57 ------- Makefile.vc | 72 --------- Readme.txt => Readme.md | 4 + crt_proxy_app/crt_proxy_app.c | 7 + crt_proxy_app/crt_proxy_app.h | 5 + crt_proxy_app/crt_proxy_app.sln | 31 ++++ crt_proxy_app/crt_proxy_app.vcxproj | 161 ++++++++++++++++++++ crt_proxy_app/crt_proxy_app.vcxproj.filters | 51 +++++++ mkg++.bat | 1 - mkgcc.bat | 1 - mkvc++.bat | 1 - mkvc.bat | 1 - projects/CodeBlocks/Code.cbp | 51 ------- projects/CodeBlocks/Code.workspace | 6 - src/ecore.c | 2 + src/ecore.h | 4 +- src/estdio.c | 2 + 18 files changed, 265 insertions(+), 192 deletions(-) rename LICENSE_1_0.txt => LICENSE (100%) delete mode 100644 Makefile.gcc delete mode 100644 Makefile.vc rename Readme.txt => Readme.md (96%) create mode 100644 crt_proxy_app/crt_proxy_app.c create mode 100644 crt_proxy_app/crt_proxy_app.h create mode 100644 crt_proxy_app/crt_proxy_app.sln create mode 100644 crt_proxy_app/crt_proxy_app.vcxproj create mode 100644 crt_proxy_app/crt_proxy_app.vcxproj.filters delete mode 100644 mkg++.bat delete mode 100644 mkgcc.bat delete mode 100644 mkvc++.bat delete mode 100644 mkvc.bat delete mode 100644 projects/CodeBlocks/Code.cbp delete mode 100644 projects/CodeBlocks/Code.workspace diff --git a/LICENSE_1_0.txt b/LICENSE similarity index 100% rename from LICENSE_1_0.txt rename to LICENSE 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.txt b/Readme.md similarity index 96% rename from Readme.txt rename to Readme.md index d65aff2..c1fc437 100644 --- a/Readme.txt +++ b/Readme.md @@ -1,3 +1,7 @@ + + +# Original + Provide error checked version of various functions from std C library. Created on 3 July 2011, by Martin Moene diff --git a/crt_proxy_app/crt_proxy_app.c b/crt_proxy_app/crt_proxy_app.c new file mode 100644 index 0000000..0a390cb --- /dev/null +++ b/crt_proxy_app/crt_proxy_app.c @@ -0,0 +1,7 @@ + +#include "crt_proxy_app.h" + +int main() +{ + return 0; +} diff --git a/crt_proxy_app/crt_proxy_app.h b/crt_proxy_app/crt_proxy_app.h new file mode 100644 index 0000000..a581503 --- /dev/null +++ b/crt_proxy_app/crt_proxy_app.h @@ -0,0 +1,5 @@ +#pragma once + +#define _CRT_SECURE_NO_WARNINGS 1 + +#include "../src/ecore.h" \ No newline at end of file diff --git a/crt_proxy_app/crt_proxy_app.sln b/crt_proxy_app/crt_proxy_app.sln new file mode 100644 index 0000000..9d0dbea --- /dev/null +++ b/crt_proxy_app/crt_proxy_app.sln @@ -0,0 +1,31 @@ + +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 +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..7507aff --- /dev/null +++ b/crt_proxy_app/crt_proxy_app.vcxproj @@ -0,0 +1,161 @@ + + + + + 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 + CompileAsC + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + CompileAsC + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + CompileAsC + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + CompileAsC + + + 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..4570470 --- /dev/null +++ b/crt_proxy_app/crt_proxy_app.vcxproj.filters @@ -0,0 +1,51 @@ + + + + + {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 + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {98bfc55c-cd9d-43bf-907f-e03641a2d077} + + + + + Source Files + + + crt_proxy_lib + + + crt_proxy_lib + + + crt_proxy_lib + + + + + Header Files + + + crt_proxy_lib + + + crt_proxy_lib + + + crt_proxy_lib + + + crt_proxy_lib + + + \ 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/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 index 8633c73..4de2660 100644 --- a/src/ecore.c +++ b/src/ecore.c @@ -1,3 +1,5 @@ + +#define _CRT_SECURE_NO_WARNINGS 1 /* * ecore.c * diff --git a/src/ecore.h b/src/ecore.h index 6f7b023..69f60bb 100644 --- a/src/ecore.h +++ b/src/ecore.h @@ -37,7 +37,7 @@ * 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. + * - Brian W. Kernighan and Rob Pike. The Practice of Programming. Addison�Wesley, 1999. ISBN 0-201-61586-X. * * Currently the module consists of the following submodules: * - \ref ul_stdclib_error_core - basic error functions @@ -63,7 +63,7 @@ * 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. + * - Brian W. Kernighan and Rob Pike. The Practice of Programming. Addison�Wesley, 1999. ISBN 0�201�61586�X. * * ecore.h provides that basic tools to create error functions. See estdio.h and * emalloc.h for function-specific solutions. diff --git a/src/estdio.c b/src/estdio.c index 26a89fb..405343e 100644 --- a/src/estdio.c +++ b/src/estdio.c @@ -1,3 +1,5 @@ +#define _CRT_SECURE_NO_WARNINGS 1 + /* * estdio.c * From 3948e958082b9f4d42729ce405773a4b3878d109 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Tue, 18 Aug 2020 10:03:30 +0200 Subject: [PATCH 03/27] added --- LICENSE_DBJ | 28 + crt_proxy_app/crt_proxy_app.c | 4 + crt_proxy_app/crt_proxy_app.sln | 5 + crt_proxy_lib/readme.md | 154 +++ nonstd/optional.h | 1715 +++++++++++++++++++++++++++++++ nonstd/optional_readme.md | 477 +++++++++ src/ecore.c | 2 +- 7 files changed, 2384 insertions(+), 1 deletion(-) create mode 100644 LICENSE_DBJ create mode 100644 crt_proxy_lib/readme.md create mode 100644 nonstd/optional.h create mode 100644 nonstd/optional_readme.md 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/crt_proxy_app/crt_proxy_app.c b/crt_proxy_app/crt_proxy_app.c index 0a390cb..09d786f 100644 --- a/crt_proxy_app/crt_proxy_app.c +++ b/crt_proxy_app/crt_proxy_app.c @@ -1,7 +1,11 @@ #include "crt_proxy_app.h" +/* +* initally ecore.c has/had the main() +* int main() { return 0; } +*/ diff --git a/crt_proxy_app/crt_proxy_app.sln b/crt_proxy_app/crt_proxy_app.sln index 9d0dbea..eee7680 100644 --- a/crt_proxy_app/crt_proxy_app.sln +++ b/crt_proxy_app/crt_proxy_app.sln @@ -5,6 +5,11 @@ 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}" + ProjectSection(SolutionItems) = preProject + ..\Readme.md = ..\Readme.md + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 diff --git a/crt_proxy_lib/readme.md b/crt_proxy_lib/readme.md new file mode 100644 index 0000000..f73d862 --- /dev/null +++ b/crt_proxy_lib/readme.md @@ -0,0 +1,154 @@ + +

crt proxy lib

+ +> Copyright © 2019-2020, Dusan B. Jovanovic (dbj@dbj.org) + +- [1. motivation](#1-motivation) + - [1.1. run-time requirements](#11-run-time-requirements) +- [2. design](#2-design) + - [2.1. returns handling is new error handling policy](#21-returns-handling-is-new-error-handling-policy) + - [2.2. benchmarking policy](#22-benchmarking-policy) +- [3. implementation](#3-implementation) + - [3.1. Dependencies](#31-dependencies) + +## 1. motivation + +- decoupling users from crt legacy issues + - errno based error handling + - crashing on wrong input + - not crashing but returning wrong results, on bad input +- supporting standard C++ users labouring under strict run-time requirements + +### 1.1. run-time requirements +- no std lib +- no throw/try/catch +- no "special" return values +- no returns in arguments +- no special globals +- no magical constants + +## 2. design + +- using C++17 (or better) core language +- no classes +- no inheritance +- logging -- no direct console access + - user provided and defined + - logging function + - logging target +- resilience in the presence of threads + - user provided lock/unlock two functions + +### 2.1. returns handling is new error handling policy + +- null input, empty input or logically wrong input will provoke different responses + - API consuming functions will have to capture that +- based on the metastate paradigm -- [P2192](https://gitlab.com/dbjdbj/valstat/-/blob/07ce13ab26f662c7301a463fee55dc21cbd7a585/P2192R2.md) +- no special return types +- no special return structures beside valstat definitions +```cpp +// 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 +} +``` +- reminder + - template given parameters is a definition + - template definition is a type + - template alias is still a template +- status returned is always `const char *` message + - decoupling users from crt error handling + - message is always already logged +- **future extension**: status returned is handle to the message logged + - that handle will be GUID inside a `const char *` string + +### 2.2. benchmarking policy + +- comparing code is artificial results +- comparing applications is true results + - performance + - size +- Windows Task Manager results are part of benchmarking results + + +## 3. implementation + +- one header and one cpp file + - just include and use + - no lib or dll is built + - 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 C?** +- it is a "cat and mouse" game one has to play with CL.exe to find out which C features are enabled or not + - that might change with each visual studio update. +- we will not use deprecated crt function, whatever that means. + - we will always try and use '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 +``` + +### 3.1. Dependencies + +1. Martin Moene's `nonstd` : `nonstd::optional`. + It allows us to have the optional, minus std lib, minus exceptions. +```cpp +// 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. nonstd::optional permitting. +```cpp +// example +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 value returned + log ( *val ) ; +``` diff --git a/nonstd/optional.h b/nonstd/optional.h new file mode 100644 index 0000000..e4921d0 --- /dev/null +++ b/nonstd/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/nonstd/optional_readme.md b/nonstd/optional_readme.md new file mode 100644 index 0000000..3d57e98 --- /dev/null +++ b/nonstd/optional_readme.md @@ -0,0 +1,477 @@ +# 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/src/ecore.c b/src/ecore.c index 4de2660..060c85e 100644 --- a/src/ecore.c +++ b/src/ecore.c @@ -1,4 +1,4 @@ - +#define TEST_ERROR #define _CRT_SECURE_NO_WARNINGS 1 /* * ecore.c From 88348dc4895f876061e745816cfdcb35b930297c Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Tue, 18 Aug 2020 22:47:06 +0200 Subject: [PATCH 04/27] seems a good start --- crt_proxy_app/crt_proxy_app.c | 11 - crt_proxy_app/crt_proxy_app.cpp | 28 ++ crt_proxy_app/crt_proxy_app.h | 4 +- crt_proxy_app/crt_proxy_app.sln | 3 - crt_proxy_app/crt_proxy_app.vcxproj | 27 +- crt_proxy_app/crt_proxy_app.vcxproj.filters | 29 +- crt_proxy_lib/crt_proxy_lib.cpp | 36 ++ crt_proxy_lib/crt_proxy_lib.h | 125 +++++ crt_proxy_lib/optional_bare.h | 516 ++++++++++++++++++++ crt_proxy_lib/readme.md | 23 +- 10 files changed, 750 insertions(+), 52 deletions(-) delete mode 100644 crt_proxy_app/crt_proxy_app.c create mode 100644 crt_proxy_app/crt_proxy_app.cpp create mode 100644 crt_proxy_lib/crt_proxy_lib.cpp create mode 100644 crt_proxy_lib/crt_proxy_lib.h create mode 100644 crt_proxy_lib/optional_bare.h diff --git a/crt_proxy_app/crt_proxy_app.c b/crt_proxy_app/crt_proxy_app.c deleted file mode 100644 index 09d786f..0000000 --- a/crt_proxy_app/crt_proxy_app.c +++ /dev/null @@ -1,11 +0,0 @@ - -#include "crt_proxy_app.h" - -/* -* initally ecore.c has/had the main() -* -int main() -{ - return 0; -} -*/ diff --git a/crt_proxy_app/crt_proxy_app.cpp b/crt_proxy_app/crt_proxy_app.cpp new file mode 100644 index 0000000..e69e82b --- /dev/null +++ b/crt_proxy_app/crt_proxy_app.cpp @@ -0,0 +1,28 @@ + +#include "crt_proxy_app.h" + +int main( const int argc, char * argv[] ) +{ + namespace cpl = crt_proxy_lib; + + const char* input_ = "ABRA\v\n\f\r\t CA DABRA"; + + auto rezult_ = cpl::strlen(input_); + + static_assert(19 == cpl::strlen("ABRA\v\n\f\r\t CA DABRA").value ); + + static_assert(1 == cpl::strlen("").value ); + + const char* nullstr{}; + + auto [val, stat] = cpl::strlen(nullstr); + + if (!val) + { + // already logged + auto msg = stat; + } + + return 0; +} + diff --git a/crt_proxy_app/crt_proxy_app.h b/crt_proxy_app/crt_proxy_app.h index a581503..916b7bf 100644 --- a/crt_proxy_app/crt_proxy_app.h +++ b/crt_proxy_app/crt_proxy_app.h @@ -1,5 +1,5 @@ #pragma once -#define _CRT_SECURE_NO_WARNINGS 1 +// #define _CRT_SECURE_NO_WARNINGS 1 -#include "../src/ecore.h" \ No newline at end of file +#include "../crt_proxy_lib/crt_proxy_lib.h" \ No newline at end of file diff --git a/crt_proxy_app/crt_proxy_app.sln b/crt_proxy_app/crt_proxy_app.sln index eee7680..2773892 100644 --- a/crt_proxy_app/crt_proxy_app.sln +++ b/crt_proxy_app/crt_proxy_app.sln @@ -6,9 +6,6 @@ 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}" - ProjectSection(SolutionItems) = preProject - ..\Readme.md = ..\Readme.md - EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/crt_proxy_app/crt_proxy_app.vcxproj b/crt_proxy_app/crt_proxy_app.vcxproj index 7507aff..b5d07f3 100644 --- a/crt_proxy_app/crt_proxy_app.vcxproj +++ b/crt_proxy_app/crt_proxy_app.vcxproj @@ -88,7 +88,8 @@ true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - CompileAsC + Default + stdcpp17 Console @@ -103,7 +104,8 @@ true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - CompileAsC + Default + stdcpp17 Console @@ -118,7 +120,8 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - CompileAsC + Default + stdcpp17 Console @@ -133,7 +136,8 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - CompileAsC + Default + stdcpp17 Console @@ -143,18 +147,17 @@ - - - - + + - - - - + + + + + diff --git a/crt_proxy_app/crt_proxy_app.vcxproj.filters b/crt_proxy_app/crt_proxy_app.vcxproj.filters index 4570470..2d574e3 100644 --- a/crt_proxy_app/crt_proxy_app.vcxproj.filters +++ b/crt_proxy_app/crt_proxy_app.vcxproj.filters @@ -9,43 +9,32 @@ {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - {98bfc55c-cd9d-43bf-907f-e03641a2d077} - - Source Files - - + crt_proxy_lib - - crt_proxy_lib - - - crt_proxy_lib + + Source Files Header Files - - crt_proxy_lib - - + crt_proxy_lib - + crt_proxy_lib - + + + crt_proxy_lib - + \ No newline at end of file diff --git a/crt_proxy_lib/crt_proxy_lib.cpp b/crt_proxy_lib/crt_proxy_lib.cpp new file mode 100644 index 0000000..61051ad --- /dev/null +++ b/crt_proxy_lib/crt_proxy_lib.cpp @@ -0,0 +1,36 @@ +#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 + +namespace crt_proxy_lib +{ +// default lock/unlock is no lock/unlock + +// default logging is going to stderr +// reminder: stderr is buffered by default + +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") }; + + // OK metastate + return { ::strlen(input_), {} }; +} + +} // 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..5bf021a --- /dev/null +++ b/crt_proxy_lib/crt_proxy_lib.h @@ -0,0 +1,125 @@ +#ifndef CRT_PROXY_LIB_INC_ +#define CRT_PROXY_LIB_INC_ + +#define CRT_PROXY_LIB_VERSION "0.0.1" + +#undef CRT_PROXY_LIB_NDEBUG +#ifndef _DEBUG +#define CRT_PROXY_LIB_NDEBUG +#endif // !_DEBUG + +// C++ language version detection (C++20 is speculative): + +#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 + +////////////////////////////////////////////////////////////////////////////////////////////////// + +// default lock/unlock is no lock / no unlock +// user defined padlock type releases semaphore in destructor +// grabs in constructor +#ifndef CRT_PROXY_LIB_PADLOCK +#define CRT_PROXY_LIB_PADLOCK +#endif // ! CRT_PROXY_LIB_LOCK + + +// default logging is going to stderr +// reminder: stderr is buffered by default +// usage pattern is: log and return the same message +#ifndef CRT_PROXY_LIB_LOG +#define CRT_PROXY_LIB_LOG(M_) ( fprintf( stderr, "%s(%d) : %s() : %s", __FILE__ , __LINE__, __func__, M_ ), M_ ) +#endif // ! CRT_PROXY_LIB_LOCK + +////////////////////////////////////////////////////////////////////////////////////////////////// + +/* 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 +#include "optional_bare.h" + +namespace crt_proxy_lib +{ + // any 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 +// +////////////////////////////////////////////////////////////////////////////////////////////////// + +// NOTE: we do use CRT names in this namespace and that compiles +// which means these names can not be used without namespace prefix +// of course one can and will do something like +// namespace cpl = crt_proxy_lib; + +// strlen overloads +// unlike CRT we can use overloads here +// notice the argument type required so overloads bellow are captured +// 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; + +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 +dbj::valstat +strlen ( const char (*str)[N] ) noexcept +{ + return { N, {} }; // OK metastate +} + +template +constexpr inline +dbj::valstat +strlen ( const char (&str)[N] ) noexcept +{ + return { N, {} }; // OK metastate +} + +////////////////////////////////////////////////////////////////////////////////////////////////// + + +} // namespace crt_proxy_lib + +#endif // CRT_PROXY_LIB_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 index f73d862..cf6d068 100644 --- a/crt_proxy_lib/readme.md +++ b/crt_proxy_lib/readme.md @@ -29,10 +29,25 @@ ## 2. design -- using C++17 (or better) core language -- no classes -- no inheritance -- logging -- no direct console access +- standard C++ (17 or better) core language + - no classes + - no inheritance + - overloads are ok and are inside +```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 +- **logging** -- no direct console access - user provided and defined - logging function - logging target From ddaeb4f818eba1849e7dadf690aa83615ed8bfb9 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Wed, 19 Aug 2020 17:41:32 +0200 Subject: [PATCH 05/27] not seeing a log if SILENT requested in setup --- .gitmodules | 3 +++ crt_proxy_app/dbj--simplelog | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 crt_proxy_app/dbj--simplelog 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/crt_proxy_app/dbj--simplelog b/crt_proxy_app/dbj--simplelog new file mode 160000 index 0000000..53d7a8b --- /dev/null +++ b/crt_proxy_app/dbj--simplelog @@ -0,0 +1 @@ +Subproject commit 53d7a8bc6aa96d48362a639ac9fcbd681a011904 From c48729bdc506cbc554b9a19fd84fd3b4c3aa4d94 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Wed, 19 Aug 2020 17:41:51 +0200 Subject: [PATCH 06/27] updated --- .gitignore | 3 +++ crt_proxy_app/crt_proxy_app.cpp | 23 ++++++++++++++++----- crt_proxy_app/crt_proxy_app.h | 5 ++++- crt_proxy_app/crt_proxy_app.vcxproj | 4 ++++ crt_proxy_app/crt_proxy_app.vcxproj.filters | 12 +++++++++++ 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 4ce6fdd..a16bc82 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +## DBJ added +*.filters +*.user ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## diff --git a/crt_proxy_app/crt_proxy_app.cpp b/crt_proxy_app/crt_proxy_app.cpp index e69e82b..ea6470f 100644 --- a/crt_proxy_app/crt_proxy_app.cpp +++ b/crt_proxy_app/crt_proxy_app.cpp @@ -1,17 +1,17 @@ #include "crt_proxy_app.h" -int main( const int argc, char * argv[] ) +static inline void test_strlen() { - namespace cpl = crt_proxy_lib; + namespace cpl = crt_proxy_lib; const char* input_ = "ABRA\v\n\f\r\t CA DABRA"; auto rezult_ = cpl::strlen(input_); - static_assert(19 == cpl::strlen("ABRA\v\n\f\r\t CA DABRA").value ); + static_assert(19 == cpl::strlen("ABRA\v\n\f\r\t CA DABRA").value); - static_assert(1 == cpl::strlen("").value ); + static_assert(1 == cpl::strlen("").value); const char* nullstr{}; @@ -23,6 +23,19 @@ int main( const int argc, char * argv[] ) auto msg = stat; } - return 0; +} + +int main( const int argc, char * argv[] ) +{ + if (EXIT_SUCCESS == dbj_simple_log_startup( argv[0] )) + { + auto lfp = current_log_file_path(); + + FILE* fp_ = dbj_fhandle_log_file_ptr(NULL); + + if (fp_) { ::fclose(fp_); fp_ = nullptr; } + } + else + return EXIT_FAILURE; } diff --git a/crt_proxy_app/crt_proxy_app.h b/crt_proxy_app/crt_proxy_app.h index 916b7bf..c892a6e 100644 --- a/crt_proxy_app/crt_proxy_app.h +++ b/crt_proxy_app/crt_proxy_app.h @@ -2,4 +2,7 @@ // #define _CRT_SECURE_NO_WARNINGS 1 -#include "../crt_proxy_lib/crt_proxy_lib.h" \ No newline at end of file +#include "../crt_proxy_lib/crt_proxy_lib.h" + +#define DBJ_LOG_TESTING +#include "dbj--simplelog/log.h" \ No newline at end of file diff --git a/crt_proxy_app/crt_proxy_app.vcxproj b/crt_proxy_app/crt_proxy_app.vcxproj index b5d07f3..c5b7af4 100644 --- a/crt_proxy_app/crt_proxy_app.vcxproj +++ b/crt_proxy_app/crt_proxy_app.vcxproj @@ -149,11 +149,15 @@ + + + + diff --git a/crt_proxy_app/crt_proxy_app.vcxproj.filters b/crt_proxy_app/crt_proxy_app.vcxproj.filters index 2d574e3..ec7922a 100644 --- a/crt_proxy_app/crt_proxy_app.vcxproj.filters +++ b/crt_proxy_app/crt_proxy_app.vcxproj.filters @@ -20,6 +20,12 @@ Source Files + + Source Files + + + Source Files + @@ -31,6 +37,12 @@ crt_proxy_lib + + Header Files + + + Header Files + From ef5b185290329012df4f05af6aef019d3b2cfab7 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Wed, 19 Aug 2020 17:42:34 +0200 Subject: [PATCH 07/27] updated --- crt_proxy_app/dbj--simplelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crt_proxy_app/dbj--simplelog b/crt_proxy_app/dbj--simplelog index 53d7a8b..5912737 160000 --- a/crt_proxy_app/dbj--simplelog +++ b/crt_proxy_app/dbj--simplelog @@ -1 +1 @@ -Subproject commit 53d7a8bc6aa96d48362a639ac9fcbd681a011904 +Subproject commit 5912737add06ed1fd07dbdc08b3ef5325adc74ca From 104abb6dbd90d56a1fc777725e72a376d2c44a10 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Wed, 19 Aug 2020 18:40:19 +0200 Subject: [PATCH 08/27] WIN32 fflush + commit = ! ugh ... --- crt_proxy_app/crt_proxy_app.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crt_proxy_app/crt_proxy_app.cpp b/crt_proxy_app/crt_proxy_app.cpp index ea6470f..e93b8e5 100644 --- a/crt_proxy_app/crt_proxy_app.cpp +++ b/crt_proxy_app/crt_proxy_app.cpp @@ -32,6 +32,17 @@ int main( const int argc, char * argv[] ) auto lfp = current_log_file_path(); FILE* fp_ = dbj_fhandle_log_file_ptr(NULL); + + assert(fp_); + + int errcode = ferror(fp_); + if (errcode != 0) { + perror( __FILE__ " # " _CRT_STRINGIZE(__LINE__) ); + clearerr_s(fp_); + } + + int numflushed = _flushall(); + fprintf(stderr, "There were %d streams flushed\n", numflushed); if (fp_) { ::fclose(fp_); fp_ = nullptr; } } From 2ff88a157c478137b4b0a0d0625031278cf6465f Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Wed, 19 Aug 2020 18:40:49 +0200 Subject: [PATCH 09/27] updated --- crt_proxy_app/dbj--simplelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crt_proxy_app/dbj--simplelog b/crt_proxy_app/dbj--simplelog index 5912737..4821d6d 160000 --- a/crt_proxy_app/dbj--simplelog +++ b/crt_proxy_app/dbj--simplelog @@ -1 +1 @@ -Subproject commit 5912737add06ed1fd07dbdc08b3ef5325adc74ca +Subproject commit 4821d6d91c94d1093e3cbadc64eba1ee986f9aa4 From eda0201e00a38702590b4000ab84f1bc49feb568 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Wed, 19 Aug 2020 23:14:56 +0200 Subject: [PATCH 10/27] _flushall works + diagnostics added --- crt_proxy_app/crt_proxy_app.cpp | 18 +++++------------- crt_proxy_app/dbj--simplelog | 2 +- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/crt_proxy_app/crt_proxy_app.cpp b/crt_proxy_app/crt_proxy_app.cpp index e93b8e5..a53b280 100644 --- a/crt_proxy_app/crt_proxy_app.cpp +++ b/crt_proxy_app/crt_proxy_app.cpp @@ -27,26 +27,18 @@ static inline void test_strlen() int main( const int argc, char * argv[] ) { - if (EXIT_SUCCESS == dbj_simple_log_startup( argv[0] )) - { - auto lfp = current_log_file_path(); + if (EXIT_SUCCESS != dbj_simple_log_startup(argv[0])) + return EXIT_FAILURE; + auto lfp = current_log_file_path(); FILE* fp_ = dbj_fhandle_log_file_ptr(NULL); - assert(fp_); - - int errcode = ferror(fp_); - if (errcode != 0) { - perror( __FILE__ " # " _CRT_STRINGIZE(__LINE__) ); - clearerr_s(fp_); - } + DBJ_FERROR(fp_); int numflushed = _flushall(); fprintf(stderr, "There were %d streams flushed\n", numflushed); if (fp_) { ::fclose(fp_); fp_ = nullptr; } - } - else - return EXIT_FAILURE; + return EXIT_SUCCESS ; } diff --git a/crt_proxy_app/dbj--simplelog b/crt_proxy_app/dbj--simplelog index 4821d6d..c6739e4 160000 --- a/crt_proxy_app/dbj--simplelog +++ b/crt_proxy_app/dbj--simplelog @@ -1 +1 @@ -Subproject commit 4821d6d91c94d1093e3cbadc64eba1ee986f9aa4 +Subproject commit c6739e4c41cf3264eb2b8c4c53af6227bdb8ddec From 323e2038e4b27a76eb620c7afe4f502bb9d792d3 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Thu, 20 Aug 2020 06:07:27 +0200 Subject: [PATCH 11/27] updated --- crt_proxy_app/dbj--simplelog | 2 +- crt_proxy_lib/crt_proxy_lib.cpp | 68 ++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/crt_proxy_app/dbj--simplelog b/crt_proxy_app/dbj--simplelog index c6739e4..5650a0e 160000 --- a/crt_proxy_app/dbj--simplelog +++ b/crt_proxy_app/dbj--simplelog @@ -1 +1 @@ -Subproject commit c6739e4c41cf3264eb2b8c4c53af6227bdb8ddec +Subproject commit 5650a0e79c71abb15b17ead19ee6f2ecfc96cd8b diff --git a/crt_proxy_lib/crt_proxy_lib.cpp b/crt_proxy_lib/crt_proxy_lib.cpp index 61051ad..8a667b6 100644 --- a/crt_proxy_lib/crt_proxy_lib.cpp +++ b/crt_proxy_lib/crt_proxy_lib.cpp @@ -12,6 +12,56 @@ #include #include #include +/* + crt on winows +------------------------------------------------------------------------------ +Each and every crt function on windows is implemented by calling WIN32 +Using crt is just a shortcut. +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 { @@ -28,7 +78,23 @@ valstat strlen ( const char * & input_ ) noexcept // 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 ca 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_), {} }; } From 4a8cd72d9e3ab8bdd6da8c46657c6c39dc83c182 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Thu, 20 Aug 2020 10:25:01 +0200 Subject: [PATCH 12/27] updated --- crt_proxy_app/crt_proxy_app.cpp | 2 +- crt_proxy_app/crt_proxy_app.h | 5 ++++- crt_proxy_app/crt_proxy_app.vcxproj | 5 ++--- crt_proxy_app/crt_proxy_app.vcxproj.filters | 9 +++------ crt_proxy_app/dbj--simplelog | 2 +- crt_proxy_lib/crt_proxy_lib.cpp | 2 ++ 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/crt_proxy_app/crt_proxy_app.cpp b/crt_proxy_app/crt_proxy_app.cpp index a53b280..cc01d54 100644 --- a/crt_proxy_app/crt_proxy_app.cpp +++ b/crt_proxy_app/crt_proxy_app.cpp @@ -28,8 +28,8 @@ static inline void test_strlen() int main( const int argc, char * argv[] ) { if (EXIT_SUCCESS != dbj_simple_log_startup(argv[0])) - return EXIT_FAILURE; + auto lfp = current_log_file_path(); FILE* fp_ = dbj_fhandle_log_file_ptr(NULL); assert(fp_); diff --git a/crt_proxy_app/crt_proxy_app.h b/crt_proxy_app/crt_proxy_app.h index c892a6e..62f002b 100644 --- a/crt_proxy_app/crt_proxy_app.h +++ b/crt_proxy_app/crt_proxy_app.h @@ -4,5 +4,8 @@ #include "../crt_proxy_lib/crt_proxy_lib.h" +#ifdef _DEBUG #define DBJ_LOG_TESTING -#include "dbj--simplelog/log.h" \ No newline at end of file +#endif + +#include "dbj--simplelog/dbj_simple_log.h" \ No newline at end of file diff --git a/crt_proxy_app/crt_proxy_app.vcxproj b/crt_proxy_app/crt_proxy_app.vcxproj index c5b7af4..2fda089 100644 --- a/crt_proxy_app/crt_proxy_app.vcxproj +++ b/crt_proxy_app/crt_proxy_app.vcxproj @@ -149,15 +149,14 @@ - - + - + diff --git a/crt_proxy_app/crt_proxy_app.vcxproj.filters b/crt_proxy_app/crt_proxy_app.vcxproj.filters index ec7922a..14c1734 100644 --- a/crt_proxy_app/crt_proxy_app.vcxproj.filters +++ b/crt_proxy_app/crt_proxy_app.vcxproj.filters @@ -20,10 +20,7 @@ Source Files - - Source Files - - + Source Files @@ -37,10 +34,10 @@ crt_proxy_lib - + Header Files - + Header Files diff --git a/crt_proxy_app/dbj--simplelog b/crt_proxy_app/dbj--simplelog index 5650a0e..7d2fdc9 160000 --- a/crt_proxy_app/dbj--simplelog +++ b/crt_proxy_app/dbj--simplelog @@ -1 +1 @@ -Subproject commit 5650a0e79c71abb15b17ead19ee6f2ecfc96cd8b +Subproject commit 7d2fdc983d92b7ba9df9b73ce1d4d22c2d96caf7 diff --git a/crt_proxy_lib/crt_proxy_lib.cpp b/crt_proxy_lib/crt_proxy_lib.cpp index 8a667b6..3287121 100644 --- a/crt_proxy_lib/crt_proxy_lib.cpp +++ b/crt_proxy_lib/crt_proxy_lib.cpp @@ -1,3 +1,5 @@ +/* (c) 2019-2020 by dbj.org -- LICENSE DBJ -- https://dbj.org/license_dbj/ */ + #include "crt_proxy_lib.h" #ifdef __STDC_ALLOC_LIB__ From d8a6bca6c1679f62ce98614191eb7555a5237d8e Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Thu, 20 Aug 2020 11:23:43 +0200 Subject: [PATCH 13/27] updated --- crt_proxy_app/crt_proxy_app.cpp | 29 ++++++++++++++++++++--------- crt_proxy_app/dbj--simplelog | 2 +- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/crt_proxy_app/crt_proxy_app.cpp b/crt_proxy_app/crt_proxy_app.cpp index cc01d54..1a48764 100644 --- a/crt_proxy_app/crt_proxy_app.cpp +++ b/crt_proxy_app/crt_proxy_app.cpp @@ -25,20 +25,31 @@ static inline void test_strlen() } +struct dbj_simplelog_finalizer final { + + ~dbj_simplelog_finalizer() { + FILE* fp_ = dbj_fhandle_log_file_ptr(NULL); + if (fp_) { + DBJ_FERROR(fp_); + #ifdef _DEBUG + int numflushed = _flushall(); + fprintf(stderr, "There were %d streams flushed\n", numflushed); + #else + (void)_flushall(); + #endif + if (fp_) { ::fclose(fp_); fp_ = nullptr; } + } + } +}; + +inline dbj_simplelog_finalizer dsf_ ; + int main( const int argc, char * argv[] ) { if (EXIT_SUCCESS != dbj_simple_log_startup(argv[0])) return EXIT_FAILURE; - - auto lfp = current_log_file_path(); - FILE* fp_ = dbj_fhandle_log_file_ptr(NULL); - assert(fp_); - DBJ_FERROR(fp_); - int numflushed = _flushall(); - fprintf(stderr, "There were %d streams flushed\n", numflushed); - - if (fp_) { ::fclose(fp_); fp_ = nullptr; } + test_strlen() ; return EXIT_SUCCESS ; } diff --git a/crt_proxy_app/dbj--simplelog b/crt_proxy_app/dbj--simplelog index 7d2fdc9..624abf5 160000 --- a/crt_proxy_app/dbj--simplelog +++ b/crt_proxy_app/dbj--simplelog @@ -1 +1 @@ -Subproject commit 7d2fdc983d92b7ba9df9b73ce1d4d22c2d96caf7 +Subproject commit 624abf585c6e37f5b4b9197993ee9b00055b3340 From ace80996f43ab1417d5701e079fd4dcb22441d7a Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Thu, 20 Aug 2020 13:47:59 +0200 Subject: [PATCH 14/27] updated --- crt_proxy_app/crt_proxy_app.h | 5 +++++ crt_proxy_app/dbj--simplelog | 2 +- crt_proxy_lib/crt_proxy_lib.cpp | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/crt_proxy_app/crt_proxy_app.h b/crt_proxy_app/crt_proxy_app.h index 62f002b..14fdcea 100644 --- a/crt_proxy_app/crt_proxy_app.h +++ b/crt_proxy_app/crt_proxy_app.h @@ -8,4 +8,9 @@ #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" \ No newline at end of file diff --git a/crt_proxy_app/dbj--simplelog b/crt_proxy_app/dbj--simplelog index 624abf5..1fc2168 160000 --- a/crt_proxy_app/dbj--simplelog +++ b/crt_proxy_app/dbj--simplelog @@ -1 +1 @@ -Subproject commit 624abf585c6e37f5b4b9197993ee9b00055b3340 +Subproject commit 1fc2168718378ec14ecb10868171cc9c9bb2236c diff --git a/crt_proxy_lib/crt_proxy_lib.cpp b/crt_proxy_lib/crt_proxy_lib.cpp index 3287121..f8a5a19 100644 --- a/crt_proxy_lib/crt_proxy_lib.cpp +++ b/crt_proxy_lib/crt_proxy_lib.cpp @@ -18,7 +18,8 @@ crt on winows ------------------------------------------------------------------------------ Each and every crt function on windows is implemented by calling WIN32 -Using crt is just a shortcut. +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. From f1c10167d37074cf80c20e8de6ef179361b62ecc Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Thu, 20 Aug 2020 16:50:52 +0200 Subject: [PATCH 15/27] dbj_log_finalize used --- crt_proxy_app/crt_proxy_app.cpp | 12 +----------- crt_proxy_app/dbj--simplelog | 2 +- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/crt_proxy_app/crt_proxy_app.cpp b/crt_proxy_app/crt_proxy_app.cpp index 1a48764..71f10ae 100644 --- a/crt_proxy_app/crt_proxy_app.cpp +++ b/crt_proxy_app/crt_proxy_app.cpp @@ -28,18 +28,8 @@ static inline void test_strlen() struct dbj_simplelog_finalizer final { ~dbj_simplelog_finalizer() { - FILE* fp_ = dbj_fhandle_log_file_ptr(NULL); - if (fp_) { - DBJ_FERROR(fp_); - #ifdef _DEBUG - int numflushed = _flushall(); - fprintf(stderr, "There were %d streams flushed\n", numflushed); - #else - (void)_flushall(); - #endif - if (fp_) { ::fclose(fp_); fp_ = nullptr; } + dbj_log_finalize(); } - } }; inline dbj_simplelog_finalizer dsf_ ; diff --git a/crt_proxy_app/dbj--simplelog b/crt_proxy_app/dbj--simplelog index 1fc2168..334bb84 160000 --- a/crt_proxy_app/dbj--simplelog +++ b/crt_proxy_app/dbj--simplelog @@ -1 +1 @@ -Subproject commit 1fc2168718378ec14ecb10868171cc9c9bb2236c +Subproject commit 334bb8422bc1994a249a8e158523288e5f68c5c9 From 16c1454e0a6fcc2a6ef7dd465a6beae58d8b8356 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Fri, 21 Aug 2020 09:20:27 +0200 Subject: [PATCH 16/27] logging design and implementation started --- .vscode/settings.json | 7 ++++ crt_proxy_app/crt_proxy_app.h | 3 ++ crt_proxy_lib/crt_proxy_lib.h | 4 +- crt_proxy_lib/crt_proxy_lib_log.h | 70 +++++++++++++++++++++++++++++++ crt_proxy_lib/readme.md | 42 +++++++++++++------ nonstd/optional_readme.md | 2 + 6 files changed, 113 insertions(+), 15 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 crt_proxy_lib/crt_proxy_lib_log.h diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e681dab --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "files.associations": { + "vector": "cpp", + "xstring": "cpp", + "xutility": "cpp" + } +} \ No newline at end of file diff --git a/crt_proxy_app/crt_proxy_app.h b/crt_proxy_app/crt_proxy_app.h index 14fdcea..9b739a0 100644 --- a/crt_proxy_app/crt_proxy_app.h +++ b/crt_proxy_app/crt_proxy_app.h @@ -2,6 +2,9 @@ // #define _CRT_SECURE_NO_WARNINGS 1 +#undef CRT_PROXY_LIB_LOG +#define CRT_PROXY_LIB_LOG(M_) log_error("%s() : %s", __func__, M_ ) + #include "../crt_proxy_lib/crt_proxy_lib.h" #ifdef _DEBUG diff --git a/crt_proxy_lib/crt_proxy_lib.h b/crt_proxy_lib/crt_proxy_lib.h index 5bf021a..4cea76f 100644 --- a/crt_proxy_lib/crt_proxy_lib.h +++ b/crt_proxy_lib/crt_proxy_lib.h @@ -1,7 +1,7 @@ #ifndef CRT_PROXY_LIB_INC_ #define CRT_PROXY_LIB_INC_ -#define CRT_PROXY_LIB_VERSION "0.0.1" +#define CRT_PROXY_LIB_VERSION "0.0.2" #undef CRT_PROXY_LIB_NDEBUG #ifndef _DEBUG @@ -40,7 +40,7 @@ // default logging is going to stderr // reminder: stderr is buffered by default -// usage pattern is: log and return the same message +// requirement is: log and return the same message #ifndef CRT_PROXY_LIB_LOG #define CRT_PROXY_LIB_LOG(M_) ( fprintf( stderr, "%s(%d) : %s() : %s", __FILE__ , __LINE__, __func__, M_ ), M_ ) #endif // ! CRT_PROXY_LIB_LOCK 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..9953a8b --- /dev/null +++ b/crt_proxy_lib/crt_proxy_lib_log.h @@ -0,0 +1,70 @@ +#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/ + +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 * + +The users of crt_proxy_lib need to provide the following six functions. + +// format the message, log it and return it +template +const char * crt_proxy_lib_log_trace( + const char * file, + const long line, + const char * fmt_string, + Args ... args + ); + +#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) +#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) +#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) +#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) +#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) +#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) + +*/ + +#undef CRT_PROXY_LIB_LOG_TRACE +#define CRT_PROXY_LIB_LOG_TRACE(M_) crt_proxy_lib_log_trace( __FILE__ , __LINE__, "%s(%d) : %s() : %s", __func__, M_ ) + +#endif // CRT_PROXY_LIB_LOG_INC_ diff --git a/crt_proxy_lib/readme.md b/crt_proxy_lib/readme.md index cf6d068..b160782 100644 --- a/crt_proxy_lib/readme.md +++ b/crt_proxy_lib/readme.md @@ -4,22 +4,23 @@ > Copyright © 2019-2020, Dusan B. Jovanovic (dbj@dbj.org) - [1. motivation](#1-motivation) - - [1.1. run-time requirements](#11-run-time-requirements) + - [1.1. strict run-time requirements](#11-strict-run-time-requirements) - [2. design](#2-design) - [2.1. returns handling is new error handling policy](#21-returns-handling-is-new-error-handling-policy) - [2.2. benchmarking policy](#22-benchmarking-policy) -- [3. implementation](#3-implementation) - - [3.1. Dependencies](#31-dependencies) +- [3. Logging is important](#3-logging-is-important) +- [4. implementation](#4-implementation) + - [4.1. Dependencies](#41-dependencies) ## 1. motivation -- decoupling users from crt legacy issues - - errno based error handling - - crashing on wrong input - - not crashing but returning wrong results, on bad input -- supporting standard C++ users labouring under strict run-time requirements +- decoupling restricted run-time callers, from crt legacy issues + - CRT legacy issues (non exhaustive list) + 1. errno based error handling + 1. crashing on wrong input + 1. not crashing but returning wrong results, on bad input -### 1.1. run-time requirements +### 1.1. strict run-time requirements - no std lib - no throw/try/catch - no "special" return values @@ -27,6 +28,8 @@ - no special globals - no magical constants +> that list usualy means, restricted run-time apps can not use standard C++ lib + ## 2. design - standard C++ (17 or better) core language @@ -93,8 +96,18 @@ namespace dbj { - size - Windows Task Manager results are part of benchmarking results +## 3. Logging is important + +> In WIN32 parlance module is a component. + +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 just server side apps. Invisible. -## 3. implementation +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. Neither can you. + +## 4. implementation - one header and one cpp file - just include and use @@ -128,10 +141,13 @@ namespace dbj { #endif ``` -### 3.1. Dependencies +### 4.1. Dependencies + +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. -1. Martin Moene's `nonstd` : `nonstd::optional`. - It allows us to have the optional, minus std lib, minus exceptions. ```cpp // nonstd optional #define optional_CONFIG_SELECT_OPTIONAL optional_OPTIONAL_NONSTD diff --git a/nonstd/optional_readme.md b/nonstd/optional_readme.md index 3d57e98..cbb8f08 100644 --- a/nonstd/optional_readme.md +++ b/nonstd/optional_readme.md @@ -1,3 +1,5 @@ + +> 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 From 5fbe502a480f58942b9da9283960e2cc2de014f1 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Fri, 21 Aug 2020 15:11:48 +0200 Subject: [PATCH 17/27] locking and logging concept declared and used --- crt_proxy_app/crt_proxy_app.cpp | 2 + crt_proxy_app/crt_proxy_app.h | 7 +- crt_proxy_app/crt_proxy_app.vcxproj | 2 + crt_proxy_app/crt_proxy_app.vcxproj.filters | 6 ++ crt_proxy_app/dbj--simplelog | 2 +- crt_proxy_lib/crt_proxy_lib.cpp | 2 +- crt_proxy_lib/crt_proxy_lib.h | 46 +++++++++--- crt_proxy_lib/crt_proxy_lib_lock.h | 34 +++++++++ crt_proxy_lib/crt_proxy_lib_log.h | 70 ++++++++++++++----- crt_proxy_lib/crt_proxy_lib_log_default.h | 77 +++++++++++++++++++++ crt_proxy_lib/readme.md | 32 +++++++-- 11 files changed, 243 insertions(+), 37 deletions(-) create mode 100644 crt_proxy_lib/crt_proxy_lib_lock.h create mode 100644 crt_proxy_lib/crt_proxy_lib_log_default.h diff --git a/crt_proxy_app/crt_proxy_app.cpp b/crt_proxy_app/crt_proxy_app.cpp index 71f10ae..4421a27 100644 --- a/crt_proxy_app/crt_proxy_app.cpp +++ b/crt_proxy_app/crt_proxy_app.cpp @@ -1,3 +1,4 @@ +/* (c) 2019-2020 by dbj.org -- LICENSE DBJ -- https://dbj.org/license_dbj/ */ #include "crt_proxy_app.h" @@ -21,6 +22,7 @@ static inline void test_strlen() { // already logged auto msg = stat; + log_warn("Already logged: %s", msg); } } diff --git a/crt_proxy_app/crt_proxy_app.h b/crt_proxy_app/crt_proxy_app.h index 9b739a0..8f157c3 100644 --- a/crt_proxy_app/crt_proxy_app.h +++ b/crt_proxy_app/crt_proxy_app.h @@ -2,9 +2,6 @@ // #define _CRT_SECURE_NO_WARNINGS 1 -#undef CRT_PROXY_LIB_LOG -#define CRT_PROXY_LIB_LOG(M_) log_error("%s() : %s", __func__, M_ ) - #include "../crt_proxy_lib/crt_proxy_lib.h" #ifdef _DEBUG @@ -16,4 +13,6 @@ #define DBJ_LOG_DEFAULT_SETUP DBJ_LOG_DEFAULT_WITH_CONSOLE #endif -#include "dbj--simplelog/dbj_simple_log.h" \ No newline at end of file +#include "dbj--simplelog/dbj_simple_log.h" + + diff --git a/crt_proxy_app/crt_proxy_app.vcxproj b/crt_proxy_app/crt_proxy_app.vcxproj index 2fda089..d72b364 100644 --- a/crt_proxy_app/crt_proxy_app.vcxproj +++ b/crt_proxy_app/crt_proxy_app.vcxproj @@ -153,6 +153,8 @@ + + diff --git a/crt_proxy_app/crt_proxy_app.vcxproj.filters b/crt_proxy_app/crt_proxy_app.vcxproj.filters index 14c1734..c87071d 100644 --- a/crt_proxy_app/crt_proxy_app.vcxproj.filters +++ b/crt_proxy_app/crt_proxy_app.vcxproj.filters @@ -40,6 +40,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/crt_proxy_app/dbj--simplelog b/crt_proxy_app/dbj--simplelog index 334bb84..5f2a43e 160000 --- a/crt_proxy_app/dbj--simplelog +++ b/crt_proxy_app/dbj--simplelog @@ -1 +1 @@ -Subproject commit 334bb8422bc1994a249a8e158523288e5f68c5c9 +Subproject commit 5f2a43e91af6e3263477c81ba7d8551319426027 diff --git a/crt_proxy_lib/crt_proxy_lib.cpp b/crt_proxy_lib/crt_proxy_lib.cpp index f8a5a19..f8320d9 100644 --- a/crt_proxy_lib/crt_proxy_lib.cpp +++ b/crt_proxy_lib/crt_proxy_lib.cpp @@ -80,7 +80,7 @@ valstat strlen ( const char * & input_ ) noexcept if (nullptr == input_) // ERROR metastate // same message is loged and returned - return { {}, CRT_PROXY_LIB_LOG("ERROR : null argument") }; + return { {}, CRT_PROXY_LIB_LOG_TRACE("ERROR : null argument") }; /* MS DOCS are saying: diff --git a/crt_proxy_lib/crt_proxy_lib.h b/crt_proxy_lib/crt_proxy_lib.h index 4cea76f..00cd982 100644 --- a/crt_proxy_lib/crt_proxy_lib.h +++ b/crt_proxy_lib/crt_proxy_lib.h @@ -1,6 +1,8 @@ #ifndef CRT_PROXY_LIB_INC_ #define CRT_PROXY_LIB_INC_ +/* (c) 2019-2020 by dbj.org -- LICENSE DBJ -- https://dbj.org/license_dbj/ */ + #define CRT_PROXY_LIB_VERSION "0.0.2" #undef CRT_PROXY_LIB_NDEBUG @@ -31,19 +33,47 @@ ////////////////////////////////////////////////////////////////////////////////////////////////// // default lock/unlock is no lock / no unlock -// user defined padlock type releases semaphore in destructor +// 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 -#define CRT_PROXY_LIB_PADLOCK +#error CRT_PROXY_LIB_PADLOCK is not defined? #endif // ! CRT_PROXY_LIB_LOCK -// default logging is going to stderr -// reminder: stderr is buffered by default -// requirement is: log and return the same message -#ifndef CRT_PROXY_LIB_LOG -#define CRT_PROXY_LIB_LOG(M_) ( fprintf( stderr, "%s(%d) : %s() : %s", __FILE__ , __LINE__, __func__, M_ ), M_ ) -#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 // + ////////////////////////////////////////////////////////////////////////////////////////////////// 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..e897b8f --- /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 +#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 index 9953a8b..078f4ee 100644 --- a/crt_proxy_lib/crt_proxy_lib_log.h +++ b/crt_proxy_lib/crt_proxy_lib_log.h @@ -3,6 +3,22 @@ /* (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 @@ -44,27 +60,47 @@ char * hiragana = "平仮名" ; So we better stick to char * -The users of crt_proxy_lib need to provide the following six functions. +*/ -// format the message, log it and return it -template -const char * crt_proxy_lib_log_trace( - const char * file, - const long line, - const char * fmt_string, - Args ... args - ); +/* +This is a header delivered by users who use dbj--simplelog +https://github.com/dbj-systems/dbj--simplelog +*/ -#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) -#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) -#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) -#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) -#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) -#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) +// 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(M_) crt_proxy_lib_log_trace( __FILE__ , __LINE__, "%s(%d) : %s() : %s", __func__, M_ ) +#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..f6d4034 --- /dev/null +++ b/crt_proxy_lib/crt_proxy_lib_log_default.h @@ -0,0 +1,77 @@ +#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. + + +*/ + +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/readme.md b/crt_proxy_lib/readme.md index b160782..50f146f 100644 --- a/crt_proxy_lib/readme.md +++ b/crt_proxy_lib/readme.md @@ -98,14 +98,34 @@ namespace dbj { ## 3. Logging is important -> In WIN32 parlance module is a component. - 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 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. Neither can you. +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. 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 defined `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 +``` ## 4. implementation @@ -127,8 +147,8 @@ Without logging in place admins can not see what is going on with your component - if no user provided **defaults** are used - no locking - stderr as a log target -- **Which version of C?** -- it is a "cat and mouse" game one has to play with CL.exe to find out which C features are enabled or not +- **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. - we will not use deprecated crt function, whatever that means. - we will always try and use 'safe' versions From dad00fc7eefe83b1b026e27d5b19e0fc6d805749 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Fri, 21 Aug 2020 18:20:23 +0200 Subject: [PATCH 18/27] CRT_PROXY_LIB_VERSION "0.1.0" aka FUP aka First Usable Product --- crt_proxy_app/crt_proxy_app.cpp | 17 +++++++++++--- crt_proxy_app/crt_proxy_app.h | 6 ++--- crt_proxy_app/dbj--simplelog | 2 +- crt_proxy_lib/crt_proxy_lib.cpp | 27 +++++++++++++++++++++-- crt_proxy_lib/crt_proxy_lib.h | 20 +++++++++++++++-- crt_proxy_lib/crt_proxy_lib_log_default.h | 3 +++ crt_proxy_lib/readme.md | 12 +++++----- test/estdio-test-ro.tmp | 1 - 8 files changed, 70 insertions(+), 18 deletions(-) delete mode 100644 test/estdio-test-ro.tmp diff --git a/crt_proxy_app/crt_proxy_app.cpp b/crt_proxy_app/crt_proxy_app.cpp index 4421a27..a1ab2f0 100644 --- a/crt_proxy_app/crt_proxy_app.cpp +++ b/crt_proxy_app/crt_proxy_app.cpp @@ -2,17 +2,19 @@ #include "crt_proxy_app.h" +#define SX(fmt_, x_) log_info("%s : " fmt_, #x_, x_ ) + static inline void test_strlen() { namespace cpl = crt_proxy_lib; const char* input_ = "ABRA\v\n\f\r\t CA DABRA"; - auto rezult_ = cpl::strlen(input_); + SX( "%d", cpl::strlen(input_) ); - static_assert(19 == cpl::strlen("ABRA\v\n\f\r\t CA DABRA").value); + SX("%d" , 19 == cpl::strlen("ABRA\v\n\f\r\t CA DABRA").value); - static_assert(1 == cpl::strlen("").value); + SX("%d" , 1 == cpl::strlen("").value); const char* nullstr{}; @@ -25,6 +27,12 @@ static inline void test_strlen() log_warn("Already logged: %s", msg); } + SX("%s", cpl::strcmp("", "OK").status ); + SX("%s", cpl::strcmp(0, "OK").status ); + + SX( "%d" , *(cpl::strcmp("NOT", "OK").value) ); + SX( "%d" , *(cpl::strcmp("OK", "OK").value) ); + } struct dbj_simplelog_finalizer final { @@ -42,6 +50,9 @@ int main( const int argc, char * argv[] ) return EXIT_FAILURE; test_strlen() ; + + printf("\n\n"); + return EXIT_SUCCESS ; } diff --git a/crt_proxy_app/crt_proxy_app.h b/crt_proxy_app/crt_proxy_app.h index 8f157c3..d724de8 100644 --- a/crt_proxy_app/crt_proxy_app.h +++ b/crt_proxy_app/crt_proxy_app.h @@ -4,9 +4,9 @@ #include "../crt_proxy_lib/crt_proxy_lib.h" -#ifdef _DEBUG -#define DBJ_LOG_TESTING -#endif +//#ifdef _DEBUG +//#define DBJ_LOG_TESTING +//#endif /* we want console while in debug builds */ #ifdef _DEBUG diff --git a/crt_proxy_app/dbj--simplelog b/crt_proxy_app/dbj--simplelog index 5f2a43e..8f67679 160000 --- a/crt_proxy_app/dbj--simplelog +++ b/crt_proxy_app/dbj--simplelog @@ -1 +1 @@ -Subproject commit 5f2a43e91af6e3263477c81ba7d8551319426027 +Subproject commit 8f67679a481f4059352b8b94a76d98b2fdbac147 diff --git a/crt_proxy_lib/crt_proxy_lib.cpp b/crt_proxy_lib/crt_proxy_lib.cpp index f8320d9..91b9dc9 100644 --- a/crt_proxy_lib/crt_proxy_lib.cpp +++ b/crt_proxy_lib/crt_proxy_lib.cpp @@ -80,14 +80,14 @@ valstat strlen ( const char * & input_ ) noexcept if (nullptr == input_) // ERROR metastate // same message is loged and returned - return { {}, CRT_PROXY_LIB_LOG_TRACE("ERROR : null argument") }; + 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 ca allways return INFO metastate +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); @@ -102,4 +102,27 @@ errno on proper arguments given, which we check here anyway. 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_) , {} }; +} +////////////////////////////////////////////////////////////////////////////////////////// + } // 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 index 00cd982..548485b 100644 --- a/crt_proxy_lib/crt_proxy_lib.h +++ b/crt_proxy_lib/crt_proxy_lib.h @@ -3,7 +3,7 @@ /* (c) 2019-2020 by dbj.org -- LICENSE DBJ -- https://dbj.org/license_dbj/ */ -#define CRT_PROXY_LIB_VERSION "0.0.2" +#define CRT_PROXY_LIB_VERSION "0.1.0" #undef CRT_PROXY_LIB_NDEBUG #ifndef _DEBUG @@ -147,8 +147,24 @@ 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') ; +} +////////////////////////////////////////////////////////////////////////////////////////////////// +valstat< int > strcmp(const char* lhs_, const char* rhs_); } // namespace crt_proxy_lib diff --git a/crt_proxy_lib/crt_proxy_lib_log_default.h b/crt_proxy_lib/crt_proxy_lib_log_default.h index f6d4034..10b6d1a 100644 --- a/crt_proxy_lib/crt_proxy_lib_log_default.h +++ b/crt_proxy_lib/crt_proxy_lib_log_default.h @@ -20,6 +20,9 @@ if this header is not defined crt_proxy_lib_log_default.h is used which prints t */ +#include // +#include // _snprintf_s + template inline auto crt_proxy_lib_log_default ( const char* file, diff --git a/crt_proxy_lib/readme.md b/crt_proxy_lib/readme.md index 50f146f..cc00dc4 100644 --- a/crt_proxy_lib/readme.md +++ b/crt_proxy_lib/readme.md @@ -107,12 +107,12 @@ Each data center or just simply server side component will have to have some log 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(...); +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 defined `crt_proxy_lib_log_default.h` is used which defines macros that print to stderr. 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 From 8611c3f9ad3c15fb850f49db249799c312d38d3d Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Fri, 21 Aug 2020 18:21:15 +0200 Subject: [PATCH 19/27] 0.1.0 --- crt_proxy_app/dbj--simplelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crt_proxy_app/dbj--simplelog b/crt_proxy_app/dbj--simplelog index 8f67679..37d903e 160000 --- a/crt_proxy_app/dbj--simplelog +++ b/crt_proxy_app/dbj--simplelog @@ -1 +1 @@ -Subproject commit 8f67679a481f4059352b8b94a76d98b2fdbac147 +Subproject commit 37d903e9451857d367899a94da870ace851e6b1c From a7376c098734bf63e0364247793f8143cf4410e7 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Fri, 21 Aug 2020 23:46:14 +0200 Subject: [PATCH 20/27] full string.h set of proxies asses but function interanls are not implemented --- crt_proxy_lib/crt_proxy_lib.cpp | 55 +++++++++++-- crt_proxy_lib/crt_proxy_lib.h | 139 +++++++++++++++++++++++++++++++- 2 files changed, 187 insertions(+), 7 deletions(-) diff --git a/crt_proxy_lib/crt_proxy_lib.cpp b/crt_proxy_lib/crt_proxy_lib.cpp index 91b9dc9..eab536c 100644 --- a/crt_proxy_lib/crt_proxy_lib.cpp +++ b/crt_proxy_lib/crt_proxy_lib.cpp @@ -14,6 +14,7 @@ #include #include #include +#include /* crt on winows ------------------------------------------------------------------------------ @@ -68,11 +69,6 @@ if (ferror(FP_) != 0) {\ namespace crt_proxy_lib { -// default lock/unlock is no lock/unlock - -// default logging is going to stderr -// reminder: stderr is buffered by default - valstat strlen ( const char * & input_ ) noexcept { CRT_PROXY_LIB_PADLOCK; @@ -124,5 +120,54 @@ strcmp(const char* lhs_, const char* rhs_) 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 index 548485b..a20e0bc 100644 --- a/crt_proxy_lib/crt_proxy_lib.h +++ b/crt_proxy_lib/crt_proxy_lib.h @@ -95,11 +95,14 @@ namespace dbj { // 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 { - // any type used. nonstd bare CRT_PROXY_LIB permitting. + // 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 @@ -113,6 +116,11 @@ namespace crt_proxy_lib // 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 // which means these names can not be used without namespace prefix @@ -164,8 +172,135 @@ constexpr bool is_empty(const char(&s_) [N]) noexcept { } ////////////////////////////////////////////////////////////////////////////////////////////////// -valstat< int > strcmp(const char* lhs_, const char* rhs_); +// proxyes 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_ + + + From 04c5941305357e2c5738e85f88bb1e0aad1d7aaa Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Sat, 22 Aug 2020 23:56:12 +0200 Subject: [PATCH 21/27] rearanged and updated --- crt_proxy_lib/readme.md | 112 +++++++++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 36 deletions(-) diff --git a/crt_proxy_lib/readme.md b/crt_proxy_lib/readme.md index cc00dc4..434215f 100644 --- a/crt_proxy_lib/readme.md +++ b/crt_proxy_lib/readme.md @@ -4,38 +4,49 @@ > Copyright © 2019-2020, Dusan B. Jovanovic (dbj@dbj.org) - [1. motivation](#1-motivation) - - [1.1. strict run-time requirements](#11-strict-run-time-requirements) - [2. design](#2-design) - [2.1. returns handling is new error handling policy](#21-returns-handling-is-new-error-handling-policy) - - [2.2. benchmarking policy](#22-benchmarking-policy) -- [3. Logging is important](#3-logging-is-important) -- [4. implementation](#4-implementation) - - [4.1. Dependencies](#41-dependencies) + - [2.2. Logging is important](#22-logging-is-important) +- [3. Implementation details](#3-implementation-details) + - [3.1. Locking](#31-locking) + - [3.3. Code structure details](#33-code-structure-details) + - [3.2. benchmarking attitude](#32-benchmarking-attitude) + - [3.4. Dependencies](#34-dependencies) ## 1. motivation -- decoupling restricted run-time callers, from crt legacy issues - - CRT legacy issues (non exhaustive list) - 1. errno based error handling - 1. crashing on wrong input - 1. not crashing but returning wrong results, on bad input +Circa 2020 C++ is very rarely, if ever, used for application programming. C++ is used for systems programming. + +Who might use this library? Teams wishing to code in standard C++ but who are under limitations, grouped as follows in two sets. + +- Limitations of restricted 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 -### 1.1. strict run-time requirements -- no std lib -- no throw/try/catch -- no "special" return values -- no returns in arguments -- no special globals -- no 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. -> that list usualy means, restricted run-time apps can not use standard C++ lib +- Limitation imposed by crt legacy issues. + - CRT legacy issues (non exhaustive list) + 1. errno based error handling aka using globals + - example: 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. ## 2. design - standard C++ (17 or better) core language - no classes - no inheritance - - overloads are ok and are inside + - overloads are ok and are in use inside. Example: ```cpp template constexpr inline size_t strlen ( const char (*str)[N] ) noexcept @@ -50,15 +61,11 @@ constexpr inline size_t strlen ( const char (&str)[N] ) noexcept } ``` - compile time assertions are used -- **logging** -- no direct console access - - user provided and defined - - logging function - - logging target -- resilience in the presence of threads - - user provided lock/unlock two functions + - `static_assert()` ### 2.1. returns handling is new error handling policy +- 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 - based on the metastate paradigm -- [P2192](https://gitlab.com/dbjdbj/valstat/-/blob/07ce13ab26f662c7301a463fee55dc21cbd7a585/P2192R2.md) @@ -88,15 +95,7 @@ namespace dbj { - **future extension**: status returned is handle to the message logged - that handle will be GUID inside a `const char *` string -### 2.2. benchmarking policy - -- comparing code is artificial results -- comparing applications is true results - - performance - - size -- Windows Task Manager results are part of benchmarking results - -## 3. Logging is important +### 2.2. 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 @@ -126,8 +125,42 @@ defines macros that print to stderr. #include "crt_proxy_lib_log_default.h" #endif ``` +## 3. Implementation details + +### 3.1. Locking -## 4. implementation +This library users may provide resilience in the presence of threads. Either users provide lock/unlock type or there is no locking: +```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 +// defualt is no locking + #ifndef CRT_PROXY_LIB_PADLOCK + #define CRT_PROXY_LIB_PADLOCK + #endif // ! CRT_PROXY_LIB_LOCK +#endif // +``` +Therefore 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.3. Code structure details - one header and one cpp file - just include and use @@ -160,8 +193,15 @@ defines macros that print to stderr. #define _POSIX_C_SOURCE 200809L #endif ``` +### 3.2. benchmarking attitude + +- comparing code is artificial benchmarking +- comparing applications delivers true results for: + - performance + - size +- Windows Task Manager results are part of benchmarking results -### 4.1. Dependencies +### 3.4. Dependencies 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. From bf794468d3acab5acc8ee981e3b68eb57254eab8 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Sat, 22 Aug 2020 23:56:27 +0200 Subject: [PATCH 22/27] updated --- crt_proxy_lib/crt_proxy_lib.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/crt_proxy_lib/crt_proxy_lib.h b/crt_proxy_lib/crt_proxy_lib.h index a20e0bc..2ae6ec7 100644 --- a/crt_proxy_lib/crt_proxy_lib.h +++ b/crt_proxy_lib/crt_proxy_lib.h @@ -3,14 +3,11 @@ /* (c) 2019-2020 by dbj.org -- LICENSE DBJ -- https://dbj.org/license_dbj/ */ -#define CRT_PROXY_LIB_VERSION "0.1.0" - -#undef CRT_PROXY_LIB_NDEBUG -#ifndef _DEBUG -#define CRT_PROXY_LIB_NDEBUG -#endif // !_DEBUG +#ifndef _MSC_VER +#error Sorry ... Windows only. +#endif -// C++ language version detection (C++20 is speculative): +#define CRT_PROXY_LIB_VERSION "0.1.0" #ifndef CRT_PROXY_LIB_CPLUSPLUS # if defined(_MSVC_LANG ) && !defined(__clang__) @@ -30,6 +27,11 @@ #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 @@ -39,12 +41,9 @@ #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 From f2902d7e6f4dc162e7f7e95290cb7bfdd07c3344 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Sun, 23 Aug 2020 04:24:46 +0200 Subject: [PATCH 23/27] more info --- crt_proxy_app/crt_proxy_app.cpp | 3 +-- crt_proxy_app/crt_proxy_app.vcxproj | 4 ++++ crt_proxy_lib/readme.md | 36 +++++++++++++++++++++++------ 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/crt_proxy_app/crt_proxy_app.cpp b/crt_proxy_app/crt_proxy_app.cpp index a1ab2f0..b5963a2 100644 --- a/crt_proxy_app/crt_proxy_app.cpp +++ b/crt_proxy_app/crt_proxy_app.cpp @@ -36,13 +36,12 @@ static inline void test_strlen() } struct dbj_simplelog_finalizer final { - ~dbj_simplelog_finalizer() { dbj_log_finalize(); } }; -inline dbj_simplelog_finalizer dsf_ ; +static dbj_simplelog_finalizer dsf_ ; int main( const int argc, char * argv[] ) { diff --git a/crt_proxy_app/crt_proxy_app.vcxproj b/crt_proxy_app/crt_proxy_app.vcxproj index d72b364..44dc592 100644 --- a/crt_proxy_app/crt_proxy_app.vcxproj +++ b/crt_proxy_app/crt_proxy_app.vcxproj @@ -90,6 +90,7 @@ true Default stdcpp17 + /kernel %(AdditionalOptions) Console @@ -106,6 +107,7 @@ true Default stdcpp17 + /kernel %(AdditionalOptions) Console @@ -122,6 +124,7 @@ true Default stdcpp17 + /kernel %(AdditionalOptions) Console @@ -138,6 +141,7 @@ true Default stdcpp17 + /kernel %(AdditionalOptions) Console diff --git a/crt_proxy_lib/readme.md b/crt_proxy_lib/readme.md index 434215f..39d9655 100644 --- a/crt_proxy_lib/readme.md +++ b/crt_proxy_lib/readme.md @@ -4,18 +4,19 @@ > Copyright © 2019-2020, Dusan B. Jovanovic (dbj@dbj.org) - [1. motivation](#1-motivation) + - [1.1. The CL Kernel Mode](#11-the-cl-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. Logging is important](#22-logging-is-important) - [3. Implementation details](#3-implementation-details) - [3.1. Locking](#31-locking) - - [3.3. Code structure details](#33-code-structure-details) - - [3.2. benchmarking attitude](#32-benchmarking-attitude) + - [3.2. Code structure details](#32-code-structure-details) + - [3.3. benchmarking attitude](#33-benchmarking-attitude) - [3.4. Dependencies](#34-dependencies) ## 1. motivation -Circa 2020 C++ is very rarely, if ever, used for application programming. C++ is used for systems programming. +Circa 2020, C++ is very rarely, if ever, used for application programming. C++ is used for systems programming. Who might use this library? Teams wishing to code in standard C++ but who are under limitations, grouped as follows in two sets. @@ -39,7 +40,20 @@ Very often heap allocation is added to the list above. These limitations often l 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. +Thus all of the above are limiting the design decisions and directly shaping the implementation. + +### 1.1. The CL Kernel Mode + +We might say this library is also for the people who use standard C++ **and** are building using CL /kernel switch. +Here is the 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: Sampling console app, part of this repository, is indeed built with the `/kernel` switch in use. ## 2. design @@ -160,7 +174,7 @@ noexcept // ... the rest goes here ... } ``` -### 3.3. Code structure details +### 3.2. Code structure details - one header and one cpp file - just include and use @@ -183,8 +197,9 @@ noexcept - **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 'safe' versions + - 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__ @@ -193,7 +208,14 @@ noexcept #define _POSIX_C_SOURCE 200809L #endif ``` -### 3.2. benchmarking attitude + +Of course user 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. benchmarking attitude - comparing code is artificial benchmarking - comparing applications delivers true results for: From 66c13eabc13f22fe56f853a56ad25ddfceea6a79 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Sun, 23 Aug 2020 09:51:15 +0200 Subject: [PATCH 24/27] reshuffle --- crt_proxy_lib/readme.md | 61 +++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/crt_proxy_lib/readme.md b/crt_proxy_lib/readme.md index 39d9655..49b20e8 100644 --- a/crt_proxy_lib/readme.md +++ b/crt_proxy_lib/readme.md @@ -2,12 +2,17 @@

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 CL Kernel Mode](#11-the-cl-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. Logging is important](#22-logging-is-important) + - [2.2. For Standard C++ users](#22-for-standard-c-users) + - [2.2.1. True noexcept](#221-true-noexcept) + - [2.3. Logging is important](#23-logging-is-important) - [3. Implementation details](#3-implementation-details) - [3.1. Locking](#31-locking) - [3.2. Code structure details](#32-code-structure-details) @@ -57,26 +62,6 @@ NOTE: Sampling console app, part of this repository, is indeed built with the `/ ## 2. design -- 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.1. returns handling is new error handling policy - no runtime exit, abort or crash @@ -109,7 +94,37 @@ namespace dbj { - **future extension**: status returned is handle to the message logged - that handle will be GUID inside a `const char *` string -### 2.2. Logging is important +### 2.2. 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 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. + +One using CL does not need that. But we know about it and we might use it if necessary. + +### 2.3. 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 @@ -209,7 +224,7 @@ noexcept #endif ``` -Of course user 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. +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: From 9d07fcad9c106547e5596db098ec5f4451a5ce70 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Sun, 23 Aug 2020 17:35:11 +0200 Subject: [PATCH 25/27] pico test added --- crt_proxy_app/crt_proxy_app.cpp | 29 +++----- crt_proxy_app/crt_proxy_app.h | 114 +++++++++++++++++++++++++++++++- crt_proxy_lib/crt_proxy_lib.h | 4 +- 3 files changed, 124 insertions(+), 23 deletions(-) diff --git a/crt_proxy_app/crt_proxy_app.cpp b/crt_proxy_app/crt_proxy_app.cpp index b5963a2..80819c0 100644 --- a/crt_proxy_app/crt_proxy_app.cpp +++ b/crt_proxy_app/crt_proxy_app.cpp @@ -2,36 +2,29 @@ #include "crt_proxy_app.h" -#define SX(fmt_, x_) log_info("%s : " fmt_, #x_, x_ ) +#define SX_FMT(fmt_, x_) log_info("%s : " fmt_, #x_, x_ ) -static inline void test_strlen() +static inline void test_string_h_proxy() { namespace cpl = crt_proxy_lib; const char* input_ = "ABRA\v\n\f\r\t CA DABRA"; - SX( "%d", cpl::strlen(input_) ); + metatest( cpl::strlen(input_) ); - SX("%d" , 19 == cpl::strlen("ABRA\v\n\f\r\t CA DABRA").value); + metatest( cpl::strlen("ABRA\v\n\f\r\t CA DABRA") ); - SX("%d" , 1 == cpl::strlen("").value); + metatest( cpl::strlen("") ); const char* nullstr{}; - auto [val, stat] = cpl::strlen(nullstr); + metatest( cpl::strlen(nullstr) ) ; - if (!val) - { - // already logged - auto msg = stat; - log_warn("Already logged: %s", msg); - } + metatest( cpl::strcmp("", "OK") ); + metatest( cpl::strcmp(0, "OK") ); - SX("%s", cpl::strcmp("", "OK").status ); - SX("%s", cpl::strcmp(0, "OK").status ); - - SX( "%d" , *(cpl::strcmp("NOT", "OK").value) ); - SX( "%d" , *(cpl::strcmp("OK", "OK").value) ); + metatest( cpl::strcmp("NOT", "OK") ); + metatest( cpl::strcmp("OK", "OK") ); } @@ -48,7 +41,7 @@ int main( const int argc, char * argv[] ) if (EXIT_SUCCESS != dbj_simple_log_startup(argv[0])) return EXIT_FAILURE; - test_strlen() ; + test_string_h_proxy() ; printf("\n\n"); diff --git a/crt_proxy_app/crt_proxy_app.h b/crt_proxy_app/crt_proxy_app.h index d724de8..6e62d7f 100644 --- a/crt_proxy_app/crt_proxy_app.h +++ b/crt_proxy_app/crt_proxy_app.h @@ -9,10 +9,118 @@ //#endif /* we want console while in debug builds */ -#ifdef _DEBUG -#define DBJ_LOG_DEFAULT_SETUP DBJ_LOG_DEFAULT_WITH_CONSOLE -#endif +//#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 { + +#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 + { + cout << "\t" << 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 << "\t" << 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\n" << (prompt_ ? prompt_ : ""); + + bool value_state = val_.has_value(); + bool status_state = stat_ != nullptr; + + cout << "\nmetastate: "; + if (value_state && status_state) { cout << VT100_LIGHT_GREEN << "info"; } + if (value_state && !status_state) { cout << "ok"; } + if (!value_state && status_state) { cout << VT100_LIGHT_RED << "error"; } + if (!value_state && !status_state) { cout << VT100_LIGHT_BLUE << "empty"; } + cout << VT100_RESET ; + show_option("Value : ", val_); + show_status("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_lib/crt_proxy_lib.h b/crt_proxy_lib/crt_proxy_lib.h index 2ae6ec7..1642ba1 100644 --- a/crt_proxy_lib/crt_proxy_lib.h +++ b/crt_proxy_lib/crt_proxy_lib.h @@ -140,7 +140,7 @@ constexpr inline // 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 -dbj::valstat +valstat strlen ( const char (*str)[N] ) noexcept { return { N, {} }; // OK metastate @@ -148,7 +148,7 @@ strlen ( const char (*str)[N] ) noexcept template constexpr inline -dbj::valstat +valstat strlen ( const char (&str)[N] ) noexcept { return { N, {} }; // OK metastate From b3e2965281f793b04cd5c8eef28668ab910e51e0 Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Thu, 27 Aug 2020 10:43:16 +0200 Subject: [PATCH 26/27] CRT_PROXY_LIB_VERSION "0.7.0" --- Readme.md | 16 ++- crt_proxy_app/crt_proxy_app.h | 26 ++-- crt_proxy_lib/crt_proxy_lib.h | 13 +- crt_proxy_lib/crt_proxy_lib_lock.h | 2 +- crt_proxy_lib/readme.md | 96 ++++++++------ {nonstd => notinuse}/optional.h | 0 {nonstd => notinuse}/optional_readme.md | 0 src/ecore.c | 158 ----------------------- src/ecore.h | 122 ------------------ src/emalloc.c | 142 -------------------- src/emalloc.h | 103 --------------- src/error.h | 30 ----- src/estdio.c | 164 ------------------------ src/estdio.h | 130 ------------------- 14 files changed, 90 insertions(+), 912 deletions(-) rename {nonstd => notinuse}/optional.h (100%) rename {nonstd => notinuse}/optional_readme.md (100%) delete mode 100644 src/ecore.c delete mode 100644 src/ecore.h delete mode 100644 src/emalloc.c delete mode 100644 src/emalloc.h delete mode 100644 src/error.h delete mode 100644 src/estdio.c delete mode 100644 src/estdio.h diff --git a/Readme.md b/Readme.md index c1fc437..79e8906 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,20 @@ +# What is this repository "doing" ? -# Original +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. diff --git a/crt_proxy_app/crt_proxy_app.h b/crt_proxy_app/crt_proxy_app.h index 6e62d7f..4bb173d 100644 --- a/crt_proxy_app/crt_proxy_app.h +++ b/crt_proxy_app/crt_proxy_app.h @@ -33,6 +33,9 @@ namespace dbj::picotest { + // aim is to produce comma delimited output aka CSV + constexpr auto delimiter_char = ','; + #ifndef VT100_ESC #define VT100_ESC "\x1b[" @@ -70,7 +73,8 @@ namespace dbj::picotest { // return false on empty inline auto show_option = [](const char* prompt_, auto opt_) ->bool { - cout << "\t" << prompt_ << " "; + assert(prompt_); + cout << delimiter_char << prompt_ << " "; if (opt_.has_value()) { cout << opt_.value(); return true; @@ -81,7 +85,7 @@ namespace dbj::picotest { inline auto show_status = [](const char* prompt_, const char* stat_) ->bool { - cout << "\t" << prompt_ << " "; + cout << delimiter_char << prompt_ << " "; if (stat_) { cout << stat_; return true; @@ -94,22 +98,20 @@ namespace dbj::picotest { // status is always const char * inline auto show_metastate = [](const char* prompt_, auto val_, const char* stat_) { - cout << "\n\n" << (prompt_ ? prompt_ : ""); + cout << "\n" << (prompt_ ? prompt_ : ""); bool value_state = val_.has_value(); bool status_state = stat_ != nullptr; - cout << "\nmetastate: "; - if (value_state && status_state) { cout << VT100_LIGHT_GREEN << "info"; } - if (value_state && !status_state) { cout << "ok"; } + 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_BLUE << "empty"; } + if (!value_state && !status_state) { cout << VT100_LIGHT_YELLOW << "empty"; } cout << VT100_RESET ; - show_option("Value : ", val_); - show_status("Status: ", stat_); - cout << "\n"; - - + show_option(" ", val_); + show_status(" ", stat_); +// cout << "\n"; }; // for this to work we must send diff --git a/crt_proxy_lib/crt_proxy_lib.h b/crt_proxy_lib/crt_proxy_lib.h index 1642ba1..16f40da 100644 --- a/crt_proxy_lib/crt_proxy_lib.h +++ b/crt_proxy_lib/crt_proxy_lib.h @@ -7,7 +7,7 @@ #error Sorry ... Windows only. #endif -#define CRT_PROXY_LIB_VERSION "0.1.0" +#define CRT_PROXY_LIB_VERSION "0.7.0" #ifndef CRT_PROXY_LIB_CPLUSPLUS # if defined(_MSVC_LANG ) && !defined(__clang__) @@ -122,18 +122,17 @@ namespace crt_proxy_lib #endif // __cplusplus // NOTE: we do use CRT names in this namespace and that compiles -// which means these names can not be used without namespace prefix -// of course one can and will do something like +// These names can not be used without namespace prefix +// One can and will do something like // namespace cpl = crt_proxy_lib; -// strlen overloads -// unlike CRT we can use overloads here -// notice the argument type required so overloads bellow are captured // 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 @@ -171,7 +170,7 @@ constexpr bool is_empty(const char(&s_) [N]) noexcept { } ////////////////////////////////////////////////////////////////////////////////////////////////// -// proxyes for +// 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); diff --git a/crt_proxy_lib/crt_proxy_lib_lock.h b/crt_proxy_lib/crt_proxy_lib_lock.h index e897b8f..43dc296 100644 --- a/crt_proxy_lib/crt_proxy_lib_lock.h +++ b/crt_proxy_lib/crt_proxy_lib_lock.h @@ -3,7 +3,7 @@ /* (c) 2019-2020 by dbj.org -- LICENSE DBJ -- https://dbj.org/license_dbj/ */ -#define STRICT +#define STRICT 1 #define WIN32_LEAN_AND_MEAN #include diff --git a/crt_proxy_lib/readme.md b/crt_proxy_lib/readme.md index 49b20e8..96cb604 100644 --- a/crt_proxy_lib/readme.md +++ b/crt_proxy_lib/readme.md @@ -3,29 +3,29 @@ > Copyright © 2019-2020, Dusan B. Jovanovic (dbj@dbj.org) > -> LICENSE DBJ -- https://dbj.org/license_dbj/ +> LICENSE_DBJ -- https://dbj.org/license_dbj/ - [1. motivation](#1-motivation) - - [1.1. The CL Kernel Mode](#11-the-cl-kernel-mode) + - [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. For Standard C++ users](#22-for-standard-c-users) - - [2.2.1. True noexcept](#221-true-noexcept) - - [2.3. Logging is important](#23-logging-is-important) + - [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. benchmarking attitude](#33-benchmarking-attitude) + - [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. C++ is used for systems programming. +Circa 2020, C++ is very rarely, if ever, used for application programming. In the Cloud reality, C++ is used for systems programming. -Who might use this library? Teams wishing to code in standard C++ but who are under limitations, grouped as follows in two sets. +Who this library is for? Teams wishing to code in standard C++ but who are under limitations, grouped as follows. -- Limitations of restricted run-time requirements +1. Limitations of run-time requirements - specifically **not allowed to use** any of the following - std lib - throw/try/catch @@ -36,21 +36,21 @@ Who might use this library? Teams wishing to code in standard C++ but who are u 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. -- Limitation imposed by crt legacy issues. - - CRT legacy issues (non exhaustive list) +2. Limitation imposed by crt legacy issues. + - Non exhaustive list 1. errno based error handling aka using globals - - example: pure function can not use 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. +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 CL Kernel Mode +### 1.1. The Windows, CL and Kernel Mode -We might say this library is also for the people who use standard C++ **and** are building using CL /kernel switch. -Here is the table from [further reading](https://docs.microsoft.com/en-us/cpp/build/reference/kernel-create-kernel-mode-binary?view=vs-2019) on-line: +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 | |---------------|------------------| @@ -58,22 +58,25 @@ Here is the table from [further reading](https://docs.microsoft.com/en-us/cpp/bu |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: Sampling console app, part of this repository, is indeed built with the `/kernel` switch in use. +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 -- based on the metastate paradigm -- [P2192](https://gitlab.com/dbjdbj/valstat/-/blob/07ce13ab26f662c7301a463fee55dc21cbd7a585/P2192R2.md) - no special return types -- no special return structures beside valstat definitions + - 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 dbj { +namespace your_company_name_here { template + [[nodiscard]] struct valstat final { using type = valstat ; using value_type = T_; @@ -88,13 +91,15 @@ namespace dbj { - template given parameters is a definition - template definition is a type - template alias is still a template -- status returned is always `const char *` message +- in this library status returned is always `const char *` message - decoupling users from crt error handling - - message is always already logged -- **future extension**: status returned is handle to the message logged + - 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. For Standard C++ users +### 2.2. Built For Standard C++ users - standard C++ (17 or better) core language - no classes @@ -116,21 +121,21 @@ constexpr inline size_t strlen ( const char (&str)[N] ) noexcept - compile time assertions are used - `static_assert()` -#### 2.2.1. True noexcept +#### 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. -One using CL does not need that. But we know about it and we might use it if necessary. +Teams using CL do not need that. But we know about it and we might use it if necessary. -### 2.3. Logging is important +### 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 just server side apps. Invisible. +they are 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. Neither can you. +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 @@ -142,7 +147,7 @@ CRT_PROXY_LIB_LOG_WARN(...); CRT_PROXY_LIB_LOG_ERROR(...); CRT_PROXY_LIB_LOG_FATAL(...); ``` -if this header is not defined `crt_proxy_lib_log_default.h` is used which +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 @@ -158,7 +163,7 @@ defines macros that print to stderr. ### 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: +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 @@ -171,13 +176,13 @@ This library users may provide resilience in the presence of threads. Either use #error CRT_PROXY_LIB_PADLOCK is not defined? #endif // ! CRT_PROXY_LIB_LOCK #else -// defualt is no locking +// default is no locking #ifndef CRT_PROXY_LIB_PADLOCK #define CRT_PROXY_LIB_PADLOCK #endif // ! CRT_PROXY_LIB_LOCK #endif // ``` -Therefore users need to provide `crt_proxy_lib_lock.h` . Each proxy function implementation start in this manner: +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 @@ -193,7 +198,7 @@ noexcept - one header and one cpp file - just include and use - - no lib or dll is built + - 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 @@ -230,28 +235,33 @@ 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. benchmarking attitude +### 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 results are part of benchmarking results +- Windows Task Manager (WTM) results are part of benchmarking results + - did you know WTM has the "energy" column? ### 3.4. Dependencies -Martin Moene's non [standard bare optional](https://github.com/martinmoene/optional-bare). +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. +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. @@ -264,9 +274,10 @@ namespace crt_proxy_lib > ; } ``` -Now we can readily ask the occupancy state; on both value and status. For any value type used. nonstd::optional permitting. +Now we can readily ask the occupancy state; on both value and status. For any value type used. bare optional permitting. ```cpp -// example +// 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 @@ -277,6 +288,7 @@ if ( ! val ) log ( status_msg ) ; // not empty if ( val ) - // use the value returned - log ( *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/nonstd/optional.h b/notinuse/optional.h similarity index 100% rename from nonstd/optional.h rename to notinuse/optional.h diff --git a/nonstd/optional_readme.md b/notinuse/optional_readme.md similarity index 100% rename from nonstd/optional_readme.md rename to notinuse/optional_readme.md diff --git a/src/ecore.c b/src/ecore.c deleted file mode 100644 index 060c85e..0000000 --- a/src/ecore.c +++ /dev/null @@ -1,158 +0,0 @@ -#define TEST_ERROR -#define _CRT_SECURE_NO_WARNINGS 1 -/* - * 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 69f60bb..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. Addison�Wesley, 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. Addison�Wesley, 1999. ISBN 0�201�61586�X. - * - * 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 405343e..0000000 --- a/src/estdio.c +++ /dev/null @@ -1,164 +0,0 @@ -#define _CRT_SECURE_NO_WARNINGS 1 - -/* - * 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 - */ - From e3cda1b9ef09efbdef5a81eff5acea50670304ec Mon Sep 17 00:00:00 2001 From: dbjdbj Date: Fri, 23 Oct 2020 23:33:51 +0200 Subject: [PATCH 27/27] removed --- .vscode/settings.json | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e681dab..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files.associations": { - "vector": "cpp", - "xstring": "cpp", - "xutility": "cpp" - } -} \ No newline at end of file