Update StatsReport and by extension StatsCollector to reduce data copying.

Summary of changes:
* We're now using an enum for types instead of strings which both eliminates unecessary string creations+copies and further restricts the type to a known set at compile time.
* IDs are now a separate type instead of a string, copying of Values is not possible and values are const to allow grabbing references outside of the statscollector.
* StatsReport member variables are no longer public.
* Consolidated code in StatsCollector (e.g. merged PrepareLocalReport and PrepareRemoteReport).
* Refactored methods that forced copies of string (e.g. ExtractValueFromReport).
* More asserts for thread correctness.
* Using std::list for the StatsSet instead of a set since order is not important and updates are more efficient in list<>.

BUG=2822
R=hta@webrtc.org, perkj@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/40439004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@8110 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/app/webrtc/statstypes.h b/talk/app/webrtc/statstypes.h
index 2bc0f33..8f132db 100644
--- a/talk/app/webrtc/statstypes.h
+++ b/talk/app/webrtc/statstypes.h
@@ -32,11 +32,13 @@
 #define TALK_APP_WEBRTC_STATSTYPES_H_
 
 #include <algorithm>
-#include <set>
+#include <list>
 #include <string>
 #include <vector>
 
 #include "webrtc/base/basictypes.h"
+#include "webrtc/base/linked_ptr.h"
+#include "webrtc/base/scoped_ptr.h"
 #include "webrtc/base/common.h"
 #include "webrtc/base/linked_ptr.h"
 #include "webrtc/base/scoped_ptr.h"
@@ -46,35 +48,71 @@
 
 class StatsReport {
  public:
-  // TODO(tommi): Remove this ctor after removing reliance upon it in Chromium
-  // (mock_peer_connection_impl.cc).
-  StatsReport() : timestamp_(0) {}
+  // Indicates whether a track is for sending or receiving.
+  // Used in reports for audio/video tracks.
+  enum Direction {
+    kSend = 0,
+    kReceive,
+  };
 
-  // TODO(tommi): Make protected and disallow copy completely once not needed.
-  StatsReport(const StatsReport& src);
+  enum StatsType {
+    // StatsReport types.
+    // A StatsReport of |type| = "googSession" contains overall information
+    // about the thing libjingle calls a session (which may contain one
+    // or more RTP sessions.
+    kStatsReportTypeSession,
 
-  // Constructor is protected to force use of StatsSet.
-  // TODO(tommi): Make this ctor protected.
-  explicit StatsReport(const std::string& id);
+    // A StatsReport of |type| = "googTransport" contains information
+    // about a libjingle "transport".
+    kStatsReportTypeTransport,
 
-  // TODO(tommi): Make this protected.
-  StatsReport& operator=(const StatsReport& src);
+    // A StatsReport of |type| = "googComponent" contains information
+    // about a libjingle "channel" (typically, RTP or RTCP for a transport).
+    // This is intended to be the same thing as an ICE "Component".
+    kStatsReportTypeComponent,
 
-  // Operators provided for STL container/algorithm support.
-  bool operator<(const StatsReport& other) const;
-  bool operator==(const StatsReport& other) const;
-  // Special support for being able to use std::find on a container
-  // without requiring a new StatsReport instance.
-  bool operator==(const std::string& other_id) const;
+    // A StatsReport of |type| = "googCandidatePair" contains information
+    // about a libjingle "connection" - a single source/destination port pair.
+    // This is intended to be the same thing as an ICE "candidate pair".
+    kStatsReportTypeCandidatePair,
 
-  // The unique identifier for this object.
-  // This is used as a key for this report in ordered containers,
-  // so it must never be changed.
-  // TODO(tommi): Make this member variable const.
-  std::string id_;  // See below for contents.
-  std::string type;  // See below for contents.
+    // A StatsReport of |type| = "VideoBWE" is statistics for video Bandwidth
+    // Estimation, which is global per-session.  The |id| field is "bweforvideo"
+    // (will probably change in the future).
+    kStatsReportTypeBwe,
 
-  // StatsValue names.
+    // A StatsReport of |type| = "ssrc" is statistics for a specific rtp stream.
+    // The |id| field is the SSRC in decimal form of the rtp stream.
+    kStatsReportTypeSsrc,
+
+    // A StatsReport of |type| = "remoteSsrc" is statistics for a specific
+    // rtp stream, generated by the remote end of the connection.
+    kStatsReportTypeRemoteSsrc,
+
+    // A StatsReport of |type| = "googTrack" is statistics for a specific media
+    // track. The |id| field is the track id.
+    kStatsReportTypeTrack,
+
+    // A StatsReport of |type| = "localcandidate" or "remotecandidate" is
+    // attributes on a specific ICE Candidate. It links to its connection pair
+    // by candidate id. The string value is taken from
+    // http://w3c.github.io/webrtc-stats/#rtcstatstype-enum*.
+    kStatsReportTypeIceLocalCandidate,
+    kStatsReportTypeIceRemoteCandidate,
+
+    // A StatsReport of |type| = "googCertificate" contains an SSL certificate
+    // transmitted by one of the endpoints of this connection.  The |id| is
+    // controlled by the fingerprint, and is used to identify the certificate in
+    // the Channel stats (as "googLocalCertificateId" or
+    // "googRemoteCertificateId") and in any child certificates (as
+    // "googIssuerId").
+    kStatsReportTypeCertificate,
+
+    // A StatsReport of |type| = "datachannel" with statistics for a
+    // particular DataChannel.
+    kStatsReportTypeDataChannel,
+  };
+
   enum StatsValueName {
     kStatsValueNameActiveConnection,
     kStatsValueNameAudioInputLevel,
@@ -183,40 +221,54 @@
 
   class Id {
    public:
-    Id(const std::string& id) : id_(id) {}
-    Id(const Id& id) : id_(id.id_) {}
-    const std::string& ToString() const { return id_; }
-   private:
-    const std::string id_;
+    virtual ~Id();
+    StatsType type() const;
+    virtual bool Equals(const Id& other) const;
+    virtual std::string ToString() const = 0;
+
+   protected:
+    Id(StatsType type);  // Only meant for derived classes.
+    const StatsType type_;
   };
 
   struct Value {
-    // The copy ctor can't be declared as explicit due to problems with STL.
-    Value(const Value& other);
-    explicit Value(StatsValueName name);
     Value(StatsValueName name, const std::string& value);
 
-    // TODO(tommi): Remove this operator once we don't need it.
-    // The operator is provided for compatibility with STL containers.
-    // The public |name| member variable is otherwise meant to be read-only.
-    Value& operator=(const Value& other);
-
     // Returns the string representation of |name|.
     const char* display_name() const;
 
     const StatsValueName name;
+    // TODO(tommi): Support more value types than string.
+    const std::string value;
 
-    std::string value;
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Value);
   };
 
   typedef rtc::linked_ptr<Value> ValuePtr;
   typedef std::vector<ValuePtr> Values;
-  typedef const char* StatsType;
 
   // Ownership of |id| is passed to |this|.
   explicit StatsReport(rtc::scoped_ptr<Id> id);
 
+  // Factory functions for various types of stats IDs.
+  static rtc::scoped_ptr<Id> NewBandwidthEstimationId();
   static rtc::scoped_ptr<Id> NewTypedId(StatsType type, const std::string& id);
+  static rtc::scoped_ptr<Id> NewIdWithDirection(
+      StatsType type, const std::string& id, Direction direction);
+  static rtc::scoped_ptr<Id> NewCandidateId(bool local, const std::string& id);
+  static rtc::scoped_ptr<Id> NewComponentId(
+      const std::string& content_name, int component);
+  static rtc::scoped_ptr<Id> NewCandidatePairId(
+      const std::string& content_name, int component, int index);
+
+  const Id& id() const { return *id_.get(); }
+  StatsType type() const { return id_->type(); }
+  double timestamp() const { return timestamp_; }
+  void set_timestamp(double t) { timestamp_ = t; }
+  const Values& values() const { return values_; }
+
+  const char* TypeToString() const;
 
   void AddValue(StatsValueName name, const std::string& value);
   void AddValue(StatsValueName name, int64 value);
@@ -228,122 +280,55 @@
 
   void ResetValues();
 
-  const Id id() const { return Id(id_); }
-  double timestamp() const { return timestamp_; }
-  void set_timestamp(double t) { timestamp_ = t; }
-  const Values& values() const { return values_; }
+  const Value* FindValue(StatsValueName name) const;
 
-  const char* TypeToString() const { return type.c_str(); }
-
+ private:
+  // The unique identifier for this object.
+  // This is used as a key for this report in ordered containers,
+  // so it must never be changed.
+  const rtc::scoped_ptr<Id> id_;
   double timestamp_;  // Time since 1970-01-01T00:00:00Z in milliseconds.
   Values values_;
 
-  // TODO(tommi): These should all be enum values.
-
-  // StatsReport types.
-  // A StatsReport of |type| = "googSession" contains overall information
-  // about the thing libjingle calls a session (which may contain one
-  // or more RTP sessions.
-  static const char kStatsReportTypeSession[];
-
-  // A StatsReport of |type| = "googTransport" contains information
-  // about a libjingle "transport".
-  static const char kStatsReportTypeTransport[];
-
-  // A StatsReport of |type| = "googComponent" contains information
-  // about a libjingle "channel" (typically, RTP or RTCP for a transport).
-  // This is intended to be the same thing as an ICE "Component".
-  static const char kStatsReportTypeComponent[];
-
-  // A StatsReport of |type| = "googCandidatePair" contains information
-  // about a libjingle "connection" - a single source/destination port pair.
-  // This is intended to be the same thing as an ICE "candidate pair".
-  static const char kStatsReportTypeCandidatePair[];
-
-  // StatsReport of |type| = "VideoBWE" is statistics for video Bandwidth
-  // Estimation, which is global per-session.  The |id| field is "bweforvideo"
-  // (will probably change in the future).
-  static const char kStatsReportTypeBwe[];
-
-  // StatsReport of |type| = "ssrc" is statistics for a specific rtp stream.
-  // The |id| field is the SSRC in decimal form of the rtp stream.
-  static const char kStatsReportTypeSsrc[];
-
-  // StatsReport of |type| = "remoteSsrc" is statistics for a specific
-  // rtp stream, generated by the remote end of the connection.
-  static const char kStatsReportTypeRemoteSsrc[];
-
-  // StatsReport of |type| = "googTrack" is statistics for a specific media
-  // track. The |id| field is the track id.
-  static const char kStatsReportTypeTrack[];
-
-  // StatsReport of |type| = "localcandidate" or "remotecandidate" is attributes
-  // on a specific ICE Candidate. It links to its connection pair by candidate
-  // id. The string value is taken from
-  // http://w3c.github.io/webrtc-stats/#rtcstatstype-enum*.
-  static const char kStatsReportTypeIceLocalCandidate[];
-  static const char kStatsReportTypeIceRemoteCandidate[];
-
-  // A StatsReport of |type| = "googCertificate" contains an SSL certificate
-  // transmitted by one of the endpoints of this connection.  The |id| is
-  // controlled by the fingerprint, and is used to identify the certificate in
-  // the Channel stats (as "googLocalCertificateId" or
-  // "googRemoteCertificateId") and in any child certificates (as
-  // "googIssuerId").
-  static const char kStatsReportTypeCertificate[];
-
-  // The id of StatsReport of type VideoBWE.
-  static const char kStatsReportVideoBweId[];
-
-  // A StatsReport of |type| = "datachannel" with statistics for a
-  // particular DataChannel.
-  static const char kStatsReportTypeDataChannel[];
-};
-
-// This class is provided for the cases where we need to keep
-// snapshots of reports around.  This is an edge case.
-// TODO(tommi): Move into the private section of StatsSet.
-class StatsReportCopyable : public StatsReport {
- public:
-  StatsReportCopyable(const std::string& id) : StatsReport(id) {}
-  explicit StatsReportCopyable(const StatsReport& src)
-      : StatsReport(src) {}
-
-  using StatsReport::operator=;
+  DISALLOW_COPY_AND_ASSIGN(StatsReport);
 };
 
 // Typedef for an array of const StatsReport pointers.
 // Ownership of the pointers held by this implementation is assumed to lie
 // elsewhere and lifetime guarantees are made by the implementation that uses
