Home

Resume

Blog

Teikitu


/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/*  »Project«   Teikitu Gaming System (TgS) (∂)
    »File«      TgS Common - Util SP - Array.c
    »Author«    Andrew Aye (EMail: mailto:andrew.aye@gmail.com, Web: http://www.andrewaye.com)
    »Version«   4.51 / »GUID« A9981407-3EC9-42AF-8B6F-8BE6DD919615                                                                                                        */
/*   -------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
/*  Copyright: © 2002-2017, Andrew Aye.  All Rights Reserved.
    This software is free for non-commercial use.  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
      following conditions are met:
        Redistribution of source code must retain this copyright notice, this list of conditions and the following disclaimers.
        Redistribution in binary form must reproduce this copyright notice, this list of conditions and the following disclaimers in the documentation and other materials
          provided with the distribution.
    The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
    The intellectual property rights of the algorithms used reside with Andrew Aye.
    You may not use this software, in whole or in part, in support of any commercial product without the express written consent of the author.
    There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is".                                                   */
/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/* == Common ============================================================================================================================================================ */

/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  Public Functions                                                                                                                                                      */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

/* ---- tgCM_UTS_AR_Assign_ElementN ------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgCM_UTS_AR_Assign_ElementN( PCU_STg2_UTS_AR psAR, P_TgVOID pElement, C_TgSIZE uiCount )
{
    P_TgUINT08                          puiElement;
    P_TgUINT08                          puiData;
    TgSIZE                              uiIndex;
    TgSIZE                              nuiElement;
    TgSIZE                              uiLimit;
    TgBOOL                              bFreeElement;

    if (0 == uiCount)
    {
        tgCM_UTS_AR_Clear( psAR );
        return (KTgS_OK);
    };

    puiElement = (P_TgUINT08)pElement;
    puiData = (P_TgUINT08)tgCM_UTS_AR_Get_Data( psAR );
    nuiElement = tgCM_UTS_AR_Count( psAR );
    bFreeElement = TgFALSE;

    if (uiCount > tgCM_UTS_AR_Capacity( psAR ))
    {
        if (psAR->m_bFixed)
            return (KTgE_FAIL);

        if (psAR->m_puiStart <= puiElement && puiElement < psAR->m_puiLast)
        {
            P_TgUINT08                          pTempElement;

            pTempElement = (P_TgUINT08)TgMALLOC_TEMP( psAR->m_uiStride );
            TgMEMCPY( pTempElement, psAR->m_uiStride, pElement, psAR->m_uiStride );
            pElement = puiElement = pTempElement;
            bFreeElement = TgTRUE;
        };

        tgCM_UTS_AR_Clear( psAR );
        tgCM_UTS_AR_Reserve( psAR, uiCount );

        puiData = (P_TgUINT08)tgCM_UTS_AR_Get_Data( psAR );
        nuiElement = tgCM_UTS_AR_Count( psAR );
    };

    uiIndex = 0;

    uiLimit = tgCM_MIN_UXX( nuiElement, uiCount );
    if (psAR->m_pAssignment)
    {
        for (; uiIndex < uiLimit; ++uiIndex)
        {
            psAR->m_pAssignment( puiData + uiIndex*psAR->m_uiStride, pElement );
        };
    }
    else
    {
        for (; uiIndex < uiLimit; ++uiIndex)
        {
            TgMEMCPY( puiData + uiIndex*psAR->m_uiStride, psAR->m_uiStride, pElement, psAR->m_uiStride );
        };
    };

    if (psAR->m_pInitCopy)
    {
        for (; uiIndex < uiCount; ++uiIndex)
        {
            psAR->m_pInitCopy( puiData + uiIndex*psAR->m_uiStride, pElement );
        };
    }
    else
    {
        for (; uiIndex < uiCount; ++uiIndex)
        {
            TgMEMCPY( puiData + uiIndex*psAR->m_uiStride, psAR->m_uiStride, pElement, psAR->m_uiStride );
        };
    };

    if (TgTRUE == bFreeElement)
    {
        TgFREE_TEMP( pElement );
    }

    if (psAR->m_pFree)
    {
        for (; uiIndex < nuiElement; ++uiIndex)
        {
            psAR->m_pFree( puiData + uiIndex*psAR->m_uiStride );
        };
    };

    psAR->m_puiLast = puiData + uiCount * psAR->m_uiStride;
    TgERROR(psAR->m_puiLast <= psAR->m_puiEnd);

    return (KTgS_OK);
}


/* ---- tgCM_UTS_AR_Assign_Range ---------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgCM_UTS_AR_Assign_Range( PCU_STg2_UTS_AR psAR, P_TgVOID pStart, P_TgVOID pLast )
{
    P_TgUINT08                          puiStart;
    P_TgUINT08                          puiLast;
    TgSIZE                              uiCount;
    P_TgUINT08                          puiData;
    TgSIZE                              uiIndex;
    TgSIZE                              nuiElement;
    TgSIZE                              uiLimit;

    if (pStart >= pLast || nullptr == pStart)
    {
        tgCM_UTS_AR_Clear( psAR );
        return (KTgS_OK);
    };

    puiStart = (P_TgUINT08)pStart;
    puiLast = (P_TgUINT08)pLast;
    TgERROR(0 == ((TgSIZE)(puiLast - puiStart) % psAR->m_uiStride));
    uiCount = (TgSIZE)(puiLast - puiStart) / psAR->m_uiStride;

    puiData = (P_TgUINT08)tgCM_UTS_AR_Get_Data( psAR );
    nuiElement = tgCM_UTS_AR_Count( psAR );

    if (uiCount > tgCM_UTS_AR_Capacity( psAR ))
    {
        if (psAR->m_bFixed)
            return (KTgE_FAIL);

        tgCM_UTS_AR_Clear( psAR );
        tgCM_UTS_AR_Reserve( psAR, uiCount );

        puiData = (P_TgUINT08)tgCM_UTS_AR_Get_Data( psAR );
        nuiElement = tgCM_UTS_AR_Count( psAR );
    };

    uiIndex = puiData == pStart ? uiCount : 0;

    uiLimit = tgCM_MIN_UXX( nuiElement, uiCount );
    if (psAR->m_pAssignment)
    {
        for (; uiIndex < uiLimit; ++uiIndex)
        {
            psAR->m_pAssignment( puiData + uiIndex*psAR->m_uiStride, puiStart + uiIndex*psAR->m_uiStride );
        };
    }
    else if (uiLimit > 0)
    {
        TgMEMCPY( puiData, uiLimit*psAR->m_uiStride, puiStart, uiLimit*psAR->m_uiStride );
        uiIndex = uiLimit;
    };

    if (psAR->m_pInitCopy)
    {
        for (; uiIndex < uiCount; ++uiIndex)
        {
            psAR->m_pInitCopy( puiData + uiIndex*psAR->m_uiStride, puiStart + uiIndex*psAR->m_uiStride );
        };
    }
    else if (uiIndex < uiCount)
    {
        TgSIZE                              uiCopySize;

        uiCopySize = (uiCount - uiIndex)*psAR->m_uiStride;
        TgMEMCPY( puiData + uiIndex*psAR->m_uiStride, uiCopySize, puiStart + uiIndex*psAR->m_uiStride, uiCopySize );
        uiIndex = uiCount;
    };

    if (psAR->m_pFree)
    {
        for (; uiIndex < nuiElement; ++uiIndex)
        {
            psAR->m_pFree( puiData + uiIndex*psAR->m_uiStride );
        };
    };

    psAR->m_puiLast = puiData + uiCount * psAR->m_uiStride;
    TgERROR(psAR->m_puiLast <= psAR->m_puiEnd);

    return (KTgS_OK);
}


/* ---- tgCM_UTS_AR_Insert_ElementN ------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgCM_UTS_AR_Insert_ElementN( PCU_STg2_UTS_AR psAR, C_TgSIZE uiIndex, P_TgVOID pElement, C_TgSIZE uiCount )
{
    if (0 == uiCount)
        return (KTgS_OK);

    if (psAR->m_puiEnd < psAR->m_puiLast + uiCount*psAR->m_uiStride)
    {
        P_TgUINT08                          puiData;
        TgSIZE                              uiSize;
        TgSIZE                              uiNewSize;
        P_TgUINT08                          puiNewData;
        P_TgUINT08                          puiNewStart;

        if (psAR->m_bFixed)
            return (KTgE_FAIL);

        puiData = psAR->m_puiStart;
        uiSize = (TgSIZE)(psAR->m_puiLast - psAR->m_puiStart);
        uiNewSize = uiSize + psAR->m_uiStride*uiCount;
        puiNewData = (P_TgUINT08)TgMALLOC_POOL( uiNewSize );
        if (nullptr == puiNewData)
            return (KTgE_FAIL);

        puiNewStart = puiNewData;

        /* Copy [Start, Index) into New Buffer */
        if (nullptr != psAR->m_puiStart)
        {
            if (psAR->m_pInitCopy)
            {
                while (puiData < psAR->m_puiStart + uiIndex*psAR->m_uiStride)
                {
                    psAR->m_pInitCopy( puiNewData, puiData );
                    puiNewData += psAR->m_uiStride;
                    puiData += psAR->m_uiStride;
                };
            }
            else
            {
                TgMEMCPY( puiNewData, psAR->m_uiStride*(uiSize + uiCount), puiData, uiIndex*psAR->m_uiStride );
                puiNewData += uiIndex*psAR->m_uiStride;
                puiData += uiIndex*psAR->m_uiStride;
            };

            uiNewSize -= uiIndex*psAR->m_uiStride;
        };

        /* Copy pElement uiCount times into New Buffer */
        if (psAR->m_pInitCopy)
        {
            TgSIZE                              uiElement;

            for (uiElement = 0; uiElement < uiCount; ++uiElement)
            {
                psAR->m_pInitCopy( puiNewData, pElement );
                puiNewData += psAR->m_uiStride;
            };
            uiNewSize -= uiCount*psAR->m_uiStride;
        }
        else
        {
            TgSIZE                              uiElement;

            for (uiElement = 0; uiElement < uiCount; ++uiElement)
            {
                TgMEMCPY( puiNewData, uiNewSize, pElement, psAR->m_uiStride );
                puiNewData += psAR->m_uiStride;
                uiNewSize -= psAR->m_uiStride;
            };
        };

        /* Copy [Index, Last) into New Buffer */
        if (nullptr != psAR->m_puiStart)
        {
            if (psAR->m_pInitCopy)
            {
                while (puiData < psAR->m_puiLast)
                {
                    psAR->m_pInitCopy( puiNewData, puiData );
                    puiNewData += psAR->m_uiStride;
                    puiData += psAR->m_uiStride;
                };
            }
            else
            {
                TgMEMCPY( puiNewData, uiNewSize, puiData, (TgSIZE)(psAR->m_puiLast - psAR->m_puiStart) - uiIndex*psAR->m_uiStride );
                puiNewData += (TgSIZE)(psAR->m_puiLast - psAR->m_puiStart) - uiIndex*psAR->m_uiStride;
            };

            /* Free the original buffer */
            if (psAR->m_pFree)
            {
                puiData = psAR->m_puiStart;
                while (puiData < psAR->m_puiLast)
                {
                    psAR->m_pFree( puiData );
                    puiData += psAR->m_uiStride;
                };
            };

            TgFREE_POOL( psAR->m_puiStart );
        };

        TgERROR(puiNewData == puiNewStart + uiSize + psAR->m_uiStride*uiCount);
        psAR->m_puiEnd = puiNewData;
        psAR->m_puiLast = puiNewData;
        psAR->m_puiStart = puiNewStart;
    }
    else
    {
        TgSIZE                              uiTailSize;
        P_TgUINT08                          puiSrcData;
        P_TgUINT08                          puiDestData;

        uiTailSize = (TgSIZE)(psAR->m_puiLast - psAR->m_puiStart) - uiIndex*psAR->m_uiStride;

        if (uiTailSize > uiCount*psAR->m_uiStride)
        {
            /* m_puiLast <= [m_puiLast - uiCount, m_puiLast) */
            puiSrcData = psAR->m_puiLast - uiCount*psAR->m_uiStride;
            puiDestData = psAR->m_puiLast;
            if (psAR->m_pInitCopy)
            {
                while (puiSrcData < psAR->m_puiLast)
                {
                    psAR->m_pInitCopy( puiDestData, puiSrcData );
                    puiSrcData += psAR->m_uiStride;
                    puiDestData += psAR->m_uiStride;
                };
            }
            else
            {
                TgMEMCPY( puiDestData, (TgSIZE)(psAR->m_puiEnd - psAR->m_puiLast), puiSrcData, uiCount*psAR->m_uiStride );
                puiSrcData += uiCount*psAR->m_uiStride;
                puiDestData += uiCount*psAR->m_uiStride;
            };

            /* m_puiStart + uiCount  + uiIndex <= [m_puiStart + uiIndex, m_puiLast - uiCount) */
            if (psAR->m_pAssignment)
            {
                puiSrcData = psAR->m_puiLast - uiCount*psAR->m_uiStride;
                puiDestData = psAR->m_puiLast;

                do
                {
                    puiDestData -= psAR->m_uiStride;
                    puiSrcData -= psAR->m_uiStride;
                    psAR->m_pAssignment( puiDestData, puiSrcData );
                }
                while (puiSrcData > psAR->m_puiStart + uiIndex*psAR->m_uiStride);
            }
            else
            {
                TgMEMMOVE(
                    psAR->m_puiStart + (uiCount + uiIndex)*psAR->m_uiStride,
                    (TgSIZE)(psAR->m_puiEnd - psAR->m_puiStart) - (uiCount + uiIndex)*psAR->m_uiStride,
                    psAR->m_puiStart + uiIndex*psAR->m_uiStride,
                    (TgSIZE)(psAR->m_puiLast - psAR->m_puiStart) - (uiCount + uiIndex)*psAR->m_uiStride );
            };

            /* Copy pElement uiCount times into New Buffer */
            puiDestData = psAR->m_puiStart + uiIndex*psAR->m_uiStride;
            if (psAR->m_pAssignment)
            {
                TgSIZE                              uiElement;

                for (uiElement = 0; uiElement < uiCount; ++uiElement)
                {
                    psAR->m_pAssignment( puiDestData, pElement );
                    puiDestData += psAR->m_uiStride;
                };
            }
            else
            {
                TgSIZE                              uiElement;

                for (uiElement = 0; uiElement < uiCount; ++uiElement)
                {
                    TgMEMCPY( puiDestData, psAR->m_uiStride, pElement, psAR->m_uiStride );
                    puiDestData += psAR->m_uiStride;
                };
            };
            psAR->m_puiLast += uiCount*psAR->m_uiStride;
        }
        else
        {
            P_TgUINT08                          puiOldLast;
            TgSIZE                              uiElement;

            puiDestData = psAR->m_puiLast;
            puiOldLast = psAR->m_puiLast;

            if (psAR->m_pInitCopy)
            {
                for (uiElement = 0; uiElement < uiCount - uiTailSize / psAR->m_uiStride; ++uiElement)
                {
                    psAR->m_pInitCopy( puiDestData, pElement );
                    puiDestData += psAR->m_uiStride;
                };
            }
            else
            {
                for (uiElement = 0; uiElement < uiCount - uiTailSize / psAR->m_uiStride; ++uiElement)
                {
                    TgMEMCPY( puiDestData, psAR->m_uiStride, pElement, psAR->m_uiStride );
                    puiDestData += psAR->m_uiStride;
                };
            };
            psAR->m_puiLast = puiDestData;

            if (psAR->m_pInitCopy)
            {
                P_TgUINT08                          puiData;

                puiData = psAR->m_puiStart + uiIndex*psAR->m_uiStride;
                while (puiData < puiOldLast)
                {
                    psAR->m_pInitCopy( puiDestData, puiData );
                    puiDestData += psAR->m_uiStride;
                    puiData += psAR->m_uiStride;
                };
            }
            else
            {
                TgSIZE                              uiSize;

                uiSize = (TgSIZE)(puiOldLast - psAR->m_puiStart) - uiIndex*psAR->m_uiStride;
                TgMEMCPY( puiDestData, (TgSIZE)(psAR->m_puiEnd - puiDestData), psAR->m_puiStart + uiIndex*psAR->m_uiStride, uiSize );
                puiDestData += uiSize;
            };
            psAR->m_puiLast = puiDestData;

            puiDestData = psAR->m_puiStart + uiIndex*psAR->m_uiStride;
            if (psAR->m_pAssignment)
            {
                while (puiDestData < puiOldLast)
                {
                    psAR->m_pAssignment( puiDestData, pElement );
                    puiDestData += psAR->m_uiStride;
                };
            }
            else
            {
                while (puiDestData < puiOldLast)
                {
                    TgMEMCPY( puiDestData, (TgSIZE)(psAR->m_puiEnd - puiDestData), pElement, psAR->m_uiStride );
                    puiDestData += psAR->m_uiStride;
                };
            };
        };
    };

    return (KTgS_OK);
}


