Hi all,
  the attached patch improves CharacterSet by adding a subtraction
operator, equality test and associated unit tests.

-- 
    Francesco
=== modified file 'src/base/CharacterSet.cc'
--- src/base/CharacterSet.cc	2015-12-23 20:46:09 +0000
+++ src/base/CharacterSet.cc	2015-12-26 15:18:05 +0000
@@ -10,48 +10,73 @@
 #include "CharacterSet.h"
 
 #include <algorithm>
 #include <functional>
 
 CharacterSet &
 CharacterSet::operator +=(const CharacterSet &src)
 {
     Storage::const_iterator s = src.chars_.begin();
     const Storage::const_iterator e = src.chars_.end();
     Storage::iterator d = chars_.begin();
     while (s != e) {
         if (*s)
             *d = 1;
         ++s;
         ++d;
     }
     return *this;
 }
 
+CharacterSet &
+CharacterSet::operator -=(const CharacterSet &src)
+{
+    Storage::const_iterator s = src.chars_.begin();
+    const Storage::const_iterator e = src.chars_.end();
+    Storage::iterator d = chars_.begin();
+    while (s != e) {
+        if (*s)
+            *d = 0;
+        ++s;
+        ++d;
+    }
+    return *this;
+}
+
+
 CharacterSet
 CharacterSet::operator +(const CharacterSet &src) const
 {
     CharacterSet rv(*this);
     rv += src;
     return rv;
 }
 
+CharacterSet
+CharacterSet::operator -(const CharacterSet &src) const
+{
+    CharacterSet rv(*this);
+    rv -= src;
+    return rv;
+}
+
+
 CharacterSet &
 CharacterSet::add(const unsigned char c)
 {
     chars_[static_cast<uint8_t>(c)] = 1;
     return *this;
 }
 
 CharacterSet &
 CharacterSet::addRange(unsigned char low, unsigned char high)
 {
     //manual loop splitting is needed to cover case where high is 255
     // otherwise low will wrap, resulting in infinite loop
     while (low < high) {
         chars_[static_cast<uint8_t>(low)] = 1;
         ++low;
     }
     chars_[static_cast<uint8_t>(high)] = 1;
     return *this;
 }
 
@@ -72,40 +97,53 @@ CharacterSet::CharacterSet(const char *l
     const size_t clen = strlen(c);
     for (size_t i = 0; i < clen; ++i)
         add(c[i]);
 }
 
 CharacterSet::CharacterSet(const char *label, unsigned char low, unsigned char high) :
     name(label == NULL ? "anonymous" : label),
     chars_(Storage(256,0))
 {
     addRange(low,high);
 }
 
 CharacterSet::CharacterSet(const char *label, std::initializer_list<std::pair<uint8_t, uint8_t>> ranges) :
     name(label == NULL ? "anonymous" : label),
     chars_(Storage(256,0))
 {
     for (auto range: ranges)
         addRange(range.first, range.second);
 }
 
