Skip to content

gsl-lite/gsl-lite

Repository files navigation

gsl-lite

metadata build packages try online
Language
License
Version
Azure Pipelines build status
AppVeyor build status
Vcpkg
single header
Try it on Compiler Explorer
Try it on Wandbox

gsl-lite is a portable, single-file, header-only library for defensive programming based on the C++ Core Guidelines Support Library specification.

Contents

Example usage

#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

In a nutshell

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.

License

gsl-lite uses the MIT license.

Dependencies

gsl-lite has no dependencies other than the C++ standard library.

Installation and use

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 );
}

Why gsl-lite?

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 of P 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.

Features

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

Migration guide

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).

Adapting your code

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

Using the GSL compatibility mode

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.

Using gsl-lite in libraries

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 namespace gsl; if desired, define a namespace gsl = ::gsl_lite; alias in your own namespace.
  • Use the prefixed contract checking macros gsl_Expects() and gsl_Ensures() rather than the unprefixed macros Expects() and Ensures().

Reported to work with

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

Version semantics

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.

Contributing

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.