Skip to content

Commit

Permalink
Add ReadOnlySpan API Overloads
Browse files Browse the repository at this point in the history
  • Loading branch information
Delsin-Yu committed Aug 31, 2024
1 parent a5830f6 commit a7b039f
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 50 deletions.
99 changes: 62 additions & 37 deletions modules/mono/editor/bindings_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2221,9 +2221,13 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str

int method_bind_count = 0;
for (const MethodInterface &imethod : itype.methods) {
Error method_err = _generate_cs_method(itype, imethod, method_bind_count, output);
Error method_err = _generate_cs_method(itype, imethod, method_bind_count, output, false);
ERR_FAIL_COND_V_MSG(method_err != OK, method_err,
"Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'.");

method_err = _generate_cs_method(itype, imethod, method_bind_count, output, true);
ERR_FAIL_COND_V_MSG(method_err != OK, method_err,
"Failed to generate span overload method '" + imethod.name + "' for class '" + itype.name + "'.");
}

// Signals
Expand Down Expand Up @@ -2649,7 +2653,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
return OK;
}

Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output) {
Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output, const bool p_use_span) {
const TypeInterface *return_type = _get_type_or_singleton_or_null(p_imethod.return_type);
ERR_FAIL_NULL_V(return_type, ERR_BUG); // Return type not found

Expand All @@ -2662,6 +2666,9 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
"' from the editor API. Core API cannot have dependencies on the editor API.");
}

if (p_imethod.is_virtual && p_use_span)
return OK;

String method_bind_field = CS_STATIC_FIELD_METHOD_BIND_PREFIX + itos(p_method_bind_count);

String arguments_sig;
Expand All @@ -2686,6 +2693,8 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf

StringBuilder default_args_doc;

bool has_span_argument = false;

