Skip to content

Commit

Permalink
Made versions with same major and minor but different patch versions …
Browse files Browse the repository at this point in the history
…compatible to each other + incremented version to 1.4.0.

I.e. we guarantee compatibility between versions of the library with different patch versions if the major and minor versions are the same. This allows to make releases with just e.g. documentation or test updates, where the patch version gets incremented and now no longer leads to a breaking change.
  • Loading branch information
Sedeniono committed Dec 14, 2024
1 parent c2e925c commit ac8aad5
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 51 deletions.
8 changes: 4 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.14)

project(
tiny-optional
VERSION 1.3.1
VERSION 1.4.0
DESCRIPTION "Replacement for std::optional that does not waste memory unnecessarily."
HOMEPAGE_URL "https://github.com/Sedeniono/tiny-optional"
LANGUAGES CXX
Expand Down Expand Up @@ -38,9 +38,9 @@ install(
write_basic_package_version_file(
"tiny-optionalConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
# Different versions of tiny::optional cannot be mixed. It is
# actively prevented by the use of inline namespaces.
COMPATIBILITY ExactVersion)
# Different major and minor versions of tiny::optional cannot be mixed.
# It is actively prevented by the use of inline namespaces.
COMPATIBILITY SameMinorVersion)

configure_package_config_file(
"${PROJECT_SOURCE_DIR}/cmake/tiny-optionalConfig.cmake.in"
Expand Down
69 changes: 42 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
- [Limitations](#limitations)
- [Platform specific behavior](#platform-specific-behavior)
- [Compatibility with `std::optional`](#compatibility-with-stdoptional)
- [Installation](#installation)
- [Installation using cmake](#installation-using-cmake)
- [Manual installation](#manual-installation)
- [Preprocessor flags](#preprocessor-flags)
- [Compatibility between different versions](#compatibility-between-different-versions)
- [Natvis](#natvis)
- [Usage](#usage)
- [Installation](#installation)
- [cmake](#cmake)
- [Manually](#manually)
- [Preprocessor flags](#preprocessor-flags)
- [Using `tiny::optional` as `std::optional` replacement](#using-tinyoptional-as-stdoptional-replacement)
- [Using a sentinel value](#using-a-sentinel-value)
- [Storing the empty state in a member variable](#storing-the-empty-state-in-a-member-variable)
Expand All @@ -39,7 +41,6 @@
- [Generic alternative](#generic-alternative)
- [Alternative for `static constexpr`](#alternative-for-static-constexpr)
- [Disabling platform specific tricks (`TINY_OPTIONAL_USE_SEPARATE_BOOL_INSTEAD_OF_UB_TRICKS`)](#disabling-platform-specific-tricks-tiny_optional_use_separate_bool_instead_of_ub_tricks)
- [Natvis](#natvis)
- [Performance results](#performance-results)
- [Runtime](#runtime)
- [Build time](#build-time)
Expand Down Expand Up @@ -160,11 +161,12 @@ Currently, the following components of the interface of `std::optional` are not
Moreover, the monadic operation `transform()` always returns a `tiny::optional<T>`, i.e. specification of a sentinel or some other optional as return type (`tiny::optional_sentinel_via_type` etc.) is not possible. As a workaround, you can use `and_then()`.
# Usage
## Installation
# Installation
### cmake
This is a **header-only** library.
## Installation using cmake
Via [`find_package`](https://cmake.org/cmake/help/latest/command/find_package.html) (recommended):
1. Clone or download the `tiny-optional` repository.
Expand All @@ -189,24 +191,50 @@ Via [`find_package`](https://cmake.org/cmake/help/latest/command/find_package.ht


Alternative via [`add_subdirectory`](https://cmake.org/cmake/help/latest/command/add_subdirectory.html):
1. Put all files of the `tiny-optional` library in a subdirectory of your own project, so that you end up with `own_project/tiny-optional/CMakeLists.txt` and `own_project/tiny-optional/include/`.
1. Put all files of the `tiny-optional` library in a subdirectory of your own project, so that you end up with `own_project/tiny-optional/CMakeLists.txt` and `own_project/tiny-optional/include/`.
(Actually, not all files but only those in `tiny-optional/CMakeLists.txt` and `tiny-optional/include/` are required.)
1. In your own project's `own_project/CMakeLists.txt`, add:
```cmake
add_subdirectory(tiny-optional)
target_link_libraries(<target> PRIVATE tiny-optional::tiny-optional)
```


### Manually
This is a header-only library. Just copy the folder from the include directory containing the header to your project. Include it via `#include <tiny/optional>`.
## Manual installation
Just copy the folder from the `include` directory containing the headers to your project. Include it via `#include <tiny/optional>`.


### Preprocessor flags
## Preprocessor flags
* The library uses the standard [`assert()` macro](https://en.cppreference.com/w/cpp/error/assert) in a few places, which can be disabled as usual by defining `NDEBUG` for release builds.
* If you like to disable the use of platform specific tricks at the cost of most of the features, see the chapter "[Disabling platform specific tricks (`TINY_OPTIONAL_USE_SEPARATE_BOOL_INSTEAD_OF_UB_TRICKS`)](#disabling-platform-specific-tricks-tiny_optional_use_separate_bool_instead_of_ub_tricks)".


## Compatibility between different versions
Different versions of `tiny::optional` are only guaranteed to be API and ABI compatible between different patch versions.
Different major and different minor versions are not compatible.
This breaks with usual semantic versioning rules (where newer minor versions are compatible with older ones), mainly because most updates to `tiny::optional` are breaking changes and therefore would lead to very high major versions fast (which look "weird").

The types defined by the library are in an [inline namespace](https://en.cppreference.com/w/cpp/language/namespace#Inline_namespaces) that encodes the major and the minor version numbers, causing build time errors when mixing different versions.

Also see chapter "[Helpers to distinguish types at compile-time (metaprogramming)](#helpers-to-distinguish-types-at-compile-time-metaprogramming)".


## Natvis
The `include` directory contains a Natvis file which improves the display of the optionals in the Visual Studio debugger considerably.
Copy and add the Natvis file to your project, or append its content to your existing Natvis file.
See the [official Microsoft documentation](https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects) for more information on Natvis.

The Natvis visualizers show whether the optional contains a value or not, and if it does, the contained value.
Unfortunately, when you specialize `tiny::optional_flag_manipulator`, it is not reasonably possible to write a generic Natvis visualizer because Natvis does not allow to call any functions (even if they are `constexpr`).
So you need to add additional visualizers for each custom specialization yourself.
The same holds true for `tiny::optional_inplace`.

Notes:
* If you update to a more recent version of `tiny::optional`, you also need to update your copy of the Natvis file. Reason: It contains the name of the inline namespace in which all types are defined, and the name includes the version number.
* If you compile with `TINY_OPTIONAL_USE_SEPARATE_BOOL_INSTEAD_OF_UB_TRICKS`, the types are defined in an inline namespace with a different name than the one expected by default by Natvis. So you need to replace all occurrences of the inline namespace name with the new one. See the top of the Natvis file for more information.


# Usage

## Using `tiny::optional` as `std::optional` replacement
Instead of writing `std::optional<T>`, use `tiny::optional<T>` in your code.
Expand Down Expand Up @@ -306,7 +334,8 @@ There are a few helpers available which facilitate checks at compile-time:
* `tiny::optional<T>::is_compressed` is true if the optional has the same size as the payload `T`, and false otherwise. It is also defined for all other optional types defined by this library.
* `tiny::is_tiny_optional_v<T>` is true if `T` is an optional defined by this library (`tiny::optional`, `tiny::optional_inplace` or `tiny::optional_aip`, compare below). It is false for any other type, including `std::optional`.
* Every optional defined by this library defines a static boolean member `is_tiny_optional` with value true. For example, `tiny::optional<T>::is_tiny_optional` is true for **every** type `T`. The value is never false. It can be used to determine whether something is a tiny optional. But it is most likely more convenient to use `tiny::is_tiny_optional_v`, which yields false for any type that is not a tiny optional instead of resulting in compilation error. Nevertheless, the member `is_tiny_optional` might be useful in SFINAE contexts.
* The macro `TINY_OPTIONAL_VERSION` indicates the version of the library.
* The macro `TINY_OPTIONAL_VERSION` indicates the version of the library. It is in the format `MmmmPP`, where `M` is the major version, `mmm` the minor version and `PP` the patch level. For example, `100301` means version `1.3.1`.
* Additionally, there is the macro `TINY_OPTIONAL_VERSION_MAJOR_MINOR` which is in the format `Mmmm`. For example, `1004` means any version `1.4.x`. This macro is significant because versions with identical major and minor but different patch versions are compatible (see "[Compatibility between different versions](#compatibility-between-different-versions)").


## Specifying a sentinel value via a type
Expand Down Expand Up @@ -719,20 +748,6 @@ Mixing code that was compiled with and without `TINY_OPTIONAL_USE_SEPARATE_BOOL_
To prevent this, the types defined by the library are implemented in an [inline namespace](https://en.cppreference.com/w/cpp/language/namespace#Inline_namespaces) that encodes the configuration. If you try to mix different configurations, you will get errors related to missing or mismatching symbols.
## Natvis
The `include` directory contains a Natvis file which improves the display of the optionals in the Visual Studio debugger considerably.
Copy and add the Natvis file to your project, or append its content to your existing Natvis file.
See the [official Microsoft documentation](https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects) for more information on Natvis.
The Natvis visualizers show whether the optional contains a value or not, and if it does, the contained value.
Unfortunately, when you specialize `tiny::optional_flag_manipulator` (see above), it is not reasonably possible to write a generic Natvis visualizer because Natvis does not allow to call any functions (even if they are `constexpr`).
So you need to add additional visualizers for each custom specialization yourself.
The same holds true for `tiny::optional_inplace`.
Notes:
* If you update to a more recent version of `tiny::optional`, you also need to update your copy of the Natvis file. Reason: It contains the name of the inline namespace in which all types are defined, and the name includes the version number.
* If you compile with `TINY_OPTIONAL_USE_SEPARATE_BOOL_INSTEAD_OF_UB_TRICKS`, the types are defined in an inline namespace with a different name than the one expected by default by Natvis. So you need to replace all occurrences of the inline namespace name with the new one. See the top of the Natvis file for more information.
# Performance results
Expand Down
10 changes: 7 additions & 3 deletions include/tiny/optional.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,15 @@ Original repository: https://github.com/Sedeniono/tiny-optional
// #include <utility> // Required for std::move, std::swap, etc.


// TINY_OPTIONAL_VERSION % 100 is the patch level
// TINY_OPTIONAL_VERSION % 100 is the patch level == TINY_OPTIONAL_VERSION_PATCH
// TINY_OPTIONAL_VERSION / 100 % 1000 is the minor version
// TINY_OPTIONAL_VERSION / 100000 is the major version
// So the format is: MmmmPP, where 'M'=major, 'm'=minor and 'P'=patch.
#define TINY_OPTIONAL_VERSION 100301 // If you change this, adapt Natvis, too!
// E.g. TINY_OPTIONAL_VERSION 100301
//
#define TINY_OPTIONAL_VERSION_MAJOR_MINOR 1004 // If you change this, adapt Natvis, too!
#define TINY_OPTIONAL_VERSION_PATCH 0
#define TINY_OPTIONAL_VERSION (TINY_OPTIONAL_VERSION_MAJOR_MINOR * 100 + TINY_OPTIONAL_VERSION_PATCH)


#if (!defined(__cplusplus) || __cplusplus < 201703L) && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L)
Expand Down Expand Up @@ -122,7 +126,7 @@ Original repository: https://github.com/Sedeniono/tiny-optional
// different TINY_OPTIONAL_USE_SEPARATE_BOOL_INSTEAD_OF_UB_TRICKS settings.
#define TINY_OPTIONAL_INLINE_NS_BEGIN \
inline namespace TINY_OPTIONAL_CONCAT_NS( \
TINY_OPTIONAL_VERSION, \
TINY_OPTIONAL_VERSION_MAJOR_MINOR, \
TINY_OPTIONAL_UNUSED_BITS_NS_PART, \
TINY_OPTIONAL_MEMBER_NS_PART) \
{
Expand Down
Loading

0 comments on commit ac8aad5

Please sign in to comment.