Browse code

Mercyful Release

Nat! authored on 07-03-2016 14:00:12
Showing 22 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1 @@
1
+http://www.mulle-kybernetik.com/repositories/mulle-configuration
0 2
new file mode 100644
... ...
@@ -0,0 +1,4 @@
1
+https://www.mulle-kybernetik.com/repositories/mulle-allocator
2
+https://www.mulle-kybernetik.com/repositories/mulle-thread
3
+https://www.mulle-kybernetik.com/repositories/mulle-aba
4
+
0 5
new file mode 100644
... ...
@@ -0,0 +1,13 @@
1
+.DS_Store
2
+*~.*
3
+*[Bb]uild/
4
+.idea/
5
+mulle_mintomic/
6
+.repos/
7
+xcuserdata/
8
+project.xcworkspace/
9
+mulle-configuration/
10
+.bootstrap.auto/
11
+.bootstrap.local/
12
+dependencies/
13
+cityhash/
0 14
new file mode 100644
... ...
@@ -0,0 +1,31 @@
1
+cmake_minimum_required (VERSION 3.0)
2
+
3
+project (mulle-concurrent)
4
+
5
+
6
+# using include_directories is a little bit shitty
7
+include_directories( src
8
+src/hash
9
+)
10
+
11
+include_directories( SYSTEM
12
+dependencies/include
13
+)
14
+
15
+#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -g -DDEBUG -DMULLE_ABA_TRACE_LIST -DMULLE_ABA_TRACE_SWAP")
16
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -g -DNDEBUG")
17
+
18
+set( HEADERS
19
+src/pointerarray/mulle_concurrent_pointerarray.h
20
+src/hashmap/mulle_concurrent_hashmap.h
21
+)
22
+
23
+add_library( mulle_container
24
+src/pointerarray/mulle_concurrent_pointerarray.c
25
+src/hashmap/mulle_concurrent_hashmap.c
26
+)
27
+
28
+INSTALL( TARGETS mulle_concurrent DESTINATION "lib")
29
+INSTALL( FILES ${HEADERS} DESTINATION "include/mulle_concurrent")
30
+
31
+
0 32
new file mode 100644
... ...
@@ -0,0 +1,131 @@
1
+## `mulle_concurrent_pointerlist`
2
+
3
+A growing array of pointers. 
4
+
5
+Here is a simple usage example:
6
+```
7
+#include <mulle_standalone_concurrent/mulle_standalone_concurrent.h>
8
+
9
+
10
+static void   test( void)
11
+{
12
+   struct mulle_concurrent_pointerarray             map;
13
+   struct mulle_concurrent_pointerarrayenumerator   rover;
14
+   unsigned int                                     i;
15
+   void                                             *value;
16
+
17
+   _mulle_concurrent_pointerarray_init( &map, 0, NULL, NULL);
18
+
19
+   value = (void *) 0x1848;
20
+
21
+   _mulle_concurrent_pointerarray_add( &map, value);
22
+   value = _mulle_concurrent_pointerarray_get( &map, 0);
23
+   printf( "%p\n", value);
24
+
25
+   rover = mulle_concurrent_pointerarray_enumerate( &map);
26
+   while( _mulle_concurrent_pointerarrayenumerator_next( &rover, &value) == 1)
27
+   {
28
+      printf( "%p\n", value);
29
+   }
30
+   _mulle_concurrent_pointerarrayenumerator_done( &rover);
31
+
32
+   _mulle_concurrent_pointerarray_free( &map);
33
+}
34
+
35
+
36
+int   main( void)
37
+{
38
+   mulle_aba_init( &mulle_default_allocator);
39
+   mulle_aba_register();
40
+
41
+   test();
42
+
43
+   mulle_aba_unregister();
44
+   mulle_aba_done();
45
+
46
+   return( 0);
47
+}
48
+```
49
+
50
+## `mulle_concurrent_hashmap`
51
+
52
+A mutable map of pointers, indexed by a hash.
53
+
54
+Here is a also a simple usage example:
55
+
56
+```
57
+#include <mulle_standalone_concurrent/mulle_standalone_concurrent.h>
58
+
59
+static void  test( void)
60
+{
61
+   intptr_t                                     hash;
62
+   struct mulle_concurrent_hashmap             map;
63
+   struct mulle_concurrent_hashmapenumerator   rover;
64
+   unsigned int                                i;
65
+   void                                        *value;
66
+
67
+   _mulle_concurrent_hashmap_init( &map, 0, NULL, NULL);
68
+   {
69
+      _mulle_concurrent_hashmap_insert( &map, 100000, (void *) 0x1848);
70
+      value =  _mulle_concurrent_hashmap_lookup( &map, 100000);
71
+      printf( "%p\n", value);
72
+
73
+      value =  _mulle_concurrent_hashmap_lookup( &map, 123456);
74
+      printf( "%s\n", value == (void *) 0x1848 ? "unexpected" : "expected");
75
+
76
+
77
+      rover = mulle_concurrent_hashmap_enumerate( &map);
78
+      while( _mulle_concurrent_hashmapenumerator_next( &rover, &hash, &value) == 1)
79
+      {
80
+         printf( "%ld %p\n", hash, value);
81
+      }
82
+      _mulle_concurrent_hashmapenumerator_done( &rover);
83
+
84
+      _mulle_concurrent_hashmap_remove( &map, 100000, (void *) 0x1848);
85
+
86
+      value =  _mulle_concurrent_hashmap_lookup( &map, 100000);
87
+      printf( "%s\n", value == (void *) 0x1848 ? "unexpected" : "expected");
88
+   }
89
+   _mulle_concurrent_hashmap_free( &map);
90
+}
91
+
92
+
93
+
94
+int   main( void)
95
+{
96
+   mulle_aba_init( &mulle_default_allocator);
97
+   mulle_aba_register();
98
+
99
+   test();
100
+
101
+   mulle_aba_unregister();
102
+   mulle_aba_done();
103
+
104
+   return( 0);
105
+}
106
+```
107
+
108
+## Dependencies
109
+
110
+* mulle_allocator
111
+* mulle_thread
112
+* mulle_aba
113
+
114
+## How to build on OS X
115
+
116
+Get the newest version of `mulle-bootstrap`
117
+
118
+```
119
+brew tap mulle-kybernetik/software
120
+brew install mulle-bootstrap
121
+```
122
+
123
+Download this repository
124
+
125
+```
126
+git clone https://www.mulle-kybernetik.com/repositories/mulle-concurrent
127
+
128
+# download and build dependencies
129
+cd mulle-concurrent
130
+mulle-bootstrap
131
+```
0 132
new file mode 100644
... ...
@@ -0,0 +1,632 @@
1
+// !$*UTF8*$!
2
+{
3
+	archiveVersion = 1;
4
+	classes = {
5
+	};
6
+	objectVersion = 46;
7
+	objects = {
8
+
9
+/* Begin PBXAggregateTarget section */
10
+		41CAEAC81C8D95A6003C2C7B /* Libraries */ = {
11
+			isa = PBXAggregateTarget;
12
+			buildConfigurationList = 41CAEAC91C8D95A6003C2C7B /* Build configuration list for PBXAggregateTarget "Libraries" */;
13
+			buildPhases = (
14
+			);
15
+			dependencies = (
16
+				41CAEACD1C8D95B0003C2C7B /* PBXTargetDependency */,
17
+				41CAEACF1C8D95B0003C2C7B /* PBXTargetDependency */,
18
+			);
19
+			name = Libraries;
20
+			productName = Libraries;
21
+		};
22
+/* End PBXAggregateTarget section */
23
+
24
+/* Begin PBXBuildFile section */
25
+		41CAEAD21C8D95BB003C2C7B /* libmulle_concurrent.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 41F14FE61B68F098002189F1 /* libmulle_concurrent.a */; };
26
+		41CAEAD61C8D95D4003C2C7B /* libmulle_aba.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 41CAEAD31C8D95D4003C2C7B /* libmulle_aba.a */; };
27
+		41CAEAD81C8D95D4003C2C7B /* libmulle_allocator.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 41CAEAD51C8D95D4003C2C7B /* libmulle_allocator.a */; };
28
+		41CAEADA1C8D95ED003C2C7B /* mulle_concurrent.h in Headers */ = {isa = PBXBuildFile; fileRef = 41CAEAD91C8D95ED003C2C7B /* mulle_concurrent.h */; settings = {ATTRIBUTES = (Public, ); }; };
29
+		41CAEADC1C8D9601003C2C7B /* mulle_standalone_concurrent.h in Headers */ = {isa = PBXBuildFile; fileRef = 41CAEADB1C8D9601003C2C7B /* mulle_standalone_concurrent.h */; settings = {ATTRIBUTES = (Public, ); }; };
30
+		41CAEADF1C8D98F0003C2C7B /* mulle_standalone_concurrent.c in Sources */ = {isa = PBXBuildFile; fileRef = 41CAEADE1C8D98F0003C2C7B /* mulle_standalone_concurrent.c */; };
31
+		41CAEAE11C8D9D98003C2C7B /* mulle_concurrent_types.h in Headers */ = {isa = PBXBuildFile; fileRef = 41CAEAE01C8D9D98003C2C7B /* mulle_concurrent_types.h */; settings = {ATTRIBUTES = (Public, ); }; };
32
+		41CAEAEF1C8DA00F003C2C7B /* hashmap.c in Sources */ = {isa = PBXBuildFile; fileRef = 41CAEAEE1C8DA00F003C2C7B /* hashmap.c */; };
33
+		41CAEAF21C8DA09C003C2C7B /* libmulle_standalone_concurrent.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 41CAEAC41C8D9599003C2C7B /* libmulle_standalone_concurrent.dylib */; };
34
+		41CAEB001C8DA224003C2C7B /* libmulle_standalone_concurrent.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 41CAEAC41C8D9599003C2C7B /* libmulle_standalone_concurrent.dylib */; };
35
+		41CAEB041C8DA251003C2C7B /* pointerarray.c in Sources */ = {isa = PBXBuildFile; fileRef = 41CAEB031C8DA251003C2C7B /* pointerarray.c */; };
36
+		41CAEB061C8DA326003C2C7B /* libmulle_test_allocator.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 41CAEB051C8DA326003C2C7B /* libmulle_test_allocator.a */; };
37
+		41CAEB071C8DA518003C2C7B /* libmulle_test_allocator.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 41CAEB051C8DA326003C2C7B /* libmulle_test_allocator.a */; };
38
+		41CAEB081C8DA51E003C2C7B /* libmulle_test_allocator.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 41CAEB051C8DA326003C2C7B /* libmulle_test_allocator.a */; };
39
+		41D8BA821C8D92DE00186ECE /* mulle_concurrent_hashmap.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D8BA7D1C8D92DE00186ECE /* mulle_concurrent_hashmap.c */; };
40
+		41D8BA831C8D92DE00186ECE /* mulle_concurrent_hashmap.h in Headers */ = {isa = PBXBuildFile; fileRef = 41D8BA7E1C8D92DE00186ECE /* mulle_concurrent_hashmap.h */; settings = {ATTRIBUTES = (Public, ); }; };
41
+		41D8BA841C8D92DE00186ECE /* mulle_concurrent_pointerarray.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D8BA801C8D92DE00186ECE /* mulle_concurrent_pointerarray.c */; };
42
+		41D8BA851C8D92DE00186ECE /* mulle_concurrent_pointerarray.h in Headers */ = {isa = PBXBuildFile; fileRef = 41D8BA811C8D92DE00186ECE /* mulle_concurrent_pointerarray.h */; settings = {ATTRIBUTES = (Public, ); }; };
43
+/* End PBXBuildFile section */
44
+
45
+/* Begin PBXContainerItemProxy section */
46
+		41CAEACC1C8D95B0003C2C7B /* PBXContainerItemProxy */ = {
47
+			isa = PBXContainerItemProxy;
48
+			containerPortal = 414785241ABAF290002DBAE4 /* Project object */;
49
+			proxyType = 1;
50
+			remoteGlobalIDString = 41F14FE51B68F098002189F1;
51
+			remoteInfo = mulle_container;
52
+		};
53
+		41CAEACE1C8D95B0003C2C7B /* PBXContainerItemProxy */ = {
54
+			isa = PBXContainerItemProxy;
55
+			containerPortal = 414785241ABAF290002DBAE4 /* Project object */;
56
+			proxyType = 1;
57
+			remoteGlobalIDString = 41CAEAC31C8D9599003C2C7B;
58
+			remoteInfo = mulle_standalone_concurrent;
59
+		};
60
+		41CAEAD01C8D95B5003C2C7B /* PBXContainerItemProxy */ = {
61
+			isa = PBXContainerItemProxy;
62
+			containerPortal = 414785241ABAF290002DBAE4 /* Project object */;
63
+			proxyType = 1;
64
+			remoteGlobalIDString = 41F14FE51B68F098002189F1;
65
+			remoteInfo = mulle_container;
66
+		};
67
+		41CAEAF01C8DA098003C2C7B /* PBXContainerItemProxy */ = {
68
+			isa = PBXContainerItemProxy;
69
+			containerPortal = 414785241ABAF290002DBAE4 /* Project object */;
70
+			proxyType = 1;
71
+			remoteGlobalIDString = 41CAEAC31C8D9599003C2C7B;
72
+			remoteInfo = mulle_standalone_concurrent;
73
+		};
74
+		41CAEAFE1C8DA221003C2C7B /* PBXContainerItemProxy */ = {
75
+			isa = PBXContainerItemProxy;
76
+			containerPortal = 414785241ABAF290002DBAE4 /* Project object */;
77
+			proxyType = 1;
78
+			remoteGlobalIDString = 41CAEAC31C8D9599003C2C7B;
79
+			remoteInfo = mulle_standalone_concurrent;
80
+		};
81
+/* End PBXContainerItemProxy section */
82
+
83
+/* Begin PBXFileReference section */
84
+		411A28C11BCD446E00D39FF7 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
85
+		417C02651BD8404E005A3751 /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
86
+		417C02681BD8404E005A3751 /* Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
87
+		417C026A1BD8404E005A3751 /* StaticLibraryIOS.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = StaticLibraryIOS.xcconfig; sourceTree = "<group>"; };
88
+		417C026B1BD8404E005A3751 /* StaticLibraryOSX.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = StaticLibraryOSX.xcconfig; sourceTree = "<group>"; };
89
+		417C026C1BD8404E005A3751 /* ToolOSX.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ToolOSX.xcconfig; sourceTree = "<group>"; };
90
+		41CAEAC41C8D9599003C2C7B /* libmulle_standalone_concurrent.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libmulle_standalone_concurrent.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
91
+		41CAEAD31C8D95D4003C2C7B /* libmulle_aba.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmulle_aba.a; path = dependencies/lib/Debug/libmulle_aba.a; sourceTree = "<group>"; };
92
+		41CAEAD41C8D95D4003C2C7B /* libmulle_thread.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmulle_thread.a; path = dependencies/lib/Debug/libmulle_thread.a; sourceTree = "<group>"; };
93
+		41CAEAD51C8D95D4003C2C7B /* libmulle_allocator.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmulle_allocator.a; path = dependencies/lib/Debug/libmulle_allocator.a; sourceTree = "<group>"; };
94
+		41CAEAD91C8D95ED003C2C7B /* mulle_concurrent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mulle_concurrent.h; sourceTree = "<group>"; };
95
+		41CAEADB1C8D9601003C2C7B /* mulle_standalone_concurrent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mulle_standalone_concurrent.h; sourceTree = "<group>"; };
96
+		41CAEADD1C8D982D003C2C7B /* DynamicLibraryOSX.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DynamicLibraryOSX.xcconfig; sourceTree = "<group>"; };
97
+		41CAEADE1C8D98F0003C2C7B /* mulle_standalone_concurrent.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mulle_standalone_concurrent.c; sourceTree = "<group>"; };
98
+		41CAEAE01C8D9D98003C2C7B /* mulle_concurrent_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mulle_concurrent_types.h; sourceTree = "<group>"; };
99
+		41CAEAE71C8D9FF4003C2C7B /* test-hashmap */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "test-hashmap"; sourceTree = BUILT_PRODUCTS_DIR; };
100
+		41CAEAEE1C8DA00F003C2C7B /* hashmap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hashmap.c; path = tests/hashmap/hashmap.c; sourceTree = SOURCE_ROOT; };
101
+		41CAEAF71C8DA20F003C2C7B /* test-pointerarray */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "test-pointerarray"; sourceTree = BUILT_PRODUCTS_DIR; };
102
+		41CAEB031C8DA251003C2C7B /* pointerarray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pointerarray.c; sourceTree = "<group>"; };
103
+		41CAEB051C8DA326003C2C7B /* libmulle_test_allocator.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmulle_test_allocator.a; path = dependencies/lib/Debug/libmulle_test_allocator.a; sourceTree = "<group>"; };
104
+		41CAEB091C8DB97F003C2C7B /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
105
+		41D8BA7D1C8D92DE00186ECE /* mulle_concurrent_hashmap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mulle_concurrent_hashmap.c; sourceTree = "<group>"; };
106
+		41D8BA7E1C8D92DE00186ECE /* mulle_concurrent_hashmap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mulle_concurrent_hashmap.h; sourceTree = "<group>"; };
107
+		41D8BA801C8D92DE00186ECE /* mulle_concurrent_pointerarray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mulle_concurrent_pointerarray.c; sourceTree = "<group>"; };
108
+		41D8BA811C8D92DE00186ECE /* mulle_concurrent_pointerarray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mulle_concurrent_pointerarray.h; sourceTree = "<group>"; };
109
+		41F14FE61B68F098002189F1 /* libmulle_concurrent.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libmulle_concurrent.a; sourceTree = BUILT_PRODUCTS_DIR; };
110
+/* End PBXFileReference section */
111
+
112
+/* Begin PBXFrameworksBuildPhase section */
113
+		41CAEAC11C8D9599003C2C7B /* Frameworks */ = {
114
+			isa = PBXFrameworksBuildPhase;
115
+			buildActionMask = 2147483647;
116
+			files = (
117
+				41CAEAD61C8D95D4003C2C7B /* libmulle_aba.a in Frameworks */,
118
+				41CAEAD81C8D95D4003C2C7B /* libmulle_allocator.a in Frameworks */,
119
+				41CAEB061C8DA326003C2C7B /* libmulle_test_allocator.a in Frameworks */,
120
+				41CAEAD21C8D95BB003C2C7B /* libmulle_concurrent.a in Frameworks */,
121
+			);
122
+			runOnlyForDeploymentPostprocessing = 0;
123
+		};
124
+		41CAEAE41C8D9FF4003C2C7B /* Frameworks */ = {
125
+			isa = PBXFrameworksBuildPhase;
126
+			buildActionMask = 2147483647;
127
+			files = (
128
+				41CAEB071C8DA518003C2C7B /* libmulle_test_allocator.a in Frameworks */,
129
+				41CAEAF21C8DA09C003C2C7B /* libmulle_standalone_concurrent.dylib in Frameworks */,
130
+			);
131
+			runOnlyForDeploymentPostprocessing = 0;
132
+		};
133
+		41CAEAF41C8DA20F003C2C7B /* Frameworks */ = {
134
+			isa = PBXFrameworksBuildPhase;
135
+			buildActionMask = 2147483647;
136
+			files = (
137
+				41CAEB001C8DA224003C2C7B /* libmulle_standalone_concurrent.dylib in Frameworks */,
138
+				41CAEB081C8DA51E003C2C7B /* libmulle_test_allocator.a in Frameworks */,
139
+			);
140
+			runOnlyForDeploymentPostprocessing = 0;
141
+		};
142
+		41F14FE31B68F098002189F1 /* Frameworks */ = {
143
+			isa = PBXFrameworksBuildPhase;
144
+			buildActionMask = 2147483647;
145
+			files = (
146
+			);
147
+			runOnlyForDeploymentPostprocessing = 0;
148
+		};
149
+/* End PBXFrameworksBuildPhase section */
150
+
151
+/* Begin PBXGroup section */
152
+		414785231ABAF290002DBAE4 = {
153
+			isa = PBXGroup;
154
+			children = (
155
+				41CAEB091C8DB97F003C2C7B /* README.md */,
156
+				411A28C11BCD446E00D39FF7 /* CMakeLists.txt */,
157
+				417C02631BD8404E005A3751 /* mulle-configuration */,
158
+				4147852E1ABAF290002DBAE4 /* src */,
159
+				41CAEAE21C8D9F23003C2C7B /* Libraries */,
160
+				41CAEAE81C8D9FF4003C2C7B /* test-hashmap */,
161
+				41CAEAF81C8DA20F003C2C7B /* test-pointerarray */,
162
+				4147852D1ABAF290002DBAE4 /* Products */,
163
+			);
164
+			sourceTree = "<group>";
165
+		};
166
+		4147852D1ABAF290002DBAE4 /* Products */ = {
167
+			isa = PBXGroup;
168
+			children = (
169
+				41F14FE61B68F098002189F1 /* libmulle_concurrent.a */,
170
+				41CAEAC41C8D9599003C2C7B /* libmulle_standalone_concurrent.dylib */,
171
+				41CAEAE71C8D9FF4003C2C7B /* test-hashmap */,
172
+				41CAEAF71C8DA20F003C2C7B /* test-pointerarray */,
173
+			);
174
+			name = Products;
175
+			sourceTree = "<group>";
176
+		};
177
+		4147852E1ABAF290002DBAE4 /* src */ = {
178
+			isa = PBXGroup;
179
+			children = (
180
+				41CAEAD91C8D95ED003C2C7B /* mulle_concurrent.h */,
181
+				41CAEAE01C8D9D98003C2C7B /* mulle_concurrent_types.h */,
182
+				41CAEADB1C8D9601003C2C7B /* mulle_standalone_concurrent.h */,
183
+				41CAEADE1C8D98F0003C2C7B /* mulle_standalone_concurrent.c */,
184
+				41D8BA7C1C8D92DE00186ECE /* hashmap */,
185
+				41D8BA7F1C8D92DE00186ECE /* pointerarray */,
186
+			);
187
+			path = src;
188
+			sourceTree = "<group>";
189
+		};
190
+		417C02631BD8404E005A3751 /* mulle-configuration */ = {
191
+			isa = PBXGroup;
192
+			children = (
193
+				41CAEADD1C8D982D003C2C7B /* DynamicLibraryOSX.xcconfig */,
194
+				417C02651BD8404E005A3751 /* Debug.xcconfig */,
195
+				417C02681BD8404E005A3751 /* Release.xcconfig */,
196
+				417C026A1BD8404E005A3751 /* StaticLibraryIOS.xcconfig */,
197
+				417C026B1BD8404E005A3751 /* StaticLibraryOSX.xcconfig */,
198
+				417C026C1BD8404E005A3751 /* ToolOSX.xcconfig */,
199
+			);
200
+			path = "mulle-configuration";
201
+			sourceTree = "<group>";
202
+		};
203
+		41CAEAE21C8D9F23003C2C7B /* Libraries */ = {
204
+			isa = PBXGroup;
205
+			children = (
206
+				41CAEB051C8DA326003C2C7B /* libmulle_test_allocator.a */,
207
+				41CAEAD31C8D95D4003C2C7B /* libmulle_aba.a */,
208
+				41CAEAD41C8D95D4003C2C7B /* libmulle_thread.a */,
209
+				41CAEAD51C8D95D4003C2C7B /* libmulle_allocator.a */,
210
+			);
211
+			name = Libraries;
212
+			sourceTree = "<group>";
213
+		};
214
+		41CAEAE81C8D9FF4003C2C7B /* test-hashmap */ = {
215
+			isa = PBXGroup;
216
+			children = (
217
+				41CAEAEE1C8DA00F003C2C7B /* hashmap.c */,
218
+			);
219
+			path = "test-hashmap";
220
+			sourceTree = "<group>";
221
+		};
222
+		41CAEAF81C8DA20F003C2C7B /* test-pointerarray */ = {
223
+			isa = PBXGroup;
224
+			children = (
225
+				41CAEB031C8DA251003C2C7B /* pointerarray.c */,
226
+			);
227
+			name = "test-pointerarray";
228
+			path = tests/pointerarray;
229
+			sourceTree = "<group>";
230
+		};
231
+		41D8BA7C1C8D92DE00186ECE /* hashmap */ = {
232
+			isa = PBXGroup;
233
+			children = (
234
+				41D8BA7E1C8D92DE00186ECE /* mulle_concurrent_hashmap.h */,
235
+				41D8BA7D1C8D92DE00186ECE /* mulle_concurrent_hashmap.c */,
236
+			);
237
+			path = hashmap;
238
+			sourceTree = "<group>";
239
+		};
240
+		41D8BA7F1C8D92DE00186ECE /* pointerarray */ = {
241
+			isa = PBXGroup;
242
+			children = (
243
+				41D8BA811C8D92DE00186ECE /* mulle_concurrent_pointerarray.h */,
244
+				41D8BA801C8D92DE00186ECE /* mulle_concurrent_pointerarray.c */,
245
+			);
246
+			path = pointerarray;
247
+			sourceTree = "<group>";
248
+		};
249
+/* End PBXGroup section */
250
+
251
+/* Begin PBXHeadersBuildPhase section */
252
+		4105ABF01BCB088A00D45AA8 /* Headers */ = {
253
+			isa = PBXHeadersBuildPhase;
254
+			buildActionMask = 2147483647;
255
+			files = (
256
+				41CAEADA1C8D95ED003C2C7B /* mulle_concurrent.h in Headers */,
257
+				41CAEAE11C8D9D98003C2C7B /* mulle_concurrent_types.h in Headers */,
258
+				41D8BA851C8D92DE00186ECE /* mulle_concurrent_pointerarray.h in Headers */,
259
+				41D8BA831C8D92DE00186ECE /* mulle_concurrent_hashmap.h in Headers */,
260
+			);
261
+			runOnlyForDeploymentPostprocessing = 0;
262
+		};
263
+		41CAEAC21C8D9599003C2C7B /* Headers */ = {
264
+			isa = PBXHeadersBuildPhase;
265
+			buildActionMask = 2147483647;
266
+			files = (
267
+				41CAEADC1C8D9601003C2C7B /* mulle_standalone_concurrent.h in Headers */,
268
+			);
269
+			runOnlyForDeploymentPostprocessing = 0;
270
+		};
271
+/* End PBXHeadersBuildPhase section */
272
+
273
+/* Begin PBXNativeTarget section */
274
+		41CAEAC31C8D9599003C2C7B /* mulle_standalone_concurrent */ = {
275
+			isa = PBXNativeTarget;
276
+			buildConfigurationList = 41CAEAC51C8D9599003C2C7B /* Build configuration list for PBXNativeTarget "mulle_standalone_concurrent" */;
277
+			buildPhases = (
278
+				41CAEAC01C8D9599003C2C7B /* Sources */,
279
+				41CAEAC11C8D9599003C2C7B /* Frameworks */,
280
+				41CAEAC21C8D9599003C2C7B /* Headers */,
281
+			);
282
+			buildRules = (
283
+			);
284
+			dependencies = (
285
+				41CAEAD11C8D95B5003C2C7B /* PBXTargetDependency */,
286
+			);
287
+			name = mulle_standalone_concurrent;
288
+			productName = mulle_standalone_concurrent;
289
+			productReference = 41CAEAC41C8D9599003C2C7B /* libmulle_standalone_concurrent.dylib */;
290
+			productType = "com.apple.product-type.library.dynamic";
291
+		};
292
+		41CAEAE61C8D9FF4003C2C7B /* test-hashmap */ = {
293
+			isa = PBXNativeTarget;
294
+			buildConfigurationList = 41CAEAEB1C8D9FF4003C2C7B /* Build configuration list for PBXNativeTarget "test-hashmap" */;
295
+			buildPhases = (
296
+				41CAEAE31C8D9FF4003C2C7B /* Sources */,
297
+				41CAEAE41C8D9FF4003C2C7B /* Frameworks */,
298
+			);
299
+			buildRules = (
300
+			);
301
+			dependencies = (
302
+				41CAEAF11C8DA098003C2C7B /* PBXTargetDependency */,
303
+			);
304
+			name = "test-hashmap";
305
+			productName = "test-hashmap";
306
+			productReference = 41CAEAE71C8D9FF4003C2C7B /* test-hashmap */;
307
+			productType = "com.apple.product-type.tool";
308
+		};
309
+		41CAEAF61C8DA20F003C2C7B /* test-pointerarray */ = {
310
+			isa = PBXNativeTarget;
311
+			buildConfigurationList = 41CAEAFB1C8DA20F003C2C7B /* Build configuration list for PBXNativeTarget "test-pointerarray" */;
312
+			buildPhases = (
313
+				41CAEAF31C8DA20F003C2C7B /* Sources */,
314
+				41CAEAF41C8DA20F003C2C7B /* Frameworks */,
315
+			);
316
+			buildRules = (
317
+			);
318
+			dependencies = (
319
+				41CAEAFF1C8DA221003C2C7B /* PBXTargetDependency */,
320
+			);
321
+			name = "test-pointerarray";
322
+			productName = "test-pointerlist";
323
+			productReference = 41CAEAF71C8DA20F003C2C7B /* test-pointerarray */;
324
+			productType = "com.apple.product-type.tool";
325
+		};
326
+		41F14FE51B68F098002189F1 /* mulle_concurrent */ = {
327
+			isa = PBXNativeTarget;
328
+			buildConfigurationList = 41F14FE71B68F098002189F1 /* Build configuration list for PBXNativeTarget "mulle_concurrent" */;
329
+			buildPhases = (
330
+				41F14FE21B68F098002189F1 /* Sources */,
331
+				4105ABF01BCB088A00D45AA8 /* Headers */,
332
+				41F14FE31B68F098002189F1 /* Frameworks */,
333
+			);
334
+			buildRules = (
335
+			);
336
+			dependencies = (
337
+			);
338
+			name = mulle_concurrent;
339
+			productName = mulle_aba;
340
+			productReference = 41F14FE61B68F098002189F1 /* libmulle_concurrent.a */;
341
+			productType = "com.apple.product-type.library.static";
342
+		};
343
+/* End PBXNativeTarget section */
344
+
345
+/* Begin PBXProject section */
346
+		414785241ABAF290002DBAE4 /* Project object */ = {
347
+			isa = PBXProject;
348
+			attributes = {
349
+				LastUpgradeCheck = 0640;
350
+				ORGANIZATIONNAME = "Mulle kybernetiK";
351
+				TargetAttributes = {
352
+					41CAEAC31C8D9599003C2C7B = {
353
+						CreatedOnToolsVersion = 7.2.1;
354
+					};
355
+					41CAEAC81C8D95A6003C2C7B = {
356
+						CreatedOnToolsVersion = 7.2.1;
357
+					};
358
+					41CAEAE61C8D9FF4003C2C7B = {
359
+						CreatedOnToolsVersion = 7.2.1;
360
+					};
361
+					41CAEAF61C8DA20F003C2C7B = {
362
+						CreatedOnToolsVersion = 7.2.1;
363
+					};
364
+					41F14FE51B68F098002189F1 = {
365
+						CreatedOnToolsVersion = 6.2;
366
+					};
367
+				};
368
+			};
369
+			buildConfigurationList = 414785271ABAF290002DBAE4 /* Build configuration list for PBXProject "mulle-concurrent" */;
370
+			compatibilityVersion = "Xcode 3.2";
371
+			developmentRegion = English;
372
+			hasScannedForEncodings = 0;
373
+			knownRegions = (
374
+				en,
375
+				Base,
376
+			);
377
+			mainGroup = 414785231ABAF290002DBAE4;
378
+			productRefGroup = 4147852D1ABAF290002DBAE4 /* Products */;
379
+			projectDirPath = "";
380
+			projectRoot = "";
381
+			targets = (
382
+				41CAEAC81C8D95A6003C2C7B /* Libraries */,
383
+				41F14FE51B68F098002189F1 /* mulle_concurrent */,
384
+				41CAEAC31C8D9599003C2C7B /* mulle_standalone_concurrent */,
385
+				41CAEAE61C8D9FF4003C2C7B /* test-hashmap */,
386
+				41CAEAF61C8DA20F003C2C7B /* test-pointerarray */,
387
+			);
388
+		};
389
+/* End PBXProject section */
390
+
391
+/* Begin PBXSourcesBuildPhase section */
392
+		41CAEAC01C8D9599003C2C7B /* Sources */ = {
393
+			isa = PBXSourcesBuildPhase;
394
+			buildActionMask = 2147483647;
395
+			files = (
396
+				41CAEADF1C8D98F0003C2C7B /* mulle_standalone_concurrent.c in Sources */,
397
+			);
398
+			runOnlyForDeploymentPostprocessing = 0;
399
+		};
400
+		41CAEAE31C8D9FF4003C2C7B /* Sources */ = {
401
+			isa = PBXSourcesBuildPhase;
402
+			buildActionMask = 2147483647;
403
+			files = (
404
+				41CAEAEF1C8DA00F003C2C7B /* hashmap.c in Sources */,
405
+			);
406
+			runOnlyForDeploymentPostprocessing = 0;
407
+		};
408
+		41CAEAF31C8DA20F003C2C7B /* Sources */ = {
409
+			isa = PBXSourcesBuildPhase;
410
+			buildActionMask = 2147483647;
411
+			files = (
412
+				41CAEB041C8DA251003C2C7B /* pointerarray.c in Sources */,
413
+			);
414
+			runOnlyForDeploymentPostprocessing = 0;
415
+		};
416
+		41F14FE21B68F098002189F1 /* Sources */ = {
417
+			isa = PBXSourcesBuildPhase;
418
+			buildActionMask = 2147483647;
419
+			files = (
420
+				41D8BA841C8D92DE00186ECE /* mulle_concurrent_pointerarray.c in Sources */,
421
+				41D8BA821C8D92DE00186ECE /* mulle_concurrent_hashmap.c in Sources */,
422
+			);
423
+			runOnlyForDeploymentPostprocessing = 0;
424
+		};
425
+/* End PBXSourcesBuildPhase section */
426
+
427
+/* Begin PBXTargetDependency section */
428
+		41CAEACD1C8D95B0003C2C7B /* PBXTargetDependency */ = {
429
+			isa = PBXTargetDependency;
430
+			target = 41F14FE51B68F098002189F1 /* mulle_concurrent */;
431
+			targetProxy = 41CAEACC1C8D95B0003C2C7B /* PBXContainerItemProxy */;
432
+		};
433
+		41CAEACF1C8D95B0003C2C7B /* PBXTargetDependency */ = {
434
+			isa = PBXTargetDependency;
435
+			target = 41CAEAC31C8D9599003C2C7B /* mulle_standalone_concurrent */;
436
+			targetProxy = 41CAEACE1C8D95B0003C2C7B /* PBXContainerItemProxy */;
437
+		};
438
+		41CAEAD11C8D95B5003C2C7B /* PBXTargetDependency */ = {
439
+			isa = PBXTargetDependency;
440
+			target = 41F14FE51B68F098002189F1 /* mulle_concurrent */;
441
+			targetProxy = 41CAEAD01C8D95B5003C2C7B /* PBXContainerItemProxy */;
442
+		};
443
+		41CAEAF11C8DA098003C2C7B /* PBXTargetDependency */ = {
444
+			isa = PBXTargetDependency;
445
+			target = 41CAEAC31C8D9599003C2C7B /* mulle_standalone_concurrent */;
446
+			targetProxy = 41CAEAF01C8DA098003C2C7B /* PBXContainerItemProxy */;
447
+		};
448
+		41CAEAFF1C8DA221003C2C7B /* PBXTargetDependency */ = {
449
+			isa = PBXTargetDependency;
450
+			target = 41CAEAC31C8D9599003C2C7B /* mulle_standalone_concurrent */;
451
+			targetProxy = 41CAEAFE1C8DA221003C2C7B /* PBXContainerItemProxy */;
452
+		};
453
+/* End PBXTargetDependency section */
454
+
455
+/* Begin XCBuildConfiguration section */
456
+		414785311ABAF290002DBAE4 /* Debug */ = {
457
+			isa = XCBuildConfiguration;
458
+			baseConfigurationReference = 417C02651BD8404E005A3751 /* Debug.xcconfig */;
459
+			buildSettings = {
460
+			};
461
+			name = Debug;
462
+		};
463
+		414785321ABAF290002DBAE4 /* Release */ = {
464
+			isa = XCBuildConfiguration;
465
+			baseConfigurationReference = 417C02681BD8404E005A3751 /* Release.xcconfig */;
466
+			buildSettings = {
467
+			};
468
+			name = Release;
469
+		};
470
+		41CAEAC61C8D9599003C2C7B /* Debug */ = {
471
+			isa = XCBuildConfiguration;
472
+			baseConfigurationReference = 41CAEADD1C8D982D003C2C7B /* DynamicLibraryOSX.xcconfig */;
473
+			buildSettings = {
474
+				LIBRARY_SEARCH_PATHS = (
475
+					"$(inherited)",
476
+					"$(PROJECT_DIR)/dependencies/lib/Debug",
477
+				);
478
+				OTHER_LDFLAGS = (
479
+					"-force_load",
480
+					"$(DEPENDENCIES_DIR)/lib/$(CONFIGURATION)/libmulle_test_allocator.a",
481
+					"-force_load",
482
+					"$(CONFIGURATION_BUILD_DIR)/libmulle_concurrent.a",
483
+				);
484
+			};
485
+			name = Debug;
486
+		};
487
+		41CAEAC71C8D9599003C2C7B /* Release */ = {
488
+			isa = XCBuildConfiguration;
489
+			baseConfigurationReference = 41CAEADD1C8D982D003C2C7B /* DynamicLibraryOSX.xcconfig */;
490
+			buildSettings = {
491
+				LIBRARY_SEARCH_PATHS = (
492
+					"$(inherited)",
493
+					"$(PROJECT_DIR)/dependencies/lib/Debug",
494
+				);
495
+				OTHER_LDFLAGS = (
496
+					"-force_load",
497
+					"$(DEPENDENCIES_DIR)/lib/$(CONFIGURATION)/libmulle_test_allocator.a",
498
+					"-force_load",
499
+					"$(CONFIGURATION_BUILD_DIR)/libmulle_concurrent.a",
500
+				);
501
+			};
502
+			name = Release;
503
+		};
504
+		41CAEACA1C8D95A6003C2C7B /* Debug */ = {
505
+			isa = XCBuildConfiguration;
506
+			buildSettings = {
507
+				PRODUCT_NAME = "$(TARGET_NAME)";
508
+			};
509
+			name = Debug;
510
+		};
511
+		41CAEACB1C8D95A6003C2C7B /* Release */ = {
512
+			isa = XCBuildConfiguration;
513
+			buildSettings = {
514
+				PRODUCT_NAME = "$(TARGET_NAME)";
515
+			};
516
+			name = Release;
517
+		};
518
+		41CAEAEC1C8D9FF4003C2C7B /* Debug */ = {
519
+			isa = XCBuildConfiguration;
520
+			baseConfigurationReference = 417C026C1BD8404E005A3751 /* ToolOSX.xcconfig */;
521
+			buildSettings = {
522
+				LIBRARY_SEARCH_PATHS = (
523
+					"$(inherited)",
524
+					"$(PROJECT_DIR)/dependencies/lib/Debug",
525
+				);
526
+			};
527
+			name = Debug;
528
+		};
529
+		41CAEAED1C8D9FF4003C2C7B /* Release */ = {
530
+			isa = XCBuildConfiguration;
531
+			baseConfigurationReference = 417C026C1BD8404E005A3751 /* ToolOSX.xcconfig */;
532
+			buildSettings = {
533
+				LIBRARY_SEARCH_PATHS = (
534
+					"$(inherited)",
535
+					"$(PROJECT_DIR)/dependencies/lib/Debug",
536
+				);
537
+			};
538
+			name = Release;
539
+		};
540
+		41CAEAFC1C8DA20F003C2C7B /* Debug */ = {
541
+			isa = XCBuildConfiguration;
542
+			baseConfigurationReference = 417C026C1BD8404E005A3751 /* ToolOSX.xcconfig */;
543
+			buildSettings = {
544
+				LIBRARY_SEARCH_PATHS = (
545
+					"$(inherited)",
546
+					"$(PROJECT_DIR)/dependencies/lib/Debug",
547
+				);
548
+			};
549
+			name = Debug;
550
+		};
551
+		41CAEAFD1C8DA20F003C2C7B /* Release */ = {
552
+			isa = XCBuildConfiguration;
553
+			baseConfigurationReference = 417C026C1BD8404E005A3751 /* ToolOSX.xcconfig */;
554
+			buildSettings = {
555
+				LIBRARY_SEARCH_PATHS = (
556
+					"$(inherited)",
557
+					"$(PROJECT_DIR)/dependencies/lib/Debug",
558
+				);
559
+			};
560
+			name = Release;
561
+		};
562
+		41F14FE81B68F098002189F1 /* Debug */ = {
563
+			isa = XCBuildConfiguration;
564
+			baseConfigurationReference = 417C026B1BD8404E005A3751 /* StaticLibraryOSX.xcconfig */;
565
+			buildSettings = {
566
+			};
567
+			name = Debug;
568
+		};
569
+		41F14FE91B68F098002189F1 /* Release */ = {
570
+			isa = XCBuildConfiguration;
571
+			baseConfigurationReference = 417C026B1BD8404E005A3751 /* StaticLibraryOSX.xcconfig */;
572
+			buildSettings = {
573
+			};
574
+			name = Release;
575
+		};
576
+/* End XCBuildConfiguration section */
577
+
578
+/* Begin XCConfigurationList section */
579
+		414785271ABAF290002DBAE4 /* Build configuration list for PBXProject "mulle-concurrent" */ = {
580
+			isa = XCConfigurationList;
581
+			buildConfigurations = (
582
+				414785311ABAF290002DBAE4 /* Debug */,
583
+				414785321ABAF290002DBAE4 /* Release */,
584
+			);
585
+			defaultConfigurationIsVisible = 0;
586
+			defaultConfigurationName = Release;
587
+		};
588
+		41CAEAC51C8D9599003C2C7B /* Build configuration list for PBXNativeTarget "mulle_standalone_concurrent" */ = {
589
+			isa = XCConfigurationList;
590
+			buildConfigurations = (
591
+				41CAEAC61C8D9599003C2C7B /* Debug */,
592
+				41CAEAC71C8D9599003C2C7B /* Release */,
593
+			);
594
+			defaultConfigurationIsVisible = 0;
595
+		};
596
+		41CAEAC91C8D95A6003C2C7B /* Build configuration list for PBXAggregateTarget "Libraries" */ = {
597
+			isa = XCConfigurationList;
598
+			buildConfigurations = (
599
+				41CAEACA1C8D95A6003C2C7B /* Debug */,
600
+				41CAEACB1C8D95A6003C2C7B /* Release */,
601
+			);
602
+			defaultConfigurationIsVisible = 0;
603
+		};
604
+		41CAEAEB1C8D9FF4003C2C7B /* Build configuration list for PBXNativeTarget "test-hashmap" */ = {
605
+			isa = XCConfigurationList;
606
+			buildConfigurations = (
607
+				41CAEAEC1C8D9FF4003C2C7B /* Debug */,
608
+				41CAEAED1C8D9FF4003C2C7B /* Release */,
609
+			);
610
+			defaultConfigurationIsVisible = 0;
611
+		};
612
+		41CAEAFB1C8DA20F003C2C7B /* Build configuration list for PBXNativeTarget "test-pointerarray" */ = {
613
+			isa = XCConfigurationList;
614
+			buildConfigurations = (
615
+				41CAEAFC1C8DA20F003C2C7B /* Debug */,
616
+				41CAEAFD1C8DA20F003C2C7B /* Release */,
617
+			);
618
+			defaultConfigurationIsVisible = 0;
619
+		};
620
+		41F14FE71B68F098002189F1 /* Build configuration list for PBXNativeTarget "mulle_concurrent" */ = {
621
+			isa = XCConfigurationList;
622
+			buildConfigurations = (
623
+				41F14FE81B68F098002189F1 /* Debug */,
624
+				41F14FE91B68F098002189F1 /* Release */,
625
+			);
626
+			defaultConfigurationIsVisible = 0;
627
+			defaultConfigurationName = Release;
628
+		};
629
+/* End XCConfigurationList section */
630
+	};
631
+	rootObject = 414785241ABAF290002DBAE4 /* Project object */;
632
+}
0 633
new file mode 100644
... ...
@@ -0,0 +1,621 @@
1
+//
2
+//  mulle_concurrent_hashmap.c
3
+//  mulle-concurrent
4
+//
5
+//  Created by Nat! on 04.03.16.
6
+//  Copyright © 2016 Mulle kybernetiK. All rights reserved.
7
+//
8
+//  Redistribution and use in source and binary forms, with or without
9
+//  modification, are permitted provided that the following conditions are met:
10
+//
11
+//  Redistributions of source code must retain the above copyright notice, this
12
+//  list of conditions and the following disclaimer.
13
+//
14
+//  Redistributions in binary form must reproduce the above copyright notice,
15
+//  this list of conditions and the following disclaimer in the documentation
16
+//  and/or other materials provided with the distribution.
17
+//
18
+//  Neither the name of Mulle kybernetiK nor the names of its contributors
19
+//  may be used to endorse or promote products derived from this software
20
+//  without specific prior written permission.
21
+//
22
+//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+//  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+//  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+//  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
26
+//  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+//  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+//  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+//  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+//  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+//  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+//  POSSIBILITY OF SUCH DAMAGE.
33
+//
34
+#include "mulle_concurrent_hashmap.h"
35
+
36
+#include "mulle_concurrent_types.h"
37
+#include <mulle_aba/mulle_aba.h>
38
+#include <assert.h>
39
+#include <errno.h>
40
+#include <stdint.h>
41
+
42
+
43
+struct _mulle_concurrent_hashvaluepair
44
+{
45
+   intptr_t                 hash;
46
+   mulle_atomic_pointer_t   value;
47
+};
48
+
49
+
50
+struct mulle_concurrent_hashmapstorage
51
+{
52
+   mulle_atomic_pointer_t   n_hashs;  // with possibly empty values
53
+   unsigned int             mask;
54
+   
55
+   struct _mulle_concurrent_hashvaluepair  entries[ 1];
56
+};
57
+
58
+
59
+#define REDIRECT_VALUE     MULLE_CONCURRENT_INVALID_POINTER
60
+
61
+#pragma mark -
62
+#pragma mark _mulle_concurrent_hashmapstorage
63
+
64
+
65
+// n must be a power of 2
66
+static struct mulle_concurrent_hashmapstorage *
67
+   _mulle_concurrent_alloc_hashmapstorage( unsigned int n,
68
+                                           struct mulle_allocator *allocator)
69
+{
70
+   struct mulle_concurrent_hashmapstorage  *p;
71
+   
72
+   if( n < 8)
73
+      n = 8;
74
+   
75
+   p = allocator->calloc( 1, sizeof( struct _mulle_concurrent_hashvaluepair) * (n - 1) +
76
+                             sizeof( struct mulle_concurrent_hashmapstorage));
77
+   if( ! p)
78
+      return( p);
79
+   
80
+   p->mask = n - 1;
81
+   
82
+   /*
83
+    * in theory, one should be able to use different values for NO_POINTER and
84
+    * INVALID_POINTER
85
+    */
86
+   if( MULLE_CONCURRENT_NO_HASH || MULLE_CONCURRENT_NO_POINTER)
87
+   {
88
+      struct _mulle_concurrent_hashvaluepair   *q;
89
+      struct _mulle_concurrent_hashvaluepair   *sentinel;
90
+      
91
+      q        = p->entries;
92
+      sentinel = &p->entries[ p->mask];
93
+      while( q <= sentinel)
94
+      {
95
+         q->hash  = MULLE_CONCURRENT_NO_HASH;
96
+         q->value = MULLE_CONCURRENT_NO_POINTER;
97
+         ++q;
98
+      }
99
+   }
100
+   
101
+   return( p);
102
+}
103
+
104
+
105
+static unsigned int
106
+   _mulle_concurrent_hashmapstorage_get_max_n_hashs( struct mulle_concurrent_hashmapstorage *p)
107
+{
108
+   unsigned int   size;
109
+   unsigned int   max;
110
+   
111
+   size = p->mask + 1;
112
+   max  = size - (size >> 1);
113
+   return( max);
114
+}
115
+
116
+
117
+static void   *_mulle_concurrent_hashmapstorage_lookup( struct mulle_concurrent_hashmapstorage *p,
118
+                                                        intptr_t hash)
119
+{
120
+   struct _mulle_concurrent_hashvaluepair   *entry;
121
+   unsigned int                             index;
122
+   unsigned int                             sentinel;
123
+   
124
+   index    = (unsigned int) hash;
125
+   sentinel = (unsigned int) (index + p->mask + 1);
126
+
127
+   for(;;)
128
+   {
129
+      entry = &p->entries[ index & p->mask];
130
+
131
+      if( entry->hash == MULLE_CONCURRENT_NO_HASH)
132
+         return( MULLE_CONCURRENT_NO_POINTER);
133
+      
134
+      if( entry->hash == hash)
135
+         return( _mulle_atomic_pointer_read( &entry->value));
136
+      
137
+      ++index;
138
+      assert( index != sentinel);  // can't happen we always leave space
139
+   }
140
+}
141
+
142
+
143
+static struct _mulle_concurrent_hashvaluepair  *
144
+    _mulle_concurrent_hashmapstorage_next_pair( struct mulle_concurrent_hashmapstorage *p,
145
+                                                unsigned int *index)
146
+{
147
+   struct _mulle_concurrent_hashvaluepair   *entry;
148
+   struct _mulle_concurrent_hashvaluepair   *sentinel;
149
+   
150
+   entry    = &p->entries[ *index];
151
+   sentinel = &p->entries[ p->mask + 1];
152
+
153
+   while( entry < sentinel)
154
+   {
155
+      if( entry->hash == MULLE_CONCURRENT_NO_HASH)
156
+      {
157
+         ++entry;
158
+         continue;
159
+      }
160
+      
161
+      *index = (unsigned int) (entry - p->entries) + 1;
162
+      return( entry);
163
+   }
164
+   return( NULL);
165
+}
166
+
167
+
168
+//
169
+// insert:
170
+//
171
+//  0      : did insert
172
+//  EEXIST : key already exists (can't replace currently)
173
+//  EBUSY  : this storage can't be written to
174
+//
175
+static int   _mulle_concurrent_hashmapstorage_insert( struct mulle_concurrent_hashmapstorage *p,
176
+                                                      intptr_t hash,
177
+                                                      void *value)
178
+{
179
+   struct _mulle_concurrent_hashvaluepair   *entry;
180
+   void                               *found;
181
+   unsigned int                       index;
182
+   unsigned int                       sentinel;
183
+   
184
+   assert( hash != MULLE_CONCURRENT_NO_HASH);
185
+   assert( value != MULLE_CONCURRENT_NO_POINTER && value != MULLE_CONCURRENT_INVALID_POINTER);
186
+
187
+   index    = (unsigned int) hash;
188
+   sentinel = (unsigned int) (index + p->mask + 1);
189
+   
190
+   for(;;)
191
+   {
192
+      entry = &p->entries[ index & p->mask];
193
+
194
+      if( entry->hash == MULLE_CONCURRENT_NO_HASH || entry->hash == hash)
195
+      {
196
+         found = __mulle_atomic_pointer_compare_and_swap( &entry->value, value, MULLE_CONCURRENT_NO_POINTER);
197
+         if( found != MULLE_CONCURRENT_NO_POINTER)
198
+         {
199
+            if( found == REDIRECT_VALUE)
200
+               return( EBUSY);
201
+            return( EEXIST);
202
+         }
203
+
204
+         if( ! entry->hash)
205
+         {
206
+            _mulle_atomic_pointer_increment( &p->n_hashs);
207
+            entry->hash = hash;
208
+         }
209
+         
210
+         return( 0);
211
+      }
212
+      
213
+      ++index;
214
+      assert( index != sentinel);  // can't happen we always leave space
215
+   }
216
+}
217
+
218
+
219
+static int   _mulle_concurrent_hashmapstorage_put( struct mulle_concurrent_hashmapstorage *p,
220
+                                                   intptr_t hash,
221
+                                                   void *value)
222
+{
223
+   struct _mulle_concurrent_hashvaluepair   *entry;
224
+   void                                     *found;
225
+   void                                     *expect;
226
+   unsigned int                             index;
227
+   unsigned int                             sentinel;
228
+   
229
+   assert( value);
230
+
231
+   index    = (unsigned int) hash;
232
+   sentinel = (unsigned int) (index + p->mask + 1);
233
+   
234
+   for(;;)
235
+   {
236
+      entry = &p->entries[ index & p->mask];
237
+
238
+      if( entry->hash == hash)
239
+      {
240
+         expect = MULLE_CONCURRENT_NO_POINTER;
241
+         for(;;)
242
+         {
243
+            found = __mulle_atomic_pointer_compare_and_swap( &entry->value, value, expect);
244
+            if( found == expect)
245
+               return( 0);
246
+            if( found == REDIRECT_VALUE)
247
+               return( EBUSY);
248
+            expect = found;
249
+         }
250
+      }
251
+      
252
+      if( entry->hash == MULLE_CONCURRENT_NO_HASH)
253
+      {
254
+         found = __mulle_atomic_pointer_compare_and_swap( &entry->value, value, MULLE_CONCURRENT_NO_POINTER);
255
+         if( found)
256
+         {
257
+            if( found == REDIRECT_VALUE)
258
+               return( EBUSY);
259
+            return( EEXIST);
260
+         }
261
+
262
+         _mulle_atomic_pointer_increment( &p->n_hashs);
263
+         entry->hash = hash;
264
+         
265
+         return( 0);
266
+      }
267
+   
268
+      ++index;
269
+      assert( index != sentinel);  // can't happen we always leave space
270
+   }
271
+}
272
+
273
+
274
+static int   _mulle_concurrent_hashmapstorage_remove( struct mulle_concurrent_hashmapstorage *p,
275
+                                                      intptr_t hash,
276
+                                                      void *value)
277
+{
278
+   struct _mulle_concurrent_hashvaluepair   *entry;
279
+   void                                     *found;
280
+   unsigned int                             index;
281
+   unsigned int                             sentinel;
282
+   
283
+   index    = (unsigned int) hash;
284
+   sentinel = (unsigned int) (hash + p->mask + 1);
285
+   for(;;)
286
+   {
287
+      entry  = &p->entries[ index & p->mask];
288
+
289
+      if( entry->hash == hash)
290
+      {
291
+         found = __mulle_atomic_pointer_compare_and_swap( &entry->value, MULLE_CONCURRENT_NO_POINTER, value);
292
+         if( found != MULLE_CONCURRENT_NO_POINTER)
293
+         {
294
+            if( found == REDIRECT_VALUE)
295
+               return( EBUSY);
296
+
297
+            // once a entry->hash it must not be erased (except
298
+            // during migration)
299
+         }
300
+         return( 0);
301
+      }
302
+      
303
+      if( entry->hash == MULLE_CONCURRENT_NO_HASH)
304
+         return( 0);
305
+      
306
+      ++index;
307
+      assert( index != sentinel);  // can't happen we always leave space
308
+   }
309
+}
310
+
311
+
312
+static void   _mulle_concurrent_hashmapstorage_copy( struct mulle_concurrent_hashmapstorage *dst,
313
+                                                     struct mulle_concurrent_hashmapstorage *src)
314
+{
315
+   struct _mulle_concurrent_hashvaluepair   *p;
316
+   struct _mulle_concurrent_hashvaluepair   *p_last;
317
+   void                                   *actual;
318
+   void                                   *value;
319
+   
320
+   p      = src->entries;
321
+   p_last = &src->entries[ src->mask];
322
+
323
+   for( ;p <= p_last; p++)
324
+   {
325
+      if( ! p->hash)
326
+         continue;
327
+
328
+      value = _mulle_atomic_pointer_read( &p->value);
329
+      for(;;)
330
+      {
331
+         if( value == MULLE_CONCURRENT_NO_POINTER)
332
+            break;
333
+         if( value == REDIRECT_VALUE)
334
+            break;
335
+         
336
+         // it's important that we copy over first so
337
+         // No One Gets Left Behind
338
+         _mulle_concurrent_hashmapstorage_put( dst, p->hash, value);
339
+         
340
+         actual = __mulle_atomic_pointer_compare_and_swap( &p->value, REDIRECT_VALUE, value);
341
+         if( actual == value)
342
+            break;
343
+         
344
+         value = actual;
345
+      }
346
+   }
347
+}
348
+
349
+
350
+#pragma mark -
351
+#pragma mark _mulle_concurrent_hashmap
352
+
353
+int  _mulle_concurrent_hashmap_init( struct mulle_concurrent_hashmap *map,
354
+                                     unsigned int size,
355
+                                     struct mulle_allocator *allocator,
356
+                                     struct mulle_aba *aba)
357
+{
358
+   if( ! allocator)
359
+      allocator = &mulle_default_allocator;
360
+   if( ! aba)
361
+      aba = mulle_aba_get_global();
362
+   
363
+   map->allocator    = allocator;
364
+   map->aba          = aba;
365
+   map->storage      = _mulle_concurrent_alloc_hashmapstorage( size, allocator);
366
+   map->next_storage = map->storage;
367
+   
368
+   if( ! map->storage)
369
+      return( -1);
370
+   return( 0);
371
+}
372
+
373
+
374
+//
375
+// this is called when you know, no other threads are accessing it anymore
376
+//
377
+void  _mulle_concurrent_hashmap_free( struct mulle_concurrent_hashmap *map)
378
+{
379
+   _mulle_aba_free( map->aba, map->allocator->free, map->storage);
380
+   if( map->storage != map->next_storage)
381
+      _mulle_aba_free( map->aba, map->allocator->free, map->next_storage);
382
+}
383
+
384
+
385
+static int  _mulle_concurrent_hashmap_migrate_storage( struct mulle_concurrent_hashmap *map,
386
+                                                       struct mulle_concurrent_hashmapstorage *p)
387
+{
388
+
389
+   struct mulle_concurrent_hashmapstorage   *q;
390
+   struct mulle_concurrent_hashmapstorage   *alloced;
391
+   struct mulle_concurrent_hashmapstorage   *previous;
392
+
393
+   assert( p);
394
+   
395
+   // acquire new storage
396
+   alloced = _mulle_concurrent_alloc_hashmapstorage( (p->mask + 1) * 2, map->allocator);
397
+   if( ! alloced)
398
+      return( -1);
399
+
400
+   // make this the next world, assume that's still set to 'p' (SIC)
401
+   q = __mulle_atomic_pointer_compare_and_swap( &map->next_storage, alloced, p);
402
+   if( q != p)
403
+   {
404
+      // someone else produced a next world, use that and get rid of 'alloced'
405
+      _mulle_aba_free( map->aba, map->allocator->free, alloced);
406
+      alloced = NULL;
407
+   }
408
+   else
409
+      q = alloced;
410
+   
411
+   // this thread can partake in copying
412
+   _mulle_concurrent_hashmapstorage_copy( q, p);
413
+   
414
+   // now update world, giving it the same value as 'next_world'
415
+   previous = __mulle_atomic_pointer_compare_and_swap( &map->storage, q, p);
416
+
417
+   // ok, if we succeed free old, if we fail alloced is
418
+   // already gone
419
+   if( previous == p)
420
+      _mulle_aba_free( map->aba, map->allocator->free, previous);
421
+   
422
+   return( 0);
423
+}
424
+
425
+
426
+void  *_mulle_concurrent_hashmap_lookup( struct mulle_concurrent_hashmap *map,
427
+                                         intptr_t hash)
428
+{
429
+   struct mulle_concurrent_hashmapstorage   *p;
430
+   void                                    *value;
431
+   
432
+retry:
433
+   p     = _mulle_atomic_pointer_read( &map->storage);
434
+   value = _mulle_concurrent_hashmapstorage_lookup( p, hash);
435
+   if( value == REDIRECT_VALUE)
436
+   {
437
+      if( _mulle_concurrent_hashmap_migrate_storage( map, p))
438
+         return( (void *) MULLE_CONCURRENT_NO_POINTER);
439
+      goto retry;
440
+   }
441
+   return( value);
442
+}
443
+
444
+
445
+static int   _mulle_concurrent_hashmap_search_next( struct mulle_concurrent_hashmap *map,
446
+                                                    unsigned int  *expect_mask,
447
+                                                    unsigned int  *index,
448
+                                                    intptr_t *p_hash,
449
+                                                    void **p_value)
450
+{
451
+   struct mulle_concurrent_hashmapstorage   *p;
452
+   struct _mulle_concurrent_hashvaluepair   *entry;
453
+   void                                     *value;
454
+   
455
+retry:
456
+   p = _mulle_atomic_pointer_read( &map->storage);
457
+   if( *expect_mask && p->mask != *expect_mask)
458
+   {
459
+      errno = ECANCELED;
460
+      return( -1);
461
+   }
462
+   
463
+   for(;;)
464
+   {
465
+      entry = _mulle_concurrent_hashmapstorage_next_pair( p, index);
466
+      if( ! entry)
467
+         return( 0);
468
+      
469
+      value = _mulle_atomic_pointer_read( &entry->value);
470
+      if( value != MULLE_CONCURRENT_NO_POINTER)
471
+         break;
472
+
473
+      if( value == REDIRECT_VALUE)
474
+      {
475
+         if( _mulle_concurrent_hashmap_migrate_storage( map, p))
476
+            return( -1);
477
+         goto retry;
478
+      }
479
+   }
480
+   
481
+   if( p_hash)
482
+      *p_hash = entry->hash;
483
+   if( p_value)
484
+      *p_value = value;
485
+   
486
+   if( ! *expect_mask)
487
+      *expect_mask = p->mask;
488
+   
489
+   return( 1);
490
+}
491
+
492
+
493
+int  _mulle_concurrent_hashmap_insert( struct mulle_concurrent_hashmap *map,
494
+                                       intptr_t hash,
495
+                                       void *value)
496
+{
497
+   struct mulle_concurrent_hashmapstorage   *p;
498
+   unsigned int                              n;
499
+   unsigned int                              max;
500
+
501
+   assert( hash != MULLE_CONCURRENT_NO_HASH);
502
+   assert( value);
503
+   assert( value != MULLE_CONCURRENT_NO_POINTER && value != MULLE_CONCURRENT_INVALID_POINTER);
504
+   
505
+retry:
506
+   p = _mulle_atomic_pointer_read( &map->storage);
507
+   assert( p);
508
+
509
+   max = _mulle_concurrent_hashmapstorage_get_max_n_hashs( p);
510
+   n   = (unsigned int) _mulle_atomic_pointer_read( &p->n_hashs);
511
+   
512
+   if( n >= max)
513
+   {
514
+      if( _mulle_concurrent_hashmap_migrate_storage( map, p))
515
+         return( -1);
516
+      goto retry;
517
+   }
518
+   
519
+   switch( _mulle_concurrent_hashmapstorage_insert( p, hash, value))
520
+   {
521
+   case EEXIST :
522
+      errno = EEXIST;
523
+      return( -1);
524
+
525
+   case EBUSY  :
526
+      if( _mulle_concurrent_hashmap_migrate_storage( map, p))
527
+         return( -1);
528
+      goto retry;
529
+   }
530
+
531
+   return( 0);
532
+}
533
+
534
+
535
+int  _mulle_concurrent_hashmap_remove( struct mulle_concurrent_hashmap *map,
536
+                                       intptr_t hash,
537
+                                       void *value)
538
+{
539
+   struct mulle_concurrent_hashmapstorage   *p;
540
+   
541
+retry:
542
+   p = _mulle_atomic_pointer_read( &map->storage);
543
+   switch( _mulle_concurrent_hashmapstorage_remove( p, hash, value))
544
+   {
545
+   case EBUSY  :
546
+      if( _mulle_concurrent_hashmap_migrate_storage( map, p))
547
+         return( -1);
548
+      goto retry;
549
+   }
550
+   return( 0);
551
+}
552
+
553
+
554
+unsigned int  _mulle_concurrent_hashmap_get_size( struct mulle_concurrent_hashmap *map)
555
+{
556
+   struct mulle_concurrent_hashmapstorage   *p;
557
+   
558
+   p = _mulle_atomic_pointer_read( &map->storage);
559
+   return( p->mask + 1);
560
+}
561
+
562
+
563
+//
564
+// obviously just a snapshot at some recent point in time
565
+//
566
+unsigned int  mulle_concurrent_hashmap_get_count( struct mulle_concurrent_hashmap *map)
567
+{
568
+   unsigned int                                count;
569
+   int                                         rval;
570
+   struct mulle_concurrent_hashmapenumerator   rover;
571
+