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/10/12 18:10:48 UTC

svn commit: r1021825 [1/4] - in /trafficserver/traffic/branches/wccp: ./ libinktomi++/ proxy/ proxy/mgmt2/ proxy/mgmt2/api2/include/ proxy/wccp/

Author: amc
Date: Tue Oct 12 16:10:47 2010
New Revision: 1021825

URL: http://svn.apache.org/viewvc?rev=1021825&view=rev
Log:
Initial patch after testing.

Added:
    trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/AtsBase.h
    trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/Errata.h
    trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/IntrusivePtr.h
    trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/NumericType.h
    trafficserver/traffic/branches/wccp/proxy/wccp/
    trafficserver/traffic/branches/wccp/proxy/wccp/AtsBaseStatic.cc
    trafficserver/traffic/branches/wccp/proxy/wccp/AtsMeta.h
    trafficserver/traffic/branches/wccp/proxy/wccp/Errata.cc
    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/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/configure.ac
    trafficserver/traffic/branches/wccp/libinktomi++/ink_resource.h
    trafficserver/traffic/branches/wccp/proxy/Makefile.am
    trafficserver/traffic/branches/wccp/proxy/mgmt2/LocalManager.cc
    trafficserver/traffic/branches/wccp/proxy/mgmt2/LocalManager.h
    trafficserver/traffic/branches/wccp/proxy/mgmt2/Main.cc
    trafficserver/traffic/branches/wccp/proxy/mgmt2/Makefile.am
    trafficserver/traffic/branches/wccp/proxy/mgmt2/RecordsConfig.cc

Modified: trafficserver/traffic/branches/wccp/configure.ac
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/configure.ac?rev=1021825&r1=1021824&r2=1021825&view=diff
==============================================================================
--- trafficserver/traffic/branches/wccp/configure.ac (original)
+++ trafficserver/traffic/branches/wccp/configure.ac Tue Oct 12 16:10:47 2010
@@ -1223,6 +1223,7 @@ AC_CONFIG_FILES([proxy/mgmt2/tools/Makef
 AC_CONFIG_FILES([proxy/mgmt2/utils/Makefile])
 AC_CONFIG_FILES([proxy/mgmt2/web2/Makefile])
 AC_CONFIG_FILES([proxy/stats/Makefile])
+AC_CONFIG_FILES([proxy/wccp/Makefile])
 AC_CONFIG_FILES([example/Makefile])
 # example plugins
 AC_CONFIG_FILES([example/add-header/Makefile])

Modified: trafficserver/traffic/branches/wccp/libinktomi++/ink_resource.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/libinktomi%2B%2B/ink_resource.h?rev=1021825&r1=1021824&r2=1021825&view=diff
==============================================================================
--- trafficserver/traffic/branches/wccp/libinktomi++/ink_resource.h (original)
+++ trafficserver/traffic/branches/wccp/libinktomi++/ink_resource.h Tue Oct 12 16:10:47 2010
@@ -120,6 +120,85 @@ void *_xfree_null(void *ptr);
 
 void xdump(void);
 
+#if defined(__cplusplus)
+/** Locally scoped holder for a chunk of memory allocated via these functions.
+    If this pointer is assigned the current memory (if any) is freed.
+    The memory is also freed when the object is destructed. This makes
+    handling temporary memory in a function more robust.
+
+    @internal A poor substitute for a real shared pointer copy on write
+    class but one step at a time. It's better than doing this by
+    hand every time.
+*/
+template <
+  typename T ///< Type of pointer.
+> class xptr {
+public:
+  typedef xptr self; ///< Self reference type.
+  /// Default constructor, zero initialized.
+  xptr() : m_ptr(0) { }
+  /// Construct from allocated memory.
+  /// @note @a ptr must refer to memory allocated @c xmalloc.
+  explicit xptr(T* ptr) : m_ptr(ptr) { }
+  /// Construct and initialized with memory for @a n instances of @a T.
+  explicit xptr(size_t n) : m_ptr(xmalloc(sizeof(T) * n)) { }
+  /// Destructor - free memory held by this instance.
+  ~xptr() { xfree(m_ptr); }
+  /// Assign memory.
+  /// @note @a ptr must be allocated via @c xmalloc.
+  self& operator = (T* ptr) {
+    xfree(m_ptr);
+    m_ptr = ptr;
+    return *this;
+  }
+  /// Auto convert to a raw pointer.
+  operator T* () { return m_ptr; }
+  /// Auto conver to raw pointer.
+  operator T const* () const { return m_ptr; }
+  /** Release memory from control of this instance.
+
+      @note Although direct assignment is forbidden due to the
+      non-obvious semantics, a pointer can be moved (@b not copied) from
+      one instance to another using this method.
+      @code
+      new_ptr = old_ptr.release();
+      @endcode
+      This is by design so any such transfer is always explicit.
+  */
+  T* release() {
+    T* zret = m_ptr;
+    m_ptr = 0;
+    return zret;
+  }
+private:
+  T* m_ptr; ///< Pointer to allocated memory.
+  /// Copy constructor - forbidden.
+  xptr(self const& that);
+  /// Self assignment - forbidden.
+  self& operator = (self const& that);
+};
+
+// Special operators for xptr<char>
+/** Combine two strings as file paths.
+    Trailing and leading separators for @a lhs and @a rhs respectively
+    are handled to yield exactly one separator.
+    @return A newly @x xmalloc string of the combined paths.
+*/
+inline char* path_join (xptr<char> const& lhs, xptr<char> const& rhs) {
+  size_t ln = strlen(lhs);
+  size_t rn = strlen(rhs);
+  char const* rptr = rhs; // May need to be modified.
+  if (ln && lhs[ln-1] == '/') --ln; // drop trailing separator.
+  if (rn && *rptr == '/') --rn, ++rptr; // drop leading separator.
+  char* x = static_cast<char*>(xmalloc(ln + rn + 2));
+  memcpy(x, lhs, ln);
+  x[ln] = '/';
+  memcpy(x + ln + 1,  rptr, rn);
+  x[ln+rn+1] = 0; // terminate string.
+  return x;
+}
+
+#endif // c++
 
 #endif /* TRACK_MEMORY */
 

Modified: trafficserver/traffic/branches/wccp/proxy/Makefile.am
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/Makefile.am?rev=1021825&r1=1021824&r2=1021825&view=diff
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/Makefile.am (original)
+++ trafficserver/traffic/branches/wccp/proxy/Makefile.am Tue Oct 12 16:10:47 2010
@@ -22,7 +22,7 @@ noinst_LIBRARIES = libTrafficServerStand
 bin_PROGRAMS =
 noinst_PROGRAMS =
 else
-SUBDIRS = congest http2 hdrs logging mgmt2 config stats
+SUBDIRS = congest http2 hdrs logging wccp mgmt2 config stats
 noinst_LIBRARIES =
 bin_PROGRAMS = \
   traffic_server \

Modified: trafficserver/traffic/branches/wccp/proxy/mgmt2/LocalManager.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/mgmt2/LocalManager.cc?rev=1021825&r1=1021824&r2=1021825&view=diff
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/mgmt2/LocalManager.cc (original)
+++ trafficserver/traffic/branches/wccp/proxy/mgmt2/LocalManager.cc Tue Oct 12 16:10:47 2010
@@ -80,6 +80,7 @@ LocalManager::mgmtShutdown(int status, b
   if (mainThread) {
     mgmt_log("[LocalManager::mgmtShutdown] Executing shutdown request.\n");
     processShutdown(mainThread);
+    // WCCP TBD: Send a shutdown message to routers.
 
     if (processRunning()) {
       waitpid(watched_process_pid, &status, 0);
@@ -343,6 +344,29 @@ BaseManager(), run_proxy(proxy_on), reco
     config_path = absolute_config_path;
   }
 
+  // Bind the WCCP address if present.
+  xptr<char> wccp_addr_str(REC_readString("proxy.config.wccp.addr", &found));
+  if (found && wccp_addr_str && *wccp_addr_str) {
+    wccp_cache.setAddr(inet_addr(wccp_addr_str));
+    mgmt_log("[LocalManager::LocalManager] WCCP identifying address set to %s.\n", static_cast<char*>(wccp_addr_str));
+  }
+
+  xptr<char> wccp_config_str(REC_readString("proxy.config.wccp.services", &found));
+  if (found && wccp_config_str && *wccp_config_str) {
+    bool located = true;
+    if (access(wccp_config_str, R_OK) == -1) {
+      wccp_config_str = Layout::relative_to(Layout::get()->sysconfdir, wccp_config_str);
+      if (access(wccp_config_str, R_OK) == -1 ) {
+        located = false;
+      }
+    }
+    if (located) {
+      wccp_cache.loadServicesFromFile(wccp_config_str);
+    } else { // not located
+      mgmt_log("[LocalManager::LocalManager] WCCP service configuration file '%s' was specified but could not be found in the file system.\n", static_cast<char*>(wccp_config_str));
+    }
+  }
+
   bin_path = REC_readString("proxy.config.bin_path", &found);
   process_server_timeout_secs = REC_readInteger("proxy.config.lm.pserver_timeout_secs", &found);
   process_server_timeout_msecs = REC_readInteger("proxy.config.lm.pserver_timeout_msecs", &found);
@@ -459,6 +483,10 @@ LocalManager::initMgmtProcessServer()
   int servlen, one = 1;
   struct sockaddr_un serv_addr;
 
+  if (wccp_cache.isConfigured()) {
+    if (0 > wccp_cache.open()) mgmt_log("Failed to open WCCP socket\n");
+  }
+
   snprintf(fpath, sizeof(fpath), "%s/%s", pserver_path, LM_CONNECTION_SERVER);
   unlink(fpath);
   if ((process_server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
@@ -504,17 +532,25 @@ LocalManager::pollMgmtProcessServer()
   struct timeval timeout;
   struct sockaddr_in clientAddr;
   fd_set fdlist;
+  int wccp_fd = wccp_cache.getSocket();
 
   while (1) {
+    // Only run WCCP housekeeping while we have a server process.
+    // Note: The WCCP socket is opened iff WCCP is configured.
+    bool wccp_active = wccp_fd != ats::NO_FD && watched_process_fd != ats::NO_FD;
 
     // poll only
     timeout.tv_sec = process_server_timeout_secs;
     timeout.tv_usec = process_server_timeout_msecs * 1000;
-
     FD_ZERO(&fdlist);
     FD_SET(process_server_sockfd, &fdlist);
-    if (watched_process_fd != -1) {
-      FD_SET(watched_process_fd, &fdlist);
+    if (watched_process_fd != -1) FD_SET(watched_process_fd, &fdlist);
+
+    if (wccp_active) {
+      wccp_cache.housekeeping();
+      time_t wccp_wait = wccp_cache.waitTime();
+      if (wccp_wait < process_server_timeout_secs) timeout.tv_sec = wccp_wait;
+      FD_SET(wccp_cache.getSocket(), &fdlist);
     }
 
     num = mgmt_select(FD_SETSIZE, &fdlist, NULL, NULL, &timeout);
@@ -524,6 +560,11 @@ LocalManager::pollMgmtProcessServer()
 
     } else if (num > 0) {       /* Have something */
 
+      if (wccp_fd != ats::NO_FD && FD_ISSET(wccp_fd, &fdlist)) {
+        wccp_cache.handleMessage();
+        --num;
+      }
+
       if (FD_ISSET(process_server_sockfd, &fdlist)) {   /* New connection */
         int clientLen = sizeof(clientAddr);
         int new_sockfd = mgmt_accept(process_server_sockfd,
@@ -554,7 +595,7 @@ LocalManager::pollMgmtProcessServer()
         --num;
       }
 
-      if (FD_ISSET(watched_process_fd, &fdlist)) {
+      if (ats::NO_FD != watched_process_fd && FD_ISSET(watched_process_fd, &fdlist)) {
         int res;
         MgmtMessageHdr mh_hdr;
         MgmtMessageHdr *mh_full;
@@ -1116,7 +1157,7 @@ LocalManager::startProxy()
   // Before we do anything lets check for the existence of
   // the traffic server binary along with it's execute permmissions
   if (access(absolute_proxy_binary, F_OK) < 0) {
-    // Error can't find trafic_server
+    // Error can't find traffic_server
     mgmt_elog(stderr, "[LocalManager::startProxy] Unable to find traffic server at %s\n", absolute_proxy_binary);
     return false;
   }

Modified: trafficserver/traffic/branches/wccp/proxy/mgmt2/LocalManager.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/mgmt2/LocalManager.h?rev=1021825&r1=1021824&r2=1021825&view=diff
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/mgmt2/LocalManager.h (original)
+++ trafficserver/traffic/branches/wccp/proxy/mgmt2/LocalManager.h Tue Oct 12 16:10:47 2010
@@ -41,6 +41,7 @@
 #include "ClusterCom.h"
 #include "VMap.h"
 #include "WebPluginList.h"
+#include "../wccp/Wccp.h"
 
 #if !defined(WIN32)
 #define ink_get_hrtime ink_get_hrtime_internal
@@ -186,6 +187,7 @@ public:
 #endif
 
   WebPluginList plugin_list;
+  Wccp::Cache wccp_cache;
 
 private:
 

Modified: trafficserver/traffic/branches/wccp/proxy/mgmt2/Main.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/mgmt2/Main.cc?rev=1021825&r1=1021824&r2=1021825&view=diff
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/mgmt2/Main.cc (original)
+++ trafficserver/traffic/branches/wccp/proxy/mgmt2/Main.cc Tue Oct 12 16:10:47 2010
@@ -445,6 +445,30 @@ set_process_limits(int fds_throttle)
 
 }
 
+void
+Errata_Logger(ats::Errata const& err) {
+  size_t n;
+  static size_t const SIZE = 4096;
+  char buff[SIZE];
+  if (err.size()) {
+    ats::Errata::Code code = err.top().getCode();
+    if (code > 0) {
+      n = err.write(buff, SIZE, 1, 0, 2, "> ");
+      // strip trailing newlines.
+      while (n && (buff[n-1] == '\n' || buff[n-1] == '\r'))
+        buff[--n] = 0;
+      // log it.
+      if (code > 1) mgmt_elog("[WCCP]%s", buff);
+      else mgmt_log("[WCCP]%s", buff);
+    }
+  }
+}
+
+void
+Init_Errata_Logging() {
+  ats::Errata::registerSink(&Errata_Logger);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -683,6 +707,7 @@ main(int argc, char **argv)
 
   RecLocalInit();
   LibRecordsConfigInit();
+  Init_Errata_Logging();
   lmgmt = new LocalManager(mgmt_path, new LMRecords(mgmt_path, recs_conf, 0), proxy_on);
   RecLocalInitMessage();
   lmgmt->initAlarm();
@@ -1365,7 +1390,7 @@ fileUpdated(char *fname)
     @code
     prctl(PR_SET_KEEPCAPS, 1);
     @endcode
-    but that had no effect even though the call reported succes.
+    but that had no effect even though the call reported success.
     Only explicit capability manipulation was effective.
 
     It does not appear to be necessary to set the capabilities on the

Modified: trafficserver/traffic/branches/wccp/proxy/mgmt2/Makefile.am
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/mgmt2/Makefile.am?rev=1021825&r1=1021824&r2=1021825&view=diff
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/mgmt2/Makefile.am (original)
+++ trafficserver/traffic/branches/wccp/proxy/mgmt2/Makefile.am Tue Oct 12 16:10:47 2010
@@ -120,4 +120,4 @@ traffic_manager_LDADD = \
   @LIBEXPAT@ @LIBPCRE@ \
   @LIBSSL@ @LIBDB@ @LIBSQLITE3@ @LIBTCL@ @LIBICONV@ \
   @LIBM@ @LIBDL@ @LIBSOCKET@ @LIBNSL@ @LIBRESOLV@ \
-  @LIBTHREAD@ @LIBRT@ @LIBEXECINFO@ @LIBCAP@
+  @LIBTHREAD@ @LIBRT@ @LIBEXECINFO@ @LIBCAP@ ../wccp/libwccp.a -lconfig++

Modified: trafficserver/traffic/branches/wccp/proxy/mgmt2/RecordsConfig.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/mgmt2/RecordsConfig.cc?rev=1021825&r1=1021824&r2=1021825&view=diff
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/mgmt2/RecordsConfig.cc (original)
+++ trafficserver/traffic/branches/wccp/proxy/mgmt2/RecordsConfig.cc Tue Oct 12 16:10:47 2010
@@ -2605,6 +2605,15 @@ RecordElement RecordsConfig[] = {
   ,
   {PROCESS, "proxy.process.icp.total_icp_request_time", "", INK_FLOAT, "0.00", RU_NULL, RR_NULL, RC_NULL, NULL, RA_NULL}
   ,
+  //############################################################################
+  //#
+  //# WCCP
+  //#
+  //############################################################################
+  {CONFIG, "proxy.config.wccp.addr", "Identifying IP address", INK_STRING, "", RU_RESTART_TM, RR_NULL, RC_STR, NULL, RA_NULL}
+  ,
+  {CONFIG, "proxy.config.wccp.services", "File with service configuration", INK_STRING, "", RU_RESTART_TM, RR_NULL, RC_STR, NULL, RA_NULL }
+  ,
   //##############################################################################
   //# Scheduled Update Configuration
   //##############################################################################

Added: trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/AtsBase.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/AtsBase.h?rev=1021825&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/AtsBase.h (added)
+++ trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/AtsBase.h Tue Oct 12 16:10:47 2010
@@ -0,0 +1,91 @@
+/** @file
+    Apach Traffic Server commons.
+    Definitions that are standardized across ATS.
+ */
+
+# include <stddef.h>
+# include <unistd.h>
+
+/// Apache Traffic Server commons.
+namespace ats {
+  namespace fixed_integers {
+#if !defined(TS_VERSION_STRING)
+    /// @name Fixed size integers.
+    //@{
+    typedef char int8;
+    typedef unsigned char uint8;
+    typedef short int16;
+    typedef unsigned short uint16;
+    typedef int int32;
+    typedef unsigned int uint32;
+    typedef long long int64;
+    typedef unsigned long long uint64;
+    //@}
+#endif
+  }
+  using namespace fixed_integers;
+
+  /// Standardized null file descriptor.
+  int const NO_FD = -1;
+
+  /** A chunk of memory.
+      A convenience class because we pass this kind of pair frequently.
+   */
+  struct Buffer {
+    typedef Buffer self; ///< Self reference type.
+
+    char* m_ptr; ///< Pointer to base of memory chunk.
+    size_t m_size; ///< Size of memory chunk.
+
+    /// Default constructor.
+    /// Elements are in unintialized state.
+    Buffer();
+
+    /// Construct from pointer and size.
+    Buffer(
+      char* ptr, ///< Pointer to buffer.
+      size_t n ///< Size of buffer.
+    );
+
+    /// Set the chunk.
+    /// Any previous values are discarded.
+    /// @return @c this object.
+    self& set(
+      char* ptr, ///< Buffer address.
+      size_t n ///< Buffer size.
+    );
+  };
+
+  /** Base class for ATS exception.
+      Clients should subclass as appropriate. This is intended to carry
+      pre-allocated text along so that it can be thrown without any
+      adddition memory allocation.
+  */
+  class Exception {
+  public:
+    /// Default constructor.
+    Exception();
+    /// Construct with alternate @a text.
+    Exception(
+      const char* text ///< Alternate text for exception.
+    );
+
+    static char const* const DEFAULT_TEXT;
+  protected:
+    char const* m_text;
+  };
+
+  // ----------------------------------------------------------
+  // Inline implementations.
+
+  inline Buffer::Buffer() { }
+  inline Buffer::Buffer(char* ptr, size_t n) : m_ptr(ptr), m_size(n) { }
+  inline Buffer& Buffer::set(char* ptr, size_t n) {
+    m_ptr = ptr;
+    m_size = n;
+    return *this;
+  }
+
+  inline Exception::Exception() : m_text(DEFAULT_TEXT) { }
+  inline Exception::Exception(char const* text) : m_text(text) { }
+}

Added: trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/Errata.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/Errata.h?rev=1021825&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/Errata.h (added)
+++ trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/Errata.h Tue Oct 12 16:10:47 2010
@@ -0,0 +1,847 @@
+# 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 ats {
+
+/** @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:
+    /// Imlementation class.
+    struct Data;
+    /// Handle for implementation class instance.
+    typedef IntrusivePtr<Data> ImpPtr;
+public:
+    typedef Errata self; /// Self reference type.
+
+    /// Message ID.
+    typedef numeric_type<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 numeric_type<unsigned int, struct CodeTag> Code;
+    class 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;
+
+    /// 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;
+
+    /** 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 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;
+    };
+};
+
+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.
+};
+
+/** 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();
+};
+
+/** 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 RvBase::RvBase() { }
+inline RvBase::RvBase(Errata const& errata) : _errata(errata) { }
+inline bool RvBase::isOK() const { return _errata; }
+inline void RvBase::clear() { _errata.clear(); }
+
+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/mgmt2/api2/include/IntrusivePtr.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/IntrusivePtr.h?rev=1021825&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/IntrusivePtr.h (added)
+++ trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/IntrusivePtr.h Tue Oct 12 16:10:47 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 ats {
+/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
+/** @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/mgmt2/api2/include/NumericType.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/NumericType.h?rev=1021825&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/NumericType.h (added)
+++ trafficserver/traffic/branches/wccp/proxy/mgmt2/api2/include/NumericType.h Tue Oct 12 16:10:47 2010
@@ -0,0 +1,169 @@
+/*      Copyright (c) 2006-2010 Network Geographics.
+ *      All rights reserved.
+ *      Licensed to the Apache Software Foundation.
+ */
+/* ------------------------------------------------------------------------ */
+# if !defined(ATS_NUMERIC_TYPE_HEADER)
+# define ATS_NUMERIC_TYPE_HEADER
+
+# include <limits>
+/* ----------------------------------------------------------------------- */
+namespace ats {
+/* ----------------------------------------------------------------------- */
+/** @file
+
+    Create a distince 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 evaulating 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 instatiation like
+
+    @code
+    typedef numeric_type<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 numeric_type;
+
+/// @cond NOT_DOCUMENTED
+/** Support template for resolving operator ambiguitity.
+
+    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 amibiguity, gcc won't distinguish between
+    class methods and builtins because @c numeric_type has a user
+    conversion to @a T. So signature <tt>(numeric_type, 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 numeric_type_int_operators {
+public:
+    numeric_type<T,X>& operator += ( int t );
+    numeric_type<T,X>& operator -= ( int t );
+
+    // Must have const and non-const versions.
+    numeric_type<T,X> operator +  ( int t );
+    numeric_type<T,X> operator -  ( int t );
+    numeric_type<T,X> operator +  ( int t ) const;
+    numeric_type<T,X> operator -  ( int t ) const;
+};
+
+template < typename T, typename X > numeric_type<T,X>
+operator + ( int t, numeric_type_int_operators<T,X> const& );
+
+template < typename T, typename X > numeric_type<T,X>
+operator - ( int t, numeric_type_int_operators<T,X> const& );
+
+/// @endcond
+
+/** Numeric type template.
+ */
+template <
+  typename T, ///< Base numeric type.
+  typename X ///< Distinguishing tag type.
+> class numeric_type : public numeric_type_int_operators<T,X> {
+public:
+    typedef T raw_type; //!< Base builtin type.
+    typedef numeric_type self; //!< Self reference type.
+
+    using numeric_type_int_operators<T,X>::operator +=;
+    using numeric_type_int_operators<T,X>::operator -=;
+    using numeric_type_int_operators<T,X>::operator +;
+    using numeric_type_int_operators<T,X>::operator -;
+
+    /// Default constructor, uninitialized.
+    numeric_type();
+    //! Construct from implementation type.
+    numeric_type(
+      raw_type const t ///< Initialized value.
+    );
+    //! Copy constructor.
+    numeric_type(
+      self const& that ///< Source instance.
+    );
+
+    //! Assignment from implementation type.
+    numeric_type & operator = (raw_type const t);
+    //! Self assignment.
+    numeric_type & 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 > numeric_type<T,X>::numeric_type() { }
+template < typename T, typename X > numeric_type<T,X>::numeric_type(raw_type const t) : _t(t) { }
+template < typename T, typename X > numeric_type<T,X>::numeric_type(self const& that) : _t(that._t) { }
+template < typename T, typename X > numeric_type<T,X>& numeric_type<T,X>::operator = (raw_type const t) { _t = t; return *this; }
+template < typename T, typename X > numeric_type<T,X>& numeric_type<T,X>::operator = (self const& that) { _t = that._t; return *this; }
+
+template < typename T, typename X > numeric_type<T,X>& numeric_type<T,X>::operator += ( self const& that ) { _t += that._t; return *this; }
+template < typename T, typename X > numeric_type<T,X>& numeric_type<T,X>::operator -= ( self const& that ) { _t -= that._t; return *this; }
+template < typename T, typename X > numeric_type<T,X> numeric_type<T,X>::operator +  ( self const& that ) { return self(_t + that._t); }
+template < typename T, typename X > numeric_type<T,X> numeric_type<T,X>::operator -  ( self const& that ) { return self(_t - that._t); }
+
+template < typename T, typename X > numeric_type<T,X>& numeric_type<T,X>::operator += ( raw_type t ) { _t += t; return *this; }
+template < typename T, typename X > numeric_type<T,X>& numeric_type<T,X>::operator -= ( raw_type t ) { _t -= t; return *this; }
+template < typename T, typename X > numeric_type<T,X> numeric_type<T,X>::operator +  ( raw_type t ) { return self(_t + t); }
+template < typename T, typename X > numeric_type<T,X> numeric_type<T,X>::operator -  ( raw_type t ) { return self(_t - t); }
+
+template < typename T, typename X > numeric_type<T,X>& numeric_type<T,X>::operator ++() { ++_t; return *this; }
+template < typename T, typename X > numeric_type<T,X>& numeric_type<T,X>::operator --() { --_t; return *this; }
+template < typename T, typename X > numeric_type<T,X> numeric_type<T,X>::operator ++(int) { self tmp(*this); ++_t; return tmp; }
+template < typename T, typename X > numeric_type<T,X> numeric_type<T,X>::operator --(int) { self tmp(*this); --_t; return tmp; }
+
+template < typename T, typename X > numeric_type<T,X> operator +  ( T const& lhs, numeric_type<T,X> const& rhs ) { return rhs + lhs; }
+template < typename T, typename X > numeric_type<T,X> operator -  ( T const& lhs, numeric_type<T,X> const& rhs ) { return numeric_type<T,X>(lhs - rhs.raw()); }
+
+/* ----------------------------------------------------------------------- */
+} /* end namespace ngeo */
+/* ----------------------------------------------------------------------- */
+# endif // ATS_NUMERIC_TYPE_HEADER

Added: trafficserver/traffic/branches/wccp/proxy/wccp/AtsBaseStatic.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/wccp/AtsBaseStatic.cc?rev=1021825&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/wccp/AtsBaseStatic.cc (added)
+++ trafficserver/traffic/branches/wccp/proxy/wccp/AtsBaseStatic.cc Tue Oct 12 16:10:47 2010
@@ -0,0 +1,5 @@
+# include "AtsBase.h"
+
+namespace ats {
+  char const* const Exception::DEFAULT_TEXT = "An unexpected error occurred.";
+}

Added: trafficserver/traffic/branches/wccp/proxy/wccp/AtsMeta.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/wccp/AtsMeta.h?rev=1021825&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/wccp/AtsMeta.h (added)
+++ trafficserver/traffic/branches/wccp/proxy/wccp/AtsMeta.h Tue Oct 12 16:10:47 2010
@@ -0,0 +1,176 @@
+#include <algorithm>
+
+// Various meta programming efforts. Experimental at present.
+
+namespace ats {
+
+// Some support templates so we can fail to compile if the
+// compile time check fails.
+
+// This creates the actual error, depending on whether X has a valid
+// nest type Result.
+template < typename X > struct TEST_RESULT { typedef typename X::Result type; };
+
+// Bool checking - a base template then specializations to succeed or
+// fail.
+template < bool VALUE > struct TEST_BOOL { };
+// Successful test defines Result.
+template <> struct TEST_BOOL<true> { typedef int Result; };
+// Failing test does not define Result.
+template <> struct TEST_BOOL<false> { };
+
+// Fail to compile if VALUE is not true.
+template < bool VALUE > struct TEST_IF_TRUE
+  : public TEST_RESULT< TEST_BOOL< VALUE > > {
+};
+
+// Helper for assigning a value to all instances in a container.
+template < typename T , typename R, typename A1 >
+struct TsAssignMember : public std::binary_function<T, A1, R> {
+  R T::*_m;
+  A1 _arg1;
+  TsAssignMember(R T::*m, A1 const& arg1) : _m(m), _arg1(arg1) { }
+  R operator () (T& t) const { return t.*_m = _arg1; }
+};
+
+// Helper function to compute types for TsAssignMember.
+template < typename T, typename R, typename A1 > struct TsAssignMember<T,R,A1> assign_member(R T::*m, A1 const& arg1) { return TsAssignMember<T,R,A1>(m,arg1); }
+
+// Overload for_each to operate on a container.
+template < typename C, typename F > void for_each(C& c, F const& f) { std::for_each(c.begin(), c.end(), f); }
+
+/** Calc minimal value over a direct type container.
+    This handles an accessor that takes a argument.
+*/
+template < typename C, typename V, typename ARG1 > V
+minima(C const& c,  V (C::value_type::*ex)(ARG1) const, ARG1 const& arg1) {
+  V v = std::numeric_limits<V>::max();
+  for ( typename C::const_iterator spot = c.begin(), limit = c.end();
+        spot != limit;
+        ++spot
+  ) {
+    v = std::min(v, ((*spot).*ex)(arg1) );
+  }
+  return v;
+}
+
+/** Calc minimal value over a paired type container.
+    This handles an accessor that takes a argument.
+*/
+template < typename C, typename V, typename ARG1 > V
+minima(C const& c,  V (C::value_type::second_type::*ex)(ARG1) const, ARG1 const& arg1) {
+  V v = std::numeric_limits<V>::max();
+  for ( typename C::const_iterator spot = c.begin(), limit = c.end();
+        spot != limit;
+        ++spot
+  ) {
+    v = std::min(v, ((spot->second).*ex)(arg1) );
+  }
+  return v;
+}
+
+/** Apply a unary method to every object in a direct container.
+*/
+template < typename C, typename V, typename ARG1 > void
+for_each(C& c,  V (C::value_type::*ex)(ARG1), ARG1 const& arg1) {
+  for ( typename C::iterator spot = c.begin(), limit = c.end();
+        spot != limit;
+        ++spot
+  ) ((*spot).*ex)(arg1);
+}
+
+/** Apply a unary method to every object in a paired container.
+*/
+template < typename C, typename V, typename ARG1 > void
+for_each(C& c,  V (C::value_type::second_type::*ex)(ARG1) const, ARG1 const& arg1) {
+  for ( typename C::iterator spot = c.begin(), limit = c.end();
+        spot != limit;
+        ++spot
+  ) ((spot->second).*ex)(arg1);
+}
+
+template <
+  typename Elt, ///< Element type.
+  typename Value ///< Member value type.
+> struct MemberPredicate {
+  Value const& m_value; ///< Value to test against.
+  Value Elt::*m_mptr; ///< Pointer to member to test.
+  MemberPredicate(Value Elt::*mptr, Value const& v)
+    : m_value(v)
+    , m_mptr(mptr) {
+  }
+  bool operator () (Elt const& elt) const {
+    return elt.*m_mptr == m_value;
+  }
+};
+
+template < typename T, typename V > MemberPredicate<T,V>
+predicate(V T::*m, V const& v) {
+  return MemberPredicate<T,V>(m, v);
+}
+
+template <
+  typename Elt, ///< Element type.
+  typename Value ///< Member value type.
+> struct MethodPredicate {
+  typedef Value (Elt::*MethodPtr)() const;
+  Value const& m_value; ///< Value to test against.
+  MethodPtr m_mptr; ///< Pointer to method returning value.
+  MethodPredicate(MethodPtr mptr , Value const& v)
+    : m_value(v)
+    , m_mptr(mptr) {
+  }
+  bool operator () (Elt const& elt) const {
+    return (elt.*m_mptr)() == m_value;
+  }
+};
+
+template < typename T, typename V > MethodPredicate<T,V>
+predicate(V (T::*m)() const, V const& v) {
+  return MethodPredicate<T,V>(m, v);
+}
+
+# if 0
+
+/// Accumulate a minimum value when called repeated on different objects.
+template < 
+  typename V, ///< Value type.
+  typename T, ///< Object type
+  typename F ///< Extractor type.
+> struct MinimaFunctor :  public std::unary_function<T, void> {
+  V& m_result; ///< Result value.
+  F m_extractor; ///< Extraction functor.
+  /// Constructor.
+MinimaFunctor(F const& f, V& v) : m_result(v), m_extractor(f) { }
+  /// Extract a value and accumulate the minimum.
+  void operator () (T const& obj) const {
+    m_result = std::min(m_result, m_extractor(obj));
+  }
+};
+
+// Working on a more general mechanism by starting with more specific
+// ones to see the pattern.
+
+template <
+  typename R, ///< Return type.
+  typename T, ///< Object type.
+  typename ARG1 ///< Bound argument type.
+> struct BinderConstMethodArg1ToNullary : std::unary_function<T, R> {
+  typedef R (T::*F)(ARG1) const; /// Method type.
+  F m_method; ///< The actual method.
+  ARG1 m_arg1; ///< Bound argument.
+  /// Constructor.
+  BinderConstMethodArg1ToNullary(
+    F const& f, ///< Pointer to  method.
+    ARG1 const& arg1 ///< Argument to bind.
+  ) : m_method(f), m_arg1(arg1) {
+  }
+  /// Call the method.
+  R operator () (T const& obj) const {
+    return (obj.*m_method)(m_arg1);
+  }
+};
+
+# endif
+
+} // namespace ats

Added: trafficserver/traffic/branches/wccp/proxy/wccp/Errata.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/branches/wccp/proxy/wccp/Errata.cc?rev=1021825&view=auto
==============================================================================
--- trafficserver/traffic/branches/wccp/proxy/wccp/Errata.cc (added)
+++ trafficserver/traffic/branches/wccp/proxy/wccp/Errata.cc Tue Oct 12 16:10:47 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 ats {
+
+/** 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