/* * Copyright (C) 2018 The Android Open Source Project * * 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 "utils/flatbuffers/reflection.h" namespace libtextclassifier3 { const reflection::Field* GetFieldOrNull(const reflection::Object* type, const StringPiece field_name) { TC3_CHECK(type != nullptr && type->fields() != nullptr); return type->fields()->LookupByKey(field_name.data()); } const reflection::Field* GetFieldOrNull(const reflection::Object* type, const int field_offset) { if (type->fields() == nullptr) { return nullptr; } for (const reflection::Field* field : *type->fields()) { if (field->offset() == field_offset) { return field; } } return nullptr; } const reflection::Field* GetFieldOrNull(const reflection::Object* type, const StringPiece field_name, const int field_offset) { // Lookup by name might be faster as the fields are sorted by name in the // schema data, so try that first. if (!field_name.empty()) { return GetFieldOrNull(type, field_name.data()); } return GetFieldOrNull(type, field_offset); } const reflection::Field* GetFieldOrNull(const reflection::Object* type, const FlatbufferField* field) { TC3_CHECK(type != nullptr && field != nullptr); if (field->field_name() == nullptr) { return GetFieldOrNull(type, field->field_offset()); } return GetFieldOrNull( type, StringPiece(field->field_name()->data(), field->field_name()->size()), field->field_offset()); } const reflection::Field* GetFieldOrNull(const reflection::Object* type, const FlatbufferFieldT* field) { TC3_CHECK(type != nullptr && field != nullptr); return GetFieldOrNull(type, field->field_name, field->field_offset); } const reflection::Object* TypeForName(const reflection::Schema* schema, const StringPiece type_name) { for (const reflection::Object* object : *schema->objects()) { if (type_name.Equals(object->name()->str())) { return object; } } return nullptr; } Optional TypeIdForObject(const reflection::Schema* schema, const reflection::Object* type) { for (int i = 0; i < schema->objects()->size(); i++) { if (schema->objects()->Get(i) == type) { return Optional(i); } } return Optional(); } Optional TypeIdForName(const reflection::Schema* schema, const StringPiece type_name) { for (int i = 0; i < schema->objects()->size(); i++) { if (type_name.Equals(schema->objects()->Get(i)->name()->str())) { return Optional(i); } } return Optional(); } bool SwapFieldNamesForOffsetsInPath(const reflection::Schema* schema, FlatbufferFieldPathT* path) { if (schema == nullptr || !schema->root_table()) { TC3_LOG(ERROR) << "Empty schema provided."; return false; } reflection::Object const* type = schema->root_table(); for (int i = 0; i < path->field.size(); i++) { const reflection::Field* field = GetFieldOrNull(type, path->field[i].get()); if (field == nullptr) { TC3_LOG(ERROR) << "Could not find field: " << path->field[i]->field_name; return false; } path->field[i]->field_name.clear(); path->field[i]->field_offset = field->offset(); // Descend. if (i < path->field.size() - 1) { if (field->type()->base_type() != reflection::Obj) { TC3_LOG(ERROR) << "Field: " << field->name()->str() << " is not of type `Object`."; return false; } type = schema->objects()->Get(field->type()->index()); } } return true; } Variant ParseEnumValue(const reflection::Schema* schema, const reflection::Type* type, StringPiece value) { TC3_DCHECK(IsEnum(type)); TC3_CHECK_NE(schema->enums(), nullptr); const auto* enum_values = schema->enums()->Get(type->index())->values(); if (enum_values == nullptr) { TC3_LOG(ERROR) << "Enum has no specified values."; return Variant(); } for (const reflection::EnumVal* enum_value : *enum_values) { if (value.Equals(StringPiece(enum_value->name()->c_str(), enum_value->name()->size()))) { const int64 value = enum_value->value(); switch (type->base_type()) { case reflection::BaseType::Byte: return Variant(static_cast(value)); case reflection::BaseType::UByte: return Variant(static_cast(value)); case reflection::BaseType::Short: return Variant(static_cast(value)); case reflection::BaseType::UShort: return Variant(static_cast(value)); case reflection::BaseType::Int: return Variant(static_cast(value)); case reflection::BaseType::UInt: return Variant(static_cast(value)); case reflection::BaseType::Long: return Variant(value); case reflection::BaseType::ULong: return Variant(static_cast(value)); default: break; } } } return Variant(); } } // namespace libtextclassifier3