Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add versioned, ABI-tagged inline namespace and namespace macros #3590

Merged
merged 12 commits into from
Jul 30, 2022
Merged
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ SED:=$(shell command -v gsed || which sed)
# the list of sources in the include folder
SRCS=$(shell find include -type f | sort)

# the list of sources in the tests folder
TESTS_SRCS=$(shell find tests -type f \( -name '*.hpp' -o -name '*.cpp' -o -name '*.cu' \) -not -path 'tests/thirdparty/*' | sort)

# the single header (amalgamated from the source files)
AMALGAMATED_FILE=single_include/nlohmann/json.hpp

Expand Down Expand Up @@ -159,11 +162,11 @@ pretty:
--preserve-date \
--suffix=none \
--formatted \
$(SRCS) $(AMALGAMATED_FILE) tests/src/*.cpp tests/src/*.hpp tests/benchmarks/src/benchmarks.cpp docs/examples/*.cpp
$(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) docs/examples/*.cpp

# call the Clang-Format on all source files
pretty_format:
for FILE in $(SRCS) $(AMALGAMATED_FILE) tests/src/*.cpp tests/src/*.hpp benchmarks/src/benchmarks.cpp docs/examples/*.cpp; do echo $$FILE; clang-format -i $$FILE; done
for FILE in $(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) docs/examples/*.cpp; do echo $$FILE; clang-format -i $$FILE; done

# create single header file
amalgamate: $(AMALGAMATED_FILE)
Expand Down
5 changes: 5 additions & 0 deletions docs/mkdocs/docs/api/macros/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ header. See also the [macro overview page](../../features/macros.md).
- [**JSON_SKIP_LIBRARY_VERSION_CHECK**](json_skip_library_version_check.md) - skip library version check
- [**NLOHMANN_JSON_VERSION_MAJOR**<br>**NLOHMANN_JSON_VERSION_MINOR**<br>**NLOHMANN_JSON_VERSION_PATCH**](nlohmann_json_version_major.md) - library version information

## Library namespace

- [**NLOHMANN_JSON_NAMESPACE**](nlohmann_json_namespace.md) - full name of the `nlohmann` namespace
- [**NLOHMANN_JSON_NAMESPACE_BEGIN**<br>**NLOHMANN_JSON_NAMESPACE_END**](nlohmann_json_namespace_begin.md) - open and close the library namespace

## Type conversions

- [**JSON_DISABLE_ENUM_SERIALIZATION**](json_disable_enum_serialization.md) - switch off default serialization/deserialization functions for enums
Expand Down
14 changes: 10 additions & 4 deletions docs/mkdocs/docs/api/macros/json_diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,16 @@ When the macro is not defined, the library will define it to its default value.

## Notes

!!! danger "ABI incompatibility"
!!! note "ABI compatibility"

As this macro changes the definition of the `basic_json` object, it MUST be defined in the same way globally, even
across different compilation units: `basic_json` objects with differently defined `JSON_DIAGNOSTICS` macros are
not compatible!
As of version 3.11.0, this macro is no longer required to be defined consistently throughout a codebase to avoid
One Definition Rule (ODR) violations, as the value of this macro is encoded in the namespace, resulting in distinct
symbol names.

This allows different parts of a codebase to use different versions or configurations of this library without
causing improper behavior.

Where possible, it is still recommended that all code define this the same way for maximum interoperability.

## Examples

Expand Down Expand Up @@ -65,3 +70,4 @@ When the macro is not defined, the library will define it to its default value.
## Version history

- Added in version 3.10.0.
- As of version 3.11.0 the definition is allowed to vary between translation units.
26 changes: 26 additions & 0 deletions docs/mkdocs/docs/api/macros/nlohmann_json_namespace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# NLOHMANN_JSON_NAMESPACE

```cpp
#define NLOHMANN_JSON_NAMESPACE
```

This macro evaluates to the full name of the `nlohmann` namespace, including
the name of a versioned and ABI-tagged inline namespace. Use this macro to
unambiguously refer to the `nlohmann` namespace.

## Default definition

The default value consists of a prefix, a version string, and optional ABI tags
depending on whether ABI-affecting macros are defined (e.g.,
[`JSON_DIAGNOSTICS`](json_diagnostics.md), and
[`JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`](json_use_legacy_discarded_value_comparison.md)).

When the macro is not defined, the library will define it to its default value.

## See also

- [`NLOHMANN_JSON_NAMESPACE_BEGIN, NLOHMANN_JSON_NAMESPACE_END`](nlohmann_json_namespace_begin.md)

## Version history

- Added in version 3.11.0.
40 changes: 40 additions & 0 deletions docs/mkdocs/docs/api/macros/nlohmann_json_namespace_begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# NLOHMANN_JSON_NAMESPACE_BEGIN, NLOHMANN_JSON_NAMESPACE_END

```cpp
#define NLOHMANN_JSON_NAMESPACE_BEGIN // (1)
#define NLOHMANN_JSON_NAMESPACE_END // (2)
```

These macros can be used to open and close the `nlohmann` namespace. They
include an inline namespace used to differentiate symbols when linking multiple
versions (including different ABI-affecting macros) of this library.

1. Opens the namespace.
```cpp
namespace nlohmann
{
inline namespace json_v3_11_0
{
```

2. Closes the namespace.
```cpp
} // namespace nlohmann
} // json_v3_11_0
```

## Default definition

The default definitions open and close the `nlohmann` as well as an inline
namespace.

When these macros are not defined, the library will define them to their
default definitions.

## See also

- [NLOHMANN_JSON_NAMESPACE](nlohmann_json_namespace.md)

## Version history

- Added in version 3.11.0.
43 changes: 24 additions & 19 deletions docs/mkdocs/docs/features/arbitrary_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,30 +155,35 @@ To solve this, you need to add a specialization of `adl_serializer` to the `nloh

```cpp
// partial specialization (full specialization works too)
namespace nlohmann {
template <typename T>
struct adl_serializer<boost::optional<T>> {
static void to_json(json& j, const boost::optional<T>& opt) {
if (opt == boost::none) {
j = nullptr;
} else {
j = *opt; // this will call adl_serializer<T>::to_json which will
// find the free function to_json in T's namespace!
}
NLOHMANN_JSON_NAMESPACE_BEGIN
template <typename T>
struct adl_serializer<boost::optional<T>> {
static void to_json(json& j, const boost::optional<T>& opt) {
if (opt == boost::none) {
j = nullptr;
} else {
j = *opt; // this will call adl_serializer<T>::to_json which will
// find the free function to_json in T's namespace!
}
}

static void from_json(const json& j, boost::optional<T>& opt) {
if (j.is_null()) {
opt = boost::none;
} else {
opt = j.get<T>(); // same as above, but with
// adl_serializer<T>::from_json
}
static void from_json(const json& j, boost::optional<T>& opt) {
if (j.is_null()) {
opt = boost::none;
} else {
opt = j.get<T>(); // same as above, but with
// adl_serializer<T>::from_json
}
};
}
}
};
NLOHMANN_JSON_NAMESPACE_END
```

!!! note "ABI compatibility"

Use [`NLOHMANN_JSON_NAMESPACE_BEGIN`](../api/macros/nlohmann_json_namespace_begin.md) and `NLOHMANN_JSON_NAMESPACE_END`
instead of `#!cpp namespace nlohmann { }` in code which may be linked with different versions of this library.

## How can I use `get()` for non-default constructible/non-copyable types?

There is a way, if your type is [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload:
Expand Down
3 changes: 3 additions & 0 deletions docs/mkdocs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,9 @@ nav:
- 'NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT': api/macros/nlohmann_define_type_intrusive.md
- 'NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE': api/macros/nlohmann_define_type_non_intrusive.md
- 'NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT': api/macros/nlohmann_define_type_non_intrusive.md
- 'NLOHMANN_JSON_NAMESPACE': api/macros/nlohmann_json_namespace.md
- 'NLOHMANN_JSON_NAMESPACE_BEGIN': api/macros/nlohmann_json_namespace_begin.md
- 'NLOHMANN_JSON_NAMESPACE_END': api/macros/nlohmann_json_namespace_begin.md
- 'NLOHMANN_JSON_SERIALIZE_ENUM': api/macros/nlohmann_json_serialize_enum.md
- 'NLOHMANN_JSON_VERSION_MAJOR': api/macros/nlohmann_json_version_major.md
- 'NLOHMANN_JSON_VERSION_MINOR': api/macros/nlohmann_json_version_major.md
Expand Down
9 changes: 4 additions & 5 deletions include/nlohmann/adl_serializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@

#pragma once

#include <type_traits>
#include <utility>

#include <nlohmann/detail/abi_macros.hpp>
#include <nlohmann/detail/conversions/from_json.hpp>
#include <nlohmann/detail/conversions/to_json.hpp>
#include <nlohmann/detail/meta/identity_tag.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>

namespace nlohmann
{
NLOHMANN_JSON_NAMESPACE_BEGIN

/// @sa https://json.nlohmann.me/api/adl_serializer/
template<typename ValueType, typename>
Expand Down Expand Up @@ -53,4 +51,5 @@ struct adl_serializer
::nlohmann::to_json(j, std::forward<TargetType>(val));
}
};
} // namespace nlohmann

NLOHMANN_JSON_NAMESPACE_END
7 changes: 4 additions & 3 deletions include/nlohmann/byte_container_with_subtype.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
#include <tuple> // tie
#include <utility> // move

namespace nlohmann
{
#include <nlohmann/detail/abi_macros.hpp>

NLOHMANN_JSON_NAMESPACE_BEGIN

/// @brief an internal type for a backed binary type
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/
Expand Down Expand Up @@ -99,4 +100,4 @@ class byte_container_with_subtype : public BinaryType
bool m_has_subtype = false;
};

} // namespace nlohmann
NLOHMANN_JSON_NAMESPACE_END
71 changes: 71 additions & 0 deletions include/nlohmann/detail/abi_macros.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#pragma once

// This file contains all macro definitions affecting or depending on the ABI

#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
nlohmann marked this conversation as resolved.
Show resolved Hide resolved
#if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
#if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 10 || NLOHMANN_JSON_VERSION_PATCH != 5
#warning "Already included a different version of the library!"
#endif
#endif
#endif

#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum)
#define NLOHMANN_JSON_VERSION_MINOR 10 // NOLINT(modernize-macro-to-enum)
#define NLOHMANN_JSON_VERSION_PATCH 5 // NOLINT(modernize-macro-to-enum)

#ifndef JSON_DIAGNOSTICS
#define JSON_DIAGNOSTICS 0
#endif

#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
#define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
#endif

#if JSON_DIAGNOSTICS
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
#else
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
#endif

#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
#else
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
#endif

#define NLOHMANN_JSON_ABI_PREFIX_EX(major, minor, patch) \
json_v ## major ## _ ## minor ## _ ## patch
#define NLOHMANN_JSON_ABI_PREFIX(major, minor, patch) \
NLOHMANN_JSON_ABI_PREFIX_EX(major, minor, patch)

#define NLOHMANN_JSON_ABI_CONCAT_EX(a, b, c) a ## b ## c
#define NLOHMANN_JSON_ABI_CONCAT(a, b, c) \
NLOHMANN_JSON_ABI_CONCAT_EX(a, b, c)

#define NLOHMANN_JSON_ABI_STRING \
NLOHMANN_JSON_ABI_CONCAT( \
NLOHMANN_JSON_ABI_PREFIX( \
NLOHMANN_JSON_VERSION_MAJOR, \
NLOHMANN_JSON_VERSION_MINOR, \
NLOHMANN_JSON_VERSION_PATCH), \
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON)

#ifndef NLOHMANN_JSON_NAMESPACE
#define NLOHMANN_JSON_NAMESPACE nlohmann::NLOHMANN_JSON_ABI_STRING
#endif

#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
#define NLOHMANN_JSON_NAMESPACE_BEGIN \
namespace nlohmann \
{ \
inline namespace NLOHMANN_JSON_ABI_STRING \
{
#endif

#ifndef NLOHMANN_JSON_NAMESPACE_END
#define NLOHMANN_JSON_NAMESPACE_END \
} /* namespace (abi_string) */ \
} /* namespace nlohmann */
#endif
25 changes: 7 additions & 18 deletions include/nlohmann/detail/conversions/from_json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,15 @@
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/identity_tag.hpp>
#include <nlohmann/detail/meta/std_fs.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/detail/string_concat.hpp>
#include <nlohmann/detail/value_t.hpp>

