source/CanonicalName.h (85 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <string>
#include <variant>
#include <boost/array.hpp>
#include <boost/container_hash/extensions.hpp>
#include <json/json.h>
#include <mariana-trench/Feature.h>
#include <mariana-trench/Method.h>
namespace marianatrench {
/**
* Represents a canonical name format for a crtex leaf frame. The format is
* determined using placeholders and the actual name will be materialized when
* the leaf is propagated.
*
* The templated form supports markers which will be replaced by the actual
* value in the call to `instantiate`.
*/
class CanonicalName final {
private:
// Leaf name marker. Will be replaced by the full signature of `method`
// passed to `instantiate`.
static constexpr std::string_view k_leaf_name_marker =
"%programmatic_leaf_name%";
static constexpr std::string_view k_graphql_root_marker = "%graphql_root%";
// Via-type-of marker. Will be replaced by the feature(s) passed to
// `instantiate`. Currently supports only one feature.
static constexpr std::string_view k_via_type_of_marker = "%via_type_of%";
public:
struct TemplateValue {
std::string value;
bool operator==(const TemplateValue& other) const {
return value == other.value;
}
bool operator!=(const TemplateValue& other) const {
return value != other.value;
}
};
struct InstantiatedValue {
std::string value;
bool operator==(const InstantiatedValue& other) const {
return value == other.value;
}
bool operator!=(const InstantiatedValue& other) const {
return value != other.value;
}
};
public:
explicit CanonicalName(const TemplateValue& template_value)
: value_(template_value) {}
explicit CanonicalName(const InstantiatedValue& instantiated_value)
: value_(instantiated_value) {}
CanonicalName(const CanonicalName&) = default;
CanonicalName(CanonicalName&&) = default;
CanonicalName& operator=(const CanonicalName&) = default;
CanonicalName& operator=(CanonicalName&&) = default;
~CanonicalName() = default;
bool operator==(const CanonicalName& other) const {
return value_ == other.value_;
}
bool operator!=(const CanonicalName& other) const {
return value_ != other.value_;
}
std::optional<std::string> template_value() const {
if (std::holds_alternative<TemplateValue>(value_)) {
return std::get<TemplateValue>(value_).value;
} else {
return std::nullopt;
}
}
std::optional<std::string> instantiated_value() const {
if (std::holds_alternative<InstantiatedValue>(value_)) {
return std::get<InstantiatedValue>(value_).value;
} else {
return std::nullopt;
}
}
bool is_via_type_of_template() const;
/**
* Determines the full form of this canonical name. Creates a `CanonicalName`
* with the instantiated value.
*
* `method` should be the Method that has the templated canonical_name defined
* in its model.
*
* `via_type_ofs` is the features to be used for the "%via_type_of%"
* placeholder. Consider deprecating to enable instantiation during
* model-generation rather than in `Frame::propagate`.
*
* Returns `std::nullopt` if unable to instantiate.
*/
std::optional<CanonicalName> instantiate(
const Method* method,
const std::vector<const Feature*>& via_type_ofs) const;
static CanonicalName from_json(const Json::Value& value);
Json::Value to_json() const;
private:
friend std::ostream& operator<<(std::ostream& out, const CanonicalName& root);
private:
std::variant<TemplateValue, InstantiatedValue> value_;
};
} // namespace marianatrench
template <>
struct std::hash<marianatrench::CanonicalName> {
std::size_t operator()(const marianatrench::CanonicalName& name) const {
std::size_t seed = 0;
boost::hash_combine(seed, name.template_value());
boost::hash_combine(seed, name.instantiated_value());
return seed;
}
};