* Copyright (c) 2021-2022 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 LIBPANDAFILE_PROTO_DATA_ACCESSOR_INL_H
#define LIBPANDAFILE_PROTO_DATA_ACCESSOR_INL_H
#include "helpers.h"
#include "file_items.h"
#include "proto_data_accessor.h"
namespace panda::panda_file {
constexpr size_t SHORTY_ELEM_SIZE = sizeof(uint16_t);
constexpr size_t SHORTY_ELEM_WIDTH = 4;
constexpr size_t SHORTY_ELEM_MASK = 0xf;
constexpr size_t SHORTY_ELEM_PER16 = std::numeric_limits<uint16_t>::digits / SHORTY_ELEM_WIDTH;
inline void ProtoDataAccessor::SkipShorty()
{
EnumerateTypes([](Type ) {});
}
template <class Callback>
inline void ProtoDataAccessor::EnumerateTypes(const Callback &c)
{
auto sp = panda_file_.GetSpanFromId(proto_id_);
uint32_t v = helpers::Read<SHORTY_ELEM_SIZE>(&sp);
uint32_t num_ref = 0;
size_ = SHORTY_ELEM_SIZE;
while (v != 0) {
size_t shift = (elem_num_ % SHORTY_ELEM_PER16) * SHORTY_ELEM_WIDTH;
uint8_t elem = (v >> shift) & SHORTY_ELEM_MASK;
if (elem == 0) {
break;
}
Type t(static_cast<Type::TypeId>(elem));
c(t);
if (!t.IsPrimitive()) {
++num_ref;
}
++elem_num_;
if ((elem_num_ % SHORTY_ELEM_PER16) == 0) {
v = helpers::Read<SHORTY_ELEM_SIZE>(&sp);
size_ += SHORTY_ELEM_SIZE;
}
}
size_ += num_ref * IDX_SIZE;
ref_types_num_ = num_ref;
ref_types_sp_ = sp;
}
inline bool ProtoDataAccessor::IsEqual(ProtoDataAccessor *other)
{
size_t ref_num = 0;
size_t shorty_idx = 0;
auto sp1 = panda_file_.GetSpanFromId(proto_id_);
auto sp2 = other->panda_file_.GetSpanFromId(other->proto_id_);
auto v1 = helpers::Read<SHORTY_ELEM_SIZE>(&sp1);
auto v2 = helpers::Read<SHORTY_ELEM_SIZE>(&sp2);
while (true) {
size_t shift = (shorty_idx % SHORTY_ELEM_PER16) * SHORTY_ELEM_WIDTH;
uint8_t s1 = (v1 >> shift) & SHORTY_ELEM_MASK;
uint8_t s2 = (v2 >> shift) & SHORTY_ELEM_MASK;
if (s1 != s2) {
return false;
}
if (s1 == 0) {
break;
}
panda_file::Type t(static_cast<panda_file::Type::TypeId>(s1));
if (!t.IsPrimitive()) {
++ref_num;
}
if ((++shorty_idx % SHORTY_ELEM_PER16) == 0) {
v1 = helpers::Read<SHORTY_ELEM_SIZE>(&sp1);
v2 = helpers::Read<SHORTY_ELEM_SIZE>(&sp2);
}
}
for (size_t ref_idx = 0; ref_idx < ref_num; ++ref_idx) {
auto id1 = panda_file_.ResolveClassIndex(proto_id_, helpers::Read<IDX_SIZE>(&sp1));
auto id2 = other->panda_file_.ResolveClassIndex(other->proto_id_, helpers::Read<IDX_SIZE>(&sp2));
if (panda_file_.GetStringData(id1) != other->panda_file_.GetStringData(id2)) {
return false;
}
}
return true;
}
inline uint32_t ProtoDataAccessor::GetNumArgs()
{
if (ref_types_sp_.data() == nullptr) {
SkipShorty();
}
return elem_num_ - 1;
}
inline File::EntityId ProtoDataAccessor::GetReferenceType(size_t i)
{
if (ref_types_sp_.data() == nullptr) {
SkipShorty();
}
auto sp = ref_types_sp_.SubSpan(i * IDX_SIZE);
auto class_idx = helpers::Read<IDX_SIZE>(&sp);
return panda_file_.ResolveClassIndex(proto_id_, class_idx);
}
inline Type ProtoDataAccessor::GetType(size_t idx) const
{
size_t block_idx = idx / SHORTY_ELEM_PER16;
size_t elem_shift = (idx % SHORTY_ELEM_PER16) * SHORTY_ELEM_WIDTH;
auto sp = panda_file_.GetSpanFromId(proto_id_);
sp = sp.SubSpan(SHORTY_ELEM_SIZE * block_idx);
uint32_t v = helpers::Read<SHORTY_ELEM_SIZE>(&sp);
return Type(static_cast<Type::TypeId>((v >> elem_shift) & SHORTY_ELEM_MASK));
}
inline Type ProtoDataAccessor::GetReturnType() const
{
return GetType(0);
}
inline Type ProtoDataAccessor::GetArgType(size_t idx) const
{
return GetType(idx + 1);
}
}
#endif