Skip to content

Commit e975fa7

Browse files
committed
Fix method calling macro for templates
1 parent f4ebb11 commit e975fa7

File tree

5 files changed

+81
-15
lines changed

5 files changed

+81
-15
lines changed

src/CppCall.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module CppCall
33
using ClangCompiler
44
using ClangCompiler: AbstractClangType, AbstractType, AbstractBuiltinType, AbstractRecordType
55
using ClangCompiler: QualType, RecordType, EnumType, ElaboratedType, TypedefType
6-
using ClangCompiler: TemplateSpecializationType
6+
using ClangCompiler: TemplateSpecializationType, SubstTemplateTypeParmType
77
using ClangCompiler: isTypeAlias, getAliasedType, isSugared, get_template_args
88
using ClangCompiler: PointerType, LValueReferenceType, RValueReferenceType
99
using ClangCompiler: FunctionNoProtoType, FunctionProtoType

src/call.jl

+32-5
Original file line numberDiff line numberDiff line change
@@ -144,17 +144,43 @@ end
144144

145145
#! format: off
146146
get_class(::Type{T}) where {T} = error("invalid object type: $T, expected a `CppObject` that represents a C++ object or a pointer to a C++ object")
147-
get_class(::Type{T}) where {S,Q,T<:CppType{S,Q}} = S
147+
get_class(::Type{T}) where {S,Q,T<:CppType{S,Q}} = string(S)
148148
get_class(::Type{S}) where {N,T<:CppType,S<:CppObject{T,N}} = get_class(T)
149149
get_class(::Type{S}) where {N,T<:CppType,S<:CppObject{Ptr{T},N}} = get_class(T)
150150
get_class(::Type{S}) where {N,T<:CppType,S<:CppObject{CppCPtr{T},N}} = get_class(T)
151151
get_class(::Type{S}) where {N,NR,T,V<:CppObject{T,N},S<:CppObject{Ptr{V},NR}} = get_class(T)
152152
get_class(::Type{S}) where {N,NR,T,V<:CppObject{T,N},S<:CppObject{CppCPtr{V},NR}} = get_class(T)
153+
154+
get_class(::Type{Cvoid}) = "void"
155+
get_class(::Type{Cchar}) = "char"
156+
get_class(::Type{Cuchar}) = "unsigned char"
157+
get_class(::Type{Cshort}) = "short"
158+
get_class(::Type{Cushort}) = "unsigned short"
159+
get_class(::Type{Cint}) = "int"
160+
get_class(::Type{Cuint}) = "unsigned int"
161+
get_class(::Type{Clong}) = "long"
162+
get_class(::Type{Culong}) = "unsigned long"
163+
if Clonglong !== Clong
164+
get_class(::Type{Clonglong}) = "long long"
165+
get_class(::Type{Culonglong}) = "unsigned long long"
166+
end
167+
get_class(::Type{Cfloat}) = "float"
168+
get_class(::Type{Cdouble}) = "double"
169+
get_class(::Type{Bool}) = "_Bool"
170+
171+
function get_class(::Type{CppTemplate{T,Targs}}) where {S,Q,T<:CppType{S,Q},Targs}
172+
return string(S) * "<" * join(map(x -> get_class(x), Targs.types), ",") * ">"
173+
end
174+
get_class(::Type{S}) where {N,T<:CppTemplate,S<:CppObject{T,N}} = get_class(T)
175+
get_class(::Type{S}) where {N,T<:CppTemplate,S<:CppObject{Ptr{T},N}} = get_class(T)
176+
get_class(::Type{S}) where {N,T<:CppTemplate,S<:CppObject{CppCPtr{T},N}} = get_class(T)
177+
# get_class(::Type{S}) where {N,NR,T<:CppTemplate,V<:CppObject{T,N},S<:CppObject{Ptr{V},NR}} = get_class(T)
178+
# get_class(::Type{S}) where {N,NR,T<:CppTemplate,V<:CppObject{T,N},S<:CppObject{CppCPtr{V},NR}} = get_class(T)
153179
#! format: on
154180

155181
@generated function cppmtcall(::CppContext{ID}, ::CppIdentifier{S}, obj::T, params...) where {ID,S,T}
156182
I = CPPCALL_INSTANCES[ID]
157-
n = string(get_class(T)) * "::" * string(S)
183+
n = get_class(T) * "::" * string(S)
158184
candidates = lookup(I, n, FuncOverloadingLookup())
159185
func = dispatch(I, candidates, params)
160186
isnothing(func) &&
@@ -202,7 +228,6 @@ end
202228

