root/trunk/AprSharp/dev/src/AprArray.cs

Revision 72, 20.5 kB (checked in by DenisG, 3 years ago)

[AprSharp] AprArray?: Fix an issue of MS.NET that consider IntPtr? as a primitive type.

  • Property svn:eol-style set to native
Line 
1 //  AprSharp, a wrapper library around the Apache Portable Runtime Library
2 #region Copyright (C) 2004 SOFTEC sa.
3 //
4 //  This library is free software; you can redistribute it and/or
5 //  modify it under the terms of the GNU Lesser General Public
6 //  License as published by the Free Software Foundation; either
7 //  version 2.1 of the License, or (at your option) any later version.
8 //
9 //  This library is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 //  Lesser General Public License for more details.
13 //
14 //  You should have received a copy of the GNU Lesser General Public
15 //  License along with this library; if not, write to the Free Software
16 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 //
18 //  Sources, support options and lastest version of the complete library
19 //  is available from:
20 //              http://www.softec.st/AprSharp
21 //             
22 //
23 //  Initial authors :
24 //              Denis Gervalle
25 //              Olivier Desaive
26 #endregion
27 //
28 using System;
29 using System.Diagnostics;
30 using System.Reflection;
31 using System.Runtime.InteropServices;
32 using System.Collections;
33
34 namespace Softec.AprSharp
35 {
36     public unsafe struct AprArray : IEnumerable, ICollection, IAprUnmanaged
37     {
38         private apr_array_header_t *mArray;
39         private Type mEltsType;
40
41         [StructLayout( LayoutKind.Sequential, Pack=4 )]
42         private struct apr_array_header_t
43         {
44                 public IntPtr pool;
45                         public int elt_size;
46                         public int nelts;
47                         public int nalloc;
48                         public IntPtr elts;
49         }
50
51         #region Generic embedding functions of an IntPtr
52         private AprArray(apr_array_header_t *ptr)
53         {
54             mArray = ptr;
55             mEltsType = null;
56         }
57
58         public AprArray(IntPtr ptr)
59         {
60             mArray = (apr_array_header_t *)ptr.ToPointer();
61             mEltsType = null;
62         }
63
64         public AprArray(IntPtr ptr, Type eltsType)
65         {
66             mArray = (apr_array_header_t *)ptr.ToPointer();
67             mEltsType = null;
68             if( eltsType != null )
69                 ElementType = eltsType;
70         }
71        
72         public bool IsNull
73         {
74                 get
75                 {
76                 return( mArray == null );
77             }
78         }
79
80         private void CheckPtr()
81         {
82             if( mArray == null )
83                 throw new AprNullReferenceException();
84         }
85
86         private void CheckPtr(Type type)
87         {
88             if( mArray == null )
89                 throw new AprNullReferenceException();
90             if( mEltsType != null && mEltsType != type )
91                 throw new AprInvalidOperationException(String.Format("Types mismatch between array ({0}) and value {1}.",mEltsType.Name,type.Name));
92         }
93        
94         public void ClearPtr()
95         {
96             mArray = null;
97             mEltsType = null;
98         }
99
100         public IntPtr ToIntPtr()
101         {
102             return new IntPtr(mArray);
103         }
104
105                 public bool ReferenceEquals(IAprUnmanaged obj)
106                 {
107                         return(obj.ToIntPtr() == ToIntPtr());
108                 }
109                
110         public static implicit operator IntPtr(AprArray array)
111         {
112             return new IntPtr(array.mArray);
113         }
114        
115         public static implicit operator AprArray(IntPtr ptr)
116         {
117             return new AprArray(ptr);
118         }
119        
120         public override string ToString()
121         {
122             return("[apr_array_header_t:"+(new IntPtr(mArray)).ToInt32().ToString("X")+"]");
123         }
124        
125         public Type ElementType
126         {
127                 get
128                 {
129                         return(mEltsType);
130                 }
131                 set
132                 {
133                                 if( (value.IsPrimitive && Marshal.SizeOf(value) != mArray->elt_size)
134                                   ||(!value.IsPrimitive && Marshal.SizeOf(typeof(IntPtr)) != mArray->elt_size) )
135                                 throw new AprArgumentException("Type does not match element size.");
136                                
137                     if( value.IsPrimitive )
138                         mEltsType = value;
139                     else {
140                         if( value != typeof(IntPtr) && value.GetConstructor(new Type[] {typeof(IntPtr)}) == null )
141                                 throw new AprInvalidOperationException("Type is not primitive and cannot be constructed from an IntPtr.");
142                         mEltsType = value;
143                     }
144                 }
145         }
146         #endregion
147        
148         #region Methods wrappers
149         public static AprArray Make(AprPool pool, int nElts, Type eltsType )
150         {
151                 if(eltsType.IsPrimitive)
152                         return(new AprArray(Make(pool, nElts, Marshal.SizeOf(eltsType)),eltsType));
153                 else
154                         return(new AprArray(Make(pool, nElts, Marshal.SizeOf(typeof(IntPtr))),eltsType));
155         }
156
157         public static AprArray Make(AprPool pool, int nElts, int eltSize )
158         {
159             IntPtr ptr;
160            
161             Debug.Write(String.Format("apr_array_make({0},{1},{2})...",pool,nElts,eltSize));
162             ptr = Apr.apr_array_make(pool,nElts,eltSize);
163             if(ptr == IntPtr.Zero )
164                 throw new AprException("apr_array_make: Can't create an apr_array_header_t");
165             Debug.WriteLine(String.Format("Done({0:X})",((Int32)ptr)));
166
167             return(ptr);
168         }
169
170         public static AprArray Make(AprPool pool, ICollection list )
171         {
172                 if(list is AprArray)
173                         return(((AprArray)list).Copy(pool));
174                 else
175                 {
176                     IEnumerator it = list.GetEnumerator();
177                     it.MoveNext();
178                    
179                     AprArray a = Make(pool, list.Count, it.Current.GetType());
180                     it.Reset();
181                    
182                     while(it.MoveNext()) {
183                         a.Push(it.Current);
184                     }
185                     return(a);
186                         }
187                 }
188
189         public static AprArray Make(AprPool pool, ICollection list, Type type )
190         {
191                 if(list is AprArray
192                    && ((AprArray)list).ElementType == type )
193                         return(((AprArray)list).Copy(pool));
194                 else
195                 {
196                     AprArray a = Make(pool, list.Count, type);
197                    
198                     IEnumerator it = list.GetEnumerator();
199                     while(it.MoveNext()) {
200                         a.Push(it.Current);
201                     }
202                     return(a);
203                         }
204                 }
205
206         public static AprArray LazyMake(AprPool pool, ICollection list )
207         {
208                 if(list is AprArray)
209                 {
210                         if( ((AprArray)list).Pool.ReferenceEquals(pool) )
211                                         return ((AprArray)list);       
212                 }
213                 return( Make(pool, list) );
214                 }
215
216         public static AprArray LazyMake(AprPool pool, ICollection list, Type type)
217         {
218                 if(list is AprArray)
219                 {
220                         if( ((AprArray)list).Pool.ReferenceEquals(pool)
221                                 && ((AprArray)list).ElementType == type )
222                                         return ((AprArray)list);       
223                 }
224                 return( Make(pool, list, type) );
225                 }
226                                                
227         public AprArray Copy(AprPool pool)
228         {
229             IntPtr ptr;
230            
231             CheckPtr();
232             Debug.Write(String.Format("apr_array_copy({0},{1})...",pool,this));
233             ptr = Apr.apr_array_copy(pool,(IntPtr)mArray);
234             if(ptr == IntPtr.Zero )
235                 throw new AprException("apr_array_copy: Can't copy an apr_array_header_t");
236             Debug.WriteLine(String.Format("Done({0:X})",((Int32)ptr)));
237
238             return(new AprArray(ptr,mEltsType));
239         }
240
241         public AprArray CopyHdr(AprPool pool)
242         {
243             IntPtr ptr;
244            
245             CheckPtr();
246             Debug.Write(String.Format("apr_array_copy_hdr({0},{1})...",pool,this));
247             ptr = Apr.apr_array_copy_hdr(pool,new IntPtr(mArray));
248             if(ptr == IntPtr.Zero )
249                 throw new AprException("apr_array_copy_hdr: Can't copy an apr_array_header_t");
250             Debug.WriteLine(String.Format("Done({0:X})",((Int32)ptr)));
251
252             return(new AprArray(ptr,mEltsType));
253         }
254
255         public AprArray Append(AprPool pool, AprArray array)
256         {
257             IntPtr ptr;
258             Type arrType;
259            
260             CheckPtr();
261             if (mEltsType != null && array.mEltsType != null && mEltsType != array.mEltsType)
262                 throw new AprInvalidOperationException("Array type mismatch.");
263            
264             if(mEltsType == null && array.mEltsType != null)
265                 arrType = array.mEltsType;
266                 arrType = mEltsType;
267                
268             Debug.Write(String.Format("apr_array_append({0},{1},{2})...",pool,array,this));
269             ptr = Apr.apr_array_append(pool,(IntPtr)mArray,array);
270             if(ptr == IntPtr.Zero )
271                 throw new AprException("apr_array_append: Can't append an apr_array_header_t");
272             Debug.WriteLine(String.Format("Done({0:X})",((Int32)ptr)));
273
274             return(new AprArray(ptr,arrType));
275         }
276
277         public void Cat(AprArray array)
278         {
279             CheckPtr();
280             if (mEltsType != null && array.mEltsType != null && mEltsType != array.mEltsType)
281                 throw new AprInvalidOperationException("Array types mismatch.");
282            
283             if(mEltsType == null && array.mEltsType != null)
284                 mEltsType = array.mEltsType;
285                
286             Debug.WriteLine(String.Format("apr_array_cat({0},{1})",this,array));
287             Apr.apr_array_cat((IntPtr)mArray,array);
288         }       
289
290         public string StrCat(AprPool pool, char sep)
291         {
292                 return(pStrCat(pool,sep).ToString());
293         }
294
295         public AprString pStrCat(AprPool pool, char sep)
296         {
297             IntPtr ptr;
298            
299             CheckPtr();
300             if(mEltsType != null && mEltsType != typeof(AprString))
301                 throw new AprInvalidOperationException("Not an AprString array.");
302                
303             Debug.Write(String.Format("apr_array_pstrcat({0},{1},{2})...",pool,this,sep));
304             ptr = Apr.apr_array_pstrcat(pool,new IntPtr(mArray),sep);
305             if(ptr == IntPtr.Zero )
306                 throw new AprException("apr_array_pstrcat: Can't convert an apr_array_header_t to AprString");
307             Debug.WriteLine(String.Format("Done({0:X})",((Int32)ptr)));
308
309             return(ptr);
310         }       
311
312         public void Push(bool o)
313         {
314             CheckPtr(typeof(bool));
315                 Marshal.WriteByte(Push(),(byte)((o) ? 1 : 0));
316         }
317
318         public void Push(byte o)
319         {
320             CheckPtr(typeof(byte));
321                 Marshal.WriteByte(Push(),o);
322         }
323
324                 [CLSCompliant(false)]
325         public void Push(sbyte o)
326         {
327             CheckPtr(typeof(sbyte));
328                 Marshal.WriteByte(Push(),unchecked((byte)o));
329         }
330        
331         public void Push(short o)
332         {
333             CheckPtr(typeof(short));
334                 Marshal.WriteInt16(Push(),o);
335         }
336
337                 [CLSCompliant(false)]
338         public void Push(ushort o)
339         {
340             CheckPtr(typeof(ushort));
341                 Marshal.WriteInt16(Push(),unchecked((short)o));
342             }
343            
344         public void Push(int o)
345         {
346             CheckPtr(typeof(int));
347                 Marshal.WriteInt32(Push(),o);
348             }
349
350                 [CLSCompliant(false)]
351         public void Push(uint o)
352         {
353             CheckPtr(typeof(uint));
354                 Marshal.WriteInt32(Push(),unchecked((int)o));
355             }
356
357         public void Push(long o)
358         {
359             CheckPtr(typeof(long));
360                 Marshal.WriteInt64(Push(),o);
361                 }
362                
363                 [CLSCompliant(false)]
364         public void Push(ulong o)
365         {
366             CheckPtr(typeof(ulong));
367                 Marshal.WriteInt64(Push(),unchecked((long)o));
368                 }
369                
370                 public void Push(IntPtr ptr)
371                 {
372             CheckPtr();
373                     Marshal.WriteIntPtr(Push(),ptr);
374         }
375        
376         public void Push(object o)
377         {
378                         if(mEltsType == typeof(IntPtr))
379                                 Push((IntPtr)o);
380                         else
381             {
382                                 if(mEltsType.IsPrimitive)
383                         {
384                                 if(mEltsType == typeof(bool))
385                                         Push((bool)o);
386                                 else if(mEltsType == typeof(byte))
387                                         Push((byte)o);
388                                 else if(mEltsType == typeof(sbyte))
389                                         Push((sbyte)o);
390                                 else if(mEltsType == typeof(short))
391                                         Push((short)o);
392                                 else if(mEltsType == typeof(ushort))
393                                         Push((ushort)o);
394                                 else if(mEltsType == typeof(int))
395                                         Push((int)o);
396                                 else if(mEltsType == typeof(uint))
397                                         Push((uint)o);
398                                 else if(mEltsType == typeof(long))
399                                         Push((long)o);
400                                 else if(mEltsType == typeof(ulong))
401                                         Push((ulong)o);
402                                 else
403                                 throw new AprInvalidOperationException("Array type not supported.");
404                         }
405                         else
406                         {
407                                 object co;
408                                
409                                 if(mEltsType != o.GetType())
410                                 {
411                                         ConstructorInfo ctor = mEltsType.GetConstructor(new Type[] {o.GetType(),
412                                                                                                                                                                 typeof(AprPool)});
413                                         if( ctor == null )
414                                         throw new AprInvalidOperationException("Type is not primitive and cannot be constructed from pushed object.");
415                                    
416                                                 co = ctor.Invoke(new Object[] { o, Pool });
417                                 }
418                                 else
419                                         co = o;
420                                        
421                                 IAprUnmanaged obj = co as IAprUnmanaged;
422                                 if( o == null )
423                                 throw new AprInvalidOperationException("Array type should implement IAprUnmanaged.");
424                         Push(obj.ToIntPtr());
425                     }
426                 }
427         }
428        
429         public IntPtr Push()
430         {
431             IntPtr ptr;
432            
433             CheckPtr();
434             Debug.Write(String.Format("apr_array_push({0})...",this));
435             ptr = Apr.apr_array_push(new IntPtr(mArray));
436             if(ptr == IntPtr.Zero )
437                 throw new AprException("apr_array_push: Can't push an element");
438             Debug.WriteLine(String.Format("Done({0:X})",((Int32)ptr)));
439
440             return(ptr);
441         }
442        
443         public object PopObject()
444                 {
445                         if(mEltsType == null)       
446                 throw new AprInvalidOperationException("Array not typed.");
447                
448                         if(mEltsType == typeof(IntPtr))
449                         {
450                                 return(Marshal.ReadIntPtr(Pop()));
451                         }
452                         if(mEltsType.IsPrimitive)
453                         {
454                                 object val;
455                         switch(ElementSize)
456                         {
457                                 case 1:
458                                         val = Marshal.ReadByte(Pop());
459                                         break;
460                                 case 2:
461                                         val = Marshal.ReadInt16(Pop());
462                                         break;
463                                 case 4:
464                                         val = Marshal.ReadInt32(Pop());
465                                         break;
466                                 case 8:
467                                         val = Marshal.ReadInt64(Pop());
468                                         break;
469                                 default:
470                                 throw new AprInvalidOperationException("Invalid element size.");
471                         }
472                         if(mEltsType == val.GetType())
473                                 return(val);
474                         else if (mEltsType == typeof(bool))
475                                 return(Convert.ChangeType(val,typeof(bool)));
476                         else if (mEltsType == typeof(sbyte))
477                                 return(unchecked((sbyte)((byte)val)));
478                         else if (mEltsType == typeof(ushort))
479                                 return(unchecked((ushort)((short)val)));
480                         else if (mEltsType == typeof(uint))
481                                 return(unchecked((uint)((int)val)));
482                         else if (mEltsType == typeof(ulong))
483                                 return(unchecked((ulong)((long)val)));
484                         return(val);
485                         }
486                        
487                 ConstructorInfo ctor = mEltsType.GetConstructor(new Type[] {typeof(IntPtr)});
488                 if( ctor == null )
489                 throw new AprInvalidOperationException("Type is not primitive and cannot be constructed from an IntPtr.");
490            
491             IntPtr ptr = Marshal.ReadIntPtr(Pop());
492                         return(ctor.Invoke(new Object[] { ptr }));
493                 }       
494        
495         public IntPtr Pop()
496         {
497             IntPtr ptr;
498            
499             CheckPtr();
500             Debug.Write(String.Format("apr_array_pop({0})...",this));
501             ptr = Apr.apr_array_pop(new IntPtr(mArray));
502             Debug.WriteLine(String.Format("Done({0:X})",((Int32)ptr)));
503
504             return(ptr);
505         }       
506        
507         public bool IsEmpty()
508         {
509                 bool isEmpty;
510             CheckPtr();
511             Debug.Write(String.Format("apr_is_empty_array({0})...",this));
512             isEmpty = Apr.apr_is_empty_array(new IntPtr(mArray));
513             Debug.WriteLine(String.Format("Done({0:X})",isEmpty));
514             return(isEmpty);
515         }
516         #endregion
517
518         #region Wrapper Properties
519         public AprPool Pool
520         {
521             get {
522                 return(mArray->pool);
523             }
524         }       
525
526         public int AllocatedCount
527         {
528             get {
529                 return(mArray->nalloc);
530             }
531         }
532        
533         public int ElementSize
534         {
535             get {
536                 return(mArray->elt_size);
537             }
538         }
539        
540         public IntPtr Data
541         {
542             get {
543                 return(mArray->elts);
544             }
545         }
546         #endregion
547        
548         #region ICollection
549         public void CopyTo(Array array, int arrayIndex)
550         {
551             if(null == array)
552                 throw new AprArgumentNullException("array");
553             if(arrayIndex < 0 || arrayIndex > array.Length)
554                 throw new AprArgumentOutOfRangeException("arrayIndex");
555             if(array.Rank > 1)
556                 throw new AprArgumentException("array is multidimensional");
557             if((array.Length - arrayIndex) < Count)
558                 throw new AprArgumentException("Not enough room from arrayIndex to end of array for this AprArray");
559            
560             int i = arrayIndex;
561             IEnumerator it = GetEnumerator();
562             while(it.MoveNext()) {
563                 array.SetValue(it.Current, i++);
564             }
565         }
566        
567         public bool IsSynchronized
568         {
569             get
570             {
571                 return false;
572             }
573         }
574
575         public object SyncRoot
576         {
577             get
578             {
579                 return this;
580             }
581         }
582
583         public int Count
584         {
585             get {
586                 return(mArray->nelts);
587             }
588         }
589         #endregion       
590        
591         #region IEnumerable
592             public IEnumerator GetEnumerator()
593         {
594             return (IEnumerator) new AprArrayEnumerator(this);
595         }
596         #endregion
597
598         }
599        
600         public class AprArrayEnumerator : IEnumerator
601     {
602         AprArray mArray;
603         int mIndex;
604    
605         public AprArrayEnumerator(AprArray array)
606         {
607             mArray = array;
608             mIndex = -1;
609         }
610        
611                 #region IEnumerator
612                 public bool MoveNext()
613                 {
614                         if (++mIndex >= mArray.Count) {
615                                 mIndex = mArray.Count;
616                                 return(false);
617                         }
618                         return(true);
619                 }
620                
621                 public void Reset()
622                 {
623                     mIndex = -1;
624                 }
625                                
626                 public object Current
627             {
628             get
629             {
630                 if (mIndex < 0 || mIndex >= mArray.Count)
631                         throw new AprInvalidOperationException("No current item.");
632                
633                                 if(mArray.ElementType == null)
634                         throw new AprInvalidOperationException("Array not typed.");
635                                    
636                                 if(mArray.ElementType == typeof(IntPtr))
637                                 {
638                                         return(Marshal.ReadIntPtr(mArray.Data,mIndex*mArray.ElementSize));
639                                 }
640                                 if(mArray.ElementType.IsPrimitive)
641                                 {
642                                         object val;
643                                 switch(mArray.ElementSize)
644                                 {
645                                         case 1:
646                                                 val = Marshal.ReadByte(mArray.Data,mIndex);
647                                                 break;
648                                         case 2:
649                                                 val = Marshal.ReadInt16(mArray.Data,mIndex*2);
650                                                 break;
651                                         case 4:
652                                                 val = Marshal.ReadInt32(mArray.Data,mIndex*4);
653                                                 break;
654                                         case 8:
655                                                 val = Marshal.ReadInt64(mArray.Data,mIndex*8);
656                                                 break;
657                                         default:
658                                         throw new AprInvalidOperationException("Invalid element size.");
659                                 }
660                                
661                                 if(mArray.ElementType == val.GetType())
662                                         return(val);
663                                 else if (mArray.ElementType == typeof(bool))
664                                         return(unchecked(Convert.ChangeType(val,typeof(bool))));
665                                 else if (mArray.ElementType == typeof(sbyte))
666                                         return(unchecked((sbyte)((byte)val)));
667                                 else if (mArray.ElementType == typeof(ushort))
668                                         return(unchecked((ushort)((short)val)));
669                                 else if (mArray.ElementType == typeof(uint))
670                                         return(unchecked((uint)((int)val)));
671                                 else if (mArray.ElementType == typeof(ulong))
672                                         return(unchecked((ulong)((long)val)));
673                                 return(val);
674                                 }
675                                
676                         ConstructorInfo ctor = mArray.ElementType.GetConstructor(new Type[] {typeof(IntPtr)});
677                         if( ctor == null )
678                         throw new AprInvalidOperationException("Type is not primitive and cannot be constructed from an IntPtr.");
679                    
680                     IntPtr ptr = Marshal.ReadIntPtr(mArray.Data,mIndex*mArray.ElementSize);
681                                 return(ctor.Invoke(new Object[] { ptr }));
682             }
683             }
684             #endregion
685
686         }
687 }
Note: See TracBrowser for help on using the browser.