/* ---- tgCM_UTS_AR_Insert_Range ---------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgCM_UTS_AR_Insert_Range( PCU_STg2_UTS_AR psAR, C_TgSIZE uiIndex, P_TgVOID pInsertStart, P_TgVOID pInsertLast )
{
    TgSIZE                              uiInsertSize;
    TgSIZE                              nuiInsert;
    TgBOOL                              bIs_Inside;
    TgSIZE                              uiSize;
    TgSIZE                              uiNewSize;
    TgSIZE                              uiFreeSize;

    if (pInsertStart >= pInsertLast || nullptr == pInsertStart || nullptr == pInsertLast || !psAR->m_uiStride)
        return (KTgS_OK);

    uiSize = (TgSIZE)(psAR->m_puiLast - psAR->m_puiStart);
    if (uiIndex > uiSize / psAR->m_uiStride)
        return (KTgE_FAIL);

    uiInsertSize = (TgSIZE)((P_TgUINT08)pInsertLast - (P_TgUINT08)pInsertStart);
    TgERROR(0 == (uiInsertSize % psAR->m_uiStride));
    nuiInsert = uiInsertSize / psAR->m_uiStride;
    bIs_Inside = !(((P_TgUINT08)pInsertLast <= psAR->m_puiStart) || ((P_TgUINT08)pInsertStart >= psAR->m_puiLast));

    uiFreeSize = (TgSIZE)(psAR->m_puiEnd - psAR->m_puiLast);
    uiNewSize = uiSize + uiInsertSize;


    if (uiFreeSize < uiInsertSize || bIs_Inside)
    {
        P_TgUINT08                          puiData;
        P_TgUINT08                          puiNewData;
        P_TgUINT08                          puiNewStart;

        if (psAR->m_bFixed)
            return (KTgE_FAIL);

        puiData = psAR->m_puiStart;
        puiNewData = (P_TgUINT08)TgMALLOC_POOL( uiNewSize );
        if (nullptr == puiNewData)
            return (KTgE_FAIL);

        puiNewStart = puiNewData;

        /* Copy [Start, Index) into New Buffer */
        if (nullptr != psAR->m_puiStart)
        {
            if (psAR->m_pInitCopy)
            {
                P_TgUINT08                          puiDataAtIndex;

                puiDataAtIndex = psAR->m_puiStart + uiIndex*psAR->m_uiStride;
                while (puiData < puiDataAtIndex)
                {
                    psAR->m_pInitCopy( puiNewData, puiData );
                    puiNewData += psAR->m_uiStride;
                    puiData += psAR->m_uiStride;
                };
            }
            else
            {
                TgMEMCPY( puiNewData, uiNewSize, puiData, uiIndex*psAR->m_uiStride );
                puiNewData += uiIndex*psAR->m_uiStride;
                puiData += uiIndex*psAR->m_uiStride;
            };

            uiNewSize -= uiIndex*psAR->m_uiStride;
        };

        /* Copy [pStart,pLast) into New Buffer */
        if (psAR->m_pInitCopy)
        {
            P_TgUINT08                          puiStart;

            puiStart = (P_TgUINT08)pInsertStart;
            while (puiStart < (P_TgUINT08)pInsertLast)
            {
                psAR->m_pInitCopy( puiNewData, puiStart );
                puiNewData += psAR->m_uiStride;
                puiStart += psAR->m_uiStride;
            };
        }
        else
        {
            TgMEMCPY( puiNewData, uiNewSize, pInsertStart, uiInsertSize );
            puiNewData += uiInsertSize;
        };

        uiNewSize -= uiInsertSize;

        /* Copy [Index, Last) into New Buffer */
        if (nullptr != psAR->m_puiStart)
        {
            if (psAR->m_pInitCopy)
            {
                while (puiData < psAR->m_puiLast)
                {
                    psAR->m_pInitCopy( puiNewData, puiData );
                    puiNewData += psAR->m_uiStride;
                    puiData += psAR->m_uiStride;
                };
            }
            else
            {
                TgMEMCPY( puiNewData, uiNewSize, puiData, uiSize - uiIndex*psAR->m_uiStride );
                puiNewData += uiSize - uiIndex*psAR->m_uiStride;
            };

            /* Free the original buffer */
            if (psAR->m_pFree)
            {
                puiData = psAR->m_puiStart;
                while (puiData < psAR->m_puiLast)
                {
                    psAR->m_pFree( puiData );
                    puiData += psAR->m_uiStride;
                };
            };

            TgFREE_POOL( psAR->m_puiStart );
        };

        psAR->m_puiEnd = puiNewData;
        psAR->m_puiLast = puiNewData;
        psAR->m_puiStart = puiNewStart;
    }
    else
    {
        TgSIZE                              uiTailSize;
        P_TgUINT08                          puiSrcData;
        P_TgUINT08                          puiDataAtIndex;

        puiDataAtIndex = psAR->m_puiStart + uiIndex*psAR->m_uiStride;
        uiTailSize = (TgSIZE)(psAR->m_puiLast - puiDataAtIndex);

        if (uiTailSize > uiInsertSize)
        {
            P_TgUINT08                          puiDestData;

            /* Copy [m_puiLast] <= [pLast - InsertSize, pLast) */
            puiSrcData = psAR->m_puiLast - uiInsertSize;
            puiDestData = psAR->m_puiLast;
            if (psAR->m_pInitCopy)
            {
                while (puiSrcData < psAR->m_puiLast)
                {
                    psAR->m_pInitCopy( puiDestData, puiSrcData );
                    puiSrcData += psAR->m_uiStride;
                    puiDestData += psAR->m_uiStride;
                };
            }
            else
            {
                TgMEMCPY( puiDestData, uiFreeSize, puiSrcData, uiInsertSize );
                puiSrcData += uiInsertSize;
                puiDestData += uiInsertSize;
            };

            /* Copy [m_puiLast] <= [puiDataAtIndex, pLast - InsertSize) backwards */
            if (psAR->m_pAssignment)
            {
                puiSrcData = psAR->m_puiLast - uiInsertSize;
                puiDestData = psAR->m_puiLast;

                do
                {
                    puiDestData -= psAR->m_uiStride;
                    puiSrcData -= psAR->m_uiStride;
                    psAR->m_pAssignment( puiDestData, puiSrcData );
                }
                while (puiSrcData > puiDataAtIndex);
            }
            else
            {
                TgMEMMOVE(
                    puiDataAtIndex + uiInsertSize,
                    (TgSIZE)(psAR->m_puiEnd - puiDataAtIndex) - uiInsertSize,
                    puiDataAtIndex,
                    (TgSIZE)(psAR->m_puiLast - puiDataAtIndex) - uiInsertSize );
            };

            /* Copy [puiDataAtIndex] <= [pStart,pLast) into Buffer */
            puiDestData = puiDataAtIndex;
            if (psAR->m_pAssignment)
            {
                P_TgUINT08                          puiInsertStart;

                puiInsertStart = (P_TgUINT08)pInsertStart;
                while (puiInsertStart < (P_TgUINT08)pInsertLast)
                {
                    psAR->m_pAssignment( puiDestData, puiInsertStart );
                    puiDestData += psAR->m_uiStride;
                    puiInsertStart += psAR->m_uiStride;
                };
            }
            else
            {
                TgMEMCPY( puiDestData, uiSize + uiFreeSize - uiInsertSize, pInsertStart, uiInsertSize );
            };

            psAR->m_puiLast += uiInsertSize;
        }
        else
        {
            P_TgUINT08                          puiOldLast;
            P_TgUINT08                          puiInsertStart;
            P_TgUINT08                          puiInsertMid;

            puiOldLast = psAR->m_puiLast;
            puiInsertStart = (P_TgUINT08)pInsertStart;
            puiInsertMid = puiInsertStart + uiTailSize;

            if (psAR->m_pInitCopy)
            {
                P_TgUINT08                          puiInsertData;

                puiInsertData = puiInsertMid;

                while (puiInsertData < (P_TgUINT08)pInsertLast)
                {
                    psAR->m_pInitCopy( psAR->m_puiLast, puiInsertData );
                    psAR->m_puiLast += psAR->m_uiStride;
                    puiInsertData += psAR->m_uiStride;
                };
            }
            else
            {
                TgMEMCPY( psAR->m_puiLast, uiFreeSize, puiInsertMid, (TgSIZE)((P_TgUINT08)pInsertLast - puiInsertMid) );
                psAR->m_puiLast += (P_TgUINT08)pInsertLast - puiInsertMid;
            };

            if (psAR->m_pInitCopy)
            {
                P_TgUINT08                          puiInsertData;

                puiInsertData = puiDataAtIndex;

                while (puiInsertData < puiOldLast)
                {
                    psAR->m_pInitCopy( psAR->m_puiLast, puiInsertData );
                    psAR->m_puiLast += psAR->m_uiStride;
                    puiInsertData += psAR->m_uiStride;
                };
            }
            else
            {
                TgMEMCPY( psAR->m_puiLast, (TgSIZE)(psAR->m_puiEnd - psAR->m_puiLast), puiDataAtIndex, (TgSIZE)(puiOldLast - puiDataAtIndex) );
                psAR->m_puiLast += puiOldLast - puiDataAtIndex;
            };

            if (psAR->m_pAssignment)
            {
                P_TgUINT08                          puiInsertData;
                P_TgUINT08                          puiDestData;

                puiInsertData = puiInsertStart;
                puiDestData = puiDataAtIndex;

                while (puiInsertData < puiInsertMid)
                {
                    psAR->m_pAssignment( puiDestData, puiInsertData );
                    puiDestData += psAR->m_uiStride;
                    puiInsertData += psAR->m_uiStride;
                };
            }
            else
            {
                TgMEMCPY( puiDataAtIndex, (TgSIZE)(psAR->m_puiEnd - puiDataAtIndex), puiInsertStart, (TgSIZE)(puiInsertMid - puiInsertStart) );
            };
        };
    };

    return (KTgS_OK);
}


/* ---- tgCM_UTS_AR_Erase_Range ----------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgCM_UTS_AR_Erase_Range( PCU_STg2_UTS_AR psAR, C_TgSIZE uiStart, C_TgSIZE uiLast )
{
    P_TgUINT08                          puiEraseStart;
    P_TgUINT08                          puiEraseLast;
    P_TgUINT08                          puiErase;
    P_TgUINT08                          puiDataLast;

    puiEraseStart = psAR->m_puiStart + uiStart*psAR->m_uiStride;
    if (nullptr == psAR->m_puiStart || psAR->m_puiLast <= puiEraseStart)
        return;

    puiEraseLast = psAR->m_puiStart + uiLast*psAR->m_uiStride;
    puiEraseLast = psAR->m_puiLast < puiEraseLast ? psAR->m_puiLast : puiEraseLast;
    puiErase = puiEraseStart;
    puiDataLast = psAR->m_puiLast;

    if (psAR->m_pInitCopy)
    {
        P_TgUINT08                          puiData;

        puiData = puiEraseLast;
        for (; puiData < puiDataLast; puiErase += psAR->m_uiStride, puiData += psAR->m_uiStride)
        {
            psAR->m_pInitCopy( puiErase, puiData );
        };
    }
    else if (puiDataLast != puiEraseLast)
    {
        memmove( puiErase, puiEraseLast, (TgSIZE)(puiDataLast - puiEraseLast) );
    };

    if (psAR->m_pFree)
    {
        puiErase = puiEraseStart + (puiDataLast - puiEraseLast);
        for (; puiErase <= puiDataLast; puiErase += psAR->m_uiStride)
        {
            psAR->m_pFree( puiErase );
        };
    };

    psAR->m_puiLast = puiEraseStart + (puiDataLast - puiEraseLast);
}




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  Private Functions                                                                                                                                                     */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

