2014-11-18 13:28:12 -05:00
|
|
|
//
|
2020-11-27 05:33:55 -05:00
|
|
|
// FILE: set.cpp
|
2014-11-18 13:28:12 -05:00
|
|
|
// AUTHOR: Rob Tillaart
|
2020-11-27 05:33:55 -05:00
|
|
|
// VERSION: 0.2.1
|
|
|
|
// DATE: 2014-09-11
|
2014-11-18 13:28:12 -05:00
|
|
|
// PURPOSE: SET library for Arduino
|
2020-11-27 05:33:55 -05:00
|
|
|
// URL: https://github.com/RobTillaart/SET
|
2014-11-18 13:28:12 -05:00
|
|
|
//
|
|
|
|
// HISTORY:
|
2020-11-27 05:33:55 -05:00
|
|
|
// 0.2.1 2020-06-19 fix library.json
|
|
|
|
// 0.2.0 2020-05-02 refactored, removed pre 1.0 support
|
2017-07-16 14:09:23 -04:00
|
|
|
// 0.1.11 2017-07-16 fix count() --> 16 bit when set is full !
|
2017-07-16 11:33:43 -04:00
|
|
|
// 0.1.10 2017-07-16 performance refactor. isEmpty()
|
2016-12-18 05:19:56 -05:00
|
|
|
// 0.1.09 2015-07-12 const + constructor
|
2016-01-03 13:11:17 -05:00
|
|
|
// 0.1.08 memset for clr()
|
2015-03-07 12:46:16 -05:00
|
|
|
// 0.1.07 faster first/next/last/prev; interface
|
2014-11-18 13:28:12 -05:00
|
|
|
// 0.1.06 added flag to constructor to optimize +,-,*,
|
|
|
|
// set -> Set
|
|
|
|
// 0.1.05 bug fixing + performance a.o. count()
|
|
|
|
// 0.1.04 support for + - *, some optimizations
|
|
|
|
// 0.1.03 changed &= to *= to follow Pascal conventions
|
|
|
|
// 0.1.02 documentation
|
|
|
|
// 0.1.01 extending/refactor etc (09/11/2014)
|
|
|
|
// 0.1.00 initial version by Rob Tillaart (09/11/2014)
|
|
|
|
//
|
|
|
|
|
2020-11-27 05:33:55 -05:00
|
|
|
#include "set.h"
|
2014-11-18 13:28:12 -05:00
|
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// CONSTRUCTORS
|
|
|
|
//
|
2016-12-18 05:19:56 -05:00
|
|
|
Set::Set(const bool clear)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
if (clear)
|
|
|
|
{
|
|
|
|
clr();
|
|
|
|
}
|
2016-12-18 05:19:56 -05:00
|
|
|
_current = -1;
|
2014-11-18 13:28:12 -05:00
|
|
|
}
|
|
|
|
|
2015-03-07 12:46:16 -05:00
|
|
|
Set::Set(const Set &t)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
2020-11-27 05:33:55 -05:00
|
|
|
for (uint8_t i = 0; i < 32; i++)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
_mem[i] = t._mem[i];
|
|
|
|
}
|
2016-12-18 05:19:56 -05:00
|
|
|
_current = -1;
|
2014-11-18 13:28:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// METHODS
|
|
|
|
//
|
2016-12-18 05:19:56 -05:00
|
|
|
void Set::add(const uint8_t v)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
uint8_t idx = v / 8;
|
2020-11-27 05:33:55 -05:00
|
|
|
_mem[idx] |= masks[v & 7];
|
2014-11-18 13:28:12 -05:00
|
|
|
}
|
|
|
|
|
2016-12-18 05:19:56 -05:00
|
|
|
void Set::sub(const uint8_t v)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
uint8_t idx = v / 8;
|
2020-11-27 05:33:55 -05:00
|
|
|
_mem[idx] &= ~masks[v & 7];
|
2014-11-18 13:28:12 -05:00
|
|
|
}
|
|
|
|
|
2016-12-18 05:19:56 -05:00
|
|
|
void Set::invert(const uint8_t v)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
uint8_t idx = v / 8;
|
2020-11-27 05:33:55 -05:00
|
|
|
_mem[idx] ^= masks[v & 7];
|
2014-11-18 13:28:12 -05:00
|
|
|
}
|
|
|
|
|
2016-12-18 05:19:56 -05:00
|
|
|
bool Set::has(const uint8_t v)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
uint8_t idx = v / 8;
|
2020-11-27 05:33:55 -05:00
|
|
|
return (_mem[idx] & masks[v & 7]) > 0;
|
2014-11-18 13:28:12 -05:00
|
|
|
}
|
|
|
|
|
2017-07-16 14:09:23 -04:00
|
|
|
uint16_t Set::count() const
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
2017-07-16 14:09:23 -04:00
|
|
|
uint16_t cnt = 0;
|
2020-11-27 05:33:55 -05:00
|
|
|
|
|
|
|
uint8_t i = 32;
|
|
|
|
do
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
// kerningham bit count trick
|
2020-11-27 05:33:55 -05:00
|
|
|
uint8_t b = _mem[--i];
|
2014-11-18 13:28:12 -05:00
|
|
|
for (; b; cnt++)
|
|
|
|
{
|
|
|
|
b &= b-1;
|
|
|
|
}
|
|
|
|
}
|
2020-11-27 05:33:55 -05:00
|
|
|
while (i != 0);
|
2014-11-18 13:28:12 -05:00
|
|
|
return cnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Set::clr()
|
|
|
|
{
|
2016-01-03 13:11:17 -05:00
|
|
|
memset(_mem, 0, 32);
|
2014-11-18 13:28:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void Set::invert()
|
|
|
|
{
|
2020-11-27 05:33:55 -05:00
|
|
|
uint8_t i = 32;
|
|
|
|
do
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
2020-11-27 05:33:55 -05:00
|
|
|
_mem[--i] ^= 0xFF;
|
|
|
|
}
|
|
|
|
while (i != 0);
|
2014-11-18 13:28:12 -05:00
|
|
|
}
|
|
|
|
|
2017-07-16 11:33:43 -04:00
|
|
|
bool Set::isEmpty()
|
|
|
|
{
|
2020-11-27 05:33:55 -05:00
|
|
|
uint8_t i = 32;
|
|
|
|
do
|
2017-07-16 11:33:43 -04:00
|
|
|
{
|
2020-11-27 05:33:55 -05:00
|
|
|
if (_mem[--i] > 0) return false;
|
|
|
|
}
|
|
|
|
while (i != 0);
|
2017-07-16 11:33:43 -04:00
|
|
|
return true;
|
|
|
|
}
|
2016-01-03 13:11:17 -05:00
|
|
|
|
2017-07-16 14:09:23 -04:00
|
|
|
bool Set::isFull()
|
|
|
|
{
|
2020-11-27 05:33:55 -05:00
|
|
|
// check two elements per loop
|
|
|
|
// is faster for full sets but slower for empty set.
|
|
|
|
// footprint is ~25 bytese larger
|
|
|
|
// overal performance gain
|
|
|
|
uint8_t i = 32;
|
|
|
|
do
|
2017-07-16 14:09:23 -04:00
|
|
|
{
|
2020-11-27 05:33:55 -05:00
|
|
|
if ((_mem[--i]) != 255) return false;
|
|
|
|
}
|
|
|
|
while (i != 0);
|
2017-07-16 14:09:23 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-11-18 13:28:12 -05:00
|
|
|
int Set::first()
|
|
|
|
{
|
2020-11-27 05:33:55 -05:00
|
|
|
if (has(0))
|
|
|
|
{
|
|
|
|
_current = 0;
|
|
|
|
return _current;
|
|
|
|
}
|
|
|
|
return findNext(0, 0);
|
2014-11-18 13:28:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int Set::next()
|
|
|
|
{
|
2016-01-03 13:11:17 -05:00
|
|
|
if (_current & 0x8000) return -1; // if current == -1
|
2015-03-07 12:46:16 -05:00
|
|
|
_current++;
|
|
|
|
uint8_t p = (uint8_t)_current / 8;
|
|
|
|
uint8_t q = (uint8_t)_current & 7;
|
|
|
|
return findNext(p, q);
|
|
|
|
}
|
|
|
|
|
2020-11-27 05:33:55 -05:00
|
|
|
// pointer math version ~12% faster but not for previous
|
|
|
|
// needs investigation.
|
|
|
|
// int Set::findNext(const uint8_t p, const uint8_t q)
|
|
|
|
// {
|
|
|
|
// uint8_t * pp = &_mem[p];
|
|
|
|
// uint8_t mask = 1 << q;
|
|
|
|
// uint8_t j = q;
|
|
|
|
// do
|
|
|
|
// {
|
|
|
|
// if (*pp != 0)
|
|
|
|
// {
|
|
|
|
// while (j < 8)
|
|
|
|
// {
|
|
|
|
// if (*pp & mask)
|
|
|
|
// {
|
|
|
|
// _current = (pp - _mem) * 8 + j;
|
|
|
|
// return _current;
|
|
|
|
// }
|
|
|
|
// mask <<= 1;
|
|
|
|
// j++;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// j = 0;
|
|
|
|
// mask = 1;
|
|
|
|
// pp++;
|
|
|
|
// }
|
|
|
|
// while (pp != &_mem[31]);
|
|
|
|
// _current = -1;
|
|
|
|
// return _current;
|
|
|
|
// }
|
|
|
|
|
2017-07-16 11:33:43 -04:00
|
|
|
int Set::findNext(const uint8_t p, uint8_t q)
|
2015-03-07 12:46:16 -05:00
|
|
|
{
|
2016-12-18 05:19:56 -05:00
|
|
|
for (uint8_t i = p; i < 32; i++)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
2015-03-07 12:46:16 -05:00
|
|
|
uint8_t b = _mem[i];
|
|
|
|
if (b != 0)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
2020-11-27 05:33:55 -05:00
|
|
|
uint8_t mask = 1 << q; // masks[q]
|
2016-12-18 05:19:56 -05:00
|
|
|
for (uint8_t j = q; j < 8; j++)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
2015-03-07 12:46:16 -05:00
|
|
|
if (b & mask)
|
|
|
|
{
|
2016-12-18 05:19:56 -05:00
|
|
|
_current = i * 8 + j;
|
2015-03-07 12:46:16 -05:00
|
|
|
return _current;
|
|
|
|
}
|
|
|
|
mask <<= 1;
|
2014-11-18 13:28:12 -05:00
|
|
|
}
|
|
|
|
}
|
2015-03-07 12:46:16 -05:00
|
|
|
q = 0;
|
2014-11-18 13:28:12 -05:00
|
|
|
}
|
|
|
|
_current = -1;
|
|
|
|
return _current;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Set::prev()
|
|
|
|
{
|
2015-03-07 12:46:16 -05:00
|
|
|
if (_current & 0x8000) return -1;
|
|
|
|
_current--;
|
|
|
|
uint8_t p = (uint8_t)_current / 8;
|
|
|
|
uint8_t q = (uint8_t)_current & 7;
|
|
|
|
return findPrev(p, q);
|
2014-11-18 13:28:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int Set::last()
|
|
|
|
{
|
2020-11-27 05:33:55 -05:00
|
|
|
if (has(255))
|
|
|
|
{
|
|
|
|
_current = 255;
|
|
|
|
return _current;
|
|
|
|
}
|
2015-03-07 12:46:16 -05:00
|
|
|
return findPrev(31, 7);
|
|
|
|
}
|
|
|
|
|
2017-07-16 11:33:43 -04:00
|
|
|
int Set::findPrev(const uint8_t p, uint8_t q)
|
2015-03-07 12:46:16 -05:00
|
|
|
{
|
|
|
|
uint8_t m = 1 << q;
|
2016-12-18 05:19:56 -05:00
|
|
|
for (uint8_t i = p; i != 255; --i) // uint < 0
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
2015-03-07 12:46:16 -05:00
|
|
|
uint8_t b = _mem[i];
|
|
|
|
if (b != 0)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
2015-03-07 12:46:16 -05:00
|
|
|
uint8_t mask = m;
|
2016-12-18 05:19:56 -05:00
|
|
|
for (uint8_t j = q; j != 255; --j)
|
2015-03-07 12:46:16 -05:00
|
|
|
{
|
|
|
|
if (b & mask)
|
|
|
|
{
|
2016-12-18 05:19:56 -05:00
|
|
|
_current = i * 8 + j;
|
2015-03-07 12:46:16 -05:00
|
|
|
return _current;
|
|
|
|
}
|
|
|
|
mask >>= 1;
|
|
|
|
}
|
2014-11-18 13:28:12 -05:00
|
|
|
}
|
2020-11-27 05:33:55 -05:00
|
|
|
m = 128; // 1 << 7;
|
2015-03-07 12:46:16 -05:00
|
|
|
q = 7;
|
2014-11-18 13:28:12 -05:00
|
|
|
}
|
2015-03-07 12:46:16 -05:00
|
|
|
_current = -1;
|
2014-11-18 13:28:12 -05:00
|
|
|
return _current;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// OPERATORS
|
|
|
|
//
|
|
|
|
|
2016-12-18 05:19:56 -05:00
|
|
|
Set Set::operator + (const Set &t) // union
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
Set s(false);
|
2016-12-18 05:19:56 -05:00
|
|
|
for (uint8_t i = 0; i < 32; i++)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
s._mem[i] = this->_mem[i] | t._mem[i];
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2016-12-18 05:19:56 -05:00
|
|
|
Set Set::operator - (const Set &t) // diff
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
Set s(false);
|
2016-12-18 05:19:56 -05:00
|
|
|
for (uint8_t i = 0; i < 32; i++)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
s._mem[i] = this->_mem[i] & ~t._mem[i];
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2016-12-18 05:19:56 -05:00
|
|
|
Set Set::operator * (const Set &t) // intersection
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
Set s(false);
|
2016-12-18 05:19:56 -05:00
|
|
|
for (uint8_t i = 0; i < 32; i++)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
s._mem[i] = this->_mem[i] & t._mem[i];
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2016-12-18 05:19:56 -05:00
|
|
|
void Set::operator += (const Set &t) // union
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
2016-12-18 05:19:56 -05:00
|
|
|
for (uint8_t i = 0; i < 32; i++)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
_mem[i] |= t._mem[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-18 05:19:56 -05:00
|
|
|
void Set::operator -= (const Set &t) // diff
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
2016-12-18 05:19:56 -05:00
|
|
|
for (uint8_t i = 0; i < 32; i++)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
_mem[i] &= ~t._mem[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-18 05:19:56 -05:00
|
|
|
void Set::operator *= (const Set &t) // intersection
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
2016-12-18 05:19:56 -05:00
|
|
|
for (uint8_t i = 0; i < 32; i++)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
_mem[i] &= t._mem[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-18 05:19:56 -05:00
|
|
|
bool Set::operator == (const Set &t) const // equal
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
2016-12-18 05:19:56 -05:00
|
|
|
for (uint8_t i = 0; i < 32; i++)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
if (_mem[i] != t._mem[i]) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-18 05:19:56 -05:00
|
|
|
bool Set::operator != (const Set &t) const // not equal
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
2016-12-18 05:19:56 -05:00
|
|
|
for (uint8_t i = 0; i < 32; i++)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
if (_mem[i] != t._mem[i]) return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-12-18 05:19:56 -05:00
|
|
|
bool Set::operator <= (const Set &t) const // subSet
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
2016-12-18 05:19:56 -05:00
|
|
|
for (uint8_t i = 0; i < 32; i++)
|
2014-11-18 13:28:12 -05:00
|
|
|
{
|
|
|
|
if ((_mem[i] & ~t._mem[i]) > 0) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2020-11-27 05:33:55 -05:00
|
|
|
|
|
|
|
// -- END OF FILE --
|