You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2010/11/30 01:06:00 UTC
svn commit: r1040352 [1/3] - in /trafficserver/traffic/branches/wccp/proxy:
tsconfig/ wccp/
Author: amc
Date: Tue Nov 30 00:05:59 2010
New Revision: 1040352
URL: http://svn.apache.org/viewvc?rev=1040352&view=rev
Log:
Added copyrights, fixed some line termination issues.
Removed:
trafficserver/traffic/branches/wccp/proxy/wccp/AtsBaseStatic.cc
trafficserver/traffic/branches/wccp/proxy/wccp/Errata.cc
Modified:
trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.cc
trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.h
trafficserver/traffic/branches/wccp/proxy/tsconfig/IntrusivePtr.h
trafficserver/traffic/branches/wccp/proxy/tsconfig/NumericType.h
trafficserver/traffic/branches/wccp/proxy/tsconfig/TsBuffer.h
trafficserver/traffic/branches/wccp/proxy/tsconfig/TsBuilder.cc
trafficserver/traffic/branches/wccp/proxy/tsconfig/TsBuilder.h
trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfig.flex
trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfig.y
trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfigParseEvents.h
trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfigTypes.h
trafficserver/traffic/branches/wccp/proxy/tsconfig/TsErrataUtil.cc
trafficserver/traffic/branches/wccp/proxy/tsconfig/TsErrataUtil.h
trafficserver/traffic/branches/wccp/proxy/tsconfig/TsValue.cc
trafficserver/traffic/branches/wccp/proxy/tsconfig/TsValue.h
trafficserver/traffic/branches/wccp/proxy/wccp/Makefile.am
trafficserver/traffic/branches/wccp/proxy/wccp/Wccp.h
trafficserver/traffic/branches/wccp/proxy/wccp/WccpConfig.cc
trafficserver/traffic/branches/wccp/proxy/wccp/WccpEndPoint.cc
trafficserver/traffic/branches/wccp/proxy/wccp/WccpLocal.h
trafficserver/traffic/branches/wccp/proxy/wccp/WccpMeta.h
trafficserver/traffic/branches/wccp/proxy/wccp/WccpMsg.cc
trafficserver/traffic/branches/wccp/proxy/wccp/WccpStatic.cc
trafficserver/traffic/branches/wccp/proxy/wccp/WccpUtil.h
trafficserver/traffic/branches/wccp/proxy/wccp/wccp-test-cache.cc
trafficserver/traffic/branches/wccp/proxy/wccp/wccp-test-router.cc
Modified: trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.cc?rev=1040352&r1=1040351&r2=1040352&view=diff
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.cc (original)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.cc Tue Nov 30 00:05:59 2010
@@ -1,11 +1,19 @@
/** @file
Errata implementation.
- */
-/*
- * Copyright 2005-2010 Network Geographics, Inc.
- * http://www.network-geographics.com
- * All rights reserved.
- * Licensed to Apache Software Foundation.
+
+ Copyright 2010 Network Geographics, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
*/
# include "Errata.h"
Modified: trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.h?rev=1040352&r1=1040351&r2=1040352&view=diff
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.h (original)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.h Tue Nov 30 00:05:59 2010
@@ -1,928 +1,941 @@
-# if !defined ATS_ERRATA_HEADER
-# define ATS_ERRATA_HEADER
-
-# include <memory>
-# include <string>
-# include <iosfwd>
-# include <deque>
-# include "NumericType.h"
-# include "IntrusivePtr.h"
-
-# if USING_BOOST
-# include <boost/function.hpp>
-# include <boost/format/format_fwd.hpp>
-# endif
-
-namespace ts {
-
-/** @file
- Stacking error message handling.
-
- The problem addressed by this library is the ability to pass back
- detailed error messages from failures. It is hard to get good
- diagnostics because the specific failures and general context are
- located in very different stack frames. This library allows local
- functions to pass back local messages which can be easily
- augmented as the error travels up the stack frame.
-
- This could be done with exceptions but
- - That is more effort to implemention
- - Generally more expensive.
-
- Each message on a stack contains text and a numeric identifier.
- The identifier value zero is reserved for messages that are not
- errors so that information can be passed back even in the success
- case.
-
- The implementation takes the position that success is fast and
- failure is expensive. Therefore it is optimized for the success
- path, imposing very little overhead. On the other hand, if an
- error occurs and is handled, that is generally so expensive that
- optimizations are pointless (although, of course, one should not
- be gratuitiously expensive).
-
- The library also provides the @c Rv ("return value") template to
- make returning values and status easier. This template allows a
- function to return a value and status pair with minimal changes.
- The pair acts like the value type in most situations, while
- providing access to the status.
-
- Each instance of an erratum is a wrapper class that emulates value
- semantics (copy on write). This means passing even large message
- stacks is inexpensive, involving only a pointer copy and reference
- counter increment and decrement. A success value is represented by
- an internal @c NULL so it is even cheaper to copy.
-
- To further ease use, the library has the ability to define @a
- sinks. A sink is a function that acts on an erratum when it
- becomes unreferenced. The indended use is to send the messages to
- an output log. This makes reporting errors to a log from even
- deeply nested functions easy while preserving the ability of the
- top level logic to control such logging.
-
- */
-
-/** Class to hold a stack of error messages (the "errata").
- This is a smart handle class, which wraps the actual data
- and can therefore be treated a value type with cheap copy
- semantics. Default construction is very cheap.
- */
-class Errata {
-protected:
- /// Implementation class.
- struct Data;
- /// Handle for implementation class instance.
- typedef IntrusivePtr<Data> ImpPtr;
-public:
- typedef Errata self; /// Self reference type.
-
- /// Message ID.
- typedef NumericType<unsigned int, struct MsgIdTag> Id;
-
- /* Tag / level / code severity.
- This is intended for clients to use to provide additional
- classification of a message. A severity code, as for syslog,
- is a common use.
-
- */
- typedef NumericType<unsigned int, struct CodeTag> Code;
- struct Message;
-
- typedef std::deque<Message> Container; ///< Storage type for messages.
- // We iterate backwards to look like a stack.
-// typedef Container::reverse_iterator iterator; ///< Message iteration.
- /// Message const iteration.
-// typedef Container::const_reverse_iterator const_iterator;
- /// Reverse message iteration.
-// typedef Container::iterator reverse_iterator;
- /// Reverse constant message iteration.
-// typedef Container::const_iterator const_reverse_iterator;
-
- /// Default constructor - empty errata, very fast.
- Errata();
- /// Copy constructor, very fast.
- Errata (
- self const& that ///< Object to copy
- );
- /// Construct from string.
- /// Message Id and Code are default.
- explicit Errata(
- std::string const& text ///< Finalized message text.
- );
- /// Construct with @a id and @a text.
- /// Code is default.
- Errata(
- Id id, ///< Message id.
- std::string const& text ///< Message text.
- );
- /// Construct with @a id, @a code, and @a text.
- Errata(
- Id id, ///< Message text.
- Code code, ///< Message code.
- std::string const& text ///< Message text.
- );
- /** Construct from a message instance.
- This is equivalent to default constructing an @c errata and then
- invoking @c push with an argument of @a msg.
- */
- Errata(
- Message const& msg ///< Message to push
- );
-
- /// destructor
- ~Errata();
-
- /// Self assignment.
- /// @return A reference to this object.
- self& operator = (
- const self& that ///< Source instance.
- );
-
- /** Assign message.
- All other messages are discarded.
- @return A reference to this object.
- */
- self& operator = (
- Message const& msg ///< Source message.
- );
-
- /** Push @a text as a message.
- The message is constructed from just the @a text.
- It becomes the top message.
- @return A reference to this object.
- */
- self& push(std::string const& text);
- /** Push @a text as a message with message @a id.
- The message is constructed from @a text and @a id.
- It becomes the top message.
- @return A reference to this object.
- */
- self& push(Id id, std::string const& text);
- /** Push @a text as a message with message @a id and @a code.
- The message is constructed from @a text and @a id.
- It becomes the top message.
- @return A reference to this object.
- */
- self& push(Id id, Code code, std::string const& text);
- /** Push a message.
- @a msg becomes the top message.
- @return A reference to this object.
- */
- self& push(Message const& msg);
-
- /** Push a nested status.
- @a err becomes the top item.
- @return A reference to this object.
- */
- self& push(self const& err);
-
- /** Access top message.
- @return If the errata is empty, a default constructed message
- otherwise the most recent message.
- */
- Message const& top() const;
-
- /** Move messages from @a that to @c this errata.
- Messages from @a that are put on the top of the
- stack in @c this and removed from @a that.
- */
- self& pull(self& that);
-
- /// Remove last message.
- void pop();
-
- /// Remove all messages.
- void clear();
-
- /** Inhibit logging.
- @note This only affects @c this as a top level @c errata.
- It has no effect on this @c this being logged as a nested
- @c errata.
- */
- self& doNotLog();
-
- friend std::ostream& operator<< (std::ostream&, self const&);
-
- /// Default glue value (a newline) for text rendering.
- static std::string const DEFAULT_GLUE;
-
- /** Test status.
-
- Equivalent to @c success but more convenient for use in
- control statements.
-
- @return @c true if no messages or last message has a zero
- message ID, @c false otherwise.
- */
- operator bool() const;
-
- /** Test errata for no failure condition.
-
- Equivalent to @c operator @c bool but easier to invoke.
-
- @return @c true if no messages or last message has a zero
- message ID, @c false otherwise.
- */
- bool isOK() const;
-
- /// Number of messages in the errata.
- size_t size() const;
-
- /* Forward declares.
- We have to make our own iterators as the least bad option. The problem
- is that we have recursive structures so declaration order is difficult.
- We can't use the container iterators here because the element type is
- not yet defined. If we define the element type here, it can't contain
- an Errata and we have to do funky things to get around that. So we
- have our own iterators, which are just shadowing sublclasses of the
- container iterators.
- */
- class iterator;
- class const_iterator;
-
- /// Reference to top item on the stack.
- iterator begin();
- /// Reference to top item on the stack.
- const_iterator begin() const;
- //! Reference one past bottom item on the stack.
- iterator end();
- //! Reference one past bottom item on the stack.
- const_iterator end() const;
-
- // Logging support.
-
- /** Base class for erratum sink.
- When an errata is abandoned, this will be called on it to perform
- any client specific logging. It is passed around by handle so that
- it doesn't have to support copy semantics (and is not destructed
- until application shutdown). Clients can subclass this class in order
- to preserve arbitrary data for the sink or retain a handle to the
- sink for runtime modifications.
- */
- class Sink : public IntrusivePtrCounter {
- public:
- typedef Sink self; ///< Self reference type.
- typedef IntrusivePtr<self> Handle; ///< Handle type.
-
- /// Handle an abandoned errata.
- virtual void operator() (Errata const&) const = 0;
- /// Force virtual destructor.
- virtual ~Sink() {}
- };
-
- //! Register a sink for discarded erratum.
- static void registerSink(Sink::Handle const& s);
-
- /// Register a function as a sink.
- typedef void (*SinkHandlerFunction)(Errata const&);
-
- // Wrapper class to support registering functions as sinks.
- struct SinkFunctionWrapper : public Sink {
- /// Constructor.
- SinkFunctionWrapper(SinkHandlerFunction f) : m_f(f) { }
- /// Operator to invoke the function.
- virtual void operator() (Errata const& e) const { m_f(e); }
- SinkHandlerFunction m_f; ///< Client supplied handler.
- };
-
- /// Register a sink function for abandonded erratum.
- static void registerSink(SinkHandlerFunction f) {
- registerSink(Sink::Handle(new SinkFunctionWrapper(f)));
- }
-
- /** Simple formatted output.
-
- Each message is written to a line. All lines are indented with
- whitespace @a offset characters. Lines are indented an
- additional @a indent. This value is increased by @a shift for
- each level of nesting of an @c Errata. if @a lead is not @c
- NULL the indentation is overwritten by @a lead if @a indent is
- non-zero. It acts as a "continuation" marker for nested
- @c Errata.
-
- */
- std::ostream& write(
- std::ostream& out, ///< Output stream.
- int offset, ///< Lead white space for every line.
- int indent, ///< Additional indention per line for messages.
- int shift, ///< Additional @a indent for nested @c Errata.
- char const* lead ///< Leading text for nested @c Errata.
- ) const;
- /// Simple formatted output to fixed sized buffer.
- /// @return Number of characters written to @a buffer.
- size_t write(
- char* buffer, ///< Output buffer.
- size_t n, ///< Buffer size.
- int offset, ///< Lead white space for every line.
- int indent, ///< Additional indention per line for messages.
- int shift, ///< Additional @a indent for nested @c Errata.
- char const* lead ///< Leading text for nested @c Errata.
- ) const;
-
-# if USING_BOOST
- /// Functor type for sink.
- typedef boost::function<void (Errata const&)> SinkFunctor;
-
- // Wrapper class to support registering functions as sinks.
- struct SinkFunctorWrapper : public Sink {
- /// Constructor.
- SinkFunctionWrapper(SinkHandlerFunctor f) : m_f(f) { }
- /// Operator to invoke the function.
- virtual void operator() (Errata const& e) const { m_f(e); }
- SinkHandlerFunctor m_f; ///< Client supplied handler.
- };
-
- /// Register a sink function for abandonded erratum.
- static void registerSink(SinkFunctor const& f) {
- registerSink(Sink::Handle(new SinkFunctorWrapper(f)));
- }
-
- /// Generate formatted output.
- /// For each message in the stack, invoke @c boost::format passing
- /// @a fmt as the format string and the message ID and message text as
- /// two values. It is not an error to elide either or both. @a glue is
- /// sent to the stream @a s between every pair of messages.
- /// @return The stream @a s.
- std::ostream& format(
- std::ostream& s, ///< Output stream
- boost::format const& fmt, ///< Format string
- std::string const& glue = DEFAULT_GLUE ///< Glue
- ) const;
-
- /// Generate formatted output.
- /// A convenience overload so clients do not have to include the Boost.Format headers.
- /// @return The formatted output.
- /// @see std::ostream& format ( std::ostream& s, boost::format const& fmt, std::string const& glue ).
- std::ostream& format(
- std::ostream& s, ///< Output stream
- std::string const& fmt, ///< Format string
- std::string const& glue = DEFAULT_GLUE ///< Glue
- ) const;
-
- /// Generate formatted output.
- /// For each message in the stack, invoke @c boost::format passing
- /// @a fmt as the format string and the message ID and message text as
- /// two values. It is not an error to elide either or both. @a glue is
- /// added between every pair of messages.
- /// @note This is identical to the stream variant except the output
- /// is put in a string instead of a stream.
- /// @return The formatted output.
- /// @see std::ostream& format ( std::ostream& s, boost::format const& fmt, std::string const& glue ).
- std::string format(
- boost::format const& fmt, ///< Format string
- std::string const& glue = DEFAULT_GLUE ///< Glue
- ) const;
-
- /// Generate formatted output.
- /// A convenience overload so clients do not have to include the Boost.Format headers.
- /// @return The formatted output.
- /// @see std::string format ( boost::format const& fmt, std::string const& glue ).
- std::string format(
- std::string const& fmt, ///< Format string
- std::string const& glue = DEFAULT_GLUE ///< Glue
- ) const;
-# endif // USING_BOOST
-
-protected:
- /// Construct from implementation pointer.
- /// Used internally by nested classes.
- Errata(ImpPtr const& ptr);
- /// Implementation instance.
- ImpPtr m_data;
-
- /// Return the implementation instance, allocating and unsharing as needed.
- Data* pre_write();
- /// Force and return an implementation instance.
- /// Does not follow copy on write.
- Data* instance();
-
- /// Used for returns when no data is present.
- static Message const NIL_MESSAGE;
-
- friend struct Data;
- friend class Item;
-
-};
-
-extern std::ostream& operator<< (std::ostream& os, Errata const& stat);
-
-/// Storage for a single message.
-struct Errata::Message {
- typedef Message self; ///< Self reference type.
-
- /// Default constructor.
- /// The message has Id = 0, default code, and empty text.
- Message();
-
- /// Construct from text.
- /// Id is zero and Code is default.
- Message(
- std::string const& text ///< Finalized message text.
- );
-
- /// Construct with @a id and @a text.
- /// Code is default.
- Message(
- Id id, ///< ID of message in table.
- std::string const& text ///< Final text for message.
- );
-
- /// Construct with @a id, @a code, and @a text.
- Message(
- Id id, ///< Message Id.
- Code code, ///< Message Code.
- std::string const& text ///< Final text for message.
- );
-
- /// Reset to the message to default state.
- self& clear();
-
- /// Set the message Id.
- self& set(
- Id id ///< New message Id.
- );
-
- /// Set the code.
- self& set(
- Code code ///< New code for message.
- );
-
- /// Set the text.
- self& set(
- std::string const& text ///< New message text.
- );
-
- /// Set the text.
- self& set(
- char const* text ///< New message text.
- );
-
- /// Set the errata.
- self& set(
- Errata const& err ///< Errata to store.
- );
-
- /// Get the text of the message.
- std::string const& text() const;
-
- /// Get the code.
- Code getCode() const;
- /// Get the nested status.
- /// @return A status object, which is not @c NULL if there is a
- /// nested status stored in this item.
- Errata getErrata() const;
-
- /** The default message code.
-
- This value is used as the Code value for constructing and
- clearing messages. It can be changed to control the value
- used for empty messages.
- */
- static Code Default_Code;
-
- /// Type for overriding success message test.
- typedef bool (*SuccessTest)(Message const& m);
-
- /** Success message test.
-
- When a message is tested for being "successful", this
- function is called. It may be overridden by a client.
- The initial value is @c DEFAULT_SUCCESS_TEST.
-
- @note This is only called when there are Messages in the
- Errata. An empty Errata (@c NULL or empty stack) is always
- a success. Only the @c top Message is checked.
-
- @return @c true if the message indicates success,
- @c false otherwise.
- */
- static SuccessTest Success_Test;
-
- /// Indicate success if the message code is zero.
- /// @note Used as the default success test.
- static bool isCodeZero(Message const& m);
-
- static SuccessTest const DEFAULT_SUCCESS_TEST;
-
- Id m_id; ///< Message ID.
- Code m_code; ///< Message code.
- std::string m_text; ///< Final text.
- Errata m_errata; ///< Nested errata.
-};
-
-/** This is the implementation class for Errata.
-
- It holds the actual messages and is treated as a passive data
- object with nice constructors.
-
- We implement reference counting semantics by hand for two
- reasons. One is that we need to do some specialized things, but
- mainly because the client can't see this class so we can't
-*/
-struct Errata::Data : public IntrusivePtrCounter {
- typedef Data self; ///< Self reference type.
-
- //! Default constructor.
- Data();
-
- /// Destructor, to do logging.
- ~Data();
-
- //! Number of messages.
- size_t size() const;
-
- /// Get the top message on the stack.
- Message const& top() const;
-
- /// Put a message on top of the stack.
- void push(Message const& msg);
-
- /// Log this when it is deleted.
- bool m_log_on_delete;
-
- //! The message stack.
- Container m_items;
-};
-
-/// Forward iterator for @c Messages in an @c Errata.
-class Errata::iterator : public Errata::Container::reverse_iterator {
-public:
- typedef iterator self; ///< Self reference type.
- typedef Errata::Container::reverse_iterator super; ///< Parent type.
- iterator(); ///< Default constructor.
- /// Copy constructor.
- iterator(
- self const& that ///< Source instance.
- );
- /// Construct from super class.
- iterator(
- super const& that ///< Source instance.
- );
- /// Assignment.
- self& operator = (self const& that);
- /// Assignment from super class.
- self& operator = (super const& that);
- /// Prefix increment.
- self& operator ++ ();
- /// Prefix decrement.
- self& operator -- ();
-};
-
-/// Forward constant iterator for @c Messages in an @c Errata.
-class Errata::const_iterator : public Errata::Container::const_reverse_iterator {
-public:
- typedef const_iterator self; ///< Self reference type.
- typedef Errata::Container::const_reverse_iterator super; ///< Parent type.
- const_iterator(); ///< Default constructor.
- /// Copy constructor.
- const_iterator(
- self const& that ///< Source instance.
- );
- const_iterator(
- super const& that ///< Source instance.
- );
- /// Assignment.
- self& operator = (self const& that);
- /// Assignment from super class.
- self& operator = (super const& that);
- /// Prefix increment.
- self& operator ++ ();
- /// Prefix decrement.
- self& operator -- ();
-};
-
-/** Helper class for @c Rv.
- This class enables us to move the implementation of non-templated methods
- and members out of the header file for a cleaner API.
- */
-struct RvBase {
- Errata _errata; ///< The status from the function.
-
- /** Default constructor. */
- RvBase();
-
- /** Construct with specific status.
- */
- RvBase (
- Errata const& s ///< Status to copy
- );
-
- //! Test the return value for success.
- bool isOK() const;
-
- /** Clear any stacked errors.
- This is useful during shutdown, to silence irrelevant errors caused
- by the shutdown process.
- */
- void clear();
-
- /// Inhibit logging of the errata.
- void doNotLog();
-};
-
-/** Return type for returning a value and status (errata). In
- general, a method wants to return both a result and a status so
- that errors are logged properly. This structure is used to do that
- in way that is more usable than just @c std::pair. - Simpler and
- shorter typography - Force use of @c errata rather than having to
- remember it (and the order) each time - Enable assignment directly
- to @a R for ease of use and compatibility so clients can upgrade
- asynchronously.
- */
-template < typename R >
-struct Rv : public RvBase {
- typedef Rv self; ///< Standard self reference type.
- typedef RvBase super; ///< Standard super class reference type.
- typedef R Result; ///< Type of result value.
-
- Result _result; ///< The actual result of the function.
-
- /** Default constructor.
- The default constructor for @a R is used.
- The status is initialized to SUCCESS.
- */
- Rv();
-
- /** Standard (success) constructor.
-
- This copies the result and sets the status to SUCCESS.
-
- @note Not @c explicit so that clients can return just a result
- and have it be marked as SUCCESS.
- */
- Rv(
- Result const& r ///< The function result
- );
-
- /** Construct from a result and a pre-existing status object.
-
- @internal No constructor from just an Errata to avoid
- potential ambiguity with constructing from result type.
- */
- Rv(
- Result const& r, ///< The function result
- Errata const& s ///< A pre-existing status object
- );
-
- /** User conversion to the result type.
-
- This makes it easy to use the function normally or to pass the
- result only to other functions without having to extract it by
- hand.
- */
- operator Result const& () const;
-
- /** Assignment from result type.
-
- This allows the result to be assigned to a pre-declared return
- value structure. The return value is a reference to the
- internal result so that this operator can be chained in other
- assignments to instances of result type. This is most commonly
- used when the result is computed in to a local variable to be
- both returned and stored in a member.
-
- @code
- Rv<int> zret;
- int value;
- // ... complex computations, result in value
- this->m_value = zret = value;
- // ...
- return zret;
- @endcode
-
- @return A reference to the copy of @a r stored in this object.
- */
- Result& operator = (
- Result const& r ///< Result to assign
- ) {
- _result = r;
- return _result;
- }
-
- /** Add the status from another instance to this one.
- @return A reference to @c this object.
- */
- template < typename U >
- self& push(
- Rv<U> const& that ///< Source of status messages
- );
-
- /** Set the result.
-
- This differs from assignment of the function result in that the
- return value is a reference to the @c Rv, not the internal
- result. This makes it useful for assigning a result local
- variable and then returning.
-
- @code
- Rv<int> zret;
- int value;
- // ... complex computation, result in value
- return zret.set(value);
- @endcode
- */
- self& set(
- Result const& r ///< Result to store
- );
-
- /** Return the result.
- @return A reference to the result value in this object.
- */
- Result& result();
-
- /** Return the result.
- @return A reference to the result value in this object.
- */
- Result const& result() const;
-
- /** Return the status.
- @return A reference to the @c errata in this object.
- */
- Errata& errata();
-
- /** Return the status.
- @return A reference to the @c errata in this object.
- */
- Errata const& errata() const;
-
- /// Directly set the errata
- self& operator = (
- Errata const& status ///< Errata to assign.
- );
-
- /// Push a message on to the status.
- self& push(
- Errata::Message const& msg
- );
-};
-
-/** Combine a function result and status in to an @c Rv.
- This is useful for clients that want to declare the status object
- and result independently.
- */
-template < typename R > Rv<R>
-MakeRv(
- R const& r, ///< The function result
- Errata const& s ///< The pre-existing status object
-) {
- return Rv<R>(r, s);
-}
-/* ----------------------------------------------------------------------- */
-/* ----------------------------------------------------------------------- */
-// Inline methods.
-inline Errata::Message::Message()
- : m_id(0), m_code(Default_Code) {
-}
-inline Errata::Message::Message(std::string const& text)
- : m_id(0), m_code(Default_Code), m_text(text) {
-}
-inline Errata::Message::Message(Id id, std::string const& text)
- : m_id(id), m_code(Default_Code), m_text(text) {
-}
-inline Errata::Message::Message(Id id, Code code, std::string const& text)
- : m_id(id), m_code(code), m_text(text) {
-}
-inline Errata::Message& Errata::Message::clear() {
- m_id = 0;
- m_code = Default_Code;
- m_text.erase();
- m_errata.clear();
- return *this;
-}
-
-inline std::string const& Errata::Message::text() const { return m_text; }
-inline Errata::Code Errata::Message::getCode() const { return m_code; }
-inline Errata Errata::Message::getErrata() const { return m_errata; }
-
-inline Errata::Message& Errata::Message::set(Id id) {
- m_id = id;
- return *this;
-}
-inline Errata::Message& Errata::Message::set(Code code) {
- m_code = code;
- return *this;
-}
-inline Errata::Message& Errata::Message::set(std::string const& text) {
- m_text = text;
- return *this;
-}
-inline Errata::Message& Errata::Message::set(char const* text) {
- m_text = text;
- return *this;
-}
-inline Errata::Message& Errata::Message::set(Errata const& err) {
- m_errata = err;
- m_errata.doNotLog();
- return *this;
-}
-
-inline Errata::Errata(Id id, Code code, std::string const& text) {
- this->push(Message(id, code, text));
-}
-inline Errata::Errata(Message const& msg) {
- this->push(msg);
-}
-
-inline Errata::operator bool() const { return this->isOK(); }
-
-inline size_t Errata::size() const {
- return m_data ? m_data->m_items.size() : 0;
-}
-
-inline bool Errata::isOK() const {
- return 0 == m_data
- || 0 == m_data->size()
- || Message::Success_Test(this->top())
- ;
-}
-
-inline Errata&
-Errata::push(std::string const& text) {
- this->push(Message(text));
- return *this;
-}
-
-inline Errata&
-Errata::push(Id id, std::string const& text) {
- this->push(Message(id, text));
- return *this;
-}
-
-inline Errata&
-Errata::push(Id id, Code code, std::string const& text) {
- this->push(Message(id, code, text));
- return *this;
-}
-
-inline Errata::Message const&
-Errata::top() const {
- return m_data ? m_data->top() : NIL_MESSAGE;
-}
-inline Errata& Errata::doNotLog() {
- this->instance()->m_log_on_delete = false;
- return *this;
-}
-
-inline Errata::Data::Data() : m_log_on_delete(true) {}
-inline size_t Errata::Data::size() const { return m_items.size(); }
-
-inline Errata::iterator::iterator() { }
-inline Errata::iterator::iterator(self const& that) : super(that) { }
-inline Errata::iterator::iterator(super const& that) : super(that) { }
-inline Errata::iterator& Errata::iterator::operator = (self const& that) { this->super::operator = (that); return *this; }
-inline Errata::iterator& Errata::iterator::operator = (super const& that) { this->super::operator = (that); return *this; }
-inline Errata::iterator& Errata::iterator::operator ++ () { this->super::operator ++ (); return *this; }
-inline Errata::iterator& Errata::iterator::operator -- () { this->super::operator -- (); return *this; }
-
-inline Errata::const_iterator::const_iterator() { }
-inline Errata::const_iterator::const_iterator(self const& that) : super(that) { }
-inline Errata::const_iterator::const_iterator(super const& that) : super(that) { }
-inline Errata::const_iterator& Errata::const_iterator::operator = (self const& that) { super::operator = (that); return *this; }
-inline Errata::const_iterator& Errata::const_iterator::operator = (super const& that) { super::operator = (that); return *this; }
-inline Errata::const_iterator& Errata::const_iterator::operator ++ () { this->super::operator ++ (); return *this; }
-inline Errata::const_iterator& Errata::const_iterator::operator -- () { this->super::operator -- (); return *this; }
-
-inline RvBase::RvBase() { }
-inline RvBase::RvBase(Errata const& errata) : _errata(errata) { }
-inline bool RvBase::isOK() const { return _errata; }
-inline void RvBase::clear() { _errata.clear(); }
-inline void RvBase::doNotLog() { _errata.doNotLog(); }
-
-template < typename T > Rv<T>::Rv() { }
-template < typename T > Rv<T>::Rv(Result const& r) : _result(r) { }
-template < typename T > Rv<T>::Rv(Result const& r, Errata const& errata)
- : super(errata)
- , _result(r) {
-}
-template < typename T > Rv<T>::operator Result const&() const {
- return _result;
-}
-template < typename T > T const& Rv<T>::result() const { return _result; }
-template < typename T > T& Rv<T>::result() { return _result; }
-template < typename T > Errata const& Rv<T>::errata() const { return _errata; }
-template < typename T > Errata& Rv<T>::errata() { return _errata; }
-template < typename T > Rv<T>&
-Rv<T>::set(Result const& r) {
- _result = r;
- return *this;
-}
-template < typename T > Rv<T>&
-Rv<T>::operator = (Errata const& errata) {
- _errata = errata;
- return *this;
-}
-template < typename T > Rv<T>&
-Rv<T>::push(Errata::Message const& msg) {
- _errata.push(msg);
- return *this;
-}
-template < typename T > template < typename U > Rv<T>&
-Rv<T>::push(Rv<U> const& that) {
- _errata.push(that.errata());
- return *this;
-}
-/* ----------------------------------------------------------------------- */
-/* ----------------------------------------------------------------------- */
-} // namespace ats
-
-# endif // ATS_ERRATA_HEADER
+# if !defined TS_ERRATA_HEADER
+# define TS_ERRATA_HEADER
+
+/** @file
+ Stacking error message handling.
+
+ The problem addressed by this library is the ability to pass back
+ detailed error messages from failures. It is hard to get good
+ diagnostics because the specific failures and general context are
+ located in very different stack frames. This library allows local
+ functions to pass back local messages which can be easily
+ augmented as the error travels up the stack frame.
+
+ This could be done with exceptions but
+ - That is more effort to implemention
+ - Generally more expensive.
+
+ Each message on a stack contains text and a numeric identifier.
+ The identifier value zero is reserved for messages that are not
+ errors so that information can be passed back even in the success
+ case.
+
+ The implementation takes the position that success is fast and
+ failure is expensive. Therefore it is optimized for the success
+ path, imposing very little overhead. On the other hand, if an
+ error occurs and is handled, that is generally so expensive that
+ optimizations are pointless (although, of course, one should not
+ be gratuitiously expensive).
+
+ The library also provides the @c Rv ("return value") template to
+ make returning values and status easier. This template allows a
+ function to return a value and status pair with minimal changes.
+ The pair acts like the value type in most situations, while
+ providing access to the status.
+
+ Each instance of an erratum is a wrapper class that emulates value
+ semantics (copy on write). This means passing even large message
+ stacks is inexpensive, involving only a pointer copy and reference
+ counter increment and decrement. A success value is represented by
+ an internal @c NULL so it is even cheaper to copy.
+
+ To further ease use, the library has the ability to define @a
+ sinks. A sink is a function that acts on an erratum when it
+ becomes unreferenced. The indended use is to send the messages to
+ an output log. This makes reporting errors to a log from even
+ deeply nested functions easy while preserving the ability of the
+ top level logic to control such logging.
+
+ Copyright 2010 Network Geographics, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+# include <memory>
+# include <string>
+# include <iosfwd>
+# include <deque>
+# include "NumericType.h"
+# include "IntrusivePtr.h"
+
+# if USING_BOOST
+# include <boost/function.hpp>
+# include <boost/format/format_fwd.hpp>
+# endif
+
+namespace ts {
+
+/** Class to hold a stack of error messages (the "errata").
+ This is a smart handle class, which wraps the actual data
+ and can therefore be treated a value type with cheap copy
+ semantics. Default construction is very cheap.
+ */
+class Errata {
+protected:
+ /// Implementation class.
+ struct Data;
+ /// Handle for implementation class instance.
+ typedef IntrusivePtr<Data> ImpPtr;
+public:
+ typedef Errata self; /// Self reference type.
+
+ /// Message ID.
+ typedef NumericType<unsigned int, struct MsgIdTag> Id;
+
+ /* Tag / level / code severity.
+ This is intended for clients to use to provide additional
+ classification of a message. A severity code, as for syslog,
+ is a common use.
+
+ */
+ typedef NumericType<unsigned int, struct CodeTag> Code;
+ struct Message;
+
+ typedef std::deque<Message> Container; ///< Storage type for messages.
+ // We iterate backwards to look like a stack.
+// typedef Container::reverse_iterator iterator; ///< Message iteration.
+ /// Message const iteration.
+// typedef Container::const_reverse_iterator const_iterator;
+ /// Reverse message iteration.
+// typedef Container::iterator reverse_iterator;
+ /// Reverse constant message iteration.
+// typedef Container::const_iterator const_reverse_iterator;
+
+ /// Default constructor - empty errata, very fast.
+ Errata();
+ /// Copy constructor, very fast.
+ Errata (
+ self const& that ///< Object to copy
+ );
+ /// Construct from string.
+ /// Message Id and Code are default.
+ explicit Errata(
+ std::string const& text ///< Finalized message text.
+ );
+ /// Construct with @a id and @a text.
+ /// Code is default.
+ Errata(
+ Id id, ///< Message id.
+ std::string const& text ///< Message text.
+ );
+ /// Construct with @a id, @a code, and @a text.
+ Errata(
+ Id id, ///< Message text.
+ Code code, ///< Message code.
+ std::string const& text ///< Message text.
+ );
+ /** Construct from a message instance.
+ This is equivalent to default constructing an @c errata and then
+ invoking @c push with an argument of @a msg.
+ */
+ Errata(
+ Message const& msg ///< Message to push
+ );
+
+ /// destructor
+ ~Errata();
+
+ /// Self assignment.
+ /// @return A reference to this object.
+ self& operator = (
+ const self& that ///< Source instance.
+ );
+
+ /** Assign message.
+ All other messages are discarded.
+ @return A reference to this object.
+ */
+ self& operator = (
+ Message const& msg ///< Source message.
+ );
+
+ /** Push @a text as a message.
+ The message is constructed from just the @a text.
+ It becomes the top message.
+ @return A reference to this object.
+ */
+ self& push(std::string const& text);
+ /** Push @a text as a message with message @a id.
+ The message is constructed from @a text and @a id.
+ It becomes the top message.
+ @return A reference to this object.
+ */
+ self& push(Id id, std::string const& text);
+ /** Push @a text as a message with message @a id and @a code.
+ The message is constructed from @a text and @a id.
+ It becomes the top message.
+ @return A reference to this object.
+ */
+ self& push(Id id, Code code, std::string const& text);
+ /** Push a message.
+ @a msg becomes the top message.
+ @return A reference to this object.
+ */
+ self& push(Message const& msg);
+
+ /** Push a nested status.
+ @a err becomes the top item.
+ @return A reference to this object.
+ */
+ self& push(self const& err);
+
+ /** Access top message.
+ @return If the errata is empty, a default constructed message
+ otherwise the most recent message.
+ */
+ Message const& top() const;
+
+ /** Move messages from @a that to @c this errata.
+ Messages from @a that are put on the top of the
+ stack in @c this and removed from @a that.
+ */
+ self& pull(self& that);
+
+ /// Remove last message.
+ void pop();
+
+ /// Remove all messages.
+ void clear();
+
+ /** Inhibit logging.
+ @note This only affects @c this as a top level @c errata.
+ It has no effect on this @c this being logged as a nested
+ @c errata.
+ */
+ self& doNotLog();
+
+ friend std::ostream& operator<< (std::ostream&, self const&);
+
+ /// Default glue value (a newline) for text rendering.
+ static std::string const DEFAULT_GLUE;
+
+ /** Test status.
+
+ Equivalent to @c success but more convenient for use in
+ control statements.
+
+ @return @c true if no messages or last message has a zero
+ message ID, @c false otherwise.
+ */
+ operator bool() const;
+
+ /** Test errata for no failure condition.
+
+ Equivalent to @c operator @c bool but easier to invoke.
+
+ @return @c true if no messages or last message has a zero
+ message ID, @c false otherwise.
+ */
+ bool isOK() const;
+
+ /// Number of messages in the errata.
+ size_t size() const;
+
+ /* Forward declares.
+ We have to make our own iterators as the least bad option. The problem
+ is that we have recursive structures so declaration order is difficult.
+ We can't use the container iterators here because the element type is
+ not yet defined. If we define the element type here, it can't contain
+ an Errata and we have to do funky things to get around that. So we
+ have our own iterators, which are just shadowing sublclasses of the
+ container iterators.
+ */
+ class iterator;
+ class const_iterator;
+
+ /// Reference to top item on the stack.
+ iterator begin();
+ /// Reference to top item on the stack.
+ const_iterator begin() const;
+ //! Reference one past bottom item on the stack.
+ iterator end();
+ //! Reference one past bottom item on the stack.
+ const_iterator end() const;
+
+ // Logging support.
+
+ /** Base class for erratum sink.
+ When an errata is abandoned, this will be called on it to perform
+ any client specific logging. It is passed around by handle so that
+ it doesn't have to support copy semantics (and is not destructed
+ until application shutdown). Clients can subclass this class in order
+ to preserve arbitrary data for the sink or retain a handle to the
+ sink for runtime modifications.
+ */
+ class Sink : public IntrusivePtrCounter {
+ public:
+ typedef Sink self; ///< Self reference type.
+ typedef IntrusivePtr<self> Handle; ///< Handle type.
+
+ /// Handle an abandoned errata.
+ virtual void operator() (Errata const&) const = 0;
+ /// Force virtual destructor.
+ virtual ~Sink() {}
+ };
+
+ //! Register a sink for discarded erratum.
+ static void registerSink(Sink::Handle const& s);
+
+ /// Register a function as a sink.
+ typedef void (*SinkHandlerFunction)(Errata const&);
+
+ // Wrapper class to support registering functions as sinks.
+ struct SinkFunctionWrapper : public Sink {
+ /// Constructor.
+ SinkFunctionWrapper(SinkHandlerFunction f) : m_f(f) { }
+ /// Operator to invoke the function.
+ virtual void operator() (Errata const& e) const { m_f(e); }
+ SinkHandlerFunction m_f; ///< Client supplied handler.
+ };
+
+ /// Register a sink function for abandonded erratum.
+ static void registerSink(SinkHandlerFunction f) {
+ registerSink(Sink::Handle(new SinkFunctionWrapper(f)));
+ }
+
+ /** Simple formatted output.
+
+ Each message is written to a line. All lines are indented with
+ whitespace @a offset characters. Lines are indented an
+ additional @a indent. This value is increased by @a shift for
+ each level of nesting of an @c Errata. if @a lead is not @c
+ NULL the indentation is overwritten by @a lead if @a indent is
+ non-zero. It acts as a "continuation" marker for nested
+ @c Errata.
+
+ */
+ std::ostream& write(
+ std::ostream& out, ///< Output stream.
+ int offset, ///< Lead white space for every line.
+ int indent, ///< Additional indention per line for messages.
+ int shift, ///< Additional @a indent for nested @c Errata.
+ char const* lead ///< Leading text for nested @c Errata.
+ ) const;
+ /// Simple formatted output to fixed sized buffer.
+ /// @return Number of characters written to @a buffer.
+ size_t write(
+ char* buffer, ///< Output buffer.
+ size_t n, ///< Buffer size.
+ int offset, ///< Lead white space for every line.
+ int indent, ///< Additional indention per line for messages.
+ int shift, ///< Additional @a indent for nested @c Errata.
+ char const* lead ///< Leading text for nested @c Errata.
+ ) const;
+
+# if USING_BOOST
+ /// Functor type for sink.
+ typedef boost::function<void (Errata const&)> SinkFunctor;
+
+ // Wrapper class to support registering functions as sinks.
+ struct SinkFunctorWrapper : public Sink {
+ /// Constructor.
+ SinkFunctionWrapper(SinkHandlerFunctor f) : m_f(f) { }
+ /// Operator to invoke the function.
+ virtual void operator() (Errata const& e) const { m_f(e); }
+ SinkHandlerFunctor m_f; ///< Client supplied handler.
+ };
+
+ /// Register a sink function for abandonded erratum.
+ static void registerSink(SinkFunctor const& f) {
+ registerSink(Sink::Handle(new SinkFunctorWrapper(f)));
+ }
+
+ /// Generate formatted output.
+ /// For each message in the stack, invoke @c boost::format passing
+ /// @a fmt as the format string and the message ID and message text as
+ /// two values. It is not an error to elide either or both. @a glue is
+ /// sent to the stream @a s between every pair of messages.
+ /// @return The stream @a s.
+ std::ostream& format(
+ std::ostream& s, ///< Output stream
+ boost::format const& fmt, ///< Format string
+ std::string const& glue = DEFAULT_GLUE ///< Glue
+ ) const;
+
+ /// Generate formatted output.
+ /// A convenience overload so clients do not have to include the Boost.Format headers.
+ /// @return The formatted output.
+ /// @see std::ostream& format ( std::ostream& s, boost::format const& fmt, std::string const& glue ).
+ std::ostream& format(
+ std::ostream& s, ///< Output stream
+ std::string const& fmt, ///< Format string
+ std::string const& glue = DEFAULT_GLUE ///< Glue
+ ) const;
+
+ /// Generate formatted output.
+ /// For each message in the stack, invoke @c boost::format passing
+ /// @a fmt as the format string and the message ID and message text as
+ /// two values. It is not an error to elide either or both. @a glue is
+ /// added between every pair of messages.
+ /// @note This is identical to the stream variant except the output
+ /// is put in a string instead of a stream.
+ /// @return The formatted output.
+ /// @see std::ostream& format ( std::ostream& s, boost::format const& fmt, std::string const& glue ).
+ std::string format(
+ boost::format const& fmt, ///< Format string
+ std::string const& glue = DEFAULT_GLUE ///< Glue
+ ) const;
+
+ /// Generate formatted output.
+ /// A convenience overload so clients do not have to include the Boost.Format headers.
+ /// @return The formatted output.
+ /// @see std::string format ( boost::format const& fmt, std::string const& glue ).
+ std::string format(
+ std::string const& fmt, ///< Format string
+ std::string const& glue = DEFAULT_GLUE ///< Glue
+ ) const;
+# endif // USING_BOOST
+
+protected:
+ /// Construct from implementation pointer.
+ /// Used internally by nested classes.
+ Errata(ImpPtr const& ptr);
+ /// Implementation instance.
+ ImpPtr m_data;
+
+ /// Return the implementation instance, allocating and unsharing as needed.
+ Data* pre_write();
+ /// Force and return an implementation instance.
+ /// Does not follow copy on write.
+ Data* instance();
+
+ /// Used for returns when no data is present.
+ static Message const NIL_MESSAGE;
+
+ friend struct Data;
+ friend class Item;
+
+};
+
+extern std::ostream& operator<< (std::ostream& os, Errata const& stat);
+
+/// Storage for a single message.
+struct Errata::Message {
+ typedef Message self; ///< Self reference type.
+
+ /// Default constructor.
+ /// The message has Id = 0, default code, and empty text.
+ Message();
+
+ /// Construct from text.
+ /// Id is zero and Code is default.
+ Message(
+ std::string const& text ///< Finalized message text.
+ );
+
+ /// Construct with @a id and @a text.
+ /// Code is default.
+ Message(
+ Id id, ///< ID of message in table.
+ std::string const& text ///< Final text for message.
+ );
+
+ /// Construct with @a id, @a code, and @a text.
+ Message(
+ Id id, ///< Message Id.
+ Code code, ///< Message Code.
+ std::string const& text ///< Final text for message.
+ );
+
+ /// Reset to the message to default state.
+ self& clear();
+
+ /// Set the message Id.
+ self& set(
+ Id id ///< New message Id.
+ );
+
+ /// Set the code.
+ self& set(
+ Code code ///< New code for message.
+ );
+
+ /// Set the text.
+ self& set(
+ std::string const& text ///< New message text.
+ );
+
+ /// Set the text.
+ self& set(
+ char const* text ///< New message text.
+ );
+
+ /// Set the errata.
+ self& set(
+ Errata const& err ///< Errata to store.
+ );
+
+ /// Get the text of the message.
+ std::string const& text() const;
+
+ /// Get the code.
+ Code getCode() const;
+ /// Get the nested status.
+ /// @return A status object, which is not @c NULL if there is a
+ /// nested status stored in this item.
+ Errata getErrata() const;
+
+ /** The default message code.
+
+ This value is used as the Code value for constructing and
+ clearing messages. It can be changed to control the value
+ used for empty messages.
+ */
+ static Code Default_Code;
+
+ /// Type for overriding success message test.
+ typedef bool (*SuccessTest)(Message const& m);
+
+ /** Success message test.
+
+ When a message is tested for being "successful", this
+ function is called. It may be overridden by a client.
+ The initial value is @c DEFAULT_SUCCESS_TEST.
+
+ @note This is only called when there are Messages in the
+ Errata. An empty Errata (@c NULL or empty stack) is always
+ a success. Only the @c top Message is checked.
+
+ @return @c true if the message indicates success,
+ @c false otherwise.
+ */
+ static SuccessTest Success_Test;
+
+ /// Indicate success if the message code is zero.
+ /// @note Used as the default success test.
+ static bool isCodeZero(Message const& m);
+
+ static SuccessTest const DEFAULT_SUCCESS_TEST;
+
+ Id m_id; ///< Message ID.
+ Code m_code; ///< Message code.
+ std::string m_text; ///< Final text.
+ Errata m_errata; ///< Nested errata.
+};
+
+/** This is the implementation class for Errata.
+
+ It holds the actual messages and is treated as a passive data
+ object with nice constructors.
+
+ We implement reference counting semantics by hand for two
+ reasons. One is that we need to do some specialized things, but
+ mainly because the client can't see this class so we can't
+*/
+struct Errata::Data : public IntrusivePtrCounter {
+ typedef Data self; ///< Self reference type.
+
+ //! Default constructor.
+ Data();
+
+ /// Destructor, to do logging.
+ ~Data();
+
+ //! Number of messages.
+ size_t size() const;
+
+ /// Get the top message on the stack.
+ Message const& top() const;
+
+ /// Put a message on top of the stack.
+ void push(Message const& msg);
+
+ /// Log this when it is deleted.
+ bool m_log_on_delete;
+
+ //! The message stack.
+ Container m_items;
+};
+
+/// Forward iterator for @c Messages in an @c Errata.
+class Errata::iterator : public Errata::Container::reverse_iterator {
+public:
+ typedef iterator self; ///< Self reference type.
+ typedef Errata::Container::reverse_iterator super; ///< Parent type.
+ iterator(); ///< Default constructor.
+ /// Copy constructor.
+ iterator(
+ self const& that ///< Source instance.
+ );
+ /// Construct from super class.
+ iterator(
+ super const& that ///< Source instance.
+ );
+ /// Assignment.
+ self& operator = (self const& that);
+ /// Assignment from super class.
+ self& operator = (super const& that);
+ /// Prefix increment.
+ self& operator ++ ();
+ /// Prefix decrement.
+ self& operator -- ();
+};
+
+/// Forward constant iterator for @c Messages in an @c Errata.
+class Errata::const_iterator : public Errata::Container::const_reverse_iterator {
+public:
+ typedef const_iterator self; ///< Self reference type.
+ typedef Errata::Container::const_reverse_iterator super; ///< Parent type.
+ const_iterator(); ///< Default constructor.
+ /// Copy constructor.
+ const_iterator(
+ self const& that ///< Source instance.
+ );
+ const_iterator(
+ super const& that ///< Source instance.
+ );
+ /// Assignment.
+ self& operator = (self const& that);
+ /// Assignment from super class.
+ self& operator = (super const& that);
+ /// Prefix increment.
+ self& operator ++ ();
+ /// Prefix decrement.
+ self& operator -- ();
+};
+
+/** Helper class for @c Rv.
+ This class enables us to move the implementation of non-templated methods
+ and members out of the header file for a cleaner API.
+ */
+struct RvBase {
+ Errata _errata; ///< The status from the function.
+
+ /** Default constructor. */
+ RvBase();
+
+ /** Construct with specific status.
+ */
+ RvBase (
+ Errata const& s ///< Status to copy
+ );
+
+ //! Test the return value for success.
+ bool isOK() const;
+
+ /** Clear any stacked errors.
+ This is useful during shutdown, to silence irrelevant errors caused
+ by the shutdown process.
+ */
+ void clear();
+
+ /// Inhibit logging of the errata.
+ void doNotLog();
+};
+
+/** Return type for returning a value and status (errata). In
+ general, a method wants to return both a result and a status so
+ that errors are logged properly. This structure is used to do that
+ in way that is more usable than just @c std::pair. - Simpler and
+ shorter typography - Force use of @c errata rather than having to
+ remember it (and the order) each time - Enable assignment directly
+ to @a R for ease of use and compatibility so clients can upgrade
+ asynchronously.
+ */
+template < typename R >
+struct Rv : public RvBase {
+ typedef Rv self; ///< Standard self reference type.
+ typedef RvBase super; ///< Standard super class reference type.
+ typedef R Result; ///< Type of result value.
+
+ Result _result; ///< The actual result of the function.
+
+ /** Default constructor.
+ The default constructor for @a R is used.
+ The status is initialized to SUCCESS.
+ */
+ Rv();
+
+ /** Standard (success) constructor.
+
+ This copies the result and sets the status to SUCCESS.
+
+ @note Not @c explicit so that clients can return just a result
+ and have it be marked as SUCCESS.
+ */
+ Rv(
+ Result const& r ///< The function result
+ );
+
+ /** Construct from a result and a pre-existing status object.
+
+ @internal No constructor from just an Errata to avoid
+ potential ambiguity with constructing from result type.
+ */
+ Rv(
+ Result const& r, ///< The function result
+ Errata const& s ///< A pre-existing status object
+ );
+
+ /** User conversion to the result type.
+
+ This makes it easy to use the function normally or to pass the
+ result only to other functions without having to extract it by
+ hand.
+ */
+ operator Result const& () const;
+
+ /** Assignment from result type.
+
+ This allows the result to be assigned to a pre-declared return
+ value structure. The return value is a reference to the
+ internal result so that this operator can be chained in other
+ assignments to instances of result type. This is most commonly
+ used when the result is computed in to a local variable to be
+ both returned and stored in a member.
+
+ @code
+ Rv<int> zret;
+ int value;
+ // ... complex computations, result in value
+ this->m_value = zret = value;
+ // ...
+ return zret;
+ @endcode
+
+ @return A reference to the copy of @a r stored in this object.
+ */
+ Result& operator = (
+ Result const& r ///< Result to assign
+ ) {
+ _result = r;
+ return _result;
+ }
+
+ /** Add the status from another instance to this one.
+ @return A reference to @c this object.
+ */
+ template < typename U >
+ self& push(
+ Rv<U> const& that ///< Source of status messages
+ );
+
+ /** Set the result.
+
+ This differs from assignment of the function result in that the
+ return value is a reference to the @c Rv, not the internal
+ result. This makes it useful for assigning a result local
+ variable and then returning.
+
+ @code
+ Rv<int> zret;
+ int value;
+ // ... complex computation, result in value
+ return zret.set(value);
+ @endcode
+ */
+ self& set(
+ Result const& r ///< Result to store
+ );
+
+ /** Return the result.
+ @return A reference to the result value in this object.
+ */
+ Result& result();
+
+ /** Return the result.
+ @return A reference to the result value in this object.
+ */
+ Result const& result() const;
+
+ /** Return the status.
+ @return A reference to the @c errata in this object.
+ */
+ Errata& errata();
+
+ /** Return the status.
+ @return A reference to the @c errata in this object.
+ */
+ Errata const& errata() const;
+
+ /// Directly set the errata
+ self& operator = (
+ Errata const& status ///< Errata to assign.
+ );
+
+ /// Push a message on to the status.
+ self& push(
+ Errata::Message const& msg
+ );
+};
+
+/** Combine a function result and status in to an @c Rv.
+ This is useful for clients that want to declare the status object
+ and result independently.
+ */
+template < typename R > Rv<R>
+MakeRv(
+ R const& r, ///< The function result
+ Errata const& s ///< The pre-existing status object
+) {
+ return Rv<R>(r, s);
+}
+/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
+// Inline methods.
+inline Errata::Message::Message()
+ : m_id(0), m_code(Default_Code) {
+}
+inline Errata::Message::Message(std::string const& text)
+ : m_id(0), m_code(Default_Code), m_text(text) {
+}
+inline Errata::Message::Message(Id id, std::string const& text)
+ : m_id(id), m_code(Default_Code), m_text(text) {
+}
+inline Errata::Message::Message(Id id, Code code, std::string const& text)
+ : m_id(id), m_code(code), m_text(text) {
+}
+inline Errata::Message& Errata::Message::clear() {
+ m_id = 0;
+ m_code = Default_Code;
+ m_text.erase();
+ m_errata.clear();
+ return *this;
+}
+
+inline std::string const& Errata::Message::text() const { return m_text; }
+inline Errata::Code Errata::Message::getCode() const { return m_code; }
+inline Errata Errata::Message::getErrata() const { return m_errata; }
+
+inline Errata::Message& Errata::Message::set(Id id) {
+ m_id = id;
+ return *this;
+}
+inline Errata::Message& Errata::Message::set(Code code) {
+ m_code = code;
+ return *this;
+}
+inline Errata::Message& Errata::Message::set(std::string const& text) {
+ m_text = text;
+ return *this;
+}
+inline Errata::Message& Errata::Message::set(char const* text) {
+ m_text = text;
+ return *this;
+}
+inline Errata::Message& Errata::Message::set(Errata const& err) {
+ m_errata = err;
+ m_errata.doNotLog();
+ return *this;
+}
+
+inline Errata::Errata(Id id, Code code, std::string const& text) {
+ this->push(Message(id, code, text));
+}
+inline Errata::Errata(Message const& msg) {
+ this->push(msg);
+}
+
+inline Errata::operator bool() const { return this->isOK(); }
+
+inline size_t Errata::size() const {
+ return m_data ? m_data->m_items.size() : 0;
+}
+
+inline bool Errata::isOK() const {
+ return 0 == m_data
+ || 0 == m_data->size()
+ || Message::Success_Test(this->top())
+ ;
+}
+
+inline Errata&
+Errata::push(std::string const& text) {
+ this->push(Message(text));
+ return *this;
+}
+
+inline Errata&
+Errata::push(Id id, std::string const& text) {
+ this->push(Message(id, text));
+ return *this;
+}
+
+inline Errata&
+Errata::push(Id id, Code code, std::string const& text) {
+ this->push(Message(id, code, text));
+ return *this;
+}
+
+inline Errata::Message const&
+Errata::top() const {
+ return m_data ? m_data->top() : NIL_MESSAGE;
+}
+inline Errata& Errata::doNotLog() {
+ this->instance()->m_log_on_delete = false;
+ return *this;
+}
+
+inline Errata::Data::Data() : m_log_on_delete(true) {}
+inline size_t Errata::Data::size() const { return m_items.size(); }
+
+inline Errata::iterator::iterator() { }
+inline Errata::iterator::iterator(self const& that) : super(that) { }
+inline Errata::iterator::iterator(super const& that) : super(that) { }
+inline Errata::iterator& Errata::iterator::operator = (self const& that) { this->super::operator = (that); return *this; }
+inline Errata::iterator& Errata::iterator::operator = (super const& that) { this->super::operator = (that); return *this; }
+inline Errata::iterator& Errata::iterator::operator ++ () { this->super::operator ++ (); return *this; }
+inline Errata::iterator& Errata::iterator::operator -- () { this->super::operator -- (); return *this; }
+
+inline Errata::const_iterator::const_iterator() { }
+inline Errata::const_iterator::const_iterator(self const& that) : super(that) { }
+inline Errata::const_iterator::const_iterator(super const& that) : super(that) { }
+inline Errata::const_iterator& Errata::const_iterator::operator = (self const& that) { super::operator = (that); return *this; }
+inline Errata::const_iterator& Errata::const_iterator::operator = (super const& that) { super::operator = (that); return *this; }
+inline Errata::const_iterator& Errata::const_iterator::operator ++ () { this->super::operator ++ (); return *this; }
+inline Errata::const_iterator& Errata::const_iterator::operator -- () { this->super::operator -- (); return *this; }
+
+inline RvBase::RvBase() { }
+inline RvBase::RvBase(Errata const& errata) : _errata(errata) { }
+inline bool RvBase::isOK() const { return _errata; }
+inline void RvBase::clear() { _errata.clear(); }
+inline void RvBase::doNotLog() { _errata.doNotLog(); }
+
+template < typename T > Rv<T>::Rv() { }
+template < typename T > Rv<T>::Rv(Result const& r) : _result(r) { }
+template < typename T > Rv<T>::Rv(Result const& r, Errata const& errata)
+ : super(errata)
+ , _result(r) {
+}
+template < typename T > Rv<T>::operator Result const&() const {
+ return _result;
+}
+template < typename T > T const& Rv<T>::result() const { return _result; }
+template < typename T > T& Rv<T>::result() { return _result; }
+template < typename T > Errata const& Rv<T>::errata() const { return _errata; }
+template < typename T > Errata& Rv<T>::errata() { return _errata; }
+template < typename T > Rv<T>&
+Rv<T>::set(Result const& r) {
+ _result = r;
+ return *this;
+}
+template < typename T > Rv<T>&
+Rv<T>::operator = (Errata const& errata) {
+ _errata = errata;
+ return *this;
+}
+template < typename T > Rv<T>&
+Rv<T>::push(Errata::Message const& msg) {
+ _errata.push(msg);
+ return *this;
+}
+template < typename T > template < typename U > Rv<T>&
+Rv<T>::push(Rv<U> const& that) {
+ _errata.push(that.errata());
+ return *this;
+}
+/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
+} // namespace ts
+
+# endif // TS_ERRATA_HEADER