203229
_unwrap(::Type{Type{T}}) where {T} = T
204230

205-
206231
@inline function dispatch(I::CppInterpreter, func::FunctionProtoType, params)
207232
argnum = length(params) ÷ 2
208233
get_param_num(func) != argnum && return false
@@ -227,14 +252,16 @@ end
227252
return GC.@preserve result params invoke(x, ret_ptr, arg_ptrs, self)
228253
end
229254

230-
@inline function cppinvoke(x::CXScope, self::S, result::Union{CppObject,Ptr}, params...) where {N,T<:CppType,S<:CppObject{T,N}}
255+
@inline function cppinvoke(x::CXScope, self::S, result::Union{CppObject,Ptr},
256+
params...) where {N,T<:CppType,S<:CppObject{T,N}}
231257
ret_ptr = unsafe_pointer_rt(result)
232258
arg_ptrs = [unsafe_pointer(params[i]) for i = 1:(length(params) ÷ 2)]
233259
self_ptr = unsafe_pointer(self)
234260
return GC.@preserve self result params invoke(x, ret_ptr, arg_ptrs, self_ptr)
235261
end
236262

237-
@inline function cppinvoke(x::CXScope, self::S, result::Union{CppObject,Ptr}, params...) where {N,T,S<:CppObject{Ptr{T},N}}
263+
@inline function cppinvoke(x::CXScope, self::S, result::Union{CppObject,Ptr},
264+
params...) where {N,T,S<:CppObject{Ptr{T},N}}
238265
ret_ptr = unsafe_pointer_rt(result)
239266
arg_ptrs = [unsafe_pointer(params[i]) for i = 1:(length(params) ÷ 2)]
240267
self_ptr = reinterpret(Ptr{Cvoid}, self.data)

src/macros.jl

+11-4
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ macro undo(i)
4747
end)
4848
end
4949

50-
function cppinit(::Type{T}, I::CppInterpreter=@__INSTANCE__) where {T<:Union{BuiltinTypes,CppType{S,Q}}} where {S,Q}
50+
function cppinit(::Type{T}, I::CppInterpreter=@__INSTANCE__) where {T<:Union{BuiltinTypes,CppType{S,Q},CppTemplate}} where {S,Q}
5151
clty = to_cpp(T, I)
5252
jlty = to_jl(clty)
5353
sz = size_of(get_ast_context(I), clty)
@@ -138,13 +138,20 @@ macro ref(obj)
138138
end)
139139
end
140140

141-
_get_scope(::Type{CppType{S,Q}}, I::CppInterpreter=@__INSTANCE__) where {S,Q} = make_scope(lookup(I, string(S)), I)
142-
143141
function cppnew(::Type{T}, I::CppInterpreter=@__INSTANCE__) where {T<:CppType{S,Q}} where {S,Q}
144142
s = string(S)
145143
haskey(DEFAULT_TYPE_MAPPING, s) && return cppnew(DEFAULT_TYPE_MAPPING[s], I)
146144
jlty = to_jl(to_cpp(T, I))
147-
ptr = construct(_get_scope(T, I))
145+
decl = lookup(I, s)
146+
ptr = construct(make_scope(decl, I))
147+
N = Core.sizeof(Int)
148+
return CppObject{Ptr{jlty},N}(reinterpret(NTuple{N,UInt8}, ptr))
149+
end
150+
151+
function cppnew(::Type{T}, I::CppInterpreter=@__INSTANCE__) where {T<:CppTemplate}
152+
scope = instantiate(T, I)
153+
jlty = to_jl(to_cpp(ClassTemplateSpecializationDecl(scope.data), I))
154+
ptr = construct(scope)
148155
N = Core.sizeof(Int)
149156
return CppObject{Ptr{jlty},N}(reinterpret(NTuple{N,UInt8}, ptr))
150157
end

src/types.jl

