mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-04-30 19:09:26 +08:00
Fix #458: Support std::string_view interop with ChaiScript strings
Register std::string_view as the "string_view" user type with a built-in implicit conversion from std::string, so a ChaiScript string can be passed directly to a C++ function taking std::string_view. Adds the reverse explicit conversion via string(sv) / to_string(sv), plus basic queries (size, length, empty, data) and comparison operators on string_view. String-style methods that take size_t (substr, find, ...) are intentionally not duplicated on string_view: with the implicit conversion in place they would create dispatch ambiguity for calls like string.substr(int, int). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d3c94e4451
commit
b7315f2db9
@ -10,6 +10,7 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@ -52,9 +53,14 @@ namespace chaiscript {
|
||||
|
||||
bootstrap::standard_library::vector_type<std::vector<Boxed_Value>>("Vector", *lib);
|
||||
bootstrap::standard_library::string_type<std::string>("string", *lib);
|
||||
bootstrap::standard_library::string_view_type<std::string_view, std::string>("string_view", *lib);
|
||||
bootstrap::standard_library::map_type<std::map<std::string, Boxed_Value>>("Map", *lib);
|
||||
bootstrap::standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value>>("Pair", *lib);
|
||||
|
||||
// Allow explicit conversion from std::string_view back to std::string,
|
||||
// e.g. `string(sv)` in ChaiScript.
|
||||
lib->add(fun([](const std::string_view sv) { return std::string{sv}; }), "string");
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
bootstrap::standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future", *lib);
|
||||
// Note: async() is registered in ChaiScript_Basic::build_eval_system()
|
||||
|
||||
@ -539,6 +539,40 @@ namespace chaiscript::bootstrap::standard_library {
|
||||
m.add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); }), "substr");
|
||||
}
|
||||
|
||||
/// Add a String_View type (e.g. std::string_view), with conversions to and from
|
||||
/// the matching owning String type (e.g. std::string).
|
||||
///
|
||||
/// Only registers operations that don't share names with the owning String type's
|
||||
/// methods that take arithmetic arguments (e.g. substr/find). Those would create
|
||||
/// dispatch ambiguity once the implicit String -> StringView conversion is in
|
||||
/// play, because neither overload would exactly match a (String, int, int) call.
|
||||
///
|
||||
/// \note A String_View is a non-owning reference. Constructing one from a
|
||||
/// temporary owning String yields a dangling reference once that temporary
|
||||
/// is destroyed; the same lifetime caveats as in C++ apply here.
|
||||
template<typename StringView, typename String>
|
||||
void string_view_type(const std::string &type, Module &m) {
|
||||
m.add(user_type<StringView>(), type);
|
||||
m.add(constructor<StringView()>(), type);
|
||||
m.add(constructor<StringView(const StringView &)>(), type);
|
||||
m.add(fun([](const String &s) { return StringView{s}; }), type);
|
||||
|
||||
opers_comparison<StringView>(m);
|
||||
|
||||
m.add(fun([](const StringView *s) { return s->size(); }), "size");
|
||||
m.add(fun([](const StringView *s) { return s->length(); }), "length");
|
||||
m.add(fun([](const StringView *s) { return s->empty(); }), "empty");
|
||||
m.add(fun([](const StringView *s) { return s->data(); }), "data");
|
||||
|
||||
// Built-in implicit conversion from owning String to non-owning StringView.
|
||||
m.add(type_conversion<const String &, StringView>());
|
||||
|
||||
// Explicit conversion from StringView back to owning String, registered as
|
||||
// to_string(sv); the call site can also register it under the owning type's
|
||||
// name (e.g. string(sv)) when desired.
|
||||
m.add(fun([](const StringView sv) { return String{sv}; }), "to_string");
|
||||
}
|
||||
|
||||
/// Add a MapType container
|
||||
/// http://www.sgi.com/tech/stl/Map.html
|
||||
template<typename FutureType>
|
||||
|
||||
@ -2204,3 +2204,19 @@ TEST_CASE("Exception from C++ [] operator is catchable in ChaiScript") {
|
||||
caught
|
||||
)") == true);
|
||||
}
|
||||
|
||||
// Issue #458: ChaiScript strings should be passable to C++ functions that
|
||||
// take std::string_view, std::string_view should be a known type, and
|
||||
// explicit conversion from std::string_view to std::string should work.
|
||||
TEST_CASE("Issue #458: std::string_view interop with ChaiScript strings") {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||
|
||||
chai.add(chaiscript::fun([](const std::string_view sv) { return std::string(sv); }), "consume_string_view");
|
||||
|
||||
CHECK(chai.eval<std::string>(R"(consume_string_view("Hi there"))") == "Hi there");
|
||||
CHECK(chai.eval<std::string>(R"(var s = "from variable"; consume_string_view(s))") == "from variable");
|
||||
|
||||
CHECK(chai.eval<bool>(R"(type_name(string_view("hello")) == "string_view")"));
|
||||
|
||||
CHECK(chai.eval<std::string>(R"(string(string_view("round trip")))") == "round trip");
|
||||
}
|
||||
|
||||
@ -39,14 +39,15 @@ assert_equal(true, test_fun_types[1].bare_equal(int_type));
|
||||
|
||||
assert_equal(2, `==`.get_arity());
|
||||
|
||||
// < should be the merging of two functions bool <(PODObject, PODObject) and bool <(string, string)
|
||||
// < should be the merging of three functions bool <(PODObject, PODObject),
|
||||
// bool <(string, string), and bool <(string_view, string_view)
|
||||
// we want to peel it apart and make sure that's true
|
||||
auto types = `<`.get_param_types();
|
||||
assert_equal(3, types.size());
|
||||
assert_equal(true, types[0].bare_equal(bool_type));
|
||||
assert_equal(true, types[1].bare_equal(Object_type));
|
||||
assert_equal(true, types[2].bare_equal(Object_type));
|
||||
assert_equal(2, `<`.get_contained_functions().size());
|
||||
assert_equal(3, `<`.get_contained_functions().size());
|
||||
|
||||
|
||||
// guard existence tests
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user