Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions backends/native/runtime/graph/Scalar.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.

#include <executorch/backends/native/runtime/graph/Scalar.h>

#include <stdexcept>

#include <executorch/backends/native/runtime/graph/Format.h>

namespace ptn {

int64_t Scalar::to_int() const {
const int64_t* v = std::get_if<int64_t>(&value_);
if (v == nullptr) {
throw std::runtime_error("Scalar::to_int: scalar is not an Int");
}
return *v;
}

double Scalar::to_double() const {
const double* v = std::get_if<double>(&value_);
if (v == nullptr) {
throw std::runtime_error("Scalar::to_double: scalar is not a Double");
}
return *v;
}

bool Scalar::to_bool() const {
const bool* v = std::get_if<bool>(&value_);
if (v == nullptr) {
throw std::runtime_error("Scalar::to_bool: scalar is not a Bool");
}
return *v;
}

const char* Scalar::tag_name() const {
switch (tag()) {
case Tag::Int:
return "Int";
case Tag::Double:
return "Double";
case Tag::Bool:
return "Bool";
}
return "?";
}

std::string Scalar::to_string() const {
if (const bool* b = std::get_if<bool>(&value_)) {
return *b ? "true" : "false";
}
if (is_int()) {
return std::to_string(to_int());
}
return format_double(to_double());
}

} // namespace ptn
74 changes: 74 additions & 0 deletions backends/native/runtime/graph/Scalar.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.

#pragma once

#include <cstdint>
#include <string>
#include <variant>

namespace ptn {

// A concrete scalar value: an int / double / bool. Analogous to c10::Scalar.
// Trivially copyable. There is no "none" state — the graph's Value owns that.
class Scalar {
public:
// Which alternative is live. Pinned to the order of the variant below, so a
// Tag is exactly an index into it.
enum class Tag : int8_t { Int = 0, Double = 1, Bool = 2 };

private:
std::variant<int64_t, double, bool> value_ = int64_t{0};

public:
constexpr Scalar() = default;
// Implicit by design (ergonomic: `Scalar s = 5;`). The int overload
// disambiguates `Scalar(5)` — without it int -> {int64_t,double,bool} is an
// ambiguous conversion. The suppression is scoped to this block so a
// genuinely accidental implicit constructor added later is still reported.
// cppcheck-suppress-begin noExplicitConstructor
/* implicit */ constexpr Scalar(int v) : value_(static_cast<int64_t>(v)) {}
/* implicit */ constexpr Scalar(int64_t v) : value_(v) {}
/* implicit */ constexpr Scalar(double v) : value_(v) {}
/* implicit */ constexpr Scalar(bool v) : value_(v) {}
// cppcheck-suppress-end noExplicitConstructor
// Every pointer converts to bool, so without this `Scalar s = some_ptr;`
// would quietly yield a Bool. Deleted rather than made explicit so the
// implicit numeric constructors above keep their ergonomics.
template <typename T>
Scalar(T*) = delete;

constexpr Tag tag() const {
return static_cast<Tag>(value_.index());
}
constexpr bool is_int() const {
return std::holds_alternative<int64_t>(value_);
}
constexpr bool is_double() const {
return std::holds_alternative<double>(value_);
}
constexpr bool is_bool() const {
return std::holds_alternative<bool>(value_);
}

// Strict accessors: return the live alternative, throw std::runtime_error on
// a tag mismatch.
int64_t to_int() const;
double to_double() const;
bool to_bool() const;

// Promoting read: static_cast the live alternative to T (like
// c10::Scalar::to<T>()); works whichever tag is live.
template <typename T>
constexpr T to() const {
return std::visit([](auto v) { return static_cast<T>(v); }, value_);
}

const char* tag_name() const;
std::string to_string() const;
};

} // namespace ptn
11 changes: 11 additions & 0 deletions backends/native/runtime/graph/targets.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ def define_common_targets():
visibility = ["//executorch/backends/native/..."],
)

# A concrete scalar value (int / double / bool), tagged. c10::Scalar analog.
runtime.cxx_library(
name = "scalar",
srcs = ["Scalar.cpp"],
exported_headers = [
"Scalar.h",
],
deps = [":format"],
visibility = ["//executorch/backends/native/..."],
)

# Concrete in-memory IR value types (pure std; no ExecuTorch, no flatbuffers).
runtime.cxx_library(
name = "tensor_meta",
Expand Down
Loading