it is used to control the inline semantics. By combining it with optimize option "-fno-inline" for the internal M*LIB function (using _Pragma optimize) we can control easily if we want to use an inline version or call of an external function. Define new user API: * M_USE_EXTERN_DECL : define it before including any MLIB header to requests to call the M*LIB functions and don't inline then. * M_USE_EXTERN_DEF : define it once in a translation unit to define the M*LIB functions. This translation unit shall contain all templated macro too. If you use one option, you need to use the other one too for another translation unit.
520 lines
36 KiB
C
520 lines
36 KiB
C
/*
|
|
* M*LIB - dynamic priority queue module
|
|
*
|
|
* Copyright (c) 2017-2023, Patrick Pelissier
|
|
* All rights reserved.
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* + Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* + Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
#ifndef MSTARLIB_PRIOQUEUE_H
|
|
#define MSTARLIB_PRIOQUEUE_H
|
|
|
|
#include "m-core.h"
|
|
#include "m-array.h" /* Priority queue are built upon array */
|
|
|
|
/* Priority queue based on binary heap implementation */
|
|
|
|
/* Define a prioqueue of a given type and its associated functions.
|
|
USAGE: PRIOQUEUE_DEF(name, type [, oplist_of_the_type]) */
|
|
#define M_PRIOQUEUE_DEF(name, ...) \
|
|
M_PRIOQUEUE_DEF_AS(name, M_F(name,_t), M_F(name,_it_t), __VA_ARGS__)
|
|
|
|
|
|
/* Define a prioqueue of a given type and its associated functions.
|
|
as the name name_t with an iterator named it_t
|
|
USAGE: PRIOQUEUE_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
|
#define M_PRIOQUEUE_DEF_AS(name, name_t, it_t, ...) \
|
|
M_BEGIN_PROTECTED_CODE \
|
|
M_PR1OQUEUE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
|
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
|
(name, __VA_ARGS__, name_t, it_t ))) \
|
|
M_END_PROTECTED_CODE
|
|
|
|
|
|
/* Define the oplist of a prioqueue of type.
|
|
USAGE: PRIOQUEUE_OPLIST(name[, oplist of the type]) */
|
|
#define M_PRIOQUEUE_OPLIST(...) \
|
|
M_PR1OQUEUE_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
|
((__VA_ARGS__, M_BASIC_OPLIST), \
|
|
(__VA_ARGS__ )))
|
|
|
|
|
|
/*****************************************************************************/
|
|
/********************************** INTERNAL *********************************/
|
|
/*****************************************************************************/
|
|
|
|
/* Deferred evaluation for the definition,
|
|
so that all arguments are evaluated before further expansion */
|
|
#define M_PR1OQUEUE_OPLIST_P1(arg) M_PR1OQUEUE_OPLIST_P2 arg
|
|
|
|
/* Validation of the given oplist */
|
|
#define M_PR1OQUEUE_OPLIST_P2(name, oplist) \
|
|
M_IF_OPLIST(oplist)(M_PR1OQUEUE_OPLIST_P3, M_PR1OQUEUE_OPLIST_FAILURE)(name, oplist)
|
|
|
|
/* Prepare a clean compilation failure */
|
|
#define M_PR1OQUEUE_OPLIST_FAILURE(name, oplist) \
|
|
((M_LIB_ERROR(ARGUMENT_OF_PRIOQUEUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
|
|
|
/* Define oplist of a priority queue */
|
|
#define M_PR1OQUEUE_OPLIST_P3(name, oplist) \
|
|
(INIT(M_F(name, _init)) \
|
|
,INIT_SET(M_F(name, _init_set)) \
|
|
,INIT_WITH(API_1(M_INIT_VAI)) \
|
|
,SET(M_F(name, _set)) \
|
|
,CLEAR(M_F(name, _clear)) \
|
|
,INIT_MOVE(M_F(name, _init_move)) \
|
|
,MOVE(M_F(name, _move)) \
|
|
,SWAP(M_F(name, _swap)) \
|
|
,NAME(name) \
|
|
,TYPE(M_F(name,_ct)) \
|
|
,SUBTYPE(M_F(name, _subtype_ct)) \
|
|
,RESET(M_F(name,_reset)) \
|
|
,PUSH(M_F(name,_push)) \
|
|
,POP(M_F(name,_pop)) \
|
|
,OPLIST(oplist) \
|
|
,EMPTY_P(M_F(name, _empty_p)) \
|
|
,GET_SIZE(M_F(name, _size)) \
|
|
,IT_TYPE(M_F(name, _it_ct)) \
|
|
,IT_FIRST(M_F(name,_it)) \
|
|
,IT_END(M_F(name,_it_end)) \
|
|
,IT_SET(M_F(name,_it_set)) \
|
|
,IT_END_P(M_F(name,_end_p)) \
|
|
,IT_EQUAL_P(M_F(name,_it_equal_p)) \
|
|
,IT_LAST_P(M_F(name,_last_p)) \
|
|
,IT_NEXT(M_F(name,_next)) \
|
|
,IT_CREF(M_F(name,_cref)) \
|
|
,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_F(name, _get_str)),) \
|
|
,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_F(name, _parse_str)),) \
|
|
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),) \
|
|
,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_F(name, _in_str)),) \
|
|
,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_F(name, _out_serial)),) \
|
|
,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_F(name, _in_serial)),) \
|
|
)
|
|
|
|
|
|
/********************************** INTERNAL *********************************/
|
|
|
|
/* Deferred evaluation for the definition,
|
|
so that all arguments are evaluated before further expansion */
|
|
#define M_PR1OQUEUE_DEF_P1(arg) M_ID( M_PR1OQUEUE_DEF_P2 arg )
|
|
|
|
/* Validate the oplist before going further */
|
|
#define M_PR1OQUEUE_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
|
|
M_IF_OPLIST(oplist)(M_PR1OQUEUE_DEF_P3, M_PR1OQUEUE_DEF_FAILURE)(name, type, oplist, prioqueue_t, it_t)
|
|
|
|
/* Stop processing with a compilation failure */
|
|
#define M_PR1OQUEUE_DEF_FAILURE(name, type, oplist, prioqueue_t, it_t) \
|
|
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(PRIOQUEUE_DEF): the given argument is not a valid oplist: " #oplist)
|
|
|
|
/* Define the priority queue:
|
|
- name: prefix to use,
|
|
- type: type of the contained objects,
|
|
- oplist: oplist of the contained objects,
|
|
- prioqueue_t: type of the container,
|
|
- it_t: iterator of the container
|
|
*/
|
|
#define M_PR1OQUEUE_DEF_P3(name, type, oplist, prioqueue_t, it_t) \
|
|
/* Definition of the internal array used to construct the priority queue */ \
|
|
ARRAY_DEF(M_F(name, _array), type, oplist) \
|
|
M_PR1OQUEUE_DEF_TYPE(name, type, oplist, prioqueue_t, it_t) \
|
|
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
|
M_PR1OQUEUE_DEF_CORE(name, type, oplist, prioqueue_t, it_t) \
|
|
M_PR1OQUEUE_DEF_IT(name, type, oplist, prioqueue_t, it_t) \
|
|
M_PR1OQUEUE_DEF_IO(name, type, oplist, prioqueue_t, it_t) \
|
|
M_EMPLACE_QUEUE_DEF(name, prioqueue_t, M_F(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
|
|
|
|
/* Define the types */
|
|
#define M_PR1OQUEUE_DEF_TYPE(name, type, oplist, prioqueue_t, it_t) \
|
|
\
|
|
/* Define the priority queue over the defined array */ \
|
|
typedef struct M_F(name, _s) { \
|
|
M_F(name, _array_t) array; \
|
|
} prioqueue_t[1]; \
|
|
/* Define the pointer references to the priority queue */ \
|
|
typedef struct M_F(name, _s) *M_F(name, _ptr); \
|
|
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
|
|
\
|
|
/* The iterator is the same one as the one of the internal array */ \
|
|
typedef M_F(name, _array_it_t) it_t; \
|
|
\
|
|
/* Definition of the internal types used by the oplist */ \
|
|
typedef prioqueue_t M_F(name, _ct); \
|
|
typedef type M_F(name, _subtype_ct); \
|
|
typedef it_t M_F(name, _it_ct); \
|
|
|
|
/* Define the core functions */
|
|
#define M_PR1OQUEUE_DEF_CORE(name, type, oplist, prioqueue_t, it_t) \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _init)(prioqueue_t p) \
|
|
{ \
|
|
M_F(name, _array_init)(p->array); \
|
|
} \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _init_set)(prioqueue_t p, prioqueue_t const o) \
|
|
{ \
|
|
M_F(name, _array_init_set)(p->array, o->array); \
|
|
} \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _set)(prioqueue_t p, prioqueue_t const o) \
|
|
{ \
|
|
M_F(name, _array_set)(p->array, o->array); \
|
|
} \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _clear)(prioqueue_t p) \
|
|
{ \
|
|
M_F(name, _array_clear)(p->array); \
|
|
} \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _init_move)(prioqueue_t p, prioqueue_t o) \
|
|
{ \
|
|
M_F(name, _array_init_move)(p->array, o->array); \
|
|
} \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _move)(prioqueue_t p, prioqueue_t o) \
|
|
{ \
|
|
M_F(name, _array_move)(p->array, o->array); \
|
|
} \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _swap)(prioqueue_t p, prioqueue_t o) \
|
|
{ \
|
|
M_F(name, _array_swap)(p->array, o->array); \
|
|
} \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _reset)(prioqueue_t p) \
|
|
{ \
|
|
M_F(name, _array_reset)(p->array); \
|
|
} \
|
|
\
|
|
M_INLINE size_t \
|
|
M_F(name, _i_parent)(size_t i) \
|
|
{ \
|
|
M_ASSERT (i > 0); \
|
|
return (i - 1) / 2; \
|
|
} \
|
|
\
|
|
M_INLINE size_t \
|
|
M_F(name, _i_lchild)(size_t i) \
|
|
{ \
|
|
M_ASSERT(i <= ((SIZE_MAX)-2)/2); \
|
|
return 2*i + 1; \
|
|
} \
|
|
\
|
|
M_INLINE size_t \
|
|
M_F(name, _i_rchild)(size_t i) \
|
|
{ \
|
|
M_ASSERT(i <= ((SIZE_MAX)-2)/2); \
|
|
return 2*i + 2; \
|
|
} \
|
|
\
|
|
M_INLINE int \
|
|
M_F(name, _i_cmp)(const prioqueue_t p, size_t i, size_t j) \
|
|
{ \
|
|
return M_CALL_CMP(oplist, *M_F(name, _array_cget)(p->array, i), \
|
|
*M_F(name, _array_cget)(p->array, j)); \
|
|
} \
|
|
\
|
|
M_INLINE bool \
|
|
M_F(name, _empty_p)(prioqueue_t const p) \
|
|
{ \
|
|
return M_F(name, _array_empty_p)(p->array); \
|
|
} \
|
|
\
|
|
M_INLINE size_t \
|
|
M_F(name, _size)(prioqueue_t const p) \
|
|
{ \
|
|
return M_F(name, _array_size)(p->array); \
|
|
} \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _push)(prioqueue_t p, type const x) \
|
|
{ \
|
|
/* Push back the new element at the end of the array */ \
|
|
M_F(name, _array_push_back)(p->array, x); \
|
|
\
|
|
/* Reorder the array by swapping with its parent \
|
|
* until it reaches the right position */ \
|
|
size_t i = M_F(name, _array_size)(p->array)-1; \
|
|
while (i > 0) { \
|
|
size_t j = M_F(name, _i_parent)(i); \
|
|
if (M_F(name, _i_cmp)(p, j, i) <= 0) \
|
|
break; \
|
|
M_F(name, _array_swap_at) (p->array, i, j); \
|
|
i = j; \
|
|
} \
|
|
} \
|
|
\
|
|
M_INLINE type const * \
|
|
M_F(name, _front)(prioqueue_t const p) \
|
|
{ \
|
|
return M_F(name, _array_cget)(p->array, 0); \
|
|
} \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _pop)(type *x, prioqueue_t p) \
|
|
{ \
|
|
/* Swap the front element with the last element */ \
|
|
size_t size = M_F(name, _array_size)(p->array)-1; \
|
|
M_F(name, _array_swap_at) (p->array, 0, size); \
|
|
/* Swap the new last element */ \
|
|
M_F(name, _array_pop_back)(x, p->array); \
|
|
\
|
|
/* Reorder the heap */ \
|
|
size_t i = 0; \
|
|
while (true) { \
|
|
size_t child = M_F(name, _i_lchild)(i); \
|
|
if (child >= size) \
|
|
break; \
|
|
size_t otherChild = M_F(name, _i_rchild)(i); \
|
|
if (otherChild < size \
|
|
&& M_F(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
|
child = otherChild; \
|
|
} \
|
|
if (M_F(name, _i_cmp)(p, i, child) <= 0) \
|
|
break; \
|
|
M_F(name, _array_swap_at) (p->array, i, child); \
|
|
i = child; \
|
|
} \
|
|
} \
|
|
\
|
|
M_IF_METHOD(EQUAL, oplist) \
|
|
( \
|
|
/* EQUAL & CMP may be uncorrelated */ \
|
|
M_INLINE bool \
|
|
M_F(name, _equal_p)(prioqueue_t const p, prioqueue_t const q) \
|
|
{ \
|
|
return M_F(name, _array_equal_p)(p->array, q->array); \
|
|
} \
|
|
\
|
|
M_INLINE size_t \
|
|
M_F(name, _i_find)(prioqueue_t p, type const x) \
|
|
{ \
|
|
size_t size = M_F(name, _array_size)(p->array); \
|
|
size_t i = 0; \
|
|
for(i = 0; i < size; i++) { \
|
|
/* FIXME: Can we use CMP and the partial order to go faster? */ \
|
|
if (M_CALL_EQUAL(oplist, *M_F(name, _array_cget)(p->array, i), x)) \
|
|
break; \
|
|
} \
|
|
return i; \
|
|
} \
|
|
\
|
|
M_INLINE bool \
|
|
M_F(name, _erase)(prioqueue_t p, type const x) \
|
|
{ \
|
|
/* First pass: search for an item EQUAL to x */ \
|
|
size_t size = M_F(name, _array_size)(p->array); \
|
|
size_t i = M_F(name, _i_find)(p, x); \
|
|
/* If x is not found, then stop */ \
|
|
if (i >= size) \
|
|
return false; \
|
|
/* Swap the found item and the last element */ \
|
|
size--; \
|
|
M_F(name, _array_swap_at) (p->array, i, size); \
|
|
M_F(name, _array_pop_back)(NULL, p->array); \
|
|
/* Move back the last swapped element to its right position in the heap */ \
|
|
while (true) { \
|
|
size_t child = M_F(name, _i_lchild)(i); \
|
|
if (child >= size) break; \
|
|
size_t otherChild = M_F(name, _i_rchild)(i); \
|
|
if (otherChild < size \
|
|
&& M_F(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
|
child = otherChild; \
|
|
} \
|
|
if (M_F(name, _i_cmp)(p, i, child) <= 0) break; \
|
|
M_F(name, _array_swap_at) (p->array, i, child); \
|
|
i = child; \
|
|
} \
|
|
return true; \
|
|
} \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _update)(prioqueue_t p, type const xold, type const xnew) \
|
|
{ \
|
|
/* NOTE: xold can be the same pointer than xnew */ \
|
|
/* First pass: search for an item EQUAL to x */ \
|
|
size_t size = M_F(name, _array_size)(p->array); \
|
|
size_t i = M_F(name, _i_find)(p, xold); \
|
|
/* We shall have found the item */ \
|
|
M_ASSERT (i < size); \
|
|
/* Test if the position of the old data is further or nearer than the new */ \
|
|
int cmp = M_CALL_CMP(oplist, *M_F(name, _array_cget)(p->array, i), xnew); \
|
|
/* Set the found item to the new element */ \
|
|
M_F(name, _array_set_at) (p->array, i, xnew); \
|
|
if (cmp < 0) { \
|
|
/* Move back the updated element to its new position, further in the heap */ \
|
|
while (true) { \
|
|
size_t child = M_F(name, _i_lchild)(i); \
|
|
if (child >= size) break; \
|
|
size_t otherChild = M_F(name, _i_rchild)(i); \
|
|
if (otherChild < size \
|
|
&& M_F(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
|
child = otherChild; \
|
|
} \
|
|
if (M_F(name, _i_cmp)(p, i, child) <= 0) break; \
|
|
M_F(name, _array_swap_at) (p->array, i, child); \
|
|
i = child; \
|
|
} \
|
|
} else { \
|
|
/* Move back the updated element to its new position, nearest in the heap */ \
|
|
while (i > 0) { \
|
|
size_t parent = M_F(name, _i_parent)(i); \
|
|
if (M_F(name, _i_cmp)(p, parent, i) <= 0) break; \
|
|
M_F(name, _array_swap_at) (p->array, i, parent); \
|
|
i = parent; \
|
|
} \
|
|
} \
|
|
} \
|
|
, /* No EQUAL */ ) \
|
|
|
|
/* Define the IT based functions */
|
|
#define M_PR1OQUEUE_DEF_IT(name, type, oplist, prioqueue_t, it_t) \
|
|
\
|
|
/* Define iterators over the array iterator */ \
|
|
M_INLINE void \
|
|
M_F(name, _it)(it_t it, prioqueue_t const v) \
|
|
{ \
|
|
M_F(name, _array_it)(it, v->array); \
|
|
} \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _it_last)(it_t it, prioqueue_t const v) \
|
|
{ \
|
|
M_F(name, _array_it_last)(it, v->array); \
|
|
} \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _it_end)(it_t it, prioqueue_t const v) \
|
|
{ \
|
|
M_F(name, _array_it_end)(it, v->array); \
|
|
} \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _it_set)(it_t it, const it_t org) \
|
|
{ \
|
|
M_F(name, _array_it_set)(it, org); \
|
|
} \
|
|
\
|
|
M_INLINE bool \
|
|
M_F(name, _end_p)(const it_t it) \
|
|
{ \
|
|
return M_F(name, _array_end_p)(it); \
|
|
} \
|
|
\
|
|
M_INLINE bool \
|
|
M_F(name, _last_p)(const it_t it) \
|
|
{ \
|
|
return M_F(name, _array_last_p)(it); \
|
|
} \
|
|
\
|
|
M_INLINE bool \
|
|
M_F(name, _it_equal_p)(const it_t it1, \
|
|
const it_t it2) \
|
|
{ \
|
|
return M_F(name, _array_it_equal_p)(it1, it2); \
|
|
} \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _next)(it_t it) \
|
|
{ \
|
|
M_F(name, _array_next)(it); \
|
|
} \
|
|
\
|
|
M_INLINE void \
|
|
M_F(name, _previous)(it_t it) \
|
|
{ \
|
|
M_F(name, _array_previous)(it); \
|
|
} \
|
|
\
|
|
M_INLINE type const * \
|
|
M_F(name, _cref)(const it_t it) \
|
|
{ \
|
|
return M_F(name, _array_cref)(it); \
|
|
} \
|
|
|
|
/* Define the IO functions */
|
|
#define M_PR1OQUEUE_DEF_IO(name, type, oplist, prioqueue_t, it_t) \
|
|
M_IF_METHOD(OUT_STR, oplist)( \
|
|
M_INLINE void \
|
|
M_F(name, _out_str)(FILE *file, const prioqueue_t p) \
|
|
{ \
|
|
M_F(name, _array_out_str)(file, p->array); \
|
|
} \
|
|
,/* No OUT_STR */) \
|
|
\
|
|
M_IF_METHOD(IN_STR, oplist)( \
|
|
M_INLINE bool \
|
|
M_F(name, _in_str)(prioqueue_t p, FILE *file) \
|
|
{ \
|
|
return M_F(name, _array_in_str)(p->array, file); \
|
|
} \
|
|
,/* No IN_STR */) \
|
|
\
|
|
M_IF_METHOD(GET_STR, oplist)( \
|
|
M_INLINE void \
|
|
M_F(name, _get_str)(string_t str, const prioqueue_t p, bool append) \
|
|
{ \
|
|
M_F(name, _array_get_str)(str, p->array, append); \
|
|
} \
|
|
,/* No GET_STR */) \
|
|
\
|
|
M_IF_METHOD(PARSE_STR, oplist)( \
|
|
M_INLINE bool \
|
|
M_F(name, _parse_str)(prioqueue_t p, const char str[], const char **endp) \
|
|
{ \
|
|
return M_F(name, _array_parse_str)(p->array, str, endp); \
|
|
} \
|
|
,/* No PARSE_STR */) \
|
|
\
|
|
M_IF_METHOD(OUT_SERIAL, oplist)( \
|
|
M_INLINE m_serial_return_code_t \
|
|
M_F(name, _out_serial)(m_serial_write_t f, const prioqueue_t p) \
|
|
{ \
|
|
return M_F(name, _array_out_serial)(f, p->array); \
|
|
} \
|
|
,/* No OUT_SERIAL */) \
|
|
\
|
|
M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \
|
|
M_INLINE m_serial_return_code_t \
|
|
M_F(name, _in_serial)(prioqueue_t p, m_serial_read_t f) \
|
|
{ \
|
|
return M_F(name, _array_in_serial)(p->array, f); \
|
|
} \
|
|
,/* No in_SERIAL */) \
|
|
|
|
|
|
// TODO: set all & remove all function
|
|
|
|
/********************************** INTERNAL *********************************/
|
|
|
|
#if M_USE_SMALL_NAME
|
|
#define PRIOQUEUE_DEF M_PRIOQUEUE_DEF
|
|
#define PRIOQUEUE_DEF_AS M_PRIOQUEUE_DEF_AS
|
|
#define PRIOQUEUE_OPLIST M_PRIOQUEUE_OPLIST
|
|
#endif
|
|
|
|
#endif
|