#if JSON_HAS_EXPERIMENTAL_FILESYSTEM
#include <experimental/filesystem>
namespace nlohmann::detail
{
namespace std_fs = std::experimental::filesystem;
} // namespace nlohmann::detail
#elif JSON_HAS_FILESYSTEM
#include <filesystem>
namespace nlohmann::detail
{
namespace std_fs = std::filesystem;
} // namespace nlohmann::detail
#endif

namespace nlohmann
{
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
{

template<typename BasicJsonType>
inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
{
Expand Down Expand Up @@ -491,6 +478,7 @@ struct from_json_fn
return from_json(j, std::forward<T>(val));
}
};

} // namespace detail

#ifndef JSON_HAS_CPP_17
Expand All @@ -503,6 +491,7 @@ namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-n
JSON_INLINE_VARIABLE constexpr const auto& from_json = // NOLINT(misc-definitions-in-headers)
detail::static_const<detail::from_json_fn>::value;
#ifndef JSON_HAS_CPP_17
} // namespace
} // namespace
#endif
} // namespace nlohmann

NLOHMANN_JSON_NAMESPACE_END
9 changes: 4 additions & 5 deletions include/nlohmann/detail/conversions/to_chars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@

#include <nlohmann/detail/macro_scope.hpp>

namespace nlohmann
{
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
{

Expand Down Expand Up @@ -1048,7 +1047,7 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent,
return append_exponent(buf, n - 1);
}

} // namespace dtoa_impl
} // namespace dtoa_impl

/*!
@brief generates a decimal representation of the floating-point number value in [first, last).
Expand Down Expand Up @@ -1115,5 +1114,5 @@ char* to_chars(char* first, const char* last, FloatType value)
return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);
}

} // namespace detail
} // namespace nlohmann
} // namespace detail
NLOHMANN_JSON_NAMESPACE_END
Loading