//===========================================================================
//  $Name: arts++-1-1-a12 $
//  $Id: ArtsRttTimeSeriesTableData.hh,v 1.2 2004/04/21 23:51:29 kkeys Exp $
//===========================================================================
//  Copyright Notice
//
//  By accessing this software, arts++, you are duly informed
//  of and agree to be bound by the conditions described below in this
//  notice:
//
//  This software product, arts++, is developed by Daniel W. McRobb, and
//  copyrighted(C) 1998 by the University of California, San Diego
//  (UCSD), with all rights reserved.  UCSD administers the CAIDA grant,
//  NCR-9711092, under which part of this code was developed.
//
//  There is no charge for arts++ software.  You can redistribute it
//  and/or modify it under the terms of the GNU Lesser General Public
//  License, Version 2.1, February 1999, which is incorporated by
//  reference herein.
//
//  arts++ is distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS, OF
//  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE or that the use
//  of it will not infringe on any third party's intellectual
//  property rights.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with arts++.  Copies can also be obtained from:
//
//    http://www.gnu.org/copyleft/lesser.html
//
//  or by writing to:
//
//  Free Software Foundation, Inc.
//  59 Temple Place, Suite 330
//  Boston, MA 02111-1307
//  USA
//
//  Or contact:
//
//    info@caida.org
//===========================================================================

#ifndef _ARTSRTTTIMESERIESTABLEDATA_HH_
#define _ARTSRTTTIMESERIESTABLEDATA_HH_

extern "C" {
#include <sys/time.h>

#include "caida_t.h"
}

#include <vector>

//----------------------------------------------------------------------------
//                     class ArtsRttTimeSeriesTableEntry
//----------------------------------------------------------------------------
//!  This class encapsulates a single RTT time series measurement (a
//!  sample).  Note we ony store time information here.  This class is
//!  not intended to be used directly for I/O, but instead as a component
//!  of the ArtsRttTimeSeriesTableData class.
//!
//!  Note we use some simple techniques to reduce disk space requirements
//!  when storing this data.  We use length,value encoding for several
//!  fields, allowing us to store 32-bit values with only the number of
//!  bytes required for the particular value (and 2 bits to indicate the
//!  length).  Some of the fields are permitted to have 0 length values;
//!  this means the field is either not applicable (for example, RTT for
//!  a measurement packet that was dropped) or the field's value is
//!  implicit (from data elsewhere, hence the higher number of arguments
//!  to the write() and read() members than those members in other Arts
//!  classes... reminder, this class is not intended to be used directly
//!  for disk I/O, and in fact the read() and write() members are not
//!  visible except from the friend ArtsRttTimeSeriesTableData class).
//!
/*!  When we write an ArtsRttTimeSeriesTableEntry to disk, we store the
  following:
  \verbatim
       1 byte flags bitfield
     0-4 byte RTT value (microseconds)
     1-4 byte timestamp seconds offset
     1-3 byte microseconds timestamp 

  The flags bitfield breaks down as follows:

                                           +--+
           dropped packet flag (1 bit)     |  |  msb (most signficant bit)
                                           +--+
           seconds offset flag (1 bit)     |  |
                                           +--+
                      RTT size (2 bits)    |  |
                                           +  +
                                           |  |
                                           +--+
    timestamp secs offset size (2 bits)    |  |
                                           +  +
                                           |  |
                                           +--+
          timestamp usecs size (2 bits)    |  |
                                           +  +
                                           |  |  lsb (least significant bit)
                                           +--+
  \endverbatim

The meaning of the flag fields:
  \verbatim
    dropped packet flag (1 bit)
      If set, the ArtsRttTimeSeriesTableEntry is for a dropped packet.
      This implies that the RTT will not be stored on disk since it's
      not applicable.  Hence the RTT size flags should be 0.  In terms
      of applications using the API, they can set the rtt (via
      Rtt(uint32_t rtt)) to k_droppedPacketRtt to indicate a dropped
      packet, and Rtt() will return k_droppedPacketRtt for one of
      these types of entries.

    seconds offset flag (1 bit)
      This flag indicates whether or not a seconds offset flag is stored.
      The idea here is that when storing multiple adjacent RTT
      measurements at greater than 1 per second, we often don't need
      to store a seconds value and can instead make it implicit if it's
      the same as the previous entry's seconds offset value.  If this
      flag is set, there is a seconds offset value.  If it is not set,
      there is no seconds offset value stored on disk (and the timestamp
      secs offset size bits should be 0) and the value is assumed to be
      that of the previous entry's seconds offset value.

    RTT size (2 bits)
      If there's an RTT value stored (dropped packet flag is 0), these
      bits indicate the length of the stored RTT (which is in microseconds).
      00 means it's a one-byte value, 01 means it's a 2-byte value, 10
      means it's a 3-byte value and 11 means it's a 4-byte value.

    timestamp secs offset size (2 bits)
      If there's a timestamp seconds offset value for this entry (i.e.
      the seconds offset flag is set), these bits indicate the length
      of the stored timestamp seconds offset value.  00 means it's a
      one-byte value, 01 means it's a 2-byte value, 10 means it's a
      3-byte value and 11 means it's a 4-byte value.

    timestamp usecs size (2 bits)
      These bits indicate the length of the stored timestamp
      microseconds value.  00 means it's a one-byte value, 01 means
      it's a 2-byte value, 10 means it's a 3-byte value.  Note we
      should never need 4 bytes here, since microseconds roll over
      at 20 bits (and hence only require 3 bytes of storage, max)
      and our microseconds value is a remainder from the seconds value.
\endverbatim
None of this trickery needs to be understood by an application
programmer.  From within an application, you just call Timestamp()
and Rtt() functions from the ArtsRttTimeSeriesTableEntry class,
and when doing disk I/O you use the higher-level
ArtsRttTimeSeriesTableData class members (which take care of the
I/O trickery under the hood).
*/
//---------------------------------------------------------------------------
class ArtsRttTimeSeriesTableEntry
{
public:
  static const uint32_t k_droppedPacketRtt            = 0xffffffff;
  