+19-5
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ Represent a (possibly-)cv-qualified C++ type in Julia.
5757
"""
5858
struct CppType{S,Q} <: AbstractCppType end
5959

60+
get_s(::Type{CppType{S,Q}}) where {S,Q} = S
61+
get_q(::Type{CppType{S,Q}}) where {S,Q} = Q
62+
6063
"""
6164
CppType(x::AbstractString, q::Qualifier=Unqualified)
6265
Create a C++ type with the given name and qualifier. The qualifier is `Unqualified` by default.
@@ -85,8 +88,9 @@ A templated type where `T` is the [`CppType`](@ref) to be templated and
8588
"""
8689
struct CppTemplate{T<:CppType{S} where {S},TARGS} <: AbstractCppType end
8790

88-
get_rt(::Type{CppTemplate{T,TARGS}}) where {T<:CppType{S} where {S},TARGS} = T
89-
get_argst(::Type{CppTemplate{T,TARGS}}) where {T<:CppType{S} where {S},TARGS} = TARGS
91+
get_t(::Type{CppTemplate{T,TARGS}}) where {T<:CppType{S} where {S},TARGS} = T
92+
get_s(::Type{CppTemplate{T,TARGS}}) where {T<:CppType{S} where {S},TARGS} = S
93+
get_targs(::Type{CppTemplate{T,TARGS}}) where {T<:CppType{S} where {S},TARGS} = TARGS
9094

9195
CppTemplate(ty, targs...) = CppTemplate{ty,Tuple{targs...}}
9296

@@ -303,11 +307,19 @@ end
303307

304308
TemplateArgInfo(x::QualType) = CXTemplateArgInfo(x.ptr)
305309

306-
function to_cpp(::Type{CppTemplate{T,TARGS}}, I::CppInterpreter) where {S,Q,T<:CppType{S,Q},TARGS}
310+
function instantiate(::Type{CppTemplate{T,TARGS}}, I::CppInterpreter) where {S,Q,T<:CppType{S,Q},TARGS}
307311
template_decl = lookup(I, string(S)) # ClassTemplateDecl
308312
args = [TemplateArgInfo(to_cpp(t, I)) for t in TARGS.types]
309313
scope = instantiateTemplate(make_scope(template_decl, I), args)
310-
return get_decl_type(get_ast_context(I), ClassTemplateSpecializationDecl(scope.data))
314+
return scope
315+
end
316+
317+
to_cpp(x::ClassTemplateSpecializationDecl, I::CppInterpreter) = get_decl_type(get_ast_context(I), x)
318+
319+
function to_cpp(::Type{T}, I::CppInterpreter) where {T<:CppTemplate}
320+
scope = instantiate(T, I)
321+
ctsd = ClassTemplateSpecializationDecl(scope.data)
322+
return get_decl_type(get_ast_context(I), ctsd)
311323
end
312324

313325
function to_cpp(::Type{CppEnum{S}}, I::CppInterpreter) where {S}
@@ -436,13 +448,15 @@ function to_jl(x::TemplateSpecializationType, q::Qualifier=Unqualified)
436448
return CppTemplate{CppType{sym,q},Tuple{targs...}}
437449
end
438450

439-
440451
to_jl(x::ElaboratedType, ::Qualifier) = to_jl(x)
441452
to_jl(x::ElaboratedType) = to_jl(desugar(x))
442453

443454
to_jl(x::TypedefType, ::Qualifier) = to_jl(x)
444455
to_jl(x::TypedefType) = to_jl(desugar(x))
445456

457+
to_jl(x::SubstTemplateTypeParmType, ::Qualifier) = to_jl(x)
458+
to_jl(x::SubstTemplateTypeParmType) = to_jl(desugar(x))
459+
446460
function to_jl(x::PointerType, q::Qualifier=Unqualified)
447461
q == Unqualified ? Ptr{to_jl(get_pointee_type(x))} : CppPtr{q,to_jl(get_pointee_type(x))}
448462
end

test/template.jl

+18
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,21 @@ end
5050
jlty2 = to_jl(clty2)
5151
@test jlty2 == @template cpp"std::basic_string"{Cuchar, @template(cpp"std::char_traits"{Cuchar}), @template cpp"std::allocator"{Cuchar}}
5252
end
53+
54+
@testset "CppTemplate | Method Call" begin
55+
@test_logs min_level=Logging.Error declare"""#include <vector> """
56+
57+
const StdVector{T} = @template cpp"std::vector"{T} where T
58+
px = @cppnew StdVector{cpp"int"}
59+
sz = @mcall px->size()
60+
@test sz[] == 0
61+
62+
v = @cppinit cpp"int"
63+
v[] = 1
64+
@mcall px->push_back(v)
65+
66+
sz = @mcall px->size()
67+
@test sz[] == 1
68+
69+
@cppdelete px
70+
end

0 commit comments

Comments
 (0)