/*
 * Copyright (c) 2021 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/regexp/regexp_parser_cache.h"
#include "ecmascript/string/line_string-inl.h"

namespace panda::ecmascript {
RegExpParserCache::RegExpParserCache()
{
    Clear();
}

RegExpParserCache::~RegExpParserCache()
{
    Clear();
}

void RegExpParserCache::Clear()
{
    for (ParserKey &info : info_) {
        info.pattern_ = nullptr;
        info.flags_ = UINT32_MAX; // flags cannot be UINT32_MAX, so it means invalid.
        info.codeBuffer_ = JSTaggedValue::Hole();
        info.bufferSize_ = 0;
    }
}

size_t RegExpParserCache::GetHash(const JSThread *thread, EcmaString *pattern, const uint32_t flags)
{
    auto hashcode = EcmaStringAccessor(pattern).GetHashcode(thread);
    return (hashcode ^ flags) % CACHE_SIZE;
}

std::pair<JSTaggedValue, size_t> RegExpParserCache::GetCache(const JSThread *thread,
                                                             EcmaString *pattern, const uint32_t flags,
                                                             CVector<CString> &groupName)
{
    size_t hash = GetHash(thread, pattern, flags);
    ParserKey &info = info_[hash];
    if (info.flags_ != flags || info.pattern_ == nullptr ||
        !EcmaStringAccessor::StringsAreEqual(thread, info.pattern_, pattern)) {
        return std::pair<JSTaggedValue, size_t>(JSTaggedValue::Hole(), 0);
    }
    groupName = info.newGroupNames_;
    return std::pair<JSTaggedValue, size_t>(info.codeBuffer_, info.bufferSize_);
}

void RegExpParserCache::SetCache(const JSThread *thread,
                                 EcmaString *pattern, const uint32_t flags,
                                 const JSTaggedValue codeBuffer, const size_t bufferSize,
                                 CVector<CString> groupName)
{
    size_t hash = GetHash(thread, pattern, flags);
    ParserKey &info = info_[hash];
    info.pattern_ = pattern;
    info.flags_ = flags;
    info.codeBuffer_ = codeBuffer;
    info.bufferSize_ = bufferSize;
    info.newGroupNames_ = groupName;
}
}  // namespace panda::ecmascript