extlzham 0.0.1.PROTOTYPE3-x86-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +27 -0
  3. data/README.md +74 -0
  4. data/Rakefile +152 -0
  5. data/contrib/lzham/LICENSE +22 -0
  6. data/contrib/lzham/README.md +209 -0
  7. data/contrib/lzham/include/lzham.h +781 -0
  8. data/contrib/lzham/lzhamcomp/lzham_comp.h +38 -0
  9. data/contrib/lzham/lzhamcomp/lzham_lzbase.cpp +244 -0
  10. data/contrib/lzham/lzhamcomp/lzham_lzbase.h +45 -0
  11. data/contrib/lzham/lzhamcomp/lzham_lzcomp.cpp +608 -0
  12. data/contrib/lzham/lzhamcomp/lzham_lzcomp_internal.cpp +1966 -0
  13. data/contrib/lzham/lzhamcomp/lzham_lzcomp_internal.h +472 -0
  14. data/contrib/lzham/lzhamcomp/lzham_lzcomp_state.cpp +1413 -0
  15. data/contrib/lzham/lzhamcomp/lzham_match_accel.cpp +562 -0
  16. data/contrib/lzham/lzhamcomp/lzham_match_accel.h +146 -0
  17. data/contrib/lzham/lzhamcomp/lzham_null_threading.h +97 -0
  18. data/contrib/lzham/lzhamcomp/lzham_pthreads_threading.cpp +229 -0
  19. data/contrib/lzham/lzhamcomp/lzham_pthreads_threading.h +520 -0
  20. data/contrib/lzham/lzhamcomp/lzham_threading.h +12 -0
  21. data/contrib/lzham/lzhamcomp/lzham_win32_threading.cpp +220 -0
  22. data/contrib/lzham/lzhamcomp/lzham_win32_threading.h +368 -0
  23. data/contrib/lzham/lzhamdecomp/lzham_assert.cpp +66 -0
  24. data/contrib/lzham/lzhamdecomp/lzham_assert.h +40 -0
  25. data/contrib/lzham/lzhamdecomp/lzham_checksum.cpp +73 -0
  26. data/contrib/lzham/lzhamdecomp/lzham_checksum.h +13 -0
  27. data/contrib/lzham/lzhamdecomp/lzham_config.h +23 -0
  28. data/contrib/lzham/lzhamdecomp/lzham_core.h +264 -0
  29. data/contrib/lzham/lzhamdecomp/lzham_decomp.h +37 -0
  30. data/contrib/lzham/lzhamdecomp/lzham_helpers.h +54 -0
  31. data/contrib/lzham/lzhamdecomp/lzham_huffman_codes.cpp +262 -0
  32. data/contrib/lzham/lzhamdecomp/lzham_huffman_codes.h +14 -0
  33. data/contrib/lzham/lzhamdecomp/lzham_lzdecomp.cpp +1527 -0
  34. data/contrib/lzham/lzhamdecomp/lzham_lzdecompbase.cpp +131 -0
  35. data/contrib/lzham/lzhamdecomp/lzham_lzdecompbase.h +89 -0
  36. data/contrib/lzham/lzhamdecomp/lzham_math.h +142 -0
  37. data/contrib/lzham/lzhamdecomp/lzham_mem.cpp +284 -0
  38. data/contrib/lzham/lzhamdecomp/lzham_mem.h +112 -0
  39. data/contrib/lzham/lzhamdecomp/lzham_platform.cpp +157 -0
  40. data/contrib/lzham/lzhamdecomp/lzham_platform.h +284 -0
  41. data/contrib/lzham/lzhamdecomp/lzham_prefix_coding.cpp +351 -0
  42. data/contrib/lzham/lzhamdecomp/lzham_prefix_coding.h +146 -0
  43. data/contrib/lzham/lzhamdecomp/lzham_symbol_codec.cpp +1484 -0
  44. data/contrib/lzham/lzhamdecomp/lzham_symbol_codec.h +556 -0
  45. data/contrib/lzham/lzhamdecomp/lzham_timer.cpp +147 -0
  46. data/contrib/lzham/lzhamdecomp/lzham_timer.h +99 -0
  47. data/contrib/lzham/lzhamdecomp/lzham_traits.h +141 -0
  48. data/contrib/lzham/lzhamdecomp/lzham_types.h +97 -0
  49. data/contrib/lzham/lzhamdecomp/lzham_utils.h +58 -0
  50. data/contrib/lzham/lzhamdecomp/lzham_vector.cpp +75 -0
  51. data/contrib/lzham/lzhamdecomp/lzham_vector.h +588 -0
  52. data/contrib/lzham/lzhamlib/lzham_lib.cpp +179 -0
  53. data/examples/basic.rb +48 -0
  54. data/ext/constants.c +64 -0
  55. data/ext/decoder.c +313 -0
  56. data/ext/depend +5 -0
  57. data/ext/encoder.c +372 -0
  58. data/ext/error.c +80 -0
  59. data/ext/extconf.rb +29 -0
  60. data/ext/extlzham.c +34 -0
  61. data/ext/extlzham.h +62 -0
  62. data/gemstub.rb +22 -0
  63. data/lib/2.0/extlzham.so +0 -0
  64. data/lib/2.1/extlzham.so +0 -0
  65. data/lib/2.2/extlzham.so +0 -0
  66. data/lib/extlzham.rb +158 -0
  67. data/lib/extlzham/version.rb +5 -0
  68. data/test/test_extlzham.rb +35 -0
  69. metadata +156 -0
@@ -0,0 +1,12 @@
1
+ // File: lzham_threading.h
2
+ // See Copyright Notice and license at the end of include/lzham.h
3
+
4
+ #if LZHAM_USE_WIN32_API
5
+ #include "lzham_win32_threading.h"
6
+ #elif LZHAM_USE_PTHREADS_API
7
+ #include "lzham_pthreads_threading.h"
8
+ #else
9
+ #include "lzham_null_threading.h"
10
+ #endif
11
+
12
+
@@ -0,0 +1,220 @@
1
+ // File: lzham_task_pool_win32.cpp
2
+ // See Copyright Notice and license at the end of include/lzham.h
3
+ #include "lzham_core.h"
4
+ #include "lzham_win32_threading.h"
5
+ #include "lzham_timer.h"
6
+ #include <process.h>
7
+
8
+ #if LZHAM_USE_WIN32_API
9
+
10
+ namespace lzham
11
+ {
12
+ task_pool::task_pool() :
13
+ m_num_threads(0),
14
+ m_tasks_available(0, 32767),
15
+ m_num_outstanding_tasks(0),
16
+ m_exit_flag(false)
17
+ {
18
+ utils::zero_object(m_threads);
19
+ }
20
+
21
+ task_pool::task_pool(uint num_threads) :
22
+ m_num_threads(0),
23
+ m_tasks_available(0, 32767),
24
+ m_num_outstanding_tasks(0),
25
+ m_exit_flag(false)
26
+ {
27
+ utils::zero_object(m_threads);
28
+
29
+ bool status = init(num_threads);
30
+ LZHAM_VERIFY(status);
31
+ }
32
+
33
+ task_pool::~task_pool()
34
+ {
35
+ deinit();
36
+ }
37
+
38
+ bool task_pool::init(uint num_threads)
39
+ {
40
+ LZHAM_ASSERT(num_threads <= cMaxThreads);
41
+ num_threads = math::minimum<uint>(num_threads, cMaxThreads);
42
+
43
+ deinit();
44
+
45
+ bool succeeded = true;
46
+
47
+ m_num_threads = 0;
48
+ while (m_num_threads < num_threads)
49
+ {
50
+ m_threads[m_num_threads] = (HANDLE)_beginthreadex(NULL, 32768, thread_func, this, 0, NULL);
51
+ LZHAM_ASSERT(m_threads[m_num_threads] != 0);
52
+
53
+ if (!m_threads[m_num_threads])
54
+ {
55
+ succeeded = false;
56
+ break;
57
+ }
58
+
59
+ m_num_threads++;
60
+ }
61
+
62
+ if (!succeeded)
63
+ {
64
+ deinit();
65
+ return false;
66
+ }
67
+
68
+ return true;
69
+ }
70
+
71
+ void task_pool::deinit()
72
+ {
73
+ if (m_num_threads)
74
+ {
75
+ join();
76
+
77
+ atomic_exchange32(&m_exit_flag, true);
78
+
79
+ m_tasks_available.release(m_num_threads);
80
+
81
+ for (uint i = 0; i < m_num_threads; i++)
82
+ {
83
+ if (m_threads[i])
84
+ {
85
+ for ( ; ; )
86
+ {
87
+ DWORD result = WaitForSingleObject(m_threads[i], 30000);
88
+ if ((result == WAIT_OBJECT_0) || (result == WAIT_ABANDONED))
89
+ break;
90
+ }
91
+
92
+ CloseHandle(m_threads[i]);
93
+ m_threads[i] = NULL;
94
+ }
95
+ }
96
+
97
+ m_num_threads = 0;
98
+
99
+ atomic_exchange32(&m_exit_flag, false);
100
+ }
101
+
102
+ m_task_stack.clear();
103
+ m_num_outstanding_tasks = 0;
104
+ }
105
+
106
+ bool task_pool::queue_task(task_callback_func pFunc, uint64 data, void* pData_ptr)
107
+ {
108
+ LZHAM_ASSERT(m_num_threads);
109
+ LZHAM_ASSERT(pFunc);
110
+
111
+ task tsk;
112
+ tsk.m_callback = pFunc;
113
+ tsk.m_data = data;
114
+ tsk.m_pData_ptr = pData_ptr;
115
+ tsk.m_flags = 0;
116
+
117
+ if (!m_task_stack.try_push(tsk))
118
+ return false;
119
+
120
+ atomic_increment32(&m_num_outstanding_tasks);
121
+
122
+ m_tasks_available.release(1);
123
+
124
+ return true;
125
+ }
126
+
127
+ // It's the object's responsibility to delete pObj within the execute_task() method, if needed!
128
+ bool task_pool::queue_task(executable_task* pObj, uint64 data, void* pData_ptr)
129
+ {
130
+ LZHAM_ASSERT(m_num_threads);
131
+ LZHAM_ASSERT(pObj);
132
+
133
+ task tsk;
134
+ tsk.m_pObj = pObj;
135
+ tsk.m_data = data;
136
+ tsk.m_pData_ptr = pData_ptr;
137
+ tsk.m_flags = cTaskFlagObject;
138
+
139
+ if (!m_task_stack.try_push(tsk))
140
+ return false;
141
+
142
+ atomic_increment32(&m_num_outstanding_tasks);
143
+
144
+ m_tasks_available.release(1);
145
+
146
+ return true;
147
+ }
148
+
149
+ void task_pool::process_task(task& tsk)
150
+ {
151
+ if (tsk.m_flags & cTaskFlagObject)
152
+ tsk.m_pObj->execute_task(tsk.m_data, tsk.m_pData_ptr);
153
+ else
154
+ tsk.m_callback(tsk.m_data, tsk.m_pData_ptr);
155
+
156
+ atomic_decrement32(&m_num_outstanding_tasks);
157
+ }
158
+
159
+ void task_pool::join()
160
+ {
161
+ while (atomic_add32(&m_num_outstanding_tasks, 0) > 0)
162
+ {
163
+ task tsk;
164
+ if (m_task_stack.pop(tsk))
165
+ {
166
+ process_task(tsk);
167
+ }
168
+ else
169
+ {
170
+ lzham_sleep(1);
171
+ }
172
+ }
173
+ }
174
+
175
+ unsigned __stdcall task_pool::thread_func(void* pContext)
176
+ {
177
+ task_pool* pPool = static_cast<task_pool*>(pContext);
178
+
179
+ for ( ; ; )
180
+ {
181
+ if (!pPool->m_tasks_available.wait())
182
+ break;
183
+
184
+ if (pPool->m_exit_flag)
185
+ break;
186
+
187
+ task tsk;
188
+ if (pPool->m_task_stack.pop(tsk))
189
+ {
190
+ pPool->process_task(tsk);
191
+ }
192
+ }
193
+
194
+ _endthreadex(0);
195
+ return 0;
196
+ }
197
+
198
+ static uint g_num_processors;
199
+
200
+ uint lzham_get_max_helper_threads()
201
+ {
202
+ if (!g_num_processors)
203
+ {
204
+ SYSTEM_INFO system_info;
205
+ GetSystemInfo(&system_info);
206
+ g_num_processors = system_info.dwNumberOfProcessors;
207
+ }
208
+
209
+ if (g_num_processors > 1)
210
+ {
211
+ // use all CPU's
212
+ return LZHAM_MIN(task_pool::cMaxThreads, g_num_processors - 1);
213
+ }
214
+
215
+ return 0;
216
+ }
217
+
218
+ } // namespace lzham
219
+
220
+ #endif // LZHAM_USE_WIN32_API
@@ -0,0 +1,368 @@
1
+ // File: lzham_task_pool_win32.h
2
+ // See Copyright Notice and license at the end of include/lzham.h
3
+ #pragma once
4
+
5
+ #if LZHAM_USE_WIN32_API
6
+
7
+ #if LZHAM_NO_ATOMICS
8
+ #error No atomic operations defined in lzham_platform.h!
9
+ #endif
10
+
11
+ namespace lzham
12
+ {
13
+ class semaphore
14
+ {
15
+ LZHAM_NO_COPY_OR_ASSIGNMENT_OP(semaphore);
16
+
17
+ public:
18
+ semaphore(long initialCount = 0, long maximumCount = 1, const char* pName = NULL)
19
+ {
20
+ m_handle = CreateSemaphoreA(NULL, initialCount, maximumCount, pName);
21
+ if (NULL == m_handle)
22
+ {
23
+ LZHAM_FAIL("semaphore: CreateSemaphore() failed");
24
+ }
25
+ }
26
+
27
+ ~semaphore()
28
+ {
29
+ if (m_handle)
30
+ {
31
+ CloseHandle(m_handle);
32
+ m_handle = NULL;
33
+ }
34
+ }
35
+
36
+ inline HANDLE get_handle(void) const { return m_handle; }
37
+
38
+ void release(long releaseCount = 1)
39
+ {
40
+ if (0 == ReleaseSemaphore(m_handle, releaseCount, NULL))
41
+ {
42
+ LZHAM_FAIL("semaphore: ReleaseSemaphore() failed");
43
+ }
44
+ }
45
+
46
+ bool wait(uint32 milliseconds = UINT32_MAX)
47
+ {
48
+ LZHAM_ASSUME(INFINITE == UINT32_MAX);
49
+
50
+ DWORD result = WaitForSingleObject(m_handle, milliseconds);
51
+
52
+ if (WAIT_FAILED == result)
53
+ {
54
+ LZHAM_FAIL("semaphore: WaitForSingleObject() failed");
55
+ }
56
+
57
+ return WAIT_OBJECT_0 == result;
58
+ }
59
+
60
+ private:
61
+ HANDLE m_handle;
62
+ };
63
+
64
+ template<typename T>
65
+ class tsstack
66
+ {
67
+ public:
68
+ inline tsstack(bool use_freelist = true) :
69
+ m_use_freelist(use_freelist)
70
+ {
71
+ LZHAM_VERIFY(((ptr_bits_t)this & (LZHAM_GET_ALIGNMENT(tsstack) - 1)) == 0);
72
+ InitializeSListHead(&m_stack_head);
73
+ InitializeSListHead(&m_freelist_head);
74
+ }
75
+
76
+ inline ~tsstack()
77
+ {
78
+ clear();
79
+ }
80
+
81
+ inline void clear()
82
+ {
83
+ for ( ; ; )
84
+ {
85
+ node* pNode = (node*)InterlockedPopEntrySList(&m_stack_head);
86
+ if (!pNode)
87
+ break;
88
+
89
+ LZHAM_MEMORY_IMPORT_BARRIER
90
+
91
+ helpers::destruct(&pNode->m_obj);
92
+
93
+ lzham_free(pNode);
94
+ }
95
+
96
+ flush_freelist();
97
+ }
98
+
99
+ inline void flush_freelist()
100
+ {
101
+ if (!m_use_freelist)
102
+ return;
103
+
104
+ for ( ; ; )
105
+ {
106
+ node* pNode = (node*)InterlockedPopEntrySList(&m_freelist_head);
107
+ if (!pNode)
108
+ break;
109
+
110
+ LZHAM_MEMORY_IMPORT_BARRIER
111
+
112
+ lzham_free(pNode);
113
+ }
114
+ }
115
+
116
+ inline bool try_push(const T& obj)
117
+ {
118
+ node* pNode = alloc_node();
119
+ if (!pNode)
120
+ return false;
121
+
122
+ helpers::construct(&pNode->m_obj, obj);
123
+
124
+ LZHAM_MEMORY_EXPORT_BARRIER
125
+
126
+ InterlockedPushEntrySList(&m_stack_head, &pNode->m_slist_entry);
127
+
128
+ return true;
129
+ }
130
+
131
+ inline bool pop(T& obj)
132
+ {
133
+ node* pNode = (node*)InterlockedPopEntrySList(&m_stack_head);
134
+ if (!pNode)
135
+ return false;
136
+
137
+ LZHAM_MEMORY_IMPORT_BARRIER
138
+
139
+ obj = pNode->m_obj;
140
+
141
+ helpers::destruct(&pNode->m_obj);
142
+
143
+ free_node(pNode);
144
+
145
+ return true;
146
+ }
147
+
148
+ private:
149
+ SLIST_HEADER m_stack_head;
150
+ SLIST_HEADER m_freelist_head;
151
+
152
+ struct node
153
+ {
154
+ SLIST_ENTRY m_slist_entry;
155
+ T m_obj;
156
+ };
157
+
158
+ bool m_use_freelist;
159
+
160
+ inline node* alloc_node()
161
+ {
162
+ node* pNode = m_use_freelist ? (node*)InterlockedPopEntrySList(&m_freelist_head) : NULL;
163
+
164
+ if (!pNode)
165
+ pNode = (node*)lzham_malloc(sizeof(node));
166
+
167
+ return pNode;
168
+ }
169
+
170
+ inline void free_node(node* pNode)
171
+ {
172
+ if (m_use_freelist)
173
+ InterlockedPushEntrySList(&m_freelist_head, &pNode->m_slist_entry);
174
+ else
175
+ lzham_free(pNode);
176
+ }
177
+ };
178
+
179
+ class task_pool
180
+ {
181
+ public:
182
+ task_pool();
183
+ task_pool(uint num_threads);
184
+ ~task_pool();
185
+
186
+ enum { cMaxThreads = LZHAM_MAX_HELPER_THREADS };
187
+ bool init(uint num_threads);
188
+ void deinit();
189
+
190
+ inline uint get_num_threads() const { return m_num_threads; }
191
+ inline uint get_num_outstanding_tasks() const { return m_num_outstanding_tasks; }
192
+
193
+ // C-style task callback
194
+ typedef void (*task_callback_func)(uint64 data, void* pData_ptr);
195
+ bool queue_task(task_callback_func pFunc, uint64 data = 0, void* pData_ptr = NULL);
196
+
197
+ class executable_task
198
+ {
199
+ public:
200
+ virtual void execute_task(uint64 data, void* pData_ptr) = 0;
201
+ };
202
+
203
+ // It's the caller's responsibility to delete pObj within the execute_task() method, if needed!
204
+ bool queue_task(executable_task* pObj, uint64 data = 0, void* pData_ptr = NULL);
205
+
206
+ template<typename S, typename T>
207
+ inline bool queue_object_task(S* pObject, T pObject_method, uint64 data = 0, void* pData_ptr = NULL);
208
+
209
+ template<typename S, typename T>
210
+ inline bool queue_multiple_object_tasks(S* pObject, T pObject_method, uint64 first_data, uint num_tasks, void* pData_ptr = NULL);
211
+
212
+ void join();
213
+
214
+ private:
215
+ struct task
216
+ {
217
+ //inline task() : m_data(0), m_pData_ptr(NULL), m_pObj(NULL), m_flags(0) { }
218
+
219
+ uint64 m_data;
220
+ void* m_pData_ptr;
221
+
222
+ union
223
+ {
224
+ task_callback_func m_callback;
225
+ executable_task* m_pObj;
226
+ };
227
+
228
+ uint m_flags;
229
+ };
230
+
231
+ tsstack<task> m_task_stack;
232
+
233
+ uint m_num_threads;
234
+ HANDLE m_threads[cMaxThreads];
235
+
236
+ semaphore m_tasks_available;
237
+
238
+ enum task_flags
239
+ {
240
+ cTaskFlagObject = 1
241
+ };
242
+
243
+ volatile atomic32_t m_num_outstanding_tasks;
244
+ volatile atomic32_t m_exit_flag;
245
+
246
+ void process_task(task& tsk);
247
+
248
+ static unsigned __stdcall thread_func(void* pContext);
249
+ };
250
+
251
+ enum object_task_flags
252
+ {
253
+ cObjectTaskFlagDefault = 0,
254
+ cObjectTaskFlagDeleteAfterExecution = 1
255
+ };
256
+
257
+ template<typename T>
258
+ class object_task : public task_pool::executable_task
259
+ {
260
+ public:
261
+ object_task(uint flags = cObjectTaskFlagDefault) :
262
+ m_pObject(NULL),
263
+ m_pMethod(NULL),
264
+ m_flags(flags)
265
+ {
266
+ }
267
+
268
+ typedef void (T::*object_method_ptr)(uint64 data, void* pData_ptr);
269
+
270
+ object_task(T* pObject, object_method_ptr pMethod, uint flags = cObjectTaskFlagDefault) :
271
+ m_pObject(pObject),
272
+ m_pMethod(pMethod),
273
+ m_flags(flags)
274
+ {
275
+ LZHAM_ASSERT(pObject && pMethod);
276
+ }
277
+
278
+ void init(T* pObject, object_method_ptr pMethod, uint flags = cObjectTaskFlagDefault)
279
+ {
280
+ LZHAM_ASSERT(pObject && pMethod);
281
+
282
+ m_pObject = pObject;
283
+ m_pMethod = pMethod;
284
+ m_flags = flags;
285
+ }
286
+
287
+ T* get_object() const { return m_pObject; }
288
+ object_method_ptr get_method() const { return m_pMethod; }
289
+
290
+ virtual void execute_task(uint64 data, void* pData_ptr)
291
+ {
292
+ (m_pObject->*m_pMethod)(data, pData_ptr);
293
+
294
+ if (m_flags & cObjectTaskFlagDeleteAfterExecution)
295
+ lzham_delete(this);
296
+ }
297
+
298
+ protected:
299
+ T* m_pObject;
300
+
301
+ object_method_ptr m_pMethod;
302
+
303
+ uint m_flags;
304
+ };
305
+
306
+ template<typename S, typename T>
307
+ inline bool task_pool::queue_object_task(S* pObject, T pObject_method, uint64 data, void* pData_ptr)
308
+ {
309
+ object_task<S> *pTask = lzham_new< object_task<S> >(pObject, pObject_method, cObjectTaskFlagDeleteAfterExecution);
310
+ if (!pTask)
311
+ return false;
312
+ return queue_task(pTask, data, pData_ptr);
313
+ }
314
+
315
+ template<typename S, typename T>
316
+ inline bool task_pool::queue_multiple_object_tasks(S* pObject, T pObject_method, uint64 first_data, uint num_tasks, void* pData_ptr)
317
+ {
318
+ LZHAM_ASSERT(m_num_threads);
319
+ LZHAM_ASSERT(pObject);
320
+ LZHAM_ASSERT(num_tasks);
321
+ if (!num_tasks)
322
+ return true;
323
+
324
+ bool status = true;
325
+
326
+ uint i;
327
+ for (i = 0; i < num_tasks; i++)
328
+ {
329
+ task tsk;
330
+
331
+ tsk.m_pObj = lzham_new< object_task<S> >(pObject, pObject_method, cObjectTaskFlagDeleteAfterExecution);
332
+ if (!tsk.m_pObj)
333
+ {
334
+ status = false;
335
+ break;
336
+ }
337
+
338
+ tsk.m_data = first_data + i;
339
+ tsk.m_pData_ptr = pData_ptr;
340
+ tsk.m_flags = cTaskFlagObject;
341
+
342
+ if (!m_task_stack.try_push(tsk))
343
+ {
344
+ status = false;
345
+ break;
346
+ }
347
+ }
348
+
349
+ if (i)
350
+ {
351
+ atomic_add32(&m_num_outstanding_tasks, i);
352
+
353
+ m_tasks_available.release(i);
354
+ }
355
+
356
+ return status;
357
+ }
358
+
359
+ inline void lzham_sleep(unsigned int milliseconds)
360
+ {
361
+ Sleep(milliseconds);
362
+ }
363
+
364
+ uint lzham_get_max_helper_threads();
365
+
366
+ } // namespace lzham
367
+
368
+ #endif // LZHAM_USE_WIN32_API