Mercurial > projects > orange
comparison orange/serialization/archives/XMLArchive.d @ 22:963b756ed579
Resolved merge conflicts.
author | Jacob Carlborg <doob@me.com> |
---|---|
date | Mon, 04 Oct 2010 20:42:45 +0200 |
parents | 8ab9588b92bf 51f05fd6a626 |
children | 55f0a9d5df8d |
comparison
equal
deleted
inserted
replaced
19:8ab9588b92bf | 22:963b756ed579 |
---|---|
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)) |
360 lastElement = tmp; | 416 lastElement = tmp; |
361 | 417 |
362 auto runtimeType = getValueOfAttribute(Attributes.runtimeTypeAttribute); | 418 auto runtimeType = getValueOfAttribute(Attributes.runtimeTypeAttribute); |
363 | 419 |
364 if (!runtimeType) | 420 if (!runtimeType) |
365 return T.init; | 421 return T.init; |
366 | 422 |
367 auto name = fromDataType!(string)(runtimeType); | 423 auto name = fromDataType!(string)(runtimeType); |
368 id = getValueOfAttribute(Attributes.idAttribute); | 424 id = getValueOfAttribute(Attributes.idAttribute); |
369 | 425 |
370 if (!id) | 426 if (!id) |
371 return T.init; | 427 return T.init; |
372 | 428 |
373 T result; | 429 T result = cast(T) newInstance(name); |
374 | |
375 /*static if (is(typeof(T._ctor))) | |
376 { | |
377 ParameterTupleOf!(typeof(T._ctor)) params; | |
378 result = factory!(T, typeof(params))(name, params); | |
379 } | |
380 | |
381 else*/ | |
382 result = cast(T) newInstance(name); | |
383 | 430 |
384 addUnarchivedReference(result, id); | 431 addUnarchivedReference(result, id); |
385 | 432 |
386 return result; | 433 return result; |
387 } | 434 } |
396 return T.init; | 443 return T.init; |
397 } | 444 } |
398 | 445 |
399 private T unarchiveString (T) (DataType key) | 446 private T unarchiveString (T) (DataType key) |
400 { | 447 { |
448 auto slice = unarchiveSlice(key); | |
449 | |
450 if (auto tmp = getUnarchivedSlice!(T)(slice)) | |
451 return *tmp; | |
452 | |
401 auto element = getElement(Tags.stringTag, key); | 453 auto element = getElement(Tags.stringTag, key); |
402 | 454 |
403 if (!element.isValid) | 455 if (!element.isValid) |
404 return T.init; | 456 return T.init; |
405 | 457 |
406 return fromDataType!(T)(element.value); | 458 auto value = fromDataType!(T)(element.value); |
407 } | 459 slice.id = getValueOfAttribute(Attributes.idAttribute, element); |
408 | 460 |
409 private T unarchiveArray (T) (DataType key) | 461 if (!slice.id) |
410 { | 462 return T.init; |
463 | |
464 addUnarchivedSlice(value, slice.id); | |
465 | |
466 return value; | |
467 } | |
468 | |
469 private T unarchiveArray (T) (DataType key, ref bool callDelegate) | |
470 { | |
471 auto slice = unarchiveSlice(key); | |
472 | |
473 if (auto tmp = getUnarchivedSlice!(T)(slice)) | |
474 { | |
475 callDelegate = false; | |
476 return *tmp; | |
477 } | |
478 | |
411 T value; | 479 T value; |
412 | 480 |
413 auto element = getElement(Tags.arrayTag, key); | 481 auto element = getElement(Tags.arrayTag, key); |
414 | 482 |
415 if (!element.isValid) | 483 if (!element.isValid) |
420 | 488 |
421 if (!length) | 489 if (!length) |
422 return T.init; | 490 return T.init; |
423 | 491 |
424 value.length = fromDataType!(size_t)(length); | 492 value.length = fromDataType!(size_t)(length); |
493 slice.id = getValueOfAttribute(Attributes.idAttribute); | |
494 | |
495 if (!slice.id) | |
496 return T.init; | |
497 | |
498 addUnarchivedSlice(value, slice.id); | |
425 | 499 |
426 return value; | 500 return value; |
427 } | 501 } |
428 | 502 |
429 private T unarchiveAssociativeArray (T) (DataType key) | 503 private T unarchiveAssociativeArray (T) (DataType key) |
562 else | 636 else |
563 errorCallback(new ArchiveException(`Could not unarchive the value with the key "` ~ to!(string)(key) ~ `" due to malformed data.`, __FILE__, __LINE__), [tag, Attributes.keyAttribute, key]); | 637 errorCallback(new ArchiveException(`Could not unarchive the value with the key "` ~ to!(string)(key) ~ `" due to malformed data.`, __FILE__, __LINE__), [tag, Attributes.keyAttribute, key]); |
564 } | 638 } |
565 | 639 |
566 return doc.Node.invalid; | 640 return doc.Node.invalid; |
567 } | 641 } |
568 } | 642 } |
569 | 643 |
570 private DataType getValueOfAttribute (DataType attribute) | 644 private DataType getValueOfAttribute (DataType attribute, doc.Node element = doc.Node.invalid) |
571 { | 645 { |
572 auto set = lastElement.query.attribute(attribute); | 646 if (!element.isValid) element = lastElement; |
647 | |
648 auto set = element.query.attribute(attribute); | |
573 | 649 |
574 if (set.nodes.length == 1) | 650 if (set.nodes.length == 1) |
575 return set.nodes[0].value; | 651 return set.nodes[0].value; |
576 | 652 |
577 else | 653 else |
583 | 659 |
584 else | 660 else |
585 errorCallback(new ArchiveException(`Could not unarchive the value of the attribute "` ~ to!(string)(attribute) ~ `" due to malformed data.`, __FILE__, __LINE__), [attribute]); | 661 errorCallback(new ArchiveException(`Could not unarchive the value of the attribute "` ~ to!(string)(attribute) ~ `" due to malformed data.`, __FILE__, __LINE__), [attribute]); |
586 } | 662 } |
587 } | 663 } |
588 | 664 |
589 return null; | 665 return null; |
590 } | 666 } |
591 | 667 |
592 private void addArchivedReference (T) (T value, DataType id) | 668 private void addArchivedReference (T) (T value, DataType id) |
593 { | 669 { |
594 static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`)); | 670 static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`)); |
599 private void addUnarchivedReference (T) (T value, DataType id) | 675 private void addUnarchivedReference (T) (T value, DataType id) |
600 { | 676 { |
601 static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`)); | 677 static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`)); |
602 | 678 |
603 unarchivedReferences[id] = cast(void*) value; | 679 unarchivedReferences[id] = cast(void*) value; |
680 } | |
681 | |
682 private void addUnarchivedSlice (T) (T value, DataType id) | |
683 { | |
684 static assert(isArray!(T) || isString!(T), format!(`The given type "`, T, `" is not a slice type, i.e. array or string.`)); | |
685 | |
686 unarchivedSlices[id] = value; | |
604 } | 687 } |
605 | 688 |
606 private DataType getArchivedReference (T) (T value) | 689 private DataType getArchivedReference (T) (T value) |
607 { | 690 { |
608 if (auto tmp = cast(void*) value in archivedReferences) | 691 if (auto tmp = cast(void*) value in archivedReferences) |
614 private T* getUnarchivedReference (T) (DataType id) | 697 private T* getUnarchivedReference (T) (DataType id) |
615 { | 698 { |
616 if (auto reference = id in unarchivedReferences) | 699 if (auto reference = id in unarchivedReferences) |
617 return cast(T*) reference; | 700 return cast(T*) reference; |
618 | 701 |
702 return null; | |
703 } | |
704 | |
705 private T* getUnarchivedSlice (T) (Slice slice) | |
706 { | |
707 if (auto array = slice.id in unarchivedSlices) | |
708 return &(cast(T) *array)[slice.offset .. slice.length + 1]; // dereference the array, cast it to the right type, | |
709 // slice it and then return a pointer to the result | |
619 return null; | 710 return null; |
620 } | 711 } |
621 | 712 |
622 private DataType nextId () | 713 private DataType nextId () |
623 { | 714 { |
637 if (element.isValid) | 728 if (element.isValid) |
638 return element.value; | 729 return element.value; |
639 | 730 |
640 return cast(DataType) null; | 731 return cast(DataType) null; |
641 } | 732 } |
733 | |
734 private Slice unarchiveSlice (DataType key) | |
735 { | |
736 auto element = getElement(Tags.sliceTag, key, Attributes.keyAttribute, false); | |
737 | |
738 if (element.isValid) | |
739 { | |
740 auto length = fromDataType!(size_t)(getValueOfAttribute(Attributes.lengthAttribute, element)); | |
741 auto offset = fromDataType!(size_t)(getValueOfAttribute(Attributes.offsetAttribute, element)); | |
742 | |
743 return Slice(length, offset, element.value); | |
744 } | |
745 | |
746 return Slice.init; | |
747 } | |
642 | 748 |
643 private struct AssociativeArrayVisitor (Key, Value) | 749 private struct AssociativeArrayVisitor (Key, Value) |
644 { | 750 { |
645 private XMLArchive archive; | 751 private XMLArchive archive; |
646 | 752 |
675 } | 781 } |
676 | 782 |
677 return result; | 783 return result; |
678 } | 784 } |
679 } | 785 } |
786 | |
787 public void postProcess () | |
788 { | |
789 bool foundSlice = true; | |
790 | |
791 foreach (slice, sliceNode ; arraysToBeArchived) | |
792 { | |
793 foreach (array, arrayNode ; arraysToBeArchived) | |
794 { | |
795 if (slice.isSliceOf(array) && slice != array) | |
796 { | |
797 sliceNode.parent.element(Tags.sliceTag, arrayNode.id) | |
798 .attribute(Attributes.keyAttribute, sliceNode.key) | |
799 .attribute(Attributes.offsetAttribute, toDataType((slice.ptr - array.ptr) / slice.elementSize)) | |
800 .attribute(Attributes.lengthAttribute, toDataType(slice.length)); | |
801 | |
802 foundSlice = true; | |
803 break; | |
804 } | |
805 | |
806 else | |
807 foundSlice = false; | |
808 } | |
809 | |
810 if (!foundSlice) | |
811 sliceNode.parent.attach(sliceNode.node); | |
812 } | |
813 } | |
680 } | 814 } |