rt_private uint32 pst_store(struct rt_store_context *a_context, EIF_REFERENCE object, uint32 a_object_count) { /* Second pass of the store mechanism: writing on the disk. */ EIF_REFERENCE o_ref; EIF_REFERENCE o_ptr; long i, nb_references; union overhead *zone = HEADER(object); uint16 flags; int is_expanded, has_volatile_attributes = 0; EIF_BOOLEAN object_needs_index; long saved_file_pos = 0; long saved_object_count = a_object_count; REQUIRE ("valid need_index and make_index", (need_index && make_index) || (!need_index && !make_index)); if (need_index) { object_needs_index = (EIF_BOOLEAN) ((EIF_BOOLEAN (*)(EIF_REFERENCE, EIF_REFERENCE))need_index) (server,object); if (object_needs_index) { /* If the object needs an index, the buffer is flushed so that * a new compression header is stored just before the object * thus the decompression will work when starting the retrieve * there */ a_context->flush_buffer_function(); saved_file_pos = file_position + parsing_position; } } else { object_needs_index = 0; } flags = zone->ov_flags; is_expanded = eif_is_nested_expanded(flags); if (!(is_expanded || (flags & EO_STORE))) return a_object_count; /* Unmarked means already stored */ else if (!is_expanded) a_object_count++; zone->ov_flags &= ~EO_STORE; /* Unmark it */ #ifdef DEBUG printf("object 0x%" EIF_POINTER_DISPLAY " [%s %" EIF_POINTER_DISPLAY "]\n", (rt_uint_ptr) object, System(zone->ov_dtype).cn_generator, (rt_uint_ptr) zone->ov_flags); #endif /* Evaluation of the number of references of the object */ if (flags & EO_SPEC) { /* Special object */ if (flags & EO_REF) { /* Special of reference/composite types */ EIF_INTEGER count, elem_size; EIF_REFERENCE ref; count = RT_SPECIAL_COUNT(object); if (flags & EO_TUPLE) { EIF_TYPED_VALUE * l_item = (EIF_TYPED_VALUE *) object; /* Don't forget that first element of TUPLE is the BOOLEAN * `object_comparison' attribute. */ l_item++; count--; for (; count > 0; count--, l_item++) { if (eif_is_reference_tuple_item(l_item)) { o_ref = eif_reference_tuple_item(l_item); if (o_ref) { a_object_count = pst_store (a_context, o_ref, a_object_count); } } } } else if (!(flags & EO_COMP)) { /* Special of references */ for (ref = object; count > 0; count--, ref = (EIF_REFERENCE) ((EIF_REFERENCE *) ref + 1)) { o_ref = *(EIF_REFERENCE *) ref; if (o_ref != (EIF_REFERENCE) 0) a_object_count = pst_store (a_context, o_ref,a_object_count); } } else { /* Special of composites */ elem_size = RT_SPECIAL_ELEM_SIZE(object); for (ref = object + OVERHEAD; count > 0; count --, ref += elem_size) { a_object_count = pst_store (a_context, ref,a_object_count); } } } } else { /* Normal object */ nb_references = References(zone->ov_dtype); /* Traversal of references of `object' */ for ( o_ptr = object, i = 0; i < nb_references; i++, o_ptr = (EIF_REFERENCE) (((EIF_REFERENCE *) o_ptr) +1) ) { o_ref = *(EIF_REFERENCE *)o_ptr; if (o_ref) { if (!EIF_IS_TRANSIENT_ATTRIBUTE(System(zone->ov_dtype), i)) { a_object_count = pst_store (a_context, o_ref, a_object_count); } else { has_volatile_attributes = 1; } } } } if (!is_expanded) { a_context->object_write_function(object, has_volatile_attributes); /* write the object */ } /* Call `make_index' on `server' with `object' */ if (object_needs_index) { (make_index)(server, object, saved_file_pos, a_object_count - saved_object_count); } return a_object_count; }
rt_public EIF_BOOLEAN spiso(register EIF_REFERENCE target, register EIF_REFERENCE source) { /* Compare two special objects in term of their structures. `source' * and `target' are refering two special objects. There is three cases: * 1- either the elements are direct instances: block comparison. * 2- either the elements are references: comparison of referenced * dynamic type. * 3- or the elements are expanded: call `eiso' (special objects * cannot be expanded). */ union overhead *s_zone; /* Source header */ uint32 s_flags; /* Source flags */ /*uint32 t_flags;*/ /* Target flags */ EIF_REFERENCE s_ref; EIF_REFERENCE t_ref; EIF_INTEGER count; /* Common count */ EIF_INTEGER elem_size; /* Common element size */ EIF_REFERENCE s_field, t_field; REQUIRE("special objects", (HEADER(target)->ov_flags & EO_SPEC) && (HEADER(source)->ov_flags & EO_SPEC)); if (source == target) return EIF_TRUE; s_zone = HEADER(source); #ifdef DEBUG dprintf(2)("spiso: source = 0x%lx [%d] target = 0x%lx [%d]\n", source, RT_SPECIAL_COUNT(source), target, RT_SPECIAL_COUNT(target)); #endif count = RT_SPECIAL_COUNT(source); if (count != RT_SPECIAL_COUNT(target)) return EIF_FALSE; /* Second condition: same element size */ elem_size = RT_SPECIAL_ELEM_SIZE(source); if (elem_size != RT_SPECIAL_ELEM_SIZE(target)) return EIF_FALSE; s_flags = s_zone->ov_flags; /* In final mode, we can do block comparison on special of basic types * or on special of expanded which have no references since they have no header. * In workbench mode, block comparison is only possible on special of basic types. */ #ifdef WORKBENCH if (!(s_flags & EO_REF) && !(s_flags & EO_COMP)) { #else if (!(s_flags & EO_REF)) { #endif /* Case 1: specials filled with direct instances: block comparison */ return EIF_TEST(!memcmp (source, target, (rt_uint_ptr) count * (rt_uint_ptr) elem_size)); } if (s_flags & EO_TUPLE) { EIF_TYPED_VALUE * l_source = (EIF_TYPED_VALUE *) source; EIF_TYPED_VALUE * l_target = (EIF_TYPED_VALUE *) target; /* Don't forget that first element of TUPLE is the BOOLEAN * `object_comparison' attribute. */ for (; count > 0; count--, l_source++, l_target++) { if (eif_is_reference_tuple_item(l_source) && eif_is_reference_tuple_item(l_target)) { s_field = eif_reference_tuple_item (l_source); t_field = eif_reference_tuple_item (l_target); if ((s_field == NULL) && (t_field == NULL)) { continue; } else if ((s_field) && (t_field) && (Dtype(s_field) == Dtype(t_field))) { continue; } else { return EIF_FALSE; } } } return EIF_TRUE; } else if ((s_flags & EO_REF) && !(s_flags & EO_COMP)) { /* Case 2: specials filled with references: we have to check fields * one by one. */ for( s_ref = (EIF_REFERENCE)source, t_ref = (EIF_REFERENCE) target; count > 0; count --, s_ref = (EIF_REFERENCE) ((EIF_REFERENCE *) s_ref + 1), t_ref = (EIF_REFERENCE) ((EIF_REFERENCE *) t_ref + 1) ) { /* Evaluation of two references */ s_field = *(EIF_REFERENCE *) s_ref; t_field = *(EIF_REFERENCE *) t_ref; if ((!s_field) && (!t_field)) /* Two void references */ continue; else if ( (((EIF_REFERENCE) 0) != s_field) && (((EIF_REFERENCE) 0) != t_field) && (Dtype(s_field) == Dtype(t_field)) ) /* Two non-void references on objects of same dynamic type */ continue; else /* No ismorphism */ return EIF_FALSE; } return EIF_TRUE; } /* Case 3: special objects filled with (non-special) expanded objects. * we call then standard isomorphism test on normal objects. */ for ( s_ref = source +OVERHEAD, t_ref = target+OVERHEAD; count >0; count--, s_ref += elem_size, t_ref += elem_size ) { /* Iteration on expanded elements */ if (!eiso(t_ref, s_ref)) return EIF_FALSE; } return EIF_TRUE; } rt_public EIF_BOOLEAN ediso(EIF_REFERENCE target, EIF_REFERENCE source) { /* Compare recursively the structure attached to `target' to the * one attached to `source'. This is the standard Eiffel feature * because it called recursively the standard isomorhic Eiffel * feature. * Return a boolean. */ RT_GET_CONTEXT EIF_BOOLEAN result; #ifdef ISE_GC char g_status; /* Save GC status */ g_status = eif_gc_ison(); if (g_status) eif_gc_stop(); /* Stop GC if enabled*/ #endif eif_equality_table = s_create(100); /* Create search table */ result = rdeepiso(target,source); /* Recursive isomorphism test */ #ifdef ISE_GC if (g_status) eif_gc_run(); /* Enabled GC it was previously enabled */ #endif eif_rt_xfree((EIF_REFERENCE) (eif_equality_table->s_keys)); /* Free search table keys */ eif_rt_xfree((EIF_REFERENCE) eif_equality_table); /* Free search table descriptor */ eif_equality_table = NULL; return result; }
rt_private EIF_BOOLEAN rdeepiso(EIF_REFERENCE target,EIF_REFERENCE source) { /* Recursive isomorphism test. * Return a boolean. */ RT_GET_CONTEXT union overhead *zone = HEADER(target); /* Target header */ uint32 flags; /* Target flags */ EIF_REFERENCE s_ref, t_ref, t_field, s_field; EIF_INTEGER count, elem_size; flags = zone->ov_flags; /* Check if the object has already been inspected */ if (s_put(eif_equality_table, target) == EIF_SEARCH_CONFLICT) return EIF_TRUE; /* Isomorphism test between `source' and `target'. * Two cases: either a normal object or a special object. */ if (flags & EO_SPEC) { /* Special or tuple objects */ if (!spiso(target, source)) return EIF_FALSE; if (!(flags & EO_REF)) /* No reference to inspect */ return EIF_TRUE; /* Evaluation of the count of the target special object */ count = RT_SPECIAL_COUNT(target); if (flags & EO_TUPLE) { EIF_TYPED_VALUE * l_source = (EIF_TYPED_VALUE *) source; EIF_TYPED_VALUE * l_target = (EIF_TYPED_VALUE *) target; /* Don't forget that first element of TUPLE is the BOOLEAN * `object_comparison' attribute. */ for (; count > 0; count--, l_source++, l_target++) { if (eif_is_reference_tuple_item(l_source) && eif_is_reference_tuple_item(l_target)) { s_field = eif_reference_tuple_item (l_source); t_field = eif_reference_tuple_item (l_target); if ((s_field == NULL) && (t_field == NULL)) { continue; } else if ((s_field) && (t_field)) { if (!rdeepiso(t_field, s_field)) { return EIF_FALSE; } } else { return EIF_FALSE; } } } return EIF_TRUE; } else if (!(flags & EO_COMP)) { CHECK("Special of reference", flags & EO_REF); /* Specials filled with references: we have to iterate on fields * two by two. */ /* Evaluation of the count of the target special object */ for( s_ref = (EIF_REFERENCE)source, t_ref = (EIF_REFERENCE) target; count > 0; count --, s_ref = (EIF_REFERENCE) ((EIF_REFERENCE *) s_ref + 1), t_ref = (EIF_REFERENCE) ((EIF_REFERENCE *) t_ref + 1) ) { /* Evaluation of two references */ s_field = *(EIF_REFERENCE *) s_ref; t_field = *(EIF_REFERENCE *) t_ref; if ((((EIF_REFERENCE) 0) == s_field) && (((EIF_REFERENCE) 0) == t_field)) /* Two void references */ continue; else if ((EIF_REFERENCE) 0 != s_field && (EIF_REFERENCE) 0 != t_field) { /* Recursion on references of the special object */ if (!rdeepiso(t_field, s_field)) return EIF_FALSE; } else return EIF_FALSE; } return EIF_TRUE; } else { CHECK("Special of expanded with references", flags & EO_REF); /* Special objects filled with (non-special) expanded objects. * we call then standard isomorphism test on normal objects. */ elem_size = RT_SPECIAL_ELEM_SIZE(target); for ( s_ref = source+OVERHEAD, t_ref = target+OVERHEAD; count > 0; count--, s_ref += elem_size, t_ref += elem_size ) { /* Iteration on expanded elements which cannot be special * objects */ if (!(rdeepiter(t_ref, s_ref))) return EIF_FALSE; } return EIF_TRUE; } } else { /* Normal object */ if (!eiso(target, source)) return EIF_FALSE; /* Iteration on references */ return rdeepiter(target, source); } /* NOTREACHED */ return EIF_FALSE; }
rt_private void rdeepclone (EIF_REFERENCE source, EIF_REFERENCE enclosing, rt_uint_ptr offset) /* Source object to be cloned */ /* Object receiving clone */ /* Offset within enclosing where attachment is made */ { /* Recursive deep clone of `source' is attached to `receiver'. Then * enclosing parameter gives us a pointer to where the address of the * currently built object lies, or in other words, it's the object on * which we are currently recurring. That way, we are able to perform aging * tests when the attachment to the receiving reference is done. */ RT_GET_CONTEXT EIF_REFERENCE clone, c_field; uint16 flags; EIF_INTEGER count, elem_size; REQUIRE("source not null", source); REQUIRE("enclosing not null", enclosing); flags = HEADER(source)->ov_flags; if (!(flags & EO_STORE)) { /* Object has already been cloned */ /* Object is no longer marked: it has already been duplicated and * thus the resulting duplication is in the hash table. */ clone = *hash_search(&hclone, source); *(EIF_REFERENCE *) (enclosing + offset) = clone; CHECK ("Not forwarded", !(HEADER (enclosing)->ov_size & B_FWD)); RTAR(enclosing, clone); return; } /* The object has not already been duplicated */ flags &= ~EO_STORE; /* Unmark the object */ HEADER(source)->ov_flags = flags; /* Resynchronize object flags */ clone = duplicate(source, enclosing, offset); /* Duplicate object */ /* The object has now been duplicated and entered in the H table */ if (flags & EO_SPEC) { /* Special object */ if (!(flags & EO_REF)) { /* No references */ return; } count = RT_SPECIAL_COUNT(clone); /* Number of items in special */ /* If object is filled up with references, loop over it and recursively * deep clone them. If the object has expanded objects, then we need * to update their possible intra expanded fields (in case they * themselves have expanded objects) and also to deep clone them. */ if (flags & EO_TUPLE) { EIF_TYPED_VALUE * l_target = (EIF_TYPED_VALUE *) clone; EIF_TYPED_VALUE * l_source = (EIF_TYPED_VALUE *) source; /* Don't forget that first element of TUPLE is the BOOLEAN * `object_comparison' attribute. */ for (offset = 0; count > 0; count--, l_target++, l_source++, offset +=sizeof(EIF_TYPED_VALUE)) { if (eif_is_reference_tuple_item(l_source)) { c_field = eif_reference_tuple_item(l_target); if (c_field) { rdeepclone(c_field, clone, offset); } } } } else if (!(flags & EO_COMP)) { /* Special object filled with references */ for (offset = 0; count > 0; count--, offset += REFSIZ) { c_field = *(EIF_REFERENCE *) (clone + offset); /* Iteration on non void references and Eiffel references */ if (c_field) { rdeepclone(c_field, clone, offset); } } } else { /* Special filled with expanded objects */ elem_size = RT_SPECIAL_ELEM_SIZE(clone); for (offset = OVERHEAD; count > 0; count--, offset += elem_size) expanded_update(source, clone + offset, DEEP); } } else expanded_update(source, clone, DEEP); /* Update intra expanded refs */ }