...
 
Commits (31)
......@@ -20,7 +20,7 @@
#ifndef _L_ENUM_GENERATOR_H_
#define _L_ENUM_GENERATOR_H_
#include "linphone/utils/magic-macros.h"
#include "linphone/utils/general.h"
// =============================================================================
......
......@@ -21,9 +21,12 @@
#define _L_GENERAL_H_
#ifdef __cplusplus
#include <tuple>
#include <type_traits>
#endif
#include "linphone/utils/magic-macros.h"
// =============================================================================
#ifdef __cplusplus
......@@ -101,6 +104,8 @@ void l_assert (const char *condition, const char *file, int line);
// Define an integer version like: 0xXXYYZZ, XX=MAJOR, YY=MINOR, and ZZ=PATCH.
#define L_VERSION(MAJOR, MINOR, PATCH) (((MAJOR) << 16) | ((MINOR) << 8) | (PATCH))
#define L_AUTO_CONSTEXPR_RETURN(VALUE) -> decltype(VALUE) { return VALUE; }
// -----------------------------------------------------------------------------
// Data access.
// -----------------------------------------------------------------------------
......@@ -254,7 +259,7 @@ namespace Private {
};
template<typename... Args>
struct ResolveOverload : ResolveMemberFunctionOverload<Args...>, ResolveConstMemberFunctionOverload<Args...> {
struct ResolveOverload : ResolveConstMemberFunctionOverload<Args...>, ResolveMemberFunctionOverload<Args...> {
using ResolveMemberFunctionOverload<Args...>::operator();
using ResolveConstMemberFunctionOverload<Args...>::operator();
......@@ -265,8 +270,9 @@ namespace Private {
};
}
// Useful to select a specific overloaded function. (Avoid usage of static_cast.)
#define L_RESOLVE_OVERLOAD(ARGS) LinphonePrivate::Private::ResolveOverload<ARGS>
// Useful to select a specific overloaded function.
#define L_RESOLVE_OVERLOAD(...) \
LinphonePrivate::Private::ResolveOverload<__VA_ARGS__>()
// -----------------------------------------------------------------------------
// Wrapper public.
......@@ -275,6 +281,81 @@ namespace Private {
#define L_DECL_C_STRUCT(STRUCT) typedef struct _ ## STRUCT STRUCT;
#define L_DECL_C_STRUCT_PREFIX_LESS(STRUCT) typedef struct STRUCT STRUCT;
// -----------------------------------------------------------------------------
// Index Sequence (C++11 impl).
// -----------------------------------------------------------------------------
template<std::size_t...>
struct IndexSequence {
using type = IndexSequence;
};
namespace Private {
template<class S1, class S2>
struct ConcatSequence;
template<std::size_t... S1, std::size_t... S2>
struct ConcatSequence<IndexSequence<S1...>, IndexSequence<S2...>> :
IndexSequence<S1..., (sizeof...(S1) + S2)...> {};
template<std::size_t N>
struct MakeIndexSequence : ConcatSequence<
typename MakeIndexSequence<N / 2>::type,
typename MakeIndexSequence<N - N / 2>::type
> {};
template<>
struct MakeIndexSequence<0> : IndexSequence<> {};
template<>
struct MakeIndexSequence<1> : IndexSequence<0> {};
}
template<std::size_t N>
using MakeIndexSequence = typename Private::MakeIndexSequence<N>::type;
// -----------------------------------------------------------------------------
// Compile-time string.
// -----------------------------------------------------------------------------
namespace Private {
constexpr bool equal (const char *a, const char *b) {
return *a == *b ? (*a == '\0' || equal(a + 1, b + 1)) : false;
}
}
// See: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4121.pdf
template<std::size_t N> using RawStringLiteral = const char [N];
template<std::size_t N, typename = MakeIndexSequence<N>>
struct StringLiteral;
template<std::size_t N, std::size_t... Index>
struct StringLiteral<N, IndexSequence<Index...>> {
constexpr StringLiteral (RawStringLiteral<N> &inRaw) : raw{ (inRaw[Index])... } {}
constexpr char operator[] (std::size_t p) const {
return raw[p];
}
template<std::size_t M>
constexpr bool operator== (const StringLiteral<M> &other) const {
return N != M ? false : Private::equal(raw, other.raw);
}
template<std::size_t M>
constexpr bool operator!= (const StringLiteral<M> &other) const {
return !(*this == other);
}
RawStringLiteral<N> raw;
};
template<std::size_t N>
constexpr StringLiteral<N> makeStringLiteral (RawStringLiteral<N> &raw) {
return StringLiteral<N>(raw);
}
#endif // ifdef __cplusplus
LINPHONE_END_NAMESPACE
......
......@@ -20,25 +20,32 @@
#ifndef _L_MAGIC_MACROS_H_
#define _L_MAGIC_MACROS_H_
#include "linphone/utils/general.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
// -----------------------------------------------------------------------------
// Misc.
// -----------------------------------------------------------------------------
// Concat in depth context.
#define L_CONCAT__(A, B) A ## B
#define L_CONCAT_(A, B) L_CONCAT__(A, B)
#define L_CONCAT(A, B) L_CONCAT_(A, B)
// Expand X. Useful to deal with variadic on Windows.
#define L_EXPAND(X) X
#define L_EXPAND_VARIADIC(...) __VA_ARGS__
// -----------------------------------------------------------------------------
// Variadic arguments.
// -----------------------------------------------------------------------------
// Get argument numbers from variadic.
#define L_ARG_N( \
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, \
A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, N, ... \
) N
#define L_EXPAND(X) X
#define L_GET_N_ARGS(...) L_EXPAND(L_ARG_N( \
__VA_ARGS__, \
21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \
......@@ -98,10 +105,20 @@ LINPHONE_BEGIN_NAMESPACE
L_CONCAT(L_GET_HEAP_, L_GET_N_ARGS_SUB(__VA_ARGS__)) (__VA_ARGS__) \
)
#define L_GET_TAIL(NOOP, ...) __VA_ARGS__
// -----------------------------------------------------------------------------
// Callers.
// -----------------------------------------------------------------------------
// Call a macro on args.
#define L_CALL(MACRO, ARGS) MACRO ARGS
#define L_CALL_HELPER(MACRO, ARGS) MACRO ARGS
// -----------------------------------------------------------------------------
// Apply.
// -----------------------------------------------------------------------------
// Map each variadic args.
#define L_APPLY_1(MACRONAME, DATA, A1) \
L_CALL_HELPER(MACRONAME, (DATA, A1))
......@@ -282,6 +299,59 @@ LINPHONE_BEGIN_NAMESPACE
(MACRONAME, DATA, __VA_ARGS__) \
)
LINPHONE_END_NAMESPACE
// -----------------------------------------------------------------------------
// Apply on list.
// -----------------------------------------------------------------------------
#define L_APPLY_LIST_CALL_HELPER(MACRONAME, LIST, A1) \
L_CALL_HELPER(MACRONAME, (L_CALL_HELPER(L_GET_ARG_1, LIST), A1))
#define L_APPLY_LIST_GET_TAIL(LIST) \
(L_CALL_HELPER(L_GET_TAIL, LIST))
#define L_APPLY_LIST_1(MACRONAME, LIST, A1) \
L_APPLY_LIST_CALL_HELPER(MACRONAME, LIST, A1)
#define L_APPLY_LIST_2(MACRONAME, LIST, A1, A2) \
L_APPLY_LIST_CALL_HELPER(MACRONAME, LIST, A1), \
L_APPLY_LIST_1(MACRONAME, L_APPLY_LIST_GET_TAIL(LIST), A2)
#define L_APPLY_LIST_3(MACRONAME, LIST, A1, A2, A3) \
L_APPLY_LIST_CALL_HELPER(MACRONAME, LIST, A1), \
L_APPLY_LIST_2(MACRONAME, L_APPLY_LIST_GET_TAIL(LIST), A2, A3)
#define L_APPLY_LIST_4(MACRONAME, LIST, A1, A2, A3, A4) \
L_APPLY_LIST_CALL_HELPER(MACRONAME, LIST, A1), \
L_APPLY_LIST_3(MACRONAME, L_APPLY_LIST_GET_TAIL(LIST), A2, A3, A4)
#define L_APPLY_LIST_5(MACRONAME, LIST, A1, A2, A3, A4, A5) \
L_APPLY_LIST_CALL_HELPER(MACRONAME, LIST, A1), \
L_APPLY_LIST_4(MACRONAME, L_APPLY_LIST_GET_TAIL(LIST), A2, A3, A4, A5)
#define L_APPLY_LIST_6(MACRONAME, LIST, A1, A2, A3, A4, A5, A6) \
L_APPLY_LIST_CALL_HELPER(MACRONAME, LIST, A1), \
L_APPLY_LIST_5(MACRONAME, L_APPLY_LIST_GET_TAIL(LIST), A2, A3, A4, A5, A6)
#define L_APPLY_LIST_7(MACRONAME, LIST, A1, A2, A3, A4, A5, A6, A7) \
L_APPLY_LIST_CALL_HELPER(MACRONAME, LIST, A1), \
L_APPLY_LIST_6(MACRONAME, L_APPLY_LIST_GET_TAIL(LIST), A2, A3, A4, A5, A6, A7)
#define L_APPLY_LIST_8(MACRONAME, LIST, A1, A2, A3, A4, A5, A6, A7, A8) \
L_APPLY_LIST_CALL_HELPER(MACRONAME, LIST, A1), \
L_APPLY_LIST_7(MACRONAME, L_APPLY_LIST_GET_TAIL(LIST), A2, A3, A4, A5, A6, A7, A8)
#define L_APPLY_LIST_9(MACRONAME, LIST, A1, A2, A3, A4, A5, A6, A7, A8, A9) \
L_APPLY_LIST_CALL_HELPER(MACRONAME, LIST, A1), \
L_APPLY_LIST_8(MACRONAME, L_APPLY_LIST_GET_TAIL(LIST), A2, A3, A4, A5, A6, A7, A8, A9)
#define L_APPLY_LIST_10(MACRONAME, LIST, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) \
L_APPLY_LIST_CALL_HELPER(MACRONAME, LIST, A1), \
L_APPLY_LIST_9(MACRONAME, L_APPLY_LIST_GET_TAIL(LIST), A2, A3, A4, A5, A6, A7, A8, A9, A10)
#define L_APPLY_LIST(MACRONAME, LIST, ...) \
L_CALL( \
L_CONCAT(L_APPLY_LIST_, L_GET_N_ARGS(__VA_ARGS__)), \
(MACRONAME, LIST, __VA_ARGS__) \
)
#endif // ifndef _L_MAGIC_MACROS_H_
#endif // ifndef _MAGIC_MACROS_H_
......@@ -26,6 +26,10 @@
LINPHONE_BEGIN_NAMESPACE
// -----------------------------------------------------------------------------
// Private Impl.
// -----------------------------------------------------------------------------
namespace Private {
// See: http://en.cppreference.com/w/cpp/types/void_t
template<typename... T> struct MakeVoid {
......@@ -46,12 +50,26 @@ namespace Private {
decltype(std::declval<T&>()[std::declval<const typename T::key_type&>()])
>
> : std::true_type {};
template<typename T, typename U = void>
struct IsDefinedTypeImpl : std::false_type {};
template<typename T>
struct IsDefinedTypeImpl<T, typename void_t<T>::type> : std::true_type {};
};
// -----------------------------------------------------------------------------
// Public API.
// -----------------------------------------------------------------------------
// Check if a type is a std container like map, unordered_map...
template<typename T>
struct IsMapContainer : Private::IsMapContainerImpl<T>::type {};
// Check if a type is defined.
template<typename T>
struct IsDefinedTypeImpl : Private::IsDefinedTypeImpl<T>::type {};
LINPHONE_END_NAMESPACE
#endif // ifndef _L_TRAITS_H_
......@@ -139,6 +139,12 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
object/base-object.h
object/clonable-object-p.h
object/clonable-object.h
object/connection.h
object/internal/arguments.h
object/internal/function-call.h
object/internal/function-pointer.h
object/internal/list.h
object/internal/slot-object.h
object/object-head-p.h
object/object-head.h
object/object-p.h
......@@ -240,6 +246,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
object/app-data-container.cpp
object/base-object.cpp
object/clonable-object.cpp
object/connection.cpp
object/object.cpp
object/property-container.cpp
sal/call-op.cpp
......
......@@ -22,9 +22,8 @@
#include <bctoolbox/logging.h>
#include "object/base-object-p.h"
#include "logger.h"
#include "object/base-object-p.h"
// =============================================================================
......
......@@ -29,7 +29,7 @@
LINPHONE_BEGIN_NAMESPACE
class BaseObjectPrivate {
L_OBJECT_PRIVATE;
L_OBJECT_HEAD_PRIVATE;
public:
BaseObjectPrivate () = default;
......
......@@ -27,7 +27,7 @@
LINPHONE_BEGIN_NAMESPACE
L_OBJECT_IMPL(BaseObject);
L_OBJECT_HEAD_IMPL(BaseObject);
BaseObject::BaseObject (BaseObjectPrivate &p) : mPrivate(&p) {
mPrivate->mPublic = this;
......
......@@ -29,6 +29,7 @@
LINPHONE_BEGIN_NAMESPACE
class BaseObjectPrivate;
class MetaObject;
/*
* Base Object of Linphone. Cannot be cloned. Can be Shared.
......@@ -36,11 +37,15 @@ class BaseObjectPrivate;
* like Events.
*/
class LINPHONE_PUBLIC BaseObject {
L_OBJECT;
L_OBJECT_HEAD;
public:
virtual ~BaseObject ();
virtual const MetaObject *getMetaObject () const {
return nullptr;
};
protected:
explicit BaseObject (BaseObjectPrivate &p);
......
......@@ -31,7 +31,7 @@
LINPHONE_BEGIN_NAMESPACE
class ClonableObjectPrivate {
L_OBJECT_PRIVATE;
L_OBJECT_HEAD_PRIVATE;
public:
ClonableObjectPrivate () = default;
......
......@@ -28,7 +28,7 @@ LINPHONE_BEGIN_NAMESPACE
// -----------------------------------------------------------------------------
L_OBJECT_IMPL(ClonableObject);
L_OBJECT_HEAD_IMPL(ClonableObject);
ClonableObject::ClonableObject (ClonableObjectPrivate &p) {
setRef(p);
......
......@@ -42,7 +42,7 @@ LINPHONE_BEGIN_NAMESPACE
* intelligence.
*/
class LINPHONE_PUBLIC ClonableObject : public PropertyContainer {
L_OBJECT;
L_OBJECT_HEAD;
public:
virtual ~ClonableObject ();
......
/*
* connection.cpp
* Copyright (C) 2010-2017 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "connection.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
// TODO.
LINPHONE_END_NAMESPACE
/*
* connection.h
* Copyright (C) 2010-2017 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _L_CONNECTION_H_
#define _L_CONNECTION_H_
#include "linphone/utils/general.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class Connection {
public:
Connection () = default;
~Connection () = default;
operator bool () const {
return mConnected;
}
private:
// Object *mSender = nullptr;
// Object *mReceiver = nullptr;
bool mConnected = false;
};
LINPHONE_END_NAMESPACE
#endif // ifndef _L_CONNECTION_H_
/*
* arguments.h
* Copyright (C) 2010-2017 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _L_ARGUMENTS_H_
#define _L_ARGUMENTS_H_
#include "list.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
/*
* Internal compile time consistent arguments checker.
*/
namespace Private {
template<typename, typename>
struct ArgsConsistent {
enum {
Value = false
};
};
template<typename A>
struct ArgsConsistent<A, A> {
enum {
Value = true
};
};
template<typename A>
struct ArgsConsistent<A &, A &> {
enum {
Value = true
};
};
template<typename A>
struct ArgsConsistent<void, A> {
enum {
Value = true
};
};
template<typename A>
struct ArgsConsistent<A, void> {
enum {
Value = true
};
};
template<>
struct ArgsConsistent<void, void> {
enum {
Value = true
};
};
// ---------------------------------------------------------------------------
template<typename, typename>
struct ArgsListConsistent {
enum {
Value = false
};
};
template<>
struct ArgsListConsistent<List<>, List<>> {
enum {
Value = true
};
};
template<typename L>
struct ArgsListConsistent<L, List<>> {
enum {
Value = true
};
};
template<typename Arg1, typename Arg2, typename... Tail1, typename... Tail2>
struct ArgsListConsistent<List<Arg1, Tail1...>, List<Arg2, Tail2...>> {
typedef ArgsConsistent<Arg1, Arg2> Check;
typedef ArgsListConsistent<List<Tail1...>, List<Tail2...>> CheckList;
enum {
Value = Check::Value && CheckList::Value
};
};
}
LINPHONE_END_NAMESPACE
#endif // ifndef _L_ARGUMENTS_H_
/*
* function-call.h
* Copyright (C) 2010-2017 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _L_FUNCTION_CALL_H_
#define _L_FUNCTION_CALL_H_
#include "list.h"
// =============================================================================
#define MEMBER_CALL(QUALIFIER) \
template<int... Index, typename... SignalArgs, typename... SlotArgs, typename Ret, typename Obj> \
struct FunctionCall<IndexesList<Index...>, List<SignalArgs...>, Ret (Obj::*)(SlotArgs...) QUALIFIER> { \
static void call (Ret (Obj::*function)(SlotArgs...) QUALIFIER, Obj *object, void **args) { \
(object->*function)((*reinterpret_cast<typename std::remove_reference<SignalArgs>::type *>(args[Index])) ...); \
} \
};
LINPHONE_BEGIN_NAMESPACE
/*
* Internal compile time function call object.
*/
namespace Private {
template<int...>
struct IndexesList {};
template<typename, int>
struct IndexesAppend;
template<int... Left, int Right>
struct IndexesAppend<IndexesList<Left...>, Right> {
typedef IndexesList<Left..., Right> Value;
};
template<int N>
struct Indexes {
typedef typename IndexesAppend<typename Indexes<N - 1>::Value, N - 1>::Value Value;
};
template<>
struct Indexes<0> {
typedef IndexesList<> Value;
};
template<typename, typename, typename>
struct FunctionCall;
// Call to non-member function.
template<int... Index, typename... SignalArgs, typename Func>
struct FunctionCall<IndexesList<Index...>, List<SignalArgs...>, Func> {
static void call (Func &function, void **args) {
function((*reinterpret_cast<typename std::remove_reference<SignalArgs>::type *>(args[Index]))...);
}
};
// Call to member function.
MEMBER_CALL();
// Call to member function with const qualifier.
MEMBER_CALL(const);
}
LINPHONE_END_NAMESPACE
#undef MEMBER_CALL
#endif // ifndef _L_FUNCTION_CALL_H_
/*
* function-pointer.h
* Copyright (C) 2010-2017 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _L_FUNCTION_POINTER_H_
#define _L_FUNCTION_POINTER_H_
#include "function-call.h"
// =============================================================================
#define MEMBER_FUNCTION(QUALIFIER) \
template<typename Obj, typename Ret, typename... Args> \
struct FunctionPointer<Ret (Obj::*)(Args...) QUALIFIER> { \
typedef Obj Object; \
typedef Ret ReturnType; \
typedef Ret (Obj::*Function)(Args...) QUALIFIER; \
typedef List<Args...> Arguments; \
enum { \
ArgumentsNumber = sizeof ...(Args), \
IsMemberFunction = true \
}; \
template<typename SignalArgs> \
static void call (Function function, Obj *object, void **args) { \
FunctionCall<typename Indexes<ArgumentsNumber>::Value, SignalArgs, Function>::call(function, object, args); \
} \
}
LINPHONE_BEGIN_NAMESPACE
/*
* Internal compile time function pointer object.
*/
namespace Private {
// Not a valid function.
template<typename Func>
struct FunctionPointer {
enum {
ArgumentsNumber = -1,
IsMemberFunction = false
};
};
// A non-member function.
template<typename Ret, typename... Args>
struct FunctionPointer<Ret (*)(Args...)> {
typedef Ret ReturnType;
typedef Ret (*Function)(Args...);
typedef List<Args...> Arguments;
enum {
ArgumentsNumber = sizeof ...(Args),
IsMemberFunction = false
};
template<typename SignalArgs>
static void call (Function function, void *, void **args) {
FunctionCall<typename Indexes<ArgumentsNumber>::Value, SignalArgs, Function>::call(function, args);
}
};
// A member function.
MEMBER_FUNCTION();
// A member function with const qualifier.
MEMBER_FUNCTION(const);
/*
* Meta info of one function pointer.
* Useful to get arguments number, and function name.
*/
template<typename Function, int NameLength>
struct FunctionInfo {
Function function;
StringLiteral<NameLength> name;
static constexpr int argumentsNumber = FunctionPointer<Function>::ArgumentsNumber;
};
template<typename Function, int NameLength>
constexpr FunctionInfo<Function, NameLength> makeFunctionInfo (
Function function,
RawStringLiteral<NameLength> &name
) {
return { function, { name } };
}
}
LINPHONE_END_NAMESPACE
#undef MEMBER_FUNCTION
#endif // ifndef _L_FUNCTION_POINTER_H_
/*
* list.h
* Copyright (C) 2010-2017 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _L_LIST_H_
#define _L_LIST_H_
#include "linphone/utils/general.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
/*
* Internal compile time list.
*/
namespace Private {
template<typename...>
struct List {};
template<typename Head, typename... Tail>
struct List<Head, Tail...> {
typedef Head Car;
typedef List<Tail...> Cdr;
};
template<typename, typename>
struct ListAppend;
template<typename... L1, typename... L2>
struct ListAppend<List<L1...>, List<L2...>> {
typedef List<L1..., L2...> Value;
};
template<typename L, int N>
struct ListBuilder {
typedef typename ListAppend<
List<typename L::Car>,
typename ListBuilder<typename L::Cdr, N - 1>::Value
>::Value Value;
};
template<typename L>
struct ListBuilder<L, 0> {
typedef List<> Value;
};
}
LINPHONE_END_NAMESPACE
#endif // ifndef _L_LIST_H_
/*
* slot-object.h
* Copyright (C) 2010-2017 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _L_SLOT_OBJECT_H_
#define _L_SLOT_OBJECT_H_
#include "arguments.h"
#include "function-pointer.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
namespace Private {
// ---------------------------------------------------------------------------
// Abstract slot object.
// ---------------------------------------------------------------------------
class SlotObject {
public:
enum Action {
Call,
Delete
};
private:
typedef void (*CallFunction)(Action action, SlotObject *slotObject, Object *receiver, void **args);
public:
explicit SlotObject (CallFunction function) : mCallFunction(function) {}
inline void call (Action action, Object *receiver, void **args) {
mCallFunction(action, this, receiver, args);
}
protected:
~SlotObject () = default;
private:
const CallFunction mCallFunction;
L_DISABLE_COPY(SlotObject)
};
// ---------------------------------------------------------------------------
// Slot object with non-member function.
// ---------------------------------------------------------------------------
template<typename Func, typename Args>
class SlotObjectFunction : public SlotObject {
public:
explicit SlotObjectFunction (Func function) : SlotObject(&callImpl), mFunction(function) {}
private:
typedef Private::FunctionPointer<Func> FuncType;
static void callImpl (Action action, SlotObject *slotObject, Object *receiver, void **args) {
SlotObjectFunction *slotObjectFunction = static_cast<SlotObjectFunction *>(slotObject);
switch (action) {
case Call:
FuncType::template call<Args>(slotObjectFunction->mFunction, receiver, args);
break;
case Delete:
delete slotObjectFunction;
}
}
Func mFunction;
L_DISABLE_COPY(SlotObjectFunction)
};
// ---------------------------------------------------------------------------
// Slot object with member function.
// ---------------------------------------------------------------------------
template<typename Func, typename Args>
class SlotObjectMemberFunction : public SlotObject {
public:
explicit SlotObjectMemberFunction (Func function) : SlotObject(&callImpl), mFunction(function) {}
private:
typedef Private::FunctionPointer<Func> FuncType;
static void callImpl (Action action, SlotObject *slotObject, Object *receiver, void **args) {
SlotObjectMemberFunction *slotObjectMemberFunction = static_cast<SlotObjectMemberFunction *>(slotObject);
switch (action) {
case Call:
FuncType::template call<Args>(
slotObjectMemberFunction->mFunction,
static_cast<typename FuncType::Object *>(receiver),
args
);
break;
case Delete:
delete slotObjectMemberFunction;
break;
}
}
Func mFunction;
L_DISABLE_COPY(SlotObjectMemberFunction)
};
}
LINPHONE_END_NAMESPACE
#endif // ifndef _L_SLOT_OBJECT_H_
......@@ -22,7 +22,7 @@
// =============================================================================
#define L_OBJECT_IMPL(CLASS) \
#define L_OBJECT_HEAD_IMPL(CLASS) \
void *CLASS::getCBackPtr () const { \
L_D(); \
return d->cBackPtr; \
......@@ -32,7 +32,7 @@
d->cBackPtr = cBackPtr; \
}
#define L_OBJECT_PRIVATE \
#define L_OBJECT_HEAD_PRIVATE \
void *cBackPtr = nullptr;
#endif // ifndef _L_OBJECT_HEAD_P_H_
......@@ -22,7 +22,7 @@
// =============================================================================
#define L_OBJECT \
#define L_OBJECT_HEAD \
void *getCBackPtr () const; \
void setCBackPtr (void *cBackPtr);
......
......@@ -25,8 +25,30 @@
// =============================================================================
// -----------------------------------------------------------------------------
// Public macros API.
// -----------------------------------------------------------------------------
// Declare Smart Object implementation.
#define L_OBJECT_IMPL(CLASS) \
constexpr LinphonePrivate::MetaObject CLASS::metaObject = LinphonePrivate::Private::createMetaObject<CLASS>(); \
const LinphonePrivate::MetaObject *CLASS::getMetaObject () const { \
return &CLASS::metaObject; \
};
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
namespace Private {
template<typename T>
constexpr MetaObject createMetaObject () {
// TODO.
return MetaObject();
}
};
class ObjectPrivate : public BaseObjectPrivate {
protected:
inline const Object::Lock &getLock () const {
......
......@@ -28,8 +28,40 @@ LINPHONE_BEGIN_NAMESPACE
// -----------------------------------------------------------------------------
void MetaObject::activateSignal (Object *sender, const MetaObject *metaObject, int signalIndex, void **args) {
// TODO.
}
const char *MetaObject::getClassName () const {
// TODO.
return nullptr;
}
const MetaObject *MetaObject::getParent () const {
// TODO
return nullptr;
}
int MetaObject::getSignalsNumber () const {
// TODO
return 0;
}
int MetaObject::getSignalIndex (void **signal) const {
// TODO
return -1;
}
// =============================================================================
L_OBJECT_IMPL(Object);
// -----------------------------------------------------------------------------
Object::Object (ObjectPrivate &p) : BaseObject(p) {}
// -----------------------------------------------------------------------------
shared_ptr<Object> Object::getSharedFromThis () {
return const_pointer_cast<Object>(static_cast<const Object *>(this)->getSharedFromThis());
}
......@@ -46,9 +78,55 @@ shared_ptr<const Object> Object::getSharedFromThis () const {
return nullptr;
}
inline const Object::Lock &Object::getLock () const {
const Object::Lock &Object::getLock () const {
L_D();
return d->getLock();
}
// -----------------------------------------------------------------------------
#define CHECK_CONNECT_PARAM(PARAM) \
do { \
if (!PARAM) { \
lError() << "No " #PARAM " given!"; \
slotObject->call(Private::SlotObject::Delete, nullptr, nullptr); \
return Connection(); \
} \
} while (false)
Connection Object::connectInternal (
const Object *sender,
void **signal,
const Object *receiver,
void **slot,
Private::SlotObject *slotObject,
const MetaObject *metaObject
) {
// Note: `receiver` can be null with non-member function slot.
CHECK_CONNECT_PARAM(sender);
CHECK_CONNECT_PARAM(signal);
CHECK_CONNECT_PARAM(slot);
CHECK_CONNECT_PARAM(slotObject);
// 1. Try to find signal index and signal's meta object.
int signalIndex = -1;
for (; metaObject && signalIndex < 0; metaObject = metaObject->getParent()) {
signalIndex = metaObject->getSignalIndex(signal);
if (signalIndex >= 0)
break;
}
if (!metaObject) {
lError() << "Unable to find signal in: `" << sender->getMetaObject()->getClassName() << "`";
slotObject->call(Private::SlotObject::Delete, nullptr, nullptr);
return Connection();
}
// TODO: 2. Add connection in list.
return Connection();
}
#undef CHECK_CONNECT_PARAM
LINPHONE_END_NAMESPACE
......@@ -24,10 +24,38 @@
#include <mutex>
#include "base-object.h"
#include "connection.h"
#include "internal/slot-object.h"
#include "property-container.h"
// =============================================================================
// -----------------------------------------------------------------------------
// Internal macros, do not use directly.
// -----------------------------------------------------------------------------
#define L_INTERNAL_SIGNAL_CONCAT_TYPE_ARG(TYPE, PARAM) TYPE PARAM
#define L_INTERNAL_CHECK_CONNECT_TYPES(SIGNAL_TYPE, SLOT_TYPE) \
static_assert( \
static_cast<int>(SIGNAL_TYPE::ArgumentsNumber) >= static_cast<int>(SLOT_TYPE::ArgumentsNumber), \
"Slot requires less arguments." \
); \
static_assert( \
(Private::ArgsListConsistent<typename SIGNAL_TYPE::Arguments, typename SLOT_TYPE::Arguments>::Value), \
"Signal and slot args are not consistent." \
); \
static_assert( \
(Private::ArgsConsistent<typename SLOT_TYPE::ReturnType, typename SIGNAL_TYPE::ReturnType>::Value), \
"Return type of signal and slot are not consistent." \
);
#define L_INTERNAL_SIGNAL_INDEX(NAME, LINE) L_CONCAT(lSignalIndexOf ## _, L_CONCAT(NAME ## _, LINE))
// -----------------------------------------------------------------------------
// Public macros API.
// -----------------------------------------------------------------------------
// Must be used in Object or ObjectPrivate.
#define L_SYNC() \
static_assert( \
......@@ -36,8 +64,88 @@
); \
const std::lock_guard<Object::Lock> synchronized(const_cast<Object::Lock &>(getLock()));
// Declare one Smart Object with Signals.
#define L_OBJECT(CLASS) \
public: \
typedef CLASS lType; \
using lParentType = std::remove_reference< \
decltype(LinphonePrivate::Private::getParentObject(&lType::getMetaObject)) \
>::type; \
private: \
friend constexpr std::tuple<> lMetaSignals (LinphonePrivate::Private::MetaObjectCounter<0>, lType **) { return {}; } \
public: \
struct MetaObjectBuilder; \
static const LinphonePrivate::MetaObject metaObject; \
const MetaObject *getMetaObject () const override;
// Declare one signal method.
#define L_SIGNAL(NAME, TYPES, ...) \
void NAME (L_APPLY_LIST(L_INTERNAL_SIGNAL_CONCAT_TYPE_ARG, TYPES, __VA_ARGS__)) { \
typedef decltype(L_CALL(L_RESOLVE_OVERLOAD, TYPES)(&lType::NAME)) SignalType; \
LinphonePrivate::Private::SignalEmitter<SignalType, L_INTERNAL_SIGNAL_INDEX(NAME, __LINE__)>{this}(__VA_ARGS__); \
} \
static constexpr int L_INTERNAL_SIGNAL_INDEX(NAME, __LINE__) = \
std::tuple_size< \
decltype(lMetaSignals(LinphonePrivate::Private::MetaObjectCounter<>(), static_cast<lType **>(nullptr))) \
>::value; \
friend constexpr auto lMetaSignals ( \
LinphonePrivate::Private::MetaObjectCounter<L_INTERNAL_SIGNAL_INDEX(NAME, __LINE__) + 1> counter, \
lType **context \
) L_AUTO_CONSTEXPR_RETURN( \
std::tuple_cat( \
lMetaSignals(counter.prev(), context), \
std::make_tuple(LinphonePrivate::Private::makeFunctionInfo( \
L_CALL(L_RESOLVE_OVERLOAD, TYPES)(&lType::NAME), \
#NAME \
)) \
) \
)
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class LINPHONE_PUBLIC MetaObject {
public:
const char *getClassName () const;
const MetaObject *getParent () const;
int getSignalsNumber () const;
int getSignalIndex (void **signal) const;
static void activateSignal (Object *sender, const MetaObject *metaObject, int signalIndex, void **args);
};
namespace Private {
// Compilation counter.
template<int N = 255>
struct MetaObjectCounter : MetaObjectCounter<N - 1> {
static constexpr int value = N;
static constexpr MetaObjectCounter<N - 1> prev () {
return {};
}
};
template<>
struct MetaObjectCounter<0> {
static constexpr int value = 0;
};
template<typename Func, int Index>
struct SignalEmitter {};
template<typename Obj, typename... Args, int Index>
struct SignalEmitter<void (Obj::*)(Args...), Index> {
Obj *self;
inline void operator () (Args... args) {
void *argsPack[] = { (&args)... };
MetaObject::activateSignal(self, &Obj::metaObject, Index, argsPack);
}
};
template<typename T>
T &getParentObject (const MetaObject *(T::*)() const);
};
/*
* Main Object of Linphone. Can be shared but is not Clonable.
* Supports properties and shared from this.
......@@ -47,22 +155,80 @@ class LINPHONE_PUBLIC Object :
public std::enable_shared_from_this<Object>,
public BaseObject,
public PropertyContainer {
L_OBJECT(Object);
public:
typedef std::recursive_mutex Lock;
std::shared_ptr<Object> getSharedFromThis ();
std::shared_ptr<const Object> getSharedFromThis () const;
template<typename Func1, typename Func2>
static typename std::enable_if<Private::FunctionPointer<Func2>::ArgumentsNumber >= 0, Connection>::type connect (
const typename Private::FunctionPointer<Func1>::Object *sender,
Func1 signal,
Func2 slot
) {
typedef Private::FunctionPointer<Func1> SignalType;
typedef Private::FunctionPointer<Func2> SlotType;
L_INTERNAL_CHECK_CONNECT_TYPES(SignalType, SlotType)
return connectInternal(
sender, reinterpret_cast<void **>(&signal), sender, nullptr,
new Private::SlotObjectFunction<
Func2,
typename Private::ListBuilder<typename SignalType::Arguments, SlotType::ArgumentsNumber>::Value
>(slot),
&SignalType::Object::metaObject
);
}
template<typename Func1, typename Func2>
static Connection connect (
const typename Private::FunctionPointer<Func1>::Object *sender,
Func1 signal,
const typename Private::FunctionPointer<Func2>::Object *receiver,
Func2 slot
) {
typedef Private::FunctionPointer<Func1> SignalType;
typedef Private::FunctionPointer<Func2> SlotType;
L_INTERNAL_CHECK_CONNECT_TYPES(SignalType, SlotType)
return connectInternal(
sender, reinterpret_cast<void **>(&signal), receiver, reinterpret_cast<void **>(&slot),
new Private::SlotObjectMemberFunction<
Func2,
typename Private::ListBuilder<typename SignalType::Arguments, SlotType::ArgumentsNumber>::Value
>(slot),
&SignalType::Object::metaObject
);
}
bool disconnect (const Connection &connection);
protected:
explicit Object (ObjectPrivate &p);
const Lock &getLock () const;
private:
static Connection connectInternal (
const Object *sender,
void **signal,
const Object *receiver,
void **slot,
Private::SlotObject *slotObject,
const MetaObject *metaObject
);
L_DECLARE_PRIVATE(Object);
L_DISABLE_COPY(Object);
};
LINPHONE_END_NAMESPACE
#undef L_INTERNAL_CHECK_CONNECT_TYPES
#endif // ifndef _L_OBJECT_H_
......@@ -203,6 +203,7 @@ set(SOURCE_FILES_CXX
cpim-tester.cpp
main-db-tester.cpp
multipart-tester.cpp
object-tester.cpp
property-container-tester.cpp
)
......
......@@ -49,14 +49,15 @@ extern test_suite_t content_manager_test_suite;
extern test_suite_t cpim_test_suite;
extern test_suite_t dtmf_test_suite;
extern test_suite_t event_test_suite;
extern test_suite_t main_db_test_suite;
extern test_suite_t flexisip_test_suite;
extern test_suite_t group_chat_test_suite;
extern test_suite_t log_collection_test_suite;
extern test_suite_t main_db_test_suite;
extern test_suite_t message_test_suite;
extern test_suite_t multi_call_test_suite;
extern test_suite_t multicast_call_test_suite;
extern test_suite_t multipart_test_suite;
extern test_suite_t object_test_suite;
extern test_suite_t offeranswer_test_suite;
extern test_suite_t player_test_suite;
extern test_suite_t presence_server_test_suite;
......
/*
* object-tester.cpp
* Copyright (C) 2017 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 3 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/>.
*/
#include "object/object-p.h"
#include "liblinphone_tester.h"
#include "tester_utils.h"
// =============================================================================
using namespace std;
using namespace LinphonePrivate;
// -----------------------------------------------------------------------------
#define GET_SIGNAL_INFO(INDEX) \
get<INDEX>(lMetaSignals( \
Private::MetaObjectCounter<INDEX + 1>(), \
static_cast<lType **>(nullptr) \
))
#define CHECK_SIGNAL_INDEX(INDEX, NAME) \
static_assert(L_INTERNAL_SIGNAL_INDEX(NAME, __LINE__) == INDEX, "Bad signal index.");
#define CHECK_SIGNAL_META_INTO(INDEX, NAME, ARGS_NUMBER) \
static_assert(GET_SIGNAL_INFO(INDEX).argumentsNumber == ARGS_NUMBER, "Unexpected arguments number in `" NAME "`."); \
static_assert(GET_SIGNAL_INFO(INDEX).name == makeStringLiteral(NAME), "Unexpected signal name for `" NAME "`.");
class TestObjectPrivate : public ObjectPrivate {
public:
};
// 1. First step: It's necessary to inherit from `Object` to create a smart object.
class TestObject : public Object {
// 2. `L_OBJECT` => Declare TestObject as a smart object.
L_OBJECT(TestObject);
public:
TestObject () : Object(*new TestObjectPrivate) {}
// 3. `L_SIGNAL` => Declare a signal with `signal1` name and two parameters: `int toto` and `float tata`.
L_SIGNAL(signal1, (int, float), toto, tata); CHECK_SIGNAL_INDEX(0, signal1);
L_SIGNAL(signal2, (bool, float, int), a, b, c); CHECK_SIGNAL_INDEX(1, signal2);
static void checkMetaInfoAtCompileTime () {
CHECK_SIGNAL_META_INTO(0, "signal1", 2);
CHECK_SIGNAL_META_INTO(1, "signal2", 3);
}
private:
L_DECLARE_PRIVATE(TestObject);
};
class TestObject2 : public TestObject {
public:
void slot1 (bool, float, int) {}
};
#undef GET_SIGNAL_INFO
#undef CHECK_SIGNAL_INDEX
#undef CHECK_SIGNAL_META_INFO
// 4. `L_OBJECT_IMPL` => Declare smart object implementation. MUST BE USED IN A CPP FILE!!!
L_OBJECT_IMPL(TestObject);
// -----------------------------------------------------------------------------
static void check_object_creation () {
TestObject *object = new TestObject();
delete object;
}
static void simple_slot () {
}
static void check_object_connection_to_function () {
TestObject object;
Connection connection = Object::connect(&object, &TestObject::signal1, simple_slot);
}
static void check_object_connection_to_method () {
TestObject objectA;
TestObject2 objectB;
Connection connection = Object::connect(&objectA, &TestObject::signal2, &objectB, &TestObject2::slot1);
}
test_t object_tests[] = {
TEST_NO_TAG("Check object creation", check_object_creation),
TEST_NO_TAG("Check object connection to function", check_object_connection_to_function),
TEST_NO_TAG("Check object connection to method", check_object_connection_to_method)
};
test_suite_t object_test_suite = {
"Object", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,
sizeof(object_tests) / sizeof(object_tests[0]), object_tests
};
......@@ -615,6 +615,7 @@ void liblinphone_tester_add_suites() {
bc_tester_add_suite(&cpim_test_suite);
bc_tester_add_suite(&multipart_test_suite);
bc_tester_add_suite(&clonable_object_test_suite);
bc_tester_add_suite(&object_test_suite);
bc_tester_add_suite(&main_db_test_suite);
bc_tester_add_suite(&property_container_test_suite);
#if defined(VIDEO_ENABLED) && defined(HAVE_GTK)
......