aboutsummaryrefslogtreecommitdiff
path: root/PureData/Atom.cs
blob: 6bad0b6bef14a999811cceb6efa5a9073bd03eda (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
using System;
using System.Runtime.InteropServices; // for structures
using System.Collections;
#if NET_2_0
using System.Collections.Generic;
#endif

namespace PureData
{
    [StructLayout (LayoutKind.Sequential)]
    public unsafe struct Symbol
    {
        // this should NOT be public (or at least read only)
        private readonly void *sym;

        public Symbol(string s)
        {
            sym = Internal.SymGen(s);
        }

        public override string ToString()
        {
            return Internal.SymEval(sym);
        }
    }

    [StructLayout (LayoutKind.Sequential)]
    public unsafe struct Pointer
    {
        private readonly void *ptr;

        public override string ToString()
        {
            if(sizeof(void *) == 4)
                return ((int)ptr).ToString();
            else
                return ((long)ptr).ToString();
        }
    }

	[StructLayout (LayoutKind.Sequential)]
	public unsafe struct Atom 
	{
        private enum AtomType {Null = 0, Float = 1, Symbol = 2, Pointer = 3};
        
        [StructLayout (LayoutKind.Explicit)]
        private struct Word
        {
            [FieldOffset(0)] public float w_float;
            [FieldOffset(0)] public Symbol w_sym;
            [FieldOffset(0)] public Pointer w_ptr;
        }

		private AtomType type;
		private Word word;
		
		public Atom(float f)
		{
			type = AtomType.Float;
			word = new Word();
			word.w_float = f;
		}

		public Atom(int i)
		{
            type = AtomType.Float;
            word = new Word();
            word.w_float = (float)i;
        }

        public Atom(Symbol s)
        {
            type = AtomType.Symbol;
            word = new Word();
            word.w_sym = s;
        }
        
		public Atom(string s)
		{
            type = AtomType.Symbol;
            word = new Word();
            word.w_sym = new Symbol(s);
		}

        public Atom(Pointer p)
        {
            type = AtomType.Pointer;
            word = new Word();
            word.w_ptr = p;
        }

        public bool IsFloat { get { return type == AtomType.Float; } }
        public bool IsSymbol { get { return type == AtomType.Symbol; } }
        public bool IsPointer { get { return type == AtomType.Pointer; } }

        public float ToFloat()
        {
            if(IsFloat)
                return word.w_float;
            else
                throw new System.InvalidCastException("Can't be cast to float.");
        }
        
        public Symbol ToSymbol()
        {
            if(IsSymbol)
                return word.w_sym;
            else
                throw new System.InvalidCastException("Can't be cast to Symbol.");
        }
        
        public Pointer ToPointer()
        {
            if(IsPointer)
                return word.w_ptr;
            else
                throw new System.InvalidCastException("Can't be cast to Pointer.");
        }
        
        override public string ToString()
        {
            if(IsFloat)
                return word.w_float.ToString();
            else if(IsSymbol)
                return word.w_sym.ToString();
            else if(IsPointer)
                return word.w_ptr.ToString();
            else
                // should never happen
                throw new System.InvalidProgramException("Internal error.");
        }

        public static explicit operator float(Atom a)
        {
            return a.ToFloat();
        }

        public static explicit operator Symbol(Atom a)
        {
            return a.ToSymbol();
        }

        public static explicit operator Pointer(Atom a)
        {
            return a.ToPointer();
        }
    }
	
    public class AtomListEnum
        : IEnumerator
    {
        public AtomList list;

        // Enumerators are positioned before the first element
        // until the first MoveNext() call.
        int position = -1;

        public AtomListEnum(AtomList l)
        {
            list = l;
        }

        public bool MoveNext()
        {
            return ++position < list.Count;
        }

        public void Reset()
        {
            position = -1;
        }

        public object Current
        {
            get
            {
                try
                {
                    return list[position];
                }
                catch (IndexOutOfRangeException)
                {
                    throw new InvalidOperationException();
                }
            }
        }
    }


    // attention: this is dangerous, because we could do the following
    // AtomList l2 = l;  
    // with l also being an AtomList... the two private members of the struct will get copied, although atoms is only a temporary reference

    [StructLayout (LayoutKind.Sequential)]
    unsafe public struct AtomList
#if NET_2_0
		: ICollection<Atom>
#else
        : ICollection
#endif
    {
        private readonly int len;
        private readonly Atom *atoms;
        
        public int Count { get { return len; } }
#if NET_2_0
        public bool IsReadOnly { get { return false; } } // member of generic.ICollection<Atom> (C# 2.0)
#endif        
        public bool IsSynchronized { get { return false; } }
        public Object SyncRoot { get { return null; } }

        // protect this from being used
        private AtomList(AtomList a) { len = 0; atoms = null; }

#if NET_2_0
        public void CopyTo(Atom[] array,int start)
#else        
        public void CopyTo(Array array,int start)
#endif        
        {
            if(len > array.GetUpperBound(0)+1-start)
                throw new System.ArgumentException("Destination array is not long enough.");
            int i;                
            for(i = 0; i < len-start; ++i)
                array.SetValue(atoms[start+i],i);
        }

        public IEnumerator GetEnumerator()
        {
            return new AtomListEnum(this);
        }
        
        public Atom this[int i]
        {
            get
            {
                if(i < 0 || i >= len)
                    throw new System.IndexOutOfRangeException("Index outside array bounds.");
                return atoms[i];
            }
            set
            {
                if(i < 0 || i >= len)
                    throw new System.IndexOutOfRangeException("Index outside array bounds.");
                atoms[i] = value;
            }
        }

#if !NET_2_0
        public static explicit operator Atom[](AtomList l)
        {
            Atom[] ret = new Atom[l.Count];
            int i;
            for(i = 0; i < l.Count; ++i) ret[i] = l.atoms[i];
            return ret;
        }
#endif        

        override public string ToString()
        {
            string n = "{";
            if(len > 0) {
                int i;
                for(i = 0; i < len-1; ++i) n += atoms[i].ToString()+",";
                n += atoms[i].ToString();
            }
            return n+"}";
        }
    }	
}