chenqiyang
2021-08-20 7b95fb4d4549d3452ee17165236186afc1f2b393
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*
    belle-sip - SIP (RFC3261) library.
    Copyright (C) 2019  Belledonne Communications SARL
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    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 {
 
class ObjectCAccessors;
 
class BELLESIP_EXPORT Object {
    friend ObjectCAccessors;
    public:
        Object();
        Object *ref();
        const Object *ref() const;
        void unref();
        //Overrides should keep    the size of toString() lower than BELLE_SIP_MAX_TO_STRING_SIZE
            virtual std::string toString() const;
        virtual Object *clone()const;
        belle_sip_cpp_object_t *getCObject();
        const belle_sip_cpp_object_t *getCObject()const;
        void *getCPtr(){
            return static_cast<void*>(getCObject());
        }
        const void *getCPtr()const{
            return static_cast<const void*>(getCObject());
        }
        static Object *getCppObject(void *);
        static const Object *getCppObject(const void *);
 
    protected:
        virtual ~Object(); /*the destructor must be kept protected, never public, including for all classes inherting from this*/
        Object(const Object &other);
        void constUnref()const;
    private:
        void init();
        mutable belle_sip_cpp_object_t mObject;
        belle_sip_error_code marshal(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
 *   of the class inheriting from HybridObject.
 * Example:
 * typedef struct _CExample CExample;
 * class Example : public HybridObject<CExample, Example>{
 * ...
 * }
 * The C object can be obtained with toC() method, directly casted in the expected type.
 * The C++ object can be obtained from C object with static method toCpp().
 * The destructor MUST be kept protected so that no one can call delete operator on the object. Instead unref() must be used.
 * make_shared<>() MUST NOT be used to instanciate an HybridObject, use create() instead.
 * a shared_ptr<> can be obtained at any time from an HybridObject using getSharedFromThis().
 * The static getSharedFromThis(_Ctype*) method can be used to directly obtain a shared_ptr from the C object.
 * 
 * The clone() method must be overriden to return a new _CppType contructed with copy contructor,
 * or return nullptr if the object is defined to be not clonable.
 *
 * Rational for using this template:
 * - You have an existing library in C where all C objects are inheriting from belle_sip_object_t (for refcounting, data_set etc...).
 * - You want to use C++ in your library without making any disruption in the API.
 * IMPORTANT: 
 * If you don't care about belle_sip_object_t inheritance in your C api, 
 * or if you don't need any C api associated to this object at all, DON'T USE THIS.
 * An usage example is shown in tester/object_tester.cc .
**/
template <typename _CType, typename _CppType>
class HybridObject : public Object {
    public:
        //Create the C++ object returned as a shared_ptr. 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 (new _CppType(std::forward<_Args>(__args)...))->toSharedPtr();
        }
        //Convenience creator to get the C object object instead. 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)...);
            return obj->toC();
        }
        //Obtain the C object from this.
        _CType *toC(){
            return static_cast<_CType*>(getCPtr());
        }
        //Obtain the C object this, when it is const.
        const _CType *toC()const{
            return static_cast<const _CType*>(getCPtr());
        }
        //Obtain the C++ object as a normal pointer.
        static _CppType *toCpp(_CType *ptr){
            return static_cast<_CppType *>(getCppObject(ptr));
        }
        //Obtain the C++ object as a normal pointer, when the c++ object is const.
        static const _CppType *toCpp(const _CType *ptr){
            return static_cast<const _CppType *>(getCppObject(ptr));
        }
        //Obtain a shared_ptr from the C++ object.
        std::shared_ptr<_CppType> getSharedFromThis() {
            this->ref();
            return std::shared_ptr<_CppType>(static_cast<_CppType *>(this), std::mem_fn(&Object::unref));
        }
        //Obtain a shared_ptr from the C++ object in the const case.
        std::shared_ptr<const _CppType> getSharedFromThis () const {
            this->ref();
            return std::shared_ptr<const _CppType>(static_cast<const _CppType *>(this), std::mem_fn(&HybridObject<_CType,_CppType>::constUnref));
        }
        //Convenience method for easy CType -> shared_ptr<CppType> conversion
        static std::shared_ptr<_CppType> getSharedFromThis(_CType *ptr) {
            return toCpp(ptr)->getSharedFromThis();
        }
        //Convenience method for easy CType -> shared_ptr<CppType> conversion
        static std::shared_ptr<const _CppType> getSharedFromThis(const _CType *ptr) {
            return toCpp(const_cast<_CType *>(ptr))->getSharedFromThis();
        }
        // Obtain a shared_ptr that takes ownership of the object.
        // Use this method with caution as it will transfer the ownership of the object to the shared_ptr, unlike getSharedFromThis() that
        // gives you a new reference to the object.
        // This method should be only useful to transfer into a shared_ptr an object that was created as a normal pointer, for example
        // by clone() method.
        // There should be NO const variant of this method.
        std::shared_ptr<_CppType> toSharedPtr(){
            return std::shared_ptr<_CppType>(static_cast<_CppType *>(this), std::mem_fn(&Object::unref));
        }
        
        //Convenience method for easy bctbx_list(_Ctype) -> std::list<_CppType> conversion
        //It does not take ownership of the hybrid object, but takes a ref.
        static std::list<std::shared_ptr<_CppType>> getCppListFromCList(const bctbx_list_t *cList) {
            std::list<std::shared_ptr<_CppType>> result;
            for (auto it = cList; it != nullptr; it = bctbx_list_next(it))
                result.push_back(toCpp(static_cast<_CType>(bctbx_list_get_data(it)))->getSharedFromThis() );
            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<std::shared_ptr<_CppType>> getCppListFromCList(const bctbx_list_t *cList, const std::function<std::shared_ptr<_CppType> (_CType *)> &func) {
            std::list<std::shared_ptr<_CppType>> result;
            for (auto it = cList; it != nullptr; it = bctbx_list_next(it))
                 result.push_back(func(static_cast<_CType*>(bctbx_list_get_data(it))));
            return result;
        }
        //Convenience method for easy std::list<shared_ptr<CppType>> -> bctbx_list(CType) conversion
        //It does not take ownership of the hybrid object, but takes a ref.
        static bctbx_list_t* getCListFromCppList(const std::list<std::shared_ptr<_CppType> > &cppList) {
            bctbx_list_t *result = nullptr;
            for (auto it = cppList.begin(); it != cppList.end(); it++) {
                std::shared_ptr<_CppType> cppPtr = static_cast<std::shared_ptr<_CppType>>(*it);
                cppPtr->ref();
                _CType *cptr = cppPtr->toC();
                result = bctbx_list_append(result, cptr);
            }
            return result;
        }
        //Convenience method for easy std::list<CppType*> -> bctbx_list(CType) conversion
        //It does not take ownership of the hybrid object, but takes a ref.
        static bctbx_list_t* getCListFromCppList(const std::list<_CppType*> &cppList) {
            bctbx_list_t *result = nullptr;
            for (auto it = cppList.begin(); it != cppList.end(); it++) {
                _CppType *cppPtr = static_cast<_CppType*>(*it);
                cppPtr->ref();
                _CType *cptr = cppPtr->toC();
                result = bctbx_list_append(result, cptr);
            }
            return result;
        }
 
    protected:
        virtual ~HybridObject() {}
        HybridObject() {}
        HybridObject(const HybridObject<_CType, _CppType> &other) : Object(other) {}
};
 
 
}//end of namespace
 
extern "C" {
    BELLE_SIP_DECLARE_VPTR(belle_sip_cpp_object_t);
}
 
 
 
#endif //belle_sip_object_plusplus_h