scrrun: Implement Add() and RemoveAll() for dictionary.
This commit is contained in:
parent
3765e08ddc
commit
5f41a746e9
|
@ -32,9 +32,20 @@
|
||||||
|
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
#include "wine/unicode.h"
|
#include "wine/unicode.h"
|
||||||
|
#include "wine/list.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(scrrun);
|
WINE_DEFAULT_DEBUG_CHANNEL(scrrun);
|
||||||
|
|
||||||
|
#define BUCKET_COUNT 509
|
||||||
|
|
||||||
|
struct keyitem_pair {
|
||||||
|
struct list entry;
|
||||||
|
DWORD bucket;
|
||||||
|
DWORD hash;
|
||||||
|
VARIANT key;
|
||||||
|
VARIANT item;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
IDictionary IDictionary_iface;
|
IDictionary IDictionary_iface;
|
||||||
|
@ -42,6 +53,8 @@ typedef struct
|
||||||
|
|
||||||
CompareMethod method;
|
CompareMethod method;
|
||||||
LONG count;
|
LONG count;
|
||||||
|
struct list pairs;
|
||||||
|
struct keyitem_pair *buckets[BUCKET_COUNT];
|
||||||
} dictionary;
|
} dictionary;
|
||||||
|
|
||||||
static inline dictionary *impl_from_IDictionary(IDictionary *iface)
|
static inline dictionary *impl_from_IDictionary(IDictionary *iface)
|
||||||
|
@ -49,6 +62,133 @@ static inline dictionary *impl_from_IDictionary(IDictionary *iface)
|
||||||
return CONTAINING_RECORD(iface, dictionary, IDictionary_iface);
|
return CONTAINING_RECORD(iface, dictionary, IDictionary_iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct keyitem_pair *get_bucket_head(const dictionary *dict, DWORD hash)
|
||||||
|
{
|
||||||
|
return dict->buckets[hash % BUCKET_COUNT];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline BOOL is_string_key(const VARIANT *key)
|
||||||
|
{
|
||||||
|
return V_VT(key) == VT_BSTR || V_VT(key) == (VT_BSTR|VT_BYREF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only for VT_BSTR or VT_BSTR|VT_BYREF types */
|
||||||
|
static inline WCHAR *get_key_strptr(const VARIANT *key)
|
||||||
|
{
|
||||||
|
if (V_VT(key) == VT_BSTR)
|
||||||
|
return V_BSTR(key);
|
||||||
|
|
||||||
|
if (V_BSTRREF(key))
|
||||||
|
return *V_BSTRREF(key);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* should be used only when both keys are of string type, it's not checked */
|
||||||
|
static inline int strcmp_key(const dictionary *dict, const VARIANT *key1, const VARIANT *key2)
|
||||||
|
{
|
||||||
|
const WCHAR *str1, *str2;
|
||||||
|
|
||||||
|
str1 = get_key_strptr(key1);
|
||||||
|
str2 = get_key_strptr(key2);
|
||||||
|
return dict->method == BinaryCompare ? strcmpW(str1, str2) : strcmpiW(str1, str2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL is_matching_key(const dictionary *dict, const struct keyitem_pair *pair, const VARIANT *key, DWORD hash)
|
||||||
|
{
|
||||||
|
if (is_string_key(key) && is_string_key(&pair->key)) {
|
||||||
|
if (hash != pair->hash)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return strcmp_key(dict, key, &pair->key) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((is_string_key(key) && !is_string_key(&pair->key)) ||
|
||||||
|
(!is_string_key(key) && is_string_key(&pair->key)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* for numeric keys only check hash */
|
||||||
|
return hash == pair->hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct keyitem_pair *get_keyitem_pair(dictionary *dict, VARIANT *key)
|
||||||
|
{
|
||||||
|
struct keyitem_pair *pair;
|
||||||
|
DWORD bucket;
|
||||||
|
VARIANT hash;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = IDictionary_get_HashVal(&dict->IDictionary_iface, key, &hash);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pair = get_bucket_head(dict, V_I4(&hash));
|
||||||
|
if (!pair)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
bucket = pair->bucket;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (is_matching_key(dict, pair, key, V_I4(&hash))) return pair;
|
||||||
|
pair = LIST_ENTRY(list_next(&dict->pairs, &pair->entry), struct keyitem_pair, entry);
|
||||||
|
if (pair && pair->bucket != bucket) break;
|
||||||
|
} while (pair != NULL);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT add_keyitem_pair(dictionary *dict, VARIANT *key, VARIANT *item)
|
||||||
|
{
|
||||||
|
struct keyitem_pair *pair, *head;
|
||||||
|
VARIANT hash;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = IDictionary_get_HashVal(&dict->IDictionary_iface, key, &hash);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
pair = heap_alloc(sizeof(*pair));
|
||||||
|
if (!pair)
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
|
pair->hash = V_I4(&hash);
|
||||||
|
pair->bucket = pair->hash % BUCKET_COUNT;
|
||||||
|
VariantInit(&pair->key);
|
||||||
|
VariantInit(&pair->item);
|
||||||
|
|
||||||
|
hr = VariantCopyInd(&pair->key, key);
|
||||||
|
if (FAILED(hr))
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
hr = VariantCopyInd(&pair->item, item);
|
||||||
|
if (FAILED(hr))
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
head = get_bucket_head(dict, pair->hash);
|
||||||
|
if (head)
|
||||||
|
list_add_tail(&head->entry, &pair->entry);
|
||||||
|
else {
|
||||||
|
dict->buckets[pair->bucket] = pair;
|
||||||
|
list_add_tail(&dict->pairs, &pair->entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
dict->count++;
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
VariantClear(&pair->key);
|
||||||
|
VariantClear(&pair->item);
|
||||||
|
heap_free(pair);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_keyitem_pair(struct keyitem_pair *pair)
|
||||||
|
{
|
||||||
|
VariantClear(&pair->key);
|
||||||
|
VariantClear(&pair->item);
|
||||||
|
heap_free(pair);
|
||||||
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI dictionary_QueryInterface(IDictionary *iface, REFIID riid, void **obj)
|
static HRESULT WINAPI dictionary_QueryInterface(IDictionary *iface, REFIID riid, void **obj)
|
||||||
{
|
{
|
||||||
dictionary *This = impl_from_IDictionary(iface);
|
dictionary *This = impl_from_IDictionary(iface);
|
||||||
|
@ -100,8 +240,10 @@ static ULONG WINAPI dictionary_Release(IDictionary *iface)
|
||||||
TRACE("(%p)\n", This);
|
TRACE("(%p)\n", This);
|
||||||
|
|
||||||
ref = InterlockedDecrement(&This->ref);
|
ref = InterlockedDecrement(&This->ref);
|
||||||
if(ref == 0)
|
if(ref == 0) {
|
||||||
|
IDictionary_RemoveAll(iface);
|
||||||
heap_free(This);
|
heap_free(This);
|
||||||
|
}
|
||||||
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
@ -192,13 +334,16 @@ static HRESULT WINAPI dictionary_get_Item(IDictionary *iface, VARIANT *Key, VARI
|
||||||
return E_NOTIMPL;
|
return E_NOTIMPL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI dictionary_Add(IDictionary *iface, VARIANT *Key, VARIANT *Item)
|
static HRESULT WINAPI dictionary_Add(IDictionary *iface, VARIANT *key, VARIANT *item)
|
||||||
{
|
{
|
||||||
dictionary *This = impl_from_IDictionary(iface);
|
dictionary *This = impl_from_IDictionary(iface);
|
||||||
|
|
||||||
FIXME("(%p)->(%p %p)\n", This, Key, Item);
|
TRACE("(%p)->(%s %s)\n", This, debugstr_variant(key), debugstr_variant(item));
|
||||||
|
|
||||||
return E_NOTIMPL;
|
if (get_keyitem_pair(This, key))
|
||||||
|
return CTL_E_KEY_ALREADY_EXISTS;
|
||||||
|
|
||||||
|
return add_keyitem_pair(This, key, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI dictionary_get_Count(IDictionary *iface, LONG *count)
|
static HRESULT WINAPI dictionary_get_Count(IDictionary *iface, LONG *count)
|
||||||
|
@ -259,10 +404,21 @@ static HRESULT WINAPI dictionary_Remove(IDictionary *iface, VARIANT *Key)
|
||||||
static HRESULT WINAPI dictionary_RemoveAll(IDictionary *iface)
|
static HRESULT WINAPI dictionary_RemoveAll(IDictionary *iface)
|
||||||
{
|
{
|
||||||
dictionary *This = impl_from_IDictionary(iface);
|
dictionary *This = impl_from_IDictionary(iface);
|
||||||
|
struct keyitem_pair *pair, *pair2;
|
||||||
|
|
||||||
FIXME("(%p)->()\n", This);
|
TRACE("(%p)\n", This);
|
||||||
|
|
||||||
return E_NOTIMPL;
|
if (This->count == 0)
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
|
LIST_FOR_EACH_ENTRY_SAFE(pair, pair2, &This->pairs, struct keyitem_pair, entry) {
|
||||||
|
list_remove(&pair->entry);
|
||||||
|
free_keyitem_pair(pair);
|
||||||
|
}
|
||||||
|
memset(This->buckets, 0, sizeof(This->buckets));
|
||||||
|
This->count = 0;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI dictionary_put_CompareMode(IDictionary *iface, CompareMethod method)
|
static HRESULT WINAPI dictionary_put_CompareMode(IDictionary *iface, CompareMethod method)
|
||||||
|
@ -415,6 +571,8 @@ HRESULT WINAPI Dictionary_CreateInstance(IClassFactory *factory,IUnknown *outer,
|
||||||
This->ref = 1;
|
This->ref = 1;
|
||||||
This->method = BinaryCompare;
|
This->method = BinaryCompare;
|
||||||
This->count = 0;
|
This->count = 0;
|
||||||
|
list_init(&This->pairs);
|
||||||
|
memset(This->buckets, 0, sizeof(This->buckets));
|
||||||
|
|
||||||
*obj = &This->IDictionary_iface;
|
*obj = &This->IDictionary_iface;
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ static void test_interfaces(void)
|
||||||
V_VT(&value) = VT_BSTR;
|
V_VT(&value) = VT_BSTR;
|
||||||
V_BSTR(&value) = SysAllocString(key_add_value);
|
V_BSTR(&value) = SysAllocString(key_add_value);
|
||||||
hr = IDictionary_Add(dict, &key, &value);
|
hr = IDictionary_Add(dict, &key, &value);
|
||||||
todo_wine ok(hr == S_OK, "got 0x%08x, expected 0x%08x\n", hr, S_OK);
|
ok(hr == S_OK, "got 0x%08x, expected 0x%08x\n", hr, S_OK);
|
||||||
VariantClear(&value);
|
VariantClear(&value);
|
||||||
|
|
||||||
exists = VARIANT_FALSE;
|
exists = VARIANT_FALSE;
|
||||||
|
@ -83,7 +83,7 @@ static void test_interfaces(void)
|
||||||
|
|
||||||
hr = IDictionary_get_Count(dict, &count);
|
hr = IDictionary_get_Count(dict, &count);
|
||||||
ok(hr == S_OK, "got 0x%08x, expected 0x%08x\n", hr, S_OK);
|
ok(hr == S_OK, "got 0x%08x, expected 0x%08x\n", hr, S_OK);
|
||||||
todo_wine ok(count == 1, "got %d, expected 1\n", count);
|
ok(count == 1, "got %d, expected 1\n", count);
|
||||||
|
|
||||||
IDictionary_Release(dict);
|
IDictionary_Release(dict);
|
||||||
IDispatch_Release(disp);
|
IDispatch_Release(disp);
|
||||||
|
@ -128,11 +128,9 @@ if (0) /* crashes on native */
|
||||||
V_I2(&key) = 0;
|
V_I2(&key) = 0;
|
||||||
VariantInit(&item);
|
VariantInit(&item);
|
||||||
hr = IDictionary_Add(dict, &key, &item);
|
hr = IDictionary_Add(dict, &key, &item);
|
||||||
todo_wine
|
|
||||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||||
|
|
||||||
hr = IDictionary_put_CompareMode(dict, BinaryCompare);
|
hr = IDictionary_put_CompareMode(dict, BinaryCompare);
|
||||||
todo_wine
|
|
||||||
ok(hr == CTL_E_ILLEGALFUNCTIONCALL, "got 0x%08x\n", hr);
|
ok(hr == CTL_E_ILLEGALFUNCTIONCALL, "got 0x%08x\n", hr);
|
||||||
|
|
||||||
IDictionary_Release(dict);
|
IDictionary_Release(dict);
|
||||||
|
@ -457,13 +455,11 @@ todo_wine {
|
||||||
}
|
}
|
||||||
VariantInit(&item);
|
VariantInit(&item);
|
||||||
hr = IDictionary_Add(dict, &key, &item);
|
hr = IDictionary_Add(dict, &key, &item);
|
||||||
todo_wine
|
|
||||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||||
|
|
||||||
V_VT(&key) = VT_R4;
|
V_VT(&key) = VT_R4;
|
||||||
V_R4(&key) = 0.0;
|
V_R4(&key) = 0.0;
|
||||||
hr = IDictionary_Add(dict, &key, &item);
|
hr = IDictionary_Add(dict, &key, &item);
|
||||||
todo_wine
|
|
||||||
ok(hr == CTL_E_KEY_ALREADY_EXISTS, "got 0x%08x\n", hr);
|
ok(hr == CTL_E_KEY_ALREADY_EXISTS, "got 0x%08x\n", hr);
|
||||||
|
|
||||||
V_VT(&key) = VT_I2;
|
V_VT(&key) = VT_I2;
|
||||||
|
@ -519,7 +515,6 @@ todo_wine {
|
||||||
V_R4(&key) = 0.0;
|
V_R4(&key) = 0.0;
|
||||||
VariantInit(&item);
|
VariantInit(&item);
|
||||||
hr = IDictionary_Add(dict, &key, &item);
|
hr = IDictionary_Add(dict, &key, &item);
|
||||||
todo_wine
|
|
||||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||||
|
|
||||||
VariantInit(&keys);
|
VariantInit(&keys);
|
||||||
|
@ -570,7 +565,6 @@ todo_wine
|
||||||
|
|
||||||
VariantInit(&item);
|
VariantInit(&item);
|
||||||
hr = IDictionary_Add(dict, &key, &item);
|
hr = IDictionary_Add(dict, &key, &item);
|
||||||
todo_wine
|
|
||||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||||
|
|
||||||
hr = IDictionary_Remove(dict, &key);
|
hr = IDictionary_Remove(dict, &key);
|
||||||
|
|
Loading…
Reference in New Issue