/* ---- tgCM_UTS_AR_Internal_ReAllocate --------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgCM_UTS_AR_Internal_ReAllocate( PCU_STg2_UTS_AR psAR, C_TgSIZE uiCount )
{
    P_TgUINT08                          puiNewData;
    TgSIZE                              nuiElement;
    TgSIZE                              uiLimit;

    puiNewData = (P_TgUINT08)TgMALLOC_POOL( psAR->m_uiStride*uiCount );
    if (nullptr == puiNewData)
        return (KTgE_FAIL);

    nuiElement = tgCM_UTS_AR_Count( psAR );
    if (NULL != psAR->m_puiStart)
    {
        P_TgUINT08                          puiData;

        puiData = (P_TgUINT08)tgCM_UTS_AR_Get_Data( psAR );
        uiLimit = tgCM_MIN_UXX( nuiElement, uiCount );

        if (psAR->m_pInitCopy)
        {
            TgSIZE                              uiIndex;

            for (uiIndex = 0; uiIndex < uiLimit; ++uiIndex)
            {
                psAR->m_pInitCopy( puiNewData + uiIndex*psAR->m_uiStride, puiData + uiIndex*psAR->m_uiStride );
            };
        }
        else
        {
            memcpy( puiNewData, puiData, uiLimit*psAR->m_uiStride );
        }

        if (psAR->m_pFree) /* Free the original buffer */
        {
            TgSIZE                              uiIndex;

            for (uiIndex = 0; uiIndex < nuiElement; ++uiIndex)
            {
                psAR->m_pFree( puiData + uiIndex*psAR->m_uiStride );
            };
        };

        TgFREE_POOL( psAR->m_puiStart );
    };

    psAR->m_puiEnd = puiNewData + uiCount*psAR->m_uiStride;
    psAR->m_puiLast = puiNewData + nuiElement*psAR->m_uiStride;
    psAR->m_puiStart = puiNewData;

    return (KTgS_OK);
}