Commit d5468707 authored by Nicolas Michon's avatar Nicolas Michon

- 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
mdns_register.h
message.h
object.h
object++.hh
parameters.h
provider.h
refresher.h
......
......@@ -16,17 +16,22 @@
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/utils.h"
#include <memory>
#include <list>
#include <functional>
namespace bellesip{
namespace bellesip {
class ObjectCAccessors;
class BELLESIP_EXPORT Object{
class BELLESIP_EXPORT Object {
friend ObjectCAccessors;
public:
Object();
......@@ -38,8 +43,8 @@ class BELLESIP_EXPORT Object{
return ret;
}
virtual Object *clone()const;
belle_sip_object_t *getCObject();
const belle_sip_object_t *getCObject()const;
belle_sip_cpp_object_t *getCObject();
const belle_sip_cpp_object_t *getCObject()const;
void *getCPtr(){
return static_cast<void*>(getCObject());
}
......@@ -54,16 +59,16 @@ class BELLESIP_EXPORT Object{
Object(const Object &other);
private:
void init();
belle_sip_object_t mObject;
static belle_sip_object_t *sClone(belle_sip_object_t *);
static belle_sip_error_code sMarshal(belle_sip_object_t* obj, char* buff, size_t buff_size, size_t *offset);
belle_sip_cpp_object_t mObject;
static belle_sip_cpp_object_t *sClone(belle_sip_cpp_object_t *);
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++
* The template arguments are:
* - _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.
* Example:
* typedef struct _CExample CExample;
......@@ -81,9 +86,19 @@ class BELLESIP_EXPORT Object{
* An usage example is shown in tester/object_tester.cc .
**/
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:
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(){
return static_cast<_CType*>(getCPtr());
......@@ -97,8 +112,51 @@ class BELLESIP_EXPORT HybridObject : public Object{
static const _CppType *toCpp(const _CType *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:
virtual ~HybridObject() = default;
HybridObject() {
}
HybridObject(const HybridObject<_CType, _CppType> &other) : Object(other){
}
};
......@@ -114,6 +172,7 @@ BELLESIP_EXPORT std::shared_ptr<_T> make_shared(_Args&&... __args){
}//end of namespace
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
* It contains a generic data store that allows users to store named data in it and retrieve them afterwards.
*
* 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
* initially unowned, that is with reference count of 0. Such objets are also referred as "floating object". They are automatically destroyed
* 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, 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.
*
* 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
* 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.
**/
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_clone_t)(belle_sip_object_t* obj, const belle_sip_object_t *orig);
......@@ -184,7 +185,6 @@ struct _belle_sip_object{
belle_sip_list_t *data_store;
};
BELLE_SIP_BEGIN_DECLS
......
......@@ -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 *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) {
int belle_sip_object_unref_2(void *ptr) {
belle_sip_object_t *obj=BELLE_SIP_OBJECT(ptr);
if (obj->ref <= -1) {
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);
......
......@@ -19,20 +19,16 @@
#include "belle-sip/object++.hh"
#include "belle_sip_internal.h"
struct _belle_sip_cpp_object{
belle_sip_object_t base;
};
namespace bellesip{
namespace bellesip {
class ObjectCAccessors{
public:
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);
}
static void doDelete(belle_sip_object_t* obj){
delete Object::getCppObject(obj);
}
class ObjectCAccessors {
public:
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);
}
static void doDelete(belle_sip_object_t* obj) {
delete Object::getCppObject(obj);
}
};
void Object::init(){
......@@ -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_object_uninit(&mObject);
belle_sip_message("Object destroyed");
belle_sip_message("Object destroyed [%p]", &mObject);
}
Object *Object::ref(){
......@@ -90,7 +86,7 @@ const belle_sip_object_t *Object::getCObject()const{
}
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;
return reinterpret_cast<Object*>(cppaddr);
}
......@@ -101,12 +97,9 @@ const Object *Object::getCppObject(const void *ptr){
}//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){
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
static void basic_test(void){
int object_destroyed = FALSE;
Object *obj = new Object();
belle_sip_object_t *c_obj = obj->getCObject();
BC_ASSERT_PTR_NOT_NULL(c_obj);
if (c_obj){
......@@ -49,16 +49,17 @@ static void basic_test(void){
BC_ASSERT_TRUE(object_destroyed);
object_destroyed = false;
c_obj = clone->getCObject();
BC_ASSERT_PTR_NOT_NULL(c_obj);
if (c_obj){
belle_sip_object_weak_ref(c_obj, on_object_destroyed, &object_destroyed);
}
clone->unref();
BC_ASSERT_TRUE(object_destroyed);
BC_ASSERT_TRUE(object_destroyed);
};
typedef struct _LinphoneEvent LinphoneEvent;
typedef enum _LinphoneEventState{
......@@ -68,9 +69,10 @@ typedef enum _LinphoneEventState{
namespace Linphone{
class Event : public HybridObject<LinphoneEvent, Event>, public std::enable_shared_from_this<Event>{
class Event : public HybridObject<LinphoneEvent, Event> {
public:
enum State{
enum State {
Idle,
Subscribed
};
......@@ -147,7 +149,7 @@ static void dual_object_shared_ptr(void){
belle_sip_object_weak_ref(c_obj, on_object_destroyed, &object_destroyed);
}
ev.reset();
BC_ASSERT_TRUE(object_destroyed);
BC_ASSERT_TRUE(object_destroyed);
}
static void dual_object_shared_from_this(void){
......@@ -159,7 +161,7 @@ static void dual_object_shared_from_this(void){
if (c_obj){
belle_sip_object_weak_ref(c_obj, on_object_destroyed, &object_destroyed);
}
otherptr = ev->shared_from_this();
otherptr = ev->getSharedFromThis();
ev.reset();
BC_ASSERT_FALSE(object_destroyed);
otherptr.reset();
......@@ -169,22 +171,20 @@ static void dual_object_shared_from_this(void){
static void main_loop_cpp_do_later(void){
int test = 0;
belle_sip_main_loop_t *ml = belle_sip_main_loop_new();
belle_sip_main_loop_cpp_do_later(ml, [&test](){ test = 44; });
BC_ASSERT_TRUE(test == 0);
belle_sip_main_loop_sleep(ml, 10);
BC_ASSERT_TRUE(test == 44);
belle_sip_object_unref(ml);
}
static test_t object_tests[] = {
TEST_NO_TAG("Basic test", basic_test),
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_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,
......
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