Files
deeplearning4j--deeplearning4j/libnd4j/include/array/ShapeDescriptor.h
T
2026-07-13 12:47:05 +08:00

258 lines
8.2 KiB
C++

/* ******************************************************************************
*
*
* 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
#ifndef DEV_TESTS_SHAPEDESCRIPTOR_H
#define DEV_TESTS_SHAPEDESCRIPTOR_H
#include <array/ArrayOptions.hXX>
#include <array/DataType.h>
#include <helpers/shape.h>
#include <system/common.h>
#include <initializer_list>
#include <unordered_map>
#include <vector>
namespace sd {
#define SHAPE_DESC_OK 0
#define SHAPE_DESC_INCORRECT_STRIDES 1 // strides does not match shapes
#define SHAPE_DESC_INCORRECT_EWS 2 // ews neither matches stride nor continuity
#define SHAPE_DESC_INCORRECT_RANK 4 // rank > 32 or shape size and rank does not match
#define SHAPE_DESC_INVALID_EMPTY 5 // rank > 32 or shape size and rank does not match
class SD_LIB_EXPORT ShapeDescriptor {
private:
int _rank = 0;
LongType * _shape_strides = nullptr;
char _order = 'c';
DataType _dataType;
LongType _extraProperties = 0;
LongType _paddedAllocSize = 0;
LongType _offset = 0;
public:
bool ownsShapeStrides = false;
// Hash caching
mutable uint64_t _cached_hash;
mutable bool _hash_computed;
#ifndef __JAVACPP_HACK__
#if defined(SD_GCC_FUNCTRACE)
StackTrace st;
//stack trace when stored in cache.
StackTrace storeStackTrace;
#endif
ShapeDescriptor(const DataType type, const char order, const std::vector<LongType> &shape, LongType extras);
ShapeDescriptor(const ShapeDescriptor &other);
ShapeDescriptor(const LongType *shapeInfo, bool validateDataType = true, bool overrideStrides = false);
explicit ShapeDescriptor(const LongType *shapeInfo, const DataType dtypeOverride, const bool overrideStrides);
explicit ShapeDescriptor(const LongType *shapeInfo, const LongType *dtypeOverride);
explicit ShapeDescriptor(const LongType *shapeInfo, const LongType *dtypeOverride,
const LongType *orderOverride);
explicit ShapeDescriptor(const DataType type, const LongType length);
explicit ShapeDescriptor(const DataType type, const char order, const LongType *shape, const LongType rank);
explicit ShapeDescriptor(const DataType type, const char order, const std::vector<LongType> &shape);
explicit ShapeDescriptor(const DataType type, const char order, const std::vector<LongType> &shape,
const std::vector<LongType> &strides);
explicit ShapeDescriptor(const DataType type, const char order, const std::vector<LongType> &shape,
const std::vector<LongType> &strides, const LongType ews);
explicit ShapeDescriptor(const DataType type, const char order, const LongType *shape,
const LongType *strides, const LongType rank, LongType extras);
ShapeDescriptor() = default;
~ShapeDescriptor();
#endif
int rank() const;
void invalidateHash() const {
_hash_computed = false;
_cached_hash = 0;
}
uint64_t getCachedHash() const {
return _cached_hash;
}
LongType arrLength() const;
LongType offset();
char order() const;
DataType dataType() const;
bool isEmpty() const;
sd::LongType * shape_strides();
const LongType *stridesPtr() const;
LongType extra() const {
return _extraProperties;
}
void collectStoreStackTrace();
void print() const;
// returns minimal allocation length
LongType allocLength() const;
// returns Status for the correctness
LongType validate() const;
// we use default copy assignment operator
// Modify assignment operator to reset hash cache:
ShapeDescriptor& operator=(const ShapeDescriptor& other) {
if (this != &other) {
// Existing cleanup code
if (_shape_strides != nullptr && ownsShapeStrides) {
delete[] _shape_strides;
_shape_strides = nullptr;
}
// Copy all basic members
_rank = other._rank;
_extraProperties = other._extraProperties;
_dataType = other._dataType;
_order = other._order;
_paddedAllocSize = other._paddedAllocSize;
_offset = other._offset;
// Reset hash cache
_cached_hash = 0;
_hash_computed = false;
// Handle shape_strides - make a deep copy if source has data
if (other._shape_strides != nullptr) {
const int size = (_rank < 1 ? 1 : _rank) * 2;
_shape_strides = new LongType[size];
std::memcpy(_shape_strides, other._shape_strides, size * sizeof(LongType));
ownsShapeStrides = true;
} else {
_shape_strides = nullptr;
ownsShapeStrides = false;
}
}
return *this;
}
// we use default move assignment operator
ShapeDescriptor &operator=(ShapeDescriptor &&other) noexcept = default;
// equal to operator
bool operator==(const ShapeDescriptor &other) const;
// less than operator
bool operator<(const ShapeDescriptor &other) const;
LongType *toShapeInfo() const;
const char * toString() {
std::string message;
message += " Rank:" ;
message += std::to_string(_rank);
message += " Shape and Strides:";
if(_shape_strides == nullptr) {
message += " Null";
} else {
for (int i = 0; i < _rank * 2; i++) {
message += " ";
message += std::to_string(_shape_strides[i]);
}
}
message += "Data type:";
message += std::to_string(_dataType);
message += " Order:";
message += std::to_string(_order);
message += " Extra Properties:";
message += std::to_string(_extraProperties);
message += " Padded Alloc Size: ";
message += std::to_string(_paddedAllocSize);
message += " Offset: ";
message += std::to_string(_offset);
//need this in order to avoid deallocation
std::string *ret = new std::string(message.c_str());
return ret->c_str();
}
static ShapeDescriptor * emptyDescriptor(const DataType type);
static ShapeDescriptor * scalarDescriptor(const DataType type);
static ShapeDescriptor * vectorDescriptor(const LongType length, const DataType type);
// create Descriptor with padded buffer.
static ShapeDescriptor * paddedBufferDescriptor(const DataType type, const char order,
const std::vector<LongType> &shape,
const std::vector<LongType> &paddings);
static const char *messageForShapeDescriptorError(const int errorCode) {
switch (errorCode) {
case SHAPE_DESC_OK:
return "OK";
case SHAPE_DESC_INCORRECT_STRIDES:
return "Incorrect strides";
case SHAPE_DESC_INCORRECT_EWS:
return "Incorrect ews";
case SHAPE_DESC_INCORRECT_RANK:
return "Incorrect rank";
case SHAPE_DESC_INVALID_EMPTY:
return "Invalid empty";
default:
return "Unknown error";
}
}
bool isScalar() const;
SD_INLINE void fillStrides() {
if(_rank == 0) {
return;
}
if(_shape_strides == nullptr) {
return;
}
// double checks if the _rank and _shape_strides are set correctly before filling strides
auto _shape = _shape_strides;
auto _strides = _shape_strides + _rank;
if (_rank > 0) {
if (_order == 'c')
shape::calcStrides(_shape, _rank, _strides);
else
shape::calcStridesFortran(_shape, _rank, _strides);
} else {
for (int i = 0; i < _rank; i++) {
_strides[i] = 0;
}
}
}
};
} // namespace sd
#ifndef __JAVACPP_HACK__
namespace std {
template <>
class SD_LIB_EXPORT hash<sd::ShapeDescriptor> {
public:
size_t operator()(sd::ShapeDescriptor k) const;
};
} // namespace std
#endif
#endif // DEV_TESTS_SHAPEDESCRIPTOR_H