  //--------------------------------------------------------------------------
  //                      ArtsRttTimeSeriesTableEntry() 
  //..........................................................................
  //!  constructor
  //--------------------------------------------------------------------------
  ArtsRttTimeSeriesTableEntry();

  //--------------------------------------------------------------------------
  // ArtsRttTimeSeriesTableEntry(const ArtsRttTimeSeriesTableEntry & rttEntry) 
  //..........................................................................
  //!  copy constructor
  //--------------------------------------------------------------------------
  ArtsRttTimeSeriesTableEntry(const ArtsRttTimeSeriesTableEntry & rttEntry);

  //--------------------------------------------------------------------------
  //                     ~ArtsRttTimeSeriesTableEntry() 
  //..........................................................................
  //!  destructor
  //--------------------------------------------------------------------------
  ~ArtsRttTimeSeriesTableEntry();

  //--------------------------------------------------------------------------
  //                          uint32_t Rtt() const 
  //..........................................................................
  //!  Returns the RTT value (microseconds).
  //--------------------------------------------------------------------------
  uint32_t Rtt() const;

  //--------------------------------------------------------------------------
  //                       uint32_t Rtt(uint32_t rtt) 
  //..........................................................................
  //!  Sets and returns the RTT value (microseconds).
  //--------------------------------------------------------------------------
  uint32_t Rtt(uint32_t rtt);

  //--------------------------------------------------------------------------
  //                const struct timeval & Timestamp() const 
  //..........................................................................
  //!  Returns a reference to the timestamp.
  //--------------------------------------------------------------------------
  const struct timeval & Timestamp() const;

  //--------------------------------------------------------------------------
  //   const struct timeval & Timestamp(const struct timeval & timestamp) 
  //..........................................................................
  //!  Sets the timestamp and returns a reference to the timestamp.
  //--------------------------------------------------------------------------
  const struct timeval & Timestamp(const struct timeval & timestamp);

  //--------------------------------------------------------------------------
  //        ArtsRttTimeSeriesTableEntry & 
  //        operator = (const ArtsRttTimeSeriesTableEntry & rttEntry) 
  //..........................................................................
  //!  overloaded '=' operator for copying an ArtsRttTimeSeriesTableEntry.
  //--------------------------------------------------------------------------
  ArtsRttTimeSeriesTableEntry &
  operator = (const ArtsRttTimeSeriesTableEntry & rttEntry);

  uint32_t Length(uint32_t timeBase,
                  uint32_t prevSecsOffset,
                  uint8_t version = 0) const;

  friend class ArtsRttTimeSeriesTableData;
  
  #ifndef NDEBUG
    //------------------------------------------------------------------------
    //                       static uint32_t NumObjects()
    //........................................................................
    //  
    //------------------------------------------------------------------------
    static uint32_t NumObjects()
    {
      return(_numObjects);
    }
  #endif  // NDEBUG
  
private:
  uint32_t        _rtt;
  struct timeval  _timestamp;
  
  //--------------------------------------------------------------------------
  //   std::ostream & write(std::ostream & os, uint32_t timeBase, 
  //                   uint32_t prevSecsOffset, uint8_t version = 0) const 
  //..........................................................................
  //!  Writes an ArtsRttTimeSeriesTableEntry to an ostream.  Returns the
  //!  ostream.  Note this is a private member, but visible from the
  //!  ArtsRttTimeSeriesTableData class (a friend).
  //--------------------------------------------------------------------------
  std::ostream & write(std::ostream & os, uint32_t timeBase,
                  uint32_t prevSecsOffset, uint8_t version = 0) const;

  //--------------------------------------------------------------------------
  //       int write(int fd, uint32_t timeBase, uint32_t prevSecsOffset, 
  //                 uint8_t version = 0) const 
  //..........................................................................
  //!  Writes an ArtsRttTimeSeriesTableEntry to a file descriptor.  Returns
  //!  the number of bytes written on success, -1 on failure.
  //--------------------------------------------------------------------------
  int write(int fd, uint32_t timeBase, uint32_t prevSecsOffset,
            uint8_t version = 0) const;
  
  //--------------------------------------------------------------------------
  //       std::istream & read(std::istream & is, uint32_t timeBase, 
  //                      uint32_t prevSecsOffset, uint8_t version = 0) 
  //..........................................................................
  //!  Reads an ArtsRttTimeSeriesTableEntry from an istream.  Returns the
  //!  istream.  Note this is a private member, but visible from the
  //!  ArtsRttTimeSeriesTableData class (a friend).
  //--------------------------------------------------------------------------
  std::istream & read(std::istream & is, uint32_t timeBase,
                 uint32_t prevSecsOffset, uint8_t version = 0);

  //--------------------------------------------------------------------------
  //       int read(int fd, uint32_t timeBase, 
  //                uint32_t prevSecsOffset, uint8_t version = 0) 
  //..........................................................................
  //!  Reads an ArtsRttTimeSeriesTableEntry from a file descriptor.  Returns
  //!  the number of bytes read on success, -1 on failure.
  //--------------------------------------------------------------------------
  int read(int fd, uint32_t timeBase,
           uint32_t prevSecsOffset, uint8_t version = 0);
  
  static uint32_t _numObjects;
};

//----------------------------------------------------------------------------
//               class ArtsRttTimeSeriesTableEntryGreaterRtt 
//----------------------------------------------------------------------------
//!  This class is used to compare ArtsRttTimeSeriesTableEntry objects
//!  by their Rtt().  It can be used to sort ArtsRttTimeSeriesTableEntry
//!  objects in descending order by Rtt().
//----------------------------------------------------------------------------
class ArtsRttTimeSeriesTableEntryGreaterRtt
{
public:
  //--------------------------------------------------------------------------
  //      bool operator()(const ArtsRttTimeSeriesTableEntry & rttEntry1, 
  //                      const ArtsRttTimeSeriesTableEntry & rttEntry2) 
  //..........................................................................
  //  
  //--------------------------------------------------------------------------
  bool operator()(const ArtsRttTimeSeriesTableEntry & rttEntry1,
                  const ArtsRttTimeSeriesTableEntry & rttEntry2);
};

//----------------------------------------------------------------------------
//                 class ArtsRttTimeSeriesTableEntryLessRtt 
//----------------------------------------------------------------------------
//!  This class is used to compare ArtsRttTimeSeriesTableEntry objects
//!  by their Rtt().  It can be used to sort ArtsRttTimeSeriesTableEntry
//!  objects in ascending order by Rtt().
//----------------------------------------------------------------------------
class ArtsRttTimeSeriesTableEntryLessRtt
{
public:
  //--------------------------------------------------------------------------
  //      bool operator()(const ArtsRttTimeSeriesTableEntry & rttEntry1, 
  //                      const ArtsRttTimeSeriesTableEntry & rttEntry2) 
  //..........................................................................
  //  
  //--------------------------------------------------------------------------
  bool operator()(const ArtsRttTimeSeriesTableEntry & rttEntry1,
                  const ArtsRttTimeSeriesTableEntry & rttEntry2);
};


//----------------------------------------------------------------------------
//                     class ArtsRttTimeSeriesTableData                    
//----------------------------------------------------------------------------
//!  This class encapsulates RTT (round-trip time) time-series data.  It
//!  holds a number of ArtsRttTimeSeriesTableEntry objects and provides
//!  for I/O functionality (reading and writing RTT time series data).
//!  Each entry contains a timestamp (struct timeval) and an RTT (in
//!  microseconds).  You can indicate a dropped RTT measurement packet by
//!  setting an ArtsRttTimeSeriesTableEntry's RTT to
//!  ArtsRttTimeSeriesTableEntry::k_droppedPacketRtt.
//!
//!  We use some simple techniques to save some space on disk when storing
//!  this data: see the comments in the ArtsRttTimeSeriesTableEntry class.
//!
//!  This class also holds the destination IP address of the measurement.
//!  The source IP address is assumed to be a host attribute in the
//!  higher-level Arts class' attribute vector.
//----------------------------------------------------------------------------
class ArtsRttTimeSeriesTableData
{
public:
  //--------------------------------------------------------------------------
  //                      ArtsRttTimeSeriesTableData()
  //..........................................................................
  //!  constructor
  //--------------------------------------------------------------------------
  ArtsRttTimeSeriesTableData();
  
  //--------------------------------------------------------------------------
  // ArtsRttTimeSeriesTableData(const ArtsRttTimeSeriesTableData & rttTable)
  //..........................................................................
  //!  copy constructor
  //--------------------------------------------------------------------------
  ArtsRttTimeSeriesTableData(const ArtsRttTimeSeriesTableData & rttTable);
  
  //--------------------------------------------------------------------------
  //                      ~ArtsRttTimeSeriesTableData()
  //..........................................................................
  //!  destructor
  //--------------------------------------------------------------------------
  ~ArtsRttTimeSeriesTableData();
  
  //--------------------------------------------------------------------------
  //      ArtsRttTimeSeriesTableData &                      
  //      operator = (const ArtsRttTimeSeriesTableData & rttTable)
  //..........................................................................
  //!  Overloaded '=' operator for copying an ArtsRttTimeSeriesTableData
  //!  to another.
  //--------------------------------------------------------------------------
  ArtsRttTimeSeriesTableData &
  operator = (const ArtsRttTimeSeriesTableData & rttTable);
  
  //--------------------------------------------------------------------------
  //        std::vector<ArtsRttTimeSeriesTableEntry> & RttEntries() const
  //..........................................................................
  //!  Returns a reference to the vector of RTT entries.
  //--------------------------------------------------------------------------
  std::vector<ArtsRttTimeSeriesTableEntry> & RttEntries() const;
  
  //--------------------------------------------------------------------------
  //     void AddRttEntry(const ArtsRttTimeSeriesTableEntry & rttEntry)
  //..........................................................................
  //!  Adds an RTT entry to the vector of RTT entries.
  //--------------------------------------------------------------------------
  void AddRttEntry(const ArtsRttTimeSeriesTableEntry & rttEntry);
  
  //--------------------------------------------------------------------------
  //               uint32_t Length(uint8_t version = 0) const 
  //..........................................................................
  //!  Returns the number of bytes required to store the
  //!  ArtsRttTimeSeriesTableData on disk.
  //--------------------------------------------------------------------------
  uint32_t Length(uint8_t version = 0) const;
  
  //--------------------------------------------------------------------------
  //            std::istream & read(std::istream& is, uint8_t version = 0)
  //..........................................................................
  //!  Reads an ArtsRttTimeSeriesTableData object from an istream.
  //!  Returns the istream.
  //--------------------------------------------------------------------------
  std::istream & read(std::istream& is, uint8_t version = 0);

  //--------------------------------------------------------------------------
  //       int read(int fd, uint8_t version = 0) 
  //..........................................................................
  //!  Reads an ArtsRttTimeSeriesTableData object from a file descriptor.
  //!  Returns the number of bytes read on success, -1 on failure.
  //--------------------------------------------------------------------------
  int read(int fd, uint8_t version = 0);
  
  //--------------------------------------------------------------------------
  //        std::ostream & write(std::ostream & os, uint8_t version = 0) const
  //..........................................................................
  //!  Writes an ArtsRttTimeSeriesTableData object to an ostream.
  //!  Returns the ostream.
  //--------------------------------------------------------------------------
  std::ostream & write(std::ostream & os, uint8_t version = 0) const;

  //--------------------------------------------------------------------------
  //       int write(int fd, uint8_t version = 0) const 
  //..........................................................................
  //!  Writes an ArtsRttTimeSeriesTableData object to a file descriptor.
  //!  Returns the number of bytes written on success, -1 on failure.
  //--------------------------------------------------------------------------
  int write(int fd, uint8_t version = 0) const;
  
  //--------------------------------------------------------------------------
  //                      void SortEntriesByTimestamp() 
  //..........................................................................
  //!  Sorts the contained ArtsRttTimeSeriesTableEntry objects by their
  //!  timestamp.  This is useful when you're doing something like using
  //!  the receive timestamp for measurement packets that are returned but
  //!  using the transmit timestamp for dropped measurement packets, or
  //!  are receiving out-of-order packets and using the receive timestamp.
  //!
  //!  This function is always called by write(), since we want to be sure to
  //!  store RTT measurements in chronological order on disk.
  //--------------------------------------------------------------------------
  void SortEntriesByTimestamp();

  //--------------------------------------------------------------------------
  //           const ArtsRttTimeSeriesTableEntry & RttMax() const 
  //..........................................................................
  //!  Returns the maximum RTT entry (by RTT value).  If the table has
  //!  no RTT entries, returns an ArtsRttTimeSeriesTableEntry with a
  //!  timestamp and RTT value of 0.
  //--------------------------------------------------------------------------
  const ArtsRttTimeSeriesTableEntry & RttMax() const;

  //--------------------------------------------------------------------------
  //           const ArtsRttTimeSeriesTableEntry & RttMin() const 
  //..........................................................................
  //!  Returns the minimum RTT entry (by RTT value).  If the table has
  //!  no RTT entries, returns an ArtsRttTimeSeriesTableEntry with a
  //!  timestamp and RTT value of 0.
  //--------------------------------------------------------------------------
  const ArtsRttTimeSeriesTableEntry & RttMin() const;
  
  //--------------------------------------------------------------------------
  // const ArtsRttTimeSeriesTableEntry & RttPercentile(int percentile) const 
  //..........................................................................
  //!  Returns the RTT entry whose RTT value is the percentile (0 to 100)
  //!  value of all table entries.  If the table has no RTT entries,
  //!  returns an ArtsRttTimeSeriesTableEntry with a timestamp and RTT
  //!  value of 0.
  //--------------------------------------------------------------------------
  const ArtsRttTimeSeriesTableEntry & RttPercentile(int percentile) const;

  //--------------------------------------------------------------------------
  //       size_t RttPercentiles(const std::vector<int> & percentiles, 
  //                             std::vector<uint32_t> & results) const 
  //..........................................................................
  //  
  //--------------------------------------------------------------------------
  size_t RttPercentiles(const std::vector<int> & percentiles,
                        std::vector<uint32_t> & results) const;

  //--------------------------------------------------------------------------
  //          const ArtsRttTimeSeriesTableEntry & RttMedian() const 
  //..........................................................................
  //!  Returns the RTT entry whose RTT value is the median (50th percentile)
  //!  value of all table entries.  If the table has no RTT entries,
  //!  returns an ArtsRttTimeSeriesTableEntry with a timestamp and RTT
  //!  value of 0.
  //--------------------------------------------------------------------------
  const ArtsRttTimeSeriesTableEntry & RttMedian() const;

  //--------------------------------------------------------------------------
  //      const ArtsRttTimeSeriesTableEntry & RttLowerQuartile() const 
  //..........................................................................
  //!  Returns the RTT entry whose RTT value is the lower quartile (25th
  //!  percentile) value of all table entries.  If the table has no RTT
  //!  entries, returns an ArtsRttTimeSeriesTableEntry with a timestamp
  //!  and RTT value of 0.
  //--------------------------------------------------------------------------
  const ArtsRttTimeSeriesTableEntry & RttLowerQuartile() const;

