metadata | build | packages | try online |
---|---|---|---|
gsl-lite is a portable, single-file, header-only library for defensive programming based on the C++ Core Guidelines Support Library specification.
- Example usage
- In a nutshell
- License
- Dependencies
- Installation and use
- Why gsl-lite?
- Features
- Reference documentation
- Migration guide
- Using gsl-lite in libraries
- Reported to work with
- Version semantics
- Contributing
#include <memory>
#include <utility>
#include <numeric>
#include <gsl-lite/gsl-lite.hpp>
namespace my_lib {
// Define this in your own namespace.
namespace gsl = ::gsl_lite;
// `span<T[, Extent]>`: contiguous range with bounds checks
double mean( gsl::span<double const> values )
{
// `gsl_Expects( cond )`: precondition check
gsl_Expects( !values.empty() );
double sum = std::accumulate( values.begin(), values.end(), 0. );
// `narrow_failfast<T>( u )`: checked numeric cast
double num = gsl::narrow_failfast<double>( std::ssize( values ) );
return sum / num;
}
class Resource
{
...
public:
Resource( std::size_t size );
};
// Type-encoded precondition with `not_null<P>`
void consumeResource( gsl::not_null<std::unique_ptr<Resource>> resource );
// Type-encoded postcondition with `not_null<P>`
gsl::not_null<std::unique_ptr<Resource>> acquireResource( std::size_t size )
{
// A flavor of `make_unique<T>()` which returns `not_null<std::unique_ptr<T>>`
return gsl::make_unique<Resource>( size );
}
} // namespace my_lib
gsl-lite strives to implement the Guidelines Support Library specification of the C++ Core Guidelines maintained by the Standard C++ Foundation. The library is originally based on Microsoft GSL and was adapted for C++98, C++03. It also works when compiled as C++11, C++14, C++17, C++20, or C++23.
gsl-lite does not interfere with Microsoft GSL since both libraries live in different namespaces (gsl_lite
vs. gsl
).
gsl-lite recognizes when it is compiled for the CUDA platform and decorates some functions with __host__
and __device__
accordingly.
gsl-lite uses the MIT license.
gsl-lite has no dependencies other than the C++ standard library.
The recommended way to consume gsl-lite in your CMake project is to use find_package()
to locate the package gsl-lite
and target_link_libraries()
to link to the imported target gsl-lite::gsl-lite
:
cmake_minimum_required( VERSION 3.20 FATAL_ERROR )
project( my-program LANGUAGES CXX )
find_package( gsl-lite 1.0 REQUIRED )
add_executable( my-program main.cpp )
target_compile_features( my-program PRIVATE cxx_std_17 )
target_link_libraries( my-program PRIVATE gsl-lite::gsl-lite )
gsl-lite is available via Vcpkg, Conan, and possibly other package managers. It may also be obtained with CPM:
CPMAddPackage( NAME gsl-lite VERSION 1.0.1 GITHUB_REPOSITORY gsl-lite/gsl-lite )
See the directories example/with-CPM and example/with-Vcpkg for example projects that use CPM and Vcpkg, respectively, to obtain gsl-lite.
Once the build system is set up, include the <gsl-lite/gsl-lite.hpp>
header file to use gsl-lite:
// main.cpp
#include <iostream>
#include <gsl-lite/gsl-lite.hpp>
void printCmdArgs( gsl_lite::span<gsl_lite::zstring const> cmdArgs )
{
gsl_Expects( !cmdArgs.empty() );
auto argsWithoutExeName = cmdArgs.subspan( 1 );
for ( auto arg : argsWithoutExeName )
{
std::cout << arg << "\n";
}
}
int main( int argc, char* argv[] )
{
auto numArgs = gsl_lite::narrow_failfast<std::size_t>( argc );
auto cmdArgs = gsl_lite::span( argv, numArgs );
printCmdArgs( cmdArgs );
}
gsl-lite is different from Microsoft GSL, the default implementation of the C++ Core Guidelines support library (GSL), in the following ways:
- gsl-lite maintains support for older versions of C++ (C++98, C++03, C++11) and older compilers.
(see: Reported to work with) - gsl-lite supports CUDA, and many of its features can be used in CUDA kernel code.
- Contract and assertion checks are more fine-grained, and runtime enforcement is configurable.
- In gsl-lite,
not_null<P>
retains the copyability and movability ofP
and therefore may have a moved-from state, which Microsoft GSL expressly disallows. As a consequence,not_null<std::unique_ptr<T>>
is movable in gsl-lite but not in Microsoft GSL. - gsl-lite defines feature testing macros and polyfills useful for targeting multiple versions of C++.
- gsl-lite comes as a single-header library.
See the reference documentation for a detailed explanation of the features provided by gsl-lite, and Section GSL: Guidelines support library of the C++ Core Guidelines for the specification of the Guidelines support library.
Feature \ library | GSL spec | MS GSL | gsl‑lite | Notes |
---|---|---|---|---|
Views: | ||||
owner<> |
✓ | ✓ | ✓¹¹ | Annotate a raw pointer that carries ownership |
not_null<> |
✓ | ✓ | ✓ | Annotate a (smart) pointer that must not be nullptr ; enforces non-nullability at runtime(cf. strict_not_null<> in Microsoft GSL) |
not_null_ic<> |
- | ✓ | ✓ | Like not_null<> but allows implicit construction from nullable pointers(cf. not_null<> in Microsoft GSL) |
make_unique<>() |
- | - | ✓¹¹ | Like std::make_unique<T>() but returns not_null<std::unique_ptr<T>> |
make_shared<>() |
- | - | ✓¹¹ | Like std::make_shared<T>() but returns not_null<std::shared_ptr<T>> |
span<> |
✓ | ✓ | ✓ | Like std::span<> but with bounds-checking |
zstring czstring |
✓ | ✓ | ✓ | Aliases for char * and char const * to be used for 0-terminated strings (C-style strings) |
wzstring wczstring |
- | ✓ | ✓ | Aliases for wchar_t * and wchar_t const * to be used for 0-terminated strings (C-style strings) |
Assertions: | ||||
Expects() |
✓ | ✓ | (✓) | Checks precondition at runtime (only defined in GSL compatibility mode) |
Ensures() |
✓ | ✓ | (✓) | Checks precondition at runtime (only defined in GSL compatibility mode) |
gsl_Expects() |
- | - | ✓ | Checks precondition at runtime |
gsl_ExpectsDebug() |
- | - | ✓ | Checks precondition at runtime unless NDEBUG is defined |
gsl_ExpectsAudit() |
- | - | ✓ | Checks precondition at runtime if audit mode is enabled |
gsl_Ensures() |
- | - | ✓ | Checks postcondition at runtime |
gsl_EnsuresDebug() |
- | - | ✓ | Checks postcondition at runtime unless NDEBUG is defined |
gsl_EnsuresAudit() |
- | - | ✓ | Checks postcondition at runtime if audit mode is enabled |
gsl_Assert() |
- | - | ✓ | Checks invariant at runtime |
gsl_AssertDebug() |
- | - | ✓ | Checks invariant at runtime unless NDEBUG is defined |
gsl_AssertAudit() |
- | - | ✓ | Checks invariant at runtime if audit mode is enabled |
Utilities: | ||||
finally() |
✓ | ✓ | ✓¹¹ | Returns an object that executes a given action in its destructor; use for ad hoc resource cleanup |
on_return() |
- | - | (✓¹¹) | Creates an object that executes a given action in its destructor if no exception occurred (opt-in feature) |
on_error() |
- | - | (✓¹¹) | Creates an object that executes a given action in its destructor if an exception was thrown (opt-in feature) |
at() |
✓ | ✓ | ✓ | Bounds-checked element access for C-style arrays and containers with random access |
index |
✓ | ✓ | ✓ | Signed integer type for indexes and subscripts |
dim |
- | - | ✓ | Signed integer type for sizes |
stride |
- | - | ✓ | Signed integer type for index strides |
diff |
- | - | ✓ | Signed integer type for index differences |
narrow_cast<>() |
✓ | ✓ | ✓ | Narrowing cast which tolerates lossy conversions; equivalent to static_cast<>() |
narrow<>() |
✓ | ✓ | ✓ | Checked narrowing cast; throws narrowing_error if cast is lossy |
narrow_failfast<>() |
- | - | ✓ | Checked narrowing cast; fails assertion check if cast is lossy |
¹¹: C++11 or newer required
Starting with v1.0, gsl-lite lives in the single header file <gsl-lite/gsl-lite.hpp>
, and all its symbols reside in namespace
gsl_lite
. By default, gsl-lite no longer defines a namespace gsl
or the unprefixed Expects()
and Ensures()
macros for
precondition and postcondition checking.
This change enables coexistence with Microsoft GSL (#194).
If you are migrating from gsl-lite v0.*, adapt your code by referencing namespace gsl_lite
rather than namespace gsl
, and by
using the prefixed macros gsl_Expects()
and gsl_Ensures()
rather than the unprefixed macros Expects()
and Ensures()
for
precondition and postcondition checking.
Note that gsl-lite v1 also changed the defaults for many of gsl-lite's configuration options. See the
v1.0.0 release notes for a comprehensive list of changes.
This should not affect you if you had already opted in to version-1 defaults by setting gsl_CONFIG_DEFAULTS_VERSION=1
or by linking to the gsl::gsl-lite-v1
target in CMake.
To reduce the pervasiveness of required changes, it can be useful to define a namespace alias inside your own namespace:
// my-lib.hpp
#include <gsl-lite/gsl-lite.hpp> // instead of <gsl/gsl-lite.hpp>
namespace my_lib {
namespace gsl = ::gsl_lite; // convenience alias
inline double median( gsl::span<double const> elements )
{
gsl_Expects( !elements.empty() ); // instead of Expects()
...
}
} // namespace my_lib
To minimize the impact of the breaking changes, gsl-lite introduces an optional GSL compatibility mode controlled by the
new configuration switch gsl_FEATURE_GSL_COMPATIBILITY_MODE
, which is is disabled
by default and can be enabled by defining gsl_FEATURE_GSL_COMPATIBILITY_MODE=1
.
If the GSL compatibility mode is enabled, gsl-lite additionally makes the following global definitions:
namespace gsl = ::gsl_lite;
#define Expects( x ) gsl_Expects( x )
#define Ensures( x ) gsl_Ensures( x )
The GSL compatibility mode precludes the use of gsl-lite and Microsoft GSL in the same translation unit. Therefore, do not use the GSL compatibility mode when using gsl-lite in a public header file of a library. (See notes on using gsl-lite in libraries below.)
The GSL compatibility mode causes no link-time interference between gsl-lite and as Microsoft GSL. Both libraries may be used in the same project as long as no translation unit includes both at the same time.
The legacy header file <gsl/gsl-lite.hpp>
now forwards to <gsl-lite/gsl-lite.hpp>
and implicitly enables the GSL compatibility mode.
When the legacy header is included, it emits a warning message that urges to either migrate to header <gsl-lite/gsl-lite.hpp>
,
namespace gsl_lite
and the prefixed contract checking macros gsl_Expects()
and gsl_Ensures()
, or to explicitly request GSL
compatibility by defining gsl_FEATURE_GSL_COMPATIBILITY_MODE=1
.
Many features of gsl-lite are very useful for defining library interfaces, for instance spans, contract checks, or not_null<>
.
gsl-lite can coexist with Microsoft GSL. However, the GSL compatibility mode of gsl-lite may cause interference with Microsoft GSL. Also, gsl-lite is customizable through a large number of configuration options and switches. These configuration macros may affect the API and ABI of gsl-lite in ways that renders it incompatible with other code. How gsl-lite is configured should be the prerogative of the consumer, not the author, of a library.
Therefore, when using gsl-lite in a library, please mind the following suggestions:
- Do not define, or rely on, any of gsl-lite's configuration options or switches when using gsl-lite in a library.
- In particular, do not enable the GSL compatibility mode.
- Do not use the legacy header file
<gsl/gsl-lite.hpp>
, which implicitly enables the GSL compatibility mode; use the header<gsl-lite/gsl-lite.hpp>
instead. - Use namespace
gsl_lite
rather than namespacegsl
; if desired, define anamespace gsl = ::gsl_lite;
alias in your own namespace. - Use the prefixed contract checking macros
gsl_Expects()
andgsl_Ensures()
rather than the unprefixed macrosExpects()
andEnsures()
.
The table below mentions the compiler versions and platforms gsl-lite is reported to work with.
Compiler | OS | Platforms | Versions | CI |
---|---|---|---|---|
GCC | Linux | x64 | 4.7 and newer | 9, 10, 11, 12, 13, 14 |
GCC (MinGW) | Windows | x86, x64 | 4.8.4 and newer | |
GCC (DJGPP) | DOSBox, FreeDOS | x86 | 7.2 | |
GCC | MacOS | x64 | 6 and newer | 11, 12, 13, 14 |
Clang | Linux | x64 | 3.5 and newer | 11, 12, 13, 14, 15, 16, 17, 18, 19 |
Clang with libstdc++ | Linux | x64 | 11 and newer | 19 |
Clang | Windows | x64 | version shipped with VS | VS 2019, 2022 |
MSVC (Visual Studio) | Windows | x86, x64 | VS 2010 and newer | VS 2010, 2012, 2013, 2015, 2017, 2019, 2022 |
AppleClang (Xcode) | MacOS | x64 | 7.3 and newer | 14, 15, 16 |
NVCC (CUDA Toolkit) | Linux, Windows | x64 | 10.2 and newer | 12.8 |
ARMCC | ARM | 5 and newer |
gsl-lite follows Semantic Versioning guidelines. We maintain API and ABI compatibility and avoid breaking changes in minor and patch releases.
Development of gsl-lite happens in the master
branch. Versioning semantics apply only to tagged releases: there is no stability guarantee between individual
commits in the master
branch, that is, anything added since the last tagged release may be renamed, removed, or have the semantics changed without further notice.
A minor-version release will be compatible (in both ABI and API) with the previous minor-version release. Thus, once a change is released, it becomes part of the API.
Some of the configuration options may affect the API and ABI of gsl-lite.
Contributions to gsl-lite through pull requests or issues are welcome.
gsl-lite comes with a test suite that uses an included, slightly modified copy of the lest test framework.
To build gsl-lite's test suite, enable the CMake build option GSL_LITE_OPT_BUILD_TESTS
when configuring the project.