Commit d5468707 authored by Nicolas Michon's avatar Nicolas Michon
Browse files

- Declare HybridObject constructor protected.

- Add Factory methods for shared_ptr and C Object creation inside HybridObject
- Add Convenience methods for easy list conversion
parent 7bd7c285
...@@ -40,6 +40,7 @@ set(HEADER_FILES ...@@ -40,6 +40,7 @@ set(HEADER_FILES
mdns_register.h mdns_register.h
message.h message.h
object.h object.h
object++.hh
parameters.h parameters.h
provider.h provider.h
refresher.h refresher.h
......
...@@ -16,17 +16,22 @@ ...@@ -16,17 +16,22 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef belle_sip_object_plusplus_h
#define belle_sip_object_plusplus_h
#include "belle-sip/types.h"
#include "belle-sip/object.h" #include "belle-sip/object.h"
#include "belle-sip/utils.h"
#include <memory> #include <memory>
#include <list>
#include <functional> #include <functional>
namespace bellesip{ namespace bellesip {
class ObjectCAccessors; class ObjectCAccessors;
class BELLESIP_EXPORT Object{ class BELLESIP_EXPORT Object {
friend ObjectCAccessors; friend ObjectCAccessors;
public: public:
Object(); Object();
...@@ -38,8 +43,8 @@ class BELLESIP_EXPORT Object{ ...@@ -38,8 +43,8 @@ class BELLESIP_EXPORT Object{
return ret; return ret;
} }
virtual Object *clone()const; virtual Object *clone()const;
belle_sip_object_t *getCObject(); belle_sip_cpp_object_t *getCObject();
const belle_sip_object_t *getCObject()const; const belle_sip_cpp_object_t *getCObject()const;
void *getCPtr(){ void *getCPtr(){
return static_cast<void*>(getCObject()); return static_cast<void*>(getCObject());
} }
...@@ -54,16 +59,16 @@ class BELLESIP_EXPORT Object{ ...@@ -54,16 +59,16 @@ class BELLESIP_EXPORT Object{
Object(const Object &other); Object(const Object &other);
private: private:
void init(); void init();
belle_sip_object_t mObject; belle_sip_cpp_object_t mObject;
static belle_sip_object_t *sClone(belle_sip_object_t *); static belle_sip_cpp_object_t *sClone(belle_sip_cpp_object_t *);
static belle_sip_error_code sMarshal(belle_sip_object_t* obj, char* buff, size_t buff_size, size_t *offset); static belle_sip_error_code sMarshal(belle_sip_cpp_object_t* obj, char* buff, size_t buff_size, size_t *offset);
}; };
/** /**
* Template class to help define an Object usable in both C and C++ * Template class to help define an Object usable in both C and C++
* The template arguments are: * The template arguments are:
* - _CType : the type used to represent this object in C * - _CType : the type used to represent this object in C
* - _CppType : the type used in C++ to implement this object. _CppType is used to be set to the type * - _CppType : the type used in C++ to implement this object. _CppType is used to be set to the type
* of the class inheriting from HybridObject. * of the class inheriting from HybridObject.
* Example: * Example:
* typedef struct _CExample CExample; * typedef struct _CExample CExample;
...@@ -81,9 +86,19 @@ class BELLESIP_EXPORT Object{ ...@@ -81,9 +86,19 @@ class BELLESIP_EXPORT Object{
* An usage example is shown in tester/object_tester.cc . * An usage example is shown in tester/object_tester.cc .
**/ **/
template <typename _CType, typename _CppType> template <typename _CType, typename _CppType>
class BELLESIP_EXPORT HybridObject : public Object{ class BELLESIP_EXPORT HybridObject : public Object, public std::enable_shared_from_this<HybridObject<_CType, _CppType> > {
public: public:
HybridObject(){ //Ref is managed by shared_ptr, unref will be called on last ref.
template <typename... _Args>
static inline std::shared_ptr<_CppType> create(_Args&&... __args) {
return std::shared_ptr<_CppType>(new _CppType(std::forward<_Args>(__args)...), std::mem_fun(&Object::unref));
}
//Convenience creator to get a C object. Automatically aquires a ref. Consumers have the responsibility to unref
template <typename... _Args>
static inline _CType *createCObject(_Args&&... __args) {
_CppType *obj = new _CppType(std::forward<_Args>(__args)...);
obj->ref();
return obj->toC();
} }
_CType *toC(){ _CType *toC(){
return static_cast<_CType*>(getCPtr()); return static_cast<_CType*>(getCPtr());
...@@ -97,8 +112,51 @@ class BELLESIP_EXPORT HybridObject : public Object{ ...@@ -97,8 +112,51 @@ class BELLESIP_EXPORT HybridObject : public Object{
static const _CppType *toCpp(const _CType *ptr){ static const _CppType *toCpp(const _CType *ptr){
return static_cast<const _CppType *>(getCppObject(ptr)); return static_cast<const _CppType *>(getCppObject(ptr));
} }
std::shared_ptr<const _CppType> getSharedFromThis() const {
try {
return std::dynamic_pointer_cast<const _CppType>(this->shared_from_this());
} catch (const std::exception &up) {
belle_sip_error("getSharedFromThis() exception: Object not created with 'make_shared'. Error: [%s].", up.what());
return nullptr;
}
return nullptr;
}
std::shared_ptr<_CppType> getSharedFromThis () {
return std::const_pointer_cast<_CppType>(static_cast<const _CppType *>(this)->getSharedFromThis());
}
std::shared_ptr<_CppType> toSharedPtr() {
return std::shared_ptr<_CppType>(static_cast<_CppType *>(this), std::mem_fun(&Object::unref));
}
std::shared_ptr<const _CppType> toSharedPtr() const {
return std::shared_ptr<const _CppType>(static_cast<const _CppType *>(this), std::mem_fun(&Object::unref));
}
//Convenience method for easy CType -> shared_ptr<CppType> conversion
static std::shared_ptr<_CppType> toSharedPtr(const _CType *ptr) {
return toCpp(const_cast<_CType *>(ptr))->toSharedPtr();
}
//Convenience method for easy bctbx_list(_Ctype) -> std::list<_CppType> conversion
static std::list<_CppType> getCppListFromCList(const bctbx_list_t *cList) {
std::list<_CppType> result;
for (auto it = cList; it; it = bctbx_list_next(it))
result.push_back(toCpp(static_cast<_CType>(bctbx_list_get_data(it))));
return result;
}
//Convenience method for easy bctbx_list(_Ctype) -> std::list<_CppType> conversion
//Applies 'func' to get _CppType from _CType. Used in case we do not want to call `toCpp` on _Ctype
static std::list<_CppType> getCppListFromCList(const bctbx_list_t *cList, const std::function<_CppType (_CType)> &func) {
std::list<_CppType> result;
for (auto it = cList; it; it = bctbx_list_next(it))
result.push_back(func(static_cast<_CType>(bctbx_list_get_data(it))));
return result;
}
protected: protected:
virtual ~HybridObject() = default; virtual ~HybridObject() = default;
HybridObject() {
}
HybridObject(const HybridObject<_CType, _CppType> &other) : Object(other){ HybridObject(const HybridObject<_CType, _CppType> &other) : Object(other){
} }
}; };
...@@ -114,6 +172,7 @@ BELLESIP_EXPORT std::shared_ptr<_T> make_shared(_Args&&... __args){ ...@@ -114,6 +172,7 @@ BELLESIP_EXPORT std::shared_ptr<_T> make_shared(_Args&&... __args){
}//end of namespace }//end of namespace
extern "C" { extern "C" {
BELLE_SIP_DECLARE_VPTR(belle_sip_cpp_object_t); BELLE_SIP_DECLARE_VPTR(belle_sip_cpp_object_t);
} }
#endif //belle_sip_object_plusplus_h
...@@ -114,8 +114,8 @@ static BELLE_SIP_OBJECT_VPTR_TYPE(object_type) BELLE_SIP_OBJECT_VPTR_NAME(object ...@@ -114,8 +114,8 @@ static BELLE_SIP_OBJECT_VPTR_TYPE(object_type) BELLE_SIP_OBJECT_VPTR_NAME(object
* It contains a generic data store that allows users to store named data in it and retrieve them afterwards. * It contains a generic data store that allows users to store named data in it and retrieve them afterwards.
* *
* About object lifecycle<br> * About object lifecycle<br>
* In belle-sip, objects can be, depending on their types, initially owned, that there are created with a ref count of 1, or * In belle-sip, objects can be, depending on their types, initially owned, meaning that they are created with a ref count of 1, or
* initially unowned, that is with reference count of 0. Such objets are also referred as "floating object". They are automatically destroyed * initially unowned, meaning that they are created with reference count of 0. Such objets are also referred as "floating object". They are automatically destroyed
* by the main loop iteration, so a floating object can be seen as a temporary object, until someones calls belle_sip_object_ref() on it. * by the main loop iteration, so a floating object can be seen as a temporary object, until someones calls belle_sip_object_ref() on it.
* *
* In order to know whether a kind of object is initially owned or initially unowned, you can use the test program tester/belle_sip_object_describe. * In order to know whether a kind of object is initially owned or initially unowned, you can use the test program tester/belle_sip_object_describe.
...@@ -144,9 +144,10 @@ static BELLE_SIP_OBJECT_VPTR_TYPE(object_type) BELLE_SIP_OBJECT_VPTR_NAME(object ...@@ -144,9 +144,10 @@ static BELLE_SIP_OBJECT_VPTR_TYPE(object_type) BELLE_SIP_OBJECT_VPTR_NAME(object
* Internally, belle-sip objects containing pointers to other objects must take a reference count on the other objects they hold; and leave this reference * Internally, belle-sip objects containing pointers to other objects must take a reference count on the other objects they hold; and leave this reference
* when they no longer need it. This rule must be strictly followed by developers doing things inside belle-sip. * when they no longer need it. This rule must be strictly followed by developers doing things inside belle-sip.
**/ **/
typedef struct _belle_sip_object belle_sip_object_t;
typedef struct _belle_sip_cpp_object belle_sip_cpp_object_t;
typedef struct _belle_sip_object belle_sip_object_t;
//cpp object differ only in vptr, just typedef to belle_sip_object_t for simplicity
typedef struct _belle_sip_object belle_sip_cpp_object_t;
typedef void (*belle_sip_object_destroy_t)(belle_sip_object_t*); typedef void (*belle_sip_object_destroy_t)(belle_sip_object_t*);
typedef void (*belle_sip_object_clone_t)(belle_sip_object_t* obj, const belle_sip_object_t *orig); typedef void (*belle_sip_object_clone_t)(belle_sip_object_t* obj, const belle_sip_object_t *orig);
...@@ -184,7 +185,6 @@ struct _belle_sip_object{ ...@@ -184,7 +185,6 @@ struct _belle_sip_object{
belle_sip_list_t *data_store; belle_sip_list_t *data_store;
}; };
BELLE_SIP_BEGIN_DECLS BELLE_SIP_BEGIN_DECLS
......
...@@ -106,7 +106,7 @@ belle_sip_object_t * _belle_sip_object_init(belle_sip_object_t *obj, belle_sip_o ...@@ -106,7 +106,7 @@ belle_sip_object_t * _belle_sip_object_init(belle_sip_object_t *obj, belle_sip_o
belle_sip_object_t * _belle_sip_object_new(size_t objsize, belle_sip_object_vptr_t *vptr){ belle_sip_object_t * _belle_sip_object_new(size_t objsize, belle_sip_object_vptr_t *vptr){
belle_sip_object_t *obj=(belle_sip_object_t *)belle_sip_malloc0(vptr->size); belle_sip_object_t *obj=(belle_sip_object_t *)belle_sip_malloc0(vptr->size);
return _belle_sip_object_init(obj, vptr); return _belle_sip_object_init(obj, vptr);
} }
...@@ -133,6 +133,7 @@ void belle_sip_object_unref(void *ptr) { ...@@ -133,6 +133,7 @@ void belle_sip_object_unref(void *ptr) {
int belle_sip_object_unref_2(void *ptr) { int belle_sip_object_unref_2(void *ptr) {
belle_sip_object_t *obj=BELLE_SIP_OBJECT(ptr); belle_sip_object_t *obj=BELLE_SIP_OBJECT(ptr);
if (obj->ref <= -1) { if (obj->ref <= -1) {
belle_sip_error("Object [%p] freed twice or corrupted !",obj); belle_sip_error("Object [%p] freed twice or corrupted !",obj);
if (obj->vptr && obj->vptr->type_name) belle_sip_error("Object type might be [%s]",obj->vptr->type_name); if (obj->vptr && obj->vptr->type_name) belle_sip_error("Object type might be [%s]",obj->vptr->type_name);
......
...@@ -19,20 +19,16 @@ ...@@ -19,20 +19,16 @@
#include "belle-sip/object++.hh" #include "belle-sip/object++.hh"
#include "belle_sip_internal.h" #include "belle_sip_internal.h"
struct _belle_sip_cpp_object{ namespace bellesip {
belle_sip_object_t base;
};
namespace bellesip{
class ObjectCAccessors{ class ObjectCAccessors {
public: public:
static belle_sip_error_code sMarshal(belle_sip_object_t* obj, char* buff, size_t buff_size, size_t *offset){ static belle_sip_error_code sMarshal(belle_sip_object_t* obj, char* buff, size_t buff_size, size_t *offset) {
return Object::getCppObject(obj)->marshal(buff, buff_size, offset); return Object::getCppObject(obj)->marshal(buff, buff_size, offset);
} }
static void doDelete(belle_sip_object_t* obj){ static void doDelete(belle_sip_object_t* obj) {
delete Object::getCppObject(obj); delete Object::getCppObject(obj);
} }
}; };
void Object::init(){ void Object::init(){
...@@ -61,7 +57,7 @@ Object::~Object(){ ...@@ -61,7 +57,7 @@ Object::~Object(){
belle_sip_fatal("bellesip::Object [%p] has been destroyed directly with delete operator. This is prohibited, use unref() instead.", this); belle_sip_fatal("bellesip::Object [%p] has been destroyed directly with delete operator. This is prohibited, use unref() instead.", this);
} }
belle_sip_object_uninit(&mObject); belle_sip_object_uninit(&mObject);
belle_sip_message("Object destroyed"); belle_sip_message("Object destroyed [%p]", &mObject);
} }
Object *Object::ref(){ Object *Object::ref(){
...@@ -90,7 +86,7 @@ const belle_sip_object_t *Object::getCObject()const{ ...@@ -90,7 +86,7 @@ const belle_sip_object_t *Object::getCObject()const{
} }
Object *Object::getCppObject(void *ptr){ Object *Object::getCppObject(void *ptr){
belle_sip_object_t *obj = BELLE_SIP_OBJECT(ptr); belle_sip_cpp_object_t *obj = BELLE_SIP_CAST(ptr, belle_sip_cpp_object_t);
intptr_t cppaddr = (intptr_t)obj - (intptr_t)obj->vptr->cpp_offset; intptr_t cppaddr = (intptr_t)obj - (intptr_t)obj->vptr->cpp_offset;
return reinterpret_cast<Object*>(cppaddr); return reinterpret_cast<Object*>(cppaddr);
} }
...@@ -101,12 +97,9 @@ const Object *Object::getCppObject(const void *ptr){ ...@@ -101,12 +97,9 @@ const Object *Object::getCppObject(const void *ptr){
}//end of namespace }//end of namespace
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_cpp_object_t);
BELLE_SIP_INSTANCIATE_VPTR3(belle_sip_cpp_object_t,belle_sip_object_t,NULL,NULL,bellesip::ObjectCAccessors::sMarshal,NULL,NULL,FALSE,TRUE);
void belle_sip_cpp_object_delete(belle_sip_object_t *obj){ void belle_sip_cpp_object_delete(belle_sip_object_t *obj){
bellesip::ObjectCAccessors::doDelete(obj); bellesip::ObjectCAccessors::doDelete(obj);
} }
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_cpp_object_t);
BELLE_SIP_INSTANCIATE_VPTR3(belle_sip_cpp_object_t,belle_sip_object_t,NULL,NULL,bellesip::ObjectCAccessors::sMarshal,NULL,NULL,FALSE,TRUE);
...@@ -33,7 +33,7 @@ static void on_object_destroyed(void *userpointer, belle_sip_object_t *obj_being ...@@ -33,7 +33,7 @@ static void on_object_destroyed(void *userpointer, belle_sip_object_t *obj_being
static void basic_test(void){ static void basic_test(void){
int object_destroyed = FALSE; int object_destroyed = FALSE;
Object *obj = new Object(); Object *obj = new Object();
belle_sip_object_t *c_obj = obj->getCObject(); belle_sip_object_t *c_obj = obj->getCObject();
BC_ASSERT_PTR_NOT_NULL(c_obj); BC_ASSERT_PTR_NOT_NULL(c_obj);
if (c_obj){ if (c_obj){
...@@ -49,16 +49,17 @@ static void basic_test(void){ ...@@ -49,16 +49,17 @@ static void basic_test(void){
BC_ASSERT_TRUE(object_destroyed); BC_ASSERT_TRUE(object_destroyed);
object_destroyed = false; object_destroyed = false;
c_obj = clone->getCObject(); c_obj = clone->getCObject();
BC_ASSERT_PTR_NOT_NULL(c_obj); BC_ASSERT_PTR_NOT_NULL(c_obj);
if (c_obj){ if (c_obj){
belle_sip_object_weak_ref(c_obj, on_object_destroyed, &object_destroyed); belle_sip_object_weak_ref(c_obj, on_object_destroyed, &object_destroyed);
} }
clone->unref(); clone->unref();
BC_ASSERT_TRUE(object_destroyed); BC_ASSERT_TRUE(object_destroyed);
}; };
typedef struct _LinphoneEvent LinphoneEvent; typedef struct _LinphoneEvent LinphoneEvent;
typedef enum _LinphoneEventState{ typedef enum _LinphoneEventState{
...@@ -68,9 +69,10 @@ typedef enum _LinphoneEventState{ ...@@ -68,9 +69,10 @@ typedef enum _LinphoneEventState{
namespace Linphone{ namespace Linphone{
class Event : public HybridObject<LinphoneEvent, Event>, public std::enable_shared_from_this<Event>{ class Event : public HybridObject<LinphoneEvent, Event> {
public: public:
enum State{
enum State {
Idle, Idle,
Subscribed Subscribed
}; };
...@@ -147,7 +149,7 @@ static void dual_object_shared_ptr(void){ ...@@ -147,7 +149,7 @@ static void dual_object_shared_ptr(void){
belle_sip_object_weak_ref(c_obj, on_object_destroyed, &object_destroyed); belle_sip_object_weak_ref(c_obj, on_object_destroyed, &object_destroyed);
} }
ev.reset(); ev.reset();
BC_ASSERT_TRUE(object_destroyed); BC_ASSERT_TRUE(object_destroyed);
} }
static void dual_object_shared_from_this(void){ static void dual_object_shared_from_this(void){
...@@ -159,7 +161,7 @@ static void dual_object_shared_from_this(void){ ...@@ -159,7 +161,7 @@ static void dual_object_shared_from_this(void){
if (c_obj){ if (c_obj){
belle_sip_object_weak_ref(c_obj, on_object_destroyed, &object_destroyed); belle_sip_object_weak_ref(c_obj, on_object_destroyed, &object_destroyed);
} }
otherptr = ev->shared_from_this(); otherptr = ev->getSharedFromThis();
ev.reset(); ev.reset();
BC_ASSERT_FALSE(object_destroyed); BC_ASSERT_FALSE(object_destroyed);
otherptr.reset(); otherptr.reset();
...@@ -169,22 +171,20 @@ static void dual_object_shared_from_this(void){ ...@@ -169,22 +171,20 @@ static void dual_object_shared_from_this(void){
static void main_loop_cpp_do_later(void){ static void main_loop_cpp_do_later(void){
int test = 0; int test = 0;
belle_sip_main_loop_t *ml = belle_sip_main_loop_new(); belle_sip_main_loop_t *ml = belle_sip_main_loop_new();
belle_sip_main_loop_cpp_do_later(ml, [&test](){ test = 44; }); belle_sip_main_loop_cpp_do_later(ml, [&test](){ test = 44; });
BC_ASSERT_TRUE(test == 0); BC_ASSERT_TRUE(test == 0);
belle_sip_main_loop_sleep(ml, 10); belle_sip_main_loop_sleep(ml, 10);
BC_ASSERT_TRUE(test == 44); BC_ASSERT_TRUE(test == 44);
belle_sip_object_unref(ml); belle_sip_object_unref(ml);
} }
static test_t object_tests[] = { static test_t object_tests[] = {
TEST_NO_TAG("Basic test", basic_test), TEST_NO_TAG("Basic test", basic_test),
TEST_NO_TAG("Hybrid C/C++ object", dual_object), TEST_NO_TAG("Hybrid C/C++ object", dual_object),
TEST_NO_TAG("Hybrid C/C++ object with shared_ptr", dual_object_shared_ptr), TEST_NO_TAG("Hybrid C/C++ object with shared_ptr", dual_object_shared_ptr),
TEST_NO_TAG("Hybrid C/C++ object with shared_from_this", dual_object_shared_from_this), TEST_NO_TAG("Hybrid C/C++ object with shared_from_this", dual_object_shared_from_this),
TEST_NO_TAG("Mainloop's do_later in c++", main_loop_cpp_do_later) TEST_NO_TAG("Mainloop's do_later in c++", main_loop_cpp_do_later)
}; };
test_suite_t object_test_suite = {"Object", NULL, NULL, belle_sip_tester_before_each, belle_sip_tester_after_each, test_suite_t object_test_suite = {"Object", NULL, NULL, belle_sip_tester_before_each, belle_sip_tester_after_each,
......
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