1 /** 2 * A collection of helper functions used in DMagick. 3 * 4 * Copyright: Mike Wey 2011 5 * License: zlib (See accompanying LICENSE file) 6 * Authors: Mike Wey 7 */ 8 9 module dmagick.Utils; 10 11 import std.math; 12 13 import dmagick.Exception; 14 15 import dmagick.c.memory; 16 import dmagick.c.magickString; 17 import dmagick.c.magickType; 18 19 /** 20 * Copy a string into a static array used 21 * by ImageMagick for some atributes. 22 */ 23 void copyString(ref char[MaxTextExtent] dest, string source) 24 { 25 if ( source.length > MaxTextExtent ) 26 throw new ResourceLimitException("Source is larger then MaxTextExtend", null); 27 28 dest[0 .. source.length] = source; 29 dest[source.length] = '\0'; 30 } 31 32 unittest 33 { 34 char[MaxTextExtent] dest; 35 copyString(dest, "unittest"); 36 37 assert(dest[0 .. 8] == "unittest"); 38 } 39 40 /** 41 * Our implementation of ImageMagick's CloneString. 42 * 43 * We use this since using CloneString forces us to 44 * append a \0 to the end of the string, and the realocation 45 * whould be wastefull if we are just going to copy it 46 * 47 * used for copying a string into a Imagemagick struct 48 */ 49 void copyString(ref char* dest, string source) 50 { 51 if ( source is null ) 52 { 53 if ( dest !is null ) 54 dest = DestroyString(dest); 55 return; 56 } 57 58 if ( ~source.length < MaxTextExtent ) 59 throw new ResourceLimitException("unable to acquire string", null); 60 61 if ( dest is null ) 62 dest = cast(char*)AcquireQuantumMemory(source.length+MaxTextExtent, dest.sizeof); 63 else 64 dest = cast(char*)ResizeQuantumMemory(dest, source.length+MaxTextExtent, dest.sizeof); 65 66 if ( dest is null ) 67 throw new ResourceLimitException("unable to acquire string", null); 68 69 if ( source.length > 0 ) 70 dest[0 .. source.length] = source; 71 72 dest[source.length] = '\0'; 73 } 74 75 unittest 76 { 77 char* dest; 78 string source = "test"; 79 80 copyString(dest, source); 81 82 assert( dest !is source.ptr ); 83 assert( dest[0..5] == "test\0" ); 84 85 copyString(dest, "unit"); 86 assert( dest[0..5] == "unit\0" ); 87 88 copyString(dest, null); 89 assert( dest is null ); 90 } 91 92 /** */ 93 real degreesToRadians(real deg) 94 { 95 return deg*PI/180; 96 } 97 98 99 /** 100 * A template struct to make pointers to ImageMagick structs 101 * reference counted. Excepts a predicate pred which destroys 102 * the struct pointer when refCount is 0. 103 */ 104 struct RefCounted(alias pred, T) 105 if ( !is(T == class) && is(typeof(pred(cast(T*)null)) == T*) ) 106 { 107 T* payload; 108 109 private bool isInitialized; 110 private size_t* refcount; 111 112 alias payload this; 113 114 this(T* payload) 115 { 116 this.payload = payload; 117 118 refcount = new size_t; 119 *refcount = 1; 120 121 isInitialized = true; 122 } 123 124 this(this) 125 { 126 if ( isInitialized ) 127 (*refcount)++; 128 } 129 130 ~this() 131 { 132 if ( !isInitialized ) 133 return; 134 135 (*refcount)--; 136 137 if ( *refcount == 0 ) 138 payload = pred(payload); 139 } 140 141 @property size_t refCount() 142 { 143 return *refcount; 144 } 145 } 146 147 unittest 148 { 149 int x = 10; 150 int y = 20; 151 152 alias RefCounted!( (int* t){ x = 20; return t; }, int ) IntRef; 153 154 auto a = IntRef(&x); 155 assert( a.refCount == 1 ); 156 auto b = a; 157 assert( a.refCount == 2 ); 158 159 b = IntRef(&y); 160 assert( a.refCount == 1 ); 161 assert( b.refCount == 1 ); 162 a = b; 163 assert( b.refCount == 2 ); 164 assert( x == 20 ); 165 }