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/20 16:17:56 UTC
svn commit: r1037235 [1/2] -
/trafficserver/traffic/branches/wccp/proxy/tsconfig/
Author: amc
Date: Sat Nov 20 15:17:55 2010
New Revision: 1037235
URL: http://svn.apache.org/viewvc?rev=1037235&view=rev
Log:
Initial commit of TsConfig library.
Added:
trafficserver/traffic/branches/wccp/proxy/tsconfig/
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/Makefile.am
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/TsConfigLexer.h
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
Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.cc?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.cc (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.cc Sat Nov 20 15:17:55 2010
@@ -0,0 +1,283 @@
+/** @file
+ Errata implementation.
+ */
+/*
+ * Copyright 2005-2010 Network Geographics, Inc.
+ * http://www.network-geographics.com
+ * All rights reserved.
+ * Licensed to Apache Software Foundation.
+ */
+
+# include "Errata.h"
+# include <iostream>
+# include <sstream>
+# include <iomanip>
+# include <algorithm>
+# include <memory.h>
+
+namespace ts {
+
+/** List of sinks for abandoned erratum.
+ */
+namespace {
+ std::deque<Errata::Sink::Handle> Sink_List;
+}
+
+std::string const Errata::DEFAULT_GLUE("\n");
+Errata::Message const Errata::NIL_MESSAGE;
+Errata::Code Errata::Message::Default_Code = 0;
+Errata::Message::SuccessTest const Errata::Message::DEFAULT_SUCCESS_TEST =
+ &Errata::Message::isCodeZero;
+Errata::Message::SuccessTest Errata::Message::Success_Test =
+ Errata::Message::DEFAULT_SUCCESS_TEST;
+
+bool
+Errata::Message::isCodeZero(Message const& msg) {
+ return msg.m_code == 0;
+}
+
+void
+Errata::Data::push(Message const& msg) {
+ m_items.push_back(msg);
+}
+
+Errata::Message const&
+Errata::Data::top() const {
+ return m_items.size() ? m_items.back() : NIL_MESSAGE ;
+}
+
+inline Errata::Errata(ImpPtr const& ptr)
+ : m_data(ptr) {
+}
+
+Errata::Data::~Data() {
+ if (m_log_on_delete) {
+ Errata tmp(this); // because client API requires a wrapper.
+ std::deque<Errata::Sink::Handle>::iterator spot, limit;
+ for ( spot = Sink_List.begin(), limit = Sink_List.end();
+ spot != limit;
+ ++spot
+ ) {
+ (**spot)(tmp);
+ }
+ tmp.m_data.release(); // don't delete this again.
+ }
+}
+
+Errata::Errata() {
+}
+
+Errata::Errata(self const& that)
+ : m_data(that.m_data) {
+}
+
+Errata::Errata(std::string const& text) {
+ this->push(text);
+}
+
+Errata::Errata(Id id, std::string const& text) {
+ this->push(id, text);
+}
+
+Errata::~Errata() {
+}
+
+/* This forces the errata to have a data object that only it references.
+ If we're sharing the data, clone. If there's no data, allocate.
+ This is used just before a write operation to have copy on write semantics.
+ */
+Errata::Data*
+Errata::pre_write() {
+ if (m_data) {
+ if (m_data.useCount() > 1) {
+ m_data = new Data(*m_data); // clone current data
+ }
+ } else { // create new data
+ m_data = new Data;
+ }
+ return m_data.get();
+}
+
+// Just create an instance if needed.
+Errata::Data*
+Errata::instance() {
+ if (!m_data) m_data = new Data;
+ return m_data.get();
+}
+
+Errata&
+Errata::push(Message const& msg) {
+ this->pre_write()->push(msg);
+ return *this;
+}
+
+Errata&
+Errata::operator=(self const& that) {
+ m_data = that.m_data;
+ return *this;
+}
+
+Errata&
+Errata::operator = (Message const& msg) {
+ // Avoid copy on write in the case where we discard.
+ if (!m_data || m_data.useCount() > 1) {
+ this->clear();
+ this->push(msg);
+ } else {
+ m_data->m_items.clear();
+ m_data->push(msg);
+ }
+ return *this;
+}
+
+Errata&
+Errata::join(self const& that) {
+ if (that.m_data) {
+ this->pre_write();
+ m_data->m_items.insert(
+ m_data->m_items.end(),
+ that.m_data->m_items.begin(),
+ that.m_data->m_items.end()
+ );
+ }
+ return *this;
+}
+
+void
+Errata::pop() {
+ if (m_data && m_data->size()) {
+ this->pre_write()->m_items.pop_front();
+ }
+ return;
+}
+
+void
+Errata::clear() {
+ m_data.reset(0);
+}
+
+/* We want to allow iteration on empty / nil containers because that's very
+ convenient for clients. We need only return the same value for begin()
+ and end() and everything works as expected.
+
+ However we need to be a bit more clever for VC 8. It checks for
+ iterator compatibility, i.e. that the iterators are not
+ invalidated and that they are for the same container. It appears
+ that default iterators are not compatible with anything. So we
+ use static container for the nil data case.
+ */
+static Errata::Container NIL_CONTAINER;
+
+Errata::iterator
+Errata::begin() {
+ return m_data ? m_data->m_items.rbegin() : NIL_CONTAINER.rbegin();
+}
+
+Errata::const_iterator
+Errata::begin() const {
+ return m_data ? static_cast<Data const&>(*m_data).m_items.rbegin()
+ : static_cast<Container const&>(NIL_CONTAINER).rbegin();
+}
+
+Errata::iterator
+Errata::end() {
+ return m_data ? m_data->m_items.rend() : NIL_CONTAINER.rend();
+}
+
+Errata::const_iterator
+Errata::end() const {
+ return m_data ? static_cast<Data const&>(*m_data).m_items.rend()
+ : static_cast<Container const&>(NIL_CONTAINER).rend();
+}
+
+void
+Errata::registerSink(Sink::Handle const& s) {
+ Sink_List.push_back(s);
+}
+
+std::ostream&
+Errata::write(
+ std::ostream& out,
+ int offset,
+ int indent,
+ int shift,
+ char const* lead
+) const {
+ for ( const_iterator spot = this->begin(), limit = this->end();
+ spot != limit;
+ ++spot
+ ) {
+ if ((offset + indent) > 0)
+ out << std::setw(indent + offset) << std::setfill(' ')
+ << ((indent > 0 && lead) ? lead : " ");
+
+ out << spot->m_id << " [" << spot->m_code << "]: " << spot->m_text
+ << std::endl
+ ;
+ if (spot->getErrata().size())
+ spot->getErrata().write(out, offset, indent+shift, shift, lead);
+
+ }
+ return out;
+}
+
+size_t
+Errata::write(
+ char *buff,
+ size_t n,
+ int offset,
+ int indent,
+ int shift,
+ char const* lead
+) const {
+ std::ostringstream out;
+ std::string text;
+ this->write(out, offset, indent, shift, lead);
+ text = out.str();
+ memcpy(buff, text.data(), std::min(n, text.size()));
+ return text.size();
+}
+
+std::ostream& operator<< (std::ostream& os, Errata const& err) {
+ return err.write(os, 0, 0, 2, "> ");
+}
+
+# if USING_BOOST
+
+std::ostream&
+errata::format(std::ostream& s, std::string const& fmt, std::string const& glue) const {
+ return this->format(s, boost::format(fmt), glue);
+}
+
+std::ostream&
+errata::format(std::ostream& s, boost::format const& fmt, std::string const& glue) const {
+ if (_data) {
+ bool inside = false;
+ boost::format f(fmt);
+ f.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
+ const_iterator spot(this->begin()), limit(this->end());
+ while (spot != limit) {
+ if (inside) s << glue;
+ s << ( f % spot->_id % spot->_text );
+ inside = true;
+ ++spot;
+ }
+ }
+ return s;
+}
+
+std::string
+errata::format(std::string const& fmt, std::string const& glue) const {
+ return this->format(boost::format(fmt), glue);
+}
+
+std::string
+errata::format(boost::format const& fmt, std::string const& glue) const {
+ std::ostringstream s;
+ this->format(s, fmt, glue);
+ return s.str();
+}
+
+# endif
+
+} // namespace ngeo
Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.h?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.h (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/Errata.h Sat Nov 20 15:17:55 2010
@@ -0,0 +1,928 @@
+# 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;
+
+ /** Join @a that to @c this errata.
+ Messages from @a that are put on the top of the
+ stack in @c this.
+ */
+ self& join(self const& 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
Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/IntrusivePtr.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/IntrusivePtr.h?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/IntrusivePtr.h (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/IntrusivePtr.h Sat Nov 20 15:17:55 2010
@@ -0,0 +1,600 @@
+/* Copyright (c) 2006-2010 Network Geographics.
+ * All rights reserved.
+ * Licensed to the Apache Software Foundation.
+ */
+/* ----------------------------------------------------------------------- */
+# if !defined(ATS_INTRUSIVE_PTR_HEADER)
+# define ATS_INTRUSIVE_PTR_HEADER
+/* ----------------------------------------------------------------------- */
+# include <sys/types.h>
+# include <assert.h>
+# include <functional>
+
+namespace ts {
+/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
+/** @file
+
+ This is a simple shared pointer class for restricted use. It is not a
+ completely general class. The most significant missing feature is the
+ lack of thread safety. For its intended use, this is acceptable and
+ provides a performance improvement. However, it does restrict how the
+ class may be used.
+
+ This style of shared pointer also requires explicit support from the
+ target class, which must provide an internal reference counter.
+
+ */
+/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
+class IntrusivePtrCounter;
+
+/** This class exists solely to be declared a friend of @c IntrusivePtrCounter.
+
+ @internal This is done because we can't declare the template a
+ friend, so rather than burden the client with the declaration we
+ do it here. It provides a single method that allows the smart pointer
+ to get access to the protected reference count.
+
+ */
+class IntrusivePtrBase {
+public:
+ /// Type used for reference counter.
+ typedef long Counter;
+protected:
+ Counter* getCounter(
+ IntrusivePtrCounter* c ///< Cast object with reference counter.
+ ) const;
+};
+/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
+/** Reference counter mixin.
+
+ To add support for @c IntrusivePtr to class @a T, it
+ should inherit from @c IntrusivePtrCounter<T> in order to
+
+ - provide a reference count member
+ - force the reference count to initialize to zero
+ - define the add and release global functions required by @c IntrusivePtr
+
+ In general this class should be inherited publicly. This will
+ provide methods which mimic the @c Boost.shared_ptr interface ( @c
+ unique() , @c use_count() ).
+
+ If this class is not inherited publically or the destructor is
+ non-public then the host class (@a T) must declare this class ( @c
+ reference_counter<T> ) as a friend.
+
+ @internal Due to changes in the C++ standard and design decisions
+ in gcc, it is no longer possible to declare a template parameter
+ as a friend class. (Basically, you can't use a typedef in a
+ friend declaration and gcc treats template parameters as
+ typedefs).
+
+ @note You can use this with insulated (by name only) classes. The
+ important thing is to make sure that any such class that uses @c
+ IntrusivePtr has all of its constructors and destructors declared
+ in the header and defined in the implementation translation
+ unit. If the compiler generates any of those, it will not compile
+ due to missing functions or methods
+
+ */
+class IntrusivePtrCounter {
+ friend class IntrusivePtrBase;
+public:
+ /** Copy constructor.
+
+ @internal We have to define this to explicitly _not_ copy the
+ reference count. Otherwise any client that uses a default copy
+ constructor will _copy the ref count into the new object_. That
+ way lies madness.
+ */
+
+ IntrusivePtrCounter(
+ IntrusivePtrCounter const& ///< Source object.
+ );
+
+ /** Assignment operator.
+
+ @internal We need this for the same reason as the copy
+ constructor. The reference counter must not participate in
+ assignment.
+ */
+ IntrusivePtrCounter& operator = (
+ IntrusivePtrCounter const&
+ );
+
+protected:
+ IntrusivePtrBase::Counter m_intrusive_pointer_reference_count;
+ /// Default constructor (0 init counter).
+ /// @internal Only subclasses can access this.
+ IntrusivePtrCounter();
+};
+/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
+/** Shared pointer.
+
+ This is a reference counted smart pointer. A single object is jointly
+ ownded by a set of pointers. When the last of the pointers is destructed
+ the target object is also destructed.
+
+ The smart pointer actions can be changed through class specific policy
+ by specializing the @c IntrusivePtrPolicy template class.
+*/
+template < typename T >
+class IntrusivePtr : private IntrusivePtrBase {
+private: /* don't pollute client with these typedefs */
+ typedef IntrusivePtrBase super; ///< Parent type.
+ typedef IntrusivePtr self; ///< Self reference type.
+
+public:
+ /// Promote type for reference counter.
+ typedef super::Counter Counter;
+
+ /// Default constructor (0 initialized).
+ IntrusivePtr();
+ /// Construct from instance.
+ /// The instance becomes referenced and owned by the pointer.
+ IntrusivePtr(T* obj);
+ /// Destructor.
+ ~IntrusivePtr();
+
+ /// Copy constructor.
+ IntrusivePtr(const self& src);
+ /// Self assignement.
+ self& operator = (const self& src);
+ /** Assign from instance.
+ The instance becomes referenced and owned by the pointer.
+ The reference to the current object is dropped.
+ */
+ self& operator = (
+ T* obj ///< Target instance.
+ );
+
+ /** Assign from instance.
+ The instance becomes referenced and owned by the pointer.
+ The reference to the current object is dropped.
+ @note A synonym for @c operator= for compatibility.
+ */
+ self& assign (
+ T* obj ///< Target instance.
+ );
+
+ /** Assign from instance.
+ The instance becomes referenced and owned by the pointer.
+ The reference to the current object is dropped.
+ */
+ void reset(T* obj);
+ /** Clear reference without cleanup.
+
+ This unsets this smart pointer and decrements the reference
+ count, but does @b not perform any finalization on the
+ target object. This can easily lead to memory leaks and
+ in some sense vitiates the point of this class, but it is
+ occasionally the right thing to do. Use with caution.
+
+ @return @c true if there are no references upon return,
+ @c false if the reference count is not zero.
+ */
+ bool release();
+
+ /// Test if the pointer is zero (@c NULL).
+ bool isNull() const;
+
+ /// Member dereference.
+ T* operator -> () const;
+ /// Dereference.
+ T& operator * () const;
+ /// Access raw pointer.
+ T* get() const;
+
+ /** User conversion to raw pointer.
+
+ @internal allow implicit conversion to the underlying
+ pointer. This allows for the form "if (handle)" and is not
+ particularly dangerous (as it would be for a scope_ptr or
+ shared_ptr) because the counter is carried with the object and
+ so can't get lost or duplicated.
+
+ */
+ operator T* () const;
+
+ /** Cross type construction.
+ This succeeds if an @a X* can be implicitly converted to a @a T*.
+ */
+ template <
+ typename X ///< Foreign pointer type.
+ > IntrusivePtr(
+ IntrusivePtr<X> const& that ///< Foreign pointer.
+ );
+
+ /** Cross type assignment.
+ This succeeds if an @a X* can be implicitily converted to a @a T*.
+ */
+ template <
+ typename X ///< Foreign pointer type.
+ > self& operator = (
+ IntrusivePtr<X> const& that ///< Foreign pointer.
+ );
+
+ /// Check for multiple references.
+ /// @return @c true if more than one smart pointer references the object,
+ /// @c false otherwise.
+ bool isShared() const;
+ /// Check for a single reference (@c shared_ptr compatibility)
+ /// @return @c true if this object is not shared.
+ bool unique() const;
+ /// Reference count.
+ /// @return Number of references.
+ Counter useCount() const;
+private:
+ T* m_obj; ///< Pointer to object.
+
+ /// Reference @a obj.
+ void set(
+ T* obj ///< Target object.
+ );
+ /// Drop the current reference.
+ void unset();
+
+ /// Get a pointer to the reference counter of the target object.
+ Counter* getCounter() const;
+};
+
+/** Pointer dynamic cast.
+ This allows a smart pointer to be cast from one type to another.
+ It must be used when the types do not implicitly convert (generally
+ a downcast).
+
+ @code
+ class A { ... };
+ class B : public A { ... };
+ IntrusivePtr<A> really_b(new B);
+ InstruivePtr<B> the_b;
+ the_b = dynamic_ptr_cast<B>(really_b);
+ @endcode
+*/
+template <
+ typename T, ///< Target type.
+ typename X ///< Source type.
+> IntrusivePtr<T> dynamic_ptr_cast(
+ IntrusivePtr<X> const& src ///< Source pointer.
+) {
+ return IntrusivePtr<T>(dynamic_cast<T*>(src.get()));
+}
+
+/** Pointer cast.
+ This allows a smart pointer to be cast from one type to another.
+ It must be used when the types do not implicitly convert (generally
+ a downcast). This uses @c static_cast and so performs only compile
+ time checks.
+
+ @code
+ class A { ... };
+ class B : public A { ... };
+ IntrusivePtr<A> really_b(new B);
+ IntrusivePtr<B> the_b;
+ the_b = ptr_cast<B>(really_b);
+ @endcode
+*/
+template <
+ typename T, ///< Target type.
+ typename X ///< Source type.
+> IntrusivePtr<T> ptr_cast(
+ IntrusivePtr<X> const& src ///< Source pointer.
+) {
+ return IntrusivePtr<T>(static_cast<T*>(src.get()));
+}
+/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
+/** Default policy class for intrusive pointers.
+
+ This allows per type policy, although not per target instance.
+ Clients can override policy by specializing this class for the
+ target type.
+
+ @code
+ template <> IntrusivePtrPolicy<SomeType>
+ : IntrusivePtrDefaultPolicy {
+ ... Redefinition of methods and nested types ...
+ };
+ @endcode
+
+ The inherited class will provide the default definitions so you can
+ override only what is different. Although this can be omitted if you
+ override everything, it is more robust for maintenance to inherit
+ anyway.
+*/
+
+template <typename T>
+class IntrusivePtrPolicy {
+public:
+ /// Called when the pointer is dereferenced.
+ /// Default is empty (no action).
+ static void dereferenceCheck(
+ T* ///< Target object.
+ );
+
+ /** Perform clean up on a target object that is no longer referenced.
+
+ Default is calling @c delete. Any specialization that overrides this
+ @b must clean up the object. The primary use of this is to perform
+ a clean up other than @c delete.
+
+ @note When this is called, the target object reference count
+ is zero. If it is necessary to pass a smart pointer to the
+ target object, it will be necessary to call
+ @c IntrusivePtr::release to drop the reference without
+ another finalization. Further care must be taken that none of
+ the called logic keeps a copy of the smart pointer. Use with
+ caution.
+ */
+ static void finalize(
+ T* t ///< Target object.
+ );
+ /// Strict weak order for STL containers.
+ class Order
+ : public std::binary_function< IntrusivePtr<T>, IntrusivePtr<T>, bool> {
+ public:
+ /// Default constructor.
+ Order() {
+ }
+ /// Compare by raw pointer.
+ bool operator() (
+ IntrusivePtr<T> const& lhs, ///< Left hand operand.
+ IntrusivePtr<T> const& rhs ///< Right hand operand.
+ ) const;
+ };
+};
+
+struct IntrusivePtrDefaultPolicyTag {};
+typedef IntrusivePtrPolicy<IntrusivePtrDefaultPolicyTag> IntrusivePtrDefaultPolicy;
+/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
+/* Inline Methods */
+inline IntrusivePtrCounter::IntrusivePtrCounter()
+ : m_intrusive_pointer_reference_count(0) {
+}
+
+inline IntrusivePtrCounter::IntrusivePtrCounter(IntrusivePtrCounter const&)
+ : m_intrusive_pointer_reference_count(0) {
+}
+
+inline IntrusivePtrCounter&
+IntrusivePtrCounter::operator = (IntrusivePtrCounter const&) {
+ return *this;
+}
+
+inline IntrusivePtrBase::Counter*
+IntrusivePtrBase::getCounter(IntrusivePtrCounter* c) const {
+ return &(c->m_intrusive_pointer_reference_count);
+}
+/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
+template < typename T > void
+IntrusivePtrPolicy<T>::dereferenceCheck(T*) {
+}
+
+template < typename T > void
+IntrusivePtrPolicy<T>::finalize(T* obj) {
+ delete obj;
+}
+
+template < typename T > bool
+IntrusivePtrPolicy<T>::Order::operator()(
+ IntrusivePtr<T> const& lhs,
+ IntrusivePtr<T> const& rhs
+) const {
+ return lhs.get() < rhs.get();
+}
+/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
+template < typename T >
+IntrusivePtr<T>::IntrusivePtr()
+ : m_obj(0) {
+}
+
+template < typename T >
+IntrusivePtr<T>::IntrusivePtr(T* obj) {
+ this->set(obj);
+}
+
+template < typename T >
+IntrusivePtr<T>::~IntrusivePtr() {
+ this->unset();
+}
+
+template < typename T >
+IntrusivePtr<T>::IntrusivePtr(const self& that) {
+ this->set(that.m_obj);
+}
+
+template < typename T >
+template < typename X >
+IntrusivePtr<T>::IntrusivePtr(
+ IntrusivePtr<X> const& that ///< Foreign pointer.
+) : super(that.get()) {
+}
+
+template < typename T > IntrusivePtr<T>&
+IntrusivePtr<T>::operator = (const self& that) {
+ this->reset(that.m_obj);
+ return *this;
+}
+
+template < typename T >
+template < typename X >
+IntrusivePtr<T>&
+IntrusivePtr<T>::operator = (
+ IntrusivePtr<X> const& that ///< Foreign pointer.
+) {
+ this->reset(that.get());
+ return *this;
+}
+
+template < typename T > IntrusivePtr<T>&
+IntrusivePtr<T>::operator = (T* obj) {
+ this->reset(obj);
+ return *this;
+}
+
+template < typename T > IntrusivePtr<T>&
+IntrusivePtr<T>::assign (T* obj) {
+ return *this = obj;
+}
+
+template < typename T > T*
+IntrusivePtr<T>::operator -> () const {
+ IntrusivePtrPolicy<T>::dereferenceCheck(m_obj);
+ return m_obj;
+}
+
+template < typename T > T&
+IntrusivePtr<T>::operator * () const {
+ IntrusivePtrPolicy<T>::dereferenceCheck(m_obj);
+ return *m_obj;
+}
+
+template < typename T > T*
+IntrusivePtr<T>::get() const {
+ IntrusivePtrPolicy<T>::dereferenceCheck(m_obj);
+ return m_obj;
+}
+
+template < typename T > typename IntrusivePtr<T>::Counter*
+IntrusivePtr<T>::getCounter() const {
+ return super::getCounter(static_cast<IntrusivePtrCounter*>(m_obj));
+}
+
+/* The Set/Unset methods are the basic implementation of our
+ * reference counting. The Reset method is the standard way
+ * of invoking the pair, although splitting them allows some
+ * additional efficiency in certain situations.
+ */
+
+/* set and unset are two half operations that don't do checks.
+ It is the callers responsibility to do that.
+*/
+
+template < typename T > void
+IntrusivePtr<T>::unset() {
+ if (0 != m_obj) {
+ /* magic: our target is required to inherit from IntrusivePtrCounter,
+ * which provides a protected counter variable and access via our
+ * super class. We call the super class method to get a raw pointer
+ * to the counter variable.
+ */
+ Counter* cp = this->getCounter();
+
+ /* If you hit this assert you've got a cycle of objects that
+ reference each other. A delete in the cycle will eventually
+ result in one of the objects getting deleted twice, which is
+ what this assert indicates.
+ */
+ assert(*cp);
+
+ if (0 == --*cp) {
+ IntrusivePtrPolicy<T>::finalize(m_obj);
+ }
+ m_obj = 0;
+ }
+}
+
+template < typename T > void
+IntrusivePtr<T>::set(T* obj) {
+ m_obj = obj; /* update to new object */
+ if (0 != m_obj) /* if a real object, bump the ref count */
+ ++(*(this->getCounter()));
+}
+
+template < typename T > void
+IntrusivePtr<T>::reset(T* obj) {
+ if (obj != m_obj) {
+ this->unset();
+ this->set(obj);
+ }
+}
+
+template < typename T > bool
+IntrusivePtr<T>::release() {
+ bool zret = true;
+ if (m_obj) {
+ Counter* cp = this->getCounter();
+ zret = *cp <= 1;
+ // If the client is using this method, they're doing something funky
+ // so be extra careful with the reference count.
+ if (*cp > 0) --*cp;
+ m_obj = 0;
+ }
+ return zret;
+}
+
+/* Simple method to check for invalid pointer */
+template < typename T > bool
+IntrusivePtr<T>::isNull() const {
+ return 0 == m_obj;
+}
+
+/* Pointer comparison */
+template < typename T > bool
+operator == (IntrusivePtr<T> const& lhs, IntrusivePtr<T> const& rhs) {
+ return lhs.get() == rhs.get();
+}
+
+template < typename T > bool
+operator != (IntrusivePtr<T> const& lhs, IntrusivePtr<T> const& rhs) {
+ return lhs.get() != rhs.get();
+}
+
+template < typename T > bool
+operator < (IntrusivePtr<T> const& lhs, IntrusivePtr<T> const& rhs) {
+ return lhs.get() < rhs.get();
+}
+
+template < typename T > bool
+operator == (IntrusivePtr<T> const& lhs, int rhs) {
+ assert(0 == rhs);
+ return lhs.get() == 0;
+}
+
+template < typename T > bool
+operator == (int lhs, IntrusivePtr<T> const& rhs) {
+ assert(0 == lhs);
+ return rhs.get() == 0;
+}
+
+template < typename T > bool
+operator != (int lhs, IntrusivePtr<T> const& rhs) {
+ return !(lhs == rhs);
+}
+
+template < typename T > bool
+operator != (IntrusivePtr<T> const& lhs, int rhs) {
+ return !(lhs == rhs);
+}
+
+template < typename T >
+IntrusivePtr<T>::operator T* () const {
+ return m_obj;
+}
+
+template < typename T> bool
+IntrusivePtr<T>::isShared() const {
+ return m_obj && *(this->getCounter()) > 1;
+}
+
+template < typename T> bool
+IntrusivePtr<T>::unique() const {
+ return 0 == m_obj || *(this->getCounter()) <= 1;
+}
+
+template < typename T> typename IntrusivePtr<T>::Counter
+IntrusivePtr<T>::useCount() const {
+ return m_obj ? *(this->getCounter()) : 0;
+}
+/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
+} // namespace ats
+/* ----------------------------------------------------------------------- */
+# endif // ATS_INTRUSIVE_PTR_HEADER
+
Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/Makefile.am
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/Makefile.am?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/Makefile.am (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/Makefile.am Sat Nov 20 15:17:55 2010
@@ -0,0 +1,51 @@
+#
+# Makefile.am for TS Config module.
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/proxy/mgmt2/api2/include \
+ -DPKGSYSUSER=\"$(pkgsysuser)\"
+
+noinst_LIBRARIES = libtsconfig.a
+#noinst_PROGRAMS = test-cache
+
+libtsconfig_a_SOURCES = \
+ Errata.cc \
+ Errata.h \
+ TsErrataUtil.cc \
+ TsErrata.h \
+ TsBuffer.h \
+ NumericType.h \
+ IntrusivePtr.h \
+ TsBuilder.cc \
+ TsBuilder.h \
+ TsValue.cc \
+ TsValue.h \
+ TsConfig.tab.c \
+ TsConfig.lex.c
+
+TsConfig.tab.c: TsConfig.y
+ bison -d --name-prefix tsconfig TsConfig.y
+
+TsConfig.lex.c: TsConfig.flex
+ flex --outfile TsConfig.lex.c TsConfig.flex
+
+#test_cache_SOURCES = \
+# wccp-test-cache.cc
+
+#test_cache_LDADD = ./libwccp.a -lconfig++ -lcrypto
\ No newline at end of file
Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/NumericType.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/NumericType.h?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/NumericType.h (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/NumericType.h Sat Nov 20 15:17:55 2010
@@ -0,0 +1,163 @@
+/* Copyright (c) 2006-2010 Network Geographics.
+ * All rights reserved.
+ * Licensed to the Apache Software Foundation.
+ */
+/* ------------------------------------------------------------------------ */
+# if !defined(TS_NUMERIC_TYPE_HEADER)
+# define TS_NUMERIC_TYPE_HEADER
+
+# include <limits>
+/* ----------------------------------------------------------------------- */
+namespace ts {
+/* ----------------------------------------------------------------------- */
+/** @file
+
+ Create a distinct type from a builtin numeric type.
+
+ This template class converts a basic type into a class, so that
+ instances of the class act like the basic type in normal use but
+ as a distinct type when evaluating overloads. This is very handy
+ when one has several distinct value types that map to the same
+ basic type. That means we can have overloads based on the type
+ even though the underlying basic type is the same. The second
+ template argument, X, is used only for distinguishing
+ instantiations of the template with the same base type. It doesn't
+ have to exist. One can declare an instantiation like
+
+ @code
+ typedef NumericType<int, struct some_random_tag_name> some_random_type;
+ @endcode
+
+ It is not necessary to ever mention some_random_tag_name
+ again. All we need is the entry in the symbol table.
+ */
+
+// Forward declare.
+template < typename T, typename X > class NumericType;
+
+/// @cond NOT_DOCUMENTED
+/** Support template for resolving operator ambiguity.
+
+ Not for client use.
+
+ @internal This resolves the problem when @a T is not @c int.
+ In that case, because raw numbers are @c int and the overloading
+ rule changes created an ambiguity, gcc won't distinguish between
+ class methods and builtins because @c NumericType has a user
+ conversion to @a T. So signature <tt>(NumericType, T)</tt>
+ and <tt>(T, int)</tt> are considered equivalent. This defines
+ the @c int operators explicitly. We inherit it so if @a T is
+ @c int, these are silently overridden.
+
+ @internal Note that we don't have to provide an actual implementation
+ for these operators. Funky, isn't it?
+*/
+template <
+ typename T, ///< Base numeric type.
+ typename X ///< Distinguishing tag type.
+> class NumericType_int_operators {
+public:
+ NumericType<T,X>& operator += ( int t );
+ NumericType<T,X>& operator -= ( int t );
+
+ // Must have const and non-const versions.
+ NumericType<T,X> operator + ( int t );
+ NumericType<T,X> operator - ( int t );
+ NumericType<T,X> operator + ( int t ) const;
+ NumericType<T,X> operator - ( int t ) const;
+};
+
+template < typename T, typename X > NumericType<T,X>
+operator + ( int t, NumericType_int_operators<T,X> const& );
+
+template < typename T, typename X > NumericType<T,X>
+operator - ( int t, NumericType_int_operators<T,X> const& );
+
+/// @endcond
+
+/** Numeric type template.
+ */
+template <
+ typename T, ///< Base numeric type.
+ typename X ///< Distinguishing tag type.
+> class NumericType : public NumericType_int_operators<T,X> {
+public:
+ typedef T raw_type; //!< Base builtin type.
+ typedef NumericType self; //!< Self reference type.
+
+ using NumericType_int_operators<T,X>::operator +=;
+ using NumericType_int_operators<T,X>::operator -=;
+ using NumericType_int_operators<T,X>::operator +;
+ using NumericType_int_operators<T,X>::operator -;
+
+ /// Default constructor, uninitialized.
+ NumericType();
+ //! Construct from implementation type.
+ NumericType(
+ raw_type const t ///< Initialized value.
+ );
+ //! Assignment from implementation type.
+ NumericType & operator = (raw_type const t);
+ //! Self assignment.
+ NumericType & operator = (self const& that);
+
+ /// User conversion to implementation type.
+ /// @internal If we have just a single const method conversion to a copy
+ /// of the @c raw_type then the stream operators don't work. Only a CR
+ /// conversion operator satisifies the argument matching.
+ operator raw_type const& () const { return _t; }
+ /// User conversion to implementation type.
+ operator raw_type& () { return _t; }
+ /// Explicit conversion to host type
+ raw_type raw() const { return _t; }
+
+ // User conversions to raw type provide the standard comparison operators.
+ self& operator += ( self const& that );
+ self& operator -= ( self const& that );
+
+ self& operator += ( raw_type t );
+ self& operator -= ( raw_type t );
+
+ self operator + ( self const& that );
+ self operator - ( self const& that );
+
+ self operator + ( raw_type t );
+ self operator - ( raw_type t );
+
+ self& operator ++();
+ self operator ++(int);
+ self& operator --();
+ self operator --(int);
+
+private:
+ raw_type _t;
+};
+
+// Method definitions.
+template < typename T, typename X > NumericType<T,X>::NumericType() { }
+template < typename T, typename X > NumericType<T,X>::NumericType(raw_type const t) : _t(t) { }
+template < typename T, typename X > NumericType<T,X>& NumericType<T,X>::operator = (raw_type const t) { _t = t; return *this; }
+template < typename T, typename X > NumericType<T,X>& NumericType<T,X>::operator = (self const& that) { _t = that._t; return *this; }
+
+template < typename T, typename X > NumericType<T,X>& NumericType<T,X>::operator += ( self const& that ) { _t += that._t; return *this; }
+template < typename T, typename X > NumericType<T,X>& NumericType<T,X>::operator -= ( self const& that ) { _t -= that._t; return *this; }
+template < typename T, typename X > NumericType<T,X> NumericType<T,X>::operator + ( self const& that ) { return self(_t + that._t); }
+template < typename T, typename X > NumericType<T,X> NumericType<T,X>::operator - ( self const& that ) { return self(_t - that._t); }
+
+template < typename T, typename X > NumericType<T,X>& NumericType<T,X>::operator += ( raw_type t ) { _t += t; return *this; }
+template < typename T, typename X > NumericType<T,X>& NumericType<T,X>::operator -= ( raw_type t ) { _t -= t; return *this; }
+template < typename T, typename X > NumericType<T,X> NumericType<T,X>::operator + ( raw_type t ) { return self(_t + t); }
+template < typename T, typename X > NumericType<T,X> NumericType<T,X>::operator - ( raw_type t ) { return self(_t - t); }
+
+template < typename T, typename X > NumericType<T,X>& NumericType<T,X>::operator ++() { ++_t; return *this; }
+template < typename T, typename X > NumericType<T,X>& NumericType<T,X>::operator --() { --_t; return *this; }
+template < typename T, typename X > NumericType<T,X> NumericType<T,X>::operator ++(int) { self tmp(*this); ++_t; return tmp; }
+template < typename T, typename X > NumericType<T,X> NumericType<T,X>::operator --(int) { self tmp(*this); --_t; return tmp; }
+
+template < typename T, typename X > NumericType<T,X> operator + ( T const& lhs, NumericType<T,X> const& rhs ) { return rhs + lhs; }
+template < typename T, typename X > NumericType<T,X> operator - ( T const& lhs, NumericType<T,X> const& rhs ) { return NumericType<T,X>(lhs - rhs.raw()); }
+
+/* ----------------------------------------------------------------------- */
+} /* end namespace ts */
+/* ----------------------------------------------------------------------- */
+# endif // TS_NUMERIC_TYPE_HEADER
Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/TsBuffer.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/TsBuffer.h?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/TsBuffer.h (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/TsBuffer.h Sat Nov 20 15:17:55 2010
@@ -0,0 +1,156 @@
+/** @file
+ Apach Traffic Server commons.
+ Definitions that are standardized across ATS.
+ */
+
+# if defined _MSC_VER
+# include <stddef.h>
+# else
+# include <unistd.h>
+# endif
+# include <memory.h>
+
+/// Apache Traffic Server commons.
+namespace ts {
+ struct ConstBuffer;
+ /** A chunk of writable memory.
+ A convenience class because we pass this kind of pair frequently.
+ */
+ struct Buffer {
+ typedef Buffer self; ///< Self reference type.
+
+ char * _ptr; ///< Pointer to base of memory chunk.
+ size_t _size; ///< Size of memory chunk.
+
+ /// Default constructor.
+ /// Elements are in uninitialized state.
+ Buffer();
+
+ /// Construct from pointer and size.
+ Buffer(
+ char* ptr, ///< Pointer to buffer.
+ size_t n ///< Size of buffer.
+ );
+
+ /** Equality.
+ @return @c true if the @c Buffer instances are identical,
+ @c false otherwise.
+ */
+ bool operator == (self const& that) const;
+ /** Inequality.
+ @return @c true if the @c Buffer instances are different,
+ @c false otherwise.
+ */
+ bool operator != (self const& that) const;
+ /** Equality for a constant buffer.
+ @return @c true if @a that contains identical contents.
+ @c false otherwise.
+ */
+ bool operator == (ConstBuffer const& that) const;
+ /** Inequality.
+ @return @c true if the instances have different content,
+ @c false if they are identical.
+ */
+ bool operator != (ConstBuffer const& that) const;
+
+ /// Set the chunk.
+ /// Any previous values are discarded.
+ /// @return @c this object.
+ self& set(
+ char* ptr, ///< Buffer address.
+ size_t n ///< Buffer size.
+ );
+ /// Reset to empty.
+ self& reset();
+ };
+
+ /** A chunk of read only memory.
+ A convenience class because we pass this kind of pair frequently.
+ */
+ struct ConstBuffer {
+ typedef ConstBuffer self; ///< Self reference type.
+
+ char const * _ptr; ///< Pointer to base of memory chunk.
+ size_t _size; ///< Size of memory chunk.
+
+ /// Default constructor.
+ /// Elements are in uninitialized state.
+ ConstBuffer();
+
+ /// Construct from pointer and size.
+ ConstBuffer(
+ char const * ptr, ///< Pointer to buffer.
+ size_t n ///< Size of buffer.
+ );
+ /// Construct from writable buffer.
+ ConstBuffer(
+ Buffer const& buffer ///< Buffer to copy.
+ );
+
+ /** Equality.
+ @return @c true if the @c Buffer instances are identical,
+ @c false otherwise.
+ */
+ bool operator == (self const& that) const;
+ /** Equality.
+ @return @c true if the @c Buffer instances are identical,
+ @c false otherwise.
+ */
+ bool operator == (Buffer const& that) const;
+ /** Inequality.
+ @return @c true if the @c Buffer instances are different,
+ @c false otherwise.
+ */
+ bool operator != (self const& that) const;
+ /** Inequality.
+ @return @c true if the @c Buffer instances are different,
+ @c false otherwise.
+ */
+ bool operator != (Buffer const& that) const;
+ /// Assign from non-const Buffer.
+ self& operator = (
+ Buffer const& that ///< Source buffer.
+ );
+
+ /// Set the chunk.
+ /// Any previous values are discarded.
+ /// @return @c this object.
+ self& set(
+ char const * ptr, ///< Buffer address.
+ size_t n ///< Buffer size.
+ );
+ /// Reset to empty.
+ self& reset();
+ };
+
+ // ----------------------------------------------------------
+ // Inline implementations.
+
+ inline Buffer::Buffer() { }
+ inline Buffer::Buffer(char* ptr, size_t n) : _ptr(ptr), _size(n) { }
+ inline Buffer& Buffer::set(char* ptr, size_t n) { _ptr = ptr; _size = n; return *this; }
+ inline Buffer& Buffer::reset() { _ptr = 0; _size = 0 ; return *this; }
+ inline bool Buffer::operator != (self const& that) const { return ! (*this == that); }
+ inline bool Buffer::operator != (ConstBuffer const& that) const { return ! (*this == that); }
+ inline bool Buffer::operator == (self const& that) const {
+ return _size == that._size && 0 == memcmp(_ptr, that._ptr, _size);
+ }
+ inline bool Buffer::operator == (ConstBuffer const& that) const {
+ return _size == that._size && 0 == memcmp(_ptr, that._ptr, _size);
+ }
+
+ inline ConstBuffer::ConstBuffer() { }
+ inline ConstBuffer::ConstBuffer(char const* ptr, size_t n) : _ptr(ptr), _size(n) { }
+ inline ConstBuffer::ConstBuffer(Buffer const& that) : _ptr(that._ptr), _size(that._size) { }
+ inline ConstBuffer& ConstBuffer::set(char const* ptr, size_t n) { _ptr = ptr; _size = n; return *this; }
+ inline ConstBuffer& ConstBuffer::reset() { _ptr = 0; _size = 0 ; return *this; }
+ inline bool ConstBuffer::operator != (self const& that) const { return ! (*this == that); }
+ inline bool ConstBuffer::operator != (Buffer const& that) const { return ! (*this == that); }
+ inline bool ConstBuffer::operator == (self const& that) const {
+ return _size == that._size && 0 == memcmp(_ptr, that._ptr, _size);
+ }
+ inline ConstBuffer& ConstBuffer::operator = (Buffer const& that) { _ptr = that._ptr ; _size = that._size; return *this; }
+ inline bool ConstBuffer::operator == (Buffer const& that) const {
+ return _size == that._size && 0 == memcmp(_ptr, that._ptr, _size);
+ }
+}
Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/TsBuilder.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/TsBuilder.cc?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/TsBuilder.cc (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/TsBuilder.cc Sat Nov 20 15:17:55 2010
@@ -0,0 +1,157 @@
+# include "TsBuilder.h"
+# include <TsErrataUtil.h>
+# include "TsConfigLexer.h"
+
+// Access to terminal token values.
+extern "C" {
+# include "TsConfig.tab.h"
+};
+
+# define PRE "Configuration Parser: "
+
+namespace ts { namespace config {
+
+Builder&
+Builder::init() {
+ // Simple: Resize the vector and then fill in each element to
+ // dispatch through the static method. Callback data is a pointer
+ // to an entry in @c dispatch which contains pointer to this object
+ // and a pointer to the appropriate dispatch method.
+
+ _dispatch.resize(TS_CONFIG_N_EVENT_TYPES);
+
+ for ( size_t i = 0 ; i < TS_CONFIG_N_EVENT_TYPES ; ++i) {
+ _dispatch[i]._ptr = this;
+ _handlers.handler[i]._f = &self::dispatch;
+ _handlers.handler[i]._data = &(_dispatch[i]);
+ }
+
+ _dispatch[TsConfigEventGroupOpen]._method = &self::groupOpen;
+ _dispatch[TsConfigEventGroupName]._method = &self::groupName;
+ _dispatch[TsConfigEventGroupClose]._method = &self::groupClose;
+ _dispatch[TsConfigEventListOpen]._method = &self::listOpen;
+ _dispatch[TsConfigEventListClose]._method = &self::listClose;
+ _dispatch[TsConfigEventPathOpen]._method = &self::pathOpen;
+ _dispatch[TsConfigEventPathTag]._method = &self::pathTag;
+ _dispatch[TsConfigEventPathIndex]._method = &self::pathIndex;
+ _dispatch[TsConfigEventPathClose]._method = &self::pathClose;
+ _dispatch[TsConfigEventLiteralValue]._method = &self::literalValue;
+ _dispatch[TsConfigEventInvalidToken]._method = &self::invalidToken;
+
+ _handlers.error._data = this;
+ _handlers.error._f = &self::syntaxErrorDispatch;
+
+ return *this;
+}
+
+// Error messages here have to just be logged, as they effectively report that
+// the dispatcher can't find the builder object.
+void
+Builder::dispatch(void* data, Token* token) {
+ if (data) {
+ Handler* handler = reinterpret_cast<Handler*>(data);
+ if (handler->_ptr) {
+ if (handler->_method) {
+ ((handler->_ptr)->*(handler->_method))(*token);
+ } else {
+ msg::logf(msg::WARN, PRE "Unable to dispatch event - no method.");
+ }
+ } else {
+ msg::logf(msg::WARN, PRE "Unable to dispatch event - no builder.");
+ }
+ } else {
+ msg::logf(msg::WARN, PRE "Unable to dispatch event - no handler.");
+ }
+}
+
+int
+Builder::syntaxErrorDispatch(void* data, char const* text) {
+ return reinterpret_cast<Builder*>(data)->syntaxError(text);
+}
+
+int
+Builder::syntaxError(char const* text) {
+ msg::logf(_errata, msg::WARN, "Syntax error '%s'.", text);
+ return 0;
+}
+
+Rv<Configuration>
+Builder::build(Buffer const& buffer) {
+ yyscan_t lexer;
+ YY_BUFFER_STATE lexer_buffer_state;
+
+ _v = _config.getRoot();
+ _errata.clear();
+
+ tsconfiglex_init(&lexer);
+ tsconfigset_extra(&_handlers, lexer);
+ lexer_buffer_state = tsconfig_scan_buffer(buffer._ptr, buffer._size, lexer);
+ tsconfigparse(lexer, &_handlers);
+ tsconfig_delete_buffer(lexer_buffer_state, lexer);
+ tsconfiglex_destroy(lexer);
+
+ return MakeRv(_config, _errata);
+}
+
+void
+Builder::groupOpen(Token const&) {
+ _v = _v.makeGroup(_name);
+}
+void Builder::groupClose(Token const&) {
+ _v = _v.getParent();
+}
+void Builder::groupName(Token const& token) {
+ _name.set(token._s, token._n);
+}
+void Builder::listOpen(Token const&) {
+ _v = _v.makeList(_name);
+}
+void Builder::listClose(Token const&) {
+ _v = _v.getParent();
+}
+
+void Builder::pathOpen(Token const&) {
+ _path.reset();
+ _extent.reset();
+}
+void Builder::pathTag(Token const& token) {
+ _path.append(Buffer(token._s, token._n));
+ if (_extent._ptr) _extent._size = token._s - _extent._ptr + token._n;
+ else _extent.set(token._s, token._n);
+}
+void Builder::pathIndex(Token const& token){
+ // We take advantage of the lexer - token will always be a valid digit string
+ // that is followed by a non-digit or the FLEX required double null at the end
+ // of the input buffer.
+ _path.append(Buffer(0, static_cast<size_t>(atol(token._s))));
+ if (_extent._ptr) _extent._size = token._s - _extent._ptr + token._n;
+ else _extent.set(token._s, token._n);
+}
+
+void Builder::pathClose(Token const&) {
+ Rv<Value> cv = _v.makePath(_path, _name);
+ if (cv.isOK()) cv.result().setText(_extent);
+
+ _name.reset();
+ _extent.reset();
+}
+
+void Builder::literalValue(Token const& token) {
+ Rv<Value> cv;
+ ConstBuffer text(token._s, token._n);
+ if (INTEGER == token._type) {
+ cv = _v.makeInteger(text, _name);
+ if (!cv.isOK()) _errata.join(cv.errata());
+ } else if (STRING == token._type) {
+ ++text._ptr, text._size -= 2;
+ cv = _v.makeString(text, _name);
+ // Strip enclosing quotes.
+ if (!cv.isOK()) _errata.join(cv.errata());
+ } else {
+ msg::logf(_errata, msg::WARN, PRE "Unexpected literal type %d.", token._type);
+ }
+ _name.set(0,0); // used, so clear it.
+}
+void Builder::invalidToken(Token const&) { }
+
+}} // namespace ts::config
Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/TsBuilder.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/TsBuilder.h?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/TsBuilder.h (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/TsBuilder.h Sat Nov 20 15:17:55 2010
@@ -0,0 +1,75 @@
+# if ! defined(TS_CONFIG_BUILDER_HEADER)
+# define TS_CONFIG_BUILDER_HEADER
+
+# include "TsValue.h"
+# include "TsConfigTypes.h"
+# include "TsConfigParseEvents.h"
+
+namespace ts { namespace config {
+
+/** Class to build the configuration table from parser events.
+ */
+class Builder {
+public:
+ typedef Builder self;
+ struct Handler {
+ self* _ptr; ///< Pointer to Builder instance.
+ /// Pointer to method to invoke for this event.
+ void (self::*_method)(Token const& token);
+
+ /// Default constructor.
+ Handler();
+ };
+
+ /// Default constructor.
+ Builder();
+ /// Construct with existing configuration.
+ Builder(Configuration const& config);
+ /// Build the table.
+ /// @return The configuration or error status.
+ Rv<Configuration> build(
+ Buffer const& buffer ///< Input text.
+ );
+protected:
+ /// Dispatch table for parse events.
+ std::vector<Handler> _dispatch;
+ /// Event handler table for the parser.
+ TsConfigHandlers _handlers;
+ /// Dispatch methods
+ virtual void groupOpen(Token const& token);
+ virtual void groupClose(Token const& token);
+ virtual void groupName(Token const& token);
+ virtual void listOpen(Token const& token);
+ virtual void listClose(Token const& token);
+ virtual void pathOpen(Token const& token);
+ virtual void pathTag(Token const& token);
+ virtual void pathIndex(Token const& token);
+ virtual void pathClose(Token const& token);
+ virtual void literalValue(Token const& token);
+ virtual void invalidToken(Token const& token);
+ /// Syntax error handler
+ virtual int syntaxError(char const* text);
+ /// Static method to handle parser event callbacks.
+ static void dispatch(void* data, Token* token);
+ /// Static method for syntax errors.
+ static int syntaxErrorDispatch(void* data, char const* text);
+
+ // Building state.
+ Configuration _config; ///< Configuration to update.
+ Errata _errata; ///< Error accumulator.
+ Value _v; ///< Current value.
+ Buffer _name; ///< Pending group name, if any.
+ Buffer _extent; ///< Accumulator for multi-token text.
+ Path _path; ///< Path accumulator
+
+ /// Initialization, called from constructors.
+ self& init();
+};
+
+inline Builder::Handler::Handler() : _ptr(0), _method(0) { }
+inline Builder::Builder() { this->init(); }
+inline Builder::Builder(Configuration const& config) : _config(config) { this->init(); }
+
+}} // namespace ts::config
+
+# endif // TS_CONFIG_BUILDER_HEADER
Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfig.flex
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfig.flex?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfig.flex (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfig.flex Sat Nov 20 15:17:55 2010
@@ -0,0 +1,58 @@
+%{
+
+#include "TsConfigTypes.h"
+#include "TsConfig.tab.h"
+#include "TsConfigParseEvents.h"
+
+struct Location Lex_Location = { 0, 1 };
+
+# define YY_USER_ACTION Lex_Location._col += yyleng;
+
+# define FILL yylval->_s = yytext; yylval->_n = yyleng; yylval->_loc = Lex_Location; yylval->_loc._col -= yyleng;
+# define ZRET(t) FILL; yylval->_type = t; return t;
+# define HANDLE_EVENT(x) \
+ if (yyextra) { \
+ struct TsConfigEventHandler* h = &(yyextra->handler[TsConfigEvent##x]); \
+ if (h->_f) h->_f(h->_data, yylval); \
+ }
+%}
+
+%option header-file="TsConfig.lex.h"
+%option never-interactive yylineno reentrant bison-bridge noyywrap
+%option prefix="tsconfig"
+%option nounput noinput
+%option extra-type="struct TsConfigHandlers*"
+
+DSTRING \"(?:[^\"\\]|\\.)*\"
+SSTRING '(?:[^'\\]|\\.)*'
+QSTRING {DSTRING}|{SSTRING}
+IDENT [[:alpha:]_](?:-*[[:alnum:]_])*
+
+%x bad
+%%
+\n ++(Lex_Location._line); Lex_Location._col = 0;
+(?:[[:space:]]{-}[\n])+
+^[[:space:]]*#.*$
+\/\/.*$
+{QSTRING} ZRET(STRING);
+{IDENT} ZRET(IDENT);
+[[:digit:]]+ ZRET(INTEGER);
+\{ ZRET(GROUP_OPEN);
+\} ZRET(GROUP_CLOSE);
+\( ZRET(LIST_OPEN);
+\) ZRET(LIST_CLOSE);
+\< ZRET(PATH_OPEN);
+\> ZRET(PATH_CLOSE);
+\. ZRET(PATH_SEPARATOR);
+= ZRET(ASSIGN);
+[,;]+ ZRET(SEPARATOR);
+
+. BEGIN(bad); FILL;
+<bad>\n {
+ BEGIN(0); // Terminate bad token mode.
+ ++(Lex_Location._line); // Must bump line count.
+ HANDLE_EVENT(InvalidToken);
+ }
+<bad>[[:space:]] BEGIN(0); HANDLE_EVENT(InvalidToken);
+<bad>. ++(yylval->_n);
+%%
Added: trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfig.y
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfig.y?rev=1037235&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfig.y (added)
+++ trafficserver/traffic/branches/wccp/proxy/tsconfig/TsConfig.y Sat Nov 20 15:17:55 2010
@@ -0,0 +1,81 @@
+%code top {
+# include "TsConfigTypes.h"
+
+// Inhibit Bison definitions.
+# define YYMALLOC malloc
+# define YYFREE free
+
+# include "TsConfigParseEvents.h"
+# include "TsConfig.lex.h"
+}
+
+%code {
+# define HANDLE_EVENT(x,y) if (handlers) { \
+ struct TsConfigEventHandler* h = &(handlers->handler[TsConfigEvent##x]); \
+ if (h->_f) h->_f(h->_data, &(y)); \
+ }
+
+int tsconfigerror(yyscan_t lexer, struct TsConfigHandlers* handlers, char const* text) {
+ return (handlers && handlers->error._f) ? handlers->error._f(handlers->error._data, text) : 0;
+}
+
+}
+
+%token STRING
+%token IDENT
+%token INTEGER
+%token LIST_OPEN
+%token LIST_CLOSE
+%token GROUP_OPEN
+%token GROUP_CLOSE
+%token PATH_OPEN
+%token PATH_CLOSE
+%token PATH_SEPARATOR
+%token SEPARATOR
+%token ASSIGN
+
+%error-verbose
+%define api.pure
+%parse-param { yyscan_t lexer }
+%parse-param { struct TsConfigHandlers* handlers }
+%lex-param { yyscan_t lexer }
+
+%%
+
+config: group_items;
+
+group: group_open group_items group_close ;
+
+group_open: GROUP_OPEN { HANDLE_EVENT(GroupOpen, $1); } ;
+
+group_close: GROUP_CLOSE { HANDLE_EVENT(GroupClose, $1); } ;
+
+group_items: /* empty */ | group_items assign separator | group_items error separator ;
+
+assign: IDENT ASSIGN { HANDLE_EVENT(GroupName, $1); } value ;
+
+list: list_open list_items list_close ;
+
+list_open: LIST_OPEN { HANDLE_EVENT(ListOpen, $1); } ;
+
+list_close: LIST_CLOSE { HANDLE_EVENT(ListClose, $1); } ;
+
+list_items: /* empty */ | list_items value separator | list_items error separator;
+
+value: literal { HANDLE_EVENT(LiteralValue, $1); } | list | group | path;
+
+literal: STRING | IDENT | INTEGER ;
+
+separator: /* empty */ | SEPARATOR ;
+
+path: path_open path_item path_close;
+
+path_open: PATH_OPEN { HANDLE_EVENT(PathOpen, $1); }
+
+path_close: PATH_CLOSE { HANDLE_EVENT(PathClose, $1); }
+
+path_item: path_tag | path_item PATH_SEPARATOR path_tag ;
+
+path_tag: IDENT { HANDLE_EVENT(PathTag, $1); } | INTEGER { HANDLE_EVENT(PathIndex, $1); };
+
+%%