// Retrieve information from the arguments
const ArgumentInterface &first = p_imethod.arguments.front()->get();
for (const ArgumentInterface &iarg : p_imethod.arguments) {
Expand All @@ -2708,6 +2717,8 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf

String arg_cs_type = arg_type->cs_type + _get_generic_type_parameters(*arg_type, iarg.type.generic_type_parameters);

bool use_span_for_arg = p_use_span && arg_type->is_span_compatible;

// Add the current arguments to the signature
// If the argument has a default value which is not a constant, we will make it Nullable
{
Expand All @@ -2719,7 +2730,12 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
arguments_sig += "Nullable<";
}

arguments_sig += arg_cs_type;
if (use_span_for_arg) {
arguments_sig += "ReadOnlySpan<" + arg_type->span_substitution_name + ">";
has_span_argument = true;
} else {
arguments_sig += arg_cs_type;
}

if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) {
arguments_sig += "> ";
Expand All @@ -2731,7 +2747,11 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf

if (!p_imethod.is_compat && iarg.default_argument.size()) {
if (iarg.def_param_mode != ArgumentInterface::CONSTANT) {
arguments_sig += " = null";
if (use_span_for_arg) {
arguments_sig += " = default";
} else {
arguments_sig += " = null";
}
} else {
arguments_sig += " = " + sformat(iarg.default_argument, arg_type->cs_type);
}
Expand All @@ -2740,7 +2760,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf

icall_params += ", ";

if (iarg.default_argument.size() && iarg.def_param_mode != ArgumentInterface::CONSTANT) {
if (iarg.default_argument.size() && iarg.def_param_mode != ArgumentInterface::CONSTANT && !use_span_for_arg) {
// The default value of an argument must be constant. Otherwise we make it Nullable and do the following:
// Type arg_in = arg.HasValue ? arg.Value : <non-const default value>;
String arg_or_defval_local = iarg.name;
Expand Down Expand Up @@ -2800,6 +2820,9 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
cs_in_expr_is_unsafe |= arg_type->cs_in_expr_is_unsafe;
}

if (p_use_span && !has_span_argument)
return OK;

// Collect caller name for MethodBind
if (p_imethod.is_vararg) {
icall_params += ", (godot_string_name)MethodName." + p_imethod.proxy_name + ".NativeValue";
Expand Down Expand Up @@ -4559,38 +4582,40 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_in = "Variant[]";
builtin_types.insert(itype.cname, itype);

#define INSERT_ARRAY_FULL(m_name, m_type, m_managed_type, m_proxy_t) \
{ \
itype = TypeInterface(); \
itype.name = #m_name; \
itype.cname = itype.name; \
itype.proxy_name = #m_proxy_t "[]"; \
itype.cs_type = itype.proxy_name; \
itype.c_in = "%5using %0 %1_in = " C_METHOD_MONOARRAY_TO(m_type) "(%1);\n"; \
itype.c_out = "%5return " C_METHOD_MONOARRAY_FROM(m_type) "(%1);\n"; \
itype.c_arg_in = "&%s_in"; \
itype.c_type = #m_managed_type; \
itype.c_type_in = itype.proxy_name; \
itype.c_type_out = itype.proxy_name; \
itype.c_type_is_disposable_struct = true; \
builtin_types.insert(itype.name, itype); \
}

#define INSERT_ARRAY(m_type, m_managed_type, m_proxy_t) INSERT_ARRAY_FULL(m_type, m_type, m_managed_type, m_proxy_t)

INSERT_ARRAY(PackedInt32Array, godot_packed_int32_array, int);
INSERT_ARRAY(PackedInt64Array, godot_packed_int64_array, long);
INSERT_ARRAY_FULL(PackedByteArray, PackedByteArray, godot_packed_byte_array, byte);

INSERT_ARRAY(PackedFloat32Array, godot_packed_float32_array, float);
INSERT_ARRAY(PackedFloat64Array, godot_packed_float64_array, double);

INSERT_ARRAY(PackedStringArray, godot_packed_string_array, string);

INSERT_ARRAY(PackedColorArray, godot_packed_color_array, Color);
INSERT_ARRAY(PackedVector2Array, godot_packed_vector2_array, Vector2);
INSERT_ARRAY(PackedVector3Array, godot_packed_vector3_array, Vector3);
INSERT_ARRAY(PackedVector4Array, godot_packed_vector4_array, Vector4);
#define INSERT_ARRAY_FULL(m_name, m_type, m_managed_type, m_proxy_t, m_is_span_compatible) \
{ \
itype = TypeInterface(); \
itype.name = #m_name; \
itype.cname = itype.name; \
itype.proxy_name = #m_proxy_t "[]"; \
itype.cs_type = itype.proxy_name; \
itype.c_in = "%5using %0 %1_in = " C_METHOD_MONOARRAY_TO(m_type) "(%1);\n"; \
itype.c_out = "%5return " C_METHOD_MONOARRAY_FROM(m_type) "(%1);\n"; \
itype.c_arg_in = "&%s_in"; \
itype.c_type = #m_managed_type; \
itype.c_type_in = "ReadOnlySpan<" #m_proxy_t ">"; \
itype.c_type_out = itype.proxy_name; \
itype.c_type_is_disposable_struct = true; \
itype.is_span_compatible = m_is_span_compatible; \
itype.span_substitution_name = #m_proxy_t; \
builtin_types.insert(itype.name, itype); \
}

#define INSERT_ARRAY(m_type, m_managed_type, m_proxy_t, m_is_span_compatible) INSERT_ARRAY_FULL(m_type, m_type, m_managed_type, m_proxy_t, m_is_span_compatible)

INSERT_ARRAY(PackedInt32Array, godot_packed_int32_array, int, true);
INSERT_ARRAY(PackedInt64Array, godot_packed_int64_array, long, true);
INSERT_ARRAY_FULL(PackedByteArray, PackedByteArray, godot_packed_byte_array, byte, true);

INSERT_ARRAY(PackedFloat32Array, godot_packed_float32_array, float, true);
INSERT_ARRAY(PackedFloat64Array, godot_packed_float64_array, double, true);

INSERT_ARRAY(PackedStringArray, godot_packed_string_array, string, false);

INSERT_ARRAY(PackedColorArray, godot_packed_color_array, Color, true);
INSERT_ARRAY(PackedVector2Array, godot_packed_vector2_array, Vector2, true);
INSERT_ARRAY(PackedVector3Array, godot_packed_vector3_array, Vector3, true);
INSERT_ARRAY(PackedVector4Array, godot_packed_vector4_array, Vector4, true);

#undef INSERT_ARRAY

Expand Down
8 changes: 7 additions & 1 deletion modules/mono/editor/bindings_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,19 @@ class BindingsGenerator {
*/
String proxy_name;

/**
* Name to be used in the ReadOnlySpan when [is_span_compatible] evaluates to true.
*/
String span_substitution_name;

ClassDB::APIType api_type = ClassDB::API_NONE;

bool is_enum = false;
bool is_object_type = false;
bool is_singleton = false;
bool is_singleton_instance = false;
bool is_ref_counted = false;
bool is_span_compatible = false;

/**
* Class is a singleton, but can't be declared as a static class as that would
Expand Down Expand Up @@ -840,7 +846,7 @@ class BindingsGenerator {
Error _generate_cs_type(const TypeInterface &itype, const String &p_output_file);

Error _generate_cs_property(const TypeInterface &p_itype, const PropertyInterface &p_iprop, StringBuilder &p_output);
Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output);
Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output, bool p_use_span);
Error _generate_cs_signal(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::SignalInterface &p_isignal, StringBuilder &p_output);

Error _generate_cs_native_calls(const InternalCall &p_icall, StringBuilder &r_output);
Expand Down
18 changes: 16 additions & 2 deletions modules/mono/glue/GodotSharp/GodotSharp/Compat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ public long DrawListBegin(Rid framebuffer, InitialAction initialColorAction, Fin
{
return DrawListBegin(framebuffer, initialColorAction, finalColorAction, initialDepthAction, finalDepthAction, clearColorValues, clearDepth, clearStencil, region, new Godot.Collections.Array<Rid>(storageTextures));
}

/// <inheritdoc cref="DrawListBegin(Rid, InitialAction, FinalAction, InitialAction, FinalAction, ReadOnlySpan{Color}, float, uint, Nullable{Rect2}, Godot.Collections.Array{Rid})"/>
[EditorBrowsable(EditorBrowsableState.Never)]
public long DrawListBegin(Rid framebuffer, InitialAction initialColorAction, FinalAction finalColorAction, InitialAction initialDepthAction, FinalAction finalDepthAction, ReadOnlySpan<Color> clearColorValues, float clearDepth, uint clearStencil, Nullable<Rect2> region, Godot.Collections.Array storageTextures)
{
return DrawListBegin(framebuffer, initialColorAction, finalColorAction, initialDepthAction, finalDepthAction, clearColorValues, clearDepth, clearStencil, region, new Godot.Collections.Array<Rid>(storageTextures));
}
}

partial class RichTextLabel
Expand All @@ -187,11 +194,11 @@ public void PushList(int level, ListType type, bool capitalize)
PushList(level, type, capitalize, bullet: "•");
}

/// <inheritdoc cref="PushParagraph(HorizontalAlignment, TextDirection, string, TextServer.StructuredTextParser, TextServer.JustificationFlag, float[])"/>
/// <inheritdoc cref="PushParagraph(Godot.HorizontalAlignment, Godot.Control.TextDirection, string, Godot.TextServer.StructuredTextParser, TextServer.JustificationFlag, float[])"/>
[EditorBrowsable(EditorBrowsableState.Never)]
public void PushParagraph(HorizontalAlignment alignment, TextDirection baseDirection, string language, TextServer.StructuredTextParser stParser)
{
PushParagraph(alignment, baseDirection, language, stParser, TextServer.JustificationFlag.WordBound | TextServer.JustificationFlag.Kashida | TextServer.JustificationFlag.SkipLastLine | TextServer.JustificationFlag.DoNotSkipSingleLine);
PushParagraph(alignment, baseDirection, language, stParser, TextServer.JustificationFlag.WordBound | TextServer.JustificationFlag.Kashida | TextServer.JustificationFlag.SkipLastLine | TextServer.JustificationFlag.DoNotSkipSingleLine, Array.Empty<float>());
}
}

Expand All @@ -204,6 +211,13 @@ public void AddTriangleFan(Vector3[] vertices, Vector2[] uvs, Color[] colors, Ve
AddTriangleFan(vertices, uvs, colors, uv2S, normals, new Godot.Collections.Array<Plane>(tangents));
}

/// <inheritdoc cref="AddTriangleFan(ReadOnlySpan{Vector3},ReadOnlySpan{Vector2},ReadOnlySpan{Color},ReadOnlySpan{Vector2},ReadOnlySpan{Vector3},Godot.Collections.Array)"/>
[EditorBrowsable(EditorBrowsableState.Never)]
public void AddTriangleFan(ReadOnlySpan<Vector3> vertices, ReadOnlySpan<Vector2> uvs, ReadOnlySpan<Color> colors, ReadOnlySpan<Vector2> uv2S, ReadOnlySpan<Vector3> normals, Godot.Collections.Array tangents)
{
AddTriangleFan(vertices, uvs, colors, uv2S, normals, new Godot.Collections.Array<Plane>(tangents));
}

/// <inheritdoc cref="Commit(ArrayMesh, ulong)"/>
[EditorBrowsable(EditorBrowsableState.Never)]
public ArrayMesh Commit(ArrayMesh existing, uint flags)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ public static unsafe byte[] ConvertNativePackedByteArrayToSystemArray(in godot_p
return array;
}

public static unsafe godot_packed_byte_array ConvertSystemArrayToNativePackedByteArray(Span<byte> p_array)
public static unsafe godot_packed_byte_array ConvertSystemArrayToNativePackedByteArray(ReadOnlySpan<byte> p_array)
{
if (p_array.IsEmpty)
return new godot_packed_byte_array();
Expand All @@ -417,7 +417,7 @@ public static unsafe int[] ConvertNativePackedInt32ArrayToSystemArray(godot_pack
return array;
}

public static unsafe godot_packed_int32_array ConvertSystemArrayToNativePackedInt32Array(Span<int> p_array)
public static unsafe godot_packed_int32_array ConvertSystemArrayToNativePackedInt32Array(ReadOnlySpan<int> p_array)
{
if (p_array.IsEmpty)
return new godot_packed_int32_array();
Expand All @@ -440,7 +440,7 @@ public static unsafe long[] ConvertNativePackedInt64ArrayToSystemArray(godot_pac
return array;
}

public static unsafe godot_packed_int64_array ConvertSystemArrayToNativePackedInt64Array(Span<long> p_array)
public static unsafe godot_packed_int64_array ConvertSystemArrayToNativePackedInt64Array(ReadOnlySpan<long> p_array)
{
if (p_array.IsEmpty)
return new godot_packed_int64_array();
Expand All @@ -464,7 +464,7 @@ public static unsafe float[] ConvertNativePackedFloat32ArrayToSystemArray(godot_
}

public static unsafe godot_packed_float32_array ConvertSystemArrayToNativePackedFloat32Array(
Span<float> p_array)
ReadOnlySpan<float> p_array)
{
if (p_array.IsEmpty)
return new godot_packed_float32_array();
Expand All @@ -488,7 +488,7 @@ public static unsafe double[] ConvertNativePackedFloat64ArrayToSystemArray(godot
}

public static unsafe godot_packed_float64_array ConvertSystemArrayToNativePackedFloat64Array(
Span<double> p_array)
ReadOnlySpan<double> p_array)
{
if (p_array.IsEmpty)
return new godot_packed_float64_array();
Expand All @@ -510,7 +510,7 @@ public static unsafe string[] ConvertNativePackedStringArrayToSystemArray(godot_
return array;
}

public static godot_packed_string_array ConvertSystemArrayToNativePackedStringArray(Span<string> p_array)
public static godot_packed_string_array ConvertSystemArrayToNativePackedStringArray(ReadOnlySpan<string> p_array)
{
godot_packed_string_array dest = new godot_packed_string_array();

Expand Down Expand Up @@ -545,7 +545,7 @@ public static unsafe Vector2[] ConvertNativePackedVector2ArrayToSystemArray(godo
}

public static unsafe godot_packed_vector2_array ConvertSystemArrayToNativePackedVector2Array(
Span<Vector2> p_array)
ReadOnlySpan<Vector2> p_array)
{
if (p_array.IsEmpty)
return new godot_packed_vector2_array();
Expand All @@ -569,7 +569,7 @@ public static unsafe Vector3[] ConvertNativePackedVector3ArrayToSystemArray(godo
}

public static unsafe godot_packed_vector3_array ConvertSystemArrayToNativePackedVector3Array(
Span<Vector3> p_array)
ReadOnlySpan<Vector3> p_array)
{
if (p_array.IsEmpty)
return new godot_packed_vector3_array();
Expand All @@ -593,7 +593,7 @@ public static unsafe Vector4[] ConvertNativePackedVector4ArrayToSystemArray(godo
}

public static unsafe godot_packed_vector4_array ConvertSystemArrayToNativePackedVector4Array(
Span<Vector4> p_array)
ReadOnlySpan<Vector4> p_array)
{
if (p_array.IsEmpty)
return new godot_packed_vector4_array();
Expand All @@ -616,7 +616,7 @@ public static unsafe Color[] ConvertNativePackedColorArrayToSystemArray(godot_pa
return array;
}

public static unsafe godot_packed_color_array ConvertSystemArrayToNativePackedColorArray(Span<Color> p_array)
public static unsafe godot_packed_color_array ConvertSystemArrayToNativePackedColorArray(ReadOnlySpan<Color> p_array)
{
if (p_array.IsEmpty)
return new godot_packed_color_array();
Expand Down

0 comments on commit a7b039f

Please sign in to comment.