using internal::tflite::operand::CachedData;
+ if (!obj.setAsConstant())
+ {
+ return ANEURALNETWORKS_BAD_DATA;
+ }
obj.data<CachedData>(reinterpret_cast<const uint8_t *>(buffer), length);
return ANEURALNETWORKS_NO_ERROR;
using internal::tflite::operand::ExternalData;
+ if (!obj.setAsConstant())
+ {
+ return ANEURALNETWORKS_BAD_DATA;
+ }
obj.data<ExternalData>(reinterpret_cast<const uint8_t *>(memory->base() + offset), length);
return ANEURALNETWORKS_NO_ERROR;
return ANEURALNETWORKS_BAD_STATE;
}
+ for (uint32_t i = 0; i < outputCount; i++)
+ {
+ // NOTE ::internal::tflite::operand::Index uses int as its underlying type as various NNAPI
+ // functions such as ANeuralNetworksModel_setOperandValue use int to represent operand
+ // index
+ //
+ // ANeuralNetworksModel_identifyInputsAndOutputs, however, uses uint32_t to represent
+ // operand
+ // index.
+ //
+ // Below, static_cast<int>(...) is introduced to eliminate compiler warning.
+ const internal::tflite::operand::Index ind{static_cast<int>(outputs[i])};
+ auto &obj = model->deref().operands().at(ind);
+
+ if (!obj.setAsOperationOutput())
+ {
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+
switch (type)
{
case ANEURALNETWORKS_CONV_2D:
return ANEURALNETWORKS_BAD_STATE;
}
+ for (uint32_t i = 0; i < outputCount; i++)
+ {
+ // NOTE ::internal::tflite::operand::Index uses int as its underlying type as various NNAPI
+ // functions such as ANeuralNetworksModel_setOperandValue use int to represent operand
+ // index
+ //
+ // ANeuralNetworksModel_identifyInputsAndOutputs, however, uses uint32_t to represent
+ // operand
+ // index.
+ //
+ // Below, static_cast<int>(...) is introduced to eliminate compiler warning.
+ const internal::tflite::operand::Index ind{static_cast<int>(outputs[i])};
+ auto &obj = model->deref().operands().at(ind);
+
+ if (!obj.setAsOperationOutput())
+ {
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+
switch (type)
{
default:
{
const ::internal::tflite::operand::Index ind{static_cast<int>(inputs[n])};
model->deref().inputs.emplace_back(ind);
+
+ auto &obj = model->deref().operands().at(ind);
+ if (!obj.setAsModelInput())
+ {
+ return ANEURALNETWORKS_BAD_DATA;
+ }
}
for (uint32_t n = 0; n < outputCount; ++n)
{
const ::internal::tflite::operand::Index ind{static_cast<int>(outputs[n])};
model->deref().outputs.emplace_back(ind);
+
+ auto &obj = model->deref().operands().at(ind);
+ // Model output cannot become model input
+ if (obj.isModelInput())
+ {
+ return ANEURALNETWORKS_BAD_DATA;
+ }
}
return ANEURALNETWORKS_NO_ERROR;
namespace operand
{
+// Operand usage should be exact one of these
+enum class OperandUsage
+{
+ NOT_DEFINED,
+ MODEL_INPUT,
+ CONSTANT,
+ OPERATION_OUTPUT,
+};
+
class Object
{
public:
- explicit Object(const Shape &shape) : _shape{shape}
+ explicit Object(const Shape &shape) : _shape{shape}, _usage{OperandUsage::NOT_DEFINED}
{
// DO NOTHING
}
public:
const Shape &shape(void) const { return _shape; }
+ bool setAsConstant() { return setUsage(OperandUsage::CONSTANT); }
+ bool setAsModelInput() { return setUsage(OperandUsage::MODEL_INPUT); }
+ bool setAsOperationOutput() { return setUsage(OperandUsage::OPERATION_OUTPUT); }
+ bool usageIsDefined(void) const { return _usage != OperandUsage::NOT_DEFINED; }
+ bool isModelInput(void) const { return _usage == OperandUsage::MODEL_INPUT; }
private:
void data(std::unique_ptr<Data> &&data) { _data = std::move(data); }
+ bool setUsage(OperandUsage usage);
public:
const Data &data(void) const { return *_data; }
private:
const Shape _shape;
std::unique_ptr<Data> _data;
+ OperandUsage _usage;
};
} // namespace operand