chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,873 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
// @author AbdelRauf
|
||||
|
||||
#include <array/ShapeDescriptor.h>
|
||||
#include <helpers/ShapeBuilders.h>
|
||||
#include <helpers/shape.h>
|
||||
#include <helpers/ModularHasher.h>
|
||||
#include "helpers/ShapeUtils.h"
|
||||
|
||||
namespace sd {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// equal to operator
|
||||
bool ShapeDescriptor::operator==(const ShapeDescriptor& other) const {
|
||||
// First check scalar values to fail fast
|
||||
if (_rank != other._rank ||
|
||||
_dataType != other._dataType ||
|
||||
_order != other._order ||
|
||||
_extraProperties != other._extraProperties ||
|
||||
_offset != other._offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle null pointers
|
||||
if (_shape_strides == nullptr && other._shape_strides == nullptr) {
|
||||
return true;
|
||||
}
|
||||
if (_shape_strides == nullptr || other._shape_strides == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare shape and strides
|
||||
const int total_length = (_rank < 1 ? 1 : _rank) * 2;
|
||||
return memcmp(_shape_strides, other._shape_strides, total_length * sizeof(LongType)) == 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// less than operator
|
||||
bool ShapeDescriptor::operator<(const ShapeDescriptor &other) const {
|
||||
return std::tie(_extraProperties, _rank, _dataType, _order, _shape_strides) <
|
||||
std::tie(other._extraProperties, other._rank, other._dataType, other._order, other._shape_strides);
|
||||
}
|
||||
|
||||
LongType *ShapeDescriptor::toShapeInfo() const {
|
||||
// for empty array use original
|
||||
return ShapeBuilders::createShapeInfoFrom(const_cast<ShapeDescriptor *>(this));
|
||||
}
|
||||
|
||||
ShapeDescriptor::~ShapeDescriptor() {
|
||||
// no-op
|
||||
if(_shape_strides != nullptr && this->ownsShapeStrides) {
|
||||
delete[] _shape_strides;
|
||||
_shape_strides = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LongType ShapeDescriptor::offset() {
|
||||
return _offset;
|
||||
}
|
||||
|
||||
ShapeDescriptor::ShapeDescriptor(const DataType type, const char order, const LongType *shape, const LongType rank)
|
||||
: _rank(rank), _order(order), _dataType(type) {
|
||||
int rank2 = rank < 1 ? 1 : rank;
|
||||
_shape_strides = new LongType[2 * rank2];
|
||||
this->ownsShapeStrides = true;
|
||||
if(order != 'c' && order != 'f') {
|
||||
std::string errorMessage;
|
||||
errorMessage += "Invalid ordering from shape buffer";
|
||||
errorMessage += std::to_string(order);
|
||||
delete[] _shape_strides;
|
||||
THROW_EXCEPTION(errorMessage.c_str());
|
||||
|
||||
}
|
||||
if(!DataTypeUtils::validDataType(_dataType)) {
|
||||
delete[] _shape_strides;
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
}
|
||||
auto _shape = _shape_strides;
|
||||
for (int i = 0; i < rank2; i++) {
|
||||
_shape[i] = shape[i];
|
||||
}
|
||||
|
||||
_extraProperties = ArrayOptions::flagForDataType(type);
|
||||
|
||||
fillStrides();
|
||||
|
||||
#if defined(SD_GCC_FUNCTRACE)
|
||||
// - backward-cpp's backtrace() is NOT safe during very early JVM initialization
|
||||
#ifdef __cpp_exceptions
|
||||
try {
|
||||
this->st.load_here();
|
||||
} catch (...) {
|
||||
// Stack trace capture failed - st will remain empty (size() == 0)
|
||||
}
|
||||
#else
|
||||
this->st.load_here();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
ShapeDescriptor::ShapeDescriptor(const DataType type, const char order, const LongType *shape,
|
||||
const LongType *strides, const LongType rank, LongType extras = -1) {
|
||||
if(shape == nullptr)
|
||||
THROW_EXCEPTION("ShapeDescriptor constructor: Shape can not be null!");
|
||||
_shape_strides = nullptr;
|
||||
ownsShapeStrides = false;
|
||||
if(type == UNKNOWN)
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
ownsShapeStrides = true;
|
||||
//note this used to operate directly on the vector buffer
|
||||
//it now does manual copies with more checks.
|
||||
//this is to handle the 0 length case.
|
||||
if(rank < 1) {
|
||||
_shape_strides = new LongType[2 * rank];
|
||||
_dataType = type;
|
||||
_order = order;
|
||||
_rank = rank;
|
||||
_extraProperties = extras;
|
||||
} else {
|
||||
_shape_strides = new LongType [2 * rank];
|
||||
_dataType = type;
|
||||
_order = order;
|
||||
_rank = rank;
|
||||
_extraProperties = extras;
|
||||
auto _shape = _shape_strides;
|
||||
auto _strides = _shape_strides + rank;
|
||||
for (int e = 0; e < rank; e++) {
|
||||
_shape[e] = shape[e];
|
||||
if(rank > 1 && shape[e] == 0 && !ArrayOptions::hasPropertyBitSet(_extraProperties, ARRAY_EMPTY)) {
|
||||
_extraProperties = ArrayOptions::setPropertyBitForFlagsValue(_extraProperties, ARRAY_EMPTY);
|
||||
}
|
||||
if(strides != nullptr)
|
||||
_strides[e] = strides[e];
|
||||
}
|
||||
|
||||
if(strides == nullptr)
|
||||
fillStrides();
|
||||
}
|
||||
|
||||
if(!DataTypeUtils::validDataType(_dataType)) {
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
}
|
||||
|
||||
#if defined(SD_GCC_FUNCTRACE)
|
||||
// - backward-cpp's backtrace() is NOT safe during very early JVM initialization
|
||||
#ifdef __cpp_exceptions
|
||||
try {
|
||||
this->st.load_here();
|
||||
} catch (...) {
|
||||
// Stack trace capture failed - st will remain empty (size() == 0)
|
||||
}
|
||||
#else
|
||||
this->st.load_here();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
ShapeDescriptor::ShapeDescriptor(const DataType type, const char order, const std::vector<LongType> &shape)
|
||||
: _order(order), _dataType(type) {
|
||||
if(!DataTypeUtils::validDataType(_dataType)) {
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
}
|
||||
_rank = shape.size();
|
||||
_extraProperties = ArrayOptions::defaultFlag();
|
||||
_extraProperties = ArrayOptions::setDataTypeValue(_extraProperties, type);
|
||||
int rank2 = shape.size() < 1 ? 1 : shape.size();
|
||||
_shape_strides = new LongType [2 * rank2];
|
||||
this->ownsShapeStrides = true;
|
||||
if(_rank > 0) {
|
||||
auto _shape = _shape_strides;
|
||||
for (int i = 0; i < _rank; i++) {
|
||||
_shape[i] = shape[i];
|
||||
if(shape[i] == 0 && !ArrayOptions::hasPropertyBitSet(_extraProperties, ARRAY_EMPTY)) {
|
||||
_extraProperties = ArrayOptions::setPropertyBitForFlagsValue(_extraProperties, ARRAY_EMPTY);
|
||||
}
|
||||
}
|
||||
fillStrides();
|
||||
}
|
||||
|
||||
_order = order;
|
||||
if(_order != 'c' && _order != 'f') {
|
||||
std::string errorMessage;
|
||||
errorMessage += "Invalid ordering from shape buffer";
|
||||
errorMessage += std::to_string(_order);
|
||||
delete[] _shape_strides;
|
||||
THROW_EXCEPTION(errorMessage.c_str());
|
||||
|
||||
}
|
||||
if(!DataTypeUtils::validDataType(_dataType)) {
|
||||
delete[] _shape_strides;
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
}
|
||||
#if defined(SD_GCC_FUNCTRACE)
|
||||
// - backward-cpp's backtrace() is NOT safe during very early JVM initialization
|
||||
#ifdef __cpp_exceptions
|
||||
try {
|
||||
this->st.load_here();
|
||||
} catch (...) {
|
||||
// Stack trace capture failed - st will remain empty (size() == 0)
|
||||
}
|
||||
#else
|
||||
this->st.load_here();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ShapeDescriptor::ShapeDescriptor(const DataType type, const char order, const std::vector<LongType> &shape,
|
||||
const std::vector<LongType> &strides, const LongType ews)
|
||||
: ShapeDescriptor(type, order, shape, strides) {
|
||||
if(!DataTypeUtils::validDataType(_dataType)) {
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
}
|
||||
#if defined(SD_GCC_FUNCTRACE)
|
||||
// - backward-cpp's backtrace() is NOT safe during very early JVM initialization
|
||||
#ifdef __cpp_exceptions
|
||||
try {
|
||||
this->st.load_here();
|
||||
} catch (...) {
|
||||
// Stack trace capture failed - st will remain empty (size() == 0)
|
||||
}
|
||||
#else
|
||||
this->st.load_here();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
ShapeDescriptor::ShapeDescriptor(const DataType type, const LongType length)
|
||||
: _rank(1), _order('c'), _dataType(type), _extraProperties(0) {
|
||||
_shape_strides = new LongType [2];
|
||||
_shape_strides[0] = length;
|
||||
_shape_strides[1] = 1; //{shape, stride}
|
||||
if(!DataTypeUtils::validDataType(_dataType)) {
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
}
|
||||
|
||||
#if defined(SD_GCC_FUNCTRACE)
|
||||
// - backward-cpp's backtrace() is NOT safe during very early JVM initialization
|
||||
#ifdef __cpp_exceptions
|
||||
try {
|
||||
this->st.load_here();
|
||||
} catch (...) {
|
||||
// Stack trace capture failed - st will remain empty (size() == 0)
|
||||
}
|
||||
#else
|
||||
this->st.load_here();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
ShapeDescriptor::ShapeDescriptor(const LongType *shapeInfo, bool validateDataType, bool overrideStrides) {
|
||||
if(shapeInfo == nullptr) {
|
||||
THROW_EXCEPTION("ShapeDescriptor constructor: Shape info cannot be null!");
|
||||
}
|
||||
|
||||
|
||||
sd::LongType rankVal = shape::rank(shapeInfo);
|
||||
if(rankVal < 0 || rankVal > SD_MAX_RANK) {
|
||||
std::string errorMessage;
|
||||
errorMessage += "Shape descriptor created with invalid rank: ";
|
||||
errorMessage += std::to_string(rankVal);
|
||||
errorMessage += ". Valid range is 0 to ";
|
||||
errorMessage += std::to_string(SD_MAX_RANK);
|
||||
THROW_EXCEPTION(errorMessage.c_str());
|
||||
}
|
||||
|
||||
if(rankVal == 0) {
|
||||
//detect when the shape buffer values are unset.
|
||||
auto len = shape::shapeInfoLength(rankVal);
|
||||
//min number of values in a shape info buffer
|
||||
bool allZero = true;
|
||||
for(int i = 0; i < len; i++) {
|
||||
if(shapeInfo[i] != 0) {
|
||||
allZero = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(allZero) {
|
||||
THROW_EXCEPTION("Found shape buffer with all zero values. Values likely unset.");
|
||||
}
|
||||
}
|
||||
|
||||
_shape_strides = nullptr;
|
||||
_order = shape::order(shapeInfo);
|
||||
this->ownsShapeStrides = true;
|
||||
if(_order != 'c' && _order != 'f') {
|
||||
std::string errorMessage;
|
||||
errorMessage += "Invalid ordering from shape buffer";
|
||||
errorMessage += std::to_string(_order);
|
||||
THROW_EXCEPTION(errorMessage.c_str());
|
||||
|
||||
}
|
||||
|
||||
_rank = static_cast<sd::LongType >(rankVal);
|
||||
_extraProperties = shape::extra(shapeInfo);
|
||||
_dataType = ArrayOptions::dataType(shapeInfo);
|
||||
|
||||
if(_rank > 0 && shape::isEmptyConst(shapeInfo)) {
|
||||
_shape_strides = new LongType[2 * _rank];
|
||||
auto _strides = _shape_strides + _rank;
|
||||
auto shapePtr = shape::shapeOf(shapeInfo);
|
||||
for (LongType e = 0; e < _rank; e++) {
|
||||
_shape_strides[e] = shapePtr[e];
|
||||
_strides[e] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else if (_rank > 0 && !shape::isEmptyConst(shapeInfo)) {
|
||||
_shape_strides = new LongType[2 * rankVal];
|
||||
auto _strides = _shape_strides + _rank;
|
||||
auto shapePtr = shape::shapeOf(shapeInfo);
|
||||
auto stridePtr = shape::stride(shapeInfo);
|
||||
if(overrideStrides) {
|
||||
LongType *stridesNew = shape::order(shapeInfo) == 'c' ? shape::calcStrides(shapePtr, rankVal) : shape::calcStridesFortran(shapePtr, rankVal);
|
||||
for (LongType e = 0; e < _rank; e++) {
|
||||
_shape_strides[e] = shapePtr[e];
|
||||
_shape_strides[e + _rank] = stridesNew[e];
|
||||
}
|
||||
|
||||
delete[] stridesNew;
|
||||
|
||||
} else {
|
||||
for (LongType e = 0; e < _rank; e++) {
|
||||
_shape_strides[e] = shapePtr[e];
|
||||
_shape_strides[e + _rank] = stridePtr[e];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//validate construction of the shape descriptor. This is to prevent flag regressions when modifying
|
||||
//_extraProperties.
|
||||
//ensure that we only validate this for array size > 1
|
||||
if(!ArrayOptions::hasPropertyBitSet(_extraProperties, ARRAY_EMPTY) && this->arrLength() > 1) {
|
||||
for(int i = 0; i < _rank; i++) {
|
||||
if(_strides[i] == 0 && shapePtr[i] != 1) {
|
||||
std::string errorMessage;
|
||||
errorMessage += "Shape descriptor:";
|
||||
errorMessage += toString();
|
||||
errorMessage += "Array set as not empty but stride is not 0. Index is ";
|
||||
errorMessage += std::to_string(i);
|
||||
errorMessage += " Stride is ";
|
||||
errorMessage += std::to_string(_strides[i]);
|
||||
//append the full _shape_strides data
|
||||
errorMessage += " _shape_strides is ";
|
||||
for(int j = 0; j < _rank * 2; j++) {
|
||||
errorMessage += std::to_string(_shape_strides[j]);
|
||||
if(j < _rank * 2 - 1) {
|
||||
errorMessage += ", ";
|
||||
}
|
||||
}
|
||||
|
||||
THROW_EXCEPTION(errorMessage.c_str());
|
||||
}
|
||||
}
|
||||
} else if(this->arrLength() > 1) {
|
||||
for(int i = 0; i < _rank; i++) {
|
||||
if(_strides[i] != 0) {
|
||||
std::string errorMessage;
|
||||
errorMessage += "Array set as not empty but stride is 0. Index is";
|
||||
errorMessage += std::to_string(i);
|
||||
THROW_EXCEPTION(errorMessage.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if(!shape::isEmptyConst(shapeInfo)) { // Handle scalar case
|
||||
_shape_strides = new LongType [2]; // Since we're setting shape and stride
|
||||
_shape_strides[0] = 0; // Shape for scalar
|
||||
_shape_strides[1] = 1; // Stride for scalar
|
||||
} else {
|
||||
_shape_strides = new LongType[2];
|
||||
_shape_strides[0] = 0;
|
||||
_shape_strides[1] = 0;
|
||||
}
|
||||
_order = shape::order(shapeInfo);
|
||||
_dataType = ArrayOptions::dataType(shapeInfo);
|
||||
if(validateDataType && _dataType == UNKNOWN) {
|
||||
std::string errorMessage;
|
||||
errorMessage += "Shape descriptor created with invalid data type ";
|
||||
errorMessage += DataTypeUtils::asString(_dataType);
|
||||
errorMessage += " extra properties for data type was ";
|
||||
errorMessage += DataTypeUtils::asString(ArrayOptions::dataTypeValue(_extraProperties));
|
||||
errorMessage += " Underlying extra value was ";
|
||||
errorMessage += std::to_string(_extraProperties);
|
||||
THROW_EXCEPTION(errorMessage.c_str());
|
||||
}
|
||||
|
||||
#if defined(SD_GCC_FUNCTRACE)
|
||||
// - backward-cpp's backtrace() is NOT safe during very early JVM initialization
|
||||
#ifdef __cpp_exceptions
|
||||
try {
|
||||
this->st.load_here();
|
||||
} catch (...) {
|
||||
// Stack trace capture failed - st will remain empty (size() == 0)
|
||||
}
|
||||
#else
|
||||
this->st.load_here();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
ShapeDescriptor::ShapeDescriptor(const LongType *shapeInfo, const DataType dtypeOverride, const bool overrideStrides)
|
||||
: ShapeDescriptor(shapeInfo, false, overrideStrides) {
|
||||
if(dtypeOverride == UNKNOWN)
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
_dataType = dtypeOverride;
|
||||
_order = shape::order(shapeInfo);
|
||||
if(!DataTypeUtils::validDataType(_dataType)) {
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
}
|
||||
//data type has already been set by another constructor. We need to update the _extraProperties
|
||||
//to reflect the new data type. This is effectively a cast.
|
||||
_extraProperties = ArrayOptions::propertyWithoutDataTypeValue(_extraProperties);
|
||||
_extraProperties = ArrayOptions::setDataTypeValue(_extraProperties, dtypeOverride);
|
||||
|
||||
if(!DataTypeUtils::validDataType(_dataType)) {
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
}
|
||||
|
||||
#if defined(SD_GCC_FUNCTRACE)
|
||||
// - backward-cpp's backtrace() is NOT safe during very early JVM initialization
|
||||
#ifdef __cpp_exceptions
|
||||
try {
|
||||
this->st.load_here();
|
||||
} catch (...) {
|
||||
// Stack trace capture failed - st will remain empty (size() == 0)
|
||||
}
|
||||
#else
|
||||
this->st.load_here();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
ShapeDescriptor::ShapeDescriptor(const LongType *shapeInfo, const LongType *dtypeOverride)
|
||||
: ShapeDescriptor(shapeInfo, ArrayOptions::dataType(dtypeOverride), false) {
|
||||
if(!DataTypeUtils::validDataType(_dataType)) {
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
}
|
||||
|
||||
#if defined(SD_GCC_FUNCTRACE)
|
||||
// - backward-cpp's backtrace() is NOT safe during very early JVM initialization
|
||||
#ifdef __cpp_exceptions
|
||||
try {
|
||||
this->st.load_here();
|
||||
} catch (...) {
|
||||
// Stack trace capture failed - st will remain empty (size() == 0)
|
||||
}
|
||||
#else
|
||||
this->st.load_here();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
ShapeDescriptor::ShapeDescriptor(const LongType *shapeInfo, const LongType *dtypeOverride,
|
||||
const LongType *orderOverride)
|
||||
: ShapeDescriptor(shapeInfo, ArrayOptions::dataType(dtypeOverride), false) {
|
||||
_order = shape::order(orderOverride);
|
||||
if(!DataTypeUtils::validDataType(_dataType)) {
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
}
|
||||
|
||||
|
||||
#if defined(SD_GCC_FUNCTRACE)
|
||||
// - backward-cpp's backtrace() is NOT safe during very early JVM initialization
|
||||
#ifdef __cpp_exceptions
|
||||
try {
|
||||
this->st.load_here();
|
||||
} catch (...) {
|
||||
// Stack trace capture failed - st will remain empty (size() == 0)
|
||||
}
|
||||
#else
|
||||
this->st.load_here();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
int ShapeDescriptor::rank() const { return _rank; }
|
||||
|
||||
|
||||
LongType ShapeDescriptor::arrLength() const {
|
||||
if(_shape_strides== nullptr) {
|
||||
return 0;
|
||||
}
|
||||
// when _ews == 1 allocation length is also array length
|
||||
LongType len = 1;
|
||||
for (int i = 0; i < _rank; i++) len *= _shape_strides[i];
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void ShapeDescriptor::print() const {
|
||||
printf("ShapeDescriptor: [");
|
||||
for (int i = 0; i < _rank; i++) {
|
||||
printf("%lld", _shape_strides[i]);
|
||||
if (i < _rank - 1) printf(", ");
|
||||
}
|
||||
printf("], [");
|
||||
for (int i = _rank; i < 2 * _rank; i++) {
|
||||
printf("%lld", _shape_strides[i]);
|
||||
if (i < 2 * _rank - 1) printf(", ");
|
||||
}
|
||||
printf("], %c, %s, %lld\n", _order, DataTypeUtils::asString(_dataType).c_str(), _extraProperties);
|
||||
}
|
||||
|
||||
LongType ShapeDescriptor::allocLength() const {
|
||||
if (_paddedAllocSize > 0) return _paddedAllocSize;
|
||||
auto _shape = _shape_strides;
|
||||
auto _strides = _shape_strides + _rank;
|
||||
int rank2 = _rank < 1 ? 1 : _rank;
|
||||
|
||||
LongType len = 1;
|
||||
if (_rank > 1) {
|
||||
// calculate using max stride
|
||||
int ind = _order == 'c' ? 0 : rank2 - 1;
|
||||
return _shape[ind] * _strides[ind];
|
||||
}
|
||||
for (int i = 0; i < rank2; i++) {
|
||||
len += (_shape[i] - 1) * _strides[i];
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void ShapeDescriptor::collectStoreStackTrace() {
|
||||
#if defined(SD_GCC_FUNCTRACE)
|
||||
// - backward-cpp's backtrace() is NOT safe during very early JVM initialization
|
||||
this->storeStackTrace = backward::StackTrace();
|
||||
#ifdef __cpp_exceptions
|
||||
try {
|
||||
this->storeStackTrace.load_here(32);
|
||||
} catch (...) {
|
||||
// Stack trace capture failed - storeStackTrace will remain empty (size() == 0)
|
||||
}
|
||||
#else
|
||||
this->storeStackTrace.load_here(32);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
LongType ShapeDescriptor::validate() const {
|
||||
auto status = SHAPE_DESC_OK;
|
||||
bool is_continous = true;
|
||||
//exclude scalars on purpose here
|
||||
if (_rank > 0 || _rank > SD_MAX_RANK) status |= SHAPE_DESC_INCORRECT_RANK;
|
||||
auto _shape = _shape_strides;
|
||||
auto _strides = _shape_strides + _rank;
|
||||
if(_order != 'c' && _order != 'f') {
|
||||
THROW_EXCEPTION("Invalid ordering from shape buffer");
|
||||
}
|
||||
|
||||
bool hasZero = false;
|
||||
for (int i = 0; i < _rank; i++) {
|
||||
if (_shape[i] == 0) {
|
||||
hasZero = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//this check isn't correct for vectors
|
||||
if (_rank > 0 && !shape::isVector(_shape_strides,2) && !hasZero) {
|
||||
if (_order == 'c') {
|
||||
for (int j = _rank - 2; j >= 0; j--) {
|
||||
LongType currentStride = _strides[j];
|
||||
LongType allowedStride = _strides[j + 1] * _shape[j + 1];
|
||||
if (currentStride < allowedStride) {
|
||||
status = status | SHAPE_DESC_INCORRECT_STRIDES;
|
||||
break;
|
||||
}
|
||||
is_continous = is_continous & (currentStride == allowedStride);
|
||||
}
|
||||
} else {
|
||||
for (int j = 1; j < _rank; j++) {
|
||||
LongType currentStride = _strides[j];
|
||||
LongType allowedStride = _strides[j - 1] * _shape[j - 1];
|
||||
if (currentStride < allowedStride) {
|
||||
status = status | SHAPE_DESC_INCORRECT_STRIDES;
|
||||
break;
|
||||
}
|
||||
is_continous = is_continous & (currentStride == allowedStride);
|
||||
}
|
||||
}
|
||||
|
||||
int index = (_order == 'c') ? _rank - 1 : 0;
|
||||
auto correctEws = is_continous ? _strides[index] : 0;
|
||||
}
|
||||
|
||||
if(isEmpty()) {
|
||||
for(int i = 0; i < _rank; i++) {
|
||||
if(_strides[i] != 0) {
|
||||
std::string errorMessage;
|
||||
errorMessage += "Array set as empty but stride is not 0. Index is ";
|
||||
errorMessage += std::to_string(i);
|
||||
errorMessage += " Stride is ";
|
||||
errorMessage += std::to_string(_strides[i]);
|
||||
THROW_EXCEPTION(errorMessage.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!DataTypeUtils::validDataType(_dataType)) {
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
char ShapeDescriptor::order() const { return _order; }
|
||||
|
||||
DataType ShapeDescriptor::dataType() const {
|
||||
if(!DataTypeUtils::validDataType(_dataType)) {
|
||||
std::string errorMessage;
|
||||
errorMessage += "Shape descriptor created with invalid data type";
|
||||
errorMessage += DataTypeUtils::asString(_dataType);
|
||||
THROW_EXCEPTION(errorMessage.c_str());
|
||||
}
|
||||
return _dataType;
|
||||
}
|
||||
|
||||
bool ShapeDescriptor::isEmpty() const { return (_extraProperties & ARRAY_EMPTY) == ARRAY_EMPTY; }
|
||||
bool ShapeDescriptor::isScalar() const { return (!isEmpty() && rank() == 0) || (rank() == 1 && arrLength() == 1); }
|
||||
|
||||
sd::LongType * ShapeDescriptor::shape_strides() { return _shape_strides; }
|
||||
|
||||
const LongType *ShapeDescriptor::stridesPtr() const {
|
||||
return _shape_strides == nullptr ? nullptr : _shape_strides + _rank;
|
||||
}
|
||||
|
||||
ShapeDescriptor::ShapeDescriptor(const ShapeDescriptor &other) {
|
||||
_rank = other._rank;
|
||||
_extraProperties = other._extraProperties;
|
||||
if(other._dataType == UNKNOWN)
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
_dataType = other._dataType;
|
||||
_order = other._order;
|
||||
_shape_strides = other._shape_strides;
|
||||
this->ownsShapeStrides = false;
|
||||
_paddedAllocSize = other._paddedAllocSize;
|
||||
#if defined(SD_GCC_FUNCTRACE)
|
||||
// - backward-cpp's backtrace() is NOT safe during very early JVM initialization
|
||||
#ifdef __cpp_exceptions
|
||||
try {
|
||||
this->st.load_here();
|
||||
} catch (...) {
|
||||
// Stack trace capture failed - st will remain empty (size() == 0)
|
||||
}
|
||||
#else
|
||||
this->st.load_here();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ShapeDescriptor::ShapeDescriptor(const DataType type, const char order, const std::vector<LongType> &shape,
|
||||
const std::vector<LongType> &strides)
|
||||
: _order(order), _dataType(type) {
|
||||
_rank = shape.size();
|
||||
int rank2 = _rank < 1 ? 1 : _rank;
|
||||
|
||||
_shape_strides = new LongType [2 * rank2];
|
||||
this->ownsShapeStrides = true;
|
||||
#if defined(SD_GCC_FUNCTRACE)
|
||||
// - backward-cpp's backtrace() is NOT safe during very early JVM initialization
|
||||
#ifdef __cpp_exceptions
|
||||
try {
|
||||
this->st.load_here();
|
||||
} catch (...) {
|
||||
// Stack trace capture failed - st will remain empty (size() == 0)
|
||||
}
|
||||
#else
|
||||
this->st.load_here();
|
||||
#endif
|
||||
#endif
|
||||
auto _shape = _shape_strides;
|
||||
auto _strides = _shape_strides + rank2;
|
||||
if (!shape.empty() && strides.size() != shape.size() ) {
|
||||
for (int i = 0; i < rank2; i++) {
|
||||
_shape[i] = shape[i];
|
||||
}
|
||||
fillStrides();
|
||||
} else {
|
||||
for (int i = 0; i < rank2; i++) {
|
||||
_shape[i] = shape[i];
|
||||
_strides[i] = strides[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShapeDescriptor * ShapeDescriptor::emptyDescriptor(const DataType type) {
|
||||
ShapeDescriptor *descriptor = new ShapeDescriptor();
|
||||
if(type == UNKNOWN)
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
descriptor->_dataType = type;
|
||||
descriptor->_extraProperties = ARRAY_EMPTY | ArrayOptions::flagForDataType(type);
|
||||
descriptor->_rank = 0;
|
||||
descriptor->_order = 'c';
|
||||
descriptor->ownsShapeStrides = true;
|
||||
descriptor->_shape_strides = new LongType [1];
|
||||
descriptor->_shape_strides[0] = 0;
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
ShapeDescriptor * ShapeDescriptor::scalarDescriptor(const DataType type) {
|
||||
ShapeDescriptor *descriptor = new ShapeDescriptor();
|
||||
if(type == UNKNOWN)
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
descriptor->_dataType = type;
|
||||
descriptor->_extraProperties = ArrayOptions::flagForDataType(type);
|
||||
descriptor->_rank = 0;
|
||||
descriptor->_order = 'c';
|
||||
descriptor->ownsShapeStrides = true;
|
||||
descriptor->_shape_strides = new LongType [2];
|
||||
descriptor->_shape_strides[0] = 0;
|
||||
descriptor->_shape_strides[1] = 1;
|
||||
descriptor->_offset = 0;
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
ShapeDescriptor * ShapeDescriptor::vectorDescriptor(const LongType length, const DataType type) {
|
||||
ShapeDescriptor *descriptor = new ShapeDescriptor();
|
||||
if(type == UNKNOWN)
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
|
||||
descriptor->_dataType = type;
|
||||
descriptor->_shape_strides = new LongType [2];
|
||||
descriptor->_shape_strides[0] = length;
|
||||
descriptor->_shape_strides[1] = 0;
|
||||
descriptor->ownsShapeStrides = true;
|
||||
descriptor->_offset = 0;
|
||||
if (length > 0) {
|
||||
descriptor->_shape_strides[1] = 1;
|
||||
descriptor->_extraProperties = ArrayOptions::flagForDataType(type);
|
||||
}
|
||||
else {
|
||||
descriptor->_shape_strides[1] = 0;
|
||||
descriptor->_extraProperties = ARRAY_EMPTY;
|
||||
descriptor->_extraProperties = ArrayOptions::setDataTypeValue(descriptor->_extraProperties, type);
|
||||
}
|
||||
|
||||
descriptor->_order = 'c';
|
||||
descriptor->_rank = 1;
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
ShapeDescriptor * ShapeDescriptor::paddedBufferDescriptor(const DataType type, const char order,
|
||||
const std::vector<LongType> &shape,
|
||||
const std::vector<LongType> &paddings) {
|
||||
ShapeDescriptor *descriptor = new ShapeDescriptor();
|
||||
if(type == UNKNOWN)
|
||||
THROW_EXCEPTION("Shape descriptor created with invalid data type");
|
||||
|
||||
descriptor->_dataType = type;
|
||||
descriptor->_order = order;
|
||||
descriptor->_rank = shape.size();
|
||||
descriptor->_extraProperties = ArrayOptions::flagForDataType(type);
|
||||
descriptor->ownsShapeStrides = true;
|
||||
if (descriptor->_rank < 1) {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
int rank2 = descriptor->_rank < 1 ? 1 : descriptor->_rank;
|
||||
|
||||
descriptor->_shape_strides = new LongType [2 * rank2];
|
||||
auto _shape = descriptor->_shape_strides;
|
||||
auto _strides = descriptor->_shape_strides + rank2;
|
||||
for (size_t i = 0; i < shape.size(); i++) {
|
||||
_shape[i] = shape[i];
|
||||
}
|
||||
// calculate strides with paddings
|
||||
int min_rank = static_cast<size_t>(descriptor->_rank) > paddings.size() ? paddings.size() : rank2;
|
||||
bool is_continous = true;
|
||||
if (order == 'c') {
|
||||
_strides[rank2 - 1] = 1L;
|
||||
for (int j = descriptor->_rank - 2; j >= 0; j--) {
|
||||
LongType pad = (j + 1 < min_rank) ? paddings[j + 1] : 0;
|
||||
_strides[j] = _strides[j + 1] * (_shape[j + 1] + pad);
|
||||
descriptor->_extraProperties = descriptor->_extraProperties | (_shape[j + 1] == 0);
|
||||
if (pad != 0) is_continous = false;
|
||||
}
|
||||
if (!is_continous && descriptor->_rank > 0) {
|
||||
LongType size_pad = paddings.size() > 0 ? paddings[0] : 0;
|
||||
// alloc size should be supplied manually as we dont have place to store it
|
||||
descriptor->_paddedAllocSize = _strides[0] * (_shape[0] + size_pad);
|
||||
}
|
||||
} else {
|
||||
_strides[0] = 1L;
|
||||
for (int j = 1; j < rank2; j++) {
|
||||
LongType pad = (j - 1 < min_rank) ? paddings[j - 1] : 0;
|
||||
_strides[j] = _strides[j - 1] * (_shape[j - 1] + pad);
|
||||
descriptor->_extraProperties = descriptor->_extraProperties | (_shape[j - 1] == 0);
|
||||
if (pad != 0) is_continous = false;
|
||||
}
|
||||
if (!is_continous && descriptor->_rank > 0) {
|
||||
LongType size_pad = paddings.size() >= static_cast<size_t>(descriptor->_rank) ? paddings[descriptor->_rank - 1] : 0;
|
||||
// alloc size should be supplied manually as we dont have place to store it
|
||||
descriptor->_paddedAllocSize = _strides[descriptor->_rank - 1] * (_shape[descriptor->_rank - 1] + size_pad);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_continous) descriptor->_extraProperties |= ARRAY_HAS_PADDED_BUFFER;
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
} // namespace sd
|
||||
|
||||
namespace std {
|
||||
size_t hash<sd::ShapeDescriptor>::operator()(sd::ShapeDescriptor k) const {
|
||||
// Check cache first
|
||||
if (k._hash_computed) {
|
||||
return k._cached_hash;
|
||||
}
|
||||
// Check cache first
|
||||
if (k._hash_computed) {
|
||||
return k._cached_hash;
|
||||
}
|
||||
|
||||
using namespace sd::helpers::detail;
|
||||
|
||||
// Combine order and dataType into initial hash
|
||||
uint64_t hash = ModularHasher::combine_hashes({
|
||||
static_cast<uint64_t>(k.order()),
|
||||
static_cast<uint64_t>(k.dataType()) << 8
|
||||
});
|
||||
|
||||
// Hash the shape and strides array
|
||||
sd::LongType* shape_strides = k.shape_strides();
|
||||
const int stop = k.rank() * 2;
|
||||
|
||||
if (shape_strides != nullptr) {
|
||||
hash = DataChunkHasher<sd::LongType>::hash_data(
|
||||
shape_strides,
|
||||
stop,
|
||||
hash
|
||||
);
|
||||
}
|
||||
|
||||
// Cache the computed hash
|
||||
k._cached_hash = hash;
|
||||
k._hash_computed = true;
|
||||
|
||||
return hash;
|
||||
}
|
||||
} // namespace std
|
||||
Reference in New Issue
Block a user