-// this type.  In the StatsCollector, object ownership lies with the StatsSet
-// class.
+// this type.  In the StatsCollector, object ownership lies with the
+// StatsCollection class.
 typedef std::vector<const StatsReport*> StatsReports;
 
 // A map from the report id to the report.
 // This class wraps an STL container and provides a limited set of
 // functionality in order to keep things simple.
 // TODO(tommi): Use a thread checker here (currently not in libjingle).
-class StatsSet {
+class StatsCollection {
  public:
-  StatsSet();
-  ~StatsSet();
+  StatsCollection();
+  ~StatsCollection();
 
-  typedef std::set<StatsReportCopyable> Container;
+  // TODO(tommi): shared_ptr (or linked_ptr)?
+  typedef std::list<StatsReport*> Container;
   typedef Container::iterator iterator;
   typedef Container::const_iterator const_iterator;
 
   const_iterator begin() const;
   const_iterator end() const;
+  size_t size() const;
 
   // Creates a new report object with |id| that does not already
   // exist in the list of reports.
-  StatsReport* InsertNew(const std::string& id);
-  StatsReport* FindOrAddNew(const std::string& id);
-  StatsReport* ReplaceOrAddNew(const std::string& id);
+  StatsReport* InsertNew(rtc::scoped_ptr<StatsReport::Id> id);
+  StatsReport* FindOrAddNew(rtc::scoped_ptr<StatsReport::Id> id);
+  StatsReport* ReplaceOrAddNew(rtc::scoped_ptr<StatsReport::Id> id);
 
   // Looks for a report with the given |id|.  If one is not found, NULL
   // will be returned.
-  StatsReport* Find(const std::string& id);
+  StatsReport* Find(const StatsReport::Id& id);
+  // TODO(tommi): we should only need one of these.
+  StatsReport* Find(const rtc::scoped_ptr<StatsReport::Id>& id);
 
  private:
   Container list_;