From 56daebbd49fc4ae9973bd78b639d48146cc7e850 Mon Sep 17 00:00:00 2001 From: Robert Ramey Date: Sun, 20 Sep 2009 02:18:02 +0000 Subject: [PATCH] Merge trunk to release [SVN r56316] --- build/Jamfile.v2 | 3 + doc/acknowledgments.html | 6 +- doc/archive_reference.html | 16 +- doc/contents.html | 472 ++++++++++++++------------- doc/exceptions.html | 10 +- doc/extended_type_info.html | 110 +++++-- doc/rationale.html | 220 ------------- doc/serialization.html | 6 +- doc/special.html | 79 +++-- doc/traits.html | 401 ++++++++++++++++++++--- module.cmake | 6 +- src/archive_exception.cpp | 110 +++++++ src/basic_archive.cpp | 3 +- src/basic_iarchive.cpp | 4 +- src/basic_serializer_map.cpp | 77 +++-- src/extended_type_info.cpp | 33 +- src/extended_type_info_no_rtti.cpp | 16 +- src/extended_type_info_typeid.cpp | 14 +- src/polymorphic_oarchive.cpp | 2 - src/shared_ptr_helper.cpp | 113 +++++++ src/void_cast.cpp | 11 + src/xml_archive_exception.cpp | 56 ++++ test/Jamfile.v2 | 5 +- test/polymorphic_base.cpp | 2 +- test/polymorphic_base.hpp | 5 + test/polymorphic_derived1.cpp | 5 +- test/polymorphic_derived1.hpp | 3 + test/polymorphic_derived2.cpp | 2 +- test/polymorphic_derived2.hpp | 13 +- test/test_binary.cpp | 50 ++- test/test_check.cpp | 142 ++++++++ test/test_class_info_save.cpp | 2 +- test/test_complex.cpp | 2 + test/test_derived.cpp | 11 +- test/test_dll_exported.cpp | 5 +- test/test_exported.cpp | 7 +- test/test_no_rtti.cpp | 22 +- test/test_non_default_ctor.cpp | 2 + test/test_non_intrusive.cpp | 2 + test/test_shared_ptr.cpp | 3 +- test/test_simple_class_ptr.cpp | 2 +- test/test_static_warning.cpp | 22 +- test/test_tracking.cpp | 1 - test/test_utf8_codecvt.cpp | 2 + vc7ide/BoostSerializationLibrary.sln | 100 +++++- vc7ide/Library.vcproj | 39 ++- vc7ide/dll_a.vcproj | 77 +++-- vc7ide/dll_base.vcproj | 25 +- vc7ide/dll_derived2.vcproj | 67 +++- vc7ide/polymorphic_derived2.vcproj | 78 +++-- vc7ide/test_array.vcproj | 3 - vc7ide/test_dll_exported.vcproj | 35 +- vc7ide/test_dll_plugin.vcproj | 6 - vc7ide/test_exported.vcproj | 3 + vc7ide/test_multiple_ptrs.vcproj | 3 +- 55 files changed, 1679 insertions(+), 835 deletions(-) create mode 100644 src/archive_exception.cpp create mode 100644 src/shared_ptr_helper.cpp create mode 100644 src/xml_archive_exception.cpp create mode 100644 test/test_check.cpp diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index bad48047..1630713f 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -75,9 +75,12 @@ SOURCES = text_iarchive text_oarchive void_cast + archive_exception xml_grammar xml_iarchive xml_oarchive + xml_archive_exception + shared_ptr_helper ; WSOURCES = diff --git a/doc/acknowledgments.html b/doc/acknowledgments.html index 83786a8e..e0484881 100644 --- a/doc/acknowledgments.html +++ b/doc/acknowledgments.html @@ -1,4 +1,4 @@ - +

-

