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

Fix compilation of input_adapter(container) in edge cases #2553

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions include/nlohmann/detail/input/input_adapters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,14 +371,35 @@ typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapte
}

// Convenience shorthand from container to iterator
// Enables ADL on begin(container) and end(container)
// Encloses the using declarations in namespace for not to leak them to outside scope

namespace container_input_adapter_factory_impl {

using std::begin;
using std::end;

template<typename ContainerType, typename Enable = void>
struct container_input_adapter_factory {};

template<typename ContainerType>
auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container)))
struct container_input_adapter_factory< ContainerType,
void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))> >
{
// Enable ADL
using std::begin;
using std::end;
using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));

static adapter_type create(const ContainerType& container)
{
return input_adapter(begin(container), end(container));
}
};

}

return input_adapter(begin(container), end(container));
template<typename ContainerType>
typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)
{
return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);
}

// Special cases with fast paths
Expand Down
35 changes: 28 additions & 7 deletions single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5183,14 +5183,35 @@ typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapte
}

// Convenience shorthand from container to iterator
// Enables ADL on begin(container) and end(container)
// Encloses the using declarations in namespace for not to leak them to outside scope

namespace container_input_adapter_factory_impl {

using std::begin;
using std::end;

template<typename ContainerType, typename Enable = void>
struct container_input_adapter_factory {};

template<typename ContainerType>
auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container)))
struct container_input_adapter_factory< ContainerType,
void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))> >
{
// Enable ADL
using std::begin;
using std::end;
using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));

static adapter_type create(const ContainerType& container)
{
return input_adapter(begin(container), end(container));
}
};

return input_adapter(begin(container), end(container));
}

template<typename ContainerType>
typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)
{
return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);
}

// Special cases with fast paths
Expand Down Expand Up @@ -16801,7 +16822,7 @@ class basic_json
detail::parser_callback_t<basic_json>cb = nullptr,
const bool allow_exceptions = true,
const bool ignore_comments = false
)
)
{
return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
std::move(cb), allow_exceptions, ignore_comments);
Expand Down Expand Up @@ -25346,7 +25367,7 @@ template<>
inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept(
is_nothrow_move_constructible<nlohmann::json>::value&&
is_nothrow_move_assignable<nlohmann::json>::value
)
)
{
j1.swap(j2);
}
Expand Down
27 changes: 26 additions & 1 deletion test/src/unit-user_defined_input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const char* end(const MyContainer& c)
return c.data + strlen(c.data);
}

TEST_CASE("Custom container")
TEST_CASE("Custom container non-member begin/end")
{

MyContainer data{"[1,2,3,4]"};
Expand All @@ -75,6 +75,31 @@ TEST_CASE("Custom container")

}

TEST_CASE("Custom container member begin/end")
{
struct MyContainer2
{
const char* data;

const char* begin() const
{
return data;
}

const char* end() const
{
return data + strlen(data);
}
};

MyContainer2 data{"[1,2,3,4]"};
json as_json = json::parse(data);
CHECK(as_json.at(0) == 1);
CHECK(as_json.at(1) == 2);
CHECK(as_json.at(2) == 3);
CHECK(as_json.at(3) == 4);
}

TEST_CASE("Custom iterator")
{
const char* raw_data = "[1,2,3,4]";
Expand Down