comparison orange/serialization/archives/XMLArchive.d @ 20:9a575087b961

Added support for slices. Strings and arrays are now treated as references.
author Jacob Carlborg <doob@me.com>
date Mon, 04 Oct 2010 18:27:21 +0200
parents 3d42ea434d46
children 51f05fd6a626
comparison
equal deleted inserted replaced
18:3d42ea434d46 20:9a575087b961
38 static const DataType referenceTag = "reference"; 38 static const DataType referenceTag = "reference";
39 static const DataType pointerTag = "pointer"; 39 static const DataType pointerTag = "pointer";
40 static const DataType associativeArrayTag = "associativeArray"; 40 static const DataType associativeArrayTag = "associativeArray";
41 static const DataType typedefTag = "typedef"; 41 static const DataType typedefTag = "typedef";
42 static const DataType nullTag = "null"; 42 static const DataType nullTag = "null";
43 static const DataType enumTag = "enum"; 43 static const DataType enumTag = "enum";
44 static const DataType sliceTag = "slice";
44 } 45 }
45 46
46 private struct Attributes 47 private struct Attributes
47 { 48 {
48 static const DataType typeAttribute = "type"; 49 static const DataType typeAttribute = "type";
51 static const DataType keyAttribute = "key"; 52 static const DataType keyAttribute = "key";
52 static const DataType runtimeTypeAttribute = "runtimeType"; 53 static const DataType runtimeTypeAttribute = "runtimeType";
53 static const DataType idAttribute = "id"; 54 static const DataType idAttribute = "id";
54 static const DataType keyTypeAttribute = "keyType"; 55 static const DataType keyTypeAttribute = "keyType";
55 static const DataType valueTypeAttribute = "valueType"; 56 static const DataType valueTypeAttribute = "valueType";
57 static const DataType offsetAttribute = "offset";
56 } 58 }
57 59
58 private 60 private
59 { 61 {
62 struct ArrayNode
63 {
64 XMLDocument!(U).Node parent;
65 XMLDocument!(U).Node node;
66 DataType id;
67 DataType key;
68 }
69
70 struct Array
71 {
72 void* ptr;
73 size_t length;
74 size_t elementSize;
75
76 static Array opCall (T) (T[] value)
77 {
78 Array array;
79 array.ptr = value.ptr;
80 array.length = value.length;
81 array.elementSize = T.sizeof;
82
83 return array;
84 }
85
86 bool isSliceOf (Array b)
87 {
88 return ptr >= b.ptr && ptr + length * elementSize <= b.ptr + b.length * b.elementSize;
89 }
90 }
91
92 struct Slice
93 {
94 size_t length;
95 size_t offset;
96 DataType id;
97 }
98
60 DataType archiveType = "org.dsource.orange.xml"; 99 DataType archiveType = "org.dsource.orange.xml";
61 DataType archiveVersion = "0.1"; 100 DataType archiveVersion = "0.1";
62 101
63 XMLDocument!(U) doc; 102 XMLDocument!(U) doc;
64 doc.Node lastElement; 103 doc.Node lastElement;
68 bool hasBegunArchiving; 107 bool hasBegunArchiving;
69 bool hasBegunUnarchiving; 108 bool hasBegunUnarchiving;
70 109
71 DataType[void*] archivedReferences; 110 DataType[void*] archivedReferences;
72 void*[DataType] unarchivedReferences; 111 void*[DataType] unarchivedReferences;
112
113 ArrayNode[Array] arraysToBeArchived;
114 void[][DataType] unarchivedSlices;
73 115
74 size_t idCounter; 116 size_t idCounter;
75 } 117 }
76 118
77 this () 119 this ()
226 .attribute(Attributes.typeAttribute, toDataType(T.stringof)) 268 .attribute(Attributes.typeAttribute, toDataType(T.stringof))
227 .attribute(Attributes.keyAttribute, key); 269 .attribute(Attributes.keyAttribute, key);
228 } 270 }
229 271
230 private void archiveString (T) (T value, DataType key) 272 private void archiveString (T) (T value, DataType key)
231 { 273 {
232 lastElement.element(Tags.stringTag, toDataType(value)) 274 archiveArrayImpl(value, key, Tags.stringTag, toDataType(value));
233 .attribute(Attributes.typeAttribute, toDataType(BaseTypeOfArray!(T).stringof))
234 .attribute(Attributes.keyAttribute, key);
235 } 275 }
236 276
237 private void archiveArray (T) (T value, DataType key) 277 private void archiveArray (T) (T value, DataType key)
238 { 278 {
239 lastElement = lastElement.element(Tags.arrayTag) 279 archiveArrayImpl(value, key, Tags.arrayTag);
240 .attribute(Attributes.typeAttribute, toDataType(BaseTypeOfArray!(T).stringof)) 280 }
281
282 private void archiveArrayImpl (T) (T value, DataType key, DataType tag, DataType content = null)
283 {
284 DataType id = nextId;
285 auto parent = lastElement;
286
287 if (value.length == 0)
288 lastElement = lastElement.element(tag);
289
290 else
291 lastElement = doc.createNode(tag, content);
292
293 lastElement.attribute(Attributes.typeAttribute, toDataType(BaseTypeOfArray!(T).stringof))
241 .attribute(Attributes.lengthAttribute, toDataType(value.length)) 294 .attribute(Attributes.lengthAttribute, toDataType(value.length))
242 .attribute(Attributes.keyAttribute, key); 295 .attribute(Attributes.keyAttribute, key)
296 .attribute(Attributes.idAttribute, id);
297
298 arraysToBeArchived[Array(value)] = ArrayNode(parent, lastElement, id, key);
243 } 299 }
244 300
245 private void archiveAssociativeArray (T) (T value, DataType key) 301 private void archiveAssociativeArray (T) (T value, DataType key)
246 { 302 {
247 lastElement = lastElement.element(Tags.associativeArrayTag) 303 lastElement = lastElement.element(Tags.associativeArrayTag)
312 368
313 else static if (isString!(T)) 369 else static if (isString!(T))
314 value = unarchiveString!(T)(key); 370 value = unarchiveString!(T)(key);
315 371
316 else static if (isArray!(T)) 372 else static if (isArray!(T))
317 value = unarchiveArray!(T)(key); 373 value = unarchiveArray!(T)(key, callDelegate);
318 374
319 else static if (isAssociativeArray!(T)) 375 else static if (isAssociativeArray!(T))
320 value = unarchiveAssociativeArray!(T)(key); 376 value = unarchiveAssociativeArray!(T)(key);
321 377
322 else static if (isPrimitive!(T)) 378 else static if (isPrimitive!(T))
359 415
360 lastElement = tmp; 416 lastElement = tmp;
361 417
362 auto runtimeType = getValueOfAttribute(Attributes.runtimeTypeAttribute); 418 auto runtimeType = getValueOfAttribute(Attributes.runtimeTypeAttribute);
363 auto name = fromDataType!(string)(runtimeType); 419 auto name = fromDataType!(string)(runtimeType);
364 id = getValueOfAttribute(Attributes.idAttribute); 420 id = getValueOfAttribute(Attributes.idAttribute);
365 421 T result = cast(T) newInstance(name);
366 T result;
367
368 /*static if (is(typeof(T._ctor)))
369 {
370 ParameterTupleOf!(typeof(T._ctor)) params;
371 result = factory!(T, typeof(params))(name, params);
372 }
373
374 else*/
375 result = cast(T) newInstance(name);
376 422
377 addUnarchivedReference(result, id); 423 addUnarchivedReference(result, id);
378 424
379 return result; 425 return result;
380 } 426 }
389 return T.init; 435 return T.init;
390 } 436 }
391 437
392 private T unarchiveString (T) (DataType key) 438 private T unarchiveString (T) (DataType key)
393 { 439 {
440 auto slice = unarchiveSlice(key);
441
442 if (auto tmp = getUnarchivedSlice!(T)(slice))
443 return *tmp;
444
394 auto element = getElement(Tags.stringTag, key); 445 auto element = getElement(Tags.stringTag, key);
395 446
396 if (!element.isValid) 447 if (!element.isValid)
397 return T.init; 448 return T.init;
398 449
399 return fromDataType!(T)(element.value); 450 auto value = fromDataType!(T)(element.value);
400 } 451 slice.id = getValueOfAttribute(Attributes.idAttribute, element);
401 452
402 private T unarchiveArray (T) (DataType key) 453 addUnarchivedSlice(value, slice.id);
403 { 454
455 return value;
456 }
457
458 private T unarchiveArray (T) (DataType key, ref bool callDelegate)
459 {
460 auto slice = unarchiveSlice(key);
461
462 if (auto tmp = getUnarchivedSlice!(T)(slice))
463 {
464 callDelegate = false;
465 return *tmp;
466 }
467
404 T value; 468 T value;
405 469
406 auto element = getElement(Tags.arrayTag, key); 470 auto element = getElement(Tags.arrayTag, key);
407 471
408 if (!element.isValid) 472 if (!element.isValid)
409 return T.init; 473 return T.init;
410 474
411 lastElement = element; 475 lastElement = element;
412 auto length = getValueOfAttribute(Attributes.lengthAttribute); 476 auto length = getValueOfAttribute(Attributes.lengthAttribute);
413 value.length = fromDataType!(size_t)(length); 477 value.length = fromDataType!(size_t)(length);
478 slice.id = getValueOfAttribute(Attributes.idAttribute);
479
480 addUnarchivedSlice(value, slice.id);
414 481
415 return value; 482 return value;
416 } 483 }
417 484
418 private T unarchiveAssociativeArray (T) (DataType key) 485 private T unarchiveAssociativeArray (T) (DataType key)
551 618
552 return doc.Node.invalid; 619 return doc.Node.invalid;
553 } 620 }
554 } 621 }
555 622
556 private DataType getValueOfAttribute (DataType attribute) 623 private DataType getValueOfAttribute (DataType attribute, doc.Node element = doc.Node.invalid)
557 { 624 {
558 auto set = lastElement.query.attribute(attribute); 625 if (!element.isValid) element = lastElement;
626
627 auto set = element.query.attribute(attribute);
559 628
560 if (set.nodes.length == 1) 629 if (set.nodes.length == 1)
561 return set.nodes[0].value; 630 return set.nodes[0].value;
562 631
563 else 632 else
585 static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`)); 654 static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`));
586 655
587 unarchivedReferences[id] = cast(void*) value; 656 unarchivedReferences[id] = cast(void*) value;
588 } 657 }
589 658
659 private void addUnarchivedSlice (T) (T value, DataType id)
660 {
661 static assert(isArray!(T) || isString!(T), format!(`The given type "`, T, `" is not a slice type, i.e. array or string.`));
662
663 unarchivedSlices[id] = value;
664 }
665
590 private DataType getArchivedReference (T) (T value) 666 private DataType getArchivedReference (T) (T value)
591 { 667 {
592 if (auto tmp = cast(void*) value in archivedReferences) 668 if (auto tmp = cast(void*) value in archivedReferences)
593 return *tmp; 669 return *tmp;
594 670
598 private T* getUnarchivedReference (T) (DataType id) 674 private T* getUnarchivedReference (T) (DataType id)
599 { 675 {
600 if (auto reference = id in unarchivedReferences) 676 if (auto reference = id in unarchivedReferences)
601 return cast(T*) reference; 677 return cast(T*) reference;
602 678
679 return null;
680 }
681
682 private T* getUnarchivedSlice (T) (Slice slice)
683 {
684 if (auto array = slice.id in unarchivedSlices)
685 return &(cast(T) *array)[slice.offset .. slice.length + 1]; // dereference the array, cast it to the right type,
686 // slice it and then return a pointer to the result
603 return null; 687 return null;
604 } 688 }
605 689
606 private DataType nextId () 690 private DataType nextId ()
607 { 691 {
621 if (element.isValid) 705 if (element.isValid)
622 return element.value; 706 return element.value;
623 707
624 return cast(DataType) null; 708 return cast(DataType) null;
625 } 709 }
710
711 private Slice unarchiveSlice (DataType key)
712 {
713 auto element = getElement(Tags.sliceTag, key, Attributes.keyAttribute, false);
714
715 if (element.isValid)
716 {
717 auto length = fromDataType!(size_t)(getValueOfAttribute(Attributes.lengthAttribute, element));
718 auto offset = fromDataType!(size_t)(getValueOfAttribute(Attributes.offsetAttribute, element));
719
720 return Slice(length, offset, element.value);
721 }
722
723 return Slice.init;
724 }
626 725
627 private struct AssociativeArrayVisitor (Key, Value) 726 private struct AssociativeArrayVisitor (Key, Value)
628 { 727 {
629 private XMLArchive archive; 728 private XMLArchive archive;
630 729
659 } 758 }
660 759
661 return result; 760 return result;
662 } 761 }
663 } 762 }
763
764 public void postProcess ()
765 {
766 bool foundSlice = true;
767
768 foreach (slice, sliceNode ; arraysToBeArchived)
769 {
770 foreach (array, arrayNode ; arraysToBeArchived)
771 {
772 if (slice.isSliceOf(array) && slice != array)
773 {
774 sliceNode.parent.element(Tags.sliceTag, arrayNode.id)
775 .attribute(Attributes.keyAttribute, sliceNode.key)
776 .attribute(Attributes.offsetAttribute, toDataType((slice.ptr - array.ptr) / slice.elementSize))
777 .attribute(Attributes.lengthAttribute, toDataType(slice.length));
778
779 foundSlice = true;
780 break;
781 }
782
783 else
784 foundSlice = false;
785 }
786
787 if (!foundSlice)
788 sliceNode.parent.attach(sliceNode.node);
789 }
790 }
664 } 791 }