| /*************************************************************************/ /*! |
| @File |
| @Title Linked list shared functions templates. |
| @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved |
| @Description Definition of the linked list function templates. |
| @License Dual MIT/GPLv2 |
| |
| The contents of this file are subject to the MIT license as set out below. |
| |
| Permission is hereby granted, free of charge, to any person obtaining a copy |
| of this software and associated documentation files (the "Software"), to deal |
| in the Software without restriction, including without limitation the rights |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| copies of the Software, and to permit persons to whom the Software is |
| furnished to do so, subject to the following conditions: |
| |
| The above copyright notice and this permission notice shall be included in |
| all copies or substantial portions of the Software. |
| |
| Alternatively, the contents of this file may be used under the terms of |
| the GNU General Public License Version 2 ("GPL") in which case the provisions |
| of GPL are applicable instead of those above. |
| |
| If you wish to allow use of your version of this file only under the terms of |
| GPL, and not to allow others to use your version of this file under the terms |
| of the MIT license, indicate your decision by deleting the provisions above |
| and replace them with the notice and other provisions required by GPL as set |
| out in the file called "GPL-COPYING" included in this distribution. If you do |
| not delete the provisions above, a recipient may use your version of this file |
| under the terms of either the MIT license or GPL. |
| |
| This License is also included in this distribution in the file called |
| "MIT-COPYING". |
| |
| EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS |
| PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING |
| BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
| PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR |
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ /**************************************************************************/ |
| |
| #ifndef __LISTS_UTILS__ |
| #define __LISTS_UTILS__ |
| |
| /* instruct QAC to ignore warnings about the following custom formatted macros */ |
| /* PRQA S 0881,3410 ++ */ |
| #include <stdarg.h> |
| #include "img_types.h" |
| #include "device.h" |
| #include "power.h" |
| |
| /* |
| - USAGE - |
| |
| The list functions work with any structure that provides the fields psNext and |
| ppsThis. In order to make a function available for a given type, it is required |
| to use the function template macro that creates the actual code. |
| |
| There are 5 main types of functions: |
| - INSERT : given a pointer to the head pointer of the list and a pointer |
| to the node, inserts it as the new head. |
| - INSERT TAIL : given a pointer to the head pointer of the list and a pointer |
| to the node, inserts the node at the tail of the list. |
| - REMOVE : given a pointer to a node, removes it from its list. |
| - FOR EACH : apply a function over all the elements of a list. |
| - ANY : apply a function over the elements of a list, until one of them |
| return a non null value, and then returns it. |
| |
| The two last functions can have a variable argument form, with allows to pass |
| additional parameters to the callback function. In order to do this, the |
| callback function must take two arguments, the first is the current node and |
| the second is a list of variable arguments (va_list). |
| |
| The ANY functions have also another for which specifies the return type of the |
| callback function and the default value returned by the callback function. |
| |
| */ |
| |
| /*************************************************************************/ /*! |
| @Function List_##TYPE##_ForEach |
| @Description Apply a callback function to all the elements of a list. |
| @Input psHead The head of the list to be processed. |
| @Input pfnCallBack The function to be applied to each element of the list. |
| */ /**************************************************************************/ |
| #define DECLARE_LIST_FOR_EACH(TYPE) \ |
| void List_##TYPE##_ForEach(TYPE *psHead, void(*pfnCallBack)(TYPE* psNode)) |
| |
| #define IMPLEMENT_LIST_FOR_EACH(TYPE) \ |
| void List_##TYPE##_ForEach(TYPE *psHead, void(*pfnCallBack)(TYPE* psNode))\ |
| {\ |
| while (psHead)\ |
| {\ |
| pfnCallBack(psHead);\ |
| psHead = psHead->psNext;\ |
| }\ |
| } |
| |
| /*************************************************************************/ /*! |
| @Function List_##TYPE##_ForEachSafe |
| @Description Apply a callback function to all the elements of a list. Do it |
| in a safe way that handles the fact that a node might remove |
| itself from the list during the iteration. |
| @Input psHead The head of the list to be processed. |
| @Input pfnCallBack The function to be applied to each element of the list. |
| */ /**************************************************************************/ |
| #define DECLARE_LIST_FOR_EACH_SAFE(TYPE) \ |
| void List_##TYPE##_ForEachSafe(TYPE *psHead, void(*pfnCallBack)(TYPE* psNode)) |
| |
| #define IMPLEMENT_LIST_FOR_EACH_SAFE(TYPE) \ |
| void List_##TYPE##_ForEachSafe(TYPE *psHead, void(*pfnCallBack)(TYPE* psNode))\ |
| {\ |
| TYPE *psNext;\ |
| \ |
| while (psHead)\ |
| {\ |
| psNext = psHead->psNext; \ |
| pfnCallBack(psHead);\ |
| psHead = psNext;\ |
| }\ |
| } |
| |
| |
| #define DECLARE_LIST_FOR_EACH_VA(TYPE) \ |
| void List_##TYPE##_ForEach_va(TYPE *psHead, void(*pfnCallBack)(TYPE* psNode, va_list va), ...) |
| |
| #define IMPLEMENT_LIST_FOR_EACH_VA(TYPE) \ |
| void List_##TYPE##_ForEach_va(TYPE *psHead, void(*pfnCallBack)(TYPE* psNode, va_list va), ...) \ |
| {\ |
| va_list ap;\ |
| while (psHead)\ |
| {\ |
| va_start(ap, pfnCallBack);\ |
| pfnCallBack(psHead, ap);\ |
| psHead = psHead->psNext;\ |
| va_end(ap);\ |
| }\ |
| } |
| |
| |
| /*************************************************************************/ /*! |
| @Function List_##TYPE##_Any |
| @Description Applies a callback function to the elements of a list until |
| the function returns a non null value, then returns it. |
| @Input psHead The head of the list to be processed. |
| @Input pfnCallBack The function to be applied to each element of the list. |
| @Return The first non null value returned by the callback function. |
| */ /**************************************************************************/ |
| #define DECLARE_LIST_ANY(TYPE) \ |
| void* List_##TYPE##_Any(TYPE *psHead, void* (*pfnCallBack)(TYPE* psNode)) |
| |
| #define IMPLEMENT_LIST_ANY(TYPE) \ |
| void* List_##TYPE##_Any(TYPE *psHead, void* (*pfnCallBack)(TYPE* psNode))\ |
| { \ |
| void *pResult;\ |
| TYPE *psNextNode;\ |
| pResult = NULL;\ |
| psNextNode = psHead;\ |
| while (psHead && !pResult)\ |
| {\ |
| psNextNode = psNextNode->psNext;\ |
| pResult = pfnCallBack(psHead);\ |
| psHead = psNextNode;\ |
| }\ |
| return pResult;\ |
| } |
| |
| |
| /*with variable arguments, that will be passed as a va_list to the callback function*/ |
| |
| #define DECLARE_LIST_ANY_VA(TYPE) \ |
| void* List_##TYPE##_Any_va(TYPE *psHead, void*(*pfnCallBack)(TYPE* psNode, va_list va), ...) |
| |
| #define IMPLEMENT_LIST_ANY_VA(TYPE) \ |
| void* List_##TYPE##_Any_va(TYPE *psHead, void*(*pfnCallBack)(TYPE* psNode, va_list va), ...)\ |
| {\ |
| va_list ap;\ |
| TYPE *psNextNode;\ |
| void* pResult = NULL;\ |
| while (psHead && !pResult)\ |
| {\ |
| psNextNode = psHead->psNext;\ |
| va_start(ap, pfnCallBack);\ |
| pResult = pfnCallBack(psHead, ap);\ |
| va_end(ap);\ |
| psHead = psNextNode;\ |
| }\ |
| return pResult;\ |
| } |
| |
| /*those ones are for extra type safety, so there's no need to use castings for the results*/ |
| |
| #define DECLARE_LIST_ANY_2(TYPE, RTYPE, CONTINUE) \ |
| RTYPE List_##TYPE##_##RTYPE##_Any(TYPE *psHead, RTYPE (*pfnCallBack)(TYPE* psNode)) |
| |
| #define IMPLEMENT_LIST_ANY_2(TYPE, RTYPE, CONTINUE) \ |
| RTYPE List_##TYPE##_##RTYPE##_Any(TYPE *psHead, RTYPE (*pfnCallBack)(TYPE* psNode))\ |
| { \ |
| RTYPE result;\ |
| TYPE *psNextNode;\ |
| result = CONTINUE;\ |
| psNextNode = psHead;\ |
| while (psHead && result == CONTINUE)\ |
| {\ |
| psNextNode = psNextNode->psNext;\ |
| result = pfnCallBack(psHead);\ |
| psHead = psNextNode;\ |
| }\ |
| return result;\ |
| } |
| |
| |
| #define DECLARE_LIST_ANY_VA_2(TYPE, RTYPE, CONTINUE) \ |
| RTYPE List_##TYPE##_##RTYPE##_Any_va(TYPE *psHead, RTYPE(*pfnCallBack)(TYPE* psNode, va_list va), ...) |
| |
| #define IMPLEMENT_LIST_ANY_VA_2(TYPE, RTYPE, CONTINUE) \ |
| RTYPE List_##TYPE##_##RTYPE##_Any_va(TYPE *psHead, RTYPE(*pfnCallBack)(TYPE* psNode, va_list va), ...)\ |
| {\ |
| va_list ap;\ |
| TYPE *psNextNode;\ |
| RTYPE result = CONTINUE;\ |
| while (psHead && result == CONTINUE)\ |
| {\ |
| psNextNode = psHead->psNext;\ |
| va_start(ap, pfnCallBack);\ |
| result = pfnCallBack(psHead, ap);\ |
| va_end(ap);\ |
| psHead = psNextNode;\ |
| }\ |
| return result;\ |
| } |
| |
| |
| /*************************************************************************/ /*! |
| @Function List_##TYPE##_Remove |
| @Description Removes a given node from the list. |
| @Input psNode The pointer to the node to be removed. |
| */ /**************************************************************************/ |
| #define DECLARE_LIST_REMOVE(TYPE) \ |
| void List_##TYPE##_Remove(TYPE *psNode) |
| |
| #define IMPLEMENT_LIST_REMOVE(TYPE) \ |
| void List_##TYPE##_Remove(TYPE *psNode)\ |
| {\ |
| (*psNode->ppsThis)=psNode->psNext;\ |
| if (psNode->psNext)\ |
| {\ |
| psNode->psNext->ppsThis = psNode->ppsThis;\ |
| }\ |
| } |
| |
| /*************************************************************************/ /*! |
| @Function List_##TYPE##_Insert |
| @Description Inserts a given node at the beginning of the list. |
| @Input psHead The pointer to the pointer to the head node. |
| @Input psNode The pointer to the node to be inserted. |
| */ /**************************************************************************/ |
| #define DECLARE_LIST_INSERT(TYPE) \ |
| void List_##TYPE##_Insert(TYPE **ppsHead, TYPE *psNewNode) |
| |
| #define IMPLEMENT_LIST_INSERT(TYPE) \ |
| void List_##TYPE##_Insert(TYPE **ppsHead, TYPE *psNewNode)\ |
| {\ |
| psNewNode->ppsThis = ppsHead;\ |
| psNewNode->psNext = *ppsHead;\ |
| *ppsHead = psNewNode;\ |
| if (psNewNode->psNext)\ |
| {\ |
| psNewNode->psNext->ppsThis = &(psNewNode->psNext);\ |
| }\ |
| } |
| |
| /*************************************************************************/ /*! |
| @Function List_##TYPE##_InsertTail |
| @Description Inserts a given node at the end of the list. |
| @Input psHead The pointer to the pointer to the head node. |
| @Input psNode The pointer to the node to be inserted. |
| */ /**************************************************************************/ |
| #define DECLARE_LIST_INSERT_TAIL(TYPE) \ |
| void List_##TYPE##_InsertTail(TYPE **ppsHead, TYPE *psNewNode) |
| |
| #define IMPLEMENT_LIST_INSERT_TAIL(TYPE) \ |
| void List_##TYPE##_InsertTail(TYPE **ppsHead, TYPE *psNewNode)\ |
| {\ |
| TYPE *psTempNode = *ppsHead;\ |
| if (psTempNode != NULL)\ |
| {\ |
| while (psTempNode->psNext)\ |
| psTempNode = psTempNode->psNext;\ |
| ppsHead = &psTempNode->psNext;\ |
| }\ |
| psNewNode->ppsThis = ppsHead;\ |
| psNewNode->psNext = NULL;\ |
| *ppsHead = psNewNode;\ |
| } |
| |
| /*************************************************************************/ /*! |
| @Function List_##TYPE##_Reverse |
| @Description Reverse a list in place |
| @Input ppsHead The pointer to the pointer to the head node. |
| */ /**************************************************************************/ |
| #define DECLARE_LIST_REVERSE(TYPE) \ |
| void List_##TYPE##_Reverse(TYPE **ppsHead) |
| |
| #define IMPLEMENT_LIST_REVERSE(TYPE) \ |
| void List_##TYPE##_Reverse(TYPE **ppsHead)\ |
| {\ |
| TYPE *psTmpNode1; \ |
| TYPE *psTmpNode2; \ |
| TYPE *psCurNode; \ |
| psTmpNode1 = NULL; \ |
| psCurNode = *ppsHead; \ |
| while (psCurNode) { \ |
| psTmpNode2 = psCurNode->psNext; \ |
| psCurNode->psNext = psTmpNode1; \ |
| psTmpNode1 = psCurNode; \ |
| psCurNode = psTmpNode2; \ |
| if (psCurNode) \ |
| { \ |
| psTmpNode1->ppsThis = &(psCurNode->psNext); \ |
| } \ |
| else \ |
| { \ |
| psTmpNode1->ppsThis = ppsHead; \ |
| } \ |
| } \ |
| *ppsHead = psTmpNode1; \ |
| } |
| |
| #define IS_LAST_ELEMENT(x) ((x)->psNext == NULL) |
| |
| |
| DECLARE_LIST_ANY(PVRSRV_DEVICE_NODE); |
| DECLARE_LIST_ANY_2(PVRSRV_DEVICE_NODE, IMG_BOOL, IMG_FALSE); |
| DECLARE_LIST_ANY_2(PVRSRV_DEVICE_NODE, PVRSRV_ERROR, PVRSRV_OK); |
| DECLARE_LIST_ANY_VA(PVRSRV_DEVICE_NODE); |
| DECLARE_LIST_ANY_VA_2(PVRSRV_DEVICE_NODE, PVRSRV_ERROR, PVRSRV_OK); |
| DECLARE_LIST_FOR_EACH(PVRSRV_DEVICE_NODE); |
| DECLARE_LIST_FOR_EACH_VA(PVRSRV_DEVICE_NODE); |
| DECLARE_LIST_INSERT_TAIL(PVRSRV_DEVICE_NODE); |
| DECLARE_LIST_REMOVE(PVRSRV_DEVICE_NODE); |
| |
| #undef DECLARE_LIST_ANY_2 |
| #undef DECLARE_LIST_ANY_VA |
| #undef DECLARE_LIST_ANY_VA_2 |
| #undef DECLARE_LIST_FOR_EACH |
| #undef DECLARE_LIST_FOR_EACH_VA |
| #undef DECLARE_LIST_INSERT |
| #undef DECLARE_LIST_REMOVE |
| |
| #endif |
| |
| /* re-enable warnings */ |
| /* PRQA S 0881,3410 -- */ |