Commit 26c0dccf authored by François Grisez's avatar François Grisez

C++ wrapper: pubilc structures support

parent 3ec8d366
......@@ -38,6 +38,7 @@ target_link_libraries(linphone++
target_include_directories(linphone++
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include
PRIVATE ${CMAKE_BINARY_DIR}/include
PRIVATE ${CMAKE_SOURCE_DIR}/include
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${BCTOOLBOX_INCLUDE_DIRS}
PRIVATE ${BELLESIP_INCLUDE_DIRS}
......
......@@ -178,7 +178,7 @@ class ArgName(Name):
return Name.to_snake_case(self)
class PropertyName(Name):
class PropertyName(ArgName):
pass
......@@ -357,6 +357,7 @@ class Property(DocumentableObject):
DocumentableObject.__init__(self, name)
self._setter = None
self._getter = None
self._type = None
def set_setter(self, setter):
self._setter = setter
......@@ -367,6 +368,8 @@ class Property(DocumentableObject):
def set_getter(self, getter):
self._getter = getter
if self._type is None:
self._type = getter.returnType
getter.parent = self
def get_getter(self):
......@@ -384,6 +387,7 @@ class Class(DocumentableObject):
self.classMethods = []
self._listenerInterface = None
self.multilistener = False
self.refcountable = False
def add_property(self, property):
self.properties.append(property)
......@@ -482,13 +486,21 @@ class CParser(object):
'linphone_friend_new', # was deprecated when the wrapper generator was made
'linphone_friend_new_with_address', # was deprecated when the wrapper generator was made
'linphone_core_get_sound_source', # was deprecated when the wrapper generator was made
'linphone_core_set_sound_source'] # was deprecated when the wrapper generator was made
'linphone_core_set_sound_source', # was deprecated when the wrapper generator was made
'linphone_core_get_sip_transports', # not wrappable
'linphone_core_get_sip_transports_used'] # not wrappable
self.classBl = ['LinphoneImEncryptionEngine',
'LinphoneImEncryptionEngineCbs',
'LinphoneImNotifPolicy',
'LpConfig',
'LinphoneCallStats'] # temporarly blacklisted
'LinphoneErrorInfo',
'LinphonePayloadType',
'LinphonePlayer'] # temporarly blacklisted
# list of classes that must be concidered as refcountable even if
# they are no ref()/unref() methods
self.forcedRefcountableClasses = ['LinphoneFactory']
self.cProject = cProject
......@@ -531,8 +543,19 @@ class CParser(object):
pass
except Error as e:
print('Could not parse \'{0}\' class: {1}'.format(_class.name, e.args[0]))
CParser._fix_all_types(self)
def _class_is_refcountable(self, _class):
if _class.name in self.forcedRefcountableClasses:
return True
for method in _class.instanceMethods:
if method.startswith(_class.cFunctionPrefix) and method[len(_class.cFunctionPrefix):] == 'ref':
return True
return False
def _fix_all_types(self):
for _class in self.classesIndex.values() + self.interfacesIndex.values():
if _class is not None:
......@@ -563,24 +586,24 @@ class CParser(object):
except Error as e:
print('warning: some types could not be fixed in {0}() function: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0]))
def _fix_type(self, type):
if isinstance(type, EnumType) and type.desc is None:
type.desc = self.enumsIndex[type.name]
elif isinstance(type, ClassType) and type.desc is None:
if type.name in self.classesIndex:
type.desc = self.classesIndex[type.name]
def _fix_type(self, _type):
if isinstance(_type, EnumType) and _type.desc is None:
_type.desc = self.enumsIndex[_type.name]
elif isinstance(_type, ClassType) and _type.desc is None:
if _type.name in self.classesIndex:
_type.desc = self.classesIndex[_type.name]
else:
type.desc = self.interfacesIndex[type.name]
elif isinstance(type, ListType) and type.containedTypeDesc is None:
if type.containedTypeName in self.classesIndex:
type.containedTypeDesc = ClassType(type.containedTypeName, classDesc=self.classesIndex[type.containedTypeName])
elif type.containedTypeName in self.interfacesIndex:
type.containedTypeDesc = ClassType(type.containedTypeName, classDesc=self.interfacesIndex[type.containedTypeName])
elif type.containedTypeName in self.enumsIndex:
type.containedTypeDesc = EnumType(type.containedTypeName, enumDesc=self.enumsIndex[type.containedTypeName])
_type.desc = self.interfacesIndex[_type.name]
elif isinstance(_type, ListType) and _type.containedTypeDesc is None:
if _type.containedTypeName in self.classesIndex:
_type.containedTypeDesc = ClassType(_type.containedTypeName, classDesc=self.classesIndex[_type.containedTypeName])
elif _type.containedTypeName in self.interfacesIndex:
_type.containedTypeDesc = ClassType(_type.containedTypeName, classDesc=self.interfacesIndex[_type.containedTypeName])
elif _type.containedTypeName in self.enumsIndex:
_type.containedTypeDesc = EnumType(_type.containedTypeName, enumDesc=self.enumsIndex[_type.containedTypeName])
else:
if type.containedTypeName is not None:
type.containedTypeDesc = CParser.parse_c_base_type(self, type.containedTypeName)
if _type.containedTypeName is not None:
_type.containedTypeDesc = CParser.parse_c_base_type(self, _type.containedTypeName)
else:
raise Error('bctbx_list_t type without specified contained type')
......@@ -621,6 +644,7 @@ class CParser(object):
name = ClassName()
name.from_camel_case(cclass.name, namespace=self.namespace.name)
_class = Class(name)
_class.refcountable = CParser._class_is_refcountable(self, cclass)
for cproperty in cclass.properties.values():
try:
......@@ -755,10 +779,8 @@ class CParser(object):
elif cType.ctype in self.enumsIndex:
absType = EnumType(cType.ctype, enumDesc=self.enumsIndex[cType.ctype])
elif cType.ctype in self.classesIndex or cType.ctype in self.interfacesIndex:
#params = {'classDesc': self.classesIndex[cType.ctype]}
#if 'const' in cType.completeType.split(' '):
#params['isconst'] = True
absType = ClassType(cType.ctype)
absType.isconst = cType.completeType.startswith('const ')
elif cType.ctype == self.cListType:
absType = ListType(cType.containedType)
else:
......
......@@ -43,14 +43,23 @@ namespace linphone {
{{/priorDeclarations}}
{{#_class}}
class {{className}}: public {{{parentClassName}}} {
class {{className}}{{#parentClassName}}: public {{{parentClassName}}}{{/parentClassName}} {
{{#friendClasses}}
friend class {{name}};
{{/friendClasses}}
public:
{{#isNotListener}}
{{#isrefcountable}}
{{{className}}}(void *ptr, bool takeRef=true);
{{/isrefcountable}}
{{#isnotrefcountable}}
LINPHONECXX_PUBLIC {{{className}}}();
LINPHONECXX_PUBLIC {{{className}}}(const {{{className}}} &src);
{{{className}}}(const void *src);
LINPHONECXX_PUBLIC ~{{{className}}}();
LINPHONECXX_PUBLIC const void *c_struct() const {return mPrivPtr;}
{{/isnotrefcountable}}
{{/isNotListener}}
{{#ismonolistenable}}
......@@ -71,6 +80,7 @@ namespace linphone {
{{#isVcard}}
LINPHONECXX_PUBLIC std::shared_ptr<belcard::BelCard> &getVcard();
{{/isVcard}}
{{#methods}}
{{{prototype}}}
......@@ -91,7 +101,11 @@ namespace linphone {
private:
void *mCallbacks;
{{/ismultilistenable}}
{{#isnotrefcountable}}
private:
void *mPrivPtr;
{{/isnotrefcountable}}
};
{{/_class}}
......
......@@ -47,12 +47,33 @@ static {{{returnType}}} {{{cbName}}}({{{declArgs}}}) {
{{/wrapperCbs}}
{{#isNotListener}}
{{#isrefcountable}}
{{{namespace}}}::{{{className}}}::{{{className}}}(void *ptr, bool takeRef): {{{parentClassName}}}(ptr, takeRef) {
{{#ismultilistenable}}
mCallbacks = ({{{cListenerName}}} *)createCallbacks(&getListeners());
{{{callbacksAdder}}}(({{{cClassName}}} *)mPrivPtr, ({{{cListenerName}}} *)mCallbacks);
{{/ismultilistenable}}
}
{{/isrefcountable}}
{{#isnotrefcountable}}
{{{namespace}}}::{{{className}}}::{{{className}}}() {
mPrivPtr = new {{{cClassName}}};
memset(mPrivPtr, 0, sizeof({{{cClassName}}}));
}
{{{namespace}}}::{{{className}}}::{{{className}}}(const {{{className}}} &src) {
mPrivPtr = new {{{cClassName}}}(*({{{cClassName}}} *)src.mPrivPtr);
}
{{{namespace}}}::{{{className}}}::{{{className}}}(const void *src) {
mPrivPtr = new {{{cClassName}}}(*({{{cClassName}}} *)src);
}
{{{namespace}}}::{{{className}}}::~{{{className}}}() {
delete ({{{cClassName}}} *)mPrivPtr;
}
{{/isnotrefcountable}}
{{/isNotListener}}
{{#ismonolistenable}}
......
......@@ -66,22 +66,24 @@ class CppTranslator(object):
ismonolistenable = (islistenable and not _class.multilistener)
ismultilistenable = (islistenable and _class.multilistener)
classDict = {}
classDict['islistenable'] = islistenable
classDict['isnotlistenable'] = not islistenable
classDict['ismonolistenable'] = ismonolistenable
classDict['ismultilistenable'] = ismultilistenable
classDict['isNotListener'] = True
classDict['isfactory'] = (_class.name.to_c() == 'LinphoneFactory')
classDict['isVcard'] = (_class.name.to_c() == 'LinphoneVcard')
classDict['parentClassName'] = None
classDict['className'] = CppTranslator.translate_class_name(_class.name)
classDict['cClassName'] = '::' + _class.name.to_c()
classDict['parentClassName'] = 'Object'
classDict['methods'] = []
classDict['staticMethods'] = []
classDict['wrapperCbs'] = []
classDict['friendClasses'] = []
classDict = {
'islistenable' : islistenable,
'isnotlistenable' : not islistenable,
'ismonolistenable' : ismonolistenable,
'ismultilistenable' : ismultilistenable,
'isrefcountable' : _class.refcountable,
'isnotrefcountable' : not _class.refcountable,
'isNotListener' : True,
'isfactory' : (_class.name.to_c() == 'LinphoneFactory'),
'isVcard' : (_class.name.to_c() == 'LinphoneVcard'),
'className' : CppTranslator.translate_class_name(_class.name),
'cClassName' : '::' + _class.name.to_c(),
'parentClassName' : 'Object' if _class.refcountable else None,
'methods' : [],
'staticMethods' : [],
'wrapperCbs' : [],
'friendClasses' : []
}
if _class.name.to_c() == 'LinphoneCore':
classDict['friendClasses'].append({'name': 'Factory'});
......@@ -279,20 +281,33 @@ class CppTranslator(object):
elif type(exprtype) is AbsApi.EnumType:
cExpr = '(::{0}){1}'.format(exprtype.desc.name.to_c(), cppExpr)
elif type(exprtype) is AbsApi.ClassType:
param = {}
param['ptrType'] = CppTranslator.translate_class_type(self, exprtype, namespace=usedNamespace)
param['ptrType'] = CppTranslator.sharedPtrTypeExtractor.match(param['ptrType']).group(2)
param['cPtrType'] = exprtype.desc.name.to_c()
param['cppExpr'] = cppExpr
param['object'] = 'const Object' if exprtype.isconst else 'Object'
cExpr = '(::{cPtrType} *)Object::sharedPtrToCPtr(std::static_pointer_cast<{object},{ptrType}>({cppExpr}))'.format(**param)
cPtrType = exprtype.desc.name.to_c()
if exprtype.desc.refcountable:
ptrType = CppTranslator.translate_class_type(self, exprtype, namespace=usedNamespace)
ptrType = CppTranslator.sharedPtrTypeExtractor.match(ptrType).group(2)
param = {
'ptrType' : ptrType,
'cPtrType': cPtrType,
'cppExpr' : cppExpr,
'object' : 'const Object' if exprtype.isconst else 'Object'
}
cExpr = '(::{cPtrType} *)Object::sharedPtrToCPtr(std::static_pointer_cast<{object},{ptrType}>({cppExpr}))'.format(**param)
else:
cExpr = '(const ::{_type} *)({expr}).c_struct()'.format(_type=cPtrType, expr=cppExpr)
elif type(exprtype) is AbsApi.ListType:
if type(exprtype.containedTypeDesc) is AbsApi.BaseType and exprtype.containedTypeDesc.name == 'string':
cExpr = 'StringBctbxListWrapper({0}).c_list()'.format(cppExpr)
elif type(exprtype.containedTypeDesc) is AbsApi.ClassType:
ptrType = CppTranslator.translate_class_type(self, exprtype.containedTypeDesc, namespace=usedNamespace)
ptrType = CppTranslator.sharedPtrTypeExtractor.match(ptrType).group(2)
cExpr = 'ObjectBctbxListWrapper<{0}>({1}).c_list()'.format(ptrType, cppExpr)
if exprtype.containedTypeDesc.desc.refcountable:
ptrType = CppTranslator.sharedPtrTypeExtractor.match(ptrType).group(2)
cExpr = 'ObjectBctbxListWrapper<{0}>({1}).c_list()'.format(ptrType, cppExpr)
else:
cType = exprtype.containedTypeDesc.desc.name.to_c()
if exprtype.isconst:
cExpr = 'StructBctbxListWrapper<{0},{1}>({2}).c_list()'.format(ptrType, cType, cppExpr)
else:
cExpr = 'StructBctbxListWrapper<{0},{1}>::cppListToBctbxList({2})'.format(ptrType, cType, cppExpr)
else:
raise AbsApi.Error('translation of bctbx_list_t of enums or basic C types is not supported')
......@@ -315,19 +330,26 @@ class CppTranslator(object):
return '({0}){1}'.format(cppEnumName, cExpr)
elif type(exprtype) is AbsApi.ClassType:
cppReturnType = CppTranslator.translate_class_type(self, exprtype, namespace=usedNamespace)
cppReturnType = CppTranslator.sharedPtrTypeExtractor.match(cppReturnType).group(2)
if type(exprtype.parent) is AbsApi.Method and len(exprtype.parent.name.words) >=1 and (exprtype.parent.name.words == ['new'] or exprtype.parent.name.words[0] == 'create'):
return 'Object::cPtrToSharedPtr<{0}>((::belle_sip_object_t *){1}, false)'.format(cppReturnType, cExpr)
if exprtype.desc.refcountable:
cppReturnType = CppTranslator.sharedPtrTypeExtractor.match(cppReturnType).group(2)
if type(exprtype.parent) is AbsApi.Method and len(exprtype.parent.name.words) >=1 and (exprtype.parent.name.words == ['new'] or exprtype.parent.name.words[0] == 'create'):
return 'Object::cPtrToSharedPtr<{0}>({1}, false)'.format(cppReturnType, cExpr)
else:
return 'Object::cPtrToSharedPtr<{0}>({1})'.format(cppReturnType, cExpr)
else:
return 'Object::cPtrToSharedPtr<{0}>((::belle_sip_object_t *){1})'.format(cppReturnType, cExpr)
return '{0}({1})'.format(exprtype.desc.name.to_camel_case(), cExpr);
elif type(exprtype) is AbsApi.ListType:
if type(exprtype.containedTypeDesc) is AbsApi.BaseType and exprtype.containedTypeDesc.name == 'string':
return 'StringBctbxListWrapper::bctbxListToCppList({0})'.format(cExpr)
elif type(exprtype.containedTypeDesc) is AbsApi.ClassType:
cppReturnType = CppTranslator.translate_class_type(self, exprtype.containedTypeDesc, namespace=usedNamespace)
cppReturnType = CppTranslator.sharedPtrTypeExtractor.match(cppReturnType).group(2)
return 'ObjectBctbxListWrapper<{0}>::bctbxListToCppList({1})'.format(cppReturnType, cExpr)
if exprtype.containedTypeDesc.desc.refcountable:
cppReturnType = CppTranslator.sharedPtrTypeExtractor.match(cppReturnType).group(2)
return 'ObjectBctbxListWrapper<{0}>::bctbxListToCppList({1})'.format(cppReturnType, cExpr)
else:
cType = exprtype.containedTypeDesc.desc.name.to_c()
return 'StructBctbxListWrapper<{0},{1}>::bctbxListToCppList({2})'.format(cppReturnType, cType, cExpr)
else:
raise AbsApi.Error('translation of bctbx_list_t of enums or basic C types is not supported')
else:
......@@ -429,13 +451,18 @@ class CppTranslator(object):
res = CppTranslator.translate_class_name(_type.desc.name, recursive=True, topAncestor=nsName)
if _type.isconst:
res = 'const ' + res
if type(_type.parent) is AbsApi.Argument:
return 'const std::shared_ptr<{0}> &'.format(res)
if _type.desc.refcountable:
if _type.isconst:
res = 'const ' + res
if type(_type.parent) is AbsApi.Argument:
return 'const std::shared_ptr<{0}> &'.format(res)
else:
return 'std::shared_ptr<{0}>'.format(res)
else:
return 'std::shared_ptr<{0}>'.format(res)
if type(_type.parent) is AbsApi.Argument:
return 'const {0} &'.format(res)
else:
return '{0}'.format(res)
def translate_list_type(self, _type, **params):
if _type.containedTypeDesc is None:
......@@ -679,6 +706,8 @@ def main():
render(renderer, header, includedir + '/enums.hh')
mainHeader = MainHeader()
mainHeader.add_include('enums.hh')
impl = ClassImpl()
for _class in parser.classesIndex.values() + parser.interfacesIndex.values():
......
......@@ -72,7 +72,7 @@ std::map<std::string,void *> &Object::getUserData() const {
return *userData;
}
Object *Object::getBackPtrFromCPtr(void *ptr) {
linphone::Object *linphone::Object::getBackPtrFromCPtr(const void *ptr) {
return (Object *)belle_sip_object_data_get((::belle_sip_object_t *)ptr, "cpp_object");
}
......
......@@ -85,11 +85,25 @@ namespace linphone {
}
}
}
template <class T>
static std::shared_ptr<const T> cPtrToSharedPtr(const void *ptr, bool takeRef=true) {
if (ptr == NULL) {
return nullptr;
} else {
Object *cppPtr = getBackPtrFromCPtr(ptr);
if (cppPtr == NULL) {
return std::make_shared<const T>((void *)ptr, takeRef);
} else {
return std::static_pointer_cast<const T,Object>(cppPtr->shared_from_this());
}
}
}
static void *sharedPtrToCPtr(const std::shared_ptr<const Object> &sharedPtr);
private:
LINPHONECXX_PUBLIC std::map<std::string,void *> &getUserData() const;
static Object *getBackPtrFromCPtr(void *ptr);
static Object *getBackPtrFromCPtr(const void *ptr);
template <class T> static void deleteSharedPtr(std::shared_ptr<T> *ptr) {if (ptr != NULL) delete ptr;}
static void deleteString(std::string *str) {if (str != NULL) delete str;}
......
......@@ -43,14 +43,12 @@ namespace linphone {
class ObjectBctbxListWrapper: public AbstractBctbxListWrapper {
public:
ObjectBctbxListWrapper(const std::list<std::shared_ptr<T> > &cppList) {
for(auto it=cppList.cbegin(); it!=cppList.cend(); it++) {
::belle_sip_object_t *cPtr = (::belle_sip_object_t *)Object::sharedPtrToCPtr(std::static_pointer_cast<Object,T>(*it));
if (cPtr != NULL) belle_sip_object_ref(cPtr);
mCList = bctbx_list_append(mCList, cPtr);
}
mCList = cppListToBctbxList(cppList);
}
virtual ~ObjectBctbxListWrapper() {
mCList = bctbx_list_free_with_data(mCList, unrefData);
if (mCList != NULL) {
bctbx_list_free_with_data(mCList, unrefData);
}
}
static std::list<std::shared_ptr<T> > bctbxListToCppList(const ::bctbx_list_t *bctbxList) {
std::list<std::shared_ptr<T> > cppList;
......@@ -60,6 +58,15 @@ namespace linphone {
}
return cppList;
}
static ::bctbx_list_t *cppListToBctbxList(const std::list<std::shared_ptr<T> > &cppList) {
bctbx_list_t *cList = NULL;
for(auto it=cppList.cbegin(); it!=cppList.cend(); it++) {
::belle_sip_object_t *cPtr = (::belle_sip_object_t *)Object::sharedPtrToCPtr(std::static_pointer_cast<Object,T>(*it));
if (cPtr != NULL) belle_sip_object_ref(cPtr);
cList = bctbx_list_append(cList, cPtr);
}
return cList;
}
private:
static void unrefData(void *data) {
......@@ -75,6 +82,35 @@ namespace linphone {
static std::list<std::string> bctbxListToCppList(const ::bctbx_list_t *bctbxList);
};
template <class T, class U>
class StructBctbxListWrapper: public AbstractBctbxListWrapper {
public:
StructBctbxListWrapper(const std::list<T> &cppList): AbstractBctbxListWrapper() {
mCList = cppListToBctbxList(cppList);
}
virtual ~StructBctbxListWrapper() {
bctbx_list_free_with_data(mCList, (bctbx_list_free_func)deleteCStruct);
}
static std::list<T> bctbxListToCppList(const ::bctbx_list_t *bctbxList) {
std::list<T> cppList;
for(const bctbx_list_t *it = bctbx_list_first_elem(bctbxList); it != NULL; it = bctbx_list_next(it)) {
cppList->push_back(T(it->data));
}
return cppList;
}
static bctbx_list_t *cppListToBctbxList(const std::list<T> &cppList) {
bctbx_list_t *cList = NULL;
for(auto it=cppList.cbegin(); it!=cppList.cend(); it++) {
cList = bctbx_list_append(cList, new U(it->c_struct()));
}
return cList;
}
private:
static void deleteCStruct(U *cStruct) {delete cStruct;}
};
class StringUtilities {
public:
static std::string cStringToCpp(const char *cstr);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment