📄 objmap.c
字号:
/* * This module implements a hash table class for mapping C/C++ addresses to the * corresponding wrapped Python object. * * Copyright (c) 2006 * Riverbank Computing Limited <info@riverbankcomputing.co.uk> * * This file is part of SIP. * * This copy of SIP is licensed for use under the terms of the SIP License * Agreement. See the file LICENSE for more details. * * SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */#include <string.h>#include "sip.h"#include "sipint.h"#define hash_1(k,s) (((unsigned long)(k)) % (s))#define hash_2(k,s) ((s) - 2 - (hash_1((k),(s)) % ((s) - 2)))/* Prime numbers to use as hash table sizes. */static unsigned long hash_primes[] = { 521, 1031, 2053, 4099, 8209, 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169, 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459, 536870923, 1073741827, 2147483659U,0};static sipHashEntry *newHashTable(unsigned long);static sipHashEntry *findHashEntry(sipObjectMap *,void *);static void reorganiseMap(sipObjectMap *om);/* * Initialise an object map. */void sipOMInit(sipObjectMap *om){ om -> primeIdx = 0; om -> unused = om -> size = hash_primes[om -> primeIdx]; om -> stale = 0; om -> hash_array = newHashTable(om -> size);}/* * Finalise an object map. */void sipOMFinalise(sipObjectMap *om){ sip_api_free(om -> hash_array);}/* * Allocate and initialise a new hash table. */static sipHashEntry *newHashTable(unsigned long size){ size_t nbytes; sipHashEntry *hashtab; nbytes = sizeof (sipHashEntry) * size; if ((hashtab = (sipHashEntry *)sip_api_malloc(nbytes)) != NULL) memset(hashtab,0,nbytes); return hashtab;}/* * Return a pointer to the hash entry that is used, or should be used, for the * given C/C++ address. */static sipHashEntry *findHashEntry(sipObjectMap *om,void *key){ unsigned long hash, inc; void *hek; hash = hash_1(key,om -> size); inc = hash_2(key,om -> size); while ((hek = om -> hash_array[hash].key) != NULL && hek != key) hash = (hash + inc) % om -> size; return &om -> hash_array[hash];}/* * Return the wrapped Python object of a specific type for a C/C++ address or * NULL if it wasn't found. */sipWrapper *sipOMFindObject(sipObjectMap *om,void *key,sipWrapperType *type){ sipHashEntry *he = findHashEntry(om,key); sipWrapper *w; /* Go through each wrapped object at this address. */ for (w = he -> first; w != NULL; w = w -> next) { /* * If this wrapped object is of the given type, or a sub-type * of it, or vice versa, then we assume it is the same C++ * object. */ if (PyObject_TypeCheck(w,&type -> super.type) || PyType_IsSubtype(&type -> super.type,w -> ob_type)) return w; } return NULL;}/* * Add a C/C++ address and the corresponding wrapped Python object to the map. */void sipOMAddObject(sipObjectMap *om,sipWrapper *val){ sipHashEntry *he = findHashEntry(om,val -> u.cppPtr); /* * If the bucket is in use then we appear to have several objects at * the same address. */ if (he -> first != NULL) { /* * This can happen for three reasons. A variable of one class * can be declared at the start of another class. Therefore * there are two objects, of different classes, with the same * address. The second reason is that the old C/C++ object has * been deleted by C/C++ but we didn't get to find out for some * reason, and a new C/C++ instance has been created at the * same address. The third reason is if we are in the process * of deleting a Python object but the C++ object gets wrapped * again because the C++ dtor called a method that has been * re-implemented in Python. The absence of the SIP_SHARE_MAP * flag tells us that a new C++ instance has just been created * and so we know the second reason is the correct one so we * mark the old pointers as invalid and reuse the entry. * Otherwise we just add this one to the existing list of * objects at this address. */ if (!(val -> flags & SIP_SHARE_MAP)) { sipWrapper *w; for (w = he -> first; w != NULL; w = w -> next) w -> u.cppPtr = NULL; he -> first = NULL; } val -> next = he -> first; he -> first = val; return; } /* See if the bucket was unused or stale. */ if (he -> key == NULL) { he -> key = val -> u.cppPtr; om -> unused--; } else om -> stale--; /* Add the rest of the new value. */ he -> first = val; val -> next = NULL; reorganiseMap(om);}/* * Reorganise a map if it is running short of space. */static void reorganiseMap(sipObjectMap *om){ unsigned long old_size, i; sipHashEntry *ohe, *old_tab; /* Don't bother if it still has more than 12% available. */ if (om -> unused > om -> size >> 3) return; /* * If reorganising (ie. making the stale buckets unused) using the same * sized table would make 25% available then do that. Otherwise use a * bigger table (if possible). */ if (om -> unused + om -> stale < om -> size >> 2 && hash_primes[om -> primeIdx + 1] != 0) om -> primeIdx++; old_size = om -> size; old_tab = om -> hash_array; om -> unused = om -> size = hash_primes[om -> primeIdx]; om -> stale = 0; om -> hash_array = newHashTable(om -> size); /* Transfer the entries from the old table to the new one. */ ohe = old_tab; for (i = 0; i < old_size; ++i) { if (ohe -> key != NULL && ohe -> first != NULL) { *findHashEntry(om,ohe -> key) = *ohe; om -> unused--; } ++ohe; } sip_api_free(old_tab);}/* * Remove a C/C++ object from the table. Return 0 if it was removed * successfully. */int sipOMRemoveObject(sipObjectMap *om,sipWrapper *val){ sipHashEntry *he = findHashEntry(om,val -> u.cppPtr); sipWrapper **wp; for (wp = &he -> first; *wp != NULL; wp = &(*wp) -> next) if (*wp == val) { *wp = val -> next; /* * If the bucket is now empty then count it as stale. * Note that we do not NULL the key and count it as * unused because that might throw out the search for * another entry that wanted to go here, found it * already occupied, and was put somewhere else. In * other words, searches must be repeatable until we * reorganise the table. */ if (he -> first == NULL) om -> stale++; return 0; } return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -