#ifndef __SharedSet__
#define __SharedSet__
#include "Forwards.hpp"
#include "Debug/Assertion.hpp"
#include "Allocator.hpp"
#include "Metaiterators.hpp"
#include "Set.hpp"
#include "Sort.hpp"
#include "Stack.hpp"
namespace Lib {
template<typename T>
class SharedSet {
typedef Stack<T> ItemStack;
public:
DECL_ELEMENT_TYPE(T);
SharedSet(size_t sz) : _size(sz) {}
inline unsigned size() const {
return _size;
}
inline bool isEmpty() const { return !_size; }
inline T operator[] (size_t n) const
{
ASS_L(n,size());
return _items[n];
}
inline T sval() const
{
ASS_EQ(size(),1);
return (*this)[0];
}
inline T maxval() const
{
ASS(!isEmpty());
return (*this)[size()-1];
}
bool member(T val) const
{
size_t l=0;
size_t r=size();
while(l<r) {
size_t m=(l+r)>>1;
T mv=(*this)[m];
if(mv==val) {
return true;
}
else if(mv<val) {
l=m+1;
}
else {
ASS_G(mv,val);
r=m;
}
}
return false;
}
const SharedSet* getUnion(const SharedSet* s) const
{
ASS(s);
if(s==this || s->isEmpty()) {
return this;
}
if(isEmpty()) {
return s;
}
bool p1Superset = true;
bool p2Superset = true;
static ItemStack acc;
acc.reset();
const T* p1=_items;
const T* p2=s->_items;
const T* p1e=p1+size();
const T* p2e=p2+s->size();
while(p1!=p1e && p2!=p2e) {
if(*p1==*p2) {
acc.push(*p1);
p1++;
p2++;
}
else if(*p1>*p2) {
acc.push(*p2);
p2++;
p1Superset = false;
}
else {
ASS_L(*p1,*p2);
acc.push(*p1);
p1++;
p2Superset = false;
}
}
while(p1!=p1e) {
acc.push(*p1);
p1++;
p2Superset = false;
}
while(p2!=p2e) {
acc.push(*p2);
p2++;
p1Superset = false;
}
ASS(!p1Superset || !p2Superset);
if(p1Superset) {
return this;
}
if(p2Superset) {
return s;
}
const SharedSet* res=create(acc);
return res;
}
const SharedSet* getIntersection(const SharedSet* s) const
{
ASS(s);
if(s==this) {
return this;
}
static ItemStack acc;
ASS(acc.isEmpty());
const T* p1=_items;
const T* p2=s->_items;
const T* p1e=p1+size();
const T* p2e=p2+s->size();
while(p1!=p1e && p2!=p2e) {
if(*p1==*p2) {
acc.push(*p1);
p1++;
p2++;
}
else if(*p1>*p2) {
p2++;
}
else {
ASS_L(*p1,*p2);
p1++;
}
}
const SharedSet* res=create(acc);
acc.reset();
return res;
}
const SharedSet* subtract(const SharedSet* s) const
{
ASS(s);
if(s==this) {
return getEmpty();
}
static ItemStack acc;
ASS(acc.isEmpty());
const T* p1=_items;
const T* p2=s->_items;
const T* p1e=p1+size();
const T* p2e=p2+s->size();
while(p1!=p1e && p2!=p2e) {
if(*p1==*p2) {
p1++;
p2++;
}
else if(*p1>*p2) {
p2++;
}
else {
ASS_L(*p1,*p2);
acc.push(*p1);
p1++;
}
}
while(p1!=p1e) {
acc.push(*p1);
p1++;
}
const SharedSet* res=create(acc);
acc.reset();
return res;
}
bool hasIntersection(const SharedSet* s) const
{
ASS(s);
const T* p1=_items;
const T* p2=s->_items;
const T* p1e=p1+size();
const T* p2e=p2+s->size();
while(p1!=p1e && p2!=p2e) {
if(*p1==*p2) {
return true;
}
else if(*p1>*p2) {
p2++;
}
else {
ASS_L(*p1,*p2);
p1++;
}
}
return false;
}
bool isSubsetOf(const SharedSet* s) const
{
ASS(s);
if(s->size()<size()) {
return false;
}
if(s==this) {
return true;
}
const T* p1=_items;
const T* p2=s->_items;
const T* p1e=p1+size();
const T* p2e=p2+s->size();
while(p1!=p1e && p2!=p2e) {
if(*p1==*p2) {
p1++;
p2++;
}
else if(*p1>*p2) {
p2++;
}
else {
ASS_L(*p1,*p2);
return false;
}
}
if(p2==p2e && p1!=p1e) {
return false;
}
return true;
}
std::string toString() const
{
std::ostringstream res;
res<<(*this);
return res.str();
}
static const SharedSet* getEmpty()
{
static SharedSet empty(0);
return ∅
}
static const SharedSet* getRange(T first, T afterLast)
{
static ItemStack is;
ASS(is.isEmpty());
for(T itm=first;itm!=afterLast;itm++) {
is.push(itm);
}
const SharedSet* res=create(is);
is.reset();
return res;
}
template<class It>
static const SharedSet* getFromIterator(It it)
{
static ItemStack is;
is.reset();
is.loadFromIterator(it);
return getFromArray(is.begin(), is.length());
}
static const SharedSet* getFromArray(T* arr, size_t len)
{
if(!len) {
return getEmpty();
}
static ItemStack is;
ASS(is.isEmpty());
bool sorted=true;
bool unique=true;
is.push(arr[0]);
for(size_t i=1; i<len; i++) {
is.push(arr[i]);
if(arr[i-1]>arr[i]) {
sorted = false;
}
else if(arr[i-1]==arr[i]) {
unique = false;
}
}
if(!sorted) {
std::sort(
is.begin(), is.end(),
[](const T &l, const T &r) -> bool { return DefaultComparator::compare(l, r) == LESS; }
);
unique = false; }
if(!unique) {
typename ItemStack::StableDelIterator uit(is);
ALWAYS(uit.hasNext());
T prev = uit.next();
while(uit.hasNext()) {
T curr = uit.next();
if(curr==prev) {
uit.del();
}
else {
prev = curr;
}
}
}
const SharedSet* res=create(is);
is.reset();
return res;
}
static const SharedSet* getSingleton(T val)
{
return getFromArray(&val, 1);
}
private:
void* operator new(size_t sz,size_t length)
{
size_t size=sizeof(SharedSet)+length*sizeof(T);
size-=sizeof(T);
return ALLOC_KNOWN(size,"SharedSet");
}
void operator delete (void* obj)
{
SharedSet* ss = static_cast<SharedSet*>(obj);
IGNORE_MAYBE_UNINITIALIZED(
size_t size=sizeof(SharedSet)+ss->_size*sizeof(T);
size-=sizeof(T);
)
DEALLOC_KNOWN(obj, size,"SharedSet");
}
size_t _size;
T _items[1];
static bool equals(const T* arr1, const T* arr2, size_t len)
{
const T* arr1e=arr1+len;
while(arr1!=arr1e) {
if(*arr1!=*arr2) {
return false;
}
arr1++;
arr2++;
}
return true;
}
static unsigned hash(const T* arr, size_t len)
{
static_assert(std::is_arithmetic<T>::value, "T must be safely hashable");
return DefaultHash::hashBytes(
reinterpret_cast<const unsigned char *>(arr),
sizeof(T) * len
);
}
static const SharedSet* create(const ItemStack& is)
{
size_t sz=is.size();
if(!sz) {
return getEmpty();
}
SharedSet* res;
if(getSStruct().find(is,res)) {
return res;
}
res=new(sz) SharedSet(sz);
for(size_t i=0;i<sz;i++) {
ASS(i==0 || is[i-1]<is[i]);
res->_items[i]=is[i];
}
getSStruct().insert(res);
return res;
}
class SharingStruct {
typedef Set<SharedSet*, SharedSet> InternalSharingSet;
InternalSharingSet _data;
public:
bool find(const ItemStack& key,SharedSet*& result) {
return _data.find(key,result);
}
void insert(SharedSet* val) {
_data.insert(val);
}
~SharingStruct() {
typename InternalSharingSet::Iterator it(_data);
while(it.hasNext())
delete it.next();
}
};
static SharingStruct& getSStruct()
{
static SharingStruct sstruct;
return sstruct;
}
public:
static bool equals(const SharedSet* s1,const SharedSet* s2)
{
if(s1->size()!=s2->size()) {
return false;
}
return equals(s1->_items, s2->_items, s1->size());
}
static unsigned hash(const SharedSet* s)
{
return hash(s->_items, s->size());
}
static bool equals(const SharedSet* s1,const ItemStack& is)
{
if(s1->size()!=is.size()) {
return false;
}
return equals(s1->_items, is.begin(), s1->size());
}
static unsigned hash(const ItemStack& is)
{
return hash(is.begin(), is.size());
}
auto iter() const
{ return arrayIter(static_cast<const T *>(_items), size()); }
};
template<typename T>
std::ostream& operator<< (std::ostream& out, const SharedSet<T>& s )
{
auto it = s.iter();
while(it.hasNext()) {
out<<it.next();
if(it.hasNext()) {
out<<", ";
}
}
return out;
}
}
#endif