Nikolay Sivov : scrrun: Implement Add() and RemoveAll() for dictionary.

Alexandre Julliard julliard at wine.codeweavers.com
Mon Mar 2 08:51:51 CST 2015


Module: wine
Branch: master
Commit: 5f41a746e97be7f2a0fd7937bc4a1a0ab6b256b0
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=5f41a746e97be7f2a0fd7937bc4a1a0ab6b256b0

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Fri Feb 27 18:00:28 2015 +0300

scrrun: Implement Add() and RemoveAll() for dictionary.

---

 dlls/scrrun/dictionary.c       | 170 +++++++++++++++++++++++++++++++++++++++--
 dlls/scrrun/tests/dictionary.c |  10 +--
 2 files changed, 166 insertions(+), 14 deletions(-)

diff --git a/dlls/scrrun/dictionary.c b/dlls/scrrun/dictionary.c
index 958d7fc..5c1893a 100644
--- a/dlls/scrrun/dictionary.c
+++ b/dlls/scrrun/dictionary.c
@@ -32,9 +32,20 @@
 
 #include "wine/debug.h"
 #include "wine/unicode.h"
+#include "wine/list.h"
 
 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
 {
     IDictionary IDictionary_iface;
@@ -42,6 +53,8 @@ typedef struct
 
     CompareMethod method;
     LONG count;
+    struct list pairs;
+    struct keyitem_pair *buckets[BUCKET_COUNT];
 } dictionary;
 
 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);
 }
 
+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)
 {
     dictionary *This = impl_from_IDictionary(iface);
@@ -100,8 +240,10 @@ static ULONG WINAPI dictionary_Release(IDictionary *iface)
     TRACE("(%p)\n", This);
 
     ref = InterlockedDecrement(&This->ref);
-    if(ref == 0)
+    if(ref == 0) {
+        IDictionary_RemoveAll(iface);
         heap_free(This);
+    }
 
     return ref;
 }
@@ -192,13 +334,16 @@ static HRESULT WINAPI dictionary_get_Item(IDictionary *iface, VARIANT *Key, VARI
     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);
 
-    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)
@@ -259,10 +404,21 @@ static HRESULT WINAPI dictionary_Remove(IDictionary *iface, VARIANT *Key)
 static HRESULT WINAPI dictionary_RemoveAll(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)
@@ -415,6 +571,8 @@ HRESULT WINAPI Dictionary_CreateInstance(IClassFactory *factory,IUnknown *outer,
     This->ref = 1;
     This->method = BinaryCompare;
     This->count = 0;
+    list_init(&This->pairs);
+    memset(This->buckets, 0, sizeof(This->buckets));
 
     *obj = &This->IDictionary_iface;
 
diff --git a/dlls/scrrun/tests/dictionary.c b/dlls/scrrun/tests/dictionary.c
index 25cb0a6..066a5ab 100644
--- a/dlls/scrrun/tests/dictionary.c
+++ b/dlls/scrrun/tests/dictionary.c
@@ -64,7 +64,7 @@ static void test_interfaces(void)
     V_VT(&value) = VT_BSTR;
     V_BSTR(&value) = SysAllocString(key_add_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);
 
     exists = VARIANT_FALSE;
@@ -83,7 +83,7 @@ static void test_interfaces(void)
 
     hr = IDictionary_get_Count(dict, &count);
     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);
     IDispatch_Release(disp);
@@ -128,11 +128,9 @@ if (0) /* crashes on native */
     V_I2(&key) = 0;
     VariantInit(&item);
     hr = IDictionary_Add(dict, &key, &item);
-todo_wine
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
     hr = IDictionary_put_CompareMode(dict, BinaryCompare);
-todo_wine
     ok(hr == CTL_E_ILLEGALFUNCTIONCALL, "got 0x%08x\n", hr);
 
     IDictionary_Release(dict);
@@ -457,13 +455,11 @@ todo_wine {
 }
     VariantInit(&item);
     hr = IDictionary_Add(dict, &key, &item);
-todo_wine
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
     V_VT(&key) = VT_R4;
     V_R4(&key) = 0.0;
     hr = IDictionary_Add(dict, &key, &item);
-todo_wine
     ok(hr == CTL_E_KEY_ALREADY_EXISTS, "got 0x%08x\n", hr);
 
     V_VT(&key) = VT_I2;
@@ -519,7 +515,6 @@ todo_wine {
     V_R4(&key) = 0.0;
     VariantInit(&item);
     hr = IDictionary_Add(dict, &key, &item);
-todo_wine
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
     VariantInit(&keys);
@@ -570,7 +565,6 @@ todo_wine
 
     VariantInit(&item);
     hr = IDictionary_Add(dict, &key, &item);
-todo_wine
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
     hr = IDictionary_Remove(dict, &key);




More information about the wine-cvs mailing list