Skip to content

Commit cdc6b11

Browse files
author
Fytch
committed
change precondition violation exceptions from opt-out to opt-in and make assertions the default
1 parent 5a9445d commit cdc6b11

19 files changed

+94
-88
lines changed

.travis.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,12 +205,6 @@ script:
205205
- $CC --version
206206
- $CXX --version
207207

208-
- mkdir bin_noexcept
209-
- cd bin_noexcept
210-
- cmake .. $CMAKE_FLAGS -DCMAKE_BUILD_TYPE=DEBUG -DCMAKE_C_COMPILER=$CC -DCMAKE_CXX_COMPILER=$CXX -DPROGRAMOPTIONS_BUILD_TEST=OFF -DPROGRAMOPTIONS_NO_EXCEPTIONS=ON
211-
- cmake --build .
212-
- cd ..
213-
214208
- mkdir bin
215209
- cd bin
216210
- cmake .. $CMAKE_FLAGS -DCMAKE_BUILD_TYPE=DEBUG -DCMAKE_C_COMPILER=$CC -DCMAKE_CXX_COMPILER=$CXX

CMakeLists.txt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ add_library(ProgramOptionsHxx INTERFACE)
1313
target_include_directories(ProgramOptionsHxx INTERFACE "${CMAKE_CURRENT_LIST_DIR}/include")
1414

1515
if(PROGRAMOPTIONS_NOT_SUBPROJECT)
16-
option(PROGRAMOPTIONS_NO_EXCEPTIONS "disable exceptions" OFF)
1716
option(PROGRAMOPTIONS_NO_COLORS "disable colored output" OFF)
1817
option(PROGRAMOPTIONS_BUILD_TEST "build test" ON)
1918
option(PROGRAMOPTIONS_BUILD_EXAMPLES "build examples" ON)
@@ -32,15 +31,6 @@ if(PROGRAMOPTIONS_NOT_SUBPROJECT)
3231
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -march=native -DNDEBUG -s -flto")
3332
endif()
3433

35-
if(PROGRAMOPTIONS_NO_EXCEPTIONS)
36-
add_definitions(-DPROGRAMOPTIONS_NO_EXCEPTIONS)
37-
if(PROGRAMOPTIONS_GNU_OPTIONS)
38-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
39-
elseif(PROGRAMOPTIONS_MS_OPTIONS)
40-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
41-
endif()
42-
endif()
43-
4434
if(PROGRAMOPTIONS_NO_COLORS)
4535
add_definitions(-DPROGRAMOPTIONS_NO_COLORS)
4636
endif()

