1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.
Jip J. Dekker 981be2067e Squashed 'software/gecode_on_replay/' content from commit 8051d92b9
git-subtree-dir: software/gecode_on_replay
git-subtree-split: 8051d92b9c89e49cccfbd1c201371580d7703ab4
2021-06-16 14:04:29 +10:00

1005 lines
26 KiB
C++

/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Main authors:
* Christian Schulte <schulte@gecode.org>
*
* Contributing authors:
* Guido Tack <tack@gecode.org>
*
* Copyright:
* Christian Schulte, 2003
* Guido Tack, 2004
*
* This file is part of Gecode, the generic constraint
* development environment:
* http://www.gecode.org
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
namespace Gecode { namespace Int {
/*
* Range lists
*
*/
#define GECODE_INT_RL2PD(r) reinterpret_cast<ptrdiff_t>(r)
#define GECODE_INT_PD2RL(p) reinterpret_cast<RangeList*>(p)
forceinline
IntVarImp::RangeList::RangeList(void) {}
forceinline
IntVarImp::RangeList::RangeList(int min, int max)
: _min(min), _max(max) {}
forceinline
IntVarImp::RangeList::RangeList(int min, int max, RangeList* p, RangeList* n)
: _min(min), _max(max) {
_next = GECODE_INT_PD2RL(GECODE_INT_RL2PD(p)^GECODE_INT_RL2PD(n));
}
forceinline IntVarImp::RangeList*
IntVarImp::RangeList::next(const RangeList* p) const {
return GECODE_INT_PD2RL(GECODE_INT_RL2PD(_next)^GECODE_INT_RL2PD(p));
}
forceinline IntVarImp::RangeList*
IntVarImp::RangeList::prev(const RangeList* n) const {
return GECODE_INT_PD2RL(GECODE_INT_RL2PD(_next)^GECODE_INT_RL2PD(n));
}
forceinline void
IntVarImp::RangeList::prevnext(RangeList* p, RangeList* n) {
_next = GECODE_INT_PD2RL(GECODE_INT_RL2PD(p)^GECODE_INT_RL2PD(n));
}
forceinline void
IntVarImp::RangeList::next(RangeList* o, RangeList* n) {
_next = GECODE_INT_PD2RL(GECODE_INT_RL2PD(_next)^
(GECODE_INT_RL2PD(o)^GECODE_INT_RL2PD(n)));
}
forceinline void
IntVarImp::RangeList::prev(RangeList* o, RangeList* n) {
_next = GECODE_INT_PD2RL(GECODE_INT_RL2PD(_next)^
(GECODE_INT_RL2PD(o)^GECODE_INT_RL2PD(n)));
}
forceinline void
IntVarImp::RangeList::fix(RangeList* n) {
_next = n;
}
forceinline void
IntVarImp::RangeList::min(int n) {
_min = n;
}
forceinline void
IntVarImp::RangeList::max(int n) {
_max = n;
}
forceinline int
IntVarImp::RangeList::min(void) const {
return _min;
}
forceinline int
IntVarImp::RangeList::max(void) const {
return _max;
}
forceinline unsigned int
IntVarImp::RangeList::width(void) const {
return static_cast<unsigned int>(_max - _min) + 1;
}
forceinline void
IntVarImp::RangeList::operator delete(void*) {}
forceinline void
IntVarImp::RangeList::operator delete(void*, Space&) {
GECODE_NEVER;
}
forceinline void
IntVarImp::RangeList::operator delete(void*, void*) {
GECODE_NEVER;
}
forceinline void*
IntVarImp::RangeList::operator new(size_t, Space& home) {
return home.fl_alloc<sizeof(RangeList)>();
}
forceinline void*
IntVarImp::RangeList::operator new(size_t, void* p) {
return p;
}
forceinline void
IntVarImp::RangeList::dispose(Space& home, RangeList* p, RangeList* l) {
RangeList* c = this;
while (c != l) {
RangeList* n = c->next(p);
c->fix(n);
p=c; c=n;
}
home.fl_dispose<sizeof(RangeList)>(this,l);
}
forceinline void
IntVarImp::RangeList::dispose(Space& home, RangeList* l) {
home.fl_dispose<sizeof(RangeList)>(this,l);
}
forceinline void
IntVarImp::RangeList::dispose(Space& home) {
home.fl_dispose<sizeof(RangeList)>(this,this);
}
#undef GECODE_INT_RL2PD
#undef GECODE_INT_PD2RL
/*
* Mainitaining range lists for variable domain
*
*/
forceinline IntVarImp::RangeList*
IntVarImp::fst(void) const {
return dom.next(nullptr);
}
forceinline void
IntVarImp::fst(IntVarImp::RangeList* f) {
dom.prevnext(nullptr,f);
}
forceinline IntVarImp::RangeList*
IntVarImp::lst(void) const {
return _lst;
}
forceinline void
IntVarImp::lst(IntVarImp::RangeList* l) {
_lst = l;
}
/*
* Creation of new variable implementations
*
*/
forceinline
IntVarImp::IntVarImp(Space& home, int min, int max)
: IntVarImpBase(home), dom(min,max,nullptr,nullptr), holes(0) {}
forceinline
IntVarImp::IntVarImp(Space& home, const IntSet& d)
: IntVarImpBase(home), dom(d.min(),d.max()) {
if (d.ranges() > 1) {
int n = d.ranges();
assert(n >= 2);
RangeList* r = home.alloc<RangeList>(n);
fst(r); lst(r+n-1);
unsigned int h = static_cast<unsigned int>(d.max()-d.min())+1;
h -= d.width(0);
r[0].min(d.min(0)); r[0].max(d.max(0));
r[0].prevnext(nullptr,&r[1]);
for (int i = 1; i < n-1; i++) {
h -= d.width(i);
r[i].min(d.min(i)); r[i].max(d.max(i));
r[i].prevnext(&r[i-1],&r[i+1]);
}
h -= d.width(n-1);
r[n-1].min(d.min(n-1)); r[n-1].max(d.max(n-1));
r[n-1].prevnext(&r[n-2],nullptr);
holes = h;
} else {
fst(nullptr); holes = 0;
}
}
/*
* Operations on integer variable implementations
*
*/
forceinline int
IntVarImp::min(void) const {
return dom.min();
}
forceinline int
IntVarImp::max(void) const {
return dom.max();
}
forceinline int
IntVarImp::val(void) const {
assert(dom.min() == dom.max());
return dom.min();
}
forceinline bool
IntVarImp::range(void) const {
return fst() == nullptr;
}
forceinline bool
IntVarImp::assigned(void) const {
return dom.min() == dom.max();
}
forceinline unsigned int
IntVarImp::width(void) const {
return dom.width();
}
forceinline unsigned int
IntVarImp::size(void) const {
return dom.width() - holes;
}
forceinline unsigned int
IntVarImp::regret_min(void) const {
if (fst() == nullptr) {
return (dom.min() == dom.max()) ? 0U : 1U;
} else if (dom.min() == fst()->max()) {
return static_cast<unsigned int>(fst()->next(nullptr)->min()-dom.min());
} else {
return 1U;
}
}
forceinline unsigned int
IntVarImp::regret_max(void) const {
if (fst() == nullptr) {
return (dom.min() == dom.max()) ? 0U : 1U;
} else if (dom.max() == lst()->min()) {
return static_cast<unsigned int>(dom.max()-lst()->prev(nullptr)->max());
} else {
return 1U;
}
}
/*
* Tests
*
*/
forceinline bool
IntVarImp::in(int n) const {
if ((n < dom.min()) || (n > dom.max()))
return false;
return (fst() == nullptr) || in_full(n);
}
forceinline bool
IntVarImp::in(long long int n) const {
if ((n < dom.min()) || (n > dom.max()))
return false;
return (fst() == nullptr) || in_full(static_cast<int>(n));
}
/*
* Accessing rangelists for iteration
*
*/
forceinline const IntVarImp::RangeList*
IntVarImp::ranges_fwd(void) const {
return (fst() == nullptr) ? &dom : fst();
}
forceinline const IntVarImp::RangeList*
IntVarImp::ranges_bwd(void) const {
return (fst() == nullptr) ? &dom : lst();
}
/*
* Support for delta information
*
*/
forceinline int
IntVarImp::min(const Delta& d) {
return static_cast<const IntDelta&>(d).min();
}
forceinline int
IntVarImp::max(const Delta& d) {
return static_cast<const IntDelta&>(d).max();
}
forceinline unsigned int
IntVarImp::width(const Delta& d) {
return static_cast<const IntDelta&>(d).width();
}
forceinline bool
IntVarImp::any(const Delta& d) {
return static_cast<const IntDelta&>(d).any();
}
/*
* Tell operations (to be inlined: performing bounds checks first)
*
*/
forceinline ModEvent
IntVarImp::gq(Space& home, int n) {
if (n <= dom.min()) return ME_INT_NONE;
if (n > dom.max()) return fail(home);
ModEvent me = gq_full(home,n);
GECODE_ASSUME((me == ME_INT_FAILED) |
(me == ME_INT_VAL) |
(me == ME_INT_BND));
return me;
}
forceinline ModEvent
IntVarImp::gq(Space& home, long long int n) {
if (n <= dom.min()) return ME_INT_NONE;
if (n > dom.max()) return fail(home);
ModEvent me = gq_full(home,static_cast<int>(n));
GECODE_ASSUME((me == ME_INT_FAILED) |
(me == ME_INT_VAL) |
(me == ME_INT_BND));
return me;
}
forceinline ModEvent
IntVarImp::lq(Space& home, int n) {
if (n >= dom.max()) return ME_INT_NONE;
if (n < dom.min()) return fail(home);
ModEvent me = lq_full(home,n);
GECODE_ASSUME((me == ME_INT_FAILED) |
(me == ME_INT_VAL) |
(me == ME_INT_BND));
return me;
}
forceinline ModEvent
IntVarImp::lq(Space& home, long long int n) {
if (n >= dom.max()) return ME_INT_NONE;
if (n < dom.min()) return fail(home);
ModEvent me = lq_full(home,static_cast<int>(n));
GECODE_ASSUME((me == ME_INT_FAILED) |
(me == ME_INT_VAL) |
(me == ME_INT_BND));
return me;
}
forceinline ModEvent
IntVarImp::eq(Space& home, int n) {
if ((n < dom.min()) || (n > dom.max()))
return fail(home);
if ((n == dom.min()) && (n == dom.max()))
return ME_INT_NONE;
ModEvent me = eq_full(home,n);
GECODE_ASSUME((me == ME_INT_FAILED) | (me == ME_INT_VAL));
return me;
}
forceinline ModEvent
IntVarImp::eq(Space& home, long long int m) {
if ((m < dom.min()) || (m > dom.max()))
return fail(home);
int n = static_cast<int>(m);
if ((n == dom.min()) && (n == dom.max()))
return ME_INT_NONE;
ModEvent me = eq_full(home,n);
GECODE_ASSUME((me == ME_INT_FAILED) | (me == ME_INT_VAL));
return me;
}
forceinline ModEvent
IntVarImp::nq(Space& home, int n) {
if ((n < dom.min()) || (n > dom.max()))
return ME_INT_NONE;
return nq_full(home,n);
}
forceinline ModEvent
IntVarImp::nq(Space& home, long long int d) {
if ((d < dom.min()) || (d > dom.max()))
return ME_INT_NONE;
return nq_full(home,static_cast<int>(d));
}
/*
* Forward range iterator for rangelists
*
*/
forceinline
IntVarImpFwd::IntVarImpFwd(void) {}
forceinline
IntVarImpFwd::IntVarImpFwd(const IntVarImp* x)
: p(nullptr), c(x->ranges_fwd()) {}
forceinline void
IntVarImpFwd::init(const IntVarImp* x) {
p=nullptr; c=x->ranges_fwd();
}
forceinline bool
IntVarImpFwd::operator ()(void) const {
return c != nullptr;
}
forceinline void
IntVarImpFwd::operator ++(void) {
const IntVarImp::RangeList* n=c->next(p); p=c; c=n;
}
forceinline int
IntVarImpFwd::min(void) const {
return c->min();
}
forceinline int
IntVarImpFwd::max(void) const {
return c->max();
}
forceinline unsigned int
IntVarImpFwd::width(void) const {
return c->width();
}
/*
* Backward range iterator for rangelists
*
*/
forceinline
IntVarImpBwd::IntVarImpBwd(void) {}
forceinline
IntVarImpBwd::IntVarImpBwd(const IntVarImp* x)
: n(nullptr), c(x->ranges_bwd()) {}
forceinline void
IntVarImpBwd::init(const IntVarImp* x) {
n=nullptr; c=x->ranges_bwd();
}
forceinline bool
IntVarImpBwd::operator ()(void) const {
return c != nullptr;
}
forceinline void
IntVarImpBwd::operator ++(void) {
const IntVarImp::RangeList* p=c->prev(n); n=c; c=p;
}
forceinline int
IntVarImpBwd::min(void) const {
return c->min();
}
forceinline int
IntVarImpBwd::max(void) const {
return c->max();
}
forceinline unsigned int
IntVarImpBwd::width(void) const {
return c->width();
}
/*
* Iterator-based domain operations
*
*/
template<class I>
forceinline ModEvent
IntVarImp::narrow_r(Space& home, I& ri, bool depends) {
// Is new domain empty?
if (!ri())
return fail(home);
int min0 = ri.min();
int max0 = ri.max();
++ri;
ModEvent me;
// Is new domain range?
if (!ri()) {
// Remove possible rangelist (if it was not a range, the domain
// must have been narrowed!)
if (fst()) {
fst()->dispose(home,nullptr,lst());
fst(nullptr); holes = 0;
}
const int min1 = dom.min(); dom.min(min0);
const int max1 = dom.max(); dom.max(max0);
if ((min0 == min1) && (max0 == max1))
return ME_INT_NONE;
me = (min0 == max0) ? ME_INT_VAL : ME_INT_BND;
goto notify;
}
if (depends || range()) {
// Construct new rangelist
RangeList* f = new (home) RangeList(min0,max0,nullptr,nullptr);
RangeList* l = f;
unsigned int s = static_cast<unsigned int>(max0-min0+1);
do {
RangeList* n = new (home) RangeList(ri.min(),ri.max(),l,nullptr);
l->next(nullptr,n);
l = n;
s += ri.width();
++ri;
} while (ri());
if (fst() != nullptr)
fst()->dispose(home,nullptr,lst());
fst(f); lst(l);
// Check for modification
if (size() == s)
return ME_INT_NONE;
const int min1 = dom.min(); min0 = f->min(); dom.min(min0);
const int max1 = dom.max(); max0 = l->max(); dom.max(max0);
holes = width() - s;
me = ((min0 == min1) && (max0 == max1)) ? ME_INT_DOM : ME_INT_BND;
goto notify;
} else {
// Set up two sentinel elements
RangeList f, l;
// Put all ranges between sentinels
f.prevnext(nullptr,fst()); l.prevnext(lst(),nullptr);
fst()->prev(nullptr,&f); lst()->next(nullptr,&l);
// Number of values removed (potential holes)
unsigned int h = 0;
// The previous range
RangeList* p = &f;
// The current range
RangeList* r = f.next(nullptr);
while (true) {
assert((r != &f) && (r != &l));
if (r->max() < min0) {
// Entire range removed
h += r->width();
RangeList* n=r->next(p);
p->next(r,n); n->prev(r,p);
r->dispose(home);
r=n;
if (r == &l)
goto done;
} else if ((r->min() == min0) && (r->max() == max0)) {
// Range unchanged
RangeList* n=r->next(p); p=r; r=n;
if (r == &l)
goto done;
if (!ri())
goto done;
min0=ri.min(); max0=ri.max(); ++ri;
} else {
// Range might have been split into many small ranges
assert((r->min() <= min0) && (max0 <= r->max()));
h += r->width();
int end = r->max();
// Copy first range
r->min(min0); r->max(max0);
assert(h > r->width());
h -= r->width();
{
RangeList* n=r->next(p); p=r; r=n;
}
while (true) {
if (!ri())
goto done;
min0=ri.min(); max0=ri.max(); ++ri;
if (max0 > end)
break;
assert(h > static_cast<unsigned int>(max0-min0+1));
h -= max0-min0+1;
RangeList* n = new (home) RangeList(min0,max0,p,r);
p->next(r,n); r->prev(p,n);
p=n;
}
if (r == &l)
goto done;
}
}
done:
// Remove remaining ranges
while (r != &l) {
h += r->width();
RangeList* n=r->next(p);
p->next(r,n); n->prev(r,p);
r->dispose(home);
r=n;
}
assert((r == &l) && !ri());
// New first and last ranges
RangeList* fn = f.next(nullptr);
RangeList* ln = l.prev(nullptr);
// All ranges pruned?
assert(fn != &l);
// Only a single range left?
assert(fn != ln);
// The number of removed values
holes += h;
// Unlink sentinel ranges
fn->prev(&f,nullptr); ln->next(&l,nullptr);
// How many values where removed at the bounds
unsigned int b = (static_cast<unsigned int>(fn->min()-dom.min()) +
static_cast<unsigned int>(dom.max()-ln->max()));
// Set new first and last ranges
fst(fn); lst(ln);
if (b > 0) {
assert((dom.min() != fn->min()) || (dom.max() != ln->max()));
dom.min(fn->min()); dom.max(ln->max());
holes -= b;
me = ME_INT_BND; goto notify;
}
if (h > 0) {
assert((dom.min() == fn->min()) && (dom.max() == ln->max()));
me = ME_INT_DOM; goto notify;
}
return ME_INT_NONE;
}
notify:
IntDelta d;
return notify(home,me,d);
}
template<class I>
forceinline ModEvent
IntVarImp::inter_r(Space& home, I& i, bool) {
IntVarImpFwd j(this);
Iter::Ranges::Inter<I,IntVarImpFwd> ij(i,j);
return narrow_r(home,ij,true);
}
template<class I>
forceinline ModEvent
IntVarImp::minus_r(Space& home, I& i, bool depends) {
if (depends) {
IntVarImpFwd j(this);
Iter::Ranges::Diff<IntVarImpFwd,I> ij(j,i);
return narrow_r(home,ij,true);
}
// Skip all ranges that are too small
while (i() && (i.max() < dom.min()))
++i;
// Is there no range left or all are too large?
if (!i() || (i.min() > dom.max()))
return ME_INT_NONE;
int i_min = i.min();
int i_max = i.max();
++i;
if ((i_min <= dom.min()) && (i_max >= dom.max()))
return fail(home);
if ((i_min > dom.min()) && (i_max >= dom.max()))
return lq(home,i_min-1);
if ((i_min <= dom.min()) && (i_max < dom.max()) &&
(!i() || (i.min() > dom.max())))
return gq(home,i_max+1);
// Set up two sentinel elements
RangeList f, l;
// Put all ranges between sentinels
if (range()) {
// Create a new rangelist just for simplicity
RangeList* n = new (home) RangeList(min(),max(),&f,&l);
f.prevnext(nullptr,n); l.prevnext(n,nullptr);
} else {
// Link the two sentinel elements
f.prevnext(nullptr,fst()); l.prevnext(lst(),nullptr);
fst()->prev(nullptr,&f); lst()->next(nullptr,&l);
}
// Number of values removed (potential holes)
unsigned int h = 0;
// The previous range
RangeList* p = &f;
// The current range
RangeList* r = f.next(nullptr);
while (true) {
assert((r != &f) && (r != &l));
if (i_min > r->max()) {
RangeList* n=r->next(p); p=r; r=n;
if (r == &l)
break;
} else if (i_max < r->min()) {
if (!i())
break;
i_min = i.min();
i_max = i.max();
++i;
} else if ((i_min <= r->min()) && (r->max() <= i_max)) {
// r is included in i: remove entire range r
h += r->width();
RangeList* n=r->next(p);
p->next(r,n); n->prev(r,p);
r->dispose(home);
r=n;
if (r == &l)
break;
} else if ((i_min > r->min()) && (i_max < r->max())) {
// i is included in r: create new range before the current one
h += static_cast<unsigned int>(i_max - i_min) + 1;
RangeList* n = new (home) RangeList(r->min(),i_min-1,p,r);
r->min(i_max+1);
p->next(r,n); r->prev(p,n);
p=n;
if (!i())
break;
i_min = i.min();
i_max = i.max();
++i;
} else if (i_max < r->max()) {
assert(i_min <= r->min());
// i ends before r: adjust minimum of r
h += i_max-r->min()+1;
r->min(i_max+1);
if (!i())
break;
i_min = i.min();
i_max = i.max();
++i;
} else {
assert((i_max >= r->max()) && (r->min() < i_min));
// r ends before i: adjust maximum of r
h += r->max()-i_min+1;
r->max(i_min-1);
RangeList* n=r->next(p); p=r; r=n;
if (r == &l)
break;
}
}
// New first and last ranges
RangeList* fn = f.next(nullptr);
RangeList* ln = l.prev(nullptr);
// All ranges pruned?
if (fn == &l) {
fst(nullptr); lst(nullptr); holes=0;
return fail(home);
}
ModEvent me;
unsigned int b;
// Only a single range left?
if (fn == ln) {
assert(h > 0);
dom.min(fn->min()); dom.max(fn->max());
fn->dispose(home);
fst(nullptr); lst(nullptr);
holes = 0;
me = assigned() ? ME_INT_VAL : ME_INT_BND;
goto notify;
}
// The number of removed values
holes += h;
// Unlink sentinel ranges
fn->prev(&f,nullptr); ln->next(&l,nullptr);
// How many values where removed at the bounds
b = (static_cast<unsigned int>(fn->min()-dom.min()) +
static_cast<unsigned int>(dom.max()-ln->max()));
// Set new first and last ranges
fst(fn); lst(ln);
if (b > 0) {
assert((dom.min() != fn->min()) || (dom.max() != ln->max()));
dom.min(fn->min()); dom.max(ln->max());
holes -= b;
me = ME_INT_BND; goto notify;
}
if (h > 0) {
assert((dom.min() == fn->min()) && (dom.max() == ln->max()));
me = ME_INT_DOM; goto notify;
}
return ME_INT_NONE;
notify:
IntDelta d;
return notify(home,me,d);
}
template<class I>
forceinline ModEvent
IntVarImp::narrow_v(Space& home, I& i, bool depends) {
Iter::Values::ToRanges<I> r(i);
return narrow_r(home,r,depends);
}
template<class I>
forceinline ModEvent
IntVarImp::inter_v(Space& home, I& i, bool depends) {
Iter::Values::ToRanges<I> r(i);
return inter_r(home,r,depends);
}
template<class I>
forceinline ModEvent
IntVarImp::minus_v(Space& home, I& i, bool depends) {
if (depends) {
Iter::Values::ToRanges<I> r(i);
return minus_r(home, r, true);
}
// Skip all values that are too small
while (i() && (i.val() < dom.min()))
++i;
// Is there no value left or all are too large?
if (!i() || (i.val() > dom.max()))
return ME_INT_NONE;
int v = i.val();
// Skip values that are the same
do {
++i;
} while (i() && (i.val() == v));
// Is there only a single value to be pruned?
if (!i() || (i.val() > dom.max()))
return nq_full(home,v);
// Set up two sentinel elements
RangeList f, l;
// Put all ranges between sentinels
if (range()) {
// Create a new rangelist just for simplicity
RangeList* n = new (home) RangeList(min(),max(),&f,&l);
f.prevnext(nullptr,n); l.prevnext(n,nullptr);
} else {
// Link the two sentinel elements
f.prevnext(nullptr,fst()); l.prevnext(lst(),nullptr);
fst()->prev(nullptr,&f); lst()->next(nullptr,&l);
}
// Number of values removed (potential holes)
unsigned int h = 0;
// The previous range
RangeList* p = &f;
// The current range
RangeList* r = f.next(nullptr);
while (true) {
assert((r != &f) && (r != &l));
if (v > r->max()) {
// Move to next range
RangeList* n=r->next(p); p=r; r=n;
if (r == &l)
break;
} else {
if ((v == r->min()) && (v == r->max())) {
// Remove range
h++;
RangeList* n=r->next(p);
p->next(r,n); n->prev(r,p);
r->dispose(home);
r=n;
if (r == &l)
break;
} else if (v == r->min()) {
h++; r->min(v+1);
} else if (v == r->max()) {
h++; r->max(v-1);
RangeList* n=r->next(p); p=r; r=n;
if (r == &l)
break;
} else if (v > r->min()) {
// Create new range before the current one
assert(v < r->max());
h++;
RangeList* n = new (home) RangeList(r->min(),v-1,p,r);
r->min(v+1);
p->next(r,n); r->prev(p,n);
p=n;
}
if (!i())
break;
// Move to next value
v = i.val(); ++i;
}
}
assert((r == &l) || !i());
// New first and last ranges
RangeList* fn = f.next(nullptr);
RangeList* ln = l.prev(nullptr);
// All ranges pruned?
if (fn == &l) {
fst(nullptr); lst(nullptr); holes=0;
return fail(home);
}
IntDelta d;
// Only a single range left?
if (fn == ln) {
assert(h > 0);
dom.min(fn->min()); dom.max(fn->max());
fn->dispose(home);
fst(nullptr); lst(nullptr);
holes = 0;
if (assigned())
return notify(home,ME_INT_VAL,d);
else
return notify(home,ME_INT_BND,d);
}
// The number of removed values
holes += h;
// Unlink sentinel ranges
fn->prev(&f,nullptr); ln->next(&l,nullptr);
// How many values where removed at the bounds
unsigned int b = (static_cast<unsigned int>(fn->min()-dom.min()) +
static_cast<unsigned int>(dom.max()-ln->max()));
// Set new first and last ranges
fst(fn); lst(ln);
if (b > 0) {
assert((dom.min() != fn->min()) || (dom.max() != ln->max()));
dom.min(fn->min()); dom.max(ln->max());
holes -= b;
return notify(home,ME_INT_BND,d);
}
if (h > 0) {
assert((dom.min() == fn->min()) && (dom.max() == ln->max()));
return notify(home,ME_INT_DOM,d);
}
return ME_INT_NONE;
}
/*
* Copying a variable
*
*/
forceinline IntVarImp*
IntVarImp::copy(Space& home) {
return copied() ? static_cast<IntVarImp*>(forward())
: perform_copy(home);
}
forceinline ModEventDelta
IntVarImp::med(ModEvent me) {
return IntVarImpBase::med(me);
}
}}
// STATISTICS: int-var