Browse Source

Merge pull request #10670 from richardkchapman/record-compare-memcmp

HPCC-18779 Add canMemCmp() method to RtlTypeInfo classes

Reviewed-by: Gavin Halliday <ghalliday@hpccsystems.com>
Gavin Halliday 7 years ago
parent
commit
7d9d521b5f
3 changed files with 60 additions and 9 deletions
  1. 50 8
      rtl/eclrtl/rtlfield.cpp
  2. 9 1
      rtl/eclrtl/rtlfield.hpp
  3. 1 0
      rtl/include/eclhelper.hpp

+ 50 - 8
rtl/eclrtl/rtlfield.cpp

@@ -485,6 +485,15 @@ int RtlIntTypeInfo::compare(const byte * left, const byte * right) const
     }
 }
 
+bool RtlIntTypeInfo::canMemCmp() const
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    return false;
+#else
+    return isUnsigned();
+#endif
+}
+
 unsigned RtlIntTypeInfo::hash(const byte *self, unsigned inhash) const
 {
     __int64 val = getInt(self);
@@ -706,6 +715,15 @@ int RtlSwapIntTypeInfo::compare(const byte * left, const byte * right) const
     }
 }
 
+bool RtlSwapIntTypeInfo::canMemCmp() const
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    return isUnsigned();
+#else
+    return false;
+#endif
+}
+
 unsigned RtlSwapIntTypeInfo::hash(const byte *self, unsigned inhash) const
 {
     __int64 val = getInt(self);
@@ -1203,10 +1221,14 @@ __int64 RtlStringTypeInfo::getInt(const void * ptr) const
 
 int RtlStringTypeInfo::compare(const byte * left, const byte * right) const
 {
-    if (isEbcdic())
+    if (isFixedSize())
+        return memcmp(left, right, length);
+    else if (isEbcdic())
     {
-        if (isFixedSize())
-            return rtlCompareEStrEStr(length, (const char *)left, length, (const char *)right);
+        // Logically this should be
+        // if (isFixedSize())
+        //    return rtlCompareEStrEStr(length, (const char *)left, length, (const char *)right);
+        // but that's the same as a memcmp if lengths match
 
         size32_t lenLeft = rtlReadSize32t(left);
         size32_t lenRight = rtlReadSize32t(right);
@@ -1214,8 +1236,10 @@ int RtlStringTypeInfo::compare(const byte * left, const byte * right) const
     }
     else
     {
-        if (isFixedSize())
-            return rtlCompareStrStr(length, (const char *)left, length, (const char *)right);
+        // Logically this should be
+        // if (isFixedSize())
+        //    return rtlCompareStrStr(length, (const char *)left, length, (const char *)right);  // Actually this is a memcmp
+        // but that's the same as a memcmp if lengths match
 
         size32_t lenLeft = rtlReadSize32t(left);
         size32_t lenRight = rtlReadSize32t(right);
@@ -1223,6 +1247,11 @@ int RtlStringTypeInfo::compare(const byte * left, const byte * right) const
     }
 }
 
+bool RtlStringTypeInfo::canMemCmp() const
+{
+    return isFixedSize();
+}
+
 unsigned RtlStringTypeInfo::hash(const byte * self, unsigned inhash) const
 {
     size32_t len;
@@ -1409,13 +1438,20 @@ __int64 RtlDataTypeInfo::getInt(const void * ptr) const
 int RtlDataTypeInfo::compare(const byte * left, const byte * right) const
 {
     if (isFixedSize())
-        return rtlCompareDataData(length, (const char *)left, length, (const char *)right);
+        // Logically this should be return rtlCompareDataData(length, (const char *)left, length, (const char *)right);
+        // but that acts as a memcmp if lengths match
+        return memcmp(left, right, length);
 
     size32_t lenLeft = rtlReadSize32t(left);
     size32_t lenRight = rtlReadSize32t(right);
     return rtlCompareDataData(lenLeft, (const char *)left + sizeof(size32_t), lenRight, (const char *)right + sizeof(size32_t));
 }
 
+bool RtlDataTypeInfo::canMemCmp() const
+{
+    return isFixedSize();
+}
+
 unsigned RtlDataTypeInfo::hash(const byte *self, unsigned inhash) const
 {
     size32_t len;
@@ -1568,7 +1604,6 @@ void RtlVarStringTypeInfo::readAhead(IRowDeserializerSource & in) const
     }
 }
 
-
 void RtlVarStringTypeInfo::getString(size32_t & resultLen, char * & result, const void * ptr) const
 {
     const char * str = (const char *)ptr;
@@ -1774,13 +1809,20 @@ __int64 RtlQStringTypeInfo::getInt(const void * ptr) const
 int RtlQStringTypeInfo::compare(const byte * left, const byte * right) const
 {
     if (isFixedSize())
-        return rtlCompareQStrQStr(length, left, length, right);
+        // Logically this should be return rtlCompareQStrQStr(length, left, length, right);
+        // but that acts as a memcmp if lengths match
+        return memcmp(left, right, length);
 
     size32_t lenLeft = rtlReadSize32t(left);
     size32_t lenRight = rtlReadSize32t(right);
     return rtlCompareQStrQStr(lenLeft, left + sizeof(size32_t), lenRight, right + sizeof(size32_t));
 }
 
+bool RtlQStringTypeInfo::canMemCmp() const
+{
+    return isFixedSize();
+}
+
 unsigned RtlQStringTypeInfo::hash(const byte * self, unsigned inhash) const
 {
     rtlDataAttr val;

+ 9 - 1
rtl/eclrtl/rtlfield.hpp

@@ -53,6 +53,7 @@ struct ECLRTL_API RtlTypeInfoBase : public RtlTypeInfo
     virtual bool isNumeric() const override { return false; }
     virtual bool canTruncate() const override { return false; }
     virtual bool canExtend(char &) const override { return false; }
+    virtual bool canMemCmp() const override { return false; }
 
     virtual const char * queryLocale() const override;
     virtual const RtlFieldInfo * const * queryFields() const override;
@@ -82,6 +83,7 @@ struct ECLRTL_API RtlBoolTypeInfo : public RtlTypeInfoBase
     virtual void getUtf8(size32_t & resultLen, char * & result, const void * ptr) const override;
     virtual __int64 getInt(const void * ptr) const override;
     virtual int compare(const byte * left, const byte * right) const override;
+    virtual bool canMemCmp() const override { return true; }
     virtual unsigned hash(const byte *self, unsigned inhash) const override;
 protected:
     bool getBool(const void * ptr) const;
@@ -110,7 +112,6 @@ private:
     inline double value(const void * self) const;
 };
 
-//MORE: Create specialist versions
 struct ECLRTL_API RtlIntTypeInfo : public RtlTypeInfoBase
 {
     constexpr inline RtlIntTypeInfo(unsigned _fieldType, unsigned _length) : RtlTypeInfoBase(_fieldType, _length) {}
@@ -131,6 +132,7 @@ struct ECLRTL_API RtlIntTypeInfo : public RtlTypeInfoBase
     virtual bool canExtend(char &fillChar) const override;
     virtual bool isNumeric() const override { return true; }
     virtual int compare(const byte * left, const byte * right) const override;
+    virtual bool canMemCmp() const override;
     virtual unsigned hash(const byte *self, unsigned inhash) const override;
 };
 
@@ -190,6 +192,7 @@ struct ECLRTL_API RtlSwapIntTypeInfo : public RtlTypeInfoBase
     virtual bool canExtend(char &fillChar) const override;
     virtual bool isNumeric() const override { return true; }
     virtual int compare(const byte * left, const byte * right) const override;
+    virtual bool canMemCmp() const override;
     virtual unsigned hash(const byte *self, unsigned inhash) const override;
 };
 
@@ -211,6 +214,7 @@ struct ECLRTL_API RtlKeyedIntTypeInfo final : public RtlTypeInfoBase
     virtual double getReal(const void * ptr) const override;
     virtual bool isNumeric() const override { return true; }
     virtual int compare(const byte * left, const byte * right) const override;
+    virtual bool canMemCmp() const override { return true; }
     virtual unsigned hash(const byte *self, unsigned inhash) const override;
 private:
     inline __uint64 getUInt(const void * ptr) const { return (__uint64) getInt(ptr); }
@@ -265,6 +269,7 @@ struct ECLRTL_API RtlStringTypeInfo : public RtlTypeInfoBase
     virtual bool canTruncate() const override { return isFixedSize(); }
     virtual bool canExtend(char &fillChar) const override;
     virtual int compare(const byte * left, const byte * right) const override;
+    virtual bool canMemCmp() const override;
     virtual unsigned hash(const byte * self, unsigned inhash) const override;
 };
 
