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 }