/*

 * Copyright (C) 2021-2025 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *    http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */



#ifndef HC_VECTOR_H

#define HC_VECTOR_H



#include "hc_parcel.h"

#include "securec.h"



/*

 * Use DECLARE_HC_VECTOR to declare the vector in the head/src file.

 * @para ClassName: the name of the vector-class/vector-struct

 * @para Element: the type of the vector element

 * @for example:

 * DECLARE_HC_VECTOR(IntVec, int)

 */

#define DECLARE_HC_VECTOR(ClassName, Element) \

typedef struct V##ClassName{ \

    Element* (*pushBack)(struct V##ClassName*, const Element*); \

    Element* (*pushBackT)(struct V##ClassName*, Element); \

    HcBool (*popFront)(struct V##ClassName*, Element*); \

    HcBool (*eraseElement)(struct V##ClassName*, Element*, uint32_t index); \

    uint32_t (*size)(const struct V##ClassName*); \

    Element (*get)(const struct V##ClassName*, uint32_t index); \

    Element* (*getp)(const struct V##ClassName*, uint32_t index); \

    void (*clear)(struct V##ClassName*); \

    HcParcel parcel; \

} ClassName;



/*

 * Use IMPLEMENT_HC_VECTOR to implement the vector in the source file.

 * @para ClassName: the name of the vector-class/vector-struct

 * @para Element: the type of the vector element

 * @para allocCount: the minimum alloc count

 * @for example:

 * IMPLEMENT_HC_VECTOR(IntVec, int)

 */

#define IMPLEMENT_HC_VECTOR(ClassName, Element, allocCount) \

Element* VPushBack##ClassName(ClassName* obj, const Element *e) { \

    if (obj == NULL || e == NULL) { \

        return NULL; \

    } \

      \

    if (ParcelWrite(&obj->parcel, e, sizeof(Element))) { \

        uint32_t size = obj->size(obj); \

        return obj->getp(obj, size - 1); \

    } else { \

        return NULL; \

    } \

} \

Element* VPushBackT##ClassName(ClassName* obj, Element e) { \

    if (obj == NULL) { \

        return NULL; \

    } \

      \

    if (ParcelWrite(&obj->parcel, &e, sizeof(Element))) { \

        uint32_t size = obj->size(obj); \

        return obj->getp(obj, size - 1); \

    } else { \

        return NULL; \

    } \

} \

HcBool VPopFront##ClassName(ClassName* obj, Element* e) { \

        if (NULL == obj || NULL == e) { \

            return HC_FALSE; \

        } \

        if (obj->size(obj) > 0) { \

            return ParcelRead(&obj->parcel, e, sizeof(Element)); \

        } else { \

            return HC_FALSE; \

        } \

} \

HcBool VErase##ClassName(ClassName* obj, Element* e, uint32_t index) { \

        if (NULL == obj || NULL == e || index + 1 > obj->size(obj)) { \

            return HC_FALSE; \

        } \

        if (obj->size(obj) > 0) { \

            return ParcelEraseBlock(&obj->parcel, index * sizeof(Element), sizeof(Element), e); \

        } else { \

            return HC_FALSE; \

        } \

} \

uint32_t VSize##ClassName(const ClassName* obj) \

{ \

    if (NULL == obj) { \

        return 0; \

    } \

    return GetParcelDataSize(&obj->parcel) / sizeof(Element); \

} \

Element VGet##ClassName(const ClassName* obj, uint32_t index) \

{ \

    Element e; \

    (void)memset_s(&e, sizeof(Element), 0, sizeof(Element)); \

    if (NULL != obj) { \

        if (index < obj->size(obj)) { \

            if (GetParcelData(&obj->parcel)) { \

                return *((Element*)(GetParcelData(&obj->parcel)) + index); \

            } else { \

                return e; \

            } \

        } \

    } \

    (void)memset_s(&e, sizeof(Element), 0, sizeof(Element)); \

    return e; \

} \

Element* VGetPointer##ClassName(const ClassName* obj, uint32_t index) \

{ \

    if (NULL != obj) { \

        if (index < obj->size(obj)) { \

            if (GetParcelData(&obj->parcel)) { \

                return ((Element*)(GetParcelData(&obj->parcel)) + index); \

            } else { \

                return NULL; \

            } \

        } \

    } \

    return NULL; \

} \

void VClear##ClassName(ClassName* obj) \

{ \

    if (NULL != obj) { \

        ClearParcel(&obj->parcel); \

    } \

} \

ClassName Create##ClassName(void) \

{ \

    ClassName obj; \

    obj.pushBack = VPushBack##ClassName; \

    obj.pushBackT = VPushBackT##ClassName; \

    obj.popFront = VPopFront##ClassName; \

    obj.clear = VClear##ClassName; \

    obj.eraseElement = VErase##ClassName; \

    obj.size = VSize##ClassName; \

    obj.get = VGet##ClassName; \

    obj.getp = VGetPointer##ClassName; \

    obj.parcel = CreateParcel(0, sizeof(Element) * allocCount); \

    return obj; \

} \

void Destroy##ClassName(ClassName* obj) \

{ \

    if (NULL != obj) { \

        DeleteParcel(&obj->parcel); \

    } \

}



/* Use these two macros to create and destroy vector */

#define CREATE_HC_VECTOR(classname) Create##classname()

#define DESTROY_HC_VECTOR(classname, obj) Destroy##classname(obj)

#define HC_VECTOR_PUSHBACK(obj, element) (obj)->pushBack((obj), (element))

#define HC_VECTOR_POPFRONT(obj, element) (obj)->popFront((obj), (element))

#define HC_VECTOR_POPELEMENT(obj, element, index) (obj)->eraseElement((obj), (element), (index))

#define HC_VECTOR_SIZE(obj) (obj)->size(obj)

#define HC_VECTOR_GET(obj, index) (obj)->get((obj), (index))

#define HC_VECTOR_GETP(_obj, _index) (_obj)->getp((_obj), (_index))

#define FOR_EACH_HC_VECTOR(vec, i, iter) \

for ((i) = 0, (iter) = (vec).getp(&(vec), (i)); (i) < (vec).size(&(vec)); ++(i), (iter) = (vec).getp(&(vec), (i)))



#endif