bool ResourceTable::markPublicImpl(const ResourceNameRef& name, const ResourceId& resId,
                                   const SourceLine& source, const char16_t* validChars) {
    if (!name.package.empty() && name.package != mPackage) {
        Logger::error(source)
                << "resource '"
                << name
                << "' has incompatible package. Must be '"
                << mPackage
                << "'."
            << std::endl;
        return false;
    }

    auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars);
    if (badCharIter != name.entry.end()) {
        Logger::error(source)
                << "resource '"
                << name
                << "' has invalid entry name '"
                << name.entry
                << "'. Invalid character '"
                << StringPiece16(badCharIter, 1)
                << "'."
                << std::endl;
        return false;
    }

    std::unique_ptr<ResourceTableType>& type = findOrCreateType(name.type);
    if (resId.isValid() && type->typeId != ResourceTableType::kUnsetTypeId &&
            type->typeId != resId.typeId()) {
        Logger::error(source)
                << "trying to make resource '"
                << name
                << "' public with ID "
                << resId
                << " but type '"
                << type->type
                << "' already has ID "
                << std::hex << type->typeId << std::dec
                << "."
                << std::endl;
        return false;
    }

    std::unique_ptr<ResourceEntry>& entry = findOrCreateEntry(type, name.entry);
    if (resId.isValid() && entry->entryId != ResourceEntry::kUnsetEntryId &&
            entry->entryId != resId.entryId()) {
        Logger::error(source)
                << "trying to make resource '"
                << name
                << "' public with ID "
                << resId
                << " but resource already has ID "
                << ResourceId(mPackageId, type->typeId, entry->entryId)
                << "."
                << std::endl;
        return false;
    }

    type->publicStatus.isPublic = true;
    entry->publicStatus.isPublic = true;
    entry->publicStatus.source = source;

    if (resId.isValid()) {
        type->typeId = resId.typeId();
        entry->entryId = resId.entryId();
    }
    return true;
}
bool ResourceTable::addResourceImpl(const ResourceNameRef& name, const ResourceId& resId,
                                    const ConfigDescription& config, const SourceLine& source,
                                    std::unique_ptr<Value> value, const char16_t* validChars) {
    if (!name.package.empty() && name.package != mPackage) {
        Logger::error(source)
                << "resource '"
                << name
                << "' has incompatible package. Must be '"
                << mPackage
                << "'."
                << std::endl;
        return false;
    }

    auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars);
    if (badCharIter != name.entry.end()) {
        Logger::error(source)
                << "resource '"
                << name
                << "' has invalid entry name '"
                << name.entry
                << "'. Invalid character '"
                << StringPiece16(badCharIter, 1)
                << "'."
                << std::endl;
        return false;
    }

    std::unique_ptr<ResourceTableType>& type = findOrCreateType(name.type);
    if (resId.isValid() && type->typeId != ResourceTableType::kUnsetTypeId &&
            type->typeId != resId.typeId()) {
        Logger::error(source)
                << "trying to add resource '"
                << name
                << "' with ID "
                << resId
                << " but type '"
                << type->type
                << "' already has ID "
                << std::hex << type->typeId << std::dec
                << "."
                << std::endl;
        return false;
    }

    std::unique_ptr<ResourceEntry>& entry = findOrCreateEntry(type, name.entry);
    if (resId.isValid() && entry->entryId != ResourceEntry::kUnsetEntryId &&
            entry->entryId != resId.entryId()) {
        Logger::error(source)
                << "trying to add resource '"
                << name
                << "' with ID "
                << resId
                << " but resource already has ID "
                << ResourceId(mPackageId, type->typeId, entry->entryId)
                << "."
                << std::endl;
        return false;
    }

    const auto endIter = std::end(entry->values);
    auto iter = std::lower_bound(std::begin(entry->values), endIter, config, compareConfigs);
    if (iter == endIter || iter->config != config) {
        // This resource did not exist before, add it.
        entry->values.insert(iter, ResourceConfigValue{ config, source, {}, std::move(value) });
    } else {
        int collisionResult = defaultCollisionHandler(*iter->value, *value);
        if (collisionResult > 0) {
            // Take the incoming value.
            *iter = ResourceConfigValue{ config, source, {}, std::move(value) };
        } else if (collisionResult == 0) {
            Logger::error(source)
                    << "duplicate value for resource '" << name << "' "
                    << "with config '" << iter->config << "'."
                    << std::endl;

            Logger::error(iter->source)
                    << "resource previously defined here."
                    << std::endl;
            return false;
        }
    }

    if (resId.isValid()) {
        type->typeId = resId.typeId();
        entry->entryId = resId.entryId();
    }
    return true;
}