sparrow 0.3.0
Loading...
Searching...
No Matches
contracts.hpp
Go to the documentation of this file.
1// Copyright 2024 Man Group Operations Limited
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// NOTE: This is based upon v0.3.0 of NoContracts library
16// https://github.com/Klaim/nocontracts/tree/0ffc183f7527213e3f0a57b8dae9befa7c0ca02c
17// Modifications: renamed macros
18
19#pragma once
20#include <csignal>
21#include <cstdio>
22
23
25// Possible bits used to compose the behavior:
26
27// if not specified by the user but available, use std::print
28#if not defined(SPARROW_CONTRACTS_USE_STD_PRINT) and not defined(SPARROW_CONTRACTS_USE_STD_FORMAT)
29# if __cplusplus >= 202002L
30# include <version>
31# ifdef __cpp_lib_print
32# define SPARROW_CONTRACTS_USE_STD_PRINT 1
33# endif
34# endif
35#else
36// The option is defined, but is it supported? If not we fail.
37# if defined(SPARROW_CONTRACTS_USE_STD_PRINT) and not defined(__cpp_lib_print)
38# error "std::print usage is requested but not available"
39# endif
40#endif
41
42// if not specified by the user but available and std::print is not already forced, use std::format
43#if not defined(SPARROW_CONTRACTS_USE_STD_FORMAT) and not defined(SPARROW_CONTRACTS_USE_STD_PRINT)
44# if __cplusplus >= 202002L
45# include <version>
46# ifdef __cpp_lib_format
47# define SPARROW_CONTRACTS_USE_STD_FORMAT 1
48# endif
49# endif
50// The option is defined, but is it supported? If not we fail.
51# if defined(SPARROW_CONTRACTS_USE_STD_FORMAT) and not defined(__cpp_lib_format)
52# error "std::format usage is requested but not available"
53# endif
54#endif
55
56// user specified to use neither std::format nor std::print, but C's formatting
57#if defined(SPARROW_CONTRACTS_USE_CFORMAT) && SPARROW_CONTRACTS_USE_CFORMAT == 1
58# ifdef SPARROW_CONTRACTS_USE_STD_FORMAT
59# undef SPARROW_CONTRACTS_USE_STD_FORMAT
60# endif
61# ifdef SPARROW_CONTRACTS_USE_STD_PRINT
62# undef SPARROW_CONTRACTS_USE_STD_PRINT
63# endif
64#endif
65
66// clang-format off
67#if defined(__GNUC__)
68# define SPARROW_CONTRACTS_IGNORE_WARNINGS \
69 _Pragma("GCC diagnostic push") \
70 _Pragma("GCC diagnostic ignored \"-Wall\"") \
71 _Pragma("GCC diagnostic ignored \"-Wformat-security\"")
72# define SPARROW_CONTRACTS_RESTORE_WARNINGS \
73 _Pragma("GCC diagnostic pop")
74#elif defined(__clang__)
75# define SPARROW_CONTRACTS_IGNORE_WARNINGS \
76 _Pragma("clang diagnostic push") \
77 _Pragma("clang diagnostic ignored \"-Weverything\"")
78# define SPARROW_CONTRACTS_RESTORE_WARNINGS \
79 _Pragma("clang diagnostic pop")
80#elif defined(_MSC_VER)
81# define SPARROW_CONTRACTS_IGNORE_WARNINGS \
82 _Pragma("warning(push)") \
83 _Pragma("warning(disable : 4774)") // 'var' has different type in 'file1' and 'file2': 'type1' and 'type2'
84# define SPARROW_CONTRACTS_RESTORE_WARNINGS \
85 _Pragma("warning(pop)")
86#else
87# define SPARROW_CONTRACTS_IGNORE_WARNINGS
88# define SPARROW_CONTRACTS_RESTORE_WARNINGS
89#endif
90// clang-format on
91
92#ifndef SPARROW_CONTRACTS_LOG_FAILURE
93# if defined(SPARROW_CONTRACTS_USE_STD_PRINT) && SPARROW_CONTRACTS_USE_STD_PRINT == 1
94# include <cstdio>
95# include <print>
96// clang-format off
97# define SPARROW_CONTRACTS_LOG_FAILURE(expr__, message__) \
98 ::std::print(stderr, "Assertion Failed ({}:{}): {} - ({} is wrong)\n", __FILE__, __LINE__, message__, #expr__)
99// clang-format on
100# elif defined(SPARROW_CONTRACTS_USE_STD_FORMAT) && SPARROW_CONTRACTS_USE_STD_FORMAT == 1
101# include <cstdio>
102# include <format>
103// clang-format off
104# define SPARROW_CONTRACTS_LOG_FAILURE( expr__, message__ ) \
105 do { \
106 SPARROW_CONTRACTS_IGNORE_WARNINGS; \
107 ::fprintf(stderr, ::std::format("Assertion Failed ({}:{}): {} - ({} is wrong)\n", __FILE__, __LINE__, message__, #expr__ ).c_str()); \
108 SPARROW_CONTRACTS_RESTORE_WARNINGS; \
109 } while (0);
110// clang-format on
111# else
112# include <cstdio>
113# include <cstdlib>
114// clang-format off
115# define SPARROW_CONTRACTS_LOG_FAILURE(expr__, message__) \
116 ::fprintf(stderr, "Assertion Failed (%s:%i): %s - (%s is wrong)\n", __FILE__, __LINE__, message__, #expr__);
117// clang-format on
118# endif
119#endif
120
121#ifndef SPARROW_CONTRACTS_ABORT
122# define SPARROW_CONTRACTS_ABORT() std::abort()
123#endif
124
125// User specifies to just continue instead of abort on failure.
126#if defined(SPARROW_CONTRACTS_CONTINUE_ON_FAILURE) and SPARROW_CONTRACTS_CONTINUE_ON_FAILURE == 1
127# undef SPARROW_CONTRACTS_ABORT
128# define SPARROW_CONTRACTS_ABORT
129#endif
130
131#ifndef SPARROW_CONTRACTS_DEBUGBREAK
132# ifdef _WIN32
133# define SPARROW_CONTRACTS_DEBUGBREAK() __debugbreak();
134# else
135# define SPARROW_CONTRACTS_DEBUGBREAK() std::raise(SIGTRAP);
136# endif
137#endif
138
140// Default behavior:
141
142#define SPARROW_CONTRACTS_DEFAULT_CHECKS_ENABLED 1
143#define SPARROW_CONTRACTS_DEFAULT_ABORT_ON_FAILURE 1
144
145#define SPARROW_CONTRACTS_DEFAULT_ON_FAILURE(expr__, message__) \
146 SPARROW_CONTRACTS_LOG_FAILURE(expr__, message__); \
147 SPARROW_CONTRACTS_DEBUGBREAK(); \
148 SPARROW_CONTRACTS_ABORT();
149
151// Apply Configuration:
152
153// If not override, use the default behavior.
154#ifndef SPARROW_CONTRACTS_CHECKS_ENABLED
155# define SPARROW_CONTRACTS_CHECKS_ENABLED SPARROW_CONTRACTS_DEFAULT_CHECKS_ENABLED
156#endif
157
158#if SPARROW_CONTRACTS_CHECKS_ENABLED == 1 // Behavior when contracts are enabled.
159
160# ifndef SPARROW_CONTRACTS_ON_FAILURE
161# define SPARROW_CONTRACTS_ON_FAILURE(expr__, message__) \
162 SPARROW_CONTRACTS_DEFAULT_ON_FAILURE(expr__, message__)
163# endif
164
165# ifndef SPARROW_ASSERT
166# define SPARROW_ASSERT(expr__, message__) \
167 if (!(expr__)) \
168 { \
169 SPARROW_CONTRACTS_ON_FAILURE(expr__, message__); \
170 }
171# endif
172
173# define SPARROW_ASSERT_TRUE(expr__) SPARROW_ASSERT(expr__, #expr__)
174# define SPARROW_ASSERT_FALSE(expr__) SPARROW_ASSERT(!(expr__), "!(" #expr__ ")")
175
176#else // Do nothing otherwise.
177# define SPARROW_CONTRACTS_ON_FAILURE(expr__)
178# define SPARROW_ASSERT(expr__, message__)
179# define SPARROW_ASSERT_TRUE(expr__)
180# define SPARROW_ASSERT_FALSE(expr__)
181#endif