associative

来源:互联网 发布:云计算和超级计算机 编辑:程序博客网 时间:2024/04/30 18:13
id _object_get_associative_reference(id object, void *key) {    id value = nil;    uintptr_t policy = OBJC_ASSOCIATION_ASSIGN;    {        AssociationsManager manager;        AssociationsHashMap &associations(manager.associations());        disguised_ptr_t disguised_object = DISGUISE(object);        AssociationsHashMap::iterator i = associations.find(disguised_object);        if (i != associations.end()) {            ObjectAssociationMap *refs = i->second;            ObjectAssociationMap::iterator j = refs->find(key);            if (j != refs->end()) {                ObjcAssociation &entry = j->second;                value = entry.value();                policy = entry.policy();                if (policy & OBJC_ASSOCIATION_GETTER_RETAIN) ((id(*)(id, SEL))objc_msgSend)(value, SEL_retain);            }        }    }    if (value && (policy & OBJC_ASSOCIATION_GETTER_AUTORELEASE)) {        ((id(*)(id, SEL))objc_msgSend)(value, SEL_autorelease);    }    return value;}static id acquireValue(id value, uintptr_t policy) {    switch (policy & 0xFF) {    case OBJC_ASSOCIATION_SETTER_RETAIN:        return ((id(*)(id, SEL))objc_msgSend)(value, SEL_retain);    case OBJC_ASSOCIATION_SETTER_COPY:        return ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);    }    return value;}static void releaseValue(id value, uintptr_t policy) {    if (policy & OBJC_ASSOCIATION_SETTER_RETAIN) {        ((id(*)(id, SEL))objc_msgSend)(value, SEL_release);    }}struct ReleaseValue {    void operator() (ObjcAssociation &association) {        releaseValue(association.value(), association.policy());    }};void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {    // retain the new value (if any) outside the lock.    ObjcAssociation old_association(0, nil);    id new_value = value ? acquireValue(value, policy) : nil;    {        AssociationsManager manager;        AssociationsHashMap &associations(manager.associations());        disguised_ptr_t disguised_object = DISGUISE(object);        if (new_value) {            // break any existing association.            AssociationsHashMap::iterator i = associations.find(disguised_object);            if (i != associations.end()) {                // secondary table exists                ObjectAssociationMap *refs = i->second;                ObjectAssociationMap::iterator j = refs->find(key);                if (j != refs->end()) {                    old_association = j->second;                    j->second = ObjcAssociation(policy, new_value);                } else {                    (*refs)[key] = ObjcAssociation(policy, new_value);                }            } else {                // create the new association (first time).                ObjectAssociationMap *refs = new ObjectAssociationMap;                associations[disguised_object] = refs;                (*refs)[key] = ObjcAssociation(policy, new_value);                object->setHasAssociatedObjects();            }        } else {            // setting the association to nil breaks the association.            AssociationsHashMap::iterator i = associations.find(disguised_object);            if (i !=  associations.end()) {                ObjectAssociationMap *refs = i->second;                ObjectAssociationMap::iterator j = refs->find(key);                if (j != refs->end()) {                    old_association = j->second;                    refs->erase(j);                }            }        }    }    // release the old value (outside of the lock).    if (old_association.hasValue()) ReleaseValue()(old_association);}void _object_remove_assocations(id object) {    vector< ObjcAssociation,ObjcAllocator<ObjcAssociation> > elements;    {        AssociationsManager manager;        AssociationsHashMap &associations(manager.associations());        if (associations.size() == 0) return;        disguised_ptr_t disguised_object = DISGUISE(object);        AssociationsHashMap::iterator i = associations.find(disguised_object);        if (i != associations.end()) {            // copy all of the associations that need to be removed.            ObjectAssociationMap *refs = i->second;            for (ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) {                elements.push_back(j->second);            }            // remove the secondary table.            delete refs;            associations.erase(i);        }    }    // the calls to releaseValue() happen outside of the lock.    for_each(elements.begin(), elements.end(), ReleaseValue());}

0 0