-
Release Notes
-
-
Reference
-
-
Archive Concepts -
-
Saving Archive Concept -
Loading Archive Concept -
Archive Models -
Exceptions -
Character Sets +
Reference
+
+
Archive Concepts +
+
Serializable Concept +
+
Primitive Types +
Class Types +
-
Serializable Concept -
-
Primitive Types -
Class Types -
-
Member Function -
Free Function -
-
Class Members -
-
Versioning -
Splitting serialize into save/load +
Pointers +
-
Special Considerations -
-
Object Tracking -
Class Information -
Archive Portability -
-
Numerics -
Traits +
References +
Class Serialization Traits +
-
Archive Class Reference -
-
Implementation -
Usage -
Testing -
Polymorphic Archives +
Serialization Wrappers +
-
Implementation Notes -
+
Special Considerations +
+
Archive Class Reference +
+
+
Implementation Notes +
+
Partial Function Template Ordering +
Character Encoding +
Template Invocation syntax +
Partial Template Specialization +
Specific Compiler/Library Issues +
+
Code Structure +
-
Case Studies -
+
Case Studies +
+
Other Classes +
+
extended_type_info +
-
Other Classes -
diff --git a/doc/exceptions.html b/doc/exceptions.html index 99f9af76..2987b4ae 100644 --- a/doc/exceptions.html +++ b/doc/exceptions.html @@ -36,6 +36,7 @@ http://www.boost.org/LICENSE_1_0.txt)
stream_error
invalid_class_name
unregistered_class +
multiple_code_instantiation
xml_archive_parsing_error
xml_archive_tag_mismatch
xml_archive_tag_name_error @@ -75,9 +76,11 @@ public: // to insert virus via buffer overrun method. unregistered_cast, // base - derived relationship not registered with // void_cast_register - unsupported_class_version // type saved with a version # greater than the + unsupported_class_version, // type saved with a version # greater than the // one used by the program. This indicates that the proggram // needs to be rebuilt. + multiple_code_instantiation // code for implementing serialization for some + // type has been instantiated in more than one module. } exception_code; exception_code code; archive_exception(exception_code c) : code(c) {} @@ -228,6 +231,11 @@ is described in Runtime Casting. This exception is thrown if an attempt is made to convert between two pointers whose relationship has not been registered, +

multiple_code_instantiation

+This exception is thrown when it is detected that the serialization of the same type +has been instantiated more that once. This might occur when +serialization code is instantiated in both the mainline and one or more DLLS. +

xml_archive_parsing_error

The XML generated by the serialization process is intimately coupled to the C++ class structure, relationships between objects and the serialization diff --git a/doc/extended_type_info.html b/doc/extended_type_info.html index 94e587b6..c5743068 100644 --- a/doc/extended_type_info.html +++ b/doc/extended_type_info.html @@ -105,14 +105,15 @@ protected: // this class can't be used as is. It's just the // common functionality for all type_info replacement // systems. Hence, make these protected - const char * m_key; - extended_type_info(const unsigned int type_info_key); + extended_type_info( + const unsigned int type_info_key, + const char * key + ); ~extended_type_info(); + void key_register(); + void key_unregister(); public: - void key_register(const char *key); - const char * get_key() const { - return m_key; - } + const char * get_key() const; bool operator<(const extended_type_info &rhs) const; bool operator==(const extended_type_info &rhs) const; bool operator!=(const extended_type_info &rhs) const { @@ -139,30 +140,43 @@ the instances contain.


-extended_type_info(unsigned int type_info_key);
+extended_type_info(unsigned int type_info_key, const char *key);
 

This constructor should be called by all derived classes. -The argument should be the particular implementation. For -this default implementation base on typeid(), this is the +The first argument should be the particular implementation. +For this default implementation base on typeid(), this is the value 1. Each system must have its own integer. This value is used to permit the inter-operability of different typeinfo systems. +

+The second argument is a const string which is the external +name of the type to which this record corresponds. +It may sometimes be referred to as a GUID - a Global Unique IDentifier. +It is passed through archives from one program invocation to +another to uniquely identify the types that the archive contains. +If the "export" facility is not going to be used, +this value may be NULL.


-void key_register(const char *key);
+void key_register();
+void key_unregister();
 

-Assign a unique character string identifier to this -extended_type_info -instance and add it to the corresponding global trable. -This key is used to identify a type accross different instances of the program. -In this way, one instance may know what type to create when necessary. -For this purpose, it must be the same in all program instances which -refer to the same type. +This system maintains a global table which relates +external strings to +extended_type_info records. +This table is used when loading pointers to objects serialized +through a base class pointer. In this case, the archive +contains a string which is looked up in this table to +determine which extended_type_info +to use for creating a new object.

-It may sometimes be referred to as a GUID - a Global Unique IDentifier. +These functions are called by constructors and +destructors of classes which implement +extended_type_info +to add and remove entries from this table.


@@ -185,7 +199,8 @@ These functions are used to compare 'wo
 extended_type_info
  
 
-objects. They a strict total ordering on all instances of this class.
+objects. They impose a strict total ordering on all
+extended_type_info records.
 


@@ -243,20 +258,6 @@ and also implement the following:
 
 
-

-template<class ETI>
-static extended_type_info &
-ETI::get_mutable_instance();
-static const extended_type_info &
-ETI::get_const:instance();
-

-
-Return a pointer to the instance of -extended_type_info -which corresponds to type T. Normally these instances are static objects so -this just amounts to returning the address of this static object. -
-

 template<class ETI>
 const extended_type_info *
@@ -274,12 +275,47 @@ with a particular extended_type_info im
 

-bool ETI::less_than(const extended_type_info &rhs) const;
+virtual bool ETI::is_less_than(const extended_type_info &rhs) const;
 

Compare this instance to another one using the same extended_type_info implementation.
+ +

+virtual bool ETI::is_equal(const extended_type_info &rhs) const;
+

+
+Compare this instance to another one using the same +extended_type_info implementation. +Return true if the types referred +to are the same. Otherwise return +false +
+ +

+const char ETI::get_key() const;
+

+
+Retrieve the external key (aka GUID) for this class. +
+ +

+virtual void * construct(unsigned int count, ...) const;
+

+
+Construct an instance of the corresponding type +with the include argument list. +
+ +

+virtual void * destroy(void const * const ptr ) ) const;
+

+
+Destroy an instance of this type. This calls the +proper destructor and recovers allocated memory. +
+

Models

@@ -294,7 +330,8 @@ by the compiler.

extended_type_info_no_rtti

is implemented in a way that doesn't rely on the existence RTTI. -However, if the export facility is to be used to serialize types +Instead, it requires that all polymorphic types be explictly exported. +In addition, if the export facility is to be used to serialize types through base class pointers, those types are required to implement a virtual function with the signature: @@ -304,7 +341,8 @@ virtual const char * get_key(); which returns a unique string the most derived object this class. This function must be virtual in order to implement the functionality required by ETI::get_derived_extended_type_info -as described above. +as described above. +

Example

The test program test_no_rtti implements this function in terms of the diff --git a/doc/rationale.html b/doc/rationale.html index c96fa139..b7882c24 100644 --- a/doc/rationale.html +++ b/doc/rationale.html @@ -110,226 +110,6 @@ and/or export facilities described in t In effect, export generates a portable equivalent to typeid information. -

Compile time trap when saving a non-const value

-

-The following code will fail to compile. The failure will occur on a line with a -BOOST_STATIC_ASSERT. -Here, we refer to this as a compile time trap. -
-T t;
-ar << t;
-
- -unless the tracking_level serialization trait is set to "track_never". The following -will compile without problem: - -
-const T t
-ar << t;
-
- -Likewise, the following code will trap at compile time: - -
-T * t;
-ar >> t;
-
- -if the tracking_level serialization trait is set to "track_never". -

- -This behavior has been contraversial and may be revised in the future. The criticism -is that it will flag code that is in fact correct and force users to insert -const_cast. My view is that: -

    -
  • The trap is useful in detecting a certain class of programming errors. -
  • Such errors would otherwise be difficult to detect. -
  • The incovenience caused by including this trap is very small in relation - to its benefits. -
- -The following case illustrates my position. It was originally used as an example in the -mailing list by Peter Dimov. - -
-class construct_from 
-{ 
-    ... 
-}; 
-
-void main(){ 
-    ... 
-    Y y; 
-    construct_from x(y); 
-    ar << x; 
-} 
-
- -Suppose that there is no trap as described above. -
    -
  1. this example compiles and executes fine. No tracking is done because - construct_from has never been serialized through a pointer. Now some time - later, the next programmer(2) comes along and makes an enhancement. He - wants the archive to be sort of a log. - -
    -void main(){ 
    -    ... 
    -    Y y; 
    -    construct_from x(y); 
    -    ar << x; 
    -    ... 
    -    x.f(); // change x in some way 
    -   ... 
    -    ar << x 
    -} 
    -
    -

    - Again no problem. He gets two different of copies in the archive, each one is different. - That is he gets exactly what he expects and is naturally delighted. -

    -

  2. Now sometime later, a third programmer(3) sees construct_from and says - - oh cool, just what I need. He writes a function in a totally disjoint - module. (The project is so big, he doesn't even realize the existence of - the original usage) and writes something like: - -
    -class K { 
    -    shared_ptr <construct_from> z; 
    -    template <class Archive> 
    -    void serialize(Archive & ar, const unsigned version){ 
    -        ar << z; 
    -    } 
    -}; 
    -
    - -

    - He builds and runs the program and tests his new functionality. It works - great and he's delighted. -

    -

  3. Things continue smoothly as before. A month goes by and it's - discovered that when loading the archives made in the last month (reading the - log). Things don't work. The second log entry is always the same as the - first. After a series of very long and increasingly acrimonius email exchanges, -its discovered - that programmer (3) accidently broke programmer(2)'s code .This is because by - serializing via a pointer, the "log" object now being tracked. This is because - the default tracking behavior is "track_selectively". This means that class - instances are tracked only if they are serialized through pointers anywhere in - the program. Now multiple saves from the same address result in only the first one - being written to the archive. Subsequent saves only add the address - even though the - data might have been changed. When it comes time to load the data, all instances of the log record show the same data. - In this way, the behavior of a functioning piece of code is changed due the side - effect of a change in an otherwise disjoint module. - Worse yet, the data has been lost and cannot not be now recovered from the archives. - People are really upset and disappointed with boost (at least the serialization system). -

    -

  4. - After a lot of investigation, it's discovered what the source of the problem - and class construct_from is marked "track_never" by including: -
    -BOOST_CLASS_TRACKING(construct_from, track_never) 
    -
    -
  5. Now everything works again. Or - so it seems. -

    -

  6. shared_ptr<construct_from> -is not going to have a single raw pointer shared amongst the instances. Each loaded -shared_ptr<construct_from> is going to -have its own distinct raw pointer. This will break -shared_ptr and cause a memory leak. Again, -The cause of this problem is very far removed from the point of discovery. It could -well be that the problem is not even discovered until after the archives are loaded. -Now we not only have difficult to find and fix program bug, but we have a bunch of -invalid archives and lost data. -
- -Now consider what happens when the trap is enabled:. - -
    -

    -

  1. Right away, the program traps at -
    -ar << x; 
    -
    -

    -

  2. The programmer curses (another %^&*&* hoop to jump through). If he's in a - hurry (and who isn't) and would prefer not to const_cast - - because it looks bad. So he'll just make the following change an move on. -
    -Y y; 
    -const construct_from x(y); 
    -ar << x; 
    -
    -

    - Things work fine and he moves on. -

    -

  3. Now programer (2) wants to make his change - and again another - annoying const issue; -
    -Y y; 
    -const construct_from x(y); 
    -... 
    -x.f(); // change x in some way ; compile error f() is not const 
    -... 
    -ar << x 
    -
    -

    - He's mildly annoyed now he tries the following: -

      -
    • He considers making f() a const - but presumable that shifts the const - error to somewhere else. And his doesn't want to fiddle with "his" code to - work around a quirk in the serializaition system -

      -

    • He removes the const - from const construct_from above - damn now he - gets the trap. If he looks at the comment code where the - BOOST_STATIC_ASSERT - occurs, he'll do one of two things -
        -

        -

      1. This is just crazy. Its making my life needlessly difficult and flagging - code that is just fine. So I'll fix this with a const_cast - and fire off a complaint to the list and mabe they will fix it. - In this case, the story branches off to the previous scenario. -

        -

      2. Oh, this trap is suggesting that the default serialization isn't really - what I want. Of course in this particular program it doesn't matter. But - then the code in the trap can't really evaluate code in other modules (which - might not even be written yet). OK, I'll add the following to my - construct_from.hpp to solve the problem. -
        -BOOST_CLASS_TRACKING(construct_from, track_never) 
        -
        -
      -
    -

    -

  4. Now programmer (3) comes along and make his change. The behavior of the - original (and distant module) remains unchanged because the - construct_from trait has been set to - "track_never" so he should always get copies and the log should be what we expect. -

    -

  5. But now he gets another trap - trying to save an object of a - class marked "track_never" through a pointer. So he goes back to - construct_from.hpp and comments out the - BOOST_CLASS_TRACKING that - was inserted. Now the second trap is avoided, But damn - the first trap is - popping up again. Eventually, after some code restructuring, the differing - requirements of serializating construct_from - are reconciled. -
-Note that in this second scenario -
    -
  • all errors are trapped at compile time. -
  • no invalid archives are created. -
  • no data is lost. -
  • no runtime errors occur. -
- -It's true that these traps may sometimes flag code that is currently correct and -that this may be annoying to some programmers. However, this example illustrates -my view that these traps are useful and that any such annoyance is small price to -pay to avoid particularly vexing programming errors. -