Skip to content

Commit

Permalink
libdeng2|Refactor: Rules are reference-counted
Browse files Browse the repository at this point in the history
Simplified the lifetime and ownership management of rules by applying
reference counting.

Also added functions de::holdRef() and de::releaseRef() for more
convenient/safer reference holding and releasing.
  • Loading branch information
skyjake committed Jan 23, 2013
1 parent 616b3df commit 2cdaa9b
Show file tree
Hide file tree
Showing 19 changed files with 369 additions and 394 deletions.
52 changes: 46 additions & 6 deletions doomsday/libdeng2/include/de/data/counted.h
Expand Up @@ -48,11 +48,17 @@ class DENG2_PUBLIC Counted
return static_cast<Type *>(this);
}

template <typename Type>
Type const *ref() const {
addRef();
return static_cast<Type const *>(this);
}

/**
* Releases a reference that was acquired earlier with ref(). The
* object destroys itself when the reference counter hits zero.
*/
void release();
void release() const;

protected:
/**
Expand All @@ -62,22 +68,22 @@ class DENG2_PUBLIC Counted
*
* @param count Added to the reference counter.
*/
void addRef(dint count = 1) {
void addRef(dint count = 1) const {
_refCount += count;
DENG2_ASSERT(_refCount >= 0);
}

/**
* When a counted object is destroyed, its reference counter must be
* zero. Note that this is only called from release() when all
* references have been released.
* Non-public destructor. When a counted object is destroyed, its reference
* counter must be zero. Note that this is only called from release() when
* all references have been released.
*/
virtual ~Counted();

private:
/// Number of other things that refer to this object, i.e. have
/// a pointer to it.
dint _refCount;
mutable dint _refCount;

template <typename Type>
friend Type *refless(Type *counted);
Expand All @@ -95,6 +101,40 @@ inline Type *refless(Type *counted) {
return counted;
}

/**
* Holds a reference to a Counted object.
* @param counted Counted object.
* @return Same as @a counted (with reference count incremented).
*/
template <typename CountedType>
inline CountedType *holdRef(CountedType *counted) {
return counted->template ref<CountedType>();
}

/**
* Releases a reference to a Counted object. Afterwards, the pointer is cleared
* to NULL.
*
* @param ref Pointer that holds a reference. May be NULL.
*/
template <typename CountedType>
inline void releaseRef(CountedType *&ref) {
if(ref) ref->release();
ref = 0;
}

/**
* Releases a const reference to a Counted object. Afterwards, the pointer is
* cleared to NULL.
*
* @param ref Pointer that holds a reference. May be NULL.
*/
template <typename CountedType>
inline void releaseRef(CountedType const *&ref) {
if(ref) ref->release();
ref = 0;
}

} // namespace de

#endif /* LIBDENG2_COUNTED_H */
7 changes: 7 additions & 0 deletions doomsday/libdeng2/include/de/widgets/animation.h
Expand Up @@ -102,6 +102,13 @@ class Animation : public ISerializable
*/
float target() const;

/**
* Changes the target value without modifying any other parameters.
*
* @param newTarget Target value.
*/
void adjustTarget(float newTarget);

/**
* Number of seconds remaining in the ongoing transition.
*/
Expand Down
2 changes: 1 addition & 1 deletion doomsday/libdeng2/include/de/widgets/constantrule.h
Expand Up @@ -34,7 +34,7 @@ class ConstantRule : public Rule
Q_OBJECT

public:
explicit ConstantRule(float constantValue, QObject *parent = 0);
explicit ConstantRule(float constantValue);

/**
* Changes the value of the constant in the rule.
Expand Down
4 changes: 2 additions & 2 deletions doomsday/libdeng2/include/de/widgets/derivedrule.h
Expand Up @@ -33,11 +33,11 @@ class DerivedRule : public ConstantRule
Q_OBJECT

public:
explicit DerivedRule(Rule const *source, QObject *parent = 0);
explicit DerivedRule(Rule const *source);

protected:
void update();
void dependencyReplaced(Rule const *oldRule, Rule const *newRule);
//void dependencyReplaced(Rule const *oldRule, Rule const *newRule);

private:
Rule const *_source;
Expand Down
18 changes: 3 additions & 15 deletions doomsday/libdeng2/include/de/widgets/operatorrule.h
Expand Up @@ -43,25 +43,13 @@ class OperatorRule : public Rule
};

public:
explicit OperatorRule(Operator op, Rule const *unary, QObject *parent = 0);
explicit OperatorRule(Operator op, Rule const *unary);

/**
* The operator rule takes ownership of the operands that have no parent.
*/
explicit OperatorRule(Operator op, Rule *unaryOwn, QObject *parent = 0);

explicit OperatorRule(Operator op, Rule const *left, Rule const *right, QObject *parent = 0);
explicit OperatorRule(Operator op, Rule const *left, Rule *rightOwn, QObject *parent = 0);
explicit OperatorRule(Operator op, Rule *leftOwn, Rule const *right, QObject *parent = 0);

/**
* The operator rule takes ownership of the operands that have no parent.
*/
explicit OperatorRule(Operator op, Rule *leftOwn, Rule *rightOwn, QObject *parent = 0);
explicit OperatorRule(Operator op, Rule const *left, Rule const *right);

protected:
void update();
void dependencyReplaced(Rule const *oldRule, Rule const *newRule);
//void dependencyReplaced(Rule const *oldRule, Rule const *newRule);

private:
Operator _operator;
Expand Down
33 changes: 11 additions & 22 deletions doomsday/libdeng2/include/de/widgets/rectanglerule.h
Expand Up @@ -51,23 +51,21 @@ class RectangleRule : public Rule
};

public:
explicit RectangleRule(QObject *parent = 0);
explicit RectangleRule();

/**
* Constructs a rectangle rule with individual rules defining the placement
* of the rectangle. Ownership of the input rules is not claimed.
* of the rectangle. References are kept to all non-NULL rules.
*
* @param left Rule for the left coordinate.
* @param top Rule for the top coordinate.
* @param right Rule for the right coordinate.
* @param bottom Rule for the bottom coordinate.
* @param parent Parent object.
*/
explicit RectangleRule(Rule const *left, Rule const *top, Rule const *right, Rule const *bottom, QObject *parent = 0);
explicit RectangleRule(Rule const *left, Rule const *top, Rule const *right, Rule const *bottom);

explicit RectangleRule(RectangleRule const *rect, QObject *parent = 0);

~RectangleRule();
explicit RectangleRule(RectangleRule const *rect);

// Output rules.
Rule const *left() const;
Expand All @@ -76,20 +74,10 @@ class RectangleRule : public Rule
Rule const *bottom() const;

/**
* Sets one of the input rules of the rectangle. If the particular rule has
* previously been defined, the old one is destroyed first.
*
* @param inputRule Input rule to set.
* @param ruleOwn RectangleRule claims ownership (if rule has no parent yet).
*/
RectangleRule &setInput(InputRule inputRule, Rule *ruleOwn);

/**
* Sets one of the input rules of the rectangle. If the particular rule has
* previously been defined, the old one is destroyed first.
* Sets one of the input rules of the rectangle.
*
* @param inputRule Input rule to set.
* @param rule RectangleRule does not take ownership.
* @param inputRule InputRule to set.
* @param rule Rule to use as input. A reference is held.
*/
RectangleRule &setInput(InputRule inputRule, Rule const *rule);

Expand Down Expand Up @@ -127,12 +115,13 @@ class RectangleRule : public Rule
Rectanglei recti() const;

public slots:
void currentTimeChanged();
void timeChanged();

protected:
void setup();
~RectangleRule();

void update();
void dependencyReplaced(Rule const *oldRule, Rule const *newRule);
//void dependencyReplaced(Rule const *oldRule, Rule const *newRule);

private:
struct Instance;
Expand Down
72 changes: 50 additions & 22 deletions doomsday/libdeng2/include/de/widgets/rule.h
Expand Up @@ -23,6 +23,7 @@
#include <QObject>
#include <QSet>
#include "../libdeng2.h"
#include "../Counted"

namespace de {

Expand All @@ -35,25 +36,30 @@ namespace de {
* - When the value changes, all dependent rules are notified and marked as invalid.
* - When a rule is invalid, its current value will be updated (i.e., validated).
* - Rules can be replaced dynamically with other rules, see Rule::replace().
* - Reference counting is used for lifetime management.
*
* @ingroup widgets
*/
class Rule : public QObject
class Rule : public QObject, public Counted
{
Q_OBJECT

public:
explicit Rule(QObject *parent = 0);
explicit Rule(float initialValue, QObject *parent = 0);
~Rule();
explicit Rule(float initialValue = 0);

/**
* Determines the rule's current value. If it has been marked invalid,
* the value is updated first (see update()).
*/
float value() const;

#if 0
/**
* Transfers this rule's dependencies to @a newRule. The dependent rules
* are updated accordingly. Afterwards, this rule has no more dependencies.
*/
void transferDependencies(Rule *toRule);
#endif

/**
* Updates the rule with a valid value. Derived classes must call
Expand All @@ -64,50 +70,72 @@ class Rule : public QObject
*/
virtual void update();

bool isValid() const;
public slots:
/**
* Marks the rule invalid, causing all dependent rules to be invalid, too.
*/
void invalidate();

protected:
~Rule(); // Counted

/**
* Links rules together. This rule will depend on @a dependency.
* Links rules together. This rule will depend on @a dependency; if @a
* dependency becomes invalid, this rule will likewise become invalid.
* @a dependency will hold a reference to this rule.
*/
void dependsOn(Rule const *dependency);

/**
* Unlinks rules. This rule will no longer depend on @a dependency.
* @a dependency will release its reference to this rule.
*/
void independentOf(Rule const *dependency);

/**
* Adds a dependent rule.
*
* @param rule Rule that depends on this rule. A reference to @a rule
* is retained.
*/
void addDependent(Rule *rule);
void removeDependent(Rule *rule);
void setValue(float value);

float cachedValue() const;

/**
* Takes ownership of a rule.
* Removes a dependent rule.
*
* @param child Rule whose ownership should be claimed.
* @param rule Rule that depends on this rule. A reference to @a rule
* is released.
*/
void removeDependent(Rule *rule);

/**
* Sets the current value of the rule and marks it valid.
*
* @return @c true, if ownership was taken.
* @param value New valid value.
*/
bool claim(Rule *child);
void setValue(float value);

float cachedValue() const;

#if 0
/**
* Called to notify that the dependency @a oldRule has been replaced with
* @a newRule.
*/
virtual void dependencyReplaced(Rule const *oldRule, Rule const *newRule);
#endif

void invalidateSilently();

public slots:
void invalidate();
signals:
void valueInvalidated();

#if 0
protected slots:
void ruleDestroyed(QObject *rule);

signals:
void valueInvalidated();
#endif

private:
QSet<Rule *> _dependentRules;
typedef QSet<Rule *> Dependents;
Dependents _dependentRules; // ref'd

/// Current value of the rule.
float _value;
Expand Down
9 changes: 2 additions & 7 deletions doomsday/libdeng2/include/de/widgets/scalarrule.h
Expand Up @@ -35,14 +35,12 @@ class ScalarRule : public Rule
Q_OBJECT

public:
explicit ScalarRule(float initialValue, QObject *parent = 0);
explicit ScalarRule(float initialValue);

void set(float target, TimeDelta transition = 0);

void set(Rule const *target, TimeDelta transition = 0);

void set(Rule *targetOwn, TimeDelta transition = 0);

/**
* Read-only access to the scalar animation.
*/
Expand All @@ -52,17 +50,14 @@ class ScalarRule : public Rule

protected:
void update();
void dependencyReplaced(Rule const *oldRule, Rule const *newRule);

void dismissTargetRule();
//void dependencyReplaced(Rule const *oldRule, Rule const *newRule);

protected slots:
void timeChanged();

private:
Animation _animation;
Rule const *_rule;
bool _ruleOwned;
};

} // namespace de
Expand Down

0 comments on commit 2cdaa9b

Please sign in to comment.