commit bb596cae89d34308c8398de8cda8bbd91c7d7a50 Author: Eric Friedman Date: Wed May 28 08:05:16 2003 +0000 Migrated from Sandbox CVS. [SVN r18578] diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3e84d7c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,96 @@ +* text=auto !eol svneol=native#text/plain +*.gitattributes text svneol=native#text/plain + +# Scriptish formats +*.bat text svneol=native#text/plain +*.bsh text svneol=native#text/x-beanshell +*.cgi text svneol=native#text/plain +*.cmd text svneol=native#text/plain +*.js text svneol=native#text/javascript +*.php text svneol=native#text/x-php +*.pl text svneol=native#text/x-perl +*.pm text svneol=native#text/x-perl +*.py text svneol=native#text/x-python +*.sh eol=lf svneol=LF#text/x-sh +configure eol=lf svneol=LF#text/x-sh + +# Image formats +*.bmp binary svneol=unset#image/bmp +*.gif binary svneol=unset#image/gif +*.ico binary svneol=unset#image/ico +*.jpeg binary svneol=unset#image/jpeg +*.jpg binary svneol=unset#image/jpeg +*.png binary svneol=unset#image/png +*.tif binary svneol=unset#image/tiff +*.tiff binary svneol=unset#image/tiff +*.svg text svneol=native#image/svg%2Bxml + +# Data formats +*.pdf binary svneol=unset#application/pdf +*.avi binary svneol=unset#video/avi +*.doc binary svneol=unset#application/msword +*.dsp text svneol=crlf#text/plain +*.dsw text svneol=crlf#text/plain +*.eps binary svneol=unset#application/postscript +*.gz binary svneol=unset#application/gzip +*.mov binary svneol=unset#video/quicktime +*.mp3 binary svneol=unset#audio/mpeg +*.ppt binary svneol=unset#application/vnd.ms-powerpoint +*.ps binary svneol=unset#application/postscript +*.psd binary svneol=unset#application/photoshop +*.rdf binary svneol=unset#text/rdf +*.rss text svneol=unset#text/xml +*.rtf binary svneol=unset#text/rtf +*.sln text svneol=native#text/plain +*.swf binary svneol=unset#application/x-shockwave-flash +*.tgz binary svneol=unset#application/gzip +*.vcproj text svneol=native#text/xml +*.vcxproj text svneol=native#text/xml +*.vsprops text svneol=native#text/xml +*.wav binary svneol=unset#audio/wav +*.xls binary svneol=unset#application/vnd.ms-excel +*.zip binary svneol=unset#application/zip + +# Text formats +.htaccess text svneol=native#text/plain +*.bbk text svneol=native#text/xml +*.cmake text svneol=native#text/plain +*.css text svneol=native#text/css +*.dtd text svneol=native#text/xml +*.htm text svneol=native#text/html +*.html text svneol=native#text/html +*.ini text svneol=native#text/plain +*.log text svneol=native#text/plain +*.mak text svneol=native#text/plain +*.qbk text svneol=native#text/plain +*.rst text svneol=native#text/plain +*.sql text svneol=native#text/x-sql +*.txt text svneol=native#text/plain +*.xhtml text svneol=native#text/xhtml%2Bxml +*.xml text svneol=native#text/xml +*.xsd text svneol=native#text/xml +*.xsl text svneol=native#text/xml +*.xslt text svneol=native#text/xml +*.xul text svneol=native#text/xul +*.yml text svneol=native#text/plain +boost-no-inspect text svneol=native#text/plain +CHANGES text svneol=native#text/plain +COPYING text svneol=native#text/plain +INSTALL text svneol=native#text/plain +Jamfile text svneol=native#text/plain +Jamroot text svneol=native#text/plain +Jamfile.v2 text svneol=native#text/plain +Jamrules text svneol=native#text/plain +Makefile* text svneol=native#text/plain +README text svneol=native#text/plain +TODO text svneol=native#text/plain + +# Code formats +*.c text svneol=native#text/plain +*.cpp text svneol=native#text/plain +*.h text svneol=native#text/plain +*.hpp text svneol=native#text/plain +*.ipp text svneol=native#text/plain +*.tpp text svneol=native#text/plain +*.jam text svneol=native#text/plain +*.java text svneol=native#text/plain diff --git a/doc/credits.html b/doc/credits.html new file mode 100644 index 0000000..75d7eb9 --- /dev/null +++ b/doc/credits.html @@ -0,0 +1,81 @@ + + + + + + + +Boost::variant + + + + + + + + + +
+

+ C++ Boost +

+
+

boost::variant

+

Credits

+
+
+

+ +
+

Acknowledgments

+

Eric Friedman and Itay Maman designed and implemented the initial submission.

+

Andrei Alexandrescu's work in [Ale01A] and [Ale02] inspired the + library's design.

+

Anthony Williams suggested the method [Wil02] by + which variant generally guarantees strong exception-safety.

+

Douglas Gregor, Dave Abrahams, Fernando Cacciola, Brad King, Giovanni Bajo, + and others provided helpful feedback and suggestions to refine the semantics, + interface, and implementation of the library.

+
+

Bibliography

+

[Ale01A] Andrei Alexandrescu. "An Implementation of Discriminated Unions in C++." OOPSLA 2001, Second Workshop on C++ Template Programming. Tampa Bay, 14 October 2001.

+

[Ale01B] Andrei Alexandrescu. + Modern C++ Design. + Addison-Wesley, C++ In-Depth series. 2001.

+

[Ale02] Andrei Alexandrescu. "Generic<Programming>: + Discriminated Unions" Part 1, + Part 2, + Part 3. C/C++ Users + Journal. 2002.

+

[Boo02] Various Boost members. "Proposal + --- A type-safe union." Boost public discussion. 2002.

+

[Fri02] Eric Friedman. "Variant + (aka Discriminated Union)." Early implementation. 2002.

+

[Gre02] Doug Gregor. "BOOST_USER: + variant." Boost Wiki paper. 2002.

+

[Hen01] Kevlin Henney. + The Boost Any Library. + 2001.

+

[Sut00] Herb Sutter. + Exceptional C++: 47 + Engineering Puzzles, Programming Problems, and Solutions. + Addison-Wesley, C++ In-Depth series. 2000.

+

[Wil02] Anthony Williams. + + Double-Storage Proposal. 2002.

+
+

Revised 13 February 2003

+

© Copyright Eric Friedman and Itay Maman 2002-2003. All rights reserved.

+

Permission to use, copy, modify, distribute and sell this software and its + documentation for any purpose is hereby granted without fee, provided that the + above copyright notice appear in all copies and that both that copyright notice + and this permission notice appear in supporting documentation. Eric Friedman + and Itay Maman make no representations about the suitability of this software + for any purpose. It is provided "as is" without express or implied warranty.

+ + + + diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..42892a4 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,117 @@ + + + + + + + + Boost::variant + + + + + + + +
+

C++ Boost + +

+
+

boost::variant

+

Index

+
+
+

Contents

+ +
+

Revised 14 February 2003

+

© Copyright Eric Friedman and Itay Maman 2002-2003. All rights reserved.

+

Permission to use, copy, modify, distribute and sell this software and its + documentation for any purpose is hereby granted without fee, provided that the + above copyright notice appear in all copies and that both that copyright notice + and this permission notice appear in supporting documentation. Eric Friedman + and Itay Maman make no representations about the suitability of this software + for any purpose. It is provided "as is" without express or implied + warranty.

+ + diff --git a/doc/misc.html b/doc/misc.html new file mode 100644 index 0000000..261d3cb --- /dev/null +++ b/doc/misc.html @@ -0,0 +1,102 @@ + + + + + + + + Boost::variant + + + + + + + + + +
+

+ + C++ Boost +

+
+

boost::variant

+

Miscellaneous

+
+
+ +
+

Header files

+ +
+

Compatibility

+

To date the code and test harness have been compiled and tested successfully +using Microsoft Visual C++ 7.0 and GNU C++ 2.95/3.1.

+The GNU C++ implementation of extract offers an +implicit type conversion operator, which is not supported by the MSVC7 implementation.
+
+
+

Troubleshooting

+ +
+ +

Revised 10 February 2003

+ +

© Copyright Eric Friedman and Itay Maman 2002-2003. All rights +reserved.

+

Permission to use, copy, modify, distribute and sell this software + and its documentation for any purpose is hereby granted without fee, + provided that the above copyright notice appear in all copies and that + both that copyright notice and this permission notice appear in + supporting documentation. Eric Friedman and Itay Maman make no + representations about the suitability of this software for any purpose. + It is provided "as is" without express or implied warranty.

\ No newline at end of file diff --git a/doc/overview.html b/doc/overview.html new file mode 100644 index 0000000..08fb64f --- /dev/null +++ b/doc/overview.html @@ -0,0 +1,118 @@ + + + + + + + Boost::variant + + + + + + + +
+

+ C++ Boost + +

+
+

boost::variant

+

+ Overview

+
+
+

+

+
+

Introduction

+

The variant template class offers a simple, type-safe solution for + manipulating an object from an inhomogeneous set of  types in a uniform + manner. Whereas standard containers such as std::vector may be + thought of as "multi-value, single type," variant is "multi-type, + single value." This reduces code duplication and enhances + maintainability.

+

Specific features of boost::variant include:

+ +
+

Motivation

+

Many times, during the development of a C++ program, the programmer finds + himself in need of manipulating several distinct types in a uniform manner. + Indeed, C++ features direct language support for such types through + its union keyword: +

+
+
union { int i; double d; } u;
+u.d = 3.14;
+u.i = 3; // overwrites u.d (OK: u.d is a POD type)
+
+

C++'s union construct, however, is nearly useless in an + object-oriented environment. The construct entered the language primarily as a + means for preserving compatibility with C, which supports only POD types, and + so does not accept types exhibiting non-trivial construction or destruction:

+
+
union {
+  int i;
+  std::string s; // illegal: std::string is not a POD type!
+};
+
+

Clearly another approach is required. Typical solutions feature the + dynamic-allocation of objects, which are subsequently manipulated through a + common base type (often a virtual base class [Hen01] or, + more dangerously, a void*). Objects of concrete type may be then + retrieved by way of a polymorphic downcast construct (e.g., dynamic_cast).

+

However, solutions of this sort are highly error-prone, due to the following:

+ +

Furthermore, even when properly implemented, these solutions incur a relatively + significant abstraction penalty due to the use of the free store, virtual + function calls, and polymorphic downcasts.

+

The variant template class (inspired by Andrei Alexandrescu's class + of the same name described in [Ale02]) is + an efficient, recursive-capable, bounded discriminated union value type capable + of containing both POD and non-POD value types. It supports direct + initialization from any type convertible to one of its bounded types or from a + source variant whose bounded types are each convertible to one of + the destination variant's bounded types. As well, variant + supports both compile-time checked, type-safe visitation + and explicit, run-time checked, type-safe value + extraction.

+
+

Revised 13 February 2003

+

© Copyright Eric Friedman and Itay Maman 2002-2003. All rights reserved.

+

Permission to use, copy, modify, distribute and sell this software and its + documentation for any purpose is hereby granted without fee, provided that the + above copyright notice appear in all copies and that both that copyright notice + and this permission notice appear in supporting documentation. Eric Friedman + and Itay Maman make no representations about the suitability of this software + for any purpose. It is provided "as is" without express or implied + warranty.

diff --git a/doc/reference.html b/doc/reference.html new file mode 100644 index 0000000..a8c0960 --- /dev/null +++ b/doc/reference.html @@ -0,0 +1,478 @@ + + + + + + + + Boost::variant + + + + + + + +
+

C++ Boost + +

+
+

boost::variant

+

Reference

+
+
+

+ +
+

Header "boost/variant.hpp"

+

Synopsis

+

Dependencies and library features defined in + "boost/variant.hpp": +

+
#include <typeinfo>
+
+#define BOOST_VARIANT_LIMIT_TYPES implementation-defined
+
+namespace boost
+{
+    template
+    <
+        typename T1,
+        typename T2,
+        ...
+        typename Tn = implementation-defined
+    >
+    class variant;
+    
+    template <typename T1, typename T2, ... , typename Tn>
+    void swap(
+          variant<T1, T2, ... , Tn> &
+        , variant<T1, T2, ... , Tn> &
+        );
+}
+
+

Test harnesses provided in "libs/variant/test" directory.

+

+
+

BoundedType Concept

+

Given variant<T1, T2, ... , Tn>, + each type Ti is a bounded type of the variant.

+

The requirements on bounded types are as follows:

+ +

A variant's first bounded type has the additional requirement that + it is DefaultConstructible [??].

+
+

Visitor Concept

+

Given variant<T1, T2, ... , Tn>, + a function object which unambiguously accepts any value of +each of the variant's bounded types, is a +Visitor of of the variant. +

Additional requirements on visitors are as follows:

+ +

Examples:

+

The following class is a visitor of a number of variant types + (e.g., explicitly: variant<int, std::string>, or implicitly: + variant<short, std::string>, etc.):

+
class my_visitor
+{
+    typedef int result_type;
+
+    int operator()(int i)
+    {
+        return i * 2;
+    }
+
+    int operator()(std::string& s)
+    {
+        return s.length();
+    }
+};
+

Another example is the following class, which exposes a templated function + operator, allowing it to operate on values of many types. Thus, the following + class is a visitor of any variant whose bounded types each support + streaming output:

+
class printer
+{
+    typedef void result_type;
+
+    template <typename T>
+      void operator()(const T& t)
+    {
+        std::cout << t << '\n';
+    }
+};
+
+

BOOST_VARIANT_LIMIT_TYPES

+
#define BOOST_VARIANT_LIMIT_TYPES implementation-defined
+

Implementation-defined. Equal to the length of the template parameter + list for variant.

+

Note: Conforming implementations of variant must allow at + least ten bounded types. That is, BOOST_VARIANT_LIMIT_TYPES >= 10 + must evaluate true.

+
+

variant

+
template
+<
+    typename T1,
+    typename T2,
+    ...
+    typename Tn = implementation-defined
+>
+class variant
+{
+public: // structors
+
+    variant();
+    variant(const variant &);
+    template <typename OperandType>
+      variant(const OperandType &);
+    ~variant();
+
+public: // modifiers
+
+    variant & swap(variant &);
+    variant & operator=(const variant &);
+    template <typename OperandType>
+      variant & operator=(const OperandType &);
+
+public: // queries
+
+    int which() const;
+    const std::type_info & type() const;
+
+    bool empty() const; // always false (boost::any compatibility)
+
+private: // representation
+    ...
+};
+

An instance of variant contains exactly one instance of one of its + bounded types, which are specified as arguments to variant's + template parameter list. The length of variant's template + parameter list is equal to the implementation defined value + BOOST_VARIANT_LIMIT_TYPES.

+

Each type specified as a bounded type must satisfy the BoundedType + requirements. Note that  variant itself satisfies + BoundedType requirements with default construction. +

+

All members of variant satisfy the strong guarantee of + exception-safety, unless otherwise specified.

+
+
+

Structors

+
variant();
+

Default constructor. Initializes *this with the default value of + the first bounded type (i.e, T1). May fail with any exceptions + arising from the default constructor of T1.
+

+
variant(const variant& other);
+
+

Copy constructor. Copies the content of other into *this. + May fail with any exceptions arising from the copy constructor of other's + contained type.
+

+
template <typename OperandType>
+  variant(const OperandType & operand);
+
+

Templated constructor. Initializes *this according to the following + logic:

+
    +
  1. + If OperandType is not a variant:
      +
    • + If OperandType is one of the bounded types of the variant, + initialize *this with a copy of operand.
    • +
    • + Otherwise, use overload resolution rules to find the best conversion for OperandType, + and initialize *this with a copy of the converted operand. + (However, if the conversion is ambiguous, or if none exists, a compiler error + is generated.)
    • +
    +
  2. +
  3. + Otherwise (i.e: OperandType is a variant): +
      +
    • + If OperandType does not appear on *this's set of + types, then *this is initialized with operand's held + value (as described in item 1, above).
    • +
    • + Otherwise, operand is assigned, as-is, into *this. + Hence, the held value of *this is, by itself, a variant.
    • +
    +
  4. +
+

May fail with any exceptions arising from the copy constructor of OperandType.
+

+
~variant();
+
+

Non-throwing destructor that releases all resources used in management of *this, + including the currently contained value. +

+

Modifiers

+
void swap(variant& other);
+
+

Exchanges contents of *this and other. May fail with + any exceptions arising from the copy constructors of the contained types of *this + or other, or from the swap primitive of the held values, if this->type() + == other.type().
+

+
variant& operator=(const variant& rhs);
+
+

Copy assignment. Assigns rhs's contained value into *this. + The old value contained by *this is properly destroyed.

+

Note: this operator follows the same logic as the copy + constructor.

+
template<class OperandType>
+  variant& operator=(const OperandType &);
+
+

Templated assignment. Assigns rhs into *this. The old + value held by *this is properly destroyed.

+

Note: This operator follows the same logic as the templated + constructor.

+

Queries

+
const std::type_info & type() const;
+
+

Non-throwing query that returns the typeid() of the contained value

+
bool empty() const;
+
+

Always returns false. This non-throwing member function is provided + for boost::any compatibility.

+

Note: a variant object is never empty. (See the + default constructor.)

+
int which() const;
+
+

Non-throwing query that returns the zero-based index of the bounded type of the + contained value.
+

+
+
+

Visitation: apply_visitor

+
// Binary form
+template<typename VisitorType, typename VariantType>
+typename VisitorType::result_type apply_visitor(VisitorType& visitor,
+   VariantType& var_inst);
+
+// Unary form
+template<class VisitorType>
+boost::apply_visitor_t<VisitorType> apply_visitor(VisitorType& visitor);
+
+template <typename VisitorType>
+class apply_visitor_t
+{
+public:
+    typedef typename VisitorType::result_type result_type;
+
+    template <typename VariantType>
+    result_type operator()(VariantType& var_inst);
+
+    ...
+};
+
+

boost::apply_visitor(visitor, var_inst) passes the variant object, + var_inst, to the given visitor (visitor). This is + equivalent to calling visitor's function-call operator, with var_inst's + currently held value.
+ VisitorType must be a visitor of VariantType. + See Functor-based visitation + for an in-depth description of visitors.
+
+ The unary form of apply_visitor() tranforms the given visitor into + a unary function object which accepts a variant object, thus, the following two + lines are equivalent:
+

+
      boost::apply_visitor(visitor, var_inst); // Binary form
+      boost::apply_visitor(visitor)(var_inst); // Unary form
+
+

Consequently, the unary apply_visitor() function, is highly useful + when std::for_each (or a similar STL algorithm) needs to be + applied on a sequence of variant objects, as illustrated in the + Polymorphism: Inheritance Vs. Variants sample.
+

+
+

Visitation: static_visitor

+
template<typename R = void>
+struct static_visitor
+{
+    typedef R result_type;
+};
+
+
+

static_visitor defines the nested type result_type, + which is required from each visitor class. +
+

+
+

Value Extraction: extract

+

+        
class bad_extract : public std::exception
+{
+public:
+
+    virtual const char* what() const throw();
+
+};
+
+template <typename ToType>
+struct extract
+{
+public: // typedefs
+
+    typedef ToType& result_type;
+
+public: // structors
+
+    template <typename VariantType>
+      extract(VariantType &);
+    template <typename VariantType>
+      extract(const VariantType &);
+
+public: // queries
+
+    bool check() const;
+    ToType& operator()() const;
+    operator ToType&() const; //  Not supported on MSVC
+
+};
+
+

+        

boost::extract is a facility for extracting a reference to a value + held by a variant object. The 'extraction' succeeds only if the + type of the held value is identical to the ToType template + parameter. Usage:
+

+
    +
  1. + extract<RR>(var_inst)(); Initializes a temporary extractobject + and converts it to RR&. If the given variant + object, var_inst does not hold a value of type RR, a + bad_extract exception is thrown. +
  2. +
  3. + extract<RR> ex(var_inst); Initalizes an extract object, ex. + Subsequently, client code can issue an ex.check() call, to + determine whether var_inst is holding a value of type RR. +
  4. +
+

Constructors

+
    template<VariantType>
+    extract(const VariantType& from);
+
+    template<VariantType>
+    extract(VariantType& from);
+
+

Sets up an extract object which is associated with the given variant + object (from).
+

+

Queries

+
    bool check() const;   
+
+

check() is a non throwing member function which return true, + if, and only if, the associated variant object is holding a value + of type ToType.

+
    result_type operator()() const; 
+    operator result_type() const; //  Not supported on MSVC
+
+

If check() is true - operator() returns a + reference to the value held by the associated variant object. + Otherwise - a bad_extract exception is thrown.
+ operator result_type() supplies an implicit conversion to ToType&. + It is semantically identical to operator(). Note that the MSVC7 implementation does not support + this operator.
+

+
+

incomplete

+

incomplete<T> is a template class, which allows a variant + type to be instantiated with incomplete types.
+ By specifying incomplete<T> as one of the actual template + parameters, the instantiated variant will be able to handle values of type T, + although T is incomplete at the instantiation point.
+ incomplete<> is typically used for solving circular + dependencies, but, more importantly, it also enables the creation of recursive, + variant-based, constructs.
+ The snip below demonstrates the usage of Incomplete<>. A + complete sample program is available here. +

+
   using boost::variant;
+   using boost::incomplete;
+
+   struct non_leaf_node; // Forward declaration
+
+   // Define a tree_node variant with these two types:
+   //   (1) int, (2) non_leaf node
+   typedef variant
+   <
+      int,
+      incomplete<non_leaf_node>  // non_leaf_node is incomplete at
+                                 // this point so it must be wrapperd
+                                 // by incomplete<>
+   > tree_node;
+
+   struct non_leaf_node
+   {
+      non_leaf_node(const non_leaf_node& other)
+         :   left_(other.left_), right_(other.right_), num_(other.num_)
+      { }
+
+      int num_;
+      tree_node left_;
+      tree_node right_;
+   };
+
+
+
+

Revised 14 February 2003

+

© Copyright Eric Friedman and Itay Maman 2002-2003. All rights reserved.

+

Permission to use, copy, modify, distribute and sell this software and its + documentation for any purpose is hereby granted without fee, provided that the + above copyright notice appear in all copies and that both that copyright notice + and this permission notice appear in supporting documentation. Eric Friedman + and Itay Maman make no representations about the suitability of this software + for any purpose. It is provided "as is" without express or implied + warranty.

+ + diff --git a/doc/sample.html b/doc/sample.html new file mode 100644 index 0000000..b1c4457 --- /dev/null +++ b/doc/sample.html @@ -0,0 +1,335 @@ + + + + + + + + +Boost::variant + + + + + + + + + +
+

+ C++ Boost +

+
+

boost::variant

+

Sample programs

+
+
+

+ +
+

A quick example

+

This program computes the total sum of numerical values of various types.

+

The code defines a variant object, v1, which can + hold a value of this set of types: short, int, float, and + double.

+

double_sum is a visitor class: Its function-call operator, + double_sum::operator(), accepts a single value, and adds it to the + total_ data member. The program uses the construct: "boost::apply_visitor(visitor, + variant);" to invoke the visitor object, (ds) on the + specified variant (v1).

+

Naturally, ds.total_ holds the total of all previously "visited" + values, and - therefore - at the bottom of main(), its value is: 5 + + 16 + 3.11 + 15.3 = 39.41.

+
#include <iostream>
+
+#include "boost/variant.hpp"
+#include "boost/apply_visitor.hpp"
+#include "boost/static_visitor.hpp"
+
+struct double_sum : boost::static_visitor<double>
+{
+   double_sum() : total_(0.0) { }
+
+   template<class X>
+   double operator()(X x)
+   {
+      total_ += x;
+      return total_;
+   }
+
+   double total_;
+};
+
+int main(int, char* [] )
+{
+   double_sum ds;
+   boost::variant<short, int, float, double> v1;
+
+   v1 = short(5);
+   boost::apply_visitor(ds, v1);  // Apply ds to v1 (1st time)
+
+   v1 = 16;
+   boost::apply_visitor(ds, v1);  // 2nd time
+
+   v1 = 3.11f;
+   boost::apply_visitor(ds, v1);  // 3rd
+
+   v1 = 15.3;
+   double total = boost::apply_visitor(ds, v1);  // 4th
+
+   // Expected output: "Total = 39.41"
+   std::cout << "Total = " << total << std::endl;
+
+   return 0;
+}
+
+
+

A binary tree implementation

+

This sample program shows how incomplete<T> can be used to + define recursive variants.
+ The code creates a small binary tree and then performs an in-order walk thru + its nodes, producing this output: 3 4 6 10 19 20 23
+

+
#include <iostream>
+
+#include "boost/variant.hpp"
+#include "boost/apply_visitor.hpp"
+#include "boost/static_visitor.hpp"
+#include "boost/incomplete.hpp"
+
+
+using boost::variant;
+using boost::incomplete;
+using std::cout;
+using std::endl;
+
+
+struct non_leaf_node; // Forward declaration
+
+// Define a variant with these two types:
+//   1) int
+//   2) The (incomplete) non_leaf_node struct
+typedef variant<int, incomplete<non_leaf_node> > tree_node;
+
+struct non_leaf_node
+{
+   non_leaf_node(const tree_node& l, int num, const tree_node& r)
+      :  left_(l), right_(r), num_(num) { }
+   non_leaf_node(const non_leaf_node& other)
+      :  left_(other.left_), right_(other.right_), num_(other.num_)  { }
+
+   int num_;
+   tree_node left_;
+   tree_node right_;
+};
+
+
+struct tree_printer : boost::static_visitor<void>
+{
+   void operator()(int n) const
+   {
+      cout << n << ' ';
+   }
+
+   void operator()(const non_leaf_node& node) const
+   {
+      boost::apply_visitor(*this, node.left_);
+      cout << node.num_ << ' ';
+      boost::apply_visitor(*this, node.right_);
+   }
+};
+
+
+int main(int, char* [] )
+{
+   //Build a binary search tree:
+   non_leaf_node a(3,4, 6);
+   non_leaf_node b(19, 20, 23);
+   non_leaf_node c(a,10, b);
+
+   tree_node root(c);
+
+   //Perform an in-order walk
+   boost::apply_visitor(tree_printer(), root);
+
+   return 0;
+}
+
+
+

Polymorphism: Inheritance vs. Variants

+

Let's assume we need to write a program that manipulates instances of + star and space_ship, where each of these two classes + inherits from space_object. The program maintains a vector + of pointers to these objects, which is used to calculate the total weight of + all star objects:

+
   //
+   //  'classic' inheritance-based implementation
+   //
+   #include <vector>
+   #include <algorithm>
+   #include <iostream>
+
+   struct space_object
+   {
+      virtual int weight() const = 0;
+      virtual ~space_object() { }
+   };
+
+   struct space_ship : space_object
+   {
+      space_ship(int w = 0) : w_(w) { }
+      int weight() const { return w_; }
+      int get_speed() const { return 15; }
+
+      int w_;
+   };
+
+   struct star : space_object
+   {
+      star(int w = 0) : w_(w) { }
+      int weight() const { return w_; }
+
+      int w_;
+   };
+
+   struct total_weight
+   {
+      total_weight() : total_(0) { }
+
+      void operator()(space_object* so_p)
+      {
+         if(dynamic_cast<star*>(so_p))
+            total_ += so_p->weight();
+      }
+
+      int total_;
+   };
+
+   int main(int, char* [] )
+   {
+      typedef std::vector<space_object*> main_vec;
+      main_vec space_objects;
+
+      //fill space_objects
+      // ...
+
+      total_weight tw_job;
+      int total = std::for_each(space_objects.begin(), space_objects.end(),
+         tw_job).total_;
+
+      std::cout << "Total weight of all stars = " << total
+         << std::endl;
+
+      //Apply delete to all pointers stored in space_objects
+      // ...
+
+      return 0;
+   }
+
+
+

The are several issues worth noticing about this sample:
+

+ +

This real-life design problem can be elegantly solved using variants. Here is + the variant-based code:

+
   //
+   //  Variant-based implementation
+   //
+   #include <vector>
+   #include <algorithm>
+   #include <iostream>
+
+   #include "boost/variant.hpp"
+   #include "boost/apply_visitor.hpp"
+   #include "boost/static_visitor.hpp"
+
+   struct space_ship
+   {
+      space_ship(int w = 0) : w_(w) { }
+      int weight() const { return w_; }
+      int get_speed() const { return 15; }
+
+      int w_;
+   };
+
+   struct star
+   {
+      star(int w = 0) : w_(w) { }
+      int weight() const { return w_; }
+
+      int w_;
+   };
+
+   struct total_weight : boost::static_visitor<void>
+   {
+      total_weight() : total_(0) { }
+
+      void operator()(const star& a_star)
+      {
+         total_ += a_star.weight();
+      }
+
+      //space_ship objects are ignored:
+      void operator()(const space_ship& ) { }
+
+      int total_;
+   };
+
+   int main(int, char* [] )
+   {
+      typedef boost::variant<star, space_ship> space_var;
+      typedef std::vector<space_var> main_vec;
+      main_vec space_objects;
+
+      //fill space_objects
+      // ...
+
+      total_weight tw_job;
+      std::for_each(space_objects.begin(), space_objects.end(),
+         boost::apply_visitor(tw_job));
+
+      std::cout << "Total weight of all stars = " << tw_job.total_
+         << std::endl;
+
+      return 0;
+   }
+
+
+

This implementation directly addresses the three issues raised by the + non-variant implementation: (1) The space_objects vector now holds + objects (rather than pointers), (2) dynamic_cast<>s are + not needed at all, and - most importantly - (3) the compiler will + produce an error if total_weight is not changed, when a new + class is introduced.

+
+

Revised 14 February 2003

+

© Copyright Eric Friedman and Itay Maman 2002-2003. All rights reserved.

+

Permission to use, copy, modify, distribute and sell this software and its + documentation for any purpose is hereby granted without fee, provided that the + above copyright notice appear in all copies and that both that copyright notice + and this permission notice appear in supporting documentation. Eric Friedman + and Itay Maman make no representations about the suitability of this software + for any purpose. It is provided "as is" without express or implied warranty.

+ + + + diff --git a/doc/styles.css b/doc/styles.css new file mode 100644 index 0000000..fffd8b1 --- /dev/null +++ b/doc/styles.css @@ -0,0 +1,4 @@ +PRE +{ + BACKGROUND-COLOR: lightcyan +} diff --git a/doc/tutorial.html b/doc/tutorial.html new file mode 100644 index 0000000..66f689e --- /dev/null +++ b/doc/tutorial.html @@ -0,0 +1,499 @@ + + + + + + + + +Boost::variant + + + + + + + + + +
+

+ C++ Boost +

+
+

boost::variant

+

Tutorial

+
+
+

+ +
+

The following sample program illustrates a typical usage of variant. + Additional sample programs may be found here.
+

+

First variant program

+

Let's suppose you need to implement an object factory function, create. + Based on an integer argument to the function, create must + construct and return an object of one of the following types: std::string, + char*, and int. The relationship between the integer + argument, i, and the returned type is specified as follows:
+

+
    2000 < i          ->  char*
+    1000 < i <= 2000  ->  std::string
+      else            ->  int
+
+

Typical implementations would probably designate of a virtual base class, + returning objects of the derived types through a pointer to the base class. + However, since none of the desired types may derive from the base class, the + programmer would need to write "adapter" classes derived from the common base + to supply the semantics of the various concrete types (i.e, std::string, + int, and char*). Clients of the factory function + would then check the result using dynamic_cast to determine which + concrete type had in fact been created.

+

Other implementations might leverage the Boost + any class, thus avoiding the hassle + of defining and implementing the virtual base class and the derived adapter + classes. However, this solution still does not avoid the problem of needing to + manually check the result using any_cast.

+

On the other hand, by returning an object of type variant< std::string, + char*, int > from the factory function, the resultant code is clear and + straight-forward:

+
#include <iostream>
+#include <string>
+#include "boost/variant.hpp"
+#include "boost/apply_visitor.hpp"
+
+using std::string;
+using boost::variant;
+
+typedef variant<string, char*, int> create_result;
+
+//
+// create, our factory function
+//
+create_result create(int i)
+{
+   // Return char* if (i > 2000):
+   if (which > 2000) return "JKLM";
+
+   // Return std::string if (1000 < i <= 2000):
+   if (which > 1000) return string("QRST");
+
+   // Otherwise, return int:
+   return 15;
+}
+
+//
+// printer, a visitor that prints to std::cout
+//
+struct printer : boost::static_visitor<>
+{
+   template <typename T>
+   void operator()(const T& t)
+   {
+      std::cout << "operand: " << t << std::endl;
+   }
+};
+
+
+int main(int , char* [] )
+{
+   printer print;
+   create_result result;
+
+   // First, create a char*...
+   result = create(2500);
+
+   // ...and print result by applying print visitor to it:
+   boost::apply_visitor(a_printer, inst); // Output: "operand: JKLM"
+
+   // Now, create a std::string and print it:
+   result = create(1500);
+   boost::apply_visitor(a_printer, inst); // Output: "operand: QRST"
+
+   // Finally, create an int and print it:
+   result = create(5);
+   boost::apply_visitor(a_printer, inst);  // Output: "15"
+
+   return 0;
+}
+
+
+

Instantiation

+

A concrete variant instantiation has this general form:

+
typedef boost::variant<T1, T2, ... TN> variant_type;
+
+

Where the types T1, T2, ... TN must model the + BoundedType concept. An instance of + variant_type is capable of holding a value of any of these types.

+

Examples:

+
   boost::variant<int, char, double> v1; // OK
+
+   variant<int, char, double, char> v2;  // Error: char appears twice
+   variant<float> v3;                    // Error: At least two types must be specified
+   variant<char, char* const, void*> v4; // Error: top-level const types are illegal
+
+   variant<char, const char*, void*> v5; // OK - const char* is not a top-level const type
+
+

If one of these types is incomplete at the instantiation point, it must be + enclosed inside an incomplete<> wrapper, as shown below:
+

+
   struct jas1; // Forward declaration of jas1 (Just Another Struct)
+
+   variant<jas1, double, std::string> v6; // Error: jas1 is incomplete
+   struct jas1 { ... };
+
+   struct jas2; // Forward declaration of jas2
+   variant<incomplete<jas2>, double, std::string> v7; // OK -
+                                                      // incomplete<> is used for incomplete types
+   struct jas2 { ... };
+
+
+

Value semantics

+

Once a variant object has been created its value may be changed + by variant's assingment operator. The right-hand side value of the + assignment is converted to the closet possible type of the assigned variant's + set of types, by using overload + resolution rules. Naturally, If there is an exact match, no convesion is + applied, and the right-hand side value is copied as-is. On the other hand, if + no conversion exists, or, if the conversion is ambiguous, a compiler error is + triggered.

+

The assignment rules (mentioned above) also apply when a variant object is + initalized. Hence, the rest of this section will refer to assignment and + initialization interchangeably.

+
   variant<int, char, double> v1;
+   v1 = 5.9; // double -> double (no conversion is needed)
+   v1 = 3;   // int -> int                - " -
+   v1 = 'x'; // char -> char              - " -
+
+   v1 = short(5);           // short -> int
+   v1 = 5.9f;               // float -> double
+   v1 = static_cast<unsigned char>('x'); // unsigned char -> int
+
+
+   v1 = string("abc");    // Error! no implicit conversion from
+                          //   string to int/char/double
+
+   v1 = static_cast<long double>(4.0); // Error! (ambiguity):
+                          //      long double -> double conversion
+                          //      clashes with long double -> int conversion
+
+
+   variant<std::string, double, int> v2; // Default construction.
+                                         // Use default value of first type,
+                                         //    i.e: v2 = std::string()
+
+
+   struct class1
+   {
+      class1(const char* s = 0) { .. }
+      ..
+   };
+
+   struct class2
+   {
+      class2(const char* s) { .. }
+      ..
+   };
+
+   variant<class1, double> v3;
+   v3 = 5;               // int -> double
+   v3 = class1("abc");   // class1 -> class1
+   v3 = "abc";           // const char* -> class1
+
+   variant<class1, class2> v4;
+   v4 = class1("text1"); // class1 -> class1 
+   v4 = class2("text2"); // class2 -> class2      
+   v4 = "text3";         // Error! (ambiguity):
+                         //     class1 clashes with class2
+
+

Copy assignment: When a variant object is assigned to another variant object + - which is of the same concrete type - the assignee becomes an exact duplicate + of the assigned variant:

+
   variant<int, char, double> v1, v2;
+   v1 = 5.9; // v1 = double(5.9)
+   v2 = v1;  // v2 = double(5.9)
+
+   v1 = 3;   // v1 = int(3)
+   v2 = v1;  // v2 = int(3)
+
+   v1 = short(5); // short -> int, hence: v1 = int(5) 
+   v2 = v1;       // v2 = int(5)
+
+   v1 = 5.7f;     // float -> double, hence: v1 = double(5.7)
+   v2 = v1;       // v2 = double(5.7)
+
+

Variant-to-variant assignment: Consider this case:

+
   typedef variant<RR, SS, TT, .. > rhs_type;
+   rhs_type src;
+
+   typedef variant<XX, YY, ZZ, .. > lhs_type;
+   lhs_type trg;
+
+   trg = src; // Variant to variant assignment:
+              // trg and src are two variants of different types
+
+
+

What will trg's value be, following such an assignment?
+

+ +
    typedef variant<int, std::string> variant_type;
+    variant_type a;
+
+    variant<int, double, std::string> b;
+    variant<variant_type, int, double, std::string> c;
+
+    a = "hello";  // char* converted to std::string
+
+    b = a;        // b <- value of a, so b holds an std::string (Case 1)
+
+    c = a;        // c <- a, so c holds a variant_type object holding
+                  // an std::string (Case 2)
+
+

Note that a variant-to-variant assignment will fail - at compile time - if + one of src's bounded types cannot be assigned to trg + (due to ambiguity/lack of conversion).
+ For instance:

+
    variant<int, std::string> a;
+    variant<int, const char*> b;
+
+    a = b; // OK: int->int or const char* -> std::string
+
+    b = a; // Error!
+           // std::string is not implicitly convertible to either int
+           // or const char*, so the compiler will break on this line
+
+
+

Functor-based visitation

+

The visitation facility, implemented via + apply_visitor(), is the primary mechanism thru which client + code can gain access to a variant-held value.
+
+ Let us consider the following piece of code.

+
   boost::variant<XX, YY, ZZ, ... > a_variant;
+
+   struct visitor_type { ... };
+   visitor_type visitor;
+
+   boost::apply_visitor(visitor, a_variant)
+
+

In this sample, visitor_type must be a + Visitor of a_variant. These + requirements may be informally defined as: visitor_type must be a + unary function object that is capable of accepting a value of any of + a_variant's BoundedTypes. If + visitor_type fails to meet these requirements, (i.e: it cannot + accept one, or more, of the types in a_variant's set of types) a + compiler error is triggered.

+

The 'visit' begins when apply_visitor() is called: + apply_visitor(visitor, a_variant) passes a_variant's + currently held value to visitor. From visitor's + standpoint, its function-call operator is called with whatever value + a_variant is holding. This gives visitor a chacne to + inspect/modify a_variant's value.

+

The following snip demonstrates the visitation facility using a concrete + visitor class, print_int_char_visitor. The code will print "Char + value: 'x'" and "Int value: 77" to std::cout:

+
   struct print_int_float_visitor
+   {
+      //result_type specifies the return type of operator()
+      typedef void result_type;
+
+      // Handle int values
+      void operator()(int x) const
+      {
+         std::cout << "Int value: " << x << std::endl;
+      }
+
+      // Handle char values
+      void operator()(float x) const
+      {
+         std::cout << "Float value: " << x << std::endl;
+      }
+   };
+   .
+   .
+   variant<int, float> var = 53.22f;
+
+   //Apply print_int_char_visitor to var.
+   apply_visitor(print_int_float_visitor(), var); // Output: "Float value: 53.22"
+
+   var = 77;
+   apply_visitor(print_int_float_visitor(), var); // Output: "Int value: 77"
+
+

Note how print_int_char_visitor specifies the type of its return + value thru a nested type - result_type. This return value is also + the value that is returned by boost::apply_visitor() to its + caller.

+

The next code snip, demonstrate how boost::static_visitor<T> can + be used as a base class to supply result_type's definition. The + visitor in this snip, multiply_by_two multiplies its operand by + two and returns the result as an int value.

+
   struct multiply_by_two
+       :    boost::static_visitor<int> // Return type is int,
+                                        // so derive from static_visitor<int>
+   {
+      template<typename T>
+      int operator()(T t) const
+      {
+         return int(2 * t);
+      }
+   };
+   .
+   .
+   variant<int, short, char> a = 9;
+   int result = apply_visitor(multiply_by_two(), a);
+   std::cout << "Result = " << result << std::endl; //Output: "Result = 18"
+
+

If a visitor offers several overloads of operator(), overload + resolution rules are applied to choose the correct form. If a visitor cannot + accept one of the types a variant may hold (due to ambiguity/lack of + conversion), a comiler error is generated.
+

+
   struct print_int_char : boost::static_visitor<void>
+   {
+      // Handler *A*
+      void operator()(int f) const
+      {
+         std::cout << "Int value: " << f << std::endl;
+      }
+
+      // Handler *B*
+      void operator()(char c) const
+      {
+         std::cout << "Char value: '" << c << '\''
+            << std::endl;
+      }
+   };
+   .
+   .
+   variant<short, char> a = static_cast<short>(88);
+   apply_visitor(print_int_char(), a);   // Output: "Int value: 88.0"
+                                         //   (int value intercepted by handler *A*)
+
+   a = 'x';                              // a = 'x'
+   apply_visitor(print_int_char(), a);   // Output: "Char value: 'x'"
+
+   variant<int, char, void*> b = 88;     // b = int(88)
+   apply_visitor(print_int_char(), b);   // Error! -
+                                         //    void* cannot be handled by neither
+                                         //    handler (*A* or *B*)
+
+

"Catch-all" behavior can be achieved by supplying a templated form of + operator():

+
   struct ignore_non_ints_visitor : boost::static_visitor<void>
+   {
+      void operator()(int t) const
+      {
+         std::cout << "Current value: " << t << std::endl;
+      }
+
+      template<typename T>
+      void operator()(const T& t) const
+      {
+         // Catch all other types:
+         std::cout << "Ignore me" << std::endl;
+      }
+   };
+   .
+   .
+   variant<int, double, std::string> a = "abcde";
+   apply_visitor(ignore_non_ints_visitor(), a); //Output: "Ignore me"
+
+   a = 22.24;
+   apply_visitor(ignore_non_ints_visitor(), a); //Output: "Ignore me"
+
+   a = 8;
+   apply_visitor(ignore_non_ints_visitor(), a); //Output: "Current value: 8"
+
+

A visitor may accept its operand using a "pass-by-reference" parameter + passing scheme. This allows a visitor to mutate the variant-held value:

+
   struct first_capital : boost::static_visitor<void>
+   {
+       void operator()(std::string& str) const
+       {
+           str[0] = toupper(str[0]);
+       }
+
+       void operator()(char* str) const
+       {
+           *str = toupper(*str);
+       }
+   };
+
+   struct printer : boost::static_visitor<void>
+   {
+       template<typename T>
+       void operator()(const T& t) const
+       {
+           std::cout << t << std::endl;
+       }
+   };
+   .
+   .
+   variant<std::string, char*> a = std::string("abcde");
+   apply_visitor(printer(), a); //Output: "abcde"
+
+   apply_visitor(first_capital(), a); //Invoke the mutating visitor
+                                      //(capitalizes the first letter)
+
+   apply_visitor(printer(), a); //Output: "Abcde"
+
+

The last sample shows persistency of visitors. Every visitor is actually a + function object, so its data members can be used to keep persistent data. The + int_accumulator visitor uses total_ to keep track of + the total sum of its operands:

+
   struct int_accumulator : boost::static_visitor<void>
+   {
+       int_accumulator() : total_(0) { }
+
+       void operator()(int x)
+       {
+           total_ += x;
+       }
+
+       int total_;
+   } ;
+   .
+   .
+   int_accumulator adder;
+   variant<int, short, char> a = 15;
+   apply_visitor(adder, a); //adder.total_ += 15
+
+   a = short(9);
+   apply_visitor(adder, a); //adder.total_ += 9
+
+   std::cout << "Total = " << adder.total_ << std::endl; //Output: "Total = 24"
+
+

Note: When boost::apply_visitor() is used, the compiler + verifies that the specified visitor type is a valid visitor with respect to the + relevant variant type. If the visitor fails to meet the + Visitor requirements, a compiler error is + fired. This allows programming errors to be detected at compile-time rather + than run-time, thus enhancing code safety and stability.

+
+

Revised 14 February 2003

+

© Copyright Eric Friedman and Itay Maman 2002-2003. All rights reserved.

+

Permission to use, copy, modify, distribute and sell this software and its + documentation for any purpose is hereby granted without fee, provided that the + above copyright notice appear in all copies and that both that copyright notice + and this permission notice appear in supporting documentation. Eric Friedman + and Itay Maman make no representations about the suitability of this software + for any purpose. It is provided "as is" without express or implied warranty.

+ + + + diff --git a/include/boost/empty.hpp b/include/boost/empty.hpp new file mode 100644 index 0000000..32113ed --- /dev/null +++ b/include/boost/empty.hpp @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// boost empty.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2003 +// Eric Friedman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_EMPTY_HPP +#define BOOST_EMPTY_HPP + +#include "boost/config.hpp" +#include "boost/mpl/bool.hpp" +#include "boost/type_traits/is_pod.hpp" + +namespace boost { + +struct empty +{ +}; + +template <> +struct is_pod +{ + BOOST_STATIC_CONSTANT(bool, value = true); + typedef mpl::bool_ type; +}; + +} // namespace boost + +#endif // BOOST_EMPTY_HPP diff --git a/include/boost/incomplete.hpp b/include/boost/incomplete.hpp new file mode 100644 index 0000000..26b2434 --- /dev/null +++ b/include/boost/incomplete.hpp @@ -0,0 +1,114 @@ +//----------------------------------------------------------------------------- +// boost incomplete.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2002-2003 +// Eric Friedman, Itay Maman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_INCOMPLETE_HPP +#define BOOST_INCOMPLETE_HPP + +#include "boost/incomplete_fwd.hpp" +#include "boost/checked_delete.hpp" + +namespace boost { + +////////////////////////////////////////////////////////////////////////// +// class template incomplete +// +// Treats an incomplete type as a value type. +// +template +class incomplete +{ +public: // representation + + T* p_; + +public: // structors + + ~incomplete(); + incomplete(); + + incomplete(const incomplete& operand); + incomplete(const T& operand); + +public: // modifiers + + incomplete& operator=(incomplete rhs) + { + swap(rhs); + return *this; + } + + incomplete& operator=(const T& rhs) + { + incomplete temp(rhs); + swap(temp); + + return *this; + } + + void swap(incomplete& operand) + { + T* temp = operand.p_; + operand.p_ = p_; + p_ = temp; + } + +public: // queries + + T& get() { return *get_pointer(); } + const T& get() const { return *get_pointer(); } + + T* get_pointer() { return p_; } + const T* get_pointer() const { return p_; } + +}; + +template +incomplete::~incomplete() +{ + boost::checked_delete(p_); +} + +template +incomplete::incomplete() + : p_(new T) +{ +} + +template +incomplete::incomplete(const incomplete& operand) + : p_(new T( operand.get() )) +{ +} + +template +incomplete::incomplete(const T& operand) + : p_(new T(operand)) +{ +} + +// function template swap +// +// Swaps two incomplete objects of the same type T. +// +template +inline void swap(incomplete& lhs, incomplete& rhs) +{ + lhs.swap(rhs); +} + +} // namespace boost + +#endif // BOOST_INCOMPLETE_HPP diff --git a/include/boost/incomplete_fwd.hpp b/include/boost/incomplete_fwd.hpp new file mode 100644 index 0000000..9c47bb3 --- /dev/null +++ b/include/boost/incomplete_fwd.hpp @@ -0,0 +1,31 @@ +//----------------------------------------------------------------------------- +// boost incomplete_fwd.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2002 +// Eric Friedman, Itay Maman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_INCOMPLETE_FWD_HPP +#define BOOST_INCOMPLETE_FWD_HPP + +namespace boost { + +////////////////////////////////////////////////////////////////////////// +// class template incomplete +// +// Treats an incomplete type as a value type. +// +template class incomplete; + +} // namespace boost + +#endif // BOOST_INCOMPLETE_FWD_HPP diff --git a/include/boost/variant.hpp b/include/boost/variant.hpp new file mode 100644 index 0000000..24ef3f9 --- /dev/null +++ b/include/boost/variant.hpp @@ -0,0 +1,30 @@ +//----------------------------------------------------------------------------- +// boost variant.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2003 +// Eric Friedman, Itay Maman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_VARIANT_HPP +#define BOOST_VARIANT_HPP + +// variant "main" +#include "boost/variant/variant_fwd.hpp" +#include "boost/variant/variant.hpp" + +// common applications +#include "boost/variant/get.hpp" +#include "boost/variant/apply_visitor.hpp" +#include "boost/variant/static_visitor.hpp" +#include "boost/variant/visitor_ptr.hpp" + +#endif // BOOST_VARIANT_HPP diff --git a/include/boost/variant/apply_visitor.hpp b/include/boost/variant/apply_visitor.hpp new file mode 100644 index 0000000..907a1eb --- /dev/null +++ b/include/boost/variant/apply_visitor.hpp @@ -0,0 +1,24 @@ +//----------------------------------------------------------------------------- +// boost apply_visitor.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2003 +// Eric Friedman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_APPLY_VISITOR_HPP +#define BOOST_APPLY_VISITOR_HPP + +#include "boost/variant/detail/apply_visitor_unary.hpp" +#include "boost/variant/detail/apply_visitor_binary.hpp" +#include "boost/variant/detail/apply_visitor_delayed.hpp" + +#endif // BOOST_APPLY_VISITOR_HPP diff --git a/include/boost/variant/bad_visit.hpp b/include/boost/variant/bad_visit.hpp new file mode 100644 index 0000000..4cd6f07 --- /dev/null +++ b/include/boost/variant/bad_visit.hpp @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------------- +// boost visitor/bad_visit.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2002 +// Eric Friedman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_VISITOR_BAD_VISIT_HPP +#define BOOST_VISITOR_BAD_VISIT_HPP + +#include + +namespace boost { + +////////////////////////////////////////////////////////////////////////// +// class bad_visit +// +// Exception thrown when a visitation attempt fails due to invalid +// visited subtype or contents. +// +struct bad_visit + : std::exception +{ +public: + virtual const char * what() const throw() + { + return "boost::bad_visit: " + "failed visitation using boost::apply_visitor"; + } +}; + +} // namespace boost + +#endif // BOOST_VISITOR_BAD_VISIT_HPP diff --git a/include/boost/variant/detail/apply_visitor_binary.hpp b/include/boost/variant/detail/apply_visitor_binary.hpp new file mode 100644 index 0000000..2004e44 --- /dev/null +++ b/include/boost/variant/detail/apply_visitor_binary.hpp @@ -0,0 +1,133 @@ +//----------------------------------------------------------------------------- +// boost variant/detail/apply_visitor_binary.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2002-2003 +// Eric Friedman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_VARIANT_DETAIL_APPLY_VISITOR_BINARY_HPP +#define BOOST_VARIANT_DETAIL_APPLY_VISITOR_BINARY_HPP + +#include "boost/variant/detail/apply_visitor_unary.hpp" +#include "boost/variant/detail/define_forwarding_func.hpp" + +namespace boost { + +////////////////////////////////////////////////////////////////////////// +// function template apply_visitor(visitor, visitable1, visitable2) +// +// Visits visitable1 and visitable2 such that their values (which we +// shall call x and y, respectively) are used as arguments in the +// expression visitor(x, y). +// + +namespace detail { namespace visitor { + +template +class binary_delay0 +{ +public: + typedef typename Visitor::result_type + result_type; + +private: + Visitor& visitor_; + Value1& value1_; + +public: + binary_delay0(Visitor& visitor, Value1& value1) + : visitor_(visitor) + , value1_(value1) + { + } + + template + result_type operator()(Value0& value0) + { + return visitor_(value0, value1_); + } + + template + result_type operator()(const Value0& value0) + { + return visitor_(value0, value1_); + } +}; + +template +class binary_delay1 +{ +public: + typedef typename Visitor::result_type + result_type; + +private: + Visitor& visitor_; + Visitable1& visitable1_; + +public: + binary_delay1(Visitor& visitor, Visitable1& visitable1) + : visitor_(visitor) + , visitable1_(visitable1) + { + } + +# define BOOST_AUX_BINARY_VISITOR_DELAY1_FUNC_OPERATOR(CV__) \ + template \ + result_type operator()(CV__ Visitable2& visitable2) \ + { \ + binary_delay0< \ + Visitor \ + , CV__ Visitable2 \ + > delayer(visitor_, visitable2); \ + return boost::apply_visitor(delayer, visitable1_); \ + } \ + /**/ + + BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC( + BOOST_AUX_BINARY_VISITOR_DELAY1_FUNC_OPERATOR + , 1 + ) + +# undef BOOST_AUX_BINARY_VISITOR_DELAY1_FUNC_OPERATOR +}; + +}} // namespace detail::visitor + +#define BOOST_VARIANT_AUX_APPLY_VISITOR_BINARY(CV1__, CV2__, CV3__) \ + template \ + inline \ + typename Visitor::result_type \ + apply_visitor( \ + CV1__ Visitor& visitor \ + , CV2__ Visitable1& visitable1 \ + , CV3__ Visitable2& visitable2 \ + ) \ + { \ + detail::visitor::binary_delay1< \ + CV1__ Visitor \ + , CV2__ Visitable1 \ + > delayer(visitor, visitable1); \ + return boost::apply_visitor(delayer, visitable2); \ + } \ + /**/ + +BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC( + BOOST_VARIANT_AUX_APPLY_VISITOR_BINARY + , 3 + ) + +#undef BOOST_VARIANT_AUX_APPLY_VISITOR_BINARY + +} // namespace boost + +#endif // BOOST_VARIANT_DETAIL_APPLY_VISITOR_BINARY_HPP diff --git a/include/boost/variant/detail/apply_visitor_delayed.hpp b/include/boost/variant/detail/apply_visitor_delayed.hpp new file mode 100644 index 0000000..f5989e3 --- /dev/null +++ b/include/boost/variant/detail/apply_visitor_delayed.hpp @@ -0,0 +1,110 @@ +//----------------------------------------------------------------------------- +// boost variant/detail/apply_visitor_delayed.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2002-2003 +// Eric Friedman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_VISITOR_APPLY_VISITOR_DELAYED_HPP +#define BOOST_VISITOR_APPLY_VISITOR_DELAYED_HPP + +#include "boost/variant/detail/apply_visitor_unary.hpp" +#include "boost/variant/detail/apply_visitor_binary.hpp" + +#include "boost/variant/detail/define_forwarding_func.hpp" + +namespace boost { + +////////////////////////////////////////////////////////////////////////// +// function template apply_visitor(visitor) +// +// Returns a function object, overloaded for unary and binary usage, that +// visits its arguments using visitor (or a copy of visitor) via +// * apply_visitor( visitor, [argument] ) +// under unary invocation, or +// * apply_visitor( visitor, [argument1], [argument2] ) +// under binary invocation. +// +// NOTE: Unlike other apply_visitor forms, the visitor object must be +// non-const; this prevents user from giving temporary, to disastrous +// effect (i.e., returned function object would have dead reference). +// + +template +class apply_visitor_delayed_t +{ +public: // typedefs + + typedef typename Visitor::result_type + result_type; + +private: // representation + + Visitor& visitor_; + +public: // structors + + explicit apply_visitor_delayed_t(Visitor& visitor) + : visitor_(visitor) + { + } + +public: // unary function operators + +# define BOOST_AUX_APPLY_VISITOR_DELAYED_T_UNARY_FUNC_OPERATOR(CV__) \ + template \ + result_type operator()( \ + CV__ Visitable& visitable \ + ) \ + { \ + apply_visitor(visitor_, visitable); \ + } \ + /**/ + + BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC( + BOOST_AUX_APPLY_VISITOR_DELAYED_T_UNARY_FUNC_OPERATOR + , 1 + ) + +# undef BOOST_AUX_APPLY_VISITOR_DELAYED_T_UNARY_FUNC_OPERATOR + +public: // binary function operators + +# define BOOST_AUX_APPLY_VISITOR_DELAYED_T_BINARY_FUNC_OPERATOR(CV1__, CV2__) \ + template \ + result_type operator()( \ + CV1__ Visitable1& visitable1 \ + , CV2__ Visitable2& visitable2 \ + ) \ + { \ + apply_visitor(visitor_, visitable1, visitable2); \ + } \ + /**/ + + BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC( + BOOST_AUX_APPLY_VISITOR_DELAYED_T_BINARY_FUNC_OPERATOR + , 2 + ) + +# undef BOOST_AUX_APPLY_VISITOR_DELAYED_T_BINARY_FUNC_OPERATOR + +}; + +template +inline apply_visitor_delayed_t apply_visitor(Visitor& visitor) +{ + return apply_visitor_delayed_t(visitor); +} + +} // namespace boost + +#endif // BOOST_VISITOR_APPLY_VISITOR_DELAYED_HPP diff --git a/include/boost/variant/detail/apply_visitor_unary.hpp b/include/boost/variant/detail/apply_visitor_unary.hpp new file mode 100644 index 0000000..89d8f1a --- /dev/null +++ b/include/boost/variant/detail/apply_visitor_unary.hpp @@ -0,0 +1,57 @@ +//----------------------------------------------------------------------------- +// boost variant/detail/apply_visitor_unary.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2002-2003 +// Eric Friedman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_VARIANT_DETAIL_APPLY_VISITOR_UNARY_HPP +#define BOOST_VARIANT_DETAIL_APPLY_VISITOR_UNARY_HPP + +#include "boost/variant/detail/define_forwarding_func.hpp" + +namespace boost { + +////////////////////////////////////////////////////////////////////////// +// function template apply_visitor(visitor, variant) +// +// Visits visitable with visitor. +// + +#define BOOST_VARIANT_AUX_APPLY_VISITOR_FUNC(CV1_, CV2_) \ + template < \ + typename Visitor \ + , BOOST_PP_ENUM_PARAMS(BOOST_VARIANT_LIMIT_TYPES, typename T) \ + > \ + inline \ + typename Visitor::result_type \ + apply_visitor( \ + CV1_ Visitor& visitor \ + , CV2_ boost::variant< \ + BOOST_PP_ENUM_PARAMS(BOOST_VARIANT_LIMIT_TYPES, T) \ + >& var \ + ) \ + { \ + return var.apply_visitor(visitor); \ + } \ + /**/ +# +BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC( + BOOST_VARIANT_AUX_APPLY_VISITOR_FUNC + , 2 + ) +# +#undef BOOST_VARIANT_AUX_APPLY_VISITOR_FUNC + +} // namespace boost + +#endif // BOOST_VARIANT_DETAIL_APPLY_VISITOR_UNARY_HPP diff --git a/include/boost/variant/detail/define_forwarding_func.hpp b/include/boost/variant/detail/define_forwarding_func.hpp new file mode 100644 index 0000000..4179fbd --- /dev/null +++ b/include/boost/variant/detail/define_forwarding_func.hpp @@ -0,0 +1,98 @@ +//----------------------------------------------------------------------------- +// boost variant/detail/define_forwarding_func.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2002-2003 +// Eric Friedman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_VARIANT_DETAIL_DEFINE_FORWARDING_FUNC_HPP +#define BOOST_VARIANT_DETAIL_DEFINE_FORWARDING_FUNC_HPP + +#include "boost/preprocessor/debug/assert.hpp" +#include "boost/preprocessor/comparison/less_equal.hpp" + +////////////////////////////////////////////////////////////////////////// +// BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC + +// 000 +// 001 +// 010 +// 011 'const pattern' follows binary addition... +// 100 (TODO: generalize with preprocessor to N params) +// 101 +// 110 +// 111 + +// support macros +#define BOOST_VARIANT_AUX_NOTHING /**/ + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) + +#define BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC_1(macro) \ + macro(BOOST_VARIANT_AUX_NOTHING) \ + macro(const) \ + /**/ + +#define BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC_2(macro) \ + macro(BOOST_VARIANT_AUX_NOTHING,BOOST_VARIANT_AUX_NOTHING) \ + macro(BOOST_VARIANT_AUX_NOTHING,const) \ + macro(const,BOOST_VARIANT_AUX_NOTHING) \ + macro(const,const) \ + /**/ + +#define BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC_3(macro) \ + macro(BOOST_VARIANT_AUX_NOTHING,BOOST_VARIANT_AUX_NOTHING,BOOST_VARIANT_AUX_NOTHING) \ + macro(BOOST_VARIANT_AUX_NOTHING,BOOST_VARIANT_AUX_NOTHING,const) \ + macro(BOOST_VARIANT_AUX_NOTHING,const,BOOST_VARIANT_AUX_NOTHING) \ + macro(BOOST_VARIANT_AUX_NOTHING,const,const) \ + macro(const,BOOST_VARIANT_AUX_NOTHING,BOOST_VARIANT_AUX_NOTHING) \ + macro(const,BOOST_VARIANT_AUX_NOTHING,const) \ + macro(const,const,BOOST_VARIANT_AUX_NOTHING) \ + macro(const,const,const) \ + /**/ + +#else // defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) + +#define BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC_1(macro) \ + macro(BOOST_VARIANT_AUX_NOTHING) \ + /**/ + +#define BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC_2(macro) \ + macro(BOOST_VARIANT_AUX_NOTHING,BOOST_VARIANT_AUX_NOTHING) \ + /**/ + +#define BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC_3(macro) \ + macro(BOOST_VARIANT_AUX_NOTHING,BOOST_VARIANT_AUX_NOTHING,BOOST_VARIANT_AUX_NOTHING) \ + /**/ + +#endif + +#define BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC_IMPL_MAX 3 +#define BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC_IMPL_MAX_MSG \ + "current implementation of BOOST_DEFINE_FORWARDING_FUNC only supports 3 params" + +// actual macro definition: +#define BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC( macro , arg_count ) \ + BOOST_PP_ASSERT_MSG( \ + BOOST_PP_LESS_EQUAL( \ + arg_count \ + , BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC_IMPL_MAX \ + ) \ + , BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC_IMPL_MAX_MSG \ + ) \ + BOOST_PP_CAT( \ + BOOST_VARIANT_AUX_DEFINE_FORWARDING_FUNC_ \ + , arg_count \ + ) (macro) \ + /**/ + +#endif // BOOST_VARIANT_DETAIL_DEFINE_FORWARDING_FUNC_HPP diff --git a/include/boost/variant/detail/has_nothrow_move.hpp b/include/boost/variant/detail/has_nothrow_move.hpp new file mode 100644 index 0000000..2b01f56 --- /dev/null +++ b/include/boost/variant/detail/has_nothrow_move.hpp @@ -0,0 +1,106 @@ + +// (C) Copyright Eric Friedman 2002-2003. +// Permission to copy, use, modify, sell and distribute this software is +// granted provided this copyright notice appears in all copies. This software +// is provided "as is" without express or implied warranty, and with no claim +// as to its suitability for any purpose. +// +// See http://www.boost.org for most recent version including documentation. + +#ifndef BOOST_VARIANT_DETAIL_HAS_NOTHROW_MOVE_HPP_INCLUDED +#define BOOST_VARIANT_DETAIL_HAS_NOTHROW_MOVE_HPP_INCLUDED + +#include "boost/variant/detail/has_trivial_move.hpp" +#include "boost/type_traits/has_nothrow_copy.hpp" +#include "boost/type_traits/has_nothrow_assign.hpp" + +#include "boost/mpl/and.hpp" +#include "boost/mpl/or.hpp" + +// should be the last #include +#include "boost/type_traits/detail/bool_trait_def.hpp" + +namespace boost { +namespace detail { namespace variant { + +// TRAIT: has_nothrow_move + +template +struct has_nothrow_move_impl +{ + BOOST_STATIC_CONSTANT( + bool, value = ( + mpl::or_< + has_trivial_move + , mpl::and_< + has_nothrow_copy + , has_nothrow_assign + > + >::type::value + ) + ); +}; + +BOOST_TT_AUX_BOOL_TRAIT_DEF1( + has_nothrow_move + , T + , (::boost::detail::variant::has_nothrow_move_impl::value) + ) + + +// TRAIT: has_nothrow_move_constructor + +template +struct has_nothrow_move_constructor_impl +{ + BOOST_STATIC_CONSTANT( + bool, value = ( + mpl::or_< + has_nothrow_move + , has_trivial_move_constructor + , has_nothrow_copy + >::type::value + ) + ); +}; + +BOOST_TT_AUX_BOOL_TRAIT_DEF1( + has_nothrow_move_constructor + , T + , (::boost::detail::variant::has_nothrow_move_constructor_impl::value) + ) + + +// TRAIT: has_nothrow_move_assign + +template +struct has_nothrow_move_assign_impl +{ + BOOST_STATIC_CONSTANT( + bool, value = ( + mpl::or_< + has_nothrow_move + , has_trivial_move_assign + , has_nothrow_assign + >::type::value + ) + ); +}; + +BOOST_TT_AUX_BOOL_TRAIT_DEF1( + has_nothrow_move_assign + , T + , (::boost::detail::variant::has_nothrow_move_assign_impl::value) + ) + +}} // namespace detail::variant + +BOOST_TT_AUX_TEMPLATE_ARITY_SPEC(1,::boost::detail::variant::has_nothrow_move) +BOOST_TT_AUX_TEMPLATE_ARITY_SPEC(1,::boost::detail::variant::has_nothrow_move_constructor) +BOOST_TT_AUX_TEMPLATE_ARITY_SPEC(1,::boost::detail::variant::has_nothrow_move_assign) + +} // namespace boost + +#include "boost/type_traits/detail/bool_trait_undef.hpp" + +#endif // BOOST_VARIANT_DETAIL_HAS_NOTHROW_MOVE_HPP_INCLUDED diff --git a/include/boost/variant/detail/has_trivial_move.hpp b/include/boost/variant/detail/has_trivial_move.hpp new file mode 100644 index 0000000..8733b1d --- /dev/null +++ b/include/boost/variant/detail/has_trivial_move.hpp @@ -0,0 +1,100 @@ + +// (C) Copyright Eric Friedman 2002-2003. +// Permission to copy, use, modify, sell and distribute this software is +// granted provided this copyright notice appears in all copies. This software +// is provided "as is" without express or implied warranty, and with no claim +// as to its suitability for any purpose. +// +// See http://www.boost.org for most recent version including documentation. + +#ifndef BOOST_VARIANT_DETAIL_HAS_TRIVIAL_MOVE_HPP_INCLUDED +#define BOOST_VARIANT_DETAIL_HAS_TRIVIAL_MOVE_HPP_INCLUDED + +#include "boost/type_traits/has_trivial_copy.hpp" +#include "boost/type_traits/has_trivial_assign.hpp" + +#include "boost/mpl/and.hpp" +#include "boost/mpl/or.hpp" + +// should be the last #include +#include "boost/type_traits/detail/bool_trait_def.hpp" + +namespace boost { +namespace detail { namespace variant { + +// TRAIT: has_trivial_move + +template +struct has_trivial_move_impl +{ + BOOST_STATIC_CONSTANT( + bool, value = ( + mpl::and_< + has_trivial_copy + , has_trivial_assign + >::type::value + ) + ); +}; + +BOOST_TT_AUX_BOOL_TRAIT_DEF1( + has_trivial_move + , T + , (::boost::detail::variant::has_trivial_move_impl::value) + ) + + +// TRAIT: has_trivial_move_constructor + +template +struct has_trivial_move_constructor_impl +{ + BOOST_STATIC_CONSTANT( + bool, value = ( + mpl::or_< + has_trivial_move + , has_trivial_copy + >::type::value + ) + ); +}; + +BOOST_TT_AUX_BOOL_TRAIT_DEF1( + has_trivial_move_constructor + , T + , (::boost::detail::variant::has_trivial_move_constructor_impl::value) + ) + + +// TRAIT: has_trivial_move_assign + +template +struct has_trivial_move_assign_impl +{ + BOOST_STATIC_CONSTANT( + bool, value = ( + mpl::or_< + has_trivial_move + , has_trivial_assign + >::type::value + ) + ); +}; + +BOOST_TT_AUX_BOOL_TRAIT_DEF1( + has_trivial_move_assign + , T + , (::boost::detail::variant::has_trivial_move_assign_impl::value) + ) + +}} // namespace detail::variant + +BOOST_TT_AUX_TEMPLATE_ARITY_SPEC(1,::boost::detail::variant::has_trivial_move) +BOOST_TT_AUX_TEMPLATE_ARITY_SPEC(1,::boost::detail::variant::has_trivial_move_constructor) +BOOST_TT_AUX_TEMPLATE_ARITY_SPEC(1,::boost::detail::variant::has_trivial_move_assign) + +} // namespace boost + +#include "boost/type_traits/detail/bool_trait_undef.hpp" + +#endif // BOOST_VARIANT_DETAIL_HAS_TRIVIAL_MOVE_HPP_INCLUDED diff --git a/include/boost/variant/detail/move.hpp b/include/boost/variant/detail/move.hpp new file mode 100644 index 0000000..3c7fd71 --- /dev/null +++ b/include/boost/variant/detail/move.hpp @@ -0,0 +1,169 @@ +//----------------------------------------------------------------------------- +// boost variant/detail/move.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2002-2003 +// Eric Friedman +// +// See below original copyright by Andrei Alexandrescu. +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_VARIANT_DETAIL_MOVE_HPP +#define BOOST_VARIANT_DETAIL_MOVE_HPP + +#include // for iterator_traits +#include // for placement new + +#include "boost/config.hpp" +#include "boost/detail/workaround.hpp" +#include "boost/mpl/if.hpp" +#include "boost/type_traits/is_base_and_derived.hpp" + +namespace boost { +namespace detail { namespace variant { + +////////////////////////////////////////////////////////////////////////// +// forward declares +// +template class moveable; +template class move_source; +template class move_return; + +////////////////////////////////////////////////////////////////////////// +// function template move +// +// Takes a T& and returns, if T derives moveable, a move_source for +// the object; else, returns the T&. +// + +namespace detail { + +// (detail) class template move +// +// Metafunction that, given moveable T, provides move_source, else T&. +// +template +struct move_type +{ +public: // metafunction result + + typedef typename mpl::if_< + is_base_and_derived, T> + , move_source + , T& + >::type type; + +}; + +} // namespace detail + +template +inline + typename detail::move_type::type +move(T& source) +{ + typedef typename detail::move_type::type + move_t; + + return move_t(source); +} + +////////////////////////////////////////////////////////////////////////// +// class template return_t +// +// Metafunction that, given moveable T, provides move_return, else T. +// +template +struct return_t +{ +public: // metafunction result + + typedef typename mpl::if_< + is_base_and_derived, T> + , move_return + , T + >::type type; + +}; + +////////////////////////////////////////////////////////////////////////// +// function template move_swap +// +// Swaps using Koenig lookup but falls back to move-swap for primitive +// types and on non-conforming compilers. +// + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) \ + || BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(2)) + +// [Indicate that move_swap by overload is disabled...] +#define BOOST_NO_MOVE_SWAP_BY_OVERLOAD + +// [...and provide straight swap-by-move implementation:] +template +inline void move_swap(T& lhs, T& rhs) +{ + T tmp( boost::detail::variant::move(lhs) ); + lhs = boost::detail::variant::move(rhs); + rhs = boost::detail::variant::move(tmp); +} + +#else// !workaround + +namespace detail { namespace move_swap { + +template +inline void swap(T& lhs, T& rhs) +{ + T tmp( boost::detail::variant::move(lhs) ); + lhs = boost::detail::variant::move(rhs); + rhs = boost::detail::variant::move(tmp); +} + +}} // namespace detail::move_swap + +template +inline void move_swap(T& lhs, T& rhs) +{ + using detail::move_swap::swap; + + swap(lhs, rhs); +} + +#endif // workaround + +}} // namespace detail::variant +} // namespace boost + +#endif // BOOST_VARIANT_DETAIL_MOVE_HPP + + +/* This file derivative of MoJO. Much thanks to Andrei for his initial work. + * See for information on MOJO. + + * Original copyright -- on mojo.h -- follows: + +//////////////////////////////////////////////////////////////////////////////// +// MOJO: MOving Joint Objects +// Copyright (c) 2002 by Andrei Alexandrescu +// +// Created by Andrei Alexandrescu +// +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the suitability of this software +// for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// + +*/ diff --git a/include/boost/variant/get.hpp b/include/boost/variant/get.hpp new file mode 100644 index 0000000..5fd16fb --- /dev/null +++ b/include/boost/variant/get.hpp @@ -0,0 +1,130 @@ +//----------------------------------------------------------------------------- +// boost variant/get.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2003 +// Eric Friedman, Itay Maman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_VARIANT_GET_HPP +#define BOOST_VARIANT_GET_HPP + +#include + +#include "boost/preprocessor/enum_params.hpp" +#include "boost/utility/addressof.hpp" +#include "boost/variant/variant_fwd.hpp" + +namespace boost { + +////////////////////////////////////////////////////////////////////////// +// class bad_get +// +// The exception thrown in the event of a failed get of a value. +// +class bad_get + : public std::exception +{ +public: // std::exception implementation + + virtual const char * what() const throw() + { + return "boost::bad_get: " + "failed value get using boost::get"; + } + +}; + +////////////////////////////////////////////////////////////////////////// +// function template get +// +// Retrieves content of given variant object if content is of type T. +// Otherwise: pointer ver. returns 0; reference ver. throws bad_get. +// + +namespace detail { namespace variant { + +// (detail) class template get_visitor +// +// Generic static visitor that: if the value is of the specified type, +// returns a pointer to the value it visits; else a null pointer. +// +template +struct get_visitor +{ +public: // typedefs + + typedef T* result_type; + +public: // visitor interfaces + + template + T* operator()(U&) const + { + return static_cast(0); + } + + T* operator()(T& operand) const + { + return boost::addressof(operand); + } + +}; + +}} // namespace detail::variant + +template +inline U* get( + boost::variant< BOOST_PP_ENUM_PARAMS(BOOST_VARIANT_LIMIT_TYPES, T) >* operand + ) +{ + if (!operand) return static_cast(0); + + detail::variant::get_visitor v; + return operand->apply_visitor(v); +} + +template +inline U* get( + const boost::variant< BOOST_PP_ENUM_PARAMS(BOOST_VARIANT_LIMIT_TYPES, T) >* operand + ) +{ + if (!operand) return static_cast(0); + + detail::variant::get_visitor v; + return operand->apply_visitor(v); +} + +template +inline U& get( + boost::variant< BOOST_PP_ENUM_PARAMS(BOOST_VARIANT_LIMIT_TYPES, T) >& operand + ) +{ + U* result = get(&operand); + if (!result) + throw bad_get(); + return *result; +} + +template +inline U& get( + const boost::variant< BOOST_PP_ENUM_PARAMS(BOOST_VARIANT_LIMIT_TYPES, T) >& operand + ) +{ + U* result = get(&operand); + if (!result) + throw bad_get(); + return *result; +} + +} // namespace boost + +#endif // BOOST_VARIANT_GET_HPP diff --git a/include/boost/variant/static_visitor.hpp b/include/boost/variant/static_visitor.hpp new file mode 100644 index 0000000..a29723d --- /dev/null +++ b/include/boost/variant/static_visitor.hpp @@ -0,0 +1,73 @@ +//----------------------------------------------------------------------------- +// boost visitor/static_visitor.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2002-2003 +// Eric Friedman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_STATIC_VISITOR_HPP +#define BOOST_STATIC_VISITOR_HPP + +#include "boost/config.hpp" +#include "boost/type_traits/is_base_and_derived.hpp" + +#include "boost/mpl/aux_/lambda_support.hpp" // used by is_static_visitor + +namespace boost { + +////////////////////////////////////////////////////////////////////////// +// class template static_visitor +// +// An empty base class that typedefs the return type of a deriving static +// visitor. The class is analogous to std::unary_function in this role. +// + +namespace detail { + + struct is_static_visitor_tag { }; + +} // namespace detail + +template +struct static_visitor + : public detail::is_static_visitor_tag +{ + typedef R result_type; + +protected: + ~static_visitor() { } +}; + +////////////////////////////////////////////////////////////////////////// +// metafunction is_static_visitor +// +// Value metafunction indicates whether the specified type is a static +// visitor of any types. +// +// NOTE: This template never needs to be specialized! +// +template +struct is_static_visitor +{ + typedef typename is_base_and_derived< + detail::is_static_visitor_tag + , T + >::type type; + + BOOST_STATIC_CONSTANT(bool, value = type::value); + + BOOST_MPL_AUX_LAMBDA_SUPPORT(1,is_static_visitor,(T)) +}; + +} // namespace boost + +#endif // BOOST_STATIC_VISITOR_HPP diff --git a/include/boost/variant/variant.hpp b/include/boost/variant/variant.hpp new file mode 100644 index 0000000..4c958a1 --- /dev/null +++ b/include/boost/variant/variant.hpp @@ -0,0 +1,1163 @@ +//----------------------------------------------------------------------------- +// boost variant/variant.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2002-2003 +// Eric Friedman, Itay Maman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_VARIANT_VARIANT_HPP +#define BOOST_VARIANT_VARIANT_HPP + +#include // for std::size_t +#include // for placement new +#include // for std::type_info + +#include "boost/variant/variant_fwd.hpp" +#include "boost/config.hpp" +#include "boost/detail/workaround.hpp" +#include "boost/aligned_storage.hpp" +#include "boost/compressed_pair.hpp" +#include "boost/empty.hpp" +#include "boost/incomplete_fwd.hpp" +#include "boost/utility/addressof.hpp" +#include "boost/static_assert.hpp" +#include "boost/preprocessor/cat.hpp" +#include "boost/preprocessor/enum.hpp" +#include "boost/preprocessor/enum_params.hpp" +#include "boost/preprocessor/repeat.hpp" +#include "boost/type_traits/add_const.hpp" +#include "boost/type_traits/alignment_of.hpp" +#include "boost/type_traits/is_const.hpp" +#include "boost/type_traits/is_same.hpp" + +#include "boost/mpl/apply_if.hpp" +#include "boost/mpl/begin_end.hpp" +#include "boost/mpl/bool.hpp" +#include "boost/mpl/contains.hpp" +#include "boost/mpl/count_if.hpp" +#include "boost/mpl/distance.hpp" +#include "boost/mpl/deref.hpp" +#include "boost/mpl/empty.hpp" +#include "boost/mpl/equal_to.hpp" +#include "boost/mpl/identity.hpp" +#include "boost/mpl/if.hpp" +#include "boost/mpl/int.hpp" +#include "boost/mpl/is_sequence.hpp" +#include "boost/mpl/iter_fold.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/logical.hpp" +#include "boost/mpl/max_element.hpp" +#include "boost/mpl/remove_if.hpp" +#include "boost/mpl/sizeof.hpp" +#include "boost/mpl/size_t.hpp" +#include "boost/mpl/transform.hpp" +#include "boost/mpl/void.hpp" + +// The following are new/in-progress headers: +#include "boost/variant/detail/move.hpp" +#include "boost/variant/static_visitor.hpp" +#include "boost/variant/detail/has_nothrow_move.hpp" + +////////////////////////////////////////////////////////////////////////// +// BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT +// +// Defined if variant does not support variant syntax (see below). +// +#if defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) +# define BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT +#endif + +namespace boost { + +namespace detail { namespace variant { + +////////////////////////////////////////////////////////////////////////// +// (detail) metafunction max_value +// +// Finds the maximum value of the unary metafunction F over Sequence. +// +template +struct max_value +{ +private: // helpers, for metafunction result (below) + + typedef typename mpl::max_element< + typename mpl::transform::type + >::type max_it; + +public: // metafunction result + + typedef typename mpl::deref::type + type; + +}; + +////////////////////////////////////////////////////////////////////////// +// (detail) metafunction make_storage +// +// Provides an aligned storage type capable of holding any of the types +// specified in the given type-sequence. +// +template +struct make_storage +{ +private: // helpers, for metafunction result (below) + + BOOST_STATIC_CONSTANT( + std::size_t + , max_size = (max_value< Types, mpl::sizeof_ >::type::value) + ); + BOOST_STATIC_CONSTANT( + std::size_t + , max_alignment = (max_value< Types, alignment_of >::type::value) + ); + +public: // metafunction result + + typedef aligned_storage + type; + +}; + +////////////////////////////////////////////////////////////////////////// +// (detail) class null_storage +// +// Simulates aligned_storage's interface, but with nothing underneath. +// +struct null_storage +{ +public: // queries + + void* address() + { + return 0; + } + + const void* address() const + { + return 0; + } + +}; + +////////////////////////////////////////////////////////////////////////// +// (detail) class destroyer +// +// Generic static visitor that destroys the value it visits. +// +struct destroyer + : public static_visitor<> +{ +public: // visitor interfaces + + template + void operator()(T& operand) const + { + operand.~T(); + } + +}; + +////////////////////////////////////////////////////////////////////////// +// (detail) class copy_into +// +// Generic static visitor that copies the value it visits into the given buffer. +// +class copy_into + : public static_visitor<> +{ +private: // representation + + void* storage_; + +public: // structors + + explicit copy_into(void* storage) + : storage_(storage) + { + } + +public: // visitor interfaces + + template + void operator()(const T& operand) const + { + new(storage_) T(operand); + } + +}; + +////////////////////////////////////////////////////////////////////////// +// (detail) class swap_with +// +// Generic static visitor that swaps the value it visits with the given value. +// +struct swap_with + : public static_visitor<> +{ +private: // representation + + void* toswap_; + +public: // structors + + explicit swap_with(void* toswap) + : toswap_(toswap) + { + } + +public: // visitor interfaces + + template + void operator()(T& operand) const + { + boost::detail::variant::move_swap(operand, *static_cast(toswap_)); + } + +}; + +////////////////////////////////////////////////////////////////////////// +// (detail) class reflect +// +// Generic static visitor that performs a typeid on the value it visits. +// +struct reflect + : public static_visitor +{ +public: // visitor interfaces + + template + const std::type_info& operator()(const T&) + { + return typeid(T); + } + +}; + +////////////////////////////////////////////////////////////////////////// +// (detail) class template invoke_visitor +// +// Generic static visitor that invokes the given visitor using: +// * for raw visits where the given value is a +// boost::incomplete, the given value's held value. +// * for all other visits, the given value itself. +// +template +class invoke_visitor + : public static_visitor< typename Visitor::result_type > +{ +private: // representation + + Visitor& visitor_; + +public: // typedefs + + typedef typename Visitor::result_type + result_type; + +public: // structors + + explicit invoke_visitor(Visitor& visitor) + : visitor_(visitor) + { + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) + +public: // visitor interfaces + + template + result_type operator()(incomplete& operand) + { + return visitor_(operand.get()); + } + + template + result_type operator()(const incomplete& operand) + { + return visitor_(operand.get()); + } + + template + result_type operator()(T& operand) + { + return visitor_(operand); + } + +#else// defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) + +private: // helpers, for visitor interfaces (below) + + template + result_type execute_impl(incomplete& operand, long) + { + return visitor_(operand.get()); + } + + template + result_type execute_impl(const incomplete& operand, long) + { + return visitor_(operand.get()); + } + + template + result_type execute_impl(T& operand, int) + { + return visitor_(operand); + } + +public: // visitor interfaces + + template + result_type operator()(T& operand) + { + return execute_impl(operand, 1L); + } + +#endif // BOOST_NO_FUNCTION_TEMPLATE_ORDERING workaround + +}; + +////////////////////////////////////////////////////////////////////////// +// (detail) metafunction make_variant_list +// +// Provides a MPL-compatible sequence with the specified non-void types +// as arguments. However, if resultant sequence is empty, then resultant +// sequence contains boost::empty. +// +// Rationale #1: see class template convert_void (above) and using- +// declaration workaround (below). +// +// Rationale #2: boost::empty behavior enables variant<> syntax. +// +template < BOOST_PP_ENUM_PARAMS(BOOST_VARIANT_LIMIT_TYPES, typename T) > +struct make_variant_list +{ +private: // helpers, for metafunction result (below) + + // [Define a macro to convert any void(NN) tags to mpl::void...] +# define BOOST_VARIANT_DETAIL_CONVERT_VOID(z, N,_) \ + typename convert_void::type + + // [...so that the specified types can be passed to mpl::list...] + typedef typename mpl::list< + BOOST_PP_ENUM( + BOOST_VARIANT_LIMIT_TYPES + , BOOST_VARIANT_DETAIL_CONVERT_VOID + , _ + ) + >::type initial_result; + + // [...and, finally, the conversion macro can be undefined:] +# undef BOOST_VARIANT_DETAIL_CONVERT_VOID + +public: // metafunction result + + typedef typename mpl::if_< + mpl::empty + , mpl::list1 + , initial_result + >::type type; + +}; + +}} // namespace detail::variant + +////////////////////////////////////////////////////////////////////////// +// class template variant (concept inspired by Andrei Alexandrescu) +// +// See docs and boost/variant/variant_fwd.hpp for more information. +// +template < + BOOST_PP_ENUM_PARAMS(BOOST_VARIANT_LIMIT_TYPES, typename T) + > +class variant +{ +private: // static precondition assertions + +#if defined(BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT) + + // Sequences are not supported for compilers that do not support + // using declarations in templates (see below). + BOOST_STATIC_ASSERT(( + mpl::not_< // !is_sequence + mpl::is_sequence + >::type::value + )); + +#endif // BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT + +public: // typedefs + + typedef typename mpl::apply_if< + mpl::is_sequence + , mpl::identity + , detail::variant::make_variant_list< + BOOST_PP_ENUM_PARAMS(BOOST_VARIANT_LIMIT_TYPES, T) + > + >::type types; + +private: // static precondition assertions, cont. + + // [Assert unique types: ommitted due to compile-time complexity.] + /* + BOOST_STATIC_ASSERT(( + mpl::equal< + types + , typename mpl::unique::type + >::type::value + )); + */ + +#if !BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1300)) + + // [Assert no top-level const-qualified types:] + BOOST_STATIC_ASSERT(( + mpl::equal_to< + typename mpl::count_if< + types + , is_const + >::type + , mpl::size_t<0> + >::type::value + )); + +#endif // avoid on BOOST_MSVC + +private: // representation + + typedef typename detail::variant::make_storage::type + storage1_t; + + typedef typename mpl::remove_if< + types + , detail::variant::has_nothrow_move_constructor + >::type throwing_types; + + // [storage2_t = empty(throwing_types) ? null_storage : make_storage] + typedef typename mpl::apply_if< + mpl::empty + , mpl::identity + , detail::variant::make_storage + >::type storage2_t; + + // which_ on: + // * [0, size) indicates storage1 + // * [-size, 0) indicates storage2 + // if which_ >= 0: + // * then which() -> which_ + // * else which() -> -(which_ + 1) + int which_; + compressed_pair< storage1_t,storage2_t > storage_; + + static bool using_storage1_impl(mpl::true_) + { + // Since there is no storage2, we know storage1 is in use: + return true; + } + + bool using_storage1_impl(mpl::false_) const + { + // Since a true second storage is in use (i.e. NOT null_storage), we must check: + return which_ >= 0; + } + + bool using_storage1() const + { + typedef typename is_same::type + has_single_storage; + + return using_storage1_impl(has_single_storage()); + } + + void activate_storage1(int which) + { + which_ = which; + } + + void activate_storage2(int which) + { + which_ = -(which + 1); + } + + void* active_storage() + { + if (using_storage1() == false) + return storage_.second().address(); + + return storage_.first().address(); + } + + const void* active_storage() const + { + return const_cast(this)->active_storage(); + } + + void* inactive_storage() + { + if (using_storage1() == false) + return storage_.first().address(); + + return storage_.second().address(); + } + +public: // queries + + int which() const + { + // If NOT using storage1... + if (using_storage1() == false) + // ...then return adjusted which_: + return -(which_ + 1); + + // Otherwise, return which_ directly: + return which_; + } + +private: // helpers, for structors (below) + +// [On compilers where using declarations in class templates can correctly avoid name hiding...] +#if !defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) + + // [...use an optimal converting initializer based on the variant typelist:] + + struct initializer_root + { + public: // static functions + + // Root type must expose name "initialize," so + // the following dummy function is provided: + + static void initialize(); + + }; + + struct make_initializer_node + { + template + struct apply + { + private: // helpers, for metafunction result (below) + + struct initializer_node + : Base + { + private: // helpers, for static functions (below) + + typedef typename Iterator::type + T; + + public: // static functions + + using Base::initialize; + + static int initialize(void* dest, const T& operand) + { + new(dest) T(operand); + + BOOST_STATIC_CONSTANT( + std::size_t + , idx = ( + mpl::distance< + typename mpl::begin::type + , Iterator + >::type::value + ) + ); + + return idx; + } + + }; + + public: // metafunction result + + typedef initializer_node + type; + + }; + }; + + typedef typename mpl::iter_fold< + types + , initializer_root + , mpl::protect< make_initializer_node > + >::type initializer; + +#else // defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) + + // [...otherwise, use a hackish workaround based on variant's template parameters:] + + struct preprocessor_list_initializer + { + public: // static functions + + #define BOOST_VARIANT_INITIALIZE_FUNCTION(z,N,_) \ + static int initialize( \ + void* dest \ + , const BOOST_PP_CAT(T,N)& operand \ + ) \ + { \ + typedef BOOST_PP_CAT(T,N) T; \ + BOOST_STATIC_CONSTANT(int, which = (N)); \ + \ + new(dest) T(operand); \ + return which; \ + } \ + /**/ + + BOOST_PP_REPEAT( + BOOST_VARIANT_LIMIT_TYPES + , BOOST_VARIANT_INITIALIZE_FUNCTION + , _ + ) + #undef BOOST_VARIANT_INITIALIZE_FUNCTION + + }; + + typedef preprocessor_list_initializer + initializer; + +#endif // BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE workaround + + void destroy_content() + { + detail::variant::destroyer visitor; + raw_apply_visitor(visitor); + } + +public: // structors + + ~variant() + { + destroy_content(); + } + + variant() + { + // NOTE TO USER : + // Compile error from here indicates that the first bound + // type is default-constructible, and so variant cannot + // support its own default-construction + + new(storage_.first().address()) T0(); + activate_storage1(0); // zero is the index of the first bounded type + } + + variant(const variant& operand) + { + // Copy the value of operand into *this... + detail::variant::copy_into visitor(storage_.first().address()); + operand.raw_apply_visitor(visitor); + + // ...and activate the *this's primary storage on success: + activate_storage1(operand.which()); + } + +private: // helpers, for structors, cont. (below) + + class convert_copy_into + : public static_visitor + { + private: // representation + + void* storage_; + + public: // structors + + explicit convert_copy_into(void* storage) + : storage_(storage) + { + } + + public: // visitor interfaces + + template + int operator()(const T& operand) const + { + // NOTE TO USER : + // Compile error here indicates one of the source variant's types + // cannot be unambiguously converted to the destination variant's + // types (or that no conversion exists). + // + return initializer::initialize(storage_, operand); + } + + }; + +private: // helpers for structors, cont. (below) + + template + void copy_construct( + const T& operand + , mpl::false_ = mpl::false_() // from_foreign_variant + ) + { + // NOTE TO USER : + // Compile error here indicates that the given type is not + // unambiguously convertible to one of the variant's types + // (or that no conversion exists). + // + activate_storage1( + initializer::initialize( + storage_.first().address() + , operand + ) + ); + } + + template + void copy_construct( + const Variant& operand + , mpl::true_// from_foreign_variant + ) + { + convert_copy_into visitor(storage_.first().address()); + activate_storage1( + operand.raw_apply_visitor(visitor) + ); + } + +private: // workaround, for structors, cont. (below) + + // [While unnecessary for conforming compilers, this workaround doesn't break anything:] + + template + void constructor_simulated_partial_ordering( + const boost::variant& operand + , long) + { + // [Determine if operand is a bounded type, or if it needs to be converted (foreign):] + typedef mpl::bool_< + !mpl::contains< + types + , boost::variant + >::type::value + > from_foreign_variant; + + copy_construct( + operand + , from_foreign_variant() + ); + } + + template + void constructor_simulated_partial_ordering(const T& operand, int) + { + copy_construct(operand); + } + +public: // structors, cont. + + template + variant(const T& operand) + { + constructor_simulated_partial_ordering(operand, 1L); + } + +private: // helpers, for modifiers (below) + + // class assign_into + // + // Generic visitor that assigns the value it visits to the variant it is + // given, maintaining the strong guarantee of exception safety. + // + + friend class assign_into; + + class assign_into + : public static_visitor<> + { + private: // representation + + variant& target_; + int source_which_; + + public: // structors + + assign_into(variant& target, int source_which) + : target_(target) + , source_which_(source_which) + { + } + + private: // helpers, for visitor interfaces (below) + + template + void assign_impl( + const T& operand + , mpl::true_// has_nothrow_move_constructor + ) + { + // Attempt to make a temporary copy... + T temp(operand); + + // ...and upon success destroy the target's active storage... + target_.destroy_content(); // nothrow + + // ...move the temporary copy into the target's storage1... + new(target_.storage_.first().address()) // nothrow + T( detail::variant::move(temp) ); + + // ...and activate the target's storage1: + target_.activate_storage1(source_which_); // nothrow + } + + template + void assign_impl( + const T& operand + , mpl::false_// has_nothrow_move_constructor + ) + { + // Attempt a copy into target's inactive storage... + new(target_.inactive_storage()) T(operand); + + // ...and upon success destroy the target's active storage... + target_.destroy_content(); // nothrow + + // ...and if the target _was_ using storage1... + if (target_.using_storage1()) + // ...then activate storage2: + target_.activate_storage2(source_which_); // nothrow + else + // ...otherwise, activate storage1: + target_.activate_storage1(source_which_); // nothrow + } + + public: // visitor interfaces + + template + void operator()(const T& operand) + { + assign_impl( + operand + , mpl::bool_< has_nothrow_move_constructor::value >() + ); + } + + }; + + void assign(const variant& operand) + { + assign_into visitor(*this, operand.which()); + operand.raw_apply_visitor(visitor); + } + +public: // modifiers + + variant& operator=(const variant& rhs) + { + assign(rhs); + return *this; + } + + template + variant& operator=(const T& rhs) + { + // While potentially inefficient, the following (implicit) + // construction of a variant allows T as any type convertible + // to a bounded type (i.e., opposed to an exact match). + + assign(rhs); + return *this; + } + +private: // helpers, for modifiers, cont. (below) + + // class swap_variants + // + // Generic static visitor that swaps given lhs and rhs variants. + // + // NOTE: Must be applied to the rhs variant. + // + + friend class swap_variants; + + class swap_variants + : public static_visitor<> + { + private: // representation + + variant& lhs_; + variant& rhs_; + + public: // structors + + swap_variants(variant& lhs, variant& rhs) + : lhs_(lhs) + , rhs_(rhs) + { + } + + private: // helpers, for visitor interfaces (below) + + template + void swap_impl( + T& rhs_content + , mpl::true_// has_nothrow_move_constructor + ) + { + // Cache rhs's which-index (because it will be overwritten)... + int rhs_old_which = rhs_.which(); + + // ...move rhs_content to the side... + T rhs_old_content( detail::variant::move(rhs_content) ); // nothrow + + try + { + // ...attempt to move-assign lhs to (now-moved) rhs: + rhs_ = detail::variant::move(lhs_); + } + catch(...) + { + // In case of failure, restore rhs's old contents... + new(boost::addressof(rhs_content)) // nothrow + T( detail::variant::move(rhs_old_content) ); + + // ...and rethrow: + throw; + } + + // In case of success, destroy lhs's active storage... + lhs_.destroy_content(); // nothrow + + // ...move rhs's old contents to lhs's storage1... + new(lhs_.storage_.first().address()) // nothrow + T( detail::variant::move(rhs_old_content) ); + + // ...and activate lhs's storage1: + lhs_.activate_storage1(rhs_old_which); // nothrow + } + + template + void swap_impl( + T& rhs_content + , mpl::false_// has_nothrow_move_constructor + ) + { + // Cache rhs's which-index (because it will be overwritten)... + int rhs_old_which = rhs_.which(); + + // ...move rhs's content into lhs's inactive storage... + new(lhs_.inactive_storage()) T(detail::variant::move(rhs_content)); + + try + { + // ...attempt to move-assign lhs to (now-copied) rhs: + rhs_ = detail::variant::move(lhs_); + } + catch(...) + { + // In case of failure, destroy the copied value... + static_cast(lhs_.inactive_storage())->~T(); // nothrow + } + + // In case of success, destroy lhs's active storage... + lhs_.destroy_content(); // nothrow + + // ...and if lhs _was_ using storage1... + if (lhs_.using_storage1()) // nothrow + { + // ...then activate storage2: + lhs_.activate_storage2(rhs_old_which); // nothrow + } + else + { + // ...otherwise, activate storage1: + lhs_.activate_storage1(rhs_old_which); // nothrow + } + } + + public: // visitor interfaces + + template + void operator()(T& rhs_content) + { + swap_impl( + rhs_content + , mpl::bool_< has_nothrow_move_constructor::value >() + ); + } + + }; + +public: // modifiers, cont. + + void swap(variant& rhs) + { + // If the types are the same... + if (which() == rhs.which()) + { + // ...then swap the values directly: + detail::variant::swap_with visitor(active_storage()); + rhs.raw_apply_visitor(visitor); + } + else + { + // Otherwise, perform general variant swap: + swap_variants visitor(*this, rhs); + rhs.raw_apply_visitor(visitor); + } + } + +public: // queries + + // + // NOTE: member which() defined above. + // + + bool empty() const + { + typedef typename mpl::find< + types + , boost::empty + >::type empty_it; + + typedef typename mpl::distance< + typename mpl::begin::type + , empty_it + >::type empty_index; + + return which() == empty_index::value; + } + + const std::type_info& type() const + { + detail::variant::reflect visitor; + return this->apply_visitor(visitor); + } + +private: // helpers, for visitation support (below) + + template + static + typename Visitor::result_type + apply_visitor_impl( + const int var_which // [const-ness may aid in optimization by compiler] + , Variant& var + , Visitor& visitor + , mpl::false_// is_last + ) + { + typedef typename mpl::next::type next_which; + typedef typename mpl::next::type next_iter; + typedef mpl::bool_::value> next_is_last; + typedef typename mpl::apply_if< + is_const + , add_const + , mpl::identity + >::type T; + + if (var_which == Which::value) + { + return visitor( + *static_cast( var.active_storage() ) + ); + } + + return apply_visitor_impl( + var_which + , var + , visitor + , next_is_last() + ); + } + + template + static + typename Visitor::result_type + apply_visitor_impl( + const int + , Variant& + , Visitor& + , mpl::true_// is_last + ) + { + // | This is never called at runtime: a visitor must handle at | + // | least one of the variant's types. Throw to circumvent the | + // | compile-time requirement that a value is returned: | + throw; + } + +// helpers, for visitation support (below) -- private when possible +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + + template < BOOST_PP_ENUM_PARAMS(BOOST_VARIANT_LIMIT_TYPES, typename U) > + friend class variant; + +private: + +#else// defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + +public: + +#endif// !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + + template + typename Visitor::result_type + raw_apply_visitor(Visitor& visitor) + { + return apply_visitor_impl< + mpl::int_<0> + , typename mpl::begin::type + , typename mpl::end::type + >(which(), *this, visitor, mpl::false_()); + } + + template + typename Visitor::result_type + raw_apply_visitor(Visitor& visitor) const + { + return apply_visitor_impl< + mpl::int_<0> + , typename mpl::begin::type + , typename mpl::end::type + >(which(), *this, visitor, mpl::false_()); + } + +public: // visitation support + + template + typename Visitor::result_type + apply_visitor(Visitor& visitor) + { + detail::variant::invoke_visitor invoker(visitor); + return raw_apply_visitor(invoker); + } + + template + typename Visitor::result_type + apply_visitor(Visitor& visitor) const + { + detail::variant::invoke_visitor invoker(visitor); + return raw_apply_visitor(invoker); + } + +}; + +////////////////////////////////////////////////////////////////////////// +// function template swap +// +// Swaps two variants of the same type (i.e., identical specification). +// +template < BOOST_PP_ENUM_PARAMS(BOOST_VARIANT_LIMIT_TYPES, typename T) > +inline void swap( + boost::variant< BOOST_PP_ENUM_PARAMS(BOOST_VARIANT_LIMIT_TYPES, T) >& lhs + , boost::variant< BOOST_PP_ENUM_PARAMS(BOOST_VARIANT_LIMIT_TYPES, T) >& rhs + ) +{ + lhs.swap(rhs); +} + +} // namespace boost + +#endif // BOOST_VARIANT_VARIANT_HPP diff --git a/include/boost/variant/variant_fwd.hpp b/include/boost/variant/variant_fwd.hpp new file mode 100644 index 0000000..1f30ab5 --- /dev/null +++ b/include/boost/variant/variant_fwd.hpp @@ -0,0 +1,143 @@ +//----------------------------------------------------------------------------- +// boost variant/variant_fwd.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2003 +// Eric Friedman, Itay Maman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_VARIANT_VARIANT_FWD_HPP +#define BOOST_VARIANT_VARIANT_FWD_HPP + +#include "boost/config.hpp" +#include "boost/preprocessor/enum_params_with_a_default.hpp" +#include "boost/preprocessor/enum_params_with_defaults.hpp" +#include "boost/mpl/limits/list.hpp" +#include "boost/mpl/void.hpp" + +////////////////////////////////////////////////////////////////////////// +// BOOST_VARIANT_LIMIT_TYPES +// +// Implementation-defined preprocessor symbol describing the actual +// length of variant's pseudo-variadic template parameter list. +// +#define BOOST_VARIANT_LIMIT_TYPES \ + BOOST_MPL_LIMIT_LIST_SIZE + +namespace boost { + +namespace detail { namespace variant { + +////////////////////////////////////////////////////////////////////////// +// (detail) class void_ and class template convert_void +// +// Provides the mechanism by which void(NN) types are converted to +// mpl::void_ (and thus can be passed to mpl::list). +// +// Rationale: This is particularly needed for the using-declarations +// workaround (below), but also to avoid associating mpl namespace with +// variant in argument dependent lookups (which used to happen because of +// defaulting of template parameters to mpl::void_). +// + +struct void_; + +template +struct convert_void +{ + typedef T type; +}; + +template <> +struct convert_void< void_ > +{ + typedef mpl::void_ type; +}; + +////////////////////////////////////////////////////////////////////////// +// (workaround) BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE +// +// Needed to work around compilers that don't support using-declaration +// overloads. (See the variant::initializer workarounds below.) +// + +#if defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) + +// (detail) tags voidNN -- NN defined on [0, BOOST_VARIANT_LIMIT_TYPES) +// +// Defines void types that are each unique and specializations of +// convert_void that yields mpl::void_ for each voidNN type. +// + +#define BOOST_VARIANT_DETAIL_DEFINE_VOID_N(z,N,_) \ + struct BOOST_PP_CAT(void,N); \ + \ + template <> \ + struct convert_void< BOOST_PP_CAT(void,N) > \ + { \ + typedef mpl::void_ type; \ + }; \ + /**/ + +BOOST_PP_REPEAT( + BOOST_VARIANT_LIMIT_TYPES + , BOOST_VARIANT_DETAIL_DEFINE_VOID_N + , _ + ) + +#undef BOOST_VARIANT_DETAIL_DEFINE_VOID_N + +#endif // BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE workaround + +}} // namespace detail::variant + +////////////////////////////////////////////////////////////////////////// +// class template variant (concept inspired by Andrei Alexandrescu) +// +// Efficient, type-safe bounded discriminated union. +// +// Preconditions: +// - Each type must be unique. +// - No type may be const-qualified. +// +// Proper declaration form: +// variant (where types is a type-sequence) +// or +// variant (where T0 is NOT a type-sequence) +// or +// variant<>, which acts like variant +// +template < + +#if !defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) + + BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT( + BOOST_VARIANT_LIMIT_TYPES + , typename T + , detail::variant::void_ + ) + +#else// defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) + + BOOST_PP_ENUM_PARAMS_WITH_DEFAULTS( + BOOST_VARIANT_LIMIT_TYPES + , typename T + , detail::variant::void//NN + ) + +#endif // BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE workaround + + > +class variant; + +} // namespace boost + +#endif // BOOST_VARIANT_VARIANT_FWD_HPP diff --git a/include/boost/variant/visitor_ptr.hpp b/include/boost/variant/visitor_ptr.hpp new file mode 100644 index 0000000..352c4b3 --- /dev/null +++ b/include/boost/variant/visitor_ptr.hpp @@ -0,0 +1,82 @@ +//----------------------------------------------------------------------------- +// boost variant/visitor_ptr.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2002-2003 +// Eric Friedman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_VARIANT_VISITOR_PTR_HPP +#define BOOST_VARIANT_VISITOR_PTR_HPP + +#include "boost/variant/bad_visit.hpp" +#include "boost/variant/static_visitor.hpp" + +#include "boost/type_traits/add_reference.hpp" + +namespace boost { + +////////////////////////////////////////////////////////////////////////// +// function template visitor_ptr +// +// Adapts a function pointer for use as visitor capable of handling +// values of a single type. Throws bad_visit if inappropriately applied. +// +template +class visitor_ptr_t + : public static_visitor +{ +private: // representation + + typedef R (*visitor_t)(T); + + visitor_t visitor_; + +public: // typedefs + + typedef R result_type; + +private: // private typedefs + + typedef typename add_reference::type + argument_fwd_type; + +public: // structors + + explicit visitor_ptr_t(visitor_t visitor) + : visitor_(visitor) + { + } + +public: // static visitor interfaces + + result_type operator()(argument_fwd_type operand) const + { + return visitor_(operand); + } + + template + result_type operator()(const U& operand) const + { + throw bad_visit(); + } + +}; + +template +inline visitor_ptr_t visitor_ptr(R (*visitor)(T)) +{ + return visitor_ptr_t(visitor); +} + +} // namespace boost + +#endif// BOOST_VISITOR_VISITOR_PTR_HPP diff --git a/index.html b/index.html new file mode 100644 index 0000000..7119db6 --- /dev/null +++ b/index.html @@ -0,0 +1,8 @@ + + + + + +Automatic redirection failed, please go to doc/index.html + + \ No newline at end of file diff --git a/test/Jamfile b/test/Jamfile new file mode 100644 index 0000000..39cc7e7 --- /dev/null +++ b/test/Jamfile @@ -0,0 +1,20 @@ +# bring in rules for testing +SEARCH on testing.jam = $(BOOST_BUILD_PATH) ; +include testing.jam ; + +# Make tests run by default. +DEPENDS all : test ; + +{ + test-suite variant + : + [ run test1.cpp class_a.cpp ] + [ run test2.cpp ] + [ run test3.cpp ] + [ run test4.cpp class_a.cpp ] + [ run test5.cpp ] + [ run test6.cpp ] + [ run test7.cpp ] + [ run test8.cpp ] + ; +} diff --git a/test/class_a.cpp b/test/class_a.cpp new file mode 100644 index 0000000..99a7565 --- /dev/null +++ b/test/class_a.cpp @@ -0,0 +1,55 @@ +//File: class_a.cpp + + +#include +#include +#include + +#include "class_a.h" + + +using namespace std; + +class_a::~class_a() +{ + assert(self_p_ == this); +} + +class_a::class_a(int n) +{ + n_ = n; + self_p_ = this; +} + +class_a::class_a(const class_a& other) +{ + n_ = other.n_; + self_p_ = this; +} + + +class_a& class_a::operator=(const class_a& rhs) +{ + class_a temp(rhs); + swap(temp); + + return *this; +} + +void class_a::swap(class_a& other) +{ + std::swap(n_, other.n_); +} + +int class_a::get() const +{ + return n_; +} + + + + +std::ostream& operator<<(std::ostream& strm, const class_a& a) +{ + return strm << "class_a(" << a.get() << ")"; +} diff --git a/test/class_a.h b/test/class_a.h new file mode 100644 index 0000000..8ead512 --- /dev/null +++ b/test/class_a.h @@ -0,0 +1,30 @@ +//File: class_a.h + +#ifndef _CLASSA_H_INC_ +#define _CLASSA_H_INC_ + + +#include + +struct class_a +{ + ~class_a(); + class_a(int n = 5511); + class_a(const class_a& other); + + class_a& operator=(const class_a& rhs); + void swap(class_a& other); + + int get() const; + +private: + int n_; + class_a* self_p_; + +}; //Class_a + +std::ostream& operator<<(std::ostream& strm, const class_a& a); + + + +#endif //_CLASSA_H_INC_ diff --git a/test/jobs.h b/test/jobs.h new file mode 100644 index 0000000..d82617e --- /dev/null +++ b/test/jobs.h @@ -0,0 +1,310 @@ +//File: jobs.h + +#ifndef _JOBSH_INC_ +#define _JOBSH_INC_ + +#include +#include +#include +#include + +#include "boost/variant/get.hpp" +#include "boost/variant/apply_visitor.hpp" +#include "boost/variant/static_visitor.hpp" + +#include "varout.h" + +struct total_sizeof : boost::static_visitor +{ + total_sizeof() : total_(0) { } + + template + int operator()(const Value& value) const + { + total_ += sizeof(value); + return total_; + } + + int result() const + { + return total_; + } + + mutable int total_; + +}; // total_sizeof + + + +//Function object: sum_int +//Description: Compute total sum of a series of numbers, (when called successively) +//Use sizeof(T) if applied with a non-integral type +struct sum_int : boost::static_visitor +{ + + sum_int() : total_(0) { } + + + template + struct int_to_type + { + BOOST_STATIC_CONSTANT(int, value = n); + }; + + //Integral type - add numerical value + template + void add(T t, int_to_type ) const + { + total_ += t; + } + + //Other types - add sizeof + template + void add(T& , int_to_type ) const + { + total_ += sizeof(T); + } + + template + int operator()(const T& t) const + { + //Int_to_type is used to select the correct add() overload + add(t, int_to_type::value>()); + return total_; + } + + int result() const + { + return total_; + } + +private: + mutable int total_; + +}; //sum_int + + + + + + +//Function object: sum_double +//Description: Compute total sum of a series of numbers, (when called successively) +//Accpetable input types: float, double (Other types are silently ignored) +struct sum_double : boost::static_visitor +{ + + sum_double() : total_(0) { } + + void operator()(float value) const + { + total_ += value; + } + + void operator()(double value) const + { + total_ += value; + } + + template + void operator()(const T&) const + { + //Do nothing + } + + double result() const + { + return total_; + } + +private: + mutable double total_; + +}; //sum_double + + + +struct int_printer : boost::static_visitor +{ + + int_printer(std::string prefix_s = "") : prefix_s_(prefix_s) { } + int_printer(const int_printer& other) : prefix_s_(other.prefix_s_) + { + ost_ << other.str(); + } + + std::string operator()(int x) const + { + ost_ << prefix_s_ << x; + return str(); + } + + std::string operator()(const std::vector& x) const + { + ost_ << prefix_s_; + + //Use another Int_printer object for printing a list of all integers + int_printer job(","); + ost_ << std::for_each(x.begin(), x.end(), job).str(); + + return str(); + } + + std::string str() const + { + return ost_.str(); + } + +private: + std::string prefix_s_; + mutable std::ostringstream ost_; +}; //int_printer + + +struct int_adder : boost::static_visitor +{ + + int_adder(int rhs) : rhs_(rhs) { } + + void operator()(int& lhs) const + { + lhs += rhs_; + } + + template + void operator()(const T& ) const + { + //Do nothing + } + + int rhs_; +}; //int_adder + + + + +struct held_type_name : boost::static_visitor +{ + + template + std::string operator()(const T& ) const + { + ost_ << '[' << typeid(T).name() << ']'; + return result(); + } + + std::string result() const + { + return ost_.str(); + } + + mutable std::ostringstream ost_; + +}; //held_type_name + + + + +template +struct spec +{ + typedef T result; +}; + +template +void verify(const VariantType& vari, spec, std::string str = "") +{ + using namespace boost; + + BOOST_CHECK(apply_visitor(total_sizeof(), vari) == sizeof(S)); + BOOST_CHECK(vari.type() == typeid(S)); + + VariantType& mut_vari = const_cast(vari); + // + // Check get<>() + // + BOOST_CHECK(get(&vari)); + BOOST_CHECK(get(&mut_vari)); + + const S* ptr1 = 0; + const S* ptr2 = 0; + int count = 0; + try + { + const S& r = get(vari); + ptr1 = &r; + } + catch(bad_get& ) + { + count += 1; + } + + try + { + S& mut_r = get(mut_vari); + ptr2 = &mut_r; + } + catch(bad_get& ) + { + count += 1; + } + + BOOST_CHECK(count == 0); + BOOST_CHECK(ptr1 != 0 && ptr2 == ptr1); + + // + // Check string content + // + if(str.length() > 0) + { + std::string temp = apply_visitor(to_text(), vari); + std::cout << "temp = " << temp << ", str = " << str << std::endl; + BOOST_CHECK(temp == str); + } +} + + +template +void verify_not(const VariantType& vari, spec) +{ + using namespace boost; + + BOOST_CHECK(vari.type() != typeid(S)); + + // + // Check get<>() + // + BOOST_CHECK(!get(&vari)); + + VariantType& mut_vari = const_cast(vari); + BOOST_CHECK(!get(&mut_vari)); + + const S* ptr1 = 0; + const S* ptr2 = 0; + int count = 0; + try + { + const S& r = get(vari); + ptr1 = &r; + } + catch(bad_get& ) + { + count += 1; + } + + try + { + S& mut_r = get(mut_vari); + ptr2 = &mut_r; + } + catch(bad_get& ) + { + count += 1; + } + + BOOST_CHECK(count == 2); + BOOST_CHECK(ptr1 == 0 && ptr2 == 0); +} + + +#endif //_JOBSH_INC_ diff --git a/test/test1.cpp b/test/test1.cpp new file mode 100644 index 0000000..7035623 --- /dev/null +++ b/test/test1.cpp @@ -0,0 +1,135 @@ +//File: test1.cpp + +#include "boost/test/minimal.hpp" +#include "boost/variant.hpp" + +#include "class_a.h" +#include "jobs.h" +#include "varout.h" + +#include +#include +#include + + + +void run() +{ + + using boost::apply_visitor; + using boost::variant; + using std::string; + using std::vector; + using std::cout; + using std::endl; + + typedef variant< char*, string, short > t_var0; + typedef variant< int, string, double > t_var1; + typedef variant< short, const char* > t_var2; + typedef variant< string, char > t_var3; + typedef variant< unsigned short, const char* > t_var4; + typedef variant< unsigned short, const char*, t_var2 > t_var5; + typedef variant< unsigned short, const char*, t_var5 > t_var6; + typedef variant< class_a, const void* > t_var7; + typedef variant< t_var6, int > t_var8; + typedef variant< t_var8, unsigned short > t_var9; + typedef variant< char, unsigned char > t_var10; + typedef variant< short, int, vector, long> t_var11; + + t_var1 v1; + t_var0 v0; + t_var2 v2; + t_var3 v3; + t_var4 v4; + t_var5 v5; + t_var6 v6; + t_var7 v7; + t_var8 v8; + t_var9 v9; + t_var10 v10; + t_var11 v11; + + + // + // Check assignment rules + // + + v2 = 4; + v4 = v2; + verify(v4, spec()); + + v2 = "abc"; + v4 = v2; + verify(v4, spec(), "[V] abc"); + + v5 = "def"; + verify(v5, spec(), "[V] def"); + + v5 = v2; + verify(v5, spec(), "[V] [V] abc"); + + v6 = 58; + verify(v6, spec(), "[V] 58"); + + v6 = v5; + verify(v6, spec(), "[V] [V] [V] abc"); + + v8 = v2; + verify(v8, spec(), "[V] [V] abc"); + + v8 = v6; + verify(v8, spec(), "[V] [V] [V] [V] abc"); + + v7 = v2; + verify(v7, spec()); + + v7 = 199; + verify(v7, spec(), "[V] class_a(199)"); + + v2 = 200; + v7 = v2; + verify(v7, spec(), "[V] class_a(200)"); + + + + // + // Check sizes of held values + // + total_sizeof ts; + + v1 = 5.9; + apply_visitor(ts, v1); + + v1 = 'B'; + apply_visitor(ts, v1); + + v1 = 3.4f; + apply_visitor(ts, v1); + + BOOST_TEST(ts.result() == sizeof(int) + sizeof(double)*2); + + v11 = 5; + string res_s = apply_visitor(int_printer(), v11); + BOOST_TEST(res_s == "5"); + + // + // A variant object holding an std::vector + // + vector int_vec_1; + int_vec_1.push_back(512); + int_vec_1.push_back(256); + int_vec_1.push_back(128); + int_vec_1.push_back(64); + + v11 = int_vec_1; + res_s = apply_visitor(int_printer(), v11); + BOOST_TEST(res_s == ",512,256,128,64"); +} + + + +int test_main(int , char* []) +{ + run(); + return 0; +} diff --git a/test/test2.cpp b/test/test2.cpp new file mode 100644 index 0000000..20198cb --- /dev/null +++ b/test/test2.cpp @@ -0,0 +1,129 @@ +// File: test2.cpp + +#include "boost/test/minimal.hpp" +#include "boost/variant.hpp" + +#include "jobs.h" +#include "varout.h" + +#include +#include +#include + + +using boost::apply_visitor; + +struct short_string +{ + BOOST_STATIC_CONSTANT(size_t, e_limit = 101); + + short_string() : len_(0) + { + buffer_[0] = '\0'; + } + + short_string(const char* src) + { + size_t src_len = strlen(src); + + len_ = std::min(src_len, e_limit-1); + std::copy(src, src + len_, buffer_); + buffer_[len_] = '\0'; + } + + short_string(const short_string& other) : len_(other.len_) + { + std::copy(other.buffer_, other.buffer_ + e_limit, buffer_); + } + + void swap(short_string& other) + { + char temp[e_limit]; + + std::copy(buffer_, buffer_ + e_limit, temp); + std::copy(other.buffer_, other.buffer_ + e_limit, buffer_); + std::copy(temp, temp + e_limit, other.buffer_); + + std::swap(len_, other.len_); + } + + short_string& operator=(const short_string& rhs) + { + short_string temp(rhs); + swap(temp); + + return *this; + } + + operator const char*() const + { + return buffer_; + } + + +private: + char buffer_[e_limit]; + size_t len_; +}; //short_string + + +std::ostream& operator<<(std::ostream& out, const short_string& s) +{ + out << static_cast(s); + return out; +} + + + +void run() +{ + using boost::variant; + + variant v0; + variant v1; + variant v2; + + // + // Default construction + // + verify(v0, spec()); + verify(v1, spec()); + verify(v2, spec()); + + // + // Implicit conversion to bounded type + // + v1 = "I am v1"; + verify(v1, spec(), "[V] I am v1"); + + v2 = "I am v2"; + verify(v2, spec(), "[V] I am v2"); + + // + // Variant-to-variant assignment + // + + v0 = v1; + verify(v0, spec(), "[V] I am v1"); + + v1 = v0; + verify(v1, spec(), "[V] I am v1"); + + const int n0 = 88; + v1 = n0; + v0 = v1; + + // + // Implicit conversion to bounded type + // + verify(v0, spec(), "[V] 88"); + verify(v1, spec(), "[V] X"); +} + + +int test_main(int , char* []) +{ + run(); + return 0; +} + diff --git a/test/test3.cpp b/test/test3.cpp new file mode 100644 index 0000000..2782b3f --- /dev/null +++ b/test/test3.cpp @@ -0,0 +1,144 @@ +// File: test3.cpp + +#include "boost/test/minimal.hpp" +#include "boost/variant.hpp" +#include "boost/incomplete.hpp" + +#include +#include +#include + +///////////////////////////////////////////////////////////////////// + +using boost::variant; +using boost::incomplete; +using std::cout; +using std::endl; + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// + +struct Add; +struct Sub; + +typedef variant, incomplete > Expr; + +struct Sub +{ + Sub(); + Sub(const Expr& l, const Expr& r); + Sub(const Sub& other); + + Expr lhs_; + Expr rhs_; +}; + +struct Add +{ + Add() { } + Add(const Expr& l, const Expr& r) : lhs_(l), rhs_(r) { } + Add(const Add& other) : lhs_(other.lhs_), rhs_(other.rhs_) { } + + Expr lhs_; + Expr rhs_; +}; + +Sub::Sub() { } +Sub::Sub(const Expr& l, const Expr& r) : lhs_(l), rhs_(r) { } +Sub::Sub(const Sub& other) : lhs_(other.lhs_), rhs_(other.rhs_) { } + + +// +// insert-to operators +// +std::ostream& operator<<(std::ostream& out, const Expr& a); + +std::ostream& operator<<(std::ostream& out, const Add& a) +{ + out << '(' << a.lhs_ << '+' << a.rhs_ << ')'; + return out; +} + +std::ostream& operator<<(std::ostream& out, const Sub& a) +{ + out << '(' << a.lhs_ << '-' << a.rhs_ << ')'; + return out; +} + + +struct raw_text_maker : boost::static_visitor +{ + template + std::string operator()(const T& t) const + { + std::ostringstream ost; + ost << t; + + return ost.str(); + } +}; + +std::ostream& operator<<(std::ostream& out, const Expr& a) +{ + std::string temp = boost::apply_visitor(raw_text_maker(), a); + out << temp; + + return out; +} + +// +// Expression evaluation visitor +// +struct Calculator : boost::static_visitor +{ + Calculator() { } + + int operator()(Add& x) const + { + Calculator calc; + int n1 = boost::apply_visitor(calc, x.lhs_); + int n2 = boost::apply_visitor(calc, x.rhs_); + + return n1 + n2; + } + + int operator()(Sub& x) const + { + return boost::apply_visitor(Calculator(), x.lhs_) + - boost::apply_visitor(Calculator(), x.rhs_); + } + + int operator()(Expr& x) const + { + Calculator calc; + return boost::apply_visitor(calc, x); + } + + int operator()(int x) const + { + return x; + } + +}; // Calculator + + +///////////////////////////////////////////////////////////////////// + + +int test_main(int, char* []) +{ + + int n = 13; + Expr e1( Add(n, Sub(Add(40,2),Add(10,4))) ); //n + (40+2)-(10+14) = n+28 + + BOOST_CHECK(e1.type() == typeid(Add)); + BOOST_CHECK(boost::apply_visitor(raw_text_maker(), e1) == + "(13+((40+2)-(10+4)))"); + + //Evaluate expression + int res = boost::apply_visitor(Calculator(), e1); + BOOST_CHECK(res == n + 28); + + return 0; +} + diff --git a/test/test4.cpp b/test/test4.cpp new file mode 100644 index 0000000..da89412 --- /dev/null +++ b/test/test4.cpp @@ -0,0 +1,46 @@ +// File: test4.cpp + +#include "boost/test/minimal.hpp" +#include "boost/variant.hpp" +#include "boost/incomplete.hpp" + +#include "varout.h" +#include "jobs.h" + +#include + +struct class_a; + +using boost::incomplete; +using boost::variant; + +typedef variant, float> var_type_1; +typedef variant, short> var_type_2; + +#include "class_a.h" + +int test_main(int , char* []) +{ + using namespace boost; + + + var_type_1 v1; + var_type_2 v2; + + v1 = class_a(); + verify(v1, spec(), "[V] class_a(5511)"); + + verify(v2, spec(), "[V] "); + + v2 = "abcde"; + verify(v2, spec(), "[V] abcde"); + + v2 = v1; + verify(v2, spec(), "[V] class_a(5511)"); + + v2 = 5; + v1 = v2; + + return 0; +} + diff --git a/test/test5.cpp b/test/test5.cpp new file mode 100644 index 0000000..fa6db9c --- /dev/null +++ b/test/test5.cpp @@ -0,0 +1,83 @@ +// File: test5.cpp + +#include "boost/test/minimal.hpp" +#include "boost/variant.hpp" + +#include "jobs.h" +#include "varout.h" + +#include +#include +#include +#include + + + + +void run() +{ + using std::string; + using boost::variant; + using boost::apply_visitor; + + typedef variant t_var1; + typedef variant t_var2; + typedef variant t_var3; + + t_var1 v1; + t_var2 v2; + t_var2 v2_second; + t_var3 v3; + + const char c0 = 'x'; + v1 = c0; + + //v2 and v3 are holding (aka: containing) a variant + v2 = v1; + v3 = v2; + + verify(v1, spec()); + verify(v2, spec()); + verify(v3, spec()); + + + // + // assignment from const char (Converted to int) + // + v2 = c0; + v3 = c0; + + verify(v2, spec()); + verify(v3, spec()); + + + BOOST_TEST(apply_visitor(sum_int(), v2) == c0); + BOOST_TEST(apply_visitor(sum_int(), v3) == c0); + + sum_int adder; + apply_visitor(adder, v2); + apply_visitor(adder, v3); + + BOOST_TEST(adder.result() == 2*c0); + + // + // A variant holding a variant + // + typedef variant t_var4; + typedef variant t_var5; + + t_var4 v4; + t_var5 v5; + + v5 = 22.5f; + verify(v5, spec(), "[V] [V] 22.5"); +} + + + +int test_main(int , char* []) +{ + run(); + return 0; +} + diff --git a/test/test6.cpp b/test/test6.cpp new file mode 100644 index 0000000..c5b984d --- /dev/null +++ b/test/test6.cpp @@ -0,0 +1,66 @@ +// File: test6.cpp + +#include "boost/test/minimal.hpp" +#include "boost/variant.hpp" + +#include + +#include "jobs.h" +#include "varout.h" + + +//Just Another Class +struct jac +{ + jac() { } + jac(int ) { } + jac(const char* ) { } + +}; //jac + +std::ostream& operator<<(std::ostream& out, const jac& ) +{ + out << "jac "; + return out; +}; + + +void run() +{ + using boost::variant; + + variant v1; + variant v2; + + v1 = v2; + + verify(v1, spec()); + verify(v2, spec()); + + verify_not(v1, spec()); + verify_not(v1, spec()); + verify_not(v1, spec()); + + verify_not(v2, spec()); + verify_not(v2, spec()); + verify_not(v2, spec()); + verify_not(v2, spec()); + + + variant v3; + variant v4; + + v3 = v4; + verify(v3, spec()); + verify(v4, spec()); + verify_not(v4, spec()); +} + + + +int test_main(int , char* []) +{ + run(); + return 0; +} + diff --git a/test/test7.cpp b/test/test7.cpp new file mode 100644 index 0000000..ddf1494 --- /dev/null +++ b/test/test7.cpp @@ -0,0 +1,202 @@ +// File: test7.cpp + +#include "boost/test/minimal.hpp" +#include "boost/variant.hpp" + +#include "jobs.h" +#include "varout.h" + +#include +#include +#include +#include + + +using namespace boost; +using namespace std; + + + +struct jas +{ + jas(int n = 364); + jas(const jas& other); + + ~jas(); + jas& operator=(const jas& other); + + void swap(jas& other); + + int n_; + + int sn_; + static int s_inst_id_; +}; + +struct Tracker +{ + typedef map table_type; + typedef table_type::iterator iterator_type; + + static table_type s_this_to_sn_; + + static void insert(const jas& j) + { + s_this_to_sn_[&j] = j.sn_; + cout << "jas( " << j.sn_ << ") Registered" << endl; + } + + static void remove(const jas& j) + { + iterator_type iter = s_this_to_sn_.find(&j); + BOOST_CHECK(iter != s_this_to_sn_.end()); + BOOST_CHECK( ((*iter).second) == j.sn_); + + int sn = (*iter).second; + if(sn != j.sn_) + { + cout << "Mismatch: this = " << (*iter).first << ", sn_ = " << sn + << ", other: this = " << &j << ", j.sn_ = " << j.sn_ << endl; + } + + BOOST_CHECK(sn == j.sn_); + + + + + + s_this_to_sn_.erase(&j); + cout << "jas( " << j.sn_ << ") Removed" << endl; + } + + static void check() + { + BOOST_CHECK(s_this_to_sn_.empty()); + } +}; + +Tracker::table_type Tracker::s_this_to_sn_; + + + +jas::jas(int n) : n_(n) +{ + sn_ = s_inst_id_; + s_inst_id_ += 1; + + Tracker::insert(*this); +} + +jas::jas(const jas& other) : n_(other.n_) +{ + sn_ = s_inst_id_; + s_inst_id_ += 1; + + Tracker::insert(*this); +} + +jas::~jas() +{ + Tracker::remove(*this); +} + +jas& jas::operator=(const jas& other) +{ + jas temp(other); + swap(temp); + + return *this; +} + +void jas::swap(jas& other) +{ + Tracker::remove(*this); + Tracker::remove(other); + + std::swap(n_, other.n_); + std::swap(sn_, other.sn_); + + Tracker::insert(*this); + Tracker::insert(other); +} + +int jas::s_inst_id_ = 0; + + +bool operator==(const jas& a, const jas& b) +{ + return a.n_ == b.n_; +} + +ostream& operator<<(ostream& out, const jas& a) +{ + cout << "jas::n_ = " << a.n_; + return out; +} + + +template +struct compare_helper : boost::static_visitor +{ + compare_helper(ValueType& expected) : expected_(expected) { } + + bool operator()(const ValueType& value) + { + return value == expected_; + } + + template + bool operator()(const T& ) + { + return false; + } + + ValueType& expected_; + +}; + +template +void var_compare(const VariantType& v, ExpectedType expected) +{ + compare_helper ch(expected); + + bool checks = boost::apply_visitor(ch, v); + BOOST_CHECK(checks); +} + + +void run() +{ + variant v0; + + var_compare(v0, string("")); + + v0 = 8; + var_compare(v0, static_cast(8)); + + v0 = "penny lane"; + var_compare(v0, string("penny lane")); + + variant v1, v2 = jas(195); + var_compare(v1, jas(364)); + + v1 = jas(500); + v1.swap(v2); + + var_compare(v1, jas(195)); + var_compare(v2, jas(500)); + + + variant v3; + var_compare(v3, string("")); +} + + +int test_main(int , char* []) +{ + run(); + Tracker::check(); + + return 0; +} + diff --git a/test/test8.cpp b/test/test8.cpp new file mode 100644 index 0000000..9947bf0 --- /dev/null +++ b/test/test8.cpp @@ -0,0 +1,101 @@ +// File: test8.cpp + +#include "boost/test/minimal.hpp" +#include "boost/variant.hpp" + +#include +#include +#include + +using namespace std; +using namespace boost; + +typedef variant > t_var1; + +struct int_sum : static_visitor +{ + int_sum() : result_(0) { } + + void operator()(int t) + { + result_ += t; + } + + void operator()(float ) { } + void operator()(const std::string& ) { } + void operator()(const std::vector& ) { } + + int result_; +}; + +template +T& check_pass(Variant& v, T value) +{ + BOOST_CHECK(get(&v)); + + try + { + T& r = get(v); + BOOST_CHECK(r == value); + return r; + } + catch(boost::bad_get&) + { + throw; // must never reach + } +} + +template +void check_fail(Variant& v) +{ + BOOST_CHECK(!get(&v)); + + try + { + T& r = get(v); + BOOST_CHECK(false && &r); // should never reach + } + catch(boost::bad_get&) + { + // (do nothing here) + } +} + +int test_main(int , char* []) +{ + int_sum acc; + t_var1 v1 = 800; + + // check get on non-const variant + { + int& r1 = check_pass(v1, 800); + + check_fail(v1); + check_fail(v1); + check_fail(v1); + check_fail(v1); + check_fail(v1); + + apply_visitor(acc, v1); + BOOST_CHECK(acc.result_ == 800); + + r1 = 920; // NOTE: modifies content of v1 + apply_visitor(acc, v1); + BOOST_CHECK(acc.result_ == 800 + 920); + } + + // check const correctness: + { + const t_var1& c = v1; + + check_pass(c, 920); + + check_fail(c); + check_fail(c); + check_fail(c); + check_fail(c); + check_fail(c); + } + + return boost::exit_success; +} diff --git a/test/varout.h b/test/varout.h new file mode 100644 index 0000000..7d1bb08 --- /dev/null +++ b/test/varout.h @@ -0,0 +1,36 @@ +//File: varout.h + + +#ifndef _VAROUTH_INC_ +#define _VAROUTH_INC_ + +#include +#include +#include + +struct to_text : boost::static_visitor +{ + template + std::string operator()(const Value& value) const + { + std::ostringstream ost; + ost << "[V] " << value; + + return ost.str(); + } + +}; //to_text + + +template +std::ostream& operator<<(std::ostream& out, + const boost::variant& a) +{ + out << boost::apply_visitor(to_text(), a); + return out; +} + + + +#endif //_VAROUTH_INC_ +