+bool
+CharacterSet::operator ==(const CharacterSet &c) const
+{
+    if (this == &c) // identity test
+        return true;
+    auto e=chars_.cend();
+    for (auto i = chars_.cbegin(), j = c.chars_.cbegin(); i != e; ++i, ++j) {
+        if (*i != *j)
+            return false;
+    }
+    return true;
+}
+
 const CharacterSet
 // RFC 5234
     CharacterSet::ALPHA("ALPHA", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"),
     CharacterSet::BIT("BIT","01"),
     CharacterSet::CR("CR","\r"),
     CharacterSet::CTL("CTL",{{0x01,0x1f},{0x7f,0x7f}}),
     CharacterSet::DIGIT("DIGIT","0123456789"),
     CharacterSet::DQUOTE("DQUOTE","\""),
     CharacterSet::HEXDIG("HEXDIG","0123456789aAbBcCdDeEfF"),
     CharacterSet::HTAB("HTAB","\t"),
     CharacterSet::LF("LF","\n"),
     CharacterSet::SP("SP"," "),
     CharacterSet::VCHAR("VCHAR", 0x21, 0x7e),
     // RFC 7230
     CharacterSet::WSP("WSP"," \t"),
     CharacterSet::CTEXT("ctext",{{0x09,0x09},{0x20,0x20},{0x2a,0x5b},{0x5d,0x7e},{0x80,0xff}}),
     CharacterSet::TCHAR("TCHAR","!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"),
     CharacterSet::SPECIAL("SPECIAL","()<>@,;:\\\"/[]?={}"),
     CharacterSet::QDTEXT("QDTEXT",{{0x09,0x09},{0x20,0x21},{0x23,0x5b},{0x5d,0x7e},{0x80,0xff}}),
     CharacterSet::OBSTEXT("OBSTEXT",0x80,0xff),

=== modified file 'src/base/CharacterSet.h'
--- src/base/CharacterSet.h	2015-12-23 20:46:09 +0000
+++ src/base/CharacterSet.h	2015-12-26 15:50:12 +0000
@@ -30,46 +30,55 @@ public:
     /// define a character set with the given label ("anonymous" if NULL)
     ///  containing characters defined in the supplied list of low-high ranges
     /// \see addRange
     CharacterSet(const char *label, std::initializer_list<std::pair<uint8_t,uint8_t>> ranges);
 
     /// whether a given character exists in the set
     bool operator[](unsigned char c) const {return chars_[static_cast<uint8_t>(c)] != 0;}
 
     /// add a given character to the character set
     CharacterSet & add(const unsigned char c);
 
     /// add a list of character ranges, expressed as pairs [low,high], including both ends
     CharacterSet & addRange(unsigned char low, unsigned char high);
 
     /// add all characters from the given CharacterSet to this one
     CharacterSet &operator +=(const CharacterSet &src);
 
     /// return a new CharacterSet containing the union of two sets, labeled as the first argument
     CharacterSet operator +(const CharacterSet &src) const;
 
+    /// remove all characters from the given CharacterSet to this one
+    CharacterSet &operator -=(const CharacterSet &src);
+
+    /// return a new CharacterSet containing the set of characters in the first but not in the second
+    CharacterSet operator -(const CharacterSet &src) const;
+
     /// return a new CharacterSet containing characters not in this set
     CharacterSet complement(const char *complementLabel = NULL) const;
 
     /// change name; handy in const declarations that use operators
     CharacterSet &rename(const char *label) { name = label; return *this; }
 
+    /// comparison operator. Ignores label
+    bool operator == (const CharacterSet &) const;
+
     /// optional set label for debugging (default: "anonymous")
     const char * name;
 
     // common character sets, RFC 5234
     // A-Za-z
     static const CharacterSet ALPHA;
     // 0-1
     static const CharacterSet BIT;
     // carriage return
     static const CharacterSet CR;
     // controls
     static const CharacterSet CTL;
     // 0-9
     static const CharacterSet DIGIT;
     // double quote
     static const CharacterSet DQUOTE;
     // 0-9aAbBcCdDeEfF
     static const CharacterSet HEXDIG;
     // horizontal tab
     static const CharacterSet HTAB;

=== modified file 'src/tests/testCharacterSet.cc'
--- src/tests/testCharacterSet.cc	2015-08-03 02:08:22 +0000
+++ src/tests/testCharacterSet.cc	2015-12-26 15:40:43 +0000
@@ -1,90 +1,121 @@
 /*
  * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
  * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
 #include "squid.h"
 #include "base/CharacterSet.h"
 #include "testCharacterSet.h"
 #include "unitTestMain.h"
 
 #include <string>
 
+static
+std::ostream& operator<< (std::ostream &s, const CharacterSet &c)
+{
+    s << "CharacterSet(" << c.name << ')';
+    return s;
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION( testCharacterSet );
 
 void
 testCharacterSet::CharacterSetConstruction()
 {
     {
         CharacterSet t(NULL,"");
         CPPUNIT_ASSERT_EQUAL(std::string("anonymous"),std::string(t.name));
     }
     {
         CharacterSet t("test","");
         CPPUNIT_ASSERT_EQUAL(std::string("test"),std::string(t.name));
     }
     {
         CharacterSet t("test","");
         for (int j = 0; j < 255; ++j)
             CPPUNIT_ASSERT_EQUAL(false,t[j]);
     }
     {
         CharacterSet t("test","0");
         CPPUNIT_ASSERT_EQUAL(true,t['0']);
-        for (int j = 0; j < 255; ++j)
-            if (j != '0')
+        for (int j = 0; j < 255; ++j) {
+            if (j != '0') {
                 CPPUNIT_ASSERT_EQUAL(false,t[j]);
+            } else {
+                CPPUNIT_ASSERT_EQUAL(true,t[j]);
+            }
+        }
     }
 }
 
 void
 testCharacterSet::CharacterSetAdd()
 {
     CharacterSet t("test","0");
     t.add(0);
     CPPUNIT_ASSERT_EQUAL(true,t['\0']);
     CPPUNIT_ASSERT_EQUAL(true,t['0']);
 }
 
 void
 testCharacterSet::CharacterSetAddRange()
 {
     CharacterSet t("test","");
     t.addRange('0','9');
     CPPUNIT_ASSERT_EQUAL(true,t['0']);
     CPPUNIT_ASSERT_EQUAL(true,t['5']);
     CPPUNIT_ASSERT_EQUAL(true,t['9']);
     CPPUNIT_ASSERT_EQUAL(false,t['a']);
 }
 
 void
 testCharacterSet::CharacterSetConstants()
 {
     CPPUNIT_ASSERT_EQUAL(true,CharacterSet::ALPHA['a']);
     CPPUNIT_ASSERT_EQUAL(true,CharacterSet::ALPHA['z']);
     CPPUNIT_ASSERT_EQUAL(true,CharacterSet::ALPHA['A']);
     CPPUNIT_ASSERT_EQUAL(true,CharacterSet::ALPHA['Z']);
     CPPUNIT_ASSERT_EQUAL(false,CharacterSet::ALPHA['5']);
 }
 
 void
 testCharacterSet::CharacterSetUnion()
 {
     {
         CharacterSet hex("hex","");
         hex += CharacterSet::DIGIT;
         hex += CharacterSet(NULL,"aAbBcCdDeEfF");
+        CPPUNIT_ASSERT_EQUAL(CharacterSet::HEXDIG, hex);
         for (int j = 0; j < 255; ++j)
             CPPUNIT_ASSERT_EQUAL(CharacterSet::HEXDIG[j],hex[j]);
     }
     {
         CharacterSet hex(NULL,"");
         hex = CharacterSet::DIGIT + CharacterSet(NULL,"aAbBcCdDeEfF");
         for (int j = 0; j < 255; ++j)
             CPPUNIT_ASSERT_EQUAL(CharacterSet::HEXDIG[j],hex[j]);
     }
 }
 
+void
+testCharacterSet::CharacterSetEqualityOp()
+{
+    CPPUNIT_ASSERT_EQUAL(CharacterSet::ALPHA, CharacterSet::ALPHA);
+    CPPUNIT_ASSERT_EQUAL(CharacterSet::BIT, CharacterSet(NULL,"01"));
+    CPPUNIT_ASSERT_EQUAL(CharacterSet(NULL,"01"), CharacterSet(NULL,"01"));
+    CPPUNIT_ASSERT_EQUAL(CharacterSet(NULL,"01"), CharacterSet("","01"));
+    CPPUNIT_ASSERT_EQUAL(CharacterSet::BIT, CharacterSet("bit",'0','1'));
+    CPPUNIT_ASSERT_EQUAL(CharacterSet::BIT, CharacterSet("bit",{{'0','1'}}));
+    CPPUNIT_ASSERT_EQUAL(CharacterSet::BIT, CharacterSet("bit",{{'0','0'},{'1','1'}}));
+}
+
+void
+testCharacterSet::CharacterSetSubtract()
+{
+    CharacterSet sample(NULL, "0123456789aAbBcCdDeEfFz");
+    sample -= CharacterSet(NULL, "z");
+    CPPUNIT_ASSERT_EQUAL(CharacterSet::HEXDIG, sample);
+}

=== modified file 'src/tests/testCharacterSet.h'
--- src/tests/testCharacterSet.h	2015-08-03 02:08:22 +0000
+++ src/tests/testCharacterSet.h	2015-12-26 15:40:43 +0000
@@ -1,33 +1,37 @@
 /*
  * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
  * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
 #ifndef SQUID_BASE_TESTCHARACTERSET_H
 #define SQUID_BASE_TESTCHARACTERSET_H
 
 #include <cppunit/extensions/HelperMacros.h>
 
 class testCharacterSet : public CPPUNIT_NS::TestFixture
 {
     CPPUNIT_TEST_SUITE( testCharacterSet );
     CPPUNIT_TEST( CharacterSetConstruction );
     CPPUNIT_TEST( CharacterSetAdd );
     CPPUNIT_TEST( CharacterSetAddRange );
+    CPPUNIT_TEST( CharacterSetEqualityOp );
     CPPUNIT_TEST( CharacterSetConstants );
     CPPUNIT_TEST( CharacterSetUnion );
+    CPPUNIT_TEST( CharacterSetSubtract );
     CPPUNIT_TEST_SUITE_END();
 
 protected:
     void CharacterSetConstruction();
     void CharacterSetAdd();
     void CharacterSetAddRange();
     void CharacterSetConstants();
     void CharacterSetUnion();
+    void CharacterSetEqualityOp();
+    void CharacterSetSubtract();
 };
 
 #endif /* SQUID_BASE_TESTCHARACTERSET_H */
 

_______________________________________________
squid-dev mailing list
[email protected]
http://lists.squid-cache.org/listinfo/squid-dev

Reply via email to