Skip to content
Merged
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
15 changes: 9 additions & 6 deletions packages/react-native-executorch/cpp/core/conversions.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ std::vector<T> fromJsiTypedArray(jsi::Runtime &rt, const std::string &ctx, const
const size_t byteLength = getOptionalProperty<uint64_t>(rt, ctx, obj, "byteLength").value_or(buffer.size(rt));

if (byteOffset > buffer.size(rt) || byteLength > buffer.size(rt) - byteOffset) {
throw jsi::JSError(rt, ctx + " has out-of-bounds byteOffset/byteLength for its ArrayBuffer");
throw jsi::JSError(rt, std::format("{}: out-of-bounds byteOffset ({}) or byteLength ({}) for ArrayBuffer of size {}",
ctx, byteOffset, byteLength, buffer.size(rt)));
}
if (byteLength % sizeof(T) != 0) {
throw jsi::JSError(rt, std::format("{}: byteLength is not a multiple of sizeof(T)={}", ctx, sizeof(T)));
Expand All @@ -149,6 +150,9 @@ std::vector<T> fromJsiTypedArray(jsi::Runtime &rt, const std::string &ctx, const
return vec;
}

template <typename>
inline constexpr bool kAlwaysFalse = false;

/**
* Converts a std::vector of values to a new facebook::jsi::Array.
* Handles strings, booleans, and numeric types appropriately.
Expand All @@ -165,17 +169,16 @@ jsi::Array toJsiArray(jsi::Runtime &rt, const std::vector<T> &vec) {
if constexpr (std::is_same_v<T, std::string>) {
arr.setValueAtIndex(rt, i, jsi::String::createFromUtf8(rt, vec[i]));
} else if constexpr (std::is_same_v<T, bool>) {
arr.setValueAtIndex(rt, i, jsi::Value(vec[i]));
} else {
arr.setValueAtIndex(rt, i, jsi::Value(static_cast<bool>(vec[i])));
} else if constexpr (std::is_arithmetic_v<T>) {
arr.setValueAtIndex(rt, i, jsi::Value(static_cast<double>(vec[i])));
} else {
static_assert(kAlwaysFalse<T>, "Unsupported vector element type for toJsiArray");
}
}
return arr;
}

template <typename>
inline constexpr bool kAlwaysFalse = false;

/**
* Maps an arithmetic C++ type to the name of the JS TypedArray constructor whose
* elements have the same layout (e.g. int32_t -> "Int32Array"). 64-bit integers
Expand Down
16 changes: 11 additions & 5 deletions packages/react-native-executorch/cpp/core/tensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,24 @@ jsi::Value TensorHostObject::get(jsi::Runtime &rt, const jsi::PropNameID &name)
if (count == 2) {
optsObj = conversions::asType<jsi::Object>(rt, "copyTo: options", args[1]);
}

size_t offset = getOptionalProperty<uint64_t>(rt, "copyTo: options", optsObj, "offset").value_or(0);
if (offset > self->numel_) {
throw jsi::JSError(rt, "copyTo: offset is out of bounds for src tensor");
throw jsi::JSError(rt, std::format("copyTo: offset {} is out of bounds for src tensor of size {} elements",
offset, self->numel_));
}

size_t length = getOptionalProperty<uint64_t>(rt, "copyTo: options", optsObj, "length").value_or(self->numel_ - offset);
if (length > self->numel_ - offset) {
throw jsi::JSError(rt, "copyTo: length is out of bounds for the given offset of the src tensor");
throw jsi::JSError(rt, std::format("copyTo: length {} is out of bounds for offset {} of src tensor (numel {})",
length, offset, self->numel_));
}

const auto elemSize = types::elementSize(self->dtype_);

if (length * elemSize != dst->size_) {
throw jsi::JSError(rt, "copyTo: size mismatch between copy byte size and dst tensor size");
throw jsi::JSError(rt, std::format("copyTo: size mismatch between copy size ({} bytes) and dst tensor size ({} bytes)",
length * elemSize, dst->size_));
}

std::memcpy(dst->data_.get(), self->data_.get() + (offset * elemSize), length * elemSize);
Expand All @@ -102,7 +106,8 @@ jsi::Value TensorHostObject::get(jsi::Runtime &rt, const jsi::PropNameID &name)
auto lock = tryLockUnique(rt, "setData: self", self);

if (byteOffset > buffer.size(rt) || byteLength > buffer.size(rt) - byteOffset) {
throw jsi::JSError(rt, "setData: Out of bounds offset/length for buffer");
throw jsi::JSError(rt, std::format("setData: Out of bounds offset ({}) or length ({}) for buffer of size {}",
byteOffset, byteLength, buffer.size(rt)));
}

if (byteLength != self->size_) {
Expand Down Expand Up @@ -132,7 +137,8 @@ jsi::Value TensorHostObject::get(jsi::Runtime &rt, const jsi::PropNameID &name)
auto lock = tryLockShared(rt, "getData: self", self);

if (byteOffset > buffer.size(rt) || byteLength > buffer.size(rt) - byteOffset) {
throw jsi::JSError(rt, "getData: Out of bounds offset/length for buffer");
throw jsi::JSError(rt, std::format("getData: Out of bounds offset ({}) or length ({}) for buffer of size {}",
byteOffset, byteLength, buffer.size(rt)));
}

if (byteLength != self->size_) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ BoxFormat parseBoxFormat(const std::string &s) {
if (s == "cxcywh") {
return BoxFormat::CXCYWH;
}
throw std::invalid_argument("unsupported boxFormat '" + s + "'");
throw std::invalid_argument(std::format("unsupported boxFormat '{}'. Expected 'xyxy', 'xywh', or 'cxcywh'", s));
}

enum class NmsType {
Expand All @@ -59,7 +59,7 @@ NmsType parseNmsType(const std::string &s) {
if (s == "weighted") {
return NmsType::Weighted;
}
throw std::invalid_argument("unsupported nmsType '" + s + "'");
throw std::invalid_argument(std::format("unsupported nmsType '{}'. Expected 'standard' or 'weighted'", s));
}

constexpr size_t kBoxCoords = 4;
Expand Down Expand Up @@ -223,7 +223,8 @@ void install_restrictToBox(jsi::Runtime &rt, jsi::Object &module) {

auto boxVec = conversions::asVector<float>(rt, "restrictToBox: boxTuple", args[2]);
if (boxVec.size() != kBoxCoords) {
throw jsi::JSError(rt, "restrictToBox: boxTuple must contain exactly 4 coordinates");
throw jsi::JSError(rt, std::format("restrictToBox: boxTuple must contain exactly 4 coordinates (got {})",
boxVec.size()));
}

auto boxFormatStr = conversions::asType<std::string>(rt, "restrictToBox: format", args[3]);
Expand Down
11 changes: 8 additions & 3 deletions packages/react-native-executorch/cpp/extensions/cv/image_ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ int interpToFlag(const std::string &interp) {
if (interp == "lanczos") {
return ::cv::INTER_LANCZOS4;
}
throw std::invalid_argument("unsupported interpolation '" + interp + "'");
throw std::invalid_argument(std::format("unsupported interpolation '{}'. Expected"
" 'nearest', 'area', 'linear', 'cubic', or 'lanczos'",
interp));
}

struct FitBox {
Expand Down Expand Up @@ -189,7 +191,9 @@ int codeToColorConversionFlag(const std::string &code) {
if (code == "GRAY2BGRA") {
return ::cv::COLOR_GRAY2BGRA;
}
throw std::invalid_argument("cvtColor: unsupported color conversion code '" + code + "'");
throw std::invalid_argument(std::format("cvtColor: unsupported color conversion code '{}'."
" Common values are 'RGB2BGR', 'BGR2RGB', 'RGBA2RGB', 'RGB2GRAY', etc.",
code));
}
} // namespace

Expand Down Expand Up @@ -414,7 +418,8 @@ void install_applyColormap(jsi::Runtime &rt, jsi::Object &module) {
for (size_t i = 0; i < numColors; ++i) {
auto colorVec = conversions::asVector<uint8_t>(rt, "applyColormap: colormap entry", colormapArray.getValueAtIndex(rt, i));
if (colorVec.size() != numRgbaChannels) {
throw jsi::JSError(rt, "applyColormap: colormap entry must be an RGBA color array of size 4");
throw jsi::JSError(rt, std::format("applyColormap: colormap entry must be an RGBA color array of size 4 (got size {})",
colorVec.size()));
}
for (size_t c = 0; c < numRgbaChannels; ++c) {
lut[i][c] = colorVec[c];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ void install_softmax(jsi::Runtime &rt, jsi::Object &module) {
axis += rank;
}
if (axis < 0 || axis >= rank) {
throw jsi::JSError(rt, "softmax: axis is out of range");
throw jsi::JSError(rt, std::format("softmax: axis {} out of range for tensor of rank {}",
axis, rank));
}
const auto axisIdx = static_cast<size_t>(axis);

Expand Down Expand Up @@ -152,7 +153,8 @@ void install_argmax(jsi::Runtime &rt, jsi::Object &module) {
axis += rank;
}
if (axis < 0 || axis >= rank) {
throw jsi::JSError(rt, "argmax: axis is out of range");
throw jsi::JSError(rt, std::format("argmax: axis {} out of range for tensor of rank {}",
axis, rank));
}
const auto axisIdx = static_cast<size_t>(axis);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ TokenizerHostObject::TokenizerHostObject(std::string tokenizerPath)
tokenizer_(std::make_unique<tokenizers::HFTokenizer>()) {
auto error = tokenizer_->load(tokenizerPath_);
if (error != tokenizers::Error::Ok) {
throw std::runtime_error("Failed to load tokenizer from '" + tokenizerPath_ +
"': " + toString(error));
throw std::runtime_error(std::format("Failed to load tokenizer from '{}': {}",
tokenizerPath_, toString(error)));
}
}

std::unique_lock<std::mutex> TokenizerHostObject::tryLockUnique(jsi::Runtime &rt,
std::string_view context) {
std::string_view context) {
std::unique_lock<std::mutex> lock(mutex_, std::try_to_lock);
if (!lock.owns_lock()) {
throw jsi::JSError(rt, std::format("{} is currently in use", context));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <format>
#include <span>

#include "core/tensor.h"
Expand Down Expand Up @@ -41,16 +42,20 @@ void install_extractFrames(jsi::Runtime &rt, jsi::Object &module) {
const auto chunkFrames = static_cast<uint64_t>(dst->shape_[0]);
const auto fftLength = static_cast<uint64_t>(dst->shape_[1]);
if (frameLength > fftLength) {
throw jsi::JSError(rt, "extractFrames: hann length exceeds dst fftLength");
throw jsi::JSError(rt, std::format("extractFrames: hann length ({}) exceeds dst fftLength ({})",
frameLength, fftLength));
}
if (numFrames > chunkFrames) {
throw jsi::JSError(rt, "extractFrames: numFrames out of dst frame capacity");
throw jsi::JSError(rt, std::format("extractFrames: numFrames ({}) exceeds dst frame capacity ({})",
numFrames, chunkFrames));
}

if (numFrames > 0) {
const uint64_t lastSample = (numFrames - 1) * hopLength + frameLength - 1;
if (lastSample >= waveform->numel_) {
throw jsi::JSError(rt, "extractFrames: frame window out of waveform bounds");
throw jsi::JSError(rt, std::format("extractFrames: frame window (last sample index {})"
" exceeds waveform bounds (numel {})",
lastSample, waveform->numel_));
}
}

Expand Down