}
};
-class CPack::PatternMMMM : public DictionaryCompressor::Pattern
+class CPack::PatternMMMM : public MaskedPattern<0xFFFFFFFF>
{
public:
PatternMMMM(const DictionaryEntry bytes, const int match_location)
- : Pattern(MMMM, 0x2, 6, 0, match_location, true) {}
-
- static bool isPattern(const DictionaryEntry& bytes,
- const DictionaryEntry& dict_bytes,
- const int match_location)
- {
- return (bytes == dict_bytes) && (match_location >= 0);
- }
-
- DictionaryEntry
- decompress(const DictionaryEntry dict_bytes) const override
+ : MaskedPattern<0xFFFFFFFF>(MMMM, 0x2, 6, match_location, bytes, true)
{
- return dict_bytes;
}
};
-class CPack::PatternMMXX : public DictionaryCompressor::Pattern
+class CPack::PatternMMXX : public MaskedPattern<0xFFFF0000>
{
- private:
- /**
- * A copy of the unmatched bytes.
- */
- const uint8_t byte0;
- const uint8_t byte1;
-
public:
PatternMMXX(const DictionaryEntry bytes, const int match_location)
- : Pattern(MMXX, 0xC, 8, 2, match_location, true),
- byte0(bytes[0]), byte1(bytes[1]) {}
-
- static bool isPattern(const DictionaryEntry& bytes,
- const DictionaryEntry& dict_bytes,
- const int match_location)
- {
- // Notice we don't compare bytes[0], as otherwise we'd be unnecessarily
- // discarding MMXM. If that pattern is added this should be modified
- return (bytes[3] == dict_bytes[3]) && (bytes[2] == dict_bytes[2]) &&
- (bytes[1] != dict_bytes[1]) && (match_location >= 0);
-
- }
-
- DictionaryEntry
- decompress(const DictionaryEntry dict_bytes) const override
+ : MaskedPattern<0xFFFF0000>(MMXX, 0xC, 8, match_location, bytes, true)
{
- return {byte0, byte1, dict_bytes[2], dict_bytes[3]};
}
};
}
};
-class CPack::PatternMMMX : public DictionaryCompressor::Pattern
+class CPack::PatternMMMX : public MaskedPattern<0xFFFFFF00>
{
- private:
- /**
- * A copy of the unmatched byte.
- */
- const uint8_t byte;
-
public:
PatternMMMX(const DictionaryEntry bytes, const int match_location)
- : Pattern(MMMX, 0xE, 8, 1, match_location, true),
- byte(bytes[0]) {}
-
- static bool isPattern(const DictionaryEntry& bytes,
- const DictionaryEntry& dict_bytes,
- const int match_location)
- {
- return (bytes[3] == dict_bytes[3]) && (bytes[2] == dict_bytes[2]) &&
- (bytes[1] == dict_bytes[1]) && (bytes[0] != dict_bytes[0]) &&
- (match_location >= 0);
- }
-
- DictionaryEntry
- decompress(const DictionaryEntry dict_bytes) const override
+ : MaskedPattern<0xFFFFFF00>(MMMX, 0xE, 8, match_location, bytes, true)
{
- return {byte, dict_bytes[1], dict_bytes[2], dict_bytes[3]};
}
};
class DictionaryCompressor : public BaseDictionaryCompressor
{
protected:
+ /** Convenience typedef for a dictionary entry. */
+ typedef std::array<uint8_t, sizeof(T)> DictionaryEntry;
+
/**
* Compression data for the dictionary compressor. It consists of a vector
* of patterns.
// Forward declaration of a pattern
class Pattern;
class UncompressedPattern;
-
- /** Convenience typedef for a dictionary entry. */
- typedef std::array<uint8_t, sizeof(T)> DictionaryEntry;
+ template <T mask>
+ class MaskedPattern;
/**
* Create a factory to determine if input matches a pattern. The if else
}
};
+/**
+ * A pattern that compares masked values against dictionary entries. If
+ * the masked dictionary entry matches perfectly the masked value to be
+ * compressed, there is a pattern match.
+ *
+ * For example, if the mask is 0xFF00 (that is, this pattern matches the MSB),
+ * the value (V) 0xFF20 is being compressed, and the dictionary contains
+ * the value (D) 0xFF03, this is a match (V & mask == 0xFF00 == D & mask),
+ * and 0x0020 is added to the list of unmatched bits.
+ *
+ * @tparam mask A mask containing the bits that must match.
+ */
+template <class T>
+template <T mask>
+class DictionaryCompressor<T>::MaskedPattern
+ : public DictionaryCompressor<T>::Pattern
+{
+ private:
+ static_assert(mask != 0, "The pattern's value mask must not be zero. Use "
+ "the uncompressed pattern instead.");
+
+ /** A copy of the bits that do not belong to the mask. */
+ const T bits;
+
+ public:
+ MaskedPattern(const int number,
+ const uint64_t code,
+ const uint64_t metadata_length,
+ const int match_location,
+ const DictionaryEntry bytes,
+ const bool allocate = true)
+ : DictionaryCompressor<T>::Pattern(number, code, metadata_length,
+ popCount(~mask) / 8, match_location, allocate),
+ bits(DictionaryCompressor<T>::fromDictionaryEntry(bytes) & ~mask)
+ {
+ }
+
+ static bool
+ isPattern(const DictionaryEntry& bytes, const DictionaryEntry& dict_bytes,
+ const int match_location)
+ {
+ const T masked_bytes =
+ DictionaryCompressor<T>::fromDictionaryEntry(bytes) & mask;
+ const T masked_dict_bytes =
+ DictionaryCompressor<T>::fromDictionaryEntry(dict_bytes) & mask;
+ return (match_location >= 0) && (masked_bytes == masked_dict_bytes);
+ }
+
+ DictionaryEntry
+ decompress(const DictionaryEntry dict_bytes) const override
+ {
+ const T masked_dict_bytes =
+ DictionaryCompressor<T>::fromDictionaryEntry(dict_bytes) & mask;
+ return DictionaryCompressor<T>::toDictionaryEntry(
+ bits | masked_dict_bytes);
+ }
+};
+
#endif //__MEM_CACHE_COMPRESSORS_DICTIONARY_COMPRESSOR_HH__