tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

List.c (18472B)


      1 /***************************************************************************************************
      2 
      3  Zyan Core Library (Zycore-C)
      4 
      5  Original Author : Florian Bernd
      6 
      7 * Permission is hereby granted, free of charge, to any person obtaining a copy
      8 * of this software and associated documentation files (the "Software"), to deal
      9 * in the Software without restriction, including without limitation the rights
     10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11 * copies of the Software, and to permit persons to whom the Software is
     12 * furnished to do so, subject to the following conditions:
     13 *
     14 * The above copyright notice and this permission notice shall be included in all
     15 * copies or substantial portions of the Software.
     16 *
     17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23 * SOFTWARE.
     24 
     25 ***************************************************************************************************/
     26 
     27 #include "zydis/Zycore/LibC.h"
     28 #include "zydis/Zycore/List.h"
     29 
     30 /* ============================================================================================== */
     31 /* Internal macros                                                                                */
     32 /* ============================================================================================== */
     33 
     34 /**
     35 * Returns a pointer to the data of the given `node`.
     36 *
     37 * @param   node    A pointer to the `ZyanNodeData` struct.
     38 *
     39 * @return  A pointer to the data of the given `node`.
     40 */
     41 #define ZYCORE_LIST_GET_NODE_DATA(node) \
     42    ((void*)(node + 1))
     43 
     44 /* ============================================================================================== */
     45 /* Internal functions                                                                             */
     46 /* ============================================================================================== */
     47 
     48 /* ---------------------------------------------------------------------------------------------- */
     49 /* Helper functions                                                                               */
     50 /* ---------------------------------------------------------------------------------------------- */
     51 
     52 /**
     53 * Allocates memory for a new list node.
     54 *
     55 * @param   list    A pointer to the `ZyanList` instance.
     56 * @param   node    Receives a pointer to the new `ZyanListNode` struct.
     57 *
     58 * @return  A zyan status code.
     59 */
     60 static ZyanStatus ZyanListAllocateNode(ZyanList* list, ZyanListNode** node)
     61 {
     62    ZYAN_ASSERT(list);
     63    ZYAN_ASSERT(node);
     64 
     65    const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL);
     66    if (is_dynamic)
     67    {
     68        ZYAN_ASSERT(list->allocator->allocate);
     69        ZYAN_CHECK(list->allocator->allocate(list->allocator, (void**)node,
     70            sizeof(ZyanListNode) + list->element_size, 1));
     71    } else
     72    {
     73        if (list->first_unused)
     74        {
     75            *node = list->first_unused;
     76            list->first_unused = (*node)->next;
     77        } else
     78        {
     79            const ZyanUSize size = list->size * (sizeof(ZyanListNode) + list->element_size);
     80            if (size + (sizeof(ZyanListNode) + list->element_size) > list->capacity)
     81            {
     82                return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
     83            }
     84 
     85            *node = (ZyanListNode*)((ZyanU8*)list->buffer + size);
     86        }
     87    }
     88 
     89    return ZYAN_STATUS_SUCCESS;
     90 }
     91 
     92 /**
     93 * Frees memory of a node.
     94 *
     95 * @param   list    A pointer to the `ZyanList` instance.
     96 * @param   node    A pointer to the `ZyanListNode` struct.
     97 *
     98 * @return  A zyan status code.
     99 */
    100 static ZyanStatus ZyanListDeallocateNode(ZyanList* list, ZyanListNode* node)
    101 {
    102    ZYAN_ASSERT(list);
    103    ZYAN_ASSERT(node);
    104 
    105    const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL);
    106    if (is_dynamic)
    107    {
    108        ZYAN_ASSERT(list->allocator->deallocate);
    109        ZYAN_CHECK(list->allocator->deallocate(list->allocator, (void*)node,
    110            sizeof(ZyanListNode) + list->element_size, 1));
    111    } else
    112    {
    113        node->next = list->first_unused;
    114        list->first_unused = node;
    115    }
    116 
    117    return ZYAN_STATUS_SUCCESS;
    118 }
    119 
    120 /* ---------------------------------------------------------------------------------------------- */
    121 
    122 /* ============================================================================================== */
    123 /* Exported functions                                                                             */
    124 /* ============================================================================================== */
    125 
    126 /* ---------------------------------------------------------------------------------------------- */
    127 /* Constructor and destructor                                                                     */
    128 /* ---------------------------------------------------------------------------------------------- */
    129 
    130 #ifndef ZYAN_NO_LIBC
    131 
    132 ZYAN_REQUIRES_LIBC ZyanStatus ZyanListInit(ZyanList* list, ZyanUSize element_size,
    133    ZyanMemberProcedure destructor)
    134 {
    135    return ZyanListInitEx(list, element_size, destructor, ZyanAllocatorDefault());
    136 }
    137 
    138 #endif // ZYAN_NO_LIBC
    139 
    140 ZyanStatus ZyanListInitEx(ZyanList* list, ZyanUSize element_size, ZyanMemberProcedure destructor,
    141    ZyanAllocator* allocator)
    142 {
    143    if (!list || !element_size || !allocator)
    144    {
    145        return ZYAN_STATUS_INVALID_ARGUMENT;
    146    }
    147 
    148    list->allocator     = allocator;
    149    list->size          = 0;
    150    list->element_size  = element_size;
    151    list->destructor    = destructor;
    152    list->head          = ZYAN_NULL;
    153    list->tail          = ZYAN_NULL;
    154    list->buffer        = ZYAN_NULL;
    155    list->capacity      = 0;
    156    list->first_unused  = ZYAN_NULL;
    157 
    158    return ZYAN_STATUS_SUCCESS;
    159 }
    160 
    161 ZyanStatus ZyanListInitCustomBuffer(ZyanList* list, ZyanUSize element_size,
    162    ZyanMemberProcedure destructor, void* buffer, ZyanUSize capacity)
    163 {
    164    if (!list || !element_size || !buffer || !capacity)
    165    {
    166        return ZYAN_STATUS_INVALID_ARGUMENT;
    167    }
    168 
    169    list->allocator    = ZYAN_NULL;
    170    list->size         = 0;
    171    list->element_size = element_size;
    172    list->destructor   = destructor;
    173    list->head         = ZYAN_NULL;
    174    list->tail         = ZYAN_NULL;
    175    list->buffer       = buffer;
    176    list->capacity     = capacity;
    177    list->first_unused = ZYAN_NULL;
    178 
    179    return ZYAN_STATUS_SUCCESS;
    180 }
    181 
    182 ZyanStatus ZyanListDestroy(ZyanList* list)
    183 {
    184    if (!list)
    185    {
    186        return ZYAN_STATUS_INVALID_ARGUMENT;
    187    }
    188 
    189    ZYAN_ASSERT(list->element_size);
    190 
    191    const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL);
    192    ZyanListNode* node = (is_dynamic || list->destructor) ? list->head : ZYAN_NULL;
    193    while (node)
    194    {
    195        if (list->destructor)
    196        {
    197            list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
    198        }
    199 
    200        ZyanListNode* const next = node->next;
    201 
    202        if (is_dynamic)
    203        {
    204            ZYAN_CHECK(list->allocator->deallocate(list->allocator, node,
    205                sizeof(ZyanListNode) + list->element_size, 1));
    206        }
    207 
    208        node = next;
    209    }
    210 
    211    return ZYAN_STATUS_SUCCESS;
    212 }
    213 
    214 /* ---------------------------------------------------------------------------------------------- */
    215 /* Duplication                                                                                    */
    216 /* ---------------------------------------------------------------------------------------------- */
    217 
    218 
    219 
    220 /* ---------------------------------------------------------------------------------------------- */
    221 /* Item access                                                                                    */
    222 /* ---------------------------------------------------------------------------------------------- */
    223 
    224 ZyanStatus ZyanListGetHeadNode(const ZyanList* list, const ZyanListNode** node)
    225 {
    226    if (!list)
    227    {
    228        return ZYAN_STATUS_INVALID_ARGUMENT;
    229    }
    230 
    231    *node = list->head;
    232 
    233    return ZYAN_STATUS_SUCCESS;
    234 }
    235 
    236 ZyanStatus ZyanListGetTailNode(const ZyanList* list, const ZyanListNode** node)
    237 {
    238    if (!list)
    239    {
    240        return ZYAN_STATUS_INVALID_ARGUMENT;
    241    }
    242 
    243    *node = list->tail;
    244 
    245    return ZYAN_STATUS_SUCCESS;
    246 }
    247 
    248 ZyanStatus ZyanListGetPrevNode(const ZyanListNode** node)
    249 {
    250    if (!node || !*node)
    251    {
    252        return ZYAN_STATUS_INVALID_ARGUMENT;
    253    }
    254 
    255    *node = (*node)->prev;
    256 
    257    return ZYAN_STATUS_SUCCESS;
    258 }
    259 
    260 ZyanStatus ZyanListGetNextNode(const ZyanListNode** node)
    261 {
    262    if (!node || !*node)
    263    {
    264        return ZYAN_STATUS_INVALID_ARGUMENT;
    265    }
    266 
    267    *node = (*node)->next;
    268 
    269    return ZYAN_STATUS_SUCCESS;
    270 }
    271 
    272 const void* ZyanListGetNodeData(const ZyanListNode* node)
    273 {
    274    if (!node)
    275    {
    276        return ZYAN_NULL;
    277    }
    278 
    279    return (const void*)ZYCORE_LIST_GET_NODE_DATA(node);
    280 }
    281 
    282 ZyanStatus ZyanListGetNodeDataEx(const ZyanListNode* node, const void** value)
    283 {
    284    if (!node)
    285    {
    286        return ZYAN_STATUS_INVALID_ARGUMENT;
    287    }
    288 
    289    *value = (const void*)ZYCORE_LIST_GET_NODE_DATA(node);
    290 
    291    return ZYAN_STATUS_SUCCESS;
    292 }
    293 
    294 void* ZyanListGetNodeDataMutable(const ZyanListNode* node)
    295 {
    296    if (!node)
    297    {
    298        return ZYAN_NULL;
    299    }
    300 
    301    return ZYCORE_LIST_GET_NODE_DATA(node);
    302 }
    303 
    304 ZyanStatus ZyanListGetNodeDataMutableEx(const ZyanListNode* node, void** value)
    305 {
    306    if (!node)
    307    {
    308        return ZYAN_STATUS_INVALID_ARGUMENT;
    309    }
    310 
    311    *value = ZYCORE_LIST_GET_NODE_DATA(node);
    312 
    313    return ZYAN_STATUS_SUCCESS;
    314 }
    315 
    316 ZyanStatus ZyanListSetNodeData(const ZyanList* list, const ZyanListNode* node, const void* value)
    317 {
    318    if (!list || !node || !value)
    319    {
    320        return ZYAN_STATUS_INVALID_ARGUMENT;
    321    }
    322 
    323    if (list->destructor)
    324    {
    325        list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
    326    }
    327 
    328    ZYAN_ASSERT(list->element_size);
    329    ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), value, list->element_size);
    330 
    331    return ZYAN_STATUS_SUCCESS;
    332 }
    333 
    334 /* ---------------------------------------------------------------------------------------------- */
    335 /* Insertion                                                                                      */
    336 /* ---------------------------------------------------------------------------------------------- */
    337 
    338 ZyanStatus ZyanListPushBack(ZyanList* list, const void* item)
    339 {
    340    if (!list || !item)
    341    {
    342        return ZYAN_STATUS_INVALID_ARGUMENT;
    343    }
    344 
    345    ZyanListNode* node;
    346    ZYAN_CHECK(ZyanListAllocateNode(list, &node));
    347    node->prev = list->tail;
    348    node->next = ZYAN_NULL;
    349 
    350    ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), item, list->element_size);
    351 
    352    if (!list->head)
    353    {
    354        list->head = node;
    355        list->tail = node;
    356    } else
    357    {
    358        list->tail->next = node;
    359        list->tail = node;
    360    }
    361    ++list->size;
    362 
    363    return ZYAN_STATUS_SUCCESS;
    364 }
    365 
    366 ZyanStatus ZyanListPushFront(ZyanList* list, const void* item)
    367 {
    368    if (!list || !item)
    369    {
    370        return ZYAN_STATUS_INVALID_ARGUMENT;
    371    }
    372 
    373    ZyanListNode* node;
    374    ZYAN_CHECK(ZyanListAllocateNode(list, &node));
    375    node->prev = ZYAN_NULL;
    376    node->next = list->head;
    377 
    378    ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), item, list->element_size);
    379 
    380    if (!list->head)
    381    {
    382        list->head = node;
    383        list->tail = node;
    384    } else
    385    {
    386        list->head->prev= node;
    387        list->head = node;
    388    }
    389    ++list->size;
    390 
    391    return ZYAN_STATUS_SUCCESS;
    392 }
    393 
    394 ZyanStatus ZyanListEmplaceBack(ZyanList* list, void** item, ZyanMemberFunction constructor)
    395 {
    396    if (!list || !item)
    397    {
    398        return ZYAN_STATUS_INVALID_ARGUMENT;
    399    }
    400 
    401    ZyanListNode* node;
    402    ZYAN_CHECK(ZyanListAllocateNode(list, &node));
    403    node->prev = list->tail;
    404    node->next = ZYAN_NULL;
    405 
    406    *item = ZYCORE_LIST_GET_NODE_DATA(node);
    407    if (constructor)
    408    {
    409        constructor(*item);
    410    }
    411 
    412    if (!list->head)
    413    {
    414        list->head = node;
    415        list->tail = node;
    416    } else
    417    {
    418        list->tail->next = node;
    419        list->tail = node;
    420    }
    421    ++list->size;
    422 
    423    return ZYAN_STATUS_SUCCESS;
    424 }
    425 
    426 ZyanStatus ZyanListEmplaceFront(ZyanList* list, void** item, ZyanMemberFunction constructor)
    427 {
    428    if (!list || !item)
    429    {
    430        return ZYAN_STATUS_INVALID_ARGUMENT;
    431    }
    432 
    433    ZyanListNode* node;
    434    ZYAN_CHECK(ZyanListAllocateNode(list, &node));
    435    node->prev = ZYAN_NULL;
    436    node->next = list->head;
    437 
    438    *item = ZYCORE_LIST_GET_NODE_DATA(node);
    439    if (constructor)
    440    {
    441        constructor(*item);
    442    }
    443 
    444    if (!list->head)
    445    {
    446        list->head = node;
    447        list->tail = node;
    448    } else
    449    {
    450        list->head->prev= node;
    451        list->head = node;
    452    }
    453    ++list->size;
    454 
    455    return ZYAN_STATUS_SUCCESS;
    456 }
    457 
    458 /* ---------------------------------------------------------------------------------------------- */
    459 /* Deletion                                                                                       */
    460 /* ---------------------------------------------------------------------------------------------- */
    461 
    462 ZyanStatus ZyanListPopBack(ZyanList* list)
    463 {
    464    if (!list)
    465    {
    466        return ZYAN_STATUS_INVALID_ARGUMENT;
    467    }
    468    if (!list->tail)
    469    {
    470        return ZYAN_STATUS_INVALID_OPERATION;
    471    }
    472 
    473    ZyanListNode* const node = list->tail;
    474 
    475    if (list->destructor)
    476    {
    477        list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
    478    }
    479 
    480    list->tail = node->prev;
    481    if (list->tail)
    482    {
    483        list->tail->next = ZYAN_NULL;
    484    }
    485    if (list->head == node)
    486    {
    487        list->head = list->tail;
    488    }
    489    --list->size;
    490 
    491    return ZyanListDeallocateNode(list, node);
    492 }
    493 
    494 ZyanStatus ZyanListPopFront(ZyanList* list)
    495 {
    496    if (!list)
    497    {
    498        return ZYAN_STATUS_INVALID_ARGUMENT;
    499    }
    500    if (!list->head)
    501    {
    502        return ZYAN_STATUS_INVALID_OPERATION;
    503    }
    504 
    505    ZyanListNode* const node = list->head;
    506 
    507    if (list->destructor)
    508    {
    509        list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
    510    }
    511 
    512    list->head = node->next;
    513    if (list->head)
    514    {
    515        list->head->prev = ZYAN_NULL;
    516    }
    517    if (list->tail == node)
    518    {
    519        list->tail = list->head;
    520    }
    521    --list->size;
    522 
    523    return ZyanListDeallocateNode(list, node);
    524 }
    525 
    526 ZyanStatus ZyanListRemove(ZyanList* list, const ZyanListNode* node)
    527 {
    528    ZYAN_UNUSED(list);
    529    ZYAN_UNUSED(node);
    530    return ZYAN_STATUS_SUCCESS;
    531 }
    532 
    533 ZyanStatus ZyanListRemoveRange(ZyanList* list, const ZyanListNode* first, const ZyanListNode* last)
    534 {
    535    ZYAN_UNUSED(list);
    536    ZYAN_UNUSED(first);
    537    ZYAN_UNUSED(last);
    538    return ZYAN_STATUS_SUCCESS;
    539 }
    540 
    541 ZyanStatus ZyanListClear(ZyanList* list)
    542 {
    543    return ZyanListResizeEx(list, 0, ZYAN_NULL);
    544 }
    545 
    546 /* ---------------------------------------------------------------------------------------------- */
    547 /* Searching                                                                                      */
    548 /* ---------------------------------------------------------------------------------------------- */
    549 
    550 
    551 
    552 /* ---------------------------------------------------------------------------------------------- */
    553 /* Memory management                                                                              */
    554 /* ---------------------------------------------------------------------------------------------- */
    555 
    556 ZyanStatus ZyanListResize(ZyanList* list, ZyanUSize size)
    557 {
    558    return ZyanListResizeEx(list, size, ZYAN_NULL);
    559 }
    560 
    561 ZyanStatus ZyanListResizeEx(ZyanList* list, ZyanUSize size, const void* initializer)
    562 {
    563    if (!list)
    564    {
    565        return ZYAN_STATUS_INVALID_ARGUMENT;
    566    }
    567    if (size == list->size)
    568    {
    569        return ZYAN_STATUS_SUCCESS;
    570    }
    571 
    572    if (size == 0)
    573    {
    574        const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL);
    575        ZyanListNode* node = (is_dynamic || list->destructor) ? list->head : ZYAN_NULL;
    576        while (node)
    577        {
    578            if (list->destructor)
    579            {
    580                list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
    581            }
    582 
    583            ZyanListNode* const next = node->next;
    584 
    585            if (is_dynamic)
    586            {
    587                ZYAN_CHECK(list->allocator->deallocate(list->allocator, node,
    588                    sizeof(ZyanListNode) + list->element_size, 1));
    589            }
    590 
    591            node = next;
    592        }
    593 
    594        list->size = 0;
    595        list->head = 0;
    596        list->tail = 0;
    597        list->first_unused = ZYAN_NULL;
    598 
    599        return ZYAN_STATUS_SUCCESS;
    600    }
    601 
    602    if (size > list->size)
    603    {
    604        ZyanListNode* node;
    605        for (ZyanUSize i = list->size; i < size; ++i)
    606        {
    607            ZYAN_CHECK(ZyanListAllocateNode(list, &node));
    608            node->prev = list->tail;
    609            node->next = ZYAN_NULL;
    610 
    611            if (initializer)
    612            {
    613                ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), initializer, list->element_size);
    614            }
    615 
    616            if (!list->head)
    617            {
    618                list->head = node;
    619                list->tail = node;
    620            } else
    621            {
    622                list->tail->next = node;
    623                list->tail = node;
    624            }
    625 
    626            // `ZyanListAllocateNode` needs the list size
    627            ++list->size;
    628        }
    629    } else
    630    {
    631        for (ZyanUSize i = size; i < list->size; ++i)
    632        {
    633            ZyanListNode* const node = list->tail;
    634 
    635            if (list->destructor)
    636            {
    637                list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
    638            }
    639 
    640            list->tail = node->prev;
    641            if (list->tail)
    642            {
    643                list->tail->next = ZYAN_NULL;
    644            }
    645 
    646            ZYAN_CHECK(ZyanListDeallocateNode(list, node));
    647        }
    648 
    649        list->size = size;
    650    }
    651 
    652    return ZYAN_STATUS_SUCCESS;
    653 }
    654 
    655 /* ---------------------------------------------------------------------------------------------- */
    656 /* Information                                                                                    */
    657 /* ---------------------------------------------------------------------------------------------- */
    658 
    659 ZyanStatus ZyanListGetSize(const ZyanList* list, ZyanUSize* size)
    660 {
    661    if (!list)
    662    {
    663        return ZYAN_STATUS_INVALID_ARGUMENT;
    664    }
    665 
    666    *size = list->size;
    667 
    668    return ZYAN_STATUS_SUCCESS;
    669 }
    670 
    671 /* ---------------------------------------------------------------------------------------------- */
    672 
    673 /* ============================================================================================== */