mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
Remove dead code, commented-out blocks, and outdated comments
libeigen/eigen!2172 Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
This commit is contained in:
@@ -196,8 +196,6 @@ class BlockImpl_dense : public internal::dense_xpr_base<Block<XprType, BlockRows
|
||||
EIGEN_DENSE_PUBLIC_INTERFACE(BlockType)
|
||||
EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl_dense)
|
||||
|
||||
// class InnerIterator; // FIXME apparently never used
|
||||
|
||||
/** Column or Row constructor
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index i)
|
||||
|
||||
@@ -48,7 +48,6 @@ struct CommaInitializer {
|
||||
|
||||
/* Copy/Move constructor which transfers ownership. This is crucial in
|
||||
* absence of return value optimization to avoid assertions during destruction. */
|
||||
// FIXME in C++11 mode this could be replaced by a proper RValue constructor
|
||||
EIGEN_DEVICE_FUNC inline CommaInitializer(const CommaInitializer& o)
|
||||
: m_xpr(o.m_xpr), m_row(o.m_row), m_col(o.m_col), m_currentBlockRows(o.m_currentBlockRows) {
|
||||
// Mark original object as finished. In absence of R-value references we need to const_cast:
|
||||
|
||||
@@ -436,64 +436,6 @@ struct nullary_wrapper<Scalar, NullaryOp, false, true, false> {
|
||||
template <typename Scalar, typename NullaryOp>
|
||||
struct nullary_wrapper<Scalar, NullaryOp, false, false, false> {};
|
||||
|
||||
#if 0 && EIGEN_COMP_MSVC > 0
|
||||
// Disable this ugly workaround. This is now handled in traits<Ref>::match,
|
||||
// but this piece of code might still become handly if some other weird compilation
|
||||
// errors pop up again.
|
||||
|
||||
// MSVC exhibits a weird compilation error when
|
||||
// compiling:
|
||||
// Eigen::MatrixXf A = MatrixXf::Random(3,3);
|
||||
// Ref<const MatrixXf> R = 2.f*A;
|
||||
// and that has_*ary_operator<scalar_constant_op<float>> have not been instantiated yet.
|
||||
// The "problem" is that evaluator<2.f*A> is instantiated by traits<Ref>::match<2.f*A>
|
||||
// and at that time has_*ary_operator<T> returns true regardless of T.
|
||||
// Then nullary_wrapper is badly instantiated as nullary_wrapper<.,.,true,true,true>.
|
||||
// The trick is thus to defer the proper instantiation of nullary_wrapper when coeff(),
|
||||
// and packet() are really instantiated as implemented below:
|
||||
|
||||
// This is a simple wrapper around Index to enforce the re-instantiation of
|
||||
// has_*ary_operator when needed.
|
||||
template<typename T> struct nullary_wrapper_workaround_msvc {
|
||||
nullary_wrapper_workaround_msvc(const T&);
|
||||
operator T()const;
|
||||
};
|
||||
|
||||
template<typename Scalar,typename NullaryOp>
|
||||
struct nullary_wrapper<Scalar,NullaryOp,true,true,true>
|
||||
{
|
||||
template <typename IndexType>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const {
|
||||
return nullary_wrapper<Scalar,NullaryOp,
|
||||
has_nullary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
|
||||
has_unary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
|
||||
has_binary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value>().operator()(op,i,j);
|
||||
}
|
||||
template <typename IndexType>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const {
|
||||
return nullary_wrapper<Scalar,NullaryOp,
|
||||
has_nullary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
|
||||
has_unary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
|
||||
has_binary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value>().operator()(op,i);
|
||||
}
|
||||
|
||||
template <typename T, typename IndexType>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const {
|
||||
return nullary_wrapper<Scalar,NullaryOp,
|
||||
has_nullary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
|
||||
has_unary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
|
||||
has_binary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value>().template packetOp<T>(op,i,j);
|
||||
}
|
||||
template <typename T, typename IndexType>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const {
|
||||
return nullary_wrapper<Scalar,NullaryOp,
|
||||
has_nullary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
|
||||
has_unary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
|
||||
has_binary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value>().template packetOp<T>(op,i);
|
||||
}
|
||||
};
|
||||
#endif // MSVC workaround
|
||||
|
||||
template <typename NullaryOp, typename PlainObjectType>
|
||||
struct evaluator<CwiseNullaryOp<NullaryOp, PlainObjectType>>
|
||||
: evaluator_base<CwiseNullaryOp<NullaryOp, PlainObjectType>> {
|
||||
|
||||
@@ -103,25 +103,6 @@ inline ForceAlignedAccess<Derived> MatrixBase<Derived>::forceAlignedAccess() {
|
||||
return ForceAlignedAccess<Derived>(derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of *this with forced aligned access if \a Enable is true.
|
||||
* \sa forceAlignedAccess(), class ForceAlignedAccess
|
||||
*/
|
||||
template <typename Derived>
|
||||
template <bool Enable>
|
||||
inline add_const_on_value_type_t<std::conditional_t<Enable, ForceAlignedAccess<Derived>, Derived&>>
|
||||
MatrixBase<Derived>::forceAlignedAccessIf() const {
|
||||
return derived(); // FIXME This should not work but apparently is never used
|
||||
}
|
||||
|
||||
/** \returns an expression of *this with forced aligned access if \a Enable is true.
|
||||
* \sa forceAlignedAccess(), class ForceAlignedAccess
|
||||
*/
|
||||
template <typename Derived>
|
||||
template <bool Enable>
|
||||
inline std::conditional_t<Enable, ForceAlignedAccess<Derived>, Derived&> MatrixBase<Derived>::forceAlignedAccessIf() {
|
||||
return derived(); // FIXME This should not work but apparently is never used
|
||||
}
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_FORCEALIGNEDACCESS_H
|
||||
|
||||
@@ -409,7 +409,6 @@ class MatrixBase : public DenseBase<Derived> {
|
||||
|
||||
EIGEN_DEVICE_FUNC inline Matrix<Scalar, 3, 1> canonicalEulerAngles(Index a0, Index a1, Index a2) const;
|
||||
|
||||
// put this as separate enum value to work around possible GCC 4.3 bug (?)
|
||||
enum {
|
||||
HomogeneousReturnTypeDirection =
|
||||
ColsAtCompileTime == 1 && RowsAtCompileTime == 1
|
||||
|
||||
@@ -500,18 +500,6 @@ struct product_evaluator<Product<Lhs, Rhs, LazyProduct>, ProductTag, DenseShape,
|
||||
EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits<Scalar>::MulCost);
|
||||
EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits<Scalar>::AddCost);
|
||||
EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
|
||||
#if 0
|
||||
std::cerr << "LhsOuterStrideBytes= " << LhsOuterStrideBytes << "\n";
|
||||
std::cerr << "RhsOuterStrideBytes= " << RhsOuterStrideBytes << "\n";
|
||||
std::cerr << "LhsAlignment= " << LhsAlignment << "\n";
|
||||
std::cerr << "RhsAlignment= " << RhsAlignment << "\n";
|
||||
std::cerr << "CanVectorizeLhs= " << CanVectorizeLhs << "\n";
|
||||
std::cerr << "CanVectorizeRhs= " << CanVectorizeRhs << "\n";
|
||||
std::cerr << "CanVectorizeInner= " << CanVectorizeInner << "\n";
|
||||
std::cerr << "EvalToRowMajor= " << EvalToRowMajor << "\n";
|
||||
std::cerr << "Alignment= " << Alignment << "\n";
|
||||
std::cerr << "Flags= " << Flags << "\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
// Everything below here is taken from CoeffBasedProduct.h
|
||||
|
||||
@@ -333,43 +333,7 @@ struct reshaped_evaluator<ArgType, Rows, Cols, Order, /* HasDirectAccess */ fals
|
||||
const RowCol row_col = index_remap(Rows == 1 ? 0 : index, Rows == 1 ? index : 0);
|
||||
return m_argImpl.coeff(row_col.first, row_col.second);
|
||||
}
|
||||
#if 0
|
||||
EIGEN_DEVICE_FUNC
|
||||
template<int LoadMode>
|
||||
inline PacketScalar packet(Index rowId, Index colId) const
|
||||
{
|
||||
const RowCol row_col = index_remap(rowId, colId);
|
||||
return m_argImpl.template packet<Unaligned>(row_col.first, row_col.second);
|
||||
|
||||
}
|
||||
|
||||
template<int LoadMode>
|
||||
EIGEN_DEVICE_FUNC
|
||||
inline void writePacket(Index rowId, Index colId, const PacketScalar& val)
|
||||
{
|
||||
const RowCol row_col = index_remap(rowId, colId);
|
||||
m_argImpl.const_cast_derived().template writePacket<Unaligned>
|
||||
(row_col.first, row_col.second, val);
|
||||
}
|
||||
|
||||
template<int LoadMode>
|
||||
EIGEN_DEVICE_FUNC
|
||||
inline PacketScalar packet(Index index) const
|
||||
{
|
||||
const RowCol row_col = index_remap(RowsAtCompileTime == 1 ? 0 : index,
|
||||
RowsAtCompileTime == 1 ? index : 0);
|
||||
return m_argImpl.template packet<Unaligned>(row_col.first, row_col.second);
|
||||
}
|
||||
|
||||
template<int LoadMode>
|
||||
EIGEN_DEVICE_FUNC
|
||||
inline void writePacket(Index index, const PacketScalar& val)
|
||||
{
|
||||
const RowCol row_col = index_remap(RowsAtCompileTime == 1 ? 0 : index,
|
||||
RowsAtCompileTime == 1 ? index : 0);
|
||||
return m_argImpl.template packet<Unaligned>(row_col.first, row_col.second, val);
|
||||
}
|
||||
#endif
|
||||
protected:
|
||||
evaluator<ArgType> m_argImpl;
|
||||
const XprType& m_xpr;
|
||||
|
||||
@@ -236,14 +236,6 @@ class SelfAdjointView : public TriangularBase<SelfAdjointView<MatrixType_, UpLo>
|
||||
MatrixTypeNested m_matrix;
|
||||
};
|
||||
|
||||
// template<typename OtherDerived, typename MatrixType, unsigned int UpLo>
|
||||
// internal::selfadjoint_matrix_product_returntype<OtherDerived,SelfAdjointView<MatrixType,UpLo> >
|
||||
// operator*(const MatrixBase<OtherDerived>& lhs, const SelfAdjointView<MatrixType,UpLo>& rhs)
|
||||
// {
|
||||
// return internal::matrix_selfadjoint_product_returntype<OtherDerived,SelfAdjointView<MatrixType,UpLo>
|
||||
// >(lhs.derived(),rhs);
|
||||
// }
|
||||
|
||||
// selfadjoint to dense matrix
|
||||
|
||||
namespace internal {
|
||||
|
||||
@@ -28,7 +28,7 @@ class indexed_based_stl_iterator_base {
|
||||
typedef indexed_based_stl_iterator_base<typename traits::non_const_iterator> non_const_iterator;
|
||||
typedef indexed_based_stl_iterator_base<typename traits::const_iterator> const_iterator;
|
||||
typedef std::conditional_t<internal::is_const<XprType>::value, non_const_iterator, const_iterator> other_iterator;
|
||||
// NOTE: in C++03 we cannot declare friend classes through typedefs because we need to write friend class:
|
||||
|
||||
friend class indexed_based_stl_iterator_base<typename traits::const_iterator>;
|
||||
friend class indexed_based_stl_iterator_base<typename traits::non_const_iterator>;
|
||||
|
||||
@@ -174,7 +174,7 @@ class indexed_based_stl_reverse_iterator_base {
|
||||
typedef indexed_based_stl_reverse_iterator_base<typename traits::non_const_iterator> non_const_iterator;
|
||||
typedef indexed_based_stl_reverse_iterator_base<typename traits::const_iterator> const_iterator;
|
||||
typedef std::conditional_t<internal::is_const<XprType>::value, non_const_iterator, const_iterator> other_iterator;
|
||||
// NOTE: in C++03 we cannot declare friend classes through typedefs because we need to write friend class:
|
||||
|
||||
friend class indexed_based_stl_reverse_iterator_base<typename traits::const_iterator>;
|
||||
friend class indexed_based_stl_reverse_iterator_base<typename traits::non_const_iterator>;
|
||||
|
||||
@@ -318,7 +318,7 @@ class pointer_based_stl_iterator {
|
||||
typedef pointer_based_stl_iterator<std::remove_const_t<XprType>> non_const_iterator;
|
||||
typedef pointer_based_stl_iterator<std::add_const_t<XprType>> const_iterator;
|
||||
typedef std::conditional_t<internal::is_const<XprType>::value, non_const_iterator, const_iterator> other_iterator;
|
||||
// NOTE: in C++03 we cannot declare friend classes through typedefs because we need to write friend class:
|
||||
|
||||
friend class pointer_based_stl_iterator<std::add_const_t<XprType>>;
|
||||
friend class pointer_based_stl_iterator<std::remove_const_t<XprType>>;
|
||||
|
||||
|
||||
@@ -1766,12 +1766,6 @@ template <>
|
||||
EIGEN_STRONG_INLINE Packet4d preverse(const Packet4d& a) {
|
||||
__m256d tmp = _mm256_shuffle_pd(a, a, 5);
|
||||
return _mm256_permute2f128_pd(tmp, tmp, 1);
|
||||
#if 0
|
||||
// This version is unlikely to be faster as _mm256_shuffle_ps and _mm256_permute_pd
|
||||
// exhibit the same latency/throughput, but it is here for future reference/benchmarking...
|
||||
__m256d swap_halves = _mm256_permute2f128_pd(a,a,1);
|
||||
return _mm256_permute_pd(swap_halves,5);
|
||||
#endif
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8i preverse(const Packet8i& a) {
|
||||
|
||||
@@ -832,10 +832,6 @@ class gemm_class {
|
||||
|
||||
// n-remainders.
|
||||
if (n & 4 && max_b_unroll > 4) nloop<a_unroll, 4, max_b_unroll>(aa, ao, bo, co1, co2);
|
||||
#if 0
|
||||
if (n & 2 && max_b_unroll > 2) nloop<a_unroll, 2, max_b_unroll>(aa, ao, bo, co1, co2);
|
||||
if (n & 1 && max_b_unroll > 1) nloop<a_unroll, 1, max_b_unroll>(aa, ao, bo, co1, co2);
|
||||
#else
|
||||
// Copy kernels don't support tails of n = 2 for single/double precision.
|
||||
// Loop over ones.
|
||||
int n_rem = 2 * ((n & 2) != 0) + 1 * ((n & 1) != 0);
|
||||
@@ -843,7 +839,6 @@ class gemm_class {
|
||||
nloop<a_unroll, 1, max_b_unroll>(aa, ao, bo, co1, co2);
|
||||
n_rem--;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Advance A matrix pointer.
|
||||
a = ao + a_unroll * (a_stride - k - a_off);
|
||||
|
||||
@@ -82,7 +82,6 @@ EIGEN_ALWAYS_INLINE void storeComplexAccumulator(Index i, const DataMapper& data
|
||||
}
|
||||
}
|
||||
|
||||
// Defaults to float32, since Eigen still supports C++03 we can't use default template arguments
|
||||
template <typename LhsPacket, typename RhsPacket, bool NegativeAccumulate>
|
||||
EIGEN_ALWAYS_INLINE void pgerMMA(__vector_quad* acc, const RhsPacket& a, const LhsPacket& b) {
|
||||
if (NegativeAccumulate) {
|
||||
|
||||
@@ -35,18 +35,7 @@ namespace internal {
|
||||
#define EIGEN_ARCH_DEFAULT_NUMBER_OF_REGISTERS 32
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define EIGEN_MSA_DEBUG \
|
||||
static bool firstTime = true; \
|
||||
do { \
|
||||
if (firstTime) { \
|
||||
std::cout << __FILE__ << ':' << __LINE__ << ':' << __FUNCTION__ << std::endl; \
|
||||
firstTime = false; \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define EIGEN_MSA_DEBUG
|
||||
#endif
|
||||
|
||||
#define EIGEN_MSA_SHF_I8(a, b, c, d) (((d) << 6) | ((c) << 4) | ((b) << 2) | (a))
|
||||
|
||||
|
||||
@@ -2127,205 +2127,6 @@ EIGEN_STRONG_INLINE __m128i float2half(__m128 f) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Packet math for Eigen::half
|
||||
// Disable the following code since it's broken on too many platforms / compilers.
|
||||
// #elif defined(EIGEN_VECTORIZE_SSE) && (!EIGEN_ARCH_x86_64) && (!EIGEN_COMP_MSVC)
|
||||
#if 0
|
||||
|
||||
typedef struct {
|
||||
__m64 x;
|
||||
} Packet4h;
|
||||
|
||||
|
||||
template<> struct is_arithmetic<Packet4h> { enum { value = true }; };
|
||||
|
||||
template <>
|
||||
struct packet_traits<Eigen::half> : default_packet_traits {
|
||||
typedef Packet4h type;
|
||||
// There is no half-size packet for Packet4h.
|
||||
typedef Packet4h half;
|
||||
enum {
|
||||
Vectorizable = 1,
|
||||
AlignedOnScalar = 1,
|
||||
size = 4,
|
||||
HasAdd = 1,
|
||||
HasSub = 1,
|
||||
HasMul = 1,
|
||||
HasDiv = 1,
|
||||
HasNegate = 0,
|
||||
HasAbs = 0,
|
||||
HasMin = 0,
|
||||
HasMax = 0,
|
||||
HasConj = 0,
|
||||
HasSetLinear = 0,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template<> struct unpacket_traits<Packet4h> { typedef Eigen::half type; enum {size=4, alignment=Aligned16, vectorizable=true, masked_load_available=false, masked_store_available=false}; typedef Packet4h half; };
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet4h pset1<Packet4h>(const Eigen::half& from) {
|
||||
Packet4h result;
|
||||
result.x = _mm_set1_pi16(from.x);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Eigen::half pfirst<Packet4h>(const Packet4h& from) {
|
||||
return half_impl::raw_uint16_to_half(static_cast<unsigned short>(_mm_cvtsi64_si32(from.x)));
|
||||
}
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet4h pconj(const Packet4h& a) { return a; }
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet4h padd<Packet4h>(const Packet4h& a, const Packet4h& b) {
|
||||
__int64_t a64 = _mm_cvtm64_si64(a.x);
|
||||
__int64_t b64 = _mm_cvtm64_si64(b.x);
|
||||
|
||||
Eigen::half h[4];
|
||||
|
||||
Eigen::half ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64));
|
||||
Eigen::half hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64));
|
||||
h[0] = ha + hb;
|
||||
ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64 >> 16));
|
||||
hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64 >> 16));
|
||||
h[1] = ha + hb;
|
||||
ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64 >> 32));
|
||||
hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64 >> 32));
|
||||
h[2] = ha + hb;
|
||||
ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64 >> 48));
|
||||
hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64 >> 48));
|
||||
h[3] = ha + hb;
|
||||
Packet4h result;
|
||||
result.x = _mm_set_pi16(h[3].x, h[2].x, h[1].x, h[0].x);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet4h psub<Packet4h>(const Packet4h& a, const Packet4h& b) {
|
||||
__int64_t a64 = _mm_cvtm64_si64(a.x);
|
||||
__int64_t b64 = _mm_cvtm64_si64(b.x);
|
||||
|
||||
Eigen::half h[4];
|
||||
|
||||
Eigen::half ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64));
|
||||
Eigen::half hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64));
|
||||
h[0] = ha - hb;
|
||||
ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64 >> 16));
|
||||
hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64 >> 16));
|
||||
h[1] = ha - hb;
|
||||
ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64 >> 32));
|
||||
hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64 >> 32));
|
||||
h[2] = ha - hb;
|
||||
ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64 >> 48));
|
||||
hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64 >> 48));
|
||||
h[3] = ha - hb;
|
||||
Packet4h result;
|
||||
result.x = _mm_set_pi16(h[3].x, h[2].x, h[1].x, h[0].x);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet4h pmul<Packet4h>(const Packet4h& a, const Packet4h& b) {
|
||||
__int64_t a64 = _mm_cvtm64_si64(a.x);
|
||||
__int64_t b64 = _mm_cvtm64_si64(b.x);
|
||||
|
||||
Eigen::half h[4];
|
||||
|
||||
Eigen::half ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64));
|
||||
Eigen::half hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64));
|
||||
h[0] = ha * hb;
|
||||
ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64 >> 16));
|
||||
hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64 >> 16));
|
||||
h[1] = ha * hb;
|
||||
ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64 >> 32));
|
||||
hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64 >> 32));
|
||||
h[2] = ha * hb;
|
||||
ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64 >> 48));
|
||||
hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64 >> 48));
|
||||
h[3] = ha * hb;
|
||||
Packet4h result;
|
||||
result.x = _mm_set_pi16(h[3].x, h[2].x, h[1].x, h[0].x);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet4h pdiv<Packet4h>(const Packet4h& a, const Packet4h& b) {
|
||||
__int64_t a64 = _mm_cvtm64_si64(a.x);
|
||||
__int64_t b64 = _mm_cvtm64_si64(b.x);
|
||||
|
||||
Eigen::half h[4];
|
||||
|
||||
Eigen::half ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64));
|
||||
Eigen::half hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64));
|
||||
h[0] = ha / hb;
|
||||
ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64 >> 16));
|
||||
hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64 >> 16));
|
||||
h[1] = ha / hb;
|
||||
ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64 >> 32));
|
||||
hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64 >> 32));
|
||||
h[2] = ha / hb;
|
||||
ha = half_impl::raw_uint16_to_half(static_cast<unsigned short>(a64 >> 48));
|
||||
hb = half_impl::raw_uint16_to_half(static_cast<unsigned short>(b64 >> 48));
|
||||
h[3] = ha / hb;
|
||||
Packet4h result;
|
||||
result.x = _mm_set_pi16(h[3].x, h[2].x, h[1].x, h[0].x);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet4h pload<Packet4h>(const Eigen::half* from) {
|
||||
Packet4h result;
|
||||
result.x = _mm_cvtsi64_m64(*reinterpret_cast<const __int64_t*>(from));
|
||||
return result;
|
||||
}
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet4h ploadu<Packet4h>(const Eigen::half* from) {
|
||||
Packet4h result;
|
||||
result.x = _mm_cvtsi64_m64(*reinterpret_cast<const __int64_t*>(from));
|
||||
return result;
|
||||
}
|
||||
|
||||
template<> EIGEN_STRONG_INLINE void pstore<Eigen::half>(Eigen::half* to, const Packet4h& from) {
|
||||
__int64_t r = _mm_cvtm64_si64(from.x);
|
||||
*(reinterpret_cast<__int64_t*>(to)) = r;
|
||||
}
|
||||
|
||||
template<> EIGEN_STRONG_INLINE void pstoreu<Eigen::half>(Eigen::half* to, const Packet4h& from) {
|
||||
__int64_t r = _mm_cvtm64_si64(from.x);
|
||||
*(reinterpret_cast<__int64_t*>(to)) = r;
|
||||
}
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet4h
|
||||
ploadquad<Packet4h>(const Eigen::half* from) {
|
||||
return pset1<Packet4h>(*from);
|
||||
}
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet4h pgather<Eigen::half, Packet4h>(const Eigen::half* from, Index stride)
|
||||
{
|
||||
Packet4h result;
|
||||
result.x = _mm_set_pi16(from[3*stride].x, from[2*stride].x, from[1*stride].x, from[0*stride].x);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<> EIGEN_STRONG_INLINE void pscatter<Eigen::half, Packet4h>(Eigen::half* to, const Packet4h& from, Index stride)
|
||||
{
|
||||
__int64_t a = _mm_cvtm64_si64(from.x);
|
||||
to[stride*0].x = static_cast<unsigned short>(a);
|
||||
to[stride*1].x = static_cast<unsigned short>(a >> 16);
|
||||
to[stride*2].x = static_cast<unsigned short>(a >> 32);
|
||||
to[stride*3].x = static_cast<unsigned short>(a >> 48);
|
||||
}
|
||||
|
||||
EIGEN_STRONG_INLINE void
|
||||
ptranspose(PacketBlock<Packet4h,4>& kernel) {
|
||||
__m64 T0 = _mm_unpacklo_pi16(kernel.packet[0].x, kernel.packet[1].x);
|
||||
__m64 T1 = _mm_unpacklo_pi16(kernel.packet[2].x, kernel.packet[3].x);
|
||||
__m64 T2 = _mm_unpackhi_pi16(kernel.packet[0].x, kernel.packet[1].x);
|
||||
__m64 T3 = _mm_unpackhi_pi16(kernel.packet[2].x, kernel.packet[3].x);
|
||||
|
||||
kernel.packet[0].x = _mm_unpacklo_pi32(T0, T1);
|
||||
kernel.packet[1].x = _mm_unpackhi_pi32(T0, T1);
|
||||
kernel.packet[2].x = _mm_unpacklo_pi32(T2, T3);
|
||||
kernel.packet[3].x = _mm_unpackhi_pi32(T2, T3);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
@@ -173,56 +173,6 @@ EIGEN_STRONG_INLINE Packet4i preinterpret<Packet4i, Packet4ui>(const Packet4ui&
|
||||
return Packet4i(a);
|
||||
}
|
||||
|
||||
// Disable the following code since it's broken on too many platforms / compilers.
|
||||
// #elif defined(EIGEN_VECTORIZE_SSE) && (!EIGEN_ARCH_x86_64) && (!EIGEN_COMP_MSVC)
|
||||
#if 0
|
||||
|
||||
template <>
|
||||
struct type_casting_traits<Eigen::half, float> {
|
||||
enum {
|
||||
VectorizedCast = 1,
|
||||
SrcCoeffRatio = 1,
|
||||
TgtCoeffRatio = 1
|
||||
};
|
||||
};
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet4f pcast<Packet4h, Packet4f>(const Packet4h& a) {
|
||||
__int64_t a64 = _mm_cvtm64_si64(a.x);
|
||||
Eigen::half h = raw_uint16_to_half(static_cast<unsigned short>(a64));
|
||||
float f1 = static_cast<float>(h);
|
||||
h = raw_uint16_to_half(static_cast<unsigned short>(a64 >> 16));
|
||||
float f2 = static_cast<float>(h);
|
||||
h = raw_uint16_to_half(static_cast<unsigned short>(a64 >> 32));
|
||||
float f3 = static_cast<float>(h);
|
||||
h = raw_uint16_to_half(static_cast<unsigned short>(a64 >> 48));
|
||||
float f4 = static_cast<float>(h);
|
||||
return _mm_set_ps(f4, f3, f2, f1);
|
||||
}
|
||||
|
||||
template <>
|
||||
struct type_casting_traits<float, Eigen::half> {
|
||||
enum {
|
||||
VectorizedCast = 1,
|
||||
SrcCoeffRatio = 1,
|
||||
TgtCoeffRatio = 1
|
||||
};
|
||||
};
|
||||
|
||||
template<> EIGEN_STRONG_INLINE Packet4h pcast<Packet4f, Packet4h>(const Packet4f& a) {
|
||||
EIGEN_ALIGN16 float aux[4];
|
||||
pstore(aux, a);
|
||||
Eigen::half h0(aux[0]);
|
||||
Eigen::half h1(aux[1]);
|
||||
Eigen::half h2(aux[2]);
|
||||
Eigen::half h3(aux[3]);
|
||||
|
||||
Packet4h result;
|
||||
result.x = _mm_set_pi16(h3.x, h2.x, h1.x, h0.x);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
@@ -98,8 +98,6 @@ selfadjoint_matrix_vector_product<Scalar, Index, StorageOrder, UpLo, ConjugateLh
|
||||
t2 += cj1.pmul(A0[i], rhs[i]);
|
||||
t3 += cj1.pmul(A1[i], rhs[i]);
|
||||
}
|
||||
// Yes this an optimization for gcc 4.3 and 4.4 (=> huge speed up)
|
||||
// gcc 4.2 does this optimization automatically.
|
||||
const Scalar* EIGEN_RESTRICT a0It = A0 + alignedStart;
|
||||
const Scalar* EIGEN_RESTRICT a1It = A1 + alignedStart;
|
||||
const Scalar* EIGEN_RESTRICT rhsIt = rhs + alignedStart;
|
||||
|
||||
@@ -17,30 +17,6 @@ namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// template<typename Scalar, int mr, int StorageOrder, bool Conjugate, int Mode>
|
||||
// struct gemm_pack_lhs_triangular
|
||||
// {
|
||||
// Matrix<Scalar,mr,mr,
|
||||
// void operator()(Scalar* blockA, const EIGEN_RESTRICT Scalar* lhs_, int lhsStride, int depth, int rows)
|
||||
// {
|
||||
// conj_if<NumTraits<Scalar>::IsComplex && Conjugate> cj;
|
||||
// const_blas_data_mapper<Scalar, StorageOrder> lhs(lhs_,lhsStride);
|
||||
// int count = 0;
|
||||
// const int peeled_mc = (rows/mr)*mr;
|
||||
// for(int i=0; i<peeled_mc; i+=mr)
|
||||
// {
|
||||
// for(int k=0; k<depth; k++)
|
||||
// for(int w=0; w<mr; w++)
|
||||
// blockA[count++] = cj(lhs(i+w, k));
|
||||
// }
|
||||
// for(int i=peeled_mc; i<rows; i++)
|
||||
// {
|
||||
// for(int k=0; k<depth; k++)
|
||||
// blockA[count++] = cj(lhs(i, k));
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
/* Optimized triangular matrix * matrix (_TRMM++) product built on top of
|
||||
* the general matrix matrix product.
|
||||
*/
|
||||
|
||||
@@ -80,7 +80,6 @@ class MaxSizeVector {
|
||||
new (&m_data[m_size++]) T(t);
|
||||
}
|
||||
|
||||
// For C++03 compatibility this only takes one argument
|
||||
template <class X>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void emplace_back(const X& x) {
|
||||
eigen_assert(m_size < m_reserve);
|
||||
|
||||
@@ -425,12 +425,6 @@ struct scalar_product_traits {
|
||||
enum { Defined = 0 };
|
||||
};
|
||||
|
||||
// FIXME quick workaround around current limitation of result_of
|
||||
// template<typename Scalar, typename ArgType0, typename ArgType1>
|
||||
// struct result_of<scalar_product_op<Scalar>(ArgType0,ArgType1)> {
|
||||
// typedef typename scalar_product_traits<remove_all_t<ArgType0>, remove_all_t<ArgType1>>::ReturnType type;
|
||||
// };
|
||||
|
||||
/** \internal Obtains a POD type suitable to use as storage for an object of a size
|
||||
* of at most Len bytes, aligned as specified by \c Align.
|
||||
*/
|
||||
|
||||
@@ -115,13 +115,6 @@ class QuaternionBase : public RotationBase<Derived, 3> {
|
||||
template <class OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const QuaternionBase<OtherDerived>& other);
|
||||
|
||||
// disabled this copy operator as it is giving very strange compilation errors when compiling
|
||||
// test_stdvector with GCC 4.4.2. This looks like a GCC bug though, so feel free to re-enable it if it's
|
||||
// useful; however notice that we already have the templated operator= above and e.g. in MatrixBase
|
||||
// we didn't have to add, in addition to templated operator=, such a non-templated copy operator.
|
||||
// Derived& operator=(const QuaternionBase& other)
|
||||
// { return operator=<Derived>(other); }
|
||||
|
||||
EIGEN_DEVICE_FUNC Derived& operator=(const AngleAxisType& aa);
|
||||
template <class OtherDerived>
|
||||
EIGEN_DEVICE_FUNC Derived& operator=(const MatrixBase<OtherDerived>& m);
|
||||
|
||||
@@ -20,35 +20,6 @@ namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
/** \internal */
|
||||
// template<typename TriangularFactorType,typename VectorsType,typename CoeffsType>
|
||||
// void make_block_householder_triangular_factor(TriangularFactorType& triFactor, const VectorsType& vectors, const
|
||||
// CoeffsType& hCoeffs)
|
||||
// {
|
||||
// typedef typename VectorsType::Scalar Scalar;
|
||||
// const Index nbVecs = vectors.cols();
|
||||
// eigen_assert(triFactor.rows() == nbVecs && triFactor.cols() == nbVecs && vectors.rows()>=nbVecs);
|
||||
//
|
||||
// for(Index i = 0; i < nbVecs; i++)
|
||||
// {
|
||||
// Index rs = vectors.rows() - i;
|
||||
// // Warning, note that hCoeffs may alias with vectors.
|
||||
// // It is then necessary to copy it before modifying vectors(i,i).
|
||||
// typename CoeffsType::Scalar h = hCoeffs(i);
|
||||
// // This hack permits to pass through nested Block<> and Transpose<> expressions.
|
||||
// Scalar *Vii_ptr = const_cast<Scalar*>(vectors.data() + vectors.outerStride()*i + vectors.innerStride()*i);
|
||||
// Scalar Vii = *Vii_ptr;
|
||||
// *Vii_ptr = Scalar(1);
|
||||
// triFactor.col(i).head(i).noalias() = -h * vectors.block(i, 0, rs, i).adjoint()
|
||||
// * vectors.col(i).tail(rs);
|
||||
// *Vii_ptr = Vii;
|
||||
// // FIXME add .noalias() once the triangular product can work inplace
|
||||
// triFactor.col(i).head(i) = triFactor.block(0,0,i,i).template triangularView<Upper>()
|
||||
// * triFactor.col(i).head(i);
|
||||
// triFactor(i,i) = hCoeffs(i);
|
||||
// }
|
||||
// }
|
||||
|
||||
/** \internal */
|
||||
// This variant avoid modifications in vectors
|
||||
template <typename TriangularFactorType, typename VectorsType, typename CoeffsType>
|
||||
|
||||
@@ -112,31 +112,6 @@ class KLU : public SparseSolverBase<KLU<MatrixType_> > {
|
||||
eigen_assert(m_isInitialized && "Decomposition is not initialized.");
|
||||
return m_info;
|
||||
}
|
||||
#if 0 // not implemented yet
|
||||
inline const LUMatrixType& matrixL() const
|
||||
{
|
||||
if (m_extractedDataAreDirty) extractData();
|
||||
return m_l;
|
||||
}
|
||||
|
||||
inline const LUMatrixType& matrixU() const
|
||||
{
|
||||
if (m_extractedDataAreDirty) extractData();
|
||||
return m_u;
|
||||
}
|
||||
|
||||
inline const IntColVectorType& permutationP() const
|
||||
{
|
||||
if (m_extractedDataAreDirty) extractData();
|
||||
return m_p;
|
||||
}
|
||||
|
||||
inline const IntRowVectorType& permutationQ() const
|
||||
{
|
||||
if (m_extractedDataAreDirty) extractData();
|
||||
return m_q;
|
||||
}
|
||||
#endif
|
||||
/** Computes the sparse Cholesky decomposition of \a matrix
|
||||
* Note that the matrix should be column-major, and in compressed format for best performance.
|
||||
* \sa SparseMatrix::makeCompressed().
|
||||
@@ -200,12 +175,6 @@ class KLU : public SparseSolverBase<KLU<MatrixType_> > {
|
||||
template <typename BDerived, typename XDerived>
|
||||
bool _solve_impl(const MatrixBase<BDerived> &b, MatrixBase<XDerived> &x) const;
|
||||
|
||||
#if 0 // not implemented yet
|
||||
Scalar determinant() const;
|
||||
|
||||
void extractData() const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void init() {
|
||||
m_info = InvalidInput;
|
||||
@@ -255,14 +224,6 @@ class KLU : public SparseSolverBase<KLU<MatrixType_> > {
|
||||
}
|
||||
}
|
||||
|
||||
// cached data to reduce reallocation, etc.
|
||||
#if 0 // not implemented yet
|
||||
mutable LUMatrixType m_l;
|
||||
mutable LUMatrixType m_u;
|
||||
mutable IntColVectorType m_p;
|
||||
mutable IntRowVectorType m_q;
|
||||
#endif
|
||||
|
||||
KLUMatrixType m_dummy;
|
||||
KLUMatrixRef mp_matrix;
|
||||
|
||||
@@ -278,45 +239,6 @@ class KLU : public SparseSolverBase<KLU<MatrixType_> > {
|
||||
KLU(const KLU &) {}
|
||||
};
|
||||
|
||||
#if 0 // not implemented yet
|
||||
template<typename MatrixType>
|
||||
void KLU<MatrixType>::extractData() const
|
||||
{
|
||||
if (m_extractedDataAreDirty)
|
||||
{
|
||||
eigen_assert(false && "KLU: extractData Not Yet Implemented");
|
||||
|
||||
// get size of the data
|
||||
int lnz, unz, rows, cols, nz_udiag;
|
||||
umfpack_get_lunz(&lnz, &unz, &rows, &cols, &nz_udiag, m_numeric, Scalar());
|
||||
|
||||
// allocate data
|
||||
m_l.resize(rows,(std::min)(rows,cols));
|
||||
m_l.resizeNonZeros(lnz);
|
||||
|
||||
m_u.resize((std::min)(rows,cols),cols);
|
||||
m_u.resizeNonZeros(unz);
|
||||
|
||||
m_p.resize(rows);
|
||||
m_q.resize(cols);
|
||||
|
||||
// extract
|
||||
umfpack_get_numeric(m_l.outerIndexPtr(), m_l.innerIndexPtr(), m_l.valuePtr(),
|
||||
m_u.outerIndexPtr(), m_u.innerIndexPtr(), m_u.valuePtr(),
|
||||
m_p.data(), m_q.data(), 0, 0, 0, m_numeric);
|
||||
|
||||
m_extractedDataAreDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
typename KLU<MatrixType>::Scalar KLU<MatrixType>::determinant() const
|
||||
{
|
||||
eigen_assert(false && "KLU: extractData Not Yet Implemented");
|
||||
return Scalar();
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename MatrixType>
|
||||
template <typename BDerived, typename XDerived>
|
||||
bool KLU<MatrixType>::_solve_impl(const MatrixBase<BDerived> &b, MatrixBase<XDerived> &x) const {
|
||||
|
||||
@@ -28,9 +28,6 @@ struct traits<PartialPivLU<MatrixType_, PermutationIndex_> > : traits<MatrixType
|
||||
|
||||
template <typename T, typename Derived>
|
||||
struct enable_if_ref;
|
||||
// {
|
||||
// typedef Derived type;
|
||||
// };
|
||||
|
||||
template <typename T, typename Derived>
|
||||
struct enable_if_ref<Ref<T>, Derived> {
|
||||
|
||||
@@ -703,11 +703,6 @@ struct FullPivHouseholderQRMatrixQReturnType
|
||||
typename IntDiagSizeVectorType::Nested m_rowsTranspositions;
|
||||
};
|
||||
|
||||
// template<typename MatrixType>
|
||||
// struct evaluator<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
|
||||
// : public evaluator<ReturnByValue<FullPivHouseholderQRMatrixQReturnType<MatrixType> > >
|
||||
// {};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
template <typename MatrixType, typename PermutationIndex>
|
||||
|
||||
@@ -359,19 +359,6 @@ UpperBidiagonalization<MatrixType_>& UpperBidiagonalization<MatrixType_>::comput
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/** \return the Householder QR decomposition of \c *this.
|
||||
*
|
||||
* \sa class Bidiagonalization
|
||||
*/
|
||||
template<typename Derived>
|
||||
const UpperBidiagonalization<typename MatrixBase<Derived>::PlainObject>
|
||||
MatrixBase<Derived>::bidiagonalization() const
|
||||
{
|
||||
return UpperBidiagonalization<PlainObject>(eval());
|
||||
}
|
||||
#endif
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
@@ -152,17 +152,6 @@ struct sparse_time_dense_product_impl<SparseLhsType, DenseRhsType, DenseResType,
|
||||
}
|
||||
};
|
||||
|
||||
// FIXME: what is the purpose of the following specialization? Is it for the BlockedSparse format?
|
||||
// -> let's disable it for now as it is conflicting with generic scalar*matrix and matrix*scalar operators
|
||||
// template<typename T1, typename T2/*, int Options_, typename StrideType_*/>
|
||||
// struct ScalarBinaryOpTraits<T1, Ref<T2/*, Options_, StrideType_*/> >
|
||||
// {
|
||||
// enum {
|
||||
// Defined = 1
|
||||
// };
|
||||
// typedef typename CwiseUnaryOp<scalar_multiple2_op<T1, typename T2::Scalar>, T2>::PlainObject ReturnType;
|
||||
// };
|
||||
|
||||
// ColMajor, single column (ColPerCol=true): CSC SpMV
|
||||
template <typename SparseLhsType, typename DenseRhsType, typename DenseResType, typename AlphaType>
|
||||
struct sparse_time_dense_product_impl<SparseLhsType, DenseRhsType, DenseResType, AlphaType, ColMajor, true> {
|
||||
|
||||
@@ -301,26 +301,6 @@ friend inline const CwiseBinaryOp<internal::scalar_quotient_op<T, Scalar>, Const
|
||||
const T &s, const StorageBaseType &a);
|
||||
#endif
|
||||
|
||||
// NOTE disabled until we agree on argument order
|
||||
#if 0
|
||||
/** \cpp11 \returns an expression of the coefficient-wise polygamma function.
|
||||
*
|
||||
* \specialfunctions_module
|
||||
*
|
||||
* It returns the \a n -th derivative of the digamma(psi) evaluated at \c *this.
|
||||
*
|
||||
* \warning Be careful with the order of the parameters: x.polygamma(n) is equivalent to polygamma(n,x)
|
||||
*
|
||||
* \sa Eigen::polygamma()
|
||||
*/
|
||||
template<typename DerivedN>
|
||||
inline const CwiseBinaryOp<internal::scalar_polygamma_op<Scalar>, const DerivedN, const Derived>
|
||||
polygamma(const EIGEN_CURRENT_STORAGE_BASE_CLASS<DerivedN> &n) const
|
||||
{
|
||||
return CwiseBinaryOp<internal::scalar_polygamma_op<Scalar>, const DerivedN, const Derived>(n.derived(), this->derived());
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \returns an expression of the coefficient-wise zeta function.
|
||||
*
|
||||
* \specialfunctions_module
|
||||
|
||||
Reference in New Issue
Block a user