  //--------------------------------------------------------------------------
  //      const ArtsRttTimeSeriesTableEntry & RttUpperQuartile() const 
  //..........................................................................
  //!  Returns the RTT entry whose RTT value is the upper quartile (75th
  //!  percentile) value of all table entries.  If the table has no RTT
  //!  entries, returns an ArtsRttTimeSeriesTableEntry with a timestamp
  //!  and RTT value of 0.
  //--------------------------------------------------------------------------
  const ArtsRttTimeSeriesTableEntry & RttUpperQuartile() const;
  
  //--------------------------------------------------------------------------
  //                    double AveragePacketLoss() const 
  //..........................................................................
  //!  Returns the average percentage of packet loss (0.0 - 100.0) in the
  //!  RTT table.
  //--------------------------------------------------------------------------
  double AveragePacketLoss() const;

  //--------------------------------------------------------------------------
  //                           void ClearRttData() 
  //..........................................................................
  //!  Clears the RTT data (erases all RTT entries and clears the time
  //!  base).  This would typically be used in an application that wants
  //!  to reuse an ArtsRttTimeSeriesTableData object (perhaps to avoid
  //!  the overhead of construction/destruction).  This function does *not*
  //!  touch the destination IP address field.
  //--------------------------------------------------------------------------
  void ClearRttData();
  
  //--------------------------------------------------------------------------
  //   friend std::ostream & 
  //   operator << (std::ostream & os, 
  //                const ArtsRttTimeSeriesTableData & rttTimeSeriesTable) 
  //..........................................................................
  //!  Overloaded ostream << operator to dump the contents of an
  //!  ArtsRttTimeSeriesTableData object ot an ostream in a human-readable
  //!  form.
  //--------------------------------------------------------------------------
  friend std::ostream &
  operator << (std::ostream & os,
               const ArtsRttTimeSeriesTableData & rttTimeSeriesTable);
  
  #ifndef NDEBUG
    //------------------------------------------------------------------------
    //                       static uint32_t NumObjects()
    //........................................................................
    //  
    //------------------------------------------------------------------------
    static uint32_t NumObjects()
    {
      return(_numObjects);
    }
  #endif  // NDEBUG

protected:
  //--------------------------------------------------------------------------
  //                        uint32_t TimeBase() const 
  //..........................................................................
  //!  Returns the timebase of the object.  This can't be called directly
  //!  by applications; it would be private but we want it for operator =
  //!  and the copy constructor.
  //--------------------------------------------------------------------------
  uint32_t TimeBase() const;

  //--------------------------------------------------------------------------
  //                  uint32_t TimeBase(uint32_t timeBase) 
  //..........................................................................
  //!  Sets and returns the timebase of the object.  This can't be called
  //!  directly by applications; it would be private but we want it for
  //!  operator = and the copy constructor.
  //--------------------------------------------------------------------------
  uint32_t TimeBase(uint32_t timeBase);
  
private:
  mutable uint32_t                             _timeBase;
  mutable std::vector<ArtsRttTimeSeriesTableEntry>  _rttEntries;

  static uint32_t  _numObjects;
};

//----------------------------------------------------------------------------
//           class ArtsRttTimeSeriesTableEntryTimestampsLess 
//----------------------------------------------------------------------------
//!  This class is used to compare ArtsRttTimeSeriesTableEntry objects
//!  by their timestamps.  It is used to sort ArtsRttTimeSeriesTableEntry
//!  objects by timestamp in an ArtsRttTimeSeriesTableData object.
//----------------------------------------------------------------------------
class ArtsRttTimeSeriesTableEntryTimestampsLess
{
public:
  //--------------------------------------------------------------------------
  //     bool operator () (const ArtsRttTimeSeriesTableEntry & rtt1, 
  //                       const ArtsRttTimeSeriesTableEntry & rtt2)  
  //..........................................................................
  //  
  //--------------------------------------------------------------------------
  bool operator () (const ArtsRttTimeSeriesTableEntry & rtt1,
                    const ArtsRttTimeSeriesTableEntry & rtt2) 
  {
    if (rtt1.Timestamp().tv_sec < rtt2.Timestamp().tv_sec)
      return(true);
    if ((rtt1.Timestamp().tv_sec == rtt2.Timestamp().tv_sec) &&
        (rtt1.Timestamp().tv_usec < rtt2.Timestamp().tv_usec))
      return(true);
    return(false);
  }
};


#endif  // _ARTSRTTTIMESERIESTABLEDATA_HH_
