Mercurial > projects > orange
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 } |