/*

 * Copyright (c) 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.

 */



#include "ecmascript/string/external_string_table.h"



#include "ecmascript/string/external_string.h"





namespace panda::ecmascript {



void ExternalStringTable::AddString(CachedExternalString* string)

{

    std::lock_guard<std::mutex> lock(mutex_);

    externalStringList_.push_back(string);

}



static void SwapBackAndPop(CVector<CachedExternalString*>& vec, CVector<CachedExternalString*>::iterator& iter)

{

    *iter = vec.back();

    if (iter + 1 == vec.end()) {

        vec.pop_back();

        iter = vec.end();

    } else {

        vec.pop_back();

    }

}





static void ShrinkWithFactor(CVector<CachedExternalString*>& vec)

{

    constexpr size_t SHRINK_FACTOR = 2;

    if (vec.size() < vec.capacity() / SHRINK_FACTOR) {

        vec.shrink_to_fit();

    }

}



void ExternalStringTable::ProcessSharedExternalStringDelete(const WeakRootVisitor &visitor)

{

    LOG_GC(DEBUG) << "ExternalStringTable: ProcessSharedExternalStringDelete size=" << externalStringList_.size();

    auto sharedIter = externalStringList_.begin();

    while (sharedIter != externalStringList_.end()) {

        CachedExternalString* object = *sharedIter;

        auto fwd = visitor(reinterpret_cast<TaggedObject*>(object));

        if (fwd == nullptr) {

            ExternalNonMovableStringResource::FreeResource(nullptr,

                object->GetResource(), object->GetCachedResourceData());

            SwapBackAndPop(externalStringList_, sharedIter);

        } else {

            if (fwd != reinterpret_cast<TaggedObject*>(object)) {

                *sharedIter = reinterpret_cast<CachedExternalString*>(fwd);

            }

            ++sharedIter;

        }

    }

    ShrinkWithFactor(externalStringList_);

    LOG_GC(DEBUG) << "ExternalStringTable: ProcessSharedExternalStringDelete size=" << externalStringList_.size();

}



}