README.md

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ It is highly recommended that you at least briefly skim through the chapters [**
2828
The quickest way to get started is to download *ProgramOptions.hxx* as well as one of the samples and go from there.
2929

3030
### `sample.cxx`
31-
The default choice. Using *ProgramOptions.hxx* incorrectly or failing to meet a function's preconditions will throw an exception which will, by default, terminate the program and display a useful message, explaining where exactly things went wrong.
31+
The default choice. Incorrect usage of *ProgramOptions.hxx*'s API will trigger an assertion which will crash the program in debug mode.
3232

33-
### `sample_noexcept.cxx`
34-
Using this sample is only recommended if you are already somewhat familiar with *ProgramOptions.hxx*. Incorrect programs will crash without any messages unless your STL implementation does so when [`assert`ions](http://en.cppreference.com/w/cpp/error/assert) fail.
33+
### `sample_exceptions.cxx`
34+
In this sample, we [`#define PROGRAMOPTIONS_EXCEPTIONS`](#define-programoptions_exceptions). In consequence, incorrect usage of *ProgramOptions.hxx*'s API will throw an exception both in debug and release mode.
3535

3636
## Design goals
37-
- **Non-intrusive**. Unlike other program option libraries, such as [*Boost.Program_options*](http://www.boost.org/doc/libs/1_63_0/doc/html/program_options.html), *ProgramOptions.hxx* requires neither additional library binaries nor integration into the build process. Just drop in the header, include it and you're all set. *ProgramOptions.hxx* doesn't force you to enable exceptions or RTTI and runs just fine with `-fno-rtti -fno-exceptions` (the latter requires you to [`#define PROGRAMOPTIONS_NO_EXCEPTIONS`](#define-programoptions_no_exceptions) prior to including the header, though).
37+
- **Non-intrusive**. Unlike other program option libraries, such as [*Boost.Program_options*](http://www.boost.org/doc/libs/1_63_0/doc/html/program_options.html), *ProgramOptions.hxx* requires neither additional library binaries nor integration into the build process. Just drop in the header, include it and you're all set. *ProgramOptions.hxx* doesn't force you to enable exceptions or RTTI and runs just fine with `-fno-rtti -fno-exceptions`.
3838
- **Intuitive**. *ProgramOptions.hxx* is designed to feel smooth and blend in well with other modern C++11 code.
3939
- **Correct**. Extensive unit tests and runtime checks contribute to more correct software, both on the side of the user and the developer of *ProgramOptions.hxx*.
4040
- **Permissive**. The [MIT License](https://tldrlegal.com/license/mit-license) under which *ProgramOptions.hxx* is published grants unrestricted freedom.
@@ -85,6 +85,11 @@ target_link_libraries(YourExecutable ProgramOptionsHxx)
8585
```
8686
You must replace ```/third_party/ProgramOptions.hxx``` by the correct path and ```YourExecutable``` by the targets that use *ProgramOptions.hxx*.
8787

88+
You can then include the header by writing:
89+
```cpp
90+
#include <ProgramOptions.hxx>
91+
```
92+
8893
## Usage
8994
Using *ProgramOptions.hxx* is straightforward; we'll explain it by means of practical examples. All examples shown here and more can be found in the [/examples](examples) directory, all of which are well-documented.
9095

@@ -399,22 +404,22 @@ This small table helps clarifying the defaults for the different kinds of option
399404
|`.single` / `.multi` |`.single` |`.single` |`.multi` |
400405
401406
## Flags
402-
All flags have to be `#define`d before including *ProgramOptions.hxx*. Different translation units may include *ProgramOptions.hxx* using different flags.
407+
All flags have to be `#define`d before including *ProgramOptions.hxx*.
403408
404-
### `#define PROGRAMOPTIONS_NO_EXCEPTIONS`
405-
Disables all exceptions and thus allows compilation with `-fno-exceptions`. However, incorrect use of the library and unmet preconditions entail `abort()` via `assert(...)`. This flag is implied by `NDEBUG`.
409+
### `#define PROGRAMOPTIONS_EXCEPTIONS`
410+
When this flag is set, *ProgramOptions.hxx*'s functions' preconditions are validated with exceptions instead of assertions. If a precondition isn't met, an [```std::logic_error```](https://en.cppreference.com/w/cpp/error/logic_error) is thrown whose explanatory strings starts with "ProgramOptions.hxx:*N*:" where *N* is the respective line number.
406411
407-
:exclamation: This flag must not vary across different translation units in order to not violate C++' [one definition rule (ODR)](http://en.cppreference.com/w/cpp/language/definition).
412+
:exclamation: This flag must not vary across different translation units of a single program in order to not violate C++' [one definition rule (ODR)](http://en.cppreference.com/w/cpp/language/definition).
408413
409414
### `#define NDEBUG`
410-
Disables all runtime checks and all exceptions. Incorrect use of the library and unmet preconditions will lead to undefined behaviour. Implies `#define PROGRAMOPTIONS_NO_EXCEPTIONS`.
415+
Setting this flag disables all assertions.
411416
412-
:exclamation: This flag must not vary across different translation units in order to not violate C++' [one definition rule (ODR)](http://en.cppreference.com/w/cpp/language/definition).
417+
:exclamation: This flag must not vary across different translation units of a single program in order to not violate C++' [one definition rule (ODR)](http://en.cppreference.com/w/cpp/language/definition).
413418
414419
### `#define PROGRAMOPTIONS_NO_COLORS`
415-
Disables colored output. On Windows, *ProgramOptions.hxx* uses the WinAPI (i.e. [`SetConsoleTextAttribute`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686047)) to achieve colored console output whereas it uses [ANSI escape codes](http://bluesock.org/~willg/dev/ansi.html) anywhere else.
420+
Setting this flag disables colored output. On Windows, *ProgramOptions.hxx* uses the WinAPI (i.e. [`SetConsoleTextAttribute`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686047)) to achieve colored console output whereas it uses [ANSI escape codes](http://bluesock.org/~willg/dev/ansi.html) anywhere else.
416421
417-
:exclamation: This flag must not vary across different translation units in order to not violate C++' [one definition rule (ODR)](http://en.cppreference.com/w/cpp/language/definition).
422+
:exclamation: This flag must not vary across different translation units of a single program in order to not violate C++' [one definition rule (ODR)](http://en.cppreference.com/w/cpp/language/definition).
418423
419424
## Third-party libraries
420425
- [**Catch**](https://github.com/philsquared/Catch) for unit testing.

include/ProgramOptions.hxx

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,28 +31,25 @@
3131
#include <sstream>
3232
#include <iostream>
3333

34-
#ifndef PROGRAMOPTIONS_NO_EXCEPTIONS
35-
#include <stdexcept>
36-
#endif // !PROGRAMOPTIONS_NO_EXCEPTIONS
37-
3834
#ifndef NDEBUG
3935
#define PROGRAMOPTIONS_DEBUG
4036
#endif // !NDEBUG
4137

4238
#undef PROGRAMOPTIONS_ASSERT
43-
#ifdef NDEBUG
44-
#define PROGRAMOPTIONS_ASSERT(Expression, Message)
45-
#else // NDEBUG
46-
#ifdef PROGRAMOPTIONS_NO_EXCEPTIONS
47-
#define PROGRAMOPTIONS_ASSERT(Expression, Message) assert((Expression) && Message);
48-
#else // PROGRAMOPTIONS_NO_EXCEPTIONS
49-
#define PROGRAMOPTIONS_ASSERT(Expression, Message)\
50-
do {\
51-
if(!(Expression))\
52-
throw std::logic_error{ ("ProgramOptions.hxx:" + std::to_string(__LINE__) + ": ") + (Message) };\
53-
} while(0)
54-
#endif // PROGRAMOPTIONS_NO_EXCEPTIONS
55-
#endif // NDEBUG
39+
#ifdef PROGRAMOPTIONS_EXCEPTIONS
40+
#include <stdexcept>
41+
#define PROGRAMOPTIONS_ASSERT(Expression, Message)\
42+
do {\
43+
if(!(Expression))\
44+
throw std::logic_error{ ("ProgramOptions.hxx:" + std::to_string(__LINE__) + ": ") + (Message) };\
45+
} while(0)
46+
#else // PROGRAMOPTIONS_EXCEPTIONS
47+
#ifdef PROGRAMOPTIONS_DEBUG
48+
#define PROGRAMOPTIONS_ASSERT(Expression, Message) assert(Message && (Expression));
49+
#else // PROGRAMOPTIONS_DEBUG
50+
#define PROGRAMOPTIONS_ASSERT(Expression, Message)
51+
#endif // PROGRAMOPTIONS_DEBUG
52+
#endif // PROGRAMOPTIONS_EXCEPTIONS
5653

5754
#if defined(PROGRAMOPTIONS_WINDOWS) && defined(PROGRAMOPTIONS_ANSI)
5855
#error Please define either PROGRAMOPTIONS_WINDOWS or PROGRAMOPTIONS_ANSI

sample.cxx

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,32 @@
11
#include <ProgramOptions.hxx>
2-
#include <exception>
32
#include <iostream>
43

5-
int main(int argc, char** argv)
6-
try {
4+
int main(int argc, char** argv) {
75
po::parser parser;
8-
parser["help"]
9-
.abbreviation('?')
10-
.description("print this help screen")
11-
.callback([&]{ std::cout << parser << '\n'; });
126

13-
parser["PLACEHOLDER"]
7+
auto& PLACEHOLDER = parser["PLACEHOLDER"]
148
.abbreviation('PLACEHOLDER')
159
.description("PLACEHOLDER")
1610
.type(po::PLACEHOLDER)
1711
.multi()
1812
.fallback(PLACEHOLDER)
1913
.callback([&]{ PLACEHOLDER; });
2014

15+
auto& help = parser["help"]
16+
.abbreviation('?')
17+
.description("print this help screen");
18+
2119
if(!parser(argc, argv)) {
2220
// error
2321
return 1;
2422
}
2523

26-
if(parser["PLACEHOLDER"].available()) {
24+
if(help.was_set()) {
25+
std::cout << parser << '\n';
26+
return 0;
27+
}
28+
29+
if(PLACEHOLDER.available()) {
2730
// do something
2831
}
29-
} catch(std::exception const& e) {
30-
std::cerr << "uncaught exception: " << e.what() << '\n';
31-
std::cerr << "terminating application\n";
32-
return -1;
3332
}

sample_exceptions.cxx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#define PROGRAMOPTIONS_EXCEPTIONS
2+
#include <ProgramOptions.hxx>
3+
#include <exception>
4+
#include <iostream>
5+
6+
int main(int argc, char** argv)
7+
try {
8+
po::parser parser;
9+
10+
auto& PLACEHOLDER = parser["PLACEHOLDER"]
11+
.abbreviation('PLACEHOLDER')
12+
.description("PLACEHOLDER")
13+
.type(po::PLACEHOLDER)
14+
.multi()
15+
.fallback(PLACEHOLDER)
16+
.callback([&]{ PLACEHOLDER; });
17+
18+
auto& help = parser["help"]
19+
.abbreviation('?')
20+
.description("print this help screen");
21+
22+
if(!parser(argc, argv)) {
23+
// error
24+
return 1;
25+
}
26+
27+
if(help.was_set()) {
28+
std::cout << parser << '\n';
29+
return 0;
30+
}
31+
32+
if(PLACEHOLDER.available()) {
33+
// do something
34+
}
35+
} catch(std::exception const& e) {
36+
std::cerr << "uncaught exception: " << e.what() << '\n';
37+
std::cerr << "terminating application\n";
38+
return -1;
39+
}

sample_noexcept.cxx

Lines changed: 0 additions & 28 deletions
This file was deleted.

test/arg_provider.hxx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef arg_provider_hxx_included
22
#define arg_provider_hxx_included
33

4+
#define PROGRAMOPTIONS_EXCEPTIONS
45
#include <ProgramOptions.hxx>
56
#include <vector>
67
#include <iterator>

test/bind.cxx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <catch2/catch.hpp>
2+
#define PROGRAMOPTIONS_EXCEPTIONS
23
#include <ProgramOptions.hxx>
34
#include "arg_provider.hxx"
45

test/callback.cxx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <catch2/catch.hpp>
2+
#define PROGRAMOPTIONS_EXCEPTIONS
23
#include <ProgramOptions.hxx>
34
#include "arg_provider.hxx"
45

0 commit comments

Comments
 (0)