Commit 3d61f1db authored by Laszlo Agocs's avatar Laszlo Agocs
Browse files

Make some structs comparable and hashable

Focus on those that are used in combination with the pipeline state
and starting a renderpass.
parent 0856f98d
......@@ -416,6 +416,39 @@ QRhiColorClearValue::QRhiColorClearValue(float r, float g, float b, float a)
{
}
/*!
Returns \c true if the colors in the two QRhiColorClearValue objects \a a
and \a b are equal.
\relates QRhiColorClearValue
*/
bool operator==(const QRhiColorClearValue &a, const QRhiColorClearValue &b) Q_DECL_NOTHROW
{
return a.rgba() == b.rgba();
}
/*!
Returns \c false if the colors in the two QRhiColorClearValue objects \a a
and \a b are equal; otherwise returns \c true.
\relates QRhiColorClearValue
*/
bool operator!=(const QRhiColorClearValue &a, const QRhiColorClearValue &b) Q_DECL_NOTHROW
{
return !(a == b);
}
/*!
Returns the hash value for \a v, using \a seed to seed the calculation.
\relates QRhiColorClearValue
*/
uint qHash(const QRhiColorClearValue &v, uint seed) Q_DECL_NOTHROW
{
const QVector4D c = v.rgba();
return qFloor((c.x() + c.y() + c.z() + c.w()) * 1000) + seed;
}
/*!
\class QRhiDepthStencilClearValue
\inmodule QtRhi
......@@ -442,6 +475,39 @@ QRhiDepthStencilClearValue::QRhiDepthStencilClearValue(float d, quint32 s)
{
}
/*!
Returns \c true if the values in the two QRhiDepthStencilClearValue objects
\a a and \a b are equal.
\relates QRhiDepthStencilClearValue
*/
bool operator==(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) Q_DECL_NOTHROW
{
return a.depthClearValue() == b.depthClearValue()
&& a.stencilClearValue() == b.stencilClearValue();
}
/*!
Returns \c false if the values in the two QRhiDepthStencilClearValue
objects \a a and \a b are equal; otherwise returns \c true.
\relates QRhiDepthStencilClearValue
*/
bool operator!=(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) Q_DECL_NOTHROW
{
return !(a == b);
}
/*!
Returns the hash value for \a v, using \a seed to seed the calculation.
\relates QRhiDepthStencilClearValue
*/
uint qHash(const QRhiDepthStencilClearValue &v, uint seed) Q_DECL_NOTHROW
{
return seed * (qFloor(v.depthClearValue() * 100) + v.stencilClearValue());
}
/*!
\class QRhiViewport
\inmodule QtRhi
......@@ -494,6 +560,41 @@ QRhiViewport::QRhiViewport(float x, float y, float w, float h, float minDepth, f
{
}
/*!
Returns \c true if the values in the two QRhiViewport objects
\a a and \a b are equal.
\relates QRhiViewport
*/
bool operator==(const QRhiViewport &a, const QRhiViewport &b) Q_DECL_NOTHROW
{
return a.viewport() == b.viewport()
&& a.minDepth() == b.minDepth()
&& a.maxDepth() == b.maxDepth();
}
/*!
Returns \c false if the values in the two QRhiViewport
objects \a a and \a b are equal; otherwise returns \c true.
\relates QRhiViewport
*/
bool operator!=(const QRhiViewport &a, const QRhiViewport &b) Q_DECL_NOTHROW
{
return !(a == b);
}
/*!
Returns the hash value for \a v, using \a seed to seed the calculation.
\relates QRhiViewport
*/
uint qHash(const QRhiViewport &v, uint seed) Q_DECL_NOTHROW
{
const QVector4D r = v.viewport();
return seed + r.x() + r.y() + r.z() + r.w() + qFloor(v.minDepth() * 100) + qFloor(v.maxDepth() * 100);
}
/*!
\class QRhiScissor
\inmodule QtRhi
......@@ -527,6 +628,39 @@ QRhiScissor::QRhiScissor(int x, int y, int w, int h)
{
}
/*!
Returns \c true if the values in the two QRhiScissor objects
\a a and \a b are equal.
\relates QRhiScissor
*/
bool operator==(const QRhiScissor &a, const QRhiScissor &b) Q_DECL_NOTHROW
{
return a.scissor() == b.scissor();
}
/*!
Returns \c false if the values in the two QRhiScissor
objects \a a and \a b are equal; otherwise returns \c true.
\relates QRhiScissor
*/
bool operator!=(const QRhiScissor &a, const QRhiScissor &b) Q_DECL_NOTHROW
{
return !(a == b);
}
/*!
Returns the hash value for \a v, using \a seed to seed the calculation.
\relates QRhiScissor
*/
uint qHash(const QRhiScissor &v, uint seed) Q_DECL_NOTHROW
{
const QVector4D r = v.scissor();
return seed + r.x() + r.y() + r.z() + r.w();
}
/*!
\class QRhiVertexInputBinding
\inmodule QtRhi
......@@ -608,6 +742,40 @@ QRhiVertexInputBinding::QRhiVertexInputBinding(quint32 stride, Classification cl
{
}
/*!
Returns \c true if the values in the two QRhiVertexInputBinding objects
\a a and \a b are equal.
\relates QRhiVertexInputBinding
*/
bool operator==(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) Q_DECL_NOTHROW
{
return a.stride() == b.stride()
&& a.classification() == b.classification()
&& a.instanceStepRate() == b.instanceStepRate();
}
/*!
Returns \c false if the values in the two QRhiVertexInputBinding
objects \a a and \a b are equal; otherwise returns \c true.
\relates QRhiVertexInputBinding
*/
bool operator!=(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) Q_DECL_NOTHROW
{
return !(a == b);
}
/*!
Returns the hash value for \a v, using \a seed to seed the calculation.
\relates QRhiVertexInputBinding
*/
uint qHash(const QRhiVertexInputBinding &v, uint seed) Q_DECL_NOTHROW
{
return seed + v.stride() + v.classification();
}
/*!
\class QRhiVertexInputAttribute
\inmodule QtRhi
......@@ -709,6 +877,41 @@ QRhiVertexInputAttribute::QRhiVertexInputAttribute(int binding, int location, Fo
{
}
/*!
Returns \c true if the values in the two QRhiVertexInputAttribute objects
\a a and \a b are equal.
\relates QRhiVertexInputAttribute
*/
bool operator==(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) Q_DECL_NOTHROW
{
return a.binding() == b.binding()
&& a.location() == b.location()
&& a.format() == b.format()
&& a.offset() == b.offset();
}
/*!
Returns \c false if the values in the two QRhiVertexInputAttribute
objects \a a and \a b are equal; otherwise returns \c true.
\relates QRhiVertexInputAttribute
*/
bool operator!=(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) Q_DECL_NOTHROW
{
return !(a == b);
}
/*!
Returns the hash value for \a v, using \a seed to seed the calculation.
\relates QRhiVertexInputAttribute
*/
uint qHash(const QRhiVertexInputAttribute &v, uint seed) Q_DECL_NOTHROW
{
return seed + v.binding() + v.location() + v.format() + v.offset();
}
/*!
\class QRhiVertexInputLayout
\inmodule QtRhi
......@@ -725,6 +928,39 @@ QRhiVertexInputLayout::QRhiVertexInputLayout()
{
}
/*!
Returns \c true if the values in the two QRhiVertexInputLayout objects
\a a and \a b are equal.
\relates QRhiVertexInputLayout
*/
bool operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) Q_DECL_NOTHROW
{
return a.bindings() == b.bindings()
&& a.attributes() == b.attributes();
}
/*!
Returns \c false if the values in the two QRhiVertexInputLayout
objects \a a and \a b are equal; otherwise returns \c true.
\relates QRhiVertexInputLayout
*/
bool operator!=(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) Q_DECL_NOTHROW
{
return !(a == b);
}
/*!
Returns the hash value for \a v, using \a seed to seed the calculation.
\relates QRhiVertexInputLayout
*/
uint qHash(const QRhiVertexInputLayout &v, uint seed) Q_DECL_NOTHROW
{
return qHash(v.bindings(), seed) + qHash(v.attributes(), seed);
}
/*!
\class QRhiGraphicsShaderStage
\inmodule QtRhi
......@@ -761,6 +997,39 @@ QRhiGraphicsShaderStage::QRhiGraphicsShaderStage(Type type, const QBakedShader &
{
}
/*!
Returns \c true if the values in the two QRhiGraphicsShaderStage objects
\a a and \a b are equal.
\relates QRhiGraphicsShaderStage
*/
bool operator==(const QRhiGraphicsShaderStage &a, const QRhiGraphicsShaderStage &b) Q_DECL_NOTHROW
{
return a.type() == b.type()
&& a.shader() == b.shader();
}
/*!
Returns \c false if the values in the two QRhiGraphicsShaderStage
objects \a a and \a b are equal; otherwise returns \c true.
\relates QRhiGraphicsShaderStage
*/
bool operator!=(const QRhiGraphicsShaderStage &a, const QRhiGraphicsShaderStage &b) Q_DECL_NOTHROW
{
return !(a == b);
}
/*!
Returns the hash value for \a v, using \a seed to seed the calculation.
\relates QRhiGraphicsShaderStage
*/
uint qHash(const QRhiGraphicsShaderStage &v, uint seed) Q_DECL_NOTHROW
{
return v.type() + qHash(v.shader(), seed);
}
/*!
\class QRhiColorAttachment
\inmodule QtRhi
......@@ -1927,8 +2196,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture(
objects \a a and \a b are equal.
\relates QRhiShaderResourceBinding
*/
bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
*/
bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW
{
if (a.d == b.d)
return true;
......@@ -1969,13 +2238,18 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
objects \a a and \a b are equal; otherwise returns \c true.
\relates QRhiShaderResourceBinding
*/
bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
*/
bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW
{
return !(a == b);
}
uint qHash(const QRhiShaderResourceBinding &b, uint seed)
/*!
Returns the hash value for \a b, using \a seed to seed the calculation.
\relates QRhiShaderResourceBinding
*/
uint qHash(const QRhiShaderResourceBinding &b, uint seed) Q_DECL_NOTHROW
{
const char *u = reinterpret_cast<const char *>(&b.d->u);
return seed + b.d->binding + 10 * b.d->stage + 100 * b.d->type
......
......@@ -78,6 +78,10 @@ private:
Q_DECLARE_TYPEINFO(QRhiColorClearValue, Q_MOVABLE_TYPE);
Q_RHI_EXPORT bool operator==(const QRhiColorClearValue &a, const QRhiColorClearValue &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT bool operator!=(const QRhiColorClearValue &a, const QRhiColorClearValue &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT uint qHash(const QRhiColorClearValue &v, uint seed = 0) Q_DECL_NOTHROW;
class Q_RHI_EXPORT QRhiDepthStencilClearValue
{
public:
......@@ -97,6 +101,10 @@ private:
Q_DECLARE_TYPEINFO(QRhiDepthStencilClearValue, Q_MOVABLE_TYPE);
Q_RHI_EXPORT bool operator==(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT bool operator!=(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT uint qHash(const QRhiDepthStencilClearValue &v, uint seed = 0) Q_DECL_NOTHROW;
class Q_RHI_EXPORT QRhiViewport
{
public:
......@@ -120,6 +128,10 @@ private:
Q_DECLARE_TYPEINFO(QRhiViewport, Q_MOVABLE_TYPE);
Q_RHI_EXPORT bool operator==(const QRhiViewport &a, const QRhiViewport &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT bool operator!=(const QRhiViewport &a, const QRhiViewport &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT uint qHash(const QRhiViewport &v, uint seed = 0) Q_DECL_NOTHROW;
class Q_RHI_EXPORT QRhiScissor
{
public:
......@@ -135,6 +147,10 @@ private:
Q_DECLARE_TYPEINFO(QRhiScissor, Q_MOVABLE_TYPE);
Q_RHI_EXPORT bool operator==(const QRhiScissor &a, const QRhiScissor &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT bool operator!=(const QRhiScissor &a, const QRhiScissor &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT uint qHash(const QRhiScissor &v, uint seed = 0) Q_DECL_NOTHROW;
class Q_RHI_EXPORT QRhiVertexInputBinding
{
public:
......@@ -164,6 +180,10 @@ private:
Q_DECLARE_TYPEINFO(QRhiVertexInputBinding, Q_MOVABLE_TYPE);
Q_RHI_EXPORT bool operator==(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT bool operator!=(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT uint qHash(const QRhiVertexInputBinding &v, uint seed = 0) Q_DECL_NOTHROW;
class Q_RHI_EXPORT QRhiVertexInputAttribute
{
public:
......@@ -202,6 +222,10 @@ private:
Q_DECLARE_TYPEINFO(QRhiVertexInputAttribute, Q_MOVABLE_TYPE);
Q_RHI_EXPORT bool operator==(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT bool operator!=(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT uint qHash(const QRhiVertexInputAttribute &v, uint seed = 0) Q_DECL_NOTHROW;
class Q_RHI_EXPORT QRhiVertexInputLayout
{
public:
......@@ -221,6 +245,10 @@ private:
Q_DECLARE_TYPEINFO(QRhiVertexInputLayout, Q_MOVABLE_TYPE);
Q_RHI_EXPORT bool operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT bool operator!=(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT uint qHash(const QRhiVertexInputLayout &v, uint seed = 0) Q_DECL_NOTHROW;
class Q_RHI_EXPORT QRhiGraphicsShaderStage
{
public:
......@@ -248,6 +276,10 @@ private:
Q_DECLARE_TYPEINFO(QRhiGraphicsShaderStage, Q_MOVABLE_TYPE);
Q_RHI_EXPORT bool operator==(const QRhiGraphicsShaderStage &a, const QRhiGraphicsShaderStage &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT bool operator!=(const QRhiGraphicsShaderStage &a, const QRhiGraphicsShaderStage &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT uint qHash(const QRhiGraphicsShaderStage &s, uint seed = 0) Q_DECL_NOTHROW;
class Q_RHI_EXPORT QRhiShaderResourceBinding
{
public:
......@@ -277,9 +309,9 @@ public:
private:
QRhiShaderResourceBindingPrivate *d;
friend class QRhiShaderResourceBindingPrivate;
friend Q_RHI_EXPORT bool operator==(const QRhiShaderResourceBinding &, const QRhiShaderResourceBinding &);
friend Q_RHI_EXPORT bool operator!=(const QRhiShaderResourceBinding &, const QRhiShaderResourceBinding &);
friend Q_RHI_EXPORT uint qHash(const QRhiShaderResourceBinding &, uint);
friend Q_RHI_EXPORT bool operator==(const QRhiShaderResourceBinding &, const QRhiShaderResourceBinding &) Q_DECL_NOTHROW;
friend Q_RHI_EXPORT bool operator!=(const QRhiShaderResourceBinding &, const QRhiShaderResourceBinding &) Q_DECL_NOTHROW;
friend Q_RHI_EXPORT uint qHash(const QRhiShaderResourceBinding &, uint) Q_DECL_NOTHROW;
#ifndef QT_NO_DEBUG_STREAM
friend Q_RHI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBinding &);
#endif
......@@ -287,9 +319,9 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiShaderResourceBinding::StageFlags)
Q_RHI_EXPORT bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b);
Q_RHI_EXPORT bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b);
Q_RHI_EXPORT uint qHash(const QRhiShaderResourceBinding &b, uint seed = 0);
Q_RHI_EXPORT bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW;
Q_RHI_EXPORT uint qHash(const QRhiShaderResourceBinding &b, uint seed = 0) Q_DECL_NOTHROW;
#ifndef QT_NO_DEBUG_STREAM
Q_RHI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBinding &);
#endif
......
......@@ -436,6 +436,21 @@ QBakedShader QBakedShader::fromSerialized(const QByteArray &data)
return bs;
}
bool operator==(const QBakedShader &lhs, const QBakedShader &rhs) Q_DECL_NOTHROW
{
return lhs.d->stage == rhs.d->stage
&& lhs.d->shaders == rhs.d->shaders;
// do not bother with desc, if the shader code is the same, the description must match too
}
uint qHash(const QBakedShader &s, uint seed) Q_DECL_NOTHROW
{
uint h = s.stage();
for (auto it = s.d->shaders.constBegin(), itEnd = s.d->shaders.constEnd(); it != itEnd; ++it)
h += qHash(it.key(), seed) + qHash(it.value().shader(), seed);
return h;
}
bool operator==(const QBakedShaderVersion &lhs, const QBakedShaderVersion &rhs) Q_DECL_NOTHROW
{
return lhs.version() == rhs.version() && lhs.flags() == rhs.flags();
......@@ -452,8 +467,12 @@ bool operator==(const QBakedShaderCode &lhs, const QBakedShaderCode &rhs) Q_DECL
return lhs.shader() == rhs.shader() && lhs.entryPoint() == rhs.entryPoint();
}
#ifndef QT_NO_DEBUG_STREAM
uint qHash(const QBakedShaderKey &k, uint seed) Q_DECL_NOTHROW
{
return seed + 10 * k.source() + k.sourceVersion().version() + k.sourceVersion().flags() + k.sourceVariant();
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QBakedShader &bs)
{
const QBakedShaderPrivate *d = bs.d;
......@@ -468,11 +487,6 @@ QDebug operator<<(QDebug dbg, const QBakedShader &bs)
return dbg;
}
uint qHash(const QBakedShaderKey &k, uint seed)
{
return seed + 10 * k.source() + k.sourceVersion().version() + k.sourceVersion().flags() + k.sourceVariant();
}
QDebug operator<<(QDebug dbg, const QBakedShaderKey &k)
{
QDebugStateSaver saver(dbg);
......@@ -488,7 +502,6 @@ QDebug operator<<(QDebug dbg, const QBakedShaderVersion &v)
dbg.nospace() << "Version(" << v.version() << " " << v.flags() << ")";
return dbg;
}
#endif // QT_NO_DEBUG_STREAM
QT_END_NAMESPACE
......@@ -173,11 +173,21 @@ public:
private:
QBakedShaderPrivate *d;
friend struct QBakedShaderPrivate;
friend Q_SHADERTOOLS_EXPORT bool operator==(const QBakedShader &, const QBakedShader &) Q_DECL_NOTHROW;
friend Q_SHADERTOOLS_EXPORT uint qHash(const QBakedShader &, uint) Q_DECL_NOTHROW;
#ifndef QT_NO_DEBUG_STREAM
friend Q_SHADERTOOLS_EXPORT QDebug operator<<(QDebug, const QBakedShader &);
#endif
};
Q_SHADERTOOLS_EXPORT bool operator==(const QBakedShader &lhs, const QBakedShader &rhs) Q_DECL_NOTHROW;
Q_SHADERTOOLS_EXPORT uint qHash(const QBakedShader &s, uint seed = 0) Q_DECL_NOTHROW;
inline bool operator!=(const QBakedShader &lhs, const QBakedShader &rhs) Q_DECL_NOTHROW
{
return !(lhs == rhs);
}
Q_SHADERTOOLS_EXPORT bool operator==(const QBakedShaderVersion &lhs, const QBakedShaderVersion &rhs) Q_DECL_NOTHROW;
Q_SHADERTOOLS_EXPORT bool operator==(const QBakedShaderKey &lhs, const QBakedShaderKey &rhs) Q_DECL_NOTHROW;
Q_SHADERTOOLS_EXPORT bool operator==(const QBakedShaderCode &lhs, const QBakedShaderCode &rhs) Q_DECL_NOTHROW;
......@@ -197,7 +207,7 @@ inline bool operator!=(const QBakedShaderCode &lhs, const QBakedShaderCode &rhs)
return !(lhs == rhs);
}
Q_SHADERTOOLS_EXPORT uint qHash(const QBakedShaderKey &k, uint seed = 0);
Q_SHADERTOOLS_EXPORT uint qHash(const QBakedShaderKey &k, uint seed = 0) Q_DECL_NOTHROW;
#ifndef QT_NO_DEBUG_STREAM
Q_SHADERTOOLS_EXPORT QDebug operator<<(QDebug, const QBakedShader &);
......
......@@ -436,6 +436,7 @@ void tst_QShaderBaker::bakedShaderImplicitSharing()
QCOMPARE(s1.availableShaders().count(), 1);
QVERIFY(s1.availableShaders().contains(QBakedShaderKey(QBakedShaderKey::SpirvShader, QBakedShaderVersion(100))));
QCOMPARE(s0.stage(), s1.stage());
QCOMPARE(s0, s1);
s1.detach();
QVERIFY(QBakedShaderPrivate::get(&s0) != QBakedShaderPrivate::get(&s1));
......@@ -444,6 +445,7 @@ void tst_QShaderBaker::bakedShaderImplicitSharing()
QCOMPARE(s1.availableShaders().count(), 1);
QVERIFY(s1.availableShaders().contains(QBakedShaderKey(QBakedShaderKey::SpirvShader, QBakedShaderVersion(100))));
QCOMPARE(s0.stage(), s1.stage());
QCOMPARE(s0, s1);
}
{
......@@ -465,6 +467,7 @@ void tst_QShaderBaker::bakedShaderImplicitSharing()
QCOMPARE(d1.inputVariables().count(), 2);
QCOMPARE(d1.outputVariables().count(), 1);
QCOMPARE(d1.uniformBlocks().count(), 1);
QVERIFY(s0 != s1);
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment