~cosme/ubuntu/precise/freeimage/freeimage-3.15.1

« back to all changes in this revision

Viewing changes to Wrapper/FreeImage.NET/cs/Library/Classes/MemoryArray.cs

  • Committer: Bazaar Package Importer
  • Author(s): Cosme Domínguez Díaz
  • Date: 2010-07-20 13:42:15 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20100720134215-xt1454zaedv3b604
Tags: 3.13.1-0ubuntu1
* New upstream release. Closes: (LP: #607800)
 - Updated debian/freeimage-get-orig-source script.
 - Removing no longer necessary debian/patches/* and
   the patch system in debian/rules.
 - Updated debian/rules to work with the new Makefiles.
 - Drop from -O3 to -O2 and use lzma compression saves
   ~10 MB of free space. 
* lintian stuff
 - fixed debhelper-but-no-misc-depends
 - fixed ldconfig-symlink-missing-for-shlib

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
using System;
 
2
using System.Runtime.InteropServices;
 
3
using System.Collections;
 
4
using System.Collections.Generic;
 
5
using System.Diagnostics;
 
6
 
 
7
namespace FreeImageAPI
 
8
{
 
9
        /// <summary>
 
10
        /// Represents unmanaged memory, containing an array of a given structure.
 
11
        /// </summary>
 
12
        /// <typeparam name="T">Structuretype represented by the instance.</typeparam>
 
13
        /// <remarks>
 
14
        /// <see cref="System.Boolean"/> and <see cref="System.Char"/> can not be marshalled.
 
15
        /// <para/>
 
16
        /// Use <see cref="System.Int32"/> instead of <see cref="System.Boolean"/> and
 
17
        /// <see cref="System.Byte"/> instead of <see cref="System.Char"/>.
 
18
        /// </remarks>
 
19
        public unsafe class MemoryArray<T> : IDisposable, ICloneable, ICollection, IEnumerable<T>, IEquatable<MemoryArray<T>> where T : struct
 
20
        {
 
21
                /// <summary>
 
22
                /// Baseaddress of the wrapped memory.
 
23
                /// </summary>
 
24
                [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 
25
                protected byte* baseAddress;
 
26
 
 
27
                /// <summary>
 
28
                /// Number of elements being wrapped.
 
29
                /// </summary>
 
30
                [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 
31
                protected int length;
 
32
 
 
33
                /// <summary>
 
34
                /// Size, in bytes, of each element.
 
35
                /// </summary>
 
36
                [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 
37
                private static readonly int size;
 
38
 
 
39
                /// <summary>
 
40
                /// Array of <b>T</b> containing a single element.
 
41
                /// The array is used as a workaround, because there are no pointer for generic types.
 
42
                /// </summary>
 
43
                [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 
44
                protected T[] buffer;
 
45
 
 
46
                /// <summary>
 
47
                /// Pointer to the element of <b>buffer</b>.
 
48
                /// </summary>
 
49
                [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 
50
                protected byte* ptr;
 
51
 
 
52
                /// <summary>
 
53
                /// Handle for pinning <b>buffer</b>.
 
54
                /// </summary>
 
55
                [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 
56
                protected GCHandle handle;
 
57
 
 
58
                /// <summary>
 
59
                /// Indicates whether the wrapped memory is handled like a bitfield.
 
60
                /// </summary>
 
61
                [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 
62
                protected readonly bool isOneBit;
 
63
 
 
64
                /// <summary>
 
65
                /// Indicates whther the wrapped memory is handles like 4-bit blocks.
 
66
                /// </summary>
 
67
                [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 
68
                protected readonly bool isFourBit;
 
69
 
 
70
                /// <summary>
 
71
                /// An object that can be used to synchronize access to the <see cref="MemoryArray&lt;T&gt;"/>.
 
72
                /// </summary>
 
73
                [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 
74
                protected object syncRoot = null;
 
75
 
 
76
                static MemoryArray()
 
77
                {
 
78
                        T[] dummy = new T[2];
 
79
                        long marshalledSize = Marshal.SizeOf(typeof(T));
 
80
                        long structureSize =
 
81
                                Marshal.UnsafeAddrOfPinnedArrayElement(dummy, 1).ToInt64() -
 
82
                                Marshal.UnsafeAddrOfPinnedArrayElement(dummy, 0).ToInt64();
 
83
                        if (marshalledSize != structureSize)
 
84
                        {
 
85
                                throw new NotSupportedException(
 
86
                                        "The desired type can not be handled, " +
 
87
                                        "because its managed and unmanaged size in bytes are different.");
 
88
                        }
 
89
 
 
90
                        size = (int)marshalledSize;
 
91
                }
 
92
 
 
93
                /// <summary>
 
94
                /// Initializes a new instance.
 
95
                /// </summary>
 
96
                protected MemoryArray()
 
97
                {
 
98
                }
 
99
 
 
100
                /// <summary>
 
101
                /// Initializes a new instance of the <see cref="MemoryArray&lt;T&gt;"/> class. 
 
102
                /// </summary>
 
103
                /// <param name="baseAddress">Address of the memory block.</param>
 
104
                /// <param name="length">Length of the array.</param>
 
105
                /// <exception cref="ArgumentNullException">
 
106
                /// <paramref name="baseAddress"/> is null.</exception>
 
107
                /// <exception cref="ArgumentOutOfRangeException">
 
108
                /// <paramref name="length"/> is less or equal zero.</exception>
 
109
                /// <exception cref="NotSupportedException">
 
110
                /// The type is not supported.</exception>
 
111
                public MemoryArray(IntPtr baseAddress, int length)
 
112
                        : this(baseAddress.ToPointer(), length)
 
113
                {
 
114
                }
 
115
 
 
116
                /// <summary>
 
117
                /// Initializes a new instance of the <see cref="MemoryArray&lt;T&gt;"/> class. 
 
118
                /// </summary>
 
119
                /// <param name="baseAddress">Address of the memory block.</param>
 
120
                /// <param name="length">Length of the array.</param>
 
121
                /// <exception cref="ArgumentNullException">
 
122
                /// <paramref name="baseAddress"/> is null.</exception>
 
123
                /// <exception cref="ArgumentOutOfRangeException">
 
124
                /// <paramref name="length"/> is less or equal zero.</exception>
 
125
                /// <exception cref="NotSupportedException">
 
126
                /// The type is not supported.</exception>
 
127
                public MemoryArray(void* baseAddress, int length)
 
128
                {
 
129
                        if (typeof(T) == typeof(FI1BIT))
 
130
                        {
 
131
                                isOneBit = true;
 
132
                        }
 
133
                        else if (typeof(T) == typeof(FI4BIT))
 
134
                        {
 
135
                                isFourBit = true;
 
136
                        }
 
137
 
 
138
                        if (baseAddress == null)
 
139
                        {
 
140
                                throw new ArgumentNullException("baseAddress");
 
141
                        }
 
142
                        if (length < 1)
 
143
                        {
 
144
                                throw new ArgumentOutOfRangeException("length");
 
145
                        }
 
146
 
 
147
                        this.baseAddress = (byte*)baseAddress;
 
148
                        this.length = (int)length;
 
149
 
 
150
                        if (!isOneBit && !isFourBit)
 
151
                        {
 
152
                                // Create an array containing a single element.
 
153
                                // Due to the fact, that it's not possible to create pointers
 
154
                                // of generic types, an array is used to obtain the memory
 
155
                                // address of an element of T.
 
156
                                this.buffer = new T[1];
 
157
                                // The array is pinned immediately to prevent the GC from
 
158
                                // moving it to a different position in memory.
 
159
                                this.handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
 
160
                                // The array and its content have beed pinned, so that its address
 
161
                                // can be safely requested and stored for the whole lifetime
 
162
                                // of the instace.
 
163
                                this.ptr = (byte*)handle.AddrOfPinnedObject();
 
164
                        }
 
165
                }
 
166
 
 
167
                /// <summary>
 
168
                /// Frees the allocated <see cref="System.Runtime.InteropServices.GCHandle"/>.
 
169
                /// </summary>
 
170
                ~MemoryArray()
 
171
                {
 
172
                        Dispose(false);
 
173
                }
 
174
 
 
175
                /// <summary>
 
176
                /// Tests whether two specified <see cref="MemoryArray&lt;T&gt;"/> structures are equivalent.
 
177
                /// </summary>
 
178
                /// <param name="left">The <see cref="MemoryArray&lt;T&gt;"/> that is to the left of the equality operator.</param>
 
179
                /// <param name="right">The <see cref="MemoryArray&lt;T&gt;"/> that is to the right of the equality operator.</param>
 
180
                /// <returns>
 
181
                /// <b>true</b> if the two <see cref="MemoryArray&lt;T&gt;"/> structures are equal; otherwise, <b>false</b>.
 
182
                /// </returns>
 
183
                public static bool operator ==(MemoryArray<T> left, MemoryArray<T> right)
 
184
                {
 
185
                        if (object.ReferenceEquals(left, right))
 
186
                        {
 
187
                                return true;
 
188
                        }
 
189
                        if (object.ReferenceEquals(right, null) ||
 
190
                                object.ReferenceEquals(left, null) ||
 
191
                                (left.length != right.length))
 
192
                        {
 
193
                                return false;
 
194
                        }
 
195
                        if (left.baseAddress == right.baseAddress)
 
196
                        {
 
197
                                return true;
 
198
                        }
 
199
                        return FreeImage.CompareMemory(left.baseAddress, right.baseAddress, (uint)left.length);
 
200
                }
 
201
 
 
202
                /// <summary>
 
203
                /// Tests whether two specified <see cref="MemoryArray&lt;T&gt;"/> structures are different.
 
204
                /// </summary>
 
205
                /// <param name="left">The <see cref="MemoryArray&lt;T&gt;"/> that is to the left of the inequality operator.</param>
 
206
                /// <param name="right">The <see cref="MemoryArray&lt;T&gt;"/> that is to the right of the inequality operator.</param>
 
207
                /// <returns>
 
208
                /// <b>true</b> if the two <see cref="MemoryArray&lt;T&gt;"/> structures are different; otherwise, <b>false</b>.
 
209
                /// </returns>
 
210
                public static bool operator !=(MemoryArray<T> left, MemoryArray<T> right)
 
211
                {
 
212
                        return (!(left == right));
 
213
                }
 
214
 
 
215
                /// <summary>
 
216
                /// Gets the value at the specified position.
 
217
                /// </summary>
 
218
                /// <param name="index">A 32-bit integer that represents the position
 
219
                /// of the array element to get.</param>
 
220
                /// <returns>The value at the specified position.</returns>
 
221
                /// <exception cref="ArgumentOutOfRangeException">
 
222
                /// <paramref name="index"/> is outside the range of valid indexes
 
223
                /// for the unmanaged array.</exception>
 
224
                public T GetValue(int index)
 
225
                {
 
226
                        if ((index >= this.length) || (index < 0))
 
227
                        {
 
228
                                throw new ArgumentOutOfRangeException("index");
 
229
                        }
 
230
 
 
231
                        return GetValueInternal(index);
 
232
                }
 
233
 
 
234
                private T GetValueInternal(int index)
 
235
                {
 
236
                        EnsureNotDisposed();
 
237
                        if (isOneBit)
 
238
                        {
 
239
                                return (T)(object)(FI1BIT)(((baseAddress[index / 8] & ((1 << (7 - (index % 8))))) == 0) ? 0 : 1);
 
240
                        }
 
241
                        else if (isFourBit)
 
242
                        {
 
243
                                return (T)(object)(FI4BIT)(((index % 2) == 0) ? (baseAddress[index / 2] >> 4) : (baseAddress[index / 2] & 0x0F));
 
244
                        }
 
245
                        else
 
246
                        {
 
247
                                CopyMemory(ptr, baseAddress + (index * size), size);
 
248
                                return buffer[0];
 
249
                        }
 
250
                }
 
251
 
 
252
                /// <summary>
 
253
                /// Sets a value to the element at the specified position.
 
254
                /// </summary>
 
255
                /// <param name="value">The new value for the specified element.</param>
 
256
                /// <param name="index">A 32-bit integer that represents the
 
257
                /// position of the array element to set.</param>
 
258
                /// <exception cref="ArgumentOutOfRangeException">
 
259
                /// <paramref name="index"/> is outside the range of valid indexes
 
260
                /// for the unmanaged array.</exception>
 
261
                public void SetValue(T value, int index)
 
262
                {
 
263
                        if ((index >= this.length) || (index < 0))
 
264
                        {
 
265
                                throw new ArgumentOutOfRangeException("index");
 
266
                        }
 
267
                        SetValueInternal(value, index);
 
268
                }
 
269
 
 
270
                private void SetValueInternal(T value, int index)
 
271
                {
 
272
                        EnsureNotDisposed();
 
273
                        if (isOneBit)
 
274
                        {
 
275
                                if ((FI1BIT)(object)value != 0)
 
276
                                {
 
277
                                        baseAddress[index / 8] |= (byte)(1 << (7 - (index % 8)));
 
278
                                }
 
279
                                else
 
280
                                {
 
281
                                        baseAddress[index / 8] &= (byte)(~(1 << (7 - (index % 8))));
 
282
                                }
 
283
                        }
 
284
                        else if (isFourBit)
 
285
                        {
 
286
                                if ((index % 2) == 0)
 
287
                                {
 
288
                                        baseAddress[index / 2] = (byte)((baseAddress[index / 2] & 0x0F) | ((FI4BIT)(object)value << 4));
 
289
                                }
 
290
                                else
 
291
                                {
 
292
                                        baseAddress[index / 2] = (byte)((baseAddress[index / 2] & 0xF0) | ((FI4BIT)(object)value & 0x0F));
 
293
                                }
 
294
                        }
 
295
                        else
 
296
                        {
 
297
                                buffer[0] = value;
 
298
                                CopyMemory(baseAddress + (index * size), ptr, size);
 
299
                        }
 
300
                }
 
301
 
 
302
                /// <summary>
 
303
                /// Gets the values at the specified position and length.
 
304
                /// </summary>
 
305
                /// <param name="index">A 32-bit integer that represents the position
 
306
                /// of the array elements to get.</param>
 
307
                /// <param name="length"> A 32-bit integer that represents the length
 
308
                /// of the array elements to get.</param>
 
309
                /// <returns>The values at the specified position and length.</returns>
 
310
                /// <exception cref="ArgumentOutOfRangeException">
 
311
                /// <paramref name="index"/> is outside the range of valid indexes
 
312
                /// for the unmanaged array or <paramref name="length"/> is greater than the number of elements
 
313
                /// from <paramref name="index"/> to the end of the unmanaged array.</exception>
 
314
                public T[] GetValues(int index, int length)
 
315
                {
 
316
                        EnsureNotDisposed();
 
317
                        if ((index >= this.length) || (index < 0))
 
318
                        {
 
319
                                throw new ArgumentOutOfRangeException("index");
 
320
                        }
 
321
                        if (((index + length) > this.length) || (length < 1))
 
322
                        {
 
323
                                throw new ArgumentOutOfRangeException("length");
 
324
                        }
 
325
 
 
326
                        T[] data = new T[length];
 
327
                        if (isOneBit || isFourBit)
 
328
                        {
 
329
                                for (int i = 0; i < length; i++)
 
330
                                {
 
331
                                        data[i] = GetValueInternal(i);
 
332
                                }
 
333
                        }
 
334
                        else
 
335
                        {
 
336
                                GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
 
337
                                byte* dst = (byte*)Marshal.UnsafeAddrOfPinnedArrayElement(data, 0);
 
338
                                CopyMemory(dst, baseAddress + (size * index), size * length);
 
339
                                handle.Free();
 
340
                        }
 
341
                        return data;
 
342
                }
 
343
 
 
344
                /// <summary>
 
345
                /// Sets the values at the specified position.
 
346
                /// </summary>
 
347
                /// <param name="values">An array containing the new values for the specified elements.</param>
 
348
                /// <param name="index">A 32-bit integer that represents the position
 
349
                /// of the array elements to set.</param>
 
350
                /// <exception cref="ArgumentNullException">
 
351
                /// <paramref name="values"/> is a null reference (Nothing in Visual Basic).</exception>
 
352
                /// <exception cref="ArgumentOutOfRangeException">
 
353
                /// <paramref name="index"/> is outside the range of valid indexes
 
354
                /// for the unmanaged array or <paramref name="values.Length"/> is greater than the number of elements
 
355
                /// from <paramref name="index"/> to the end of the array.</exception>
 
356
                public void SetValues(T[] values, int index)
 
357
                {
 
358
                        EnsureNotDisposed();
 
359
                        if (values == null)
 
360
                        {
 
361
                                throw new ArgumentNullException("values");
 
362
                        }
 
363
                        if ((index >= this.length) || (index < 0))
 
364
                        {
 
365
                                throw new ArgumentOutOfRangeException("index");
 
366
                        }
 
367
                        if ((index + values.Length) > this.length)
 
368
                        {
 
369
                                throw new ArgumentOutOfRangeException("values.Length");
 
370
                        }
 
371
 
 
372
                        if (isOneBit || isFourBit)
 
373
                        {
 
374
                                for (int i = 0; i != values.Length; )
 
375
                                {
 
376
                                        SetValueInternal(values[i++], index++);
 
377
                                }
 
378
                        }
 
379
                        else
 
380
                        {
 
381
                                GCHandle handle = GCHandle.Alloc(values, GCHandleType.Pinned);
 
382
                                byte* src = (byte*)Marshal.UnsafeAddrOfPinnedArrayElement(values, 0);
 
383
                                CopyMemory(baseAddress + (index * size), src, size * length);
 
384
                                handle.Free();
 
385
                        }
 
386
                }
 
387
 
 
388
                /// <summary>
 
389
                /// Copies the entire array to a compatible one-dimensional <see cref="System.Array"/>,
 
390
                /// starting at the specified index of the target array.
 
391
                /// </summary>
 
392
                /// <param name="array">The one-dimensional <see cref="System.Array"/> that is the destination
 
393
                /// of the elements copied from <see cref="MemoryArray&lt;T&gt;"/>.
 
394
                /// The <see cref="System.Array"/> must have zero-based indexing.</param>
 
395
                /// <param name="index">The zero-based index in <paramref name="array"/>
 
396
                /// at which copying begins.</param>
 
397
                public void CopyTo(Array array, int index)
 
398
                {
 
399
                        EnsureNotDisposed();
 
400
                        if (!(array is T[]))
 
401
                        {
 
402
                                throw new InvalidCastException("array");
 
403
                        }
 
404
                        try
 
405
                        {
 
406
                                CopyTo((T[])array, 0, index, length);
 
407
                        }
 
408
                        catch (ArgumentOutOfRangeException ex)
 
409
                        {
 
410
                                throw new ArgumentException(ex.Message, ex);
 
411
                        }
 
412
                }
 
413
 
 
414
                /// <summary>
 
415
                /// Copies a range of elements from the unmanaged array starting at the specified
 
416
                /// <typeparamref name="sourceIndex"/> and pastes them to <paramref name="array"/>
 
417
                /// starting at the specified <paramref name="destinationIndex"/>.
 
418
                /// The length and the indexes are specified as 32-bit integers.
 
419
                /// </summary>
 
420
                /// <param name="array">The array that receives the data.</param>
 
421
                /// <param name="sourceIndex">A 32-bit integer that represents the index
 
422
                /// in the unmanaged array at which copying begins.</param>
 
423
                /// <param name="destinationIndex">A 32-bit integer that represents the index in
 
424
                /// the destination array at which storing begins.</param>
 
425
                /// <param name="length">A 32-bit integer that represents the number of elements to copy.</param>
 
426
                /// <exception cref="ArgumentNullException">
 
427
                /// <paramref name="array"/> is a null reference (Nothing in Visual Basic).</exception>
 
428
                /// <exception cref="ArgumentOutOfRangeException">
 
429
                /// <paramref name="sourceIndex"/> is outside the range of valid indexes
 
430
                /// for the unmanaged array or <paramref name="length"/> is greater than the number of elements
 
431
                /// from <paramref name="index"/> to the end of the unmanaged array
 
432
                /// <para>-or-</para>
 
433
                /// <paramref name="destinationIndex"/> is outside the range of valid indexes
 
434
                /// for the array or <paramref name="length"/> is greater than the number of elements
 
435
                /// from <paramref name="index"/> to the end of the array.
 
436
                /// </exception>
 
437
                public void CopyTo(T[] array, int sourceIndex, int destinationIndex, int length)
 
438
                {
 
439
                        EnsureNotDisposed();
 
440
                        if (array == null)
 
441
                        {
 
442
                                throw new ArgumentNullException("array");
 
443
                        }
 
444
                        if ((sourceIndex >= this.length) || (sourceIndex < 0))
 
445
                        {
 
446
                                throw new ArgumentOutOfRangeException("sourceIndex");
 
447
                        }
 
448
                        if ((destinationIndex >= array.Length) || (destinationIndex < 0))
 
449
                        {
 
450
                                throw new ArgumentOutOfRangeException("destinationIndex");
 
451
                        }
 
452
                        if ((sourceIndex + length > this.length) ||
 
453
                                (destinationIndex + length > array.Length) ||
 
454
                                (length < 1))
 
455
                        {
 
456
                                throw new ArgumentOutOfRangeException("length");
 
457
                        }
 
458
 
 
459
                        if (isOneBit || isFourBit)
 
460
                        {
 
461
                                for (int i = 0; i != length; i++)
 
462
                                {
 
463
                                        array[destinationIndex++] = GetValueInternal(sourceIndex++);
 
464
                                }
 
465
                        }
 
466
                        else
 
467
                        {
 
468
                                GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
 
469
                                byte* dst = (byte*)Marshal.UnsafeAddrOfPinnedArrayElement(array, destinationIndex);
 
470
                                CopyMemory(dst, baseAddress + (size * sourceIndex), size * length);
 
471
                                handle.Free();
 
472
                        }
 
473
                }
 
474
 
 
475
                /// <summary>
 
476
                /// Copies a range of elements from the array starting at the specified
 
477
                /// <typeparamref name="sourceIndex"/> and pastes them to the unmanaged array
 
478
                /// starting at the specified <paramref name="destinationIndex"/>.
 
479
                /// The length and the indexes are specified as 32-bit integers.
 
480
                /// </summary>
 
481
                /// <param name="array">The array that holds the data.</param>
 
482
                /// <param name="sourceIndex">A 32-bit integer that represents the index
 
483
                /// in the array at which copying begins.</param>
 
484
                /// <param name="destinationIndex">A 32-bit integer that represents the index in
 
485
                /// the unmanaged array at which storing begins.</param>
 
486
                /// <param name="length">A 32-bit integer that represents the number of elements to copy.</param>
 
487
                /// <exception cref="ArgumentNullException">
 
488
                /// <paramref name="array"/> is a null reference (Nothing in Visual Basic).</exception>
 
489
                /// <exception cref="ArgumentOutOfRangeException">
 
490
                /// <paramref name="sourceIndex"/> is outside the range of valid indexes
 
491
                /// for the array or <paramref name="length"/> is greater than the number of elements
 
492
                /// from <paramref name="index"/> to the end of the array
 
493
                /// <para>-or-</para>
 
494
                /// <paramref name="destinationIndex"/> is outside the range of valid indexes
 
495
                /// for the unmanaged array or <paramref name="length"/> is greater than the number of elements
 
496
                /// from <paramref name="index"/> to the end of the unmanaged array.
 
497
                /// </exception>
 
498
                public void CopyFrom(T[] array, int sourceIndex, int destinationIndex, int length)
 
499
                {
 
500
                        EnsureNotDisposed();
 
501
                        if (array == null)
 
502
                        {
 
503
                                throw new ArgumentNullException("array");
 
504
                        }
 
505
                        if ((destinationIndex >= this.length) || (destinationIndex < 0))
 
506
                        {
 
507
                                throw new ArgumentOutOfRangeException("destinationIndex");
 
508
                        }
 
509
                        if ((sourceIndex >= array.Length) || (sourceIndex < 0))
 
510
                        {
 
511
                                throw new ArgumentOutOfRangeException("sourceIndex");
 
512
                        }
 
513
                        if ((destinationIndex + length > this.length) ||
 
514
                                (sourceIndex + length > array.Length) ||
 
515
                                (length < 1))
 
516
                        {
 
517
                                throw new ArgumentOutOfRangeException("length");
 
518
                        }
 
519
 
 
520
                        if (isOneBit || isFourBit)
 
521
                        {
 
522
                                for (int i = 0; i != length; i++)
 
523
                                {
 
524
                                        SetValueInternal(array[sourceIndex++], destinationIndex++);
 
525
                                }
 
526
                        }
 
527
                        else
 
528
                        {
 
529
                                GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
 
530
                                byte* src = (byte*)Marshal.UnsafeAddrOfPinnedArrayElement(array, sourceIndex);
 
531
                                CopyMemory(baseAddress + (size * destinationIndex), src, size * length);
 
532
                                handle.Free();
 
533
                        }
 
534
                }
 
535
 
 
536
                /// <summary>
 
537
                /// Returns the represented block of memory as an array of <see cref="Byte"/>.
 
538
                /// </summary>
 
539
                /// <returns>The represented block of memory.</returns>
 
540
                public byte[] ToByteArray()
 
541
                {
 
542
                        EnsureNotDisposed();
 
543
                        byte[] result;
 
544
                        if (isOneBit)
 
545
                        {
 
546
                                result = new byte[(length + 7) / 8];
 
547
                        }
 
548
                        else if (isFourBit)
 
549
                        {
 
550
                                result = new byte[(length + 3) / 4];
 
551
                        }
 
552
                        else
 
553
                        {
 
554
                                result = new byte[size * length];
 
555
                        }
 
556
                        fixed (byte* dst = result)
 
557
                        {
 
558
                                CopyMemory(dst, baseAddress, result.Length);
 
559
                        }
 
560
                        return result;
 
561
                }
 
562
 
 
563
                /// <summary>
 
564
                /// Gets or sets the value at the specified position in the array.
 
565
                /// </summary>
 
566
                /// <param name="index">A 32-bit integer that represents the position
 
567
                /// of the array element to get.</param>
 
568
                /// <returns>The value at the specified position in the array.</returns>
 
569
                /// <exception cref="ArgumentOutOfRangeException">
 
570
                /// <paramref name="index"/> is outside the range of valid indexes
 
571
                /// for the unmanaged array.</exception>
 
572
                public T this[int index]
 
573
                {
 
574
                        get
 
575
                        {
 
576
                                return GetValue(index);
 
577
                        }
 
578
                        set
 
579
                        {
 
580
                                SetValue(value, index);
 
581
                        }
 
582
                }
 
583
 
 
584
                /// <summary>
 
585
                /// Gets or sets the values of the unmanaged array.
 
586
                /// </summary>
 
587
                public T[] Data
 
588
                {
 
589
                        get
 
590
                        {
 
591
                                return GetValues(0, length);
 
592
                        }
 
593
                        set
 
594
                        {
 
595
                                if (value == null)
 
596
                                {
 
597
                                        throw new ArgumentNullException("value");
 
598
                                }
 
599
                                if (value.Length != length)
 
600
                                {
 
601
                                        throw new ArgumentOutOfRangeException("value.Lengt");
 
602
                                }
 
603
                                SetValues(value, 0);
 
604
                        }
 
605
                }
 
606
 
 
607
                /// <summary>
 
608
                /// Gets the length of the unmanaged array.
 
609
                /// </summary>
 
610
                public int Length
 
611
                {
 
612
                        get
 
613
                        {
 
614
                                EnsureNotDisposed();
 
615
                                return length;
 
616
                        }
 
617
                }
 
618
 
 
619
                /// <summary>
 
620
                /// Gets the base address of the represented memory block.
 
621
                /// </summary>
 
622
                public IntPtr BaseAddress
 
623
                {
 
624
                        get
 
625
                        {
 
626
                                EnsureNotDisposed();
 
627
                                return new IntPtr(baseAddress);
 
628
                        }
 
629
                }
 
630
 
 
631
                /// <summary>
 
632
                /// Creates a shallow copy of the <see cref="MemoryArray&lt;T&gt;"/>.
 
633
                /// </summary>
 
634
                /// <returns>A shallow copy of the <see cref="MemoryArray&lt;T&gt;"/>.</returns>
 
635
                public object Clone()
 
636
                {
 
637
                        EnsureNotDisposed();
 
638
                        return new MemoryArray<T>(baseAddress, length);
 
639
                }
 
640
 
 
641
                /// <summary>
 
642
                /// Gets a 32-bit integer that represents the total number of elements
 
643
                /// in the <see cref="MemoryArray&lt;T&gt;"/>.
 
644
                /// </summary>
 
645
                public int Count
 
646
                {
 
647
                        get { EnsureNotDisposed(); return length; }
 
648
                }
 
649
 
 
650
                /// <summary>
 
651
                /// Gets a value indicating whether access to the <see cref="MemoryArray&lt;T&gt;"/>
 
652
                /// is synchronized (thread safe).
 
653
                /// </summary>
 
654
                public bool IsSynchronized
 
655
                {
 
656
                        get { EnsureNotDisposed(); return false; }
 
657
                }
 
658
 
 
659
                /// <summary>
 
660
                /// Gets an object that can be used to synchronize access to the <see cref="MemoryArray&lt;T&gt;"/>.
 
661
                /// </summary>
 
662
                public object SyncRoot
 
663
                {
 
664
                        get
 
665
                        {
 
666
                                EnsureNotDisposed();
 
667
                                if (syncRoot == null)
 
668
                                {
 
669
                                        System.Threading.Interlocked.CompareExchange(ref syncRoot, new object(), null);
 
670
                                }
 
671
                                return syncRoot;
 
672
                        }
 
673
                }
 
674
 
 
675
                /// <summary>
 
676
                /// Retrieves an object that can iterate through the individual
 
677
                /// elements in this <see cref="MemoryArray&lt;T&gt;"/>.
 
678
                /// </summary>
 
679
                /// <returns>An <see cref="IEnumerator"/> for the <see cref="MemoryArray&lt;T&gt;"/>.</returns>
 
680
                public IEnumerator GetEnumerator()
 
681
                {
 
682
                        EnsureNotDisposed();
 
683
                        T[] values = GetValues(0, length);
 
684
                        for (int i = 0; i != values.Length; i++)
 
685
                        {
 
686
                                yield return values[i];
 
687
                        }
 
688
                }
 
689
 
 
690
                /// <summary>
 
691
                /// Retrieves an object that can iterate through the individual
 
692
                /// elements in this <see cref="MemoryArray&lt;T&gt;"/>.
 
693
                /// </summary>
 
694
                /// <returns>An <see cref="IEnumerator&lt;T&gt;"/> for the <see cref="MemoryArray&lt;T&gt;"/>.</returns>
 
695
                IEnumerator<T> IEnumerable<T>.GetEnumerator()
 
696
                {
 
697
                        EnsureNotDisposed();
 
698
                        T[] values = GetValues(0, length);
 
699
                        for (int i = 0; i != values.Length; i++)
 
700
                        {
 
701
                                yield return values[i];
 
702
                        }
 
703
                }
 
704
 
 
705
                /// <summary>
 
706
                /// Releases all ressources.
 
707
                /// </summary>
 
708
                public void Dispose()
 
709
                {
 
710
                        Dispose(true);
 
711
                        GC.SuppressFinalize(this);
 
712
                }
 
713
 
 
714
                /// <summary>
 
715
                /// Releases allocated handles associated with this instance.
 
716
                /// </summary>
 
717
                /// <param name="disposing"><b>true</b> to release managed resources.</param>
 
718
                protected virtual void Dispose(bool disposing)
 
719
                {
 
720
                        if (baseAddress != null)
 
721
                        {
 
722
                                if (handle.IsAllocated)
 
723
                                        handle.Free();
 
724
                                baseAddress = null;
 
725
                                buffer = null;
 
726
                                length = 0;
 
727
                                syncRoot = null;
 
728
                        }
 
729
                }
 
730
 
 
731
                /// <summary>
 
732
                /// Throws an <see cref="ObjectDisposedException"/> if
 
733
                /// this instance is disposed.
 
734
                /// </summary>
 
735
                protected virtual void EnsureNotDisposed()
 
736
                {
 
737
                        if (baseAddress == null)
 
738
                                throw new ObjectDisposedException("This instance is disposed.");
 
739
                }
 
740
 
 
741
                /// <summary>
 
742
                /// Tests whether the specified <see cref="MemoryArray&lt;T&gt;"/> structure is equivalent to this
 
743
                /// <see cref="MemoryArray&lt;T&gt;"/> structure.
 
744
                /// </summary>
 
745
                /// <param name="obj">The structure to test.</param>
 
746
                /// <returns><b>true</b> if <paramref name="obj"/> is a <see cref="MemoryArray&lt;T&gt;"/>
 
747
                /// instance equivalent to this <see cref="MemoryArray&lt;T&gt;"/> structure; otherwise,
 
748
                /// <b>false</b>.</returns>
 
749
                public override bool Equals(object obj)
 
750
                {
 
751
                        EnsureNotDisposed();
 
752
                        return ((obj is MemoryArray<T>) && Equals((MemoryArray<T>)obj));
 
753
                }
 
754
 
 
755
                /// <summary>
 
756
                /// Tests whether the specified <see cref="MemoryArray&lt;T&gt;"/> structure is equivalent to this
 
757
                /// <see cref="MemoryArray&lt;T&gt;"/> structure.
 
758
                /// </summary>
 
759
                /// <param name="other">The structure to test.</param>
 
760
                /// <returns><b>true</b> if <paramref name="other"/> is equivalent to this
 
761
                /// <see cref="MemoryArray&lt;T&gt;"/> structure; otherwise,
 
762
                /// <b>false</b>.</returns>
 
763
                public bool Equals(MemoryArray<T> other)
 
764
                {
 
765
                        EnsureNotDisposed();
 
766
                        return ((this.baseAddress == other.baseAddress) && (this.length == other.length));
 
767
                }
 
768
 
 
769
                /// <summary>
 
770
                /// Serves as a hash function for a particular type.
 
771
                /// </summary>
 
772
                /// <returns>A hash code for the current <see cref="MemoryArray&lt;T&gt;"/>.</returns>
 
773
                public override int GetHashCode()
 
774
                {
 
775
                        EnsureNotDisposed();
 
776
                        return (int)baseAddress ^ length;
 
777
                }
 
778
 
 
779
                /// <summary>
 
780
                /// Copies a block of memory from one location to another.
 
781
                /// </summary>
 
782
                /// <param name="dest">Pointer to the starting address of the copy destination.</param>
 
783
                /// <param name="src">Pointer to the starting address of the block of memory to be copied.</param>
 
784
                /// <param name="len">Size of the block of memory to copy, in bytes.</param>
 
785
                protected static unsafe void CopyMemory(byte* dest, byte* src, int len)
 
786
                {
 
787
                        if (len >= 0x10)
 
788
                        {
 
789
                                do
 
790
                                {
 
791
                                        *((int*)dest) = *((int*)src);
 
792
                                        *((int*)(dest + 4)) = *((int*)(src + 4));
 
793
                                        *((int*)(dest + 8)) = *((int*)(src + 8));
 
794
                                        *((int*)(dest + 12)) = *((int*)(src + 12));
 
795
                                        dest += 0x10;
 
796
                                        src += 0x10;
 
797
                                }
 
798
                                while ((len -= 0x10) >= 0x10);
 
799
                        }
 
800
                        if (len > 0)
 
801
                        {
 
802
                                if ((len & 8) != 0)
 
803
                                {
 
804
                                        *((int*)dest) = *((int*)src);
 
805
                                        *((int*)(dest + 4)) = *((int*)(src + 4));
 
806
                                        dest += 8;
 
807
                                        src += 8;
 
808
                                }
 
809
                                if ((len & 4) != 0)
 
810
                                {
 
811
                                        *((int*)dest) = *((int*)src);
 
812
                                        dest += 4;
 
813
                                        src += 4;
 
814
                                }
 
815
                                if ((len & 2) != 0)
 
816
                                {
 
817
                                        *((short*)dest) = *((short*)src);
 
818
                                        dest += 2;
 
819
                                        src += 2;
 
820
                                }
 
821
                                if ((len & 1) != 0)
 
822
                                {
 
823
                                        *dest = *src;
 
824
                                }
 
825
                        }
 
826
                }
 
827
        }
 
828
}
 
 
b'\\ No newline at end of file'