@@ -288,6 +293,7 @@ struct ECLRTL_API RtlDataTypeInfo : public RtlTypeInfoBase
     virtual bool canTruncate() const override { return isFixedSize(); }
     virtual bool canExtend(char &fillChar) const override;
     virtual int compare(const byte * left, const byte * right) const override;
+    virtual bool canMemCmp() const override;
     virtual unsigned hash(const byte *self, unsigned inhash) const override;
 };
 
@@ -332,6 +338,7 @@ struct ECLRTL_API RtlQStringTypeInfo : public RtlTypeInfoBase
     virtual __int64 getInt(const void * ptr) const override;
     virtual bool canExtend(char &fillChar) const override;
     virtual int compare(const byte * left, const byte * right) const override;
+    virtual bool canMemCmp() const override;
     virtual unsigned hash(const byte * self, unsigned inhash) const override;
 };
 
@@ -372,6 +379,7 @@ struct ECLRTL_API RtlCharTypeInfo : public RtlTypeInfoBase
     virtual void getUtf8(size32_t & resultLen, char * & result, const void * ptr) const override;
     virtual __int64 getInt(const void * ptr) const override;
     virtual int compare(const byte * left, const byte * right) const override;
+    virtual bool canMemCmp() const override { return true; }
     virtual unsigned hash(const byte *self, unsigned inhash) const override;
 };
 

+ 1 - 0
rtl/include/eclhelper.hpp

@@ -419,6 +419,7 @@ struct RtlTypeInfo : public RtlITypeInfo
     virtual bool isNumeric() const = 0;
     virtual bool canTruncate() const = 0;
     virtual bool canExtend(char &) const = 0;
+    virtual bool canMemCmp() const = 0;
 
     virtual void doDelete() const = 0;  // Used in place of virtual destructor to allow constexpr constructors.
 public: