HashTable* Reference Counted, class zpp::htab_rc
The class htab_rc takes over a HashTable* and makes it its own, by incrementing its reference count, in the same way that a zval owner does. Just like htab_ptr, its HashTable* can be set to a nullptr. Like zend_string* the HashTable* can be marked as immutable, , a fixed constant in the PHP system, in which case nothing should be done to it, and the reference count is not touched. This is carried in the method lose(). In lose, the class disowns its current pointer, and has responsibility to call zend_array_destroy() if it is the last owner.
The default constructor of htab_own also creates its own minimum allocation HashTable*. This creates an initialized HashTable containing nothing, when used as a member variable in another class.
// Wcc htab_own. Disown the referenced pointer.
htab_own::~htab_own()
{
lose();
}
void htab_own::lose()
{
if (ht_) {
auto za = ht_;
ht_ = nullptr;
if (za->gc.u.type_info & GC_IMMUTABLE)
{
return;
}
if (GC_REFCOUNT(za) <= 1) {
zend_array_destroy(za);
}
else {
GC_TRY_DELREF(za);
}
}
}
Class htab_own has another of making sure that it has a writable HashTable* with a reference count of 1. The "make_own" method does similar to the SEPARATE_ARRAY macro for zval owned arrays. Creating a HashTable* from another htab_own has also requires direct array duplication. Two instances of htab_own cannot have the same HashTable*. The standard move operator constructor just switches pointer.
// Protected static function
HashTable*
htab_own::make_own(HashTable *h)
{
if (GC_REFCOUNT(h) > 1) {
HashTable* dup = zend_array_dup(h);
if (dup != h) {
// assume h was properly owned already
GC_TRY_DELREF(h);
}
return dup;
}
return h;
}
htab_own::htab_own(const htab_own& c)
{
ht_ = zend_array_dup(c.ht_);
}
// Moving HashTable*
htab_own::htab_own(htab_own&& m)
{
ht_ = m.ht_;
m.ht_ = nullptr;
dbg_dump(__FUNCTION__)
}
const htab_own&
htab_own::operator=(const htab_own& c){
if (ht_)
{
lose();
}
ht_ = c.ht_;
own();
ht_ = make_own(ht_);
return *this;
}
Of course htab_own default constructor creates its own HashTable* with a default reference count of 1. HT_MIN_SIZE is currently 8, so the only true minimum array is actually a nullptr. The methods result() or clear() will result in an empty array.
// protected
htab_own::init()
{
ht_ = zend_new_array(HT_MIN_SIZE);
}
htab_own::htab_own()
{
init();
}