-
-
Notifications
You must be signed in to change notification settings - Fork 6.7k
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
How can I use std::string_view as the json_key to "operator []" ? #1529
Comments
The library does not support string views there. Object keys are |
but I can use string_view in map<std::string, bool>, like this: std::map<std::string, bool, std::less<>> mp{{"111",true}, {"222", false}, {"333", true}}; //use std::less<> as your json_object is a map type, why can't you do it similarly ? |
Maybe some part of your code I have not understand, : ) |
Maybe under the hood, |
What a pity : ) |
Transparent comparators seem to be a C++14 extension. :/ |
Any idea how to proceed? |
See my code, I add a
|
Of course, it can be faster using |
Wouldn't reference operator[](std::string_view key)
{
return operator[](key.data());
} be already sufficient or is this too naive? |
It cannot be this. when the key is because a string_view object maybe points to a part of a continuous memory. |
Looking at your code, you seem to convert the string view in whatever key type the map has? Right? Then it would be: reference operator[](std::string_view key)
{
return operator[](std::string(key));
} |
yes, exactly. but my code above can work with cpp11/cpp14/cpp17, the template |
Oh, I see. I still tried to figure out whether some "magic" is needed. In your example, I do not like the |
I alaways tryto make the code run faster. |
I just realized we already take care of this: #if defined(JSON_HAS_CPP_14)
// Use transparent comparator if possible, combined with perfect forwarding
// on find() and count() calls prevents unnecessary string construction.
using object_comparator_t = std::less<>;
#else
using object_comparator_t = std::less<StringType>;
#endif |
Before cpp14, After cpp14, it's ok to use |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
@nlohmann This is causing me a lot of problems. I have string_view's all over my code (C++17) but am having to construct std::string objects just for the sake of calling nlohmann::json::operator[]. This is really harming performance, as well as being a pain to type out. Can a compile time option be added to the library to support this in some manner? |
make |
something is similar in rapidjson, |
This is still not fixed - correct? |
ping&upvote |
I'm interested in being able to use A silver lining is that |
I'd also be very much interested in this. If no one else finds the time to pick this up, I might give it a try. However, I'd first like to know if this lib will stay c++11 in the forseeable future or if there is a new major version on the horizon that will require c++14 or even 17. Implementing this in a purely optional and compatible manner may or may not be much more tricky than when you can just rely on std::string_view and transparent comparison being available. |
@nlohmann: Are you seeing activity on closed issues? |
I am running out of ideas here. I tried to bring the last working commit 15e4598 up to the develop branch in #3237, but this is also not working. As I obviously have no idea what I'm doing here, I will stop experimenting here now. If anyone can create a POC branch based on develop, I will happily take over and add tests and documentation. |
@nlohmann; Thank you for the effort you're doing. I'll try to have a look this evening. It is branch |
Thanks, @kentf. git checkout -b string_view2 5379b5d0910f5f712b80da09952c667e1ea21b29 to get back to the last working state of branch |
I've had a look, and I'm still looking. Currently I'm using MSVC 2022. By default, when configuring nlohmann/json with CMake, the default standard is C++14. I've added an option to When using C++14 and C++17, they both fail to compile It fails to compile on this line: json/test/src/unit-regression2.cpp Line 788 in 7254b1f
Will continue digging. |
Is there a way to solve this issue? It really would be nice if someone implemented it. |
I know, right? Most of the code for In this snippet, the problem is std::string p = "/root";
auto normal_ptr = json::json_pointer(p);
auto ordered_ptr = ordered_json::json_pointer(p);
json normal;
ordered_json ordered;
auto t1 = normal[ordered_ptr];
auto t2 = normal[normal_ptr];
auto t3 = ordered[ordered_ptr];
auto t4 = ordered[normal_ptr]; The compiler is not able to figure out the conversion between |
I can think of a few ways to fix that (e.g. just handle foreign json pointer explicitly), but what I'd like to understand first is what changed between 14,17 and 20 that makes this not work for c++17 specifically. |
@kentf On Jan 3 you said that 20 was okay, but 14 and 17 failed. Has that changed? |
I'm wondering if |
By the looks of it, you are right, however. I wonder if it was ever the plan to use the same string type as in basic_json instead of std::string. Regardless, my feeling is that such a change should not be part of this PR, because it would probably be a breaking change (e.g. in the unlikely case if someone overloaded a function for different json_pointer specializations) but on the other hand a meaningful improvement on its own. |
Btw.: A different, but related change to |
It has sort of changed. I'm not sure what, but as of now C++14 and C++20 compiles fine. Only C++17 fails to build (in VC2022). It's the test project With commit diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 4c741f274..bd1b24f6c 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -57,14 +57,19 @@ foreach(feature ${CMAKE_CXX_COMPILE_FEATURES})
if (${feature} STREQUAL cxx_std_17)
set(compiler_supports_cpp_17 TRUE)
endif()
+ if (${feature} STREQUAL cxx_std_20)
+ set(compiler_supports_cpp_20 TRUE)
+ endif()
endforeach()
# Clang only supports C++17 starting from Clang 5.0
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
unset(compiler_supports_cpp_17)
+ unset(compiler_supports_cpp_20)
endif()
# MSVC 2015 (14.0) does not support C++17
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.1)
unset(compiler_supports_cpp_17)
+ unset(compiler_supports_cpp_20)
endif()
file(GLOB files src/unit-*.cpp)
@@ -119,6 +124,43 @@ foreach(file ${files})
endif()
endif()
+ # add a copy with C++20 compilation
+ if (compiler_supports_cpp_20)
+ file(READ ${file} FILE_CONTENT)
+
+ string(FIND "${FILE_CONTENT}" "JSON_HAS_CPP_20" CPP_20_FOUND)
+ if(NOT ${CPP_20_FOUND} EQUAL -1)
+ add_executable(${testcase}_cpp20 $<TARGET_OBJECTS:doctest_main> ${file})
+ target_compile_definitions(${testcase}_cpp20 PRIVATE DOCTEST_CONFIG_SUPER_FAST_ASSERTS)
+ target_compile_options(${testcase}_cpp20 PRIVATE
+ $<$<CXX_COMPILER_ID:MSVC>:/EHsc;$<$<CONFIG:Release>:/Od>>
+ $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wno-deprecated;-Wno-float-equal>
+ $<$<CXX_COMPILER_ID:GNU>:-Wno-deprecated-declarations>
+ )
+ target_include_directories(${testcase}_cpp20 PRIVATE ${CMAKE_BINARY_DIR}/include thirdparty/doctest thirdparty/fifo_map)
+ target_link_libraries(${testcase}_cpp20 PRIVATE ${NLOHMANN_JSON_TARGET_NAME})
+ target_compile_features(${testcase}_cpp20 PRIVATE cxx_std_20)
+
+ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0 AND NOT MINGW)
+ # fix for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90050
+ target_link_libraries(${testcase}_cpp20 PRIVATE stdc++fs)
+ endif()
+
+ if (JSON_FastTests)
+ add_test(NAME "${testcase}_cpp20"
+ COMMAND ${testcase}_cpp20 ${DOCTEST_TEST_FILTER}
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ )
+ else()
+ add_test(NAME "${testcase}_cpp20"
+ COMMAND ${testcase}_cpp20 ${DOCTEST_TEST_FILTER} --no-skip
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ )
+ endif()
+ set_tests_properties("${testcase}_cpp20" PROPERTIES LABELS "all" FIXTURES_REQUIRED TEST_DATA)
+ endif()
+ endif()
+
if (JSON_FastTests)
add_test(NAME "${testcase}"
COMMAND ${testcase} ${DOCTEST_TEST_FILTER}
diff --git a/test/src/unit-regression2.cpp b/test/src/unit-regression2.cpp
index afbdf3dbe..4b6ad78f0 100644
--- a/test/src/unit-regression2.cpp
+++ b/test/src/unit-regression2.cpp
@@ -100,6 +100,10 @@ using ordered_json = nlohmann::ordered_json;
#endif
#endif
+#ifdef JSON_HAS_CPP_20
+// Trigger C++20 compilation by having JSON_HAS_CPP_20 present in the file
+#endif
+
#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM
#define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0
#endif The (C++17) compiler chokes with this error:
I'm not too well versed on the internals of this magnificent library, so I'm not qualified to give inputs on what should be done next. But it seems like there is an issues of a missing implicit conversion from |
Superficially, the problem seems to be that the foreign_json pointer doesn't pass the Now, one way to handle that (I assume, I didn't test it) would be to explicitly handle a json_ponter, that is not the same as However, out of professional pride, I would prefer if I could understand the root cause and offer a more "elegant" solution than that. But that should not stop anyone of you for applying above suggestion (assuming it actually works). |
So, I spent all of yesterday on this issue without reading this thread first (regretfully, *sigh*). Long story short, I'm very confused by what the correct behavior is supposed to be. Here are some of the options: a) Foreign b) Foreign c) Foreign I assume, removing the Personally, option B seems like the way to go. The commit history on the I've some additional ideas surrounding @nlohmann could you please chime in? |
That is similar to my suggestion here: |
Indeed, but no one else weighed in. What is this projects policy on API stability? Would that even be considered? Maybe for 4.0? Yesterday I decoupled all relevant member functions from the class template parameter via a function template parameter (exceptions still need an overload as described earlier, before the template parameter could be removed). CI on my PoC string_view3 branch is all green. I just need to know if this snippet from the regression test shows the intended and desired behavior:
I've modified this to produce and expect an object with key "root" (no leading slash). Makes more sense to me than the foreign |
Our code needs at least version 3.11 for std::string_view support (see nlohmann/json#1529). Ubuntu 22.04 (GitHub actions runner) doesn't have that.
//as follow, this will fail as the key_type pof map is std::string_view
std::map<string_view, bool> mv{{"111",true}, {"222", false}, {"333", true}};
nlohmann::json j4{mv};
//another: fail again, the std::string_view is the json_key
nlohmann::json j5;
std::string_view key = "my_key"sv;
j5[key] = 100;
The text was updated successfully, but these errors were encountered: