blob: fe21ba01ddfef63bd895e780d77e48b444745750 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "peridot/bin/context_engine/index.h"
#include <algorithm>
#include <sstream>
#include <lib/fidl/cpp/clone.h>
#include <lib/fidl/cpp/optional.h>
#include <src/lib/fxl/logging.h>
namespace modular {
ContextIndex::ContextIndex() = default;
ContextIndex::~ContextIndex() = default;
namespace internal {
// Keys for fields within fuchsia::modular::ContextMetadata.story:
const char kStoryIdKey[] = "si";
const char kStoryFocusedKey[] = "sf";
// Keys for fields within fuchsia::modular::ContextMetadata.mod:
const char kModPathKey[] = "mp";
const char kModUrlKey[] = "mu";
const char kModuleFocusedKey[] = "mf";
// Keys for fields within fuchsia::modular::ContextMetadata.entity:
const char kEntityTopicKey[] = "et";
const char kEntityTypeKey[] = "ey";
// We don't index |ctime|.
// Key for fuchsia::modular::ContextValueType.
const char kContextValueTypeKey[] = "t";
std::set<std::string> EncodeMetadataAndType(
fuchsia::modular::ContextValueType node_type,
const fuchsia::modular::ContextMetadata& metadata) {
fuchsia::modular::ContextMetadata meta_clone;
fidl::Clone(metadata, &meta_clone);
return EncodeMetadataAndType(node_type,
fidl::MakeOptional(std::move(meta_clone)));
}
std::string EncodeFocus(const std::string& key,
fuchsia::modular::FocusedStateState focused_state) {
std::ostringstream str;
str << key;
if (focused_state == fuchsia::modular::FocusedStateState::FOCUSED) {
str << "1";
} else {
str << "0";
}
return str.str();
}
std::set<std::string> EncodeMetadataAndType(
fuchsia::modular::ContextValueType node_type,
const fuchsia::modular::ContextMetadataPtr& metadata) {
std::set<std::string> ret;
if (metadata) {
if (metadata->story) {
if (metadata->story->id) {
std::ostringstream str;
str << kStoryIdKey << metadata->story->id;
ret.insert(str.str());
}
if (metadata->story->focused) {
ret.insert(
EncodeFocus(kStoryFocusedKey, metadata->story->focused->state));
}
}
if (metadata->mod) {
if (metadata->mod->url) {
std::ostringstream str;
str << kModUrlKey << metadata->mod->url;
ret.insert(str.str());
}
if (metadata->mod->path) {
std::ostringstream str;
str << kModPathKey;
for (const auto& part : *metadata->mod->path) {
str << '\0' << part;
}
ret.insert(str.str());
}
if (metadata->mod->focused) {
ret.insert(
EncodeFocus(kModuleFocusedKey, metadata->mod->focused->state));
}
}
if (metadata->entity) {
if (metadata->entity->topic) {
std::ostringstream str;
str << kEntityTopicKey << metadata->entity->topic;
ret.insert(str.str());
}
if (metadata->entity->type) {
for (const auto& type : *metadata->entity->type) {
std::ostringstream str;
str << kEntityTypeKey << type;
ret.insert(str.str());
}
}
}
}
std::ostringstream str;
str << kContextValueTypeKey << fidl::ToUnderlying(node_type);
ret.insert(str.str());
return ret;
}
} // namespace internal
void ContextIndex::Add(Id id, fuchsia::modular::ContextValueType type,
const fuchsia::modular::ContextMetadata& metadata) {
auto keys = internal::EncodeMetadataAndType(type, metadata);
for (const auto& key : keys) {
index_[key].insert(id);
}
}
void ContextIndex::Remove(Id id, fuchsia::modular::ContextValueType type,
const fuchsia::modular::ContextMetadata& metadata) {
auto keys = internal::EncodeMetadataAndType(type, metadata);
for (const auto& key : keys) {
index_[key].erase(id);
}
}
void ContextIndex::Query(fuchsia::modular::ContextValueType type,
const fuchsia::modular::ContextMetadataPtr& metadata,
std::set<ContextIndex::Id>* out) {
FXL_DCHECK(out != nullptr);
auto keys = internal::EncodeMetadataAndType(type, metadata);
std::set<ContextIndex::Id> ret;
if (keys.empty())
return;
const auto& first = index_[*keys.begin()];
ret.insert(first.begin(), first.end());
keys.erase(keys.begin());
for (const auto& key : keys) {
std::set<ContextIndex::Id> intersection;
const auto& posting_list = index_[key];
std::set_intersection(ret.begin(), ret.end(), posting_list.begin(),
posting_list.end(),
std::inserter(intersection, intersection.begin()));
ret.swap(intersection);
}
out->insert(ret.begin(), ret.end());
}
} // namespace modular