diff --git a/backends/native/runtime/graph/Scalar.cpp b/backends/native/runtime/graph/Scalar.cpp new file mode 100644 index 00000000000..daa78254a73 --- /dev/null +++ b/backends/native/runtime/graph/Scalar.cpp @@ -0,0 +1,37 @@ +// 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 + +#include + +namespace ptn { + +int64_t Scalar::to_int() const { + const int64_t* v = std::get_if(&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(&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(&value_); + if (v == nullptr) { + throw std::runtime_error("Scalar::to_bool: scalar is not a Bool"); + } + return *v; +} + +} // namespace ptn diff --git a/backends/native/runtime/graph/Scalar.h b/backends/native/runtime/graph/Scalar.h new file mode 100644 index 00000000000..28502b6e357 --- /dev/null +++ b/backends/native/runtime/graph/Scalar.h @@ -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. + +#pragma once + +#include +#include + +namespace ptn { + +// A concrete scalar value, analogous to c10::Scalar: one alternative per +// domain — integral, floating point, boolean — each stored at its widest type. +// A narrower value is stored exactly, and to() narrows it back on read. +// There is no "none" state — the graph's Value owns that. +class Scalar { + private: + std::variant 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. + // cppcheck-suppress-begin noExplicitConstructor + /* implicit */ constexpr Scalar(int v) : value_(static_cast(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. + template + Scalar(T*) = delete; + + constexpr bool is_int() const { + return std::holds_alternative(value_); + } + constexpr bool is_double() const { + return std::holds_alternative(value_); + } + constexpr bool is_bool() const { + return std::holds_alternative(value_); + } + + // Strict accessors: throw std::runtime_error unless that alternative is live. + int64_t to_int() const; + double to_double() const; + bool to_bool() const; + + // Promoting read: static_cast whichever alternative is live to T, like + // c10::Scalar::to(). + template + constexpr T to() const { + return std::visit([](auto v) { return static_cast(v); }, value_); + } +}; + +} // namespace ptn diff --git a/backends/native/runtime/graph/targets.bzl b/backends/native/runtime/graph/targets.bzl index f145936dbbb..7608bc89553 100644 --- a/backends/native/runtime/graph/targets.bzl +++ b/backends/native/runtime/graph/targets.bzl @@ -17,6 +17,15 @@ def define_common_targets(): visibility = ["//executorch/backends/native/..."], ) + runtime.cxx_library( + name = "scalar", + srcs = ["Scalar.cpp"], + exported_headers = [ + "Scalar.h", + ], + visibility = ["//executorch/backends/native/..."], + ) + runtime.cxx_library( name = "tensor_meta", srcs = ["TensorMeta.cpp"], @@ -39,7 +48,9 @@ def define_common_targets(): "utils/Print.h", ], exported_deps = [ + ":scalar", ":tensor_meta", ], + deps = [":string_format"], visibility = ["//executorch/backends/native/..."], ) diff --git a/backends/native/runtime/graph/utils/Print.cpp b/backends/native/runtime/graph/utils/Print.cpp index 9bc7ce8c486..0e3078d913f 100644 --- a/backends/native/runtime/graph/utils/Print.cpp +++ b/backends/native/runtime/graph/utils/Print.cpp @@ -9,6 +9,8 @@ #include #include +#include + namespace ptn { std::string to_string(const TensorMeta& meta) { @@ -31,4 +33,14 @@ std::string to_string(const TensorMeta& meta) { return s; } +std::string to_string(const Scalar& scalar) { + if (scalar.is_bool()) { + return scalar.to_bool() ? "true" : "false"; + } + if (scalar.is_int()) { + return std::to_string(scalar.to_int()); + } + return format_double(scalar.to_double()); +} + } // namespace ptn diff --git a/backends/native/runtime/graph/utils/Print.h b/backends/native/runtime/graph/utils/Print.h index e9740618acd..4fb3fd566c9 100644 --- a/backends/native/runtime/graph/utils/Print.h +++ b/backends/native/runtime/graph/utils/Print.h @@ -8,6 +8,7 @@ #include +#include #include namespace ptn { @@ -21,4 +22,7 @@ namespace ptn { // (unbounded). std::string to_string(const TensorMeta& meta); +// The live alternative only: "true", "-3", "1.5e-08". +std::string to_string(const Scalar& scalar); + } // namespace ptn