scide: refactor ide/language handshake
[supercollider.git] / include / lang / PyrArchiverT.h
blobdc926c66f2589e1d47da39e6ae434de4a982c399
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 An object archiving system for SuperCollider.
27 #ifndef _PyrArchiver_
28 #define _PyrArchiver_
30 #include "PyrObject.h"
31 #include "SC_AllocPool.h"
33 #include "PyrKernel.h"
34 #include "PyrPrimitive.h"
35 #include "PyrSymbol.h"
36 #include "VMGlobals.h"
37 #include "GC.h"
38 #include "ReadWriteMacros.h"
39 #include "SCBase.h"
41 const int32 kArchHdrSize = 12;
42 const int32 kObjectArrayInitialCapacity = 32;
44 template <class S>
45 class PyrArchiver
47 public:
48 PyrArchiver(VMGlobals *inG)
49 : g(inG), mObjectArray(mInitialObjectArray), mNumObjects(0),
50 mObjectArrayCapacity( kObjectArrayInitialCapacity ),
51 mReadArchiveVersion(0)
55 ~PyrArchiver()
57 if (mObjectArray != mInitialObjectArray) {
58 g->allocPool->Free(mObjectArray);
62 void setStream(S s) { mStream.SetStream(s); }
64 int32 calcArchiveSize()
66 PyrSlot *slot;
67 int32 size = kArchHdrSize;
68 if (mNumObjects == 0) {
69 size += sizeOfElem(&mTopSlot) + 1;
70 } else {
71 // object table size
72 for (int i=0; i<mNumObjects; ++i) {
73 PyrObject* obj = mObjectArray[i];
74 size += slotRawSymbol(&obj->classptr->name)->length + 1; // class name symbol
75 size += sizeof(int32); // size
76 if (obj->obj_format <= obj_slot) {
77 size += obj->size; // tags
78 slot = obj->slots;
79 for (int j=0; j<obj->size; ++j, ++slot) {
80 size += sizeOfElem(slot);
82 } else if (obj->obj_format == obj_symbol) {
83 PyrSymbol **symbol = ((PyrSymbolArray*)obj)->symbols;
84 for (int j=0; j<obj->size; ++j, ++symbol) {
85 size += (**symbol).length + 1;
87 } else {
88 size += obj->size * gFormatElemSize[obj->obj_format];
92 return size;
95 long prepareToWriteArchive(PyrSlot *objectSlot)
97 long err = errNone;
99 try {
100 slotCopy(&mTopSlot, objectSlot);
101 if (IsObj(objectSlot)) constructObjectArray(slotRawObject(objectSlot));
102 } catch (std::exception &ex) {
103 error(ex.what());
104 err = errFailed;
106 return err;
109 long writeArchive()
111 long err = errNone;
113 try {
114 writeArchiveHeader();
116 if (mNumObjects == 0) {
117 writeSlot(&mTopSlot);
118 } else {
119 for (int i=0; i<mNumObjects; ++i) {
120 writeObjectHeader(mObjectArray[i]);
122 for (int i=0; i<mNumObjects; ++i) {
123 writeSlots(mObjectArray[i]);
126 } catch (std::exception &ex) {
127 error(ex.what());
128 err = errFailed;
130 return err;
133 long readArchive(PyrSlot *objectSlot)
135 //postfl("->readArchive\n");
136 long err = errNone;
139 SetNil(objectSlot);
141 try {
142 readArchiveHeader();
143 //postfl("readObjectHeaders %d\n", mNumObjects);
144 if (mNumObjects == 0) {
145 readSlot(objectSlot);
146 } else {
147 for (int i=0; i<mNumObjects; ++i) {
148 mObjectArray[i] = readObjectHeader();
150 //postfl("readSlots\n");
151 for (int i=0; i<mNumObjects; ++i) {
152 readSlots(mObjectArray[i]);
154 //postfl("done reading\n");
155 //postfl("SetObject\n");
156 SetObject(objectSlot, mObjectArray[0]);
158 } catch (std::exception &ex) {
159 error(ex.what());
160 err = errFailed;
161 } catch (...) {
162 err = errFailed;
164 //postfl("<-readArchive\n");
165 return err;
168 private:
170 void writeArchiveHeader()
172 mStream.writeInt32_be(('!'<<24)|('S'<<16)|('C'<<8)|'a' /*'!SCa'*/);
173 mStream.writeInt32_be(2); // file version
174 mStream.writeInt32_be(mNumObjects);
177 void readArchiveHeader()
179 int32 magicNumber = mStream.readInt32_be();
180 if (magicNumber != (('!'<<24)|('S'<<16)|('C'<<8)|'a' /*'!SCa'*/)) {
181 throw std::runtime_error("not an SC archive.\n");
183 mReadArchiveVersion = mStream.readInt32_be(); // file version
184 mNumObjects = mStream.readInt32_be();
185 //post("readArchiveHeader %d %d\n", mReadArchiveVersion, mNumObjects);
187 if (mNumObjects > kObjectArrayInitialCapacity) {
188 mObjectArray = (PyrObject**)g->allocPool->Alloc(mNumObjects * sizeof(PyrObject*));
189 mObjectArrayCapacity = mNumObjects;
194 void recurse(PyrObject *obj, int n)
196 PyrSlot *slot = obj->slots;
197 for (int i=0; i<n; ++i, ++slot) {
198 if (IsObj(slot)) constructObjectArray(slotRawObject(slot));
202 void growObjectArray()
204 int32 newObjectArrayCapacity = mObjectArrayCapacity << 1;
206 int32 newSize = newObjectArrayCapacity * sizeof(PyrObject*);
207 PyrObject** newArray = (PyrObject**)g->allocPool->Alloc(newSize);
208 memcpy(newArray, mObjectArray, mNumObjects * sizeof(PyrObject*));
209 if (mObjectArray != mInitialObjectArray) {
210 g->allocPool->Free(mObjectArray);
212 mObjectArrayCapacity = newObjectArrayCapacity;
213 mObjectArray = newArray;
216 void putObject(PyrObject *obj)
218 obj->SetMark();
219 obj->scratch1 = mNumObjects;
221 // expand array if needed
222 if (mNumObjects >= mObjectArrayCapacity) growObjectArray();
224 // add to array
225 mObjectArray[mNumObjects++] = obj;
228 void constructObjectArray(PyrObject *obj)
230 if (!obj->IsMarked()) {
231 if (isKindOf(obj, class_class)) {
232 } else if (isKindOf(obj, class_process)) {
233 } else if (isKindOf(obj, s_interpreter->u.classobj)) {
234 } else if (isKindOf(obj, class_method)) {
235 throw std::runtime_error("cannot archive Methods.\n");
236 } else if (isKindOf(obj, class_thread)) {
237 throw std::runtime_error("cannot archive Threads.\n");
238 } else if (isKindOf(obj, class_frame)) {
239 throw std::runtime_error("cannot archive Frames.\n");
240 } else if (isKindOf(obj, class_func)) {
241 //if (NotNil(&((PyrClosure*)obj)->block.uoblk->context)) {
242 // throw std::runtime_error("open Function can not be archived.\n");
244 putObject(obj);
245 recurse(obj, obj->size);
246 } else {
247 if (isKindOf(obj, class_rawarray)) {
248 putObject(obj);
249 } else if (isKindOf(obj, class_array)) {
250 putObject(obj);
251 recurse(obj, obj->size);
253 } else {
254 putObject(obj);
255 recurse(obj, obj->size);
261 int32 sizeOfElem(PyrSlot *slot)
263 //postfl("writeSlot %08X\n", GetTag(slot));
264 switch (GetTag(slot)) {
265 case tagObj :
266 if (isKindOf(slotRawObject(slot), class_class)) {
267 return slotRawSymbol(&slotRawClass(slot)->name)->length + 1;
268 } else if (isKindOf(slotRawObject(slot), class_process)) {
269 return 0;
270 } else if (isKindOf(slotRawObject(slot), class_frame)) {
271 return 0;
272 } else if (isKindOf(slotRawObject(slot), s_interpreter->u.classobj)) {
273 return 0;
274 } else {
275 return sizeof(int32);
277 break;
278 case tagInt :
279 return sizeof(int32);
280 case tagSym :
281 return slotRawSymbol(slot)->length + 1;
282 case tagChar :
283 return sizeof(int32);
284 case tagNil :
285 return 0;
286 case tagFalse :
287 return 0;
288 case tagTrue :
289 return 0;
290 case tagPtr :
291 throw std::runtime_error("cannot archive RawPointers.");
292 return 0;
293 default :
294 return sizeof(double);
298 PyrSymbol* readSymbolID()
300 char str[256];
301 mStream.readSymbol(str);
302 return getsym(str);
306 PyrObject* readObjectID()
308 int32 objID = mStream.readInt32_be();
309 //postfl("readObjectID %d\n", objID);
310 return mObjectArray[objID];
313 void writeObjectHeader(PyrObject *obj)
315 obj->ClearMark();
317 //postfl("writeObjectHeader %s\n", slotRawSymbol(&obj->classptr->name)->name);
318 mStream.writeSymbol(slotRawSymbol(&obj->classptr->name)->name);
320 mStream.writeInt32_be(obj->size);
323 PyrObject* readObjectHeader()
325 PyrSymbol* classname = readSymbolID();
326 //post("readObjectHeader %s\n", classname->name);
327 PyrObject *obj;
328 int32 size = mStream.readInt32_be();
329 if (slotRawInt(&classname->u.classobj->classFlags) & classHasIndexableInstances) {
330 obj = instantiateObject(g->gc, classname->u.classobj, size, false, false);
331 obj->size = size;
332 } else {
333 obj = instantiateObject(g->gc, classname->u.classobj, 0, false, false);
335 return obj;
338 void writeSlots(PyrObject *obj)
340 //postfl(" writeSlots %s\n", slotRawSymbol(&obj->classptr->name)->name);
341 if (isKindOf(obj, class_rawarray)) {
342 writeRawArray(obj);
343 } else if (isKindOf(obj, class_func)) {
344 PyrClosure* closure = (PyrClosure*)obj;
345 if (NotNil(&slotRawBlock(&closure->block)->contextDef)) {
346 writeSlot(&closure->block);
347 writeSlot(&closure->context);
348 } else {
349 writeSlot(&closure->block);
350 writeSlot(&o_nil);
352 } else {
353 for (int i=0; i<obj->size; ++i) {
354 writeSlot(obj->slots + i);
359 void readSlots(PyrObject *obj)
361 //postfl("readSlots\n");
362 if (isKindOf(obj, class_rawarray)) {
363 readRawArray(obj);
364 } else if (isKindOf(obj, class_func)) {
365 PyrClosure* closure = (PyrClosure*)obj;
366 readSlot(&closure->block);
367 readSlot(&closure->context);
368 if (IsNil(&closure->context)) {
369 slotCopy(&closure->context, &slotRawInterpreter(&g->process->interpreter)->context);
371 } else {
372 for (int i=0; i<obj->size; ++i) {
373 readSlot(obj->slots + i);
378 void writeSlot(PyrSlot *slot)
380 PyrObject *obj;
381 //postfl(" writeSlot %08X\n", GetTag(slot));
382 switch (GetTag(slot)) {
383 case tagObj :
384 obj = slotRawObject(slot);
385 if (isKindOf(obj, class_class)) {
386 mStream.writeInt8('C');
387 mStream.writeSymbol(slotRawSymbol(&slotRawClass(slot)->name)->name);
388 } else if (isKindOf(obj, class_process)) {
389 mStream.writeInt8('P');
390 } else if (isKindOf(obj, s_interpreter->u.classobj)) {
391 mStream.writeInt8('R');
392 } else {
393 mStream.writeInt8('o');
394 mStream.writeInt32_be(obj->scratch1);
396 break;
397 case tagInt :
398 mStream.writeInt8('i');
399 mStream.writeInt32_be(slotRawInt(slot));
400 break;
401 case tagSym :
402 mStream.writeInt8('s');
403 mStream.writeSymbol(slotRawSymbol(slot)->name);
404 break;
405 case tagChar :
406 mStream.writeInt8('c');
407 mStream.writeInt32_be(slotRawInt(slot));
408 break;
409 case tagNil :
410 mStream.writeInt8('N');
411 break;
412 case tagFalse :
413 mStream.writeInt8('F');
414 break;
415 case tagTrue :
416 mStream.writeInt8('T');
417 break;
418 case tagPtr :
419 mStream.writeInt8('N');
420 break;
421 default :
422 mStream.writeInt8('f');
423 mStream.writeDouble_be(slotRawFloat(slot));
424 break;
428 void readSlot(PyrSlot *slot)
430 char tag = mStream.readInt8();
431 switch (tag) {
432 case 'o' :
433 SetObject(slot, readObjectID());
434 break;
435 case 'z' :
436 SetObject(slot, (PyrObject*)(size_t)mStream.readInt32_be()); // FIXME: fix 64bit safety
437 break;
438 case 'C' :
439 SetObject(slot, (PyrObject*)readSymbolID()->u.classobj);
440 break;
441 case 'P' :
442 SetObject(slot, (PyrObject*)g->process);
443 break;
444 case 'R' :
445 SetObject(slot, slotRawObject(&g->process->interpreter));
446 break;
447 case 'i' :
448 SetInt(slot, mStream.readInt32_be());
449 break;
450 case 's' :
451 SetSymbol(slot, readSymbolID());
452 break;
453 case 'c' :
454 SetChar(slot, mStream.readInt32_be());
455 break;
456 case 'f' :
457 SetFloat(slot, mStream.readDouble_be());
458 break;
459 case 'T' :
460 SetTrue(slot);
461 break;
462 case 'F' :
463 SetFalse(slot);
464 break;
465 case 'N' :
466 default :
467 SetNil(slot);
468 break;
472 void writeRawArray(PyrObject *obj)
474 int32 size = obj->size;
475 //postfl("writeRawArray %d\n", size);
476 switch (obj->obj_format) {
477 case obj_char :
478 case obj_int8 : {
479 char *data = (char*)obj->slots;
480 mStream.writeData(data, size);
481 } break;
482 case obj_int16 : {
483 int16 *data = (int16*)obj->slots;
484 for (int i=0; i<size; ++i) {
485 mStream.writeInt16_be(data[i]);
487 } break;
488 case obj_int32 :
489 case obj_float : {
490 int32 *data = (int32*)obj->slots;
491 for (int i=0; i<size; ++i) {
492 mStream.writeInt32_be(data[i]);
494 } break;
495 case obj_double : {
496 double *data = (double*)obj->slots;
497 for (int i=0; i<size; ++i) {
498 mStream.writeDouble_be(data[i]);
500 } break;
501 case obj_symbol : {
502 PyrSymbol **data = (PyrSymbol**)obj->slots;
503 for (int i=0; i<size; ++i) {
504 mStream.writeSymbol(data[i]->name);
506 } break;
510 void readRawArray(PyrObject *obj)
512 //postfl("readRawArray\n");
513 int32 size = obj->size;
514 switch (obj->obj_format) {
515 case obj_char :
516 case obj_int8 : {
517 int8 *data = (int8*)obj->slots;
518 for (int i=0; i<size; ++i) {
519 data[i] = mStream.readInt8();
521 } break;
522 case obj_int16 : {
523 int16 *data = (int16*)obj->slots;
524 for (int i=0; i<size; ++i) {
525 data[i] = mStream.readInt16_be();
527 } break;
528 case obj_int32 :
529 case obj_float : {
530 int32 *data = (int32*)obj->slots;
531 for (int i=0; i<size; ++i) {
532 data[i] = mStream.readInt32_be();
534 } break;
535 case obj_double : {
536 double *data = (double*)obj->slots;
537 for (int i=0; i<size; ++i) {
538 data[i] = mStream.readDouble_be();
540 } break;
541 case obj_symbol : {
542 PyrSymbol **data = (PyrSymbol**)obj->slots;
543 for (int i=0; i<size; ++i) {
544 data[i] = readSymbolID();
546 } break;
551 VMGlobals *g;
553 PyrObject **mObjectArray;
554 int32 mNumObjects;
555 int32 mObjectArrayCapacity;
556 PyrSlot mTopSlot;
558 SC_IOStream<S> mStream;
559 int32 mReadArchiveVersion;
561 PyrObject *mInitialObjectArray[kObjectArrayInitialCapacity];
565 #endif