Node::fromExpr((*i).d_tester).setAttribute(DatatypeIndexAttr(), index++);
}
d_self = self;
- //d_card = getCardinality();
}
void Datatype::addConstructor(const DatatypeConstructor& c) {
Cardinality Datatype::getCardinality() const throw(IllegalArgumentException) {
CheckArgument(isResolved(), this, "this datatype is not yet resolved");
+
+ // already computed?
+ if(!d_card.isUnknown()) {
+ return d_card;
+ }
+
RecursionBreaker<const Datatype*, DatatypeHashFunction> breaker(__PRETTY_FUNCTION__, this);
+
if(breaker.isRecursion()) {
- return Cardinality::INTEGERS;
+ return d_card = Cardinality::INTEGERS;
}
+
Cardinality c = 0;
for(const_iterator i = begin(), i_end = end(); i != i_end; ++i) {
+ // We can't just add to d_card here, since this function is reentrant
c += (*i).getCardinality();
}
- //if( d_card!=c ){
- //std::cout << "Bad card " << std::endl;
- //}
- return c;
+ return d_card = c;
}
bool Datatype::isFinite() const throw(IllegalArgumentException) {
std::vector<DatatypeConstructor> d_constructors;
bool d_resolved;
Type d_self;
- Cardinality d_card;
+
+ // "mutable" because computing the cardinality can be expensive,
+ // and so it's computed just once, on demand---this is the cache
+ mutable Cardinality d_card;
/**
* Datatypes refer to themselves, recursively, and we have a
d_constructors(),
d_resolved(false),
d_self(),
- d_card(1) {
+ d_card(CardinalityUnknown()) {
}
inline Datatype::Datatype(std::string name, const std::vector<Type>& params) :
d_constructors(),
d_resolved(false),
d_self(),
- d_card(1) {
+ d_card(CardinalityUnknown()) {
}
inline std::string Datatype::getName() const throw() {