<commit_before>/*
  tau - http://github.com/cwestin/tau
  Copyright 2013 <NAME>

  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 PXOBJECT_H
#include "pxObject.h"
#endif

#ifndef PX_STDIO_H
#include <stdio.h>
#define PX_STDIO_H
#endif

#ifndef PX_STDLIB_H
#include <stdlib.h>
#define PX_STDLIB_H
#endif

#ifndef PX_STRING_H
#include <string.h>
#define PX_STRING_H
#endif

#ifndef PXALLOC_H
#include "pxAlloc.h"
#endif

#ifndef PXALLOCEXTENT_H
#include "pxAllocExtent.h"
#endif

#ifndef PXALLOCSYSTEM_H
#include "pxAllocSystem.h"
#endif

#ifndef PXCMP_H
#include "pxCmp.h"
#endif

#ifndef PXEXIT_H
#include "pxExit.h"
#endif

#ifndef PXHASH_H
#include "pxHash.h"
#endif

#ifndef PXHM_H
#include "pxHm.h"
#endif


const char pxObjectName[] = "pxObject";

static pxInterface *pxObjectStruct_getInterface(
    const pxObjectStruct *const pObjectStruct, const char *const pName)
{
    // check through interfaces this object implements directly
    const pxObjectInterface *pInterface = pObjectStruct->pObjectVt->pInterface;
    for(int i = pObjectStruct->pObjectVt->nInterface; i; ++pInterface, --i)
    {
        if (pInterface->pName == pName)
        {
            return (pxInterface *)
                (((char *)&pObjectStruct->pObjectVt) -
                 pInterface->interfaceOffset);
        }
    }

    // check on our mixins
    for(const pxObjectStruct *pMixin = pObjectStruct->pMixinList; pMixin;
        pMixin = pMixin->pNextMixin)
    {
        // For this lookup, we use the direct implementation, otherwise
        // the mixin will use the owner pointer, causing infinite recursion
        pxInterface *const pI = pxObjectStruct_getInterface(pMixin, pName);
        if (pI)
            return pI;
    }

    // if we got here, we didn't find it
    return NULL;
}

pxInterface *pxObject_getInterface(pxInterface *pI, const char *const pName)
{
    pxObject *const pObject =
        (pxObject *)(((char *)pI) + pI->pVt->interfaceVt.pxObjectOffset);
    pxObjectStruct *const pObjectStruct =
        PXINTERFACE_STRUCT(pObject, pxObjectStruct, pObjectVt);
    
    // if we have an owner, i.e., are part of an aggregate, delegate to owner
    if (pObjectStruct->pOwner)
    {
        // we can't use the macro here because it relies on symbol manipulation
        return pObjectStruct->pOwner->pObjectVt->interfaceVt.getInterface(
            (pxInterface*)&pObjectStruct->pOwner->pObjectVt, pName);
    }

    // check this object and its mixins
    return pxObjectStruct_getInterface(pObjectStruct, pName);
}

static void pxObject_destroy_mixin(pxObjectStruct *pO)
{
    // recursively destroy mixins on the list from last to first
    if (pO->pNextMixin)
    {
        pxObject_destroy_mixin(pO->pNextMixin);

        // remove them from the list as we go (prevents interface lookups on
        // now-dysfunctional objects)
        pO->pNextMixin = NULL;
    }

    // destroy this mixin itself
    PXOBJECT_destroy((pxObject *)&pO->pObjectVt);
}

void pxObject_destroy(pxObject *pI)
{
    pxObjectStruct *const pThis =
        PXINTERFACE_STRUCT(pI, pxObjectStruct, pObjectVt);

    // mixins have to be destroyed in the reverse order, and need to be kept
    // around until they are destroyed, in case they depend on each other
    if (pThis->pMixinList)
    {
        pxObject_destroy_mixin(pThis->pMixinList);
    }
}


static size_t pxObjectStruct_countMembers(pxObjectStruct *const pO)
{
    size_t n = pO->pObjectVt->nMember;
    if (!n)
        return 0;

    size_t nonNullMembers = 0;
    const char *const p = ((char *)pO) - pO->pObjectVt->objectOffset;
    for(const pxObjectMember *pMember = pO->pObjectVt->pMember; n;
        ++pMember, --n)
    {
        pxInterface *const pI = *(pxInterface **)(p + pMember->memberOffset);
        if (pI)
            ++nonNullMembers;
    }

    return nonNullMembers;
}

static pxObjectStruct *pxObjectCloner_cloneThis(
    pxObjectCloner *pCloner, pxObjectStruct *pO, size_t *pNonNullMembers)
{
    // allocate and copy the object
    void *const pNew = PXALLOC_alloc(
        pCloner->pAlloc, pO->pObjectVt->size, PXALLOC_F_DIRTY);
    memcpy(pNew, ((char *)pO) - pO->pObjectVt->objectOffset,
           pO->pObjectVt->size);

    *pNonNullMembers += pxObjectStruct_countMembers(pO);

    pxObjectStruct *const pNewO =
        (pxObjectStruct *)(((char *)pNew) + pO->pObjectVt->objectOffset);

    // we need to clone mixins first so that any members which point
    // to an interface on a mixin can find that interface
    if (pO->pMixinList)
    {
        // Clone my mixins in the order in which they appear
        //
        // Since we always start with the owner, we know none of these will
        // be in the map. We assume the number of mixins is relatively
        // small so that we don't have to resort to pointer reversal to
        // avoid stack depth issues.
        pxObjectStruct **ppNewMixin = &pNewO->pMixinList;
        for(pxObjectStruct *pMixin = pO->pMixinList; pMixin;
            pMixin = pMixin->pNextMixin)
        {
            pxObjectStruct *const pNewMixin =
                pxObjectCloner_cloneThis(pCloner, pMixin, pNonNullMembers);

            // patch this, since cloneThis uses memcpy on the whole structure
            pNewMixin->pOwner = pNewO;<commit_msg>add some consts<commit_after>/*
  tau - http://github.com/cwestin/tau
  Copyright 2013 <NAME>

  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 PXOBJECT_H
#include "pxObject.h"
#endif

#ifndef PX_STDIO_H
#include <stdio.h>
#define PX_STDIO_H
#endif

#ifndef PX_STDLIB_H
#include <stdlib.h>
#define PX_STDLIB_H
#endif

#ifndef PX_STRING_H
#include <string.h>
#define PX_STRING_H
#endif

#ifndef PXALLOC_H
#include "pxAlloc.h"
#endif

#ifndef PXALLOCEXTENT_H
#include "pxAllocExtent.h"
#endif

#ifndef PXALLOCSYSTEM_H
#include "pxAllocSystem.h"
#endif

#ifndef PXCMP_H
#include "pxCmp.h"
#endif

#ifndef PXEXIT_H
#include "pxExit.h"
#endif

#ifndef PXHASH_H
#include "pxHash.h"
#endif

#ifndef PXHM_H
#include "pxHm.h"
#endif


const char pxObjectName[] = "pxObject";

static pxInterface *pxObjectStruct_getInterface(
    const pxObjectStruct *const pObjectStruct, const char *const pName)
{
    // check through interfaces this object implements directly
    const pxObjectInterface *pInterface = pObjectStruct->pObjectVt->pInterface;
    for(int i = pObjectStruct->pObjectVt->nInterface; i; ++pInterface, --i)
    {
        if (pInterface->pName == pName)
        {
            return (pxInterface *)
                (((char *)&pObjectStruct->pObjectVt) -
                 pInterface->interfaceOffset);
        }
    }

    // check on our mixins
    for(const pxObjectStruct *pMixin = pObjectStruct->pMixinList; pMixin;
        pMixin = pMixin->pNextMixin)
    {
        // For this lookup, we use the direct implementation, otherwise
        // the mixin will use the owner pointer, causing infinite recursion
        pxInterface *const pI = pxObjectStruct_getInterface(pMixin, pName);
        if (pI)
            return pI;
    }

    // if we got here, we didn't find it
    return NULL;
}

pxInterface *pxObject_getInterface(pxInterface *pI, const char *const pName)
{
    pxObject *const pObject =
        (pxObject *)(((char *)pI) + pI->pVt->interfaceVt.pxObjectOffset);
    pxObjectStruct *const pObjectStruct =
        PXINTERFACE_STRUCT(pObject, pxObjectStruct, pObjectVt);
    
    // if we have an owner, i.e., are part of an aggregate, delegate to owner
    if (pObjectStruct->pOwner)
    {
        // we can't use the macro here because it relies on symbol manipulation
        return pObjectStruct->pOwner->pObjectVt->interfaceVt.getInterface(
            (pxInterface*)&pObjectStruct->pOwner->pObjectVt, pName);
    }

    // check this object and its mixins
    return pxObjectStruct_getInterface(pObjectStruct, pName);
}

static void pxObject_destroy_mixin(pxObjectStruct *pO)
{
    // recursively destroy mixins on the list from last to first
    if (pO->pNextMixin)
    {
        pxObject_destroy_mixin(pO->pNextMixin);

        // remove them from the list as we go (prevents interface lookups on
        // now-dysfunctional objects)
        pO->pNextMixin = NULL;
    }

    // destroy this mixin itself
    PXOBJECT_destroy((pxObject *)&pO->pObjectVt);
}

void pxObject_destroy(pxObject *pI)
{
    pxObjectStruct *const pThis =
        PXINTERFACE_STRUCT(pI, pxObjectStruct, pObjectVt);

    // mixins have to be destroyed in the reverse order, and need to be kept
    // around until they are destroyed, in case they depend on each other
    if (pThis->pMixinList)
    {
        pxObject_destroy_mixin(pThis->pMixinList);
    }
}


static size_t pxObjectStruct_countMembers(pxObjectStruct *const pO)
{
    size_t n = pO->pObjectVt->nMember;
    if (!n)
        return 0;

    size_t nonNullMembers = 0;
    const char *const p = ((char *)pO) - pO->pObjectVt->objectOffset;
    for(const pxObjectMember *pMember = pO->pObjectVt->pMember; n;
        ++pMember, --n)
    {
        pxInterface *const pI = *(pxInterface **)(p + pMember->memberOffset);
        if (pI)
            ++nonNullMembers;
    }

    return nonNullMembers;
}

static pxObjectStruct *pxObjectCloner_cloneThis(
    pxObjectCloner *const pCloner, pxObjectStruct *const pO,
    size_t *const pNonNullMembers)
{
    // allocate and copy the object
    void *const pNew = PXALLOC_alloc(
        pCloner->pAlloc, pO->pObjectVt->size, PXALLOC_F_DIRTY);
    memcpy(pNew, ((char *)pO) - pO->pObjectVt->objectOffset,
           pO->pObjectVt->size);

    *pNonNullMembers += pxObjectStruct_countMembers(pO);

    pxObjectStruct *const pNewO =
        (pxObjectStruct *)(((char *)pNew) + pO->pObjectVt->objectOffset);

    // we need to clone mixins first so that any members which point
    // to an interface on a mixin can find that interface
    if (pO->pMixinList)
    {
        // Clone my mixins in the order in which they appear
        //
        // Since we always start with the owner, we know none of these will
        // be in the map. We assume the number of mixins is relatively
        // small so that we don't have to resort to pointer reversal to
        // avoid stack depth issues.
        pxObjectStruct **ppNewMixin = &pNewO->pMixinList;
        for(pxObjectStruct *pMixin = pO->pMixinList; pMixin;
            pMixin = pMixin->pNextMixin)
        {
            pxObjectStruct *const pNewMixin =
                pxObjectCloner_cloneThis(pCloner, pMixin, pNonNullMembers);

            // patch this, since cloneThis uses memcpy on the whole structure
            pNewMixin->pOwner = pNewO;
{'fraction_non_alphanumeric': 0.0939713249265849, 'fraction_numerical': 0.0017274140611504578, 'mean_word_length': 2.9681288553803977, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1413950', 'n_tokens_mistral': 3751, 'n_tokens_neox': 3713, 'n_words': 1102}