Convert::equals: move to operator==(PVField&,PVField&)
This commit is contained in:
@@ -15,13 +15,6 @@
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
// PVXXX object comparison
|
||||
|
||||
bool operator==(PVField& left, PVField& right)
|
||||
{
|
||||
return getConvert()->equals(left,right);
|
||||
}
|
||||
|
||||
// Introspection object comparision
|
||||
|
||||
/** Field equality conditions:
|
||||
@@ -101,8 +94,142 @@ bool operator==(const StructureArray& a, const StructureArray& b)
|
||||
return *(a.getStructure().get())==*(b.getStructure().get());
|
||||
}
|
||||
|
||||
namespace nconvert {
|
||||
// PVXXX object comparison
|
||||
|
||||
} // namespace nconvert
|
||||
namespace {
|
||||
|
||||
// fully typed comparisons
|
||||
|
||||
template<typename T>
|
||||
bool compareScalar(PVScalarValue<T>* left, PVScalarValue<T>* right)
|
||||
{
|
||||
return left->get()==right->get();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool compareArray(PVValueArray<T>* left, PVValueArray<T>* right)
|
||||
{
|
||||
return std::equal(left->get(), left->get()+left->getLength(), right->get());
|
||||
}
|
||||
|
||||
// partially typed comparisons
|
||||
|
||||
bool compareField(PVScalar* left, PVScalar* right)
|
||||
{
|
||||
ScalarType lht = left->getScalar()->getScalarType();
|
||||
if(lht != right->getScalar()->getScalarType())
|
||||
return false;
|
||||
switch(lht) {
|
||||
#define OP(ENUM, TYPE) case ENUM: return compareScalar(static_cast<PVScalarValue<TYPE>*>(left), static_cast<PVScalarValue<TYPE>*>(right))
|
||||
OP(pvBoolean, uint8);
|
||||
OP(pvUByte, uint8);
|
||||
OP(pvByte, int8);
|
||||
OP(pvUShort, uint16);
|
||||
OP(pvShort, int16);
|
||||
OP(pvUInt, uint32);
|
||||
OP(pvInt, int32);
|
||||
OP(pvULong, uint64);
|
||||
OP(pvLong, int64);
|
||||
OP(pvFloat, float);
|
||||
OP(pvDouble, double);
|
||||
#undef OP
|
||||
case pvString: {
|
||||
PVString *a=static_cast<PVString*>(left), *b=static_cast<PVString*>(right);
|
||||
return a->get()==b->get();
|
||||
}
|
||||
}
|
||||
throw std::logic_error("PVScalar with invalid scalar type!");
|
||||
}
|
||||
|
||||
bool compareField(PVScalarArray* left, PVScalarArray* right)
|
||||
{
|
||||
ScalarType lht = left->getScalarArray()->getElementType();
|
||||
if(lht != right->getScalarArray()->getElementType())
|
||||
return false;
|
||||
|
||||
if(left->getLength()!=right->getLength())
|
||||
return false;
|
||||
|
||||
switch(lht) {
|
||||
#define OP(ENUM, TYPE) case ENUM: return compareArray(static_cast<PVValueArray<TYPE>*>(left), static_cast<PVValueArray<TYPE>*>(right))
|
||||
OP(pvBoolean, uint8);
|
||||
OP(pvUByte, uint8);
|
||||
OP(pvByte, int8);
|
||||
OP(pvUShort, uint16);
|
||||
OP(pvShort, int16);
|
||||
OP(pvUInt, uint32);
|
||||
OP(pvInt, int32);
|
||||
OP(pvULong, uint64);
|
||||
OP(pvLong, int64);
|
||||
OP(pvFloat, float);
|
||||
OP(pvDouble, double);
|
||||
OP(pvString, String);
|
||||
#undef OP
|
||||
}
|
||||
throw std::logic_error("PVScalarArray with invalid element type!");
|
||||
}
|
||||
|
||||
bool compareField(PVStructure* left, PVStructure* right)
|
||||
{
|
||||
if(left->getStructure()!=right->getStructure())
|
||||
return false;
|
||||
|
||||
const PVFieldPtrArray& lf = left->getPVFields();
|
||||
const PVFieldPtrArray& rf = right->getPVFields();
|
||||
|
||||
for(size_t i=0, nfld=left->getNumberFields(); i<nfld; i++) {
|
||||
if(*lf[i]!=*rf[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool compareField(PVStructureArray* left, PVStructureArray* right)
|
||||
{
|
||||
if(left->getLength()!=right->getLength())
|
||||
return false;
|
||||
|
||||
StructureConstPtr ls = left->getStructureArray()->getStructure();
|
||||
|
||||
if(*ls!=*right->getStructureArray()->getStructure())
|
||||
return false;
|
||||
|
||||
const PVStructureArray::pointer ld=left->get(), rd=right->get();
|
||||
|
||||
for(size_t i=0, ilen=left->getLength(); i<ilen; i++)
|
||||
{
|
||||
const PVFieldPtrArray& lf = ld[i]->getPVFields();
|
||||
const PVFieldPtrArray& rf = rd[i]->getPVFields();
|
||||
|
||||
for(size_t k=0, klen=ls->getNumberFields(); k<klen; k++)
|
||||
{
|
||||
if(*lf[i]!=*rf[i])
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
// untyped comparison
|
||||
|
||||
bool operator==(PVField& left, PVField& right)
|
||||
{
|
||||
if(&left == &right)
|
||||
return true;
|
||||
|
||||
Type lht = left.getField()->getType();
|
||||
if(lht != right.getField()->getType())
|
||||
return false;
|
||||
|
||||
switch(lht) {
|
||||
case scalar: return compareField(static_cast<PVScalar*>(&left), static_cast<PVScalar*>(&right));
|
||||
case scalarArray: return compareField(static_cast<PVScalarArray*>(&left), static_cast<PVScalarArray*>(&right));
|
||||
case structure: return compareField(static_cast<PVStructure*>(&left), static_cast<PVStructure*>(&right));
|
||||
case structureArray: return compareField(static_cast<PVStructureArray*>(&left), static_cast<PVStructureArray*>(&right));
|
||||
}
|
||||
throw std::logic_error("PVField with invalid type!");
|
||||
}
|
||||
|
||||
}} // namespace epics::pvData
|
||||
|
||||
@@ -330,7 +330,6 @@ void Convert::fromDouble(PVScalarPtr const &pv, double from)
|
||||
}
|
||||
|
||||
|
||||
static bool convertEquals(PVField *a,PVField *b);
|
||||
static size_t convertFromByteArray(PVScalarArray * pv, size_t offset,
|
||||
size_t len,const int8 from[], size_t fromOffset);
|
||||
static size_t convertToByteArray(PVScalarArray *pv, size_t offset,
|
||||
@@ -421,16 +420,6 @@ Convert::Convert()
|
||||
|
||||
Convert::~Convert(){}
|
||||
|
||||
bool Convert::equals(PVFieldPtr const &a,PVFieldPtr const &b)
|
||||
{
|
||||
return convertEquals(a.get(),b.get());
|
||||
}
|
||||
|
||||
bool Convert::equals(PVField &a,PVField &b)
|
||||
{
|
||||
return convertEquals(&a,&b);
|
||||
}
|
||||
|
||||
void Convert::getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel)
|
||||
{
|
||||
convertToString(buf,pvField.get(),indentLevel);
|
||||
@@ -1329,341 +1318,6 @@ void Convert::newLine(StringBuilder buffer, int indentLevel)
|
||||
newLineImpl(buffer,indentLevel);
|
||||
}
|
||||
|
||||
static bool scalarEquals(PVScalar *a,PVScalar *b)
|
||||
{
|
||||
ScalarType ascalarType = a->getScalar()->getScalarType();
|
||||
ScalarType bscalarType = b->getScalar()->getScalarType();
|
||||
if(ascalarType!=bscalarType) return false;
|
||||
switch(ascalarType) {
|
||||
case pvBoolean: {
|
||||
PVBoolean *pa = static_cast<PVBoolean *>(a);
|
||||
PVBoolean *pb = static_cast<PVBoolean *>(b);
|
||||
bool avalue = pa->get();
|
||||
bool bvalue = pb->get();
|
||||
return ((avalue==bvalue) ? true : false);
|
||||
}
|
||||
case pvByte: {
|
||||
PVByte *pa = static_cast<PVByte *>(a);
|
||||
PVByte *pb = static_cast<PVByte *>(b);
|
||||
int8 avalue = pa->get();
|
||||
int8 bvalue = pb->get();
|
||||
return ((avalue==bvalue) ? true : false);
|
||||
}
|
||||
case pvShort: {
|
||||
PVShort *pa = static_cast<PVShort *>(a);
|
||||
PVShort *pb = static_cast<PVShort *>(b);
|
||||
int16 avalue = pa->get();
|
||||
int16 bvalue = pb->get();
|
||||
return ((avalue==bvalue) ? true : false);
|
||||
}
|
||||
case pvInt: {
|
||||
PVInt *pa = static_cast<PVInt *>(a);
|
||||
PVInt *pb = static_cast<PVInt *>(b);
|
||||
int32 avalue = pa->get();
|
||||
int32 bvalue = pb->get();
|
||||
return ((avalue==bvalue) ? true : false);
|
||||
}
|
||||
case pvLong: {
|
||||
PVLong *pa = static_cast<PVLong *>(a);
|
||||
PVLong *pb = static_cast<PVLong *>(b);
|
||||
int64 avalue = pa->get();
|
||||
int64 bvalue = pb->get();
|
||||
return ((avalue==bvalue) ? true : false);
|
||||
}
|
||||
case pvUByte: {
|
||||
PVUByte *pa = static_cast<PVUByte *>(a);
|
||||
PVUByte *pb = static_cast<PVUByte *>(b);
|
||||
uint8 avalue = pa->get();
|
||||
uint8 bvalue = pb->get();
|
||||
return ((avalue==bvalue) ? true : false);
|
||||
}
|
||||
case pvUShort: {
|
||||
PVUShort *pa = static_cast<PVUShort *>(a);
|
||||
PVUShort *pb = static_cast<PVUShort *>(b);
|
||||
uint16 avalue = pa->get();
|
||||
uint16 bvalue = pb->get();
|
||||
return ((avalue==bvalue) ? true : false);
|
||||
}
|
||||
case pvUInt: {
|
||||
PVUInt *pa = static_cast<PVUInt *>(a);
|
||||
PVUInt *pb = static_cast<PVUInt *>(b);
|
||||
uint32 avalue = pa->get();
|
||||
uint32 bvalue = pb->get();
|
||||
return ((avalue==bvalue) ? true : false);
|
||||
}
|
||||
case pvULong: {
|
||||
PVULong *pa = static_cast<PVULong *>(a);
|
||||
PVULong *pb = static_cast<PVULong *>(b);
|
||||
uint64 avalue = pa->get();
|
||||
uint64 bvalue = pb->get();
|
||||
return ((avalue==bvalue) ? true : false);
|
||||
}
|
||||
case pvFloat: {
|
||||
PVFloat *pa = static_cast<PVFloat *>(a);
|
||||
PVFloat *pb = static_cast<PVFloat *>(b);
|
||||
float avalue = pa->get();
|
||||
float bvalue = pb->get();
|
||||
return ((avalue==bvalue) ? true : false);
|
||||
}
|
||||
case pvDouble: {
|
||||
PVDouble *pa = static_cast<PVDouble *>(a);
|
||||
PVDouble *pb = static_cast<PVDouble *>(b);
|
||||
double avalue = pa->get();
|
||||
double bvalue = pb->get();
|
||||
return ((avalue==bvalue) ? true : false);
|
||||
}
|
||||
case pvString: {
|
||||
PVString *pa = static_cast<PVString *>(a);
|
||||
PVString *pb = static_cast<PVString *>(b);
|
||||
String avalue = pa->get();
|
||||
String bvalue = pb->get();
|
||||
return ((avalue==bvalue) ? true : false);
|
||||
}
|
||||
}
|
||||
String message("should not get here");
|
||||
throw std::logic_error(message);
|
||||
}
|
||||
|
||||
static bool arrayEquals(PVScalarArray *a,PVScalarArray *b)
|
||||
{
|
||||
if(a==b) return true;
|
||||
ScalarType aType = a->getScalarArray()->getElementType();
|
||||
ScalarType bType = b->getScalarArray()->getElementType();
|
||||
if(aType!=bType) return false;
|
||||
if(a->getLength()!=b->getLength()) return false;
|
||||
size_t length = a->getLength();
|
||||
switch(aType) {
|
||||
case pvBoolean: {
|
||||
PVBooleanArray *aarray = static_cast<PVBooleanArray *>(a);
|
||||
PVBooleanArray *barray = static_cast<PVBooleanArray *>(b);
|
||||
BooleanArrayData adata;
|
||||
BooleanArrayData bdata;
|
||||
aarray->get(0,length,adata);
|
||||
barray->get(0,length,bdata);
|
||||
BooleanArray & avalue = adata.data;
|
||||
BooleanArray & bvalue = bdata.data;
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(avalue[i]!=bvalue[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case pvByte: {
|
||||
PVByteArray *aarray = static_cast<PVByteArray *>(a);
|
||||
PVByteArray *barray = static_cast<PVByteArray *>(b);
|
||||
ByteArrayData adata;
|
||||
ByteArrayData bdata;
|
||||
aarray->get(0,length,adata);
|
||||
barray->get(0,length,bdata);
|
||||
ByteArray & avalue = adata.data;
|
||||
ByteArray & bvalue = bdata.data;
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(avalue[i]!=bvalue[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case pvShort: {
|
||||
PVShortArray *aarray = static_cast<PVShortArray *>(a);
|
||||
PVShortArray *barray = static_cast<PVShortArray *>(b);
|
||||
ShortArrayData adata;
|
||||
ShortArrayData bdata;
|
||||
aarray->get(0,length,adata);
|
||||
barray->get(0,length,bdata);
|
||||
ShortArray & avalue = adata.data;
|
||||
ShortArray & bvalue = bdata.data;
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(avalue[i]!=bvalue[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case pvInt: {
|
||||
PVIntArray *aarray = static_cast<PVIntArray *>(a);
|
||||
PVIntArray *barray = static_cast<PVIntArray *>(b);
|
||||
IntArrayData adata;
|
||||
IntArrayData bdata;
|
||||
aarray->get(0,length,adata);
|
||||
barray->get(0,length,bdata);
|
||||
IntArray & avalue = adata.data;
|
||||
IntArray & bvalue = bdata.data;
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(avalue[i]!=bvalue[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case pvLong: {
|
||||
PVLongArray *aarray = static_cast<PVLongArray *>(a);
|
||||
PVLongArray *barray = static_cast<PVLongArray *>(b);
|
||||
LongArrayData adata;
|
||||
LongArrayData bdata;
|
||||
aarray->get(0,length,adata);
|
||||
barray->get(0,length,bdata);
|
||||
LongArray & avalue = adata.data;
|
||||
LongArray & bvalue = bdata.data;
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(avalue[i]!=bvalue[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case pvUByte: {
|
||||
PVUByteArray *aarray = static_cast<PVUByteArray *>(a);
|
||||
PVUByteArray *barray = static_cast<PVUByteArray *>(b);
|
||||
UByteArrayData adata;
|
||||
UByteArrayData bdata;
|
||||
aarray->get(0,length,adata);
|
||||
barray->get(0,length,bdata);
|
||||
UByteArray & avalue = adata.data;
|
||||
UByteArray & bvalue = bdata.data;
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(avalue[i]!=bvalue[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case pvUShort: {
|
||||
PVUShortArray *aarray = static_cast<PVUShortArray *>(a);
|
||||
PVUShortArray *barray = static_cast<PVUShortArray *>(b);
|
||||
UShortArrayData adata;
|
||||
UShortArrayData bdata;
|
||||
aarray->get(0,length,adata);
|
||||
barray->get(0,length,bdata);
|
||||
UShortArray & avalue = adata.data;
|
||||
UShortArray & bvalue = bdata.data;
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(avalue[i]!=bvalue[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case pvUInt: {
|
||||
PVUIntArray *aarray = static_cast<PVUIntArray *>(a);
|
||||
PVUIntArray *barray = static_cast<PVUIntArray *>(b);
|
||||
UIntArrayData adata;
|
||||
UIntArrayData bdata;
|
||||
aarray->get(0,length,adata);
|
||||
barray->get(0,length,bdata);
|
||||
UIntArray & avalue = adata.data;
|
||||
UIntArray & bvalue = bdata.data;
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(avalue[i]!=bvalue[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case pvULong: {
|
||||
PVULongArray *aarray = static_cast<PVULongArray *>(a);
|
||||
PVULongArray *barray = static_cast<PVULongArray *>(b);
|
||||
ULongArrayData adata;
|
||||
ULongArrayData bdata;
|
||||
aarray->get(0,length,adata);
|
||||
barray->get(0,length,bdata);
|
||||
ULongArray & avalue = adata.data;
|
||||
ULongArray & bvalue = bdata.data;
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(avalue[i]!=bvalue[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case pvFloat: {
|
||||
PVFloatArray *aarray = static_cast<PVFloatArray *>(a);
|
||||
PVFloatArray *barray = static_cast<PVFloatArray *>(b);
|
||||
FloatArrayData adata;
|
||||
FloatArrayData bdata;
|
||||
aarray->get(0,length,adata);
|
||||
barray->get(0,length,bdata);
|
||||
FloatArray & avalue = adata.data;
|
||||
FloatArray & bvalue = bdata.data;
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(avalue[i]!=bvalue[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case pvDouble: {
|
||||
PVDoubleArray *aarray = static_cast<PVDoubleArray *>(a);
|
||||
PVDoubleArray *barray = static_cast<PVDoubleArray *>(b);
|
||||
DoubleArrayData adata;
|
||||
DoubleArrayData bdata;
|
||||
aarray->get(0,length,adata);
|
||||
barray->get(0,length,bdata);
|
||||
DoubleArray & avalue = adata.data;
|
||||
DoubleArray & bvalue = bdata.data;
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(avalue[i]!=bvalue[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case pvString: {
|
||||
PVStringArray *aarray = static_cast<PVStringArray *>(a);
|
||||
PVStringArray *barray = static_cast<PVStringArray *>(b);
|
||||
StringArrayData adata;
|
||||
StringArrayData bdata;
|
||||
aarray->get(0,length,adata);
|
||||
barray->get(0,length,bdata);
|
||||
StringArray & avalue = adata.data;
|
||||
StringArray & bvalue = bdata.data;
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(avalue[i]!=bvalue[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
String message("should not get here");
|
||||
throw std::logic_error(message);
|
||||
}
|
||||
|
||||
static bool structureArrayEquals(PVStructureArray *a,PVStructureArray *b)
|
||||
{
|
||||
StructureConstPtr aStructure = a->getStructureArray()->getStructure();
|
||||
StructureConstPtr bStructure = b->getStructureArray()->getStructure();
|
||||
if(aStructure!=bStructure) return false;
|
||||
if(a->getLength()!=b->getLength()) return false;
|
||||
StructureArrayData aData = StructureArrayData();
|
||||
StructureArrayData bData = StructureArrayData();
|
||||
size_t length = a->getLength();
|
||||
PVStructurePtrArray & aArray = aData.data;
|
||||
PVStructurePtrArray & bArray = bData.data;
|
||||
if(aArray==bArray) return true;
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(aArray[i]==0) {
|
||||
if(bArray[i]==0) continue;
|
||||
return false;
|
||||
} else {
|
||||
if(bArray[i]==0) return false;
|
||||
}
|
||||
if(*aArray[i]!=*bArray[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool structureEquals(PVStructure *a,PVStructure *b)
|
||||
{
|
||||
StructureConstPtr aStructure = a->getStructure();
|
||||
StructureConstPtr bStructure = b->getStructure();
|
||||
size_t length = aStructure->getNumberFields();
|
||||
if(length!=bStructure->getNumberFields()) return false;
|
||||
PVFieldPtrArray const & aFields = a->getPVFields();
|
||||
PVFieldPtrArray const & bFields = b->getPVFields();
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(*aFields[i]!=*bFields[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool convertEquals(PVField *a,PVField *b)
|
||||
{
|
||||
void * avoid = static_cast<void *>(a);
|
||||
void * bvoid = static_cast<void *>(b);
|
||||
if(avoid==bvoid) return true;
|
||||
Type atype = a->getField()->getType();
|
||||
Type btype = b->getField()->getType();
|
||||
if(atype!=btype) return false;
|
||||
if(atype==scalar) return scalarEquals(
|
||||
static_cast<PVScalar *>(a),static_cast<PVScalar *>(b));
|
||||
if(atype==scalarArray) return arrayEquals(
|
||||
static_cast<PVScalarArray*>(a),static_cast<PVScalarArray *>(b));
|
||||
if(atype==structureArray) return structureArrayEquals(
|
||||
static_cast<PVStructureArray *>(a),static_cast<PVStructureArray *>(b));
|
||||
if(atype==structure) return structureEquals(
|
||||
static_cast<PVStructure *>(a),static_cast<PVStructure *>(b));
|
||||
String message("should not get here");
|
||||
throw std::logic_error(message);
|
||||
}
|
||||
|
||||
template<typename PVT,typename T>
|
||||
size_t convertFromScalarArray(PVScalarArray *pv,
|
||||
size_t offset, size_t len,const T from[], size_t fromOffset)
|
||||
|
||||
@@ -89,7 +89,11 @@ public:
|
||||
* @param Second field
|
||||
* @return (false, true) if the fields (are not, are) the same.
|
||||
*/
|
||||
bool equals(PVFieldPtr const &a,PVFieldPtr const &b);
|
||||
bool equals(PVFieldPtr const &a,PVFieldPtr const &b)
|
||||
{
|
||||
return *a==*b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do fields have the same definition.
|
||||
*
|
||||
@@ -97,7 +101,11 @@ public:
|
||||
* @param Second field
|
||||
* @return (false, true) if the fields (are not, are) the same.
|
||||
*/
|
||||
bool equals(PVField &a,PVField &b);
|
||||
bool equals(PVField &a,PVField &b)
|
||||
{
|
||||
return a==b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a PVField to a string.
|
||||
* @param buf buffer for the result
|
||||
|
||||
Reference in New Issue
Block a user