c732d49e |
/* Copyright (C) 2010-2013 Mamadou Diop.
* Copyright (C) 2013 Doubango Telecom <http://doubango.org>
* This file is part of Open Source Doubango Framework.
*
* DOUBANGO 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.
*
* DOUBANGO 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 DOUBANGO.
*
*/
/**@file tsk_object.h
* @brief Base object implementation.
*/
#ifndef TSK_OBJECT_H
#define TSK_OBJECT_H
#include "tinysak_config.h"
#include <stdarg.h>
#include <stdio.h>
TSK_BEGIN_DECLS
#define TSK_OBJECT(self) ((tsk_object_t*)(self))
/**@ingroup tsk_object_group
* Plain object.
*/
typedef void tsk_object_t;
/**@ingroup tsk_object_group
* @def TSK_OBJECT_SAFE_FREE
* Safely free any well-defined object. If the reference count of the object was equal to 1 then this
* object will be freed otherwise the refrence counter will be decremented.
* In all case this operation will set the pointer (the object itself) to NULL.<br>
* <b>Very Important</b>: Mutexes, Semaphores and CondVars are not well-defined objects. You should never use this macro to destroy them.
* @param self The object to free or unref.
**/
#define TSK_OBJECT_SAFE_FREE(self) if((self)) tsk_object_unref((self)), (self) = tsk_null
#define TSK_OBJECT_SAFE_FREE_ARRAY(self, count) { \
int __i; \
for(__i = 0; __i < (count); ++__i) \
TSK_OBJECT_SAFE_FREE((self)[__i]); \
}
#define TSK_OBJECT_SAFE_FREE_TABLE(self) TSK_OBJECT_SAFE_FREE_ARRAY((self), (sizeof((self))/sizeof((self)[0])))
/**@ingroup tsk_object_group
* tag a structure as an object. If this macro is used then you MUST
* provide a constructor and a destructor functions into an object definition (or meta-data).
* @ref tsk_object_new or @ref tsk_object_new_2 are used to create the object and @ref tsk_object_unref or @ref tsk_object_delete to destroy it.
* @code
* typedef struct person_s{
* TSK_DECLARE_OBJECT;
* int id;
* char* firstName;
* char* lastName;
* } person_t;
* @endcode
* To create the object:
* @code
* // person_def_t: See bellow to understand how to create an object definition.
* person_t* person = tsk_object_new(person_def_t, "My First Name", "My last Name");
* @endcode
* To safely free the object:
* @code
* TSK_OBJECT_SAFE_FREE(person);
* @endcode
*/
#define TSK_DECLARE_OBJECT \
const void* __def__; /**< Opaque data holding a pointer to the actual meta-data(size, constructor, destructor and comparator) */ \
volatile long refCount /**< Reference counter. */
/**@ingroup tsk_object_group
* Internal macro to get the definition of the object.
*/
#define TSK_OBJECT_DEF(self) ((const tsk_object_def_t*)self)
/** Object meta-data (definition) */
typedef struct tsk_object_header_s{
TSK_DECLARE_OBJECT;
}
tsk_object_header_t;
#define TSK_OBJECT_HEADER(object) ((tsk_object_header_t*)object)
/**@ingroup tsk_object_group
* Meta-data used of define an object.
* You MUST provide at least a constructor and a destructor. The comparator should
* be provided if you would like to compare opaque object or sort linked lists.
* @code
*
* // constructor
* static void* person_create(tsk_object_t * self, va_list * app)
* {
* static int unique_id = 0;
* person_t *person = self;
* if(person){
* person->id = ++unique_id;
* person->firstName = tsk_strdup(va_arg(*app, const char *));
* person->lastName = tsk_strdup(va_arg(*app, const char *));
* }
* return self;
* }
*
* // destructor
* static void* person_destroy(tsk_object_t * self)
* {
* person_t *person = self;
* if(person){
* TSK_FREE(person->firstName);
* TSK_FREE(person->lastName);
* }
* return self;
* }
*
* // comparator
* static int person_cmp(const tsk_object_t *object1, const tsk_object_t *object1)
* {
* const person_t *person1 = object1;
* const person_t *person2 = object2;
*
* return (person1 && person2) ? (person1->id - person2->id) : -1;
* }
*
* // Meta-data (Object defnition)
* static const tsk_object_def_t person_def_s =
* {
* sizeof(person_t),
* person_create,
* person_destroy,
* person_cmp,
* }person_def_t;
*
* @endcode
* Now, to create your object:
* @code
* person_t* person = tsk_object_new(person_def_t, "My First Name", "My last Name"); // Will call "person_create" function.
* @endcode
* Or
* @code
* #define PERSON_CREATE(firstName, lastName) tsk_object_new(person_def_t, firstName, lastName)
* person_t* person = PERSON_CREATE("My First Name", "My last Name") // For clarity, this form will be used in all projects declared using @ref TSK_DECLARE_OBJECT.
* @endcode
* To safely free your object:
* @code
* TSK_OBJECT_SAFE_FREE(person); // Will call "person_destroy" function.
* @endcode
*/
typedef struct tsk_object_def_s
{
//! The size of the object.
tsk_size_t size;
//! Pointer to the constructor.
tsk_object_t* (* constructor) (tsk_object_t *, va_list *);
//! Pointer to the destructor.
tsk_object_t* (* destructor) (tsk_object_t *);
//! Pointer to the comparator.
int (* comparator) (const tsk_object_t *, const tsk_object_t *);
}
tsk_object_def_t;
TINYSAK_API tsk_object_t* tsk_object_new(const tsk_object_def_t *objdef, ...);
TINYSAK_API tsk_object_t* tsk_object_new_2(const tsk_object_def_t *objdef, va_list* ap);
TINYSAK_API tsk_size_t tsk_object_sizeof(const tsk_object_t *);
TINYSAK_API int tsk_object_cmp(const void *self, const tsk_object_t *object);
TINYSAK_API tsk_object_t* tsk_object_ref(tsk_object_t *self);
TINYSAK_API tsk_object_t* tsk_object_unref(tsk_object_t *self);
TINYSAK_API tsk_size_t tsk_object_get_refcount(tsk_object_t *self);
TINYSAK_API void tsk_object_delete(tsk_object_t *self);
TSK_END_DECLS
#endif /* TSK_OBJECT_H */
|