Re-organized the functions in C++ Resources.

Review: https://reviews.apache.org/r/28078


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/bdf2d9d4
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/bdf2d9d4
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/bdf2d9d4

Branch: refs/heads/master
Commit: bdf2d9d410aeda6733a3d1ccdcd61ae7e89dac4a
Parents: 7ff4920
Author: Jie Yu <[email protected]>
Authored: Fri Nov 14 10:14:24 2014 -0800
Committer: Jie Yu <[email protected]>
Committed: Wed Nov 19 00:14:25 2014 -0800

----------------------------------------------------------------------
 include/mesos/resources.hpp | 154 ++++-----
 src/common/resources.cpp    | 697 ++++++++++++++++++++-------------------
 2 files changed, 428 insertions(+), 423 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/bdf2d9d4/include/mesos/resources.hpp
----------------------------------------------------------------------
diff --git a/include/mesos/resources.hpp b/include/mesos/resources.hpp
index 0e37170..c2ba597 100644
--- a/include/mesos/resources.hpp
+++ b/include/mesos/resources.hpp
@@ -19,6 +19,7 @@
 #ifndef __RESOURCES_HPP__
 #define __RESOURCES_HPP__
 
+#include <iostream>
 #include <string>
 
 #include <mesos/mesos.hpp>
@@ -26,6 +27,7 @@
 
 #include <stout/bytes.hpp>
 #include <stout/option.hpp>
+#include <stout/try.hpp>
 
 
 /**
@@ -50,28 +52,66 @@
  * names is a no-op.
  */
 
-
 namespace mesos {
 
-
 bool operator == (const Resource& left, const Resource& right);
 bool operator != (const Resource& left, const Resource& right);
+
+
 bool operator <= (const Resource& left, const Resource& right);
-Resource operator + (const Resource& left, const Resource& right);
-Resource operator - (const Resource& left, const Resource& right);
+
+
 Resource& operator += (Resource& left, const Resource& right);
+Resource operator + (const Resource& left, const Resource& right);
 Resource& operator -= (Resource& left, const Resource& right);
+Resource operator - (const Resource& left, const Resource& right);
+
+
 // Return true iff both Resources have the same name, type, and role.
 bool matches(const Resource& left, const Resource& right);
 
-std::ostream& operator << (std::ostream& stream, const Resource& resource);
-
 
 // TODO(bmahler): Ensure that the underlying resources are kept
 // in a flattened state: MESOS-1714.
 class Resources
 {
 public:
+  /**
+   * Parses the value and returns a Resource with the given name and role.
+   */
+  static Try<Resource> parse(
+      const std::string& name,
+      const std::string& value,
+      const std::string& role);
+
+  /**
+   * Parses resources in the form "name:value (role);name:value...".
+   * Any name/value pair that doesn't specify a role is assigned to 
defaultRole.
+   */
+  static Try<Resources> parse(
+      const std::string& s,
+      const std::string& defaultRole = "*");
+
+  /**
+   * Returns true iff this resource has a name, a valid type, i.e. scalar,
+   * range, or set, and has the appropriate value set for its type.
+   */
+  static bool isValid(const Resource& resource);
+
+  /**
+   * Returns true iff this resource is valid and allocatable. In particular,
+   * a scalar is allocatable if it's value is greater than zero, a ranges
+   * is allocatable if there is at least one valid range in it, and a set
+   * is allocatable if it has at least one item.
+   */
+  static bool isAllocatable(const Resource& resource);
+
+  /**
+   * Returns true iff this resource is zero valued, i.e. is zero for scalars,
+   * has a range size of zero for ranges, and has no items for sets.
+   */
+  static bool isZero(const Resource& resource);
+
   Resources() {}
 
   /*implicit*/
@@ -95,57 +135,16 @@ public:
     return *this;
   }
 
-  /**
-   * Returns a Resources object with only the allocatable resources.
-   */
-  Resources allocatable() const;
-
   size_t size() const
   {
     return resources.size();
   }
 
   /**
-   * Using this operator makes it easy to copy a resources object into
-   * a protocol buffer field.
+   * Returns all resources in this object that are marked with the
+   * specified role.
    */
-  operator const google::protobuf::RepeatedPtrField<Resource>& () const
-  {
-    return resources;
-  }
-
-  bool operator == (const Resources& that) const;
-
-  bool operator != (const Resources& that) const
-  {
-    return !(*this == that);
-  }
-
-  bool operator <= (const Resources& that) const;
-
-  Resources operator + (const Resources& that) const;
-
-  Resources operator - (const Resources& that) const;
-
-  Resources& operator += (const Resources& that);
-
-  Resources& operator -= (const Resources& that);
-
-  Resources operator + (const Resource& that) const;
-
-  Resources operator - (const Resource& that) const;
-
-  Resources& operator += (const Resource& that)
-  {
-    *this = *this + that;
-    return *this;
-  }
-
-  Resources& operator -= (const Resource& that)
-  {
-    *this = *this - that;
-    return *this;
-  }
+  Resources extract(const std::string& role) const;
 
   /**
    * Returns a Resources object with the same amount of each resource
@@ -155,12 +154,6 @@ public:
   Resources flatten(const std::string& role = "*") const;
 
   /**
-   * Returns all resources in this object that are marked with the
-   * specified role.
-   */
-  Resources extract(const std::string& role) const;
-
-  /**
    * Finds a number of resources equal to toFind in these Resources
    * and returns them marked with appropriate roles. For each resource
    * type, resources are first taken from the specified role, then
@@ -185,6 +178,11 @@ public:
   template <typename T>
   T get(const std::string& name, const T& t) const;
 
+  /**
+   * Returns a Resources object with only the allocatable resources.
+   */
+  Resources allocatable() const;
+
   // Helpers to get known resource types.
   // TODO(vinod): Fix this when we make these types as first class protobufs.
   Option<double> cpus() const;
@@ -215,46 +213,32 @@ public:
   const_iterator end() const { return resources.end(); }
 
   /**
-   * Parses the value and returns a Resource with the given name and role.
+   * Using this operator makes it easy to copy a resources object into
+   * a protocol buffer field.
    */
-  static Try<Resource> parse(
-      const std::string& name,
-      const std::string& value,
-      const std::string& role);
+  operator const google::protobuf::RepeatedPtrField<Resource>& () const;
 
-  /**
-   * Parses resources in the form "name:value (role);name:value...".
-   * Any name/value pair that doesn't specify a role is assigned to 
defaultRole.
-   */
-  static Try<Resources> parse(
-      const std::string& s,
-      const std::string& defaultRole = "*");
+  bool operator == (const Resources& that) const;
+  bool operator != (const Resources& that) const;
 
-  /**
-   * Returns true iff this resource has a name, a valid type, i.e. scalar,
-   * range, or set, and has the appropriate value set for its type.
-   */
-  static bool isValid(const Resource& resource);
+  bool operator <= (const Resources& that) const;
 
-  /**
-   * Returns true iff this resource is valid and allocatable. In particular,
-   * a scalar is allocatable if it's value is greater than zero, a ranges
-   * is allocatable if there is at least one valid range in it, and a set
-   * is allocatable if it has at least one item.
-   */
-  static bool isAllocatable(const Resource& resource);
+  Resources operator + (const Resource& that) const;
+  Resources operator + (const Resources& that) const;
+  Resources& operator += (const Resource& that);
+  Resources& operator += (const Resources& that);
 
-  /**
-   * Returns true iff this resource is zero valued, i.e. is zero for scalars,
-   * has a range size of zero for ranges, and has no items for sets.
-   */
-  static bool isZero(const Resource& resource);
+  Resources operator - (const Resource& that) const;
+  Resources operator - (const Resources& that) const;
+  Resources& operator -= (const Resource& that);
+  Resources& operator -= (const Resources& that);
 
 private:
   google::protobuf::RepeatedPtrField<Resource> resources;
 };
 
 
+std::ostream& operator << (std::ostream& stream, const Resource& resource);
 std::ostream& operator << (std::ostream& stream, const Resources& resources);
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/bdf2d9d4/src/common/resources.cpp
----------------------------------------------------------------------
diff --git a/src/common/resources.cpp b/src/common/resources.cpp
index e9a0c85..1ffebbb 100644
--- a/src/common/resources.cpp
+++ b/src/common/resources.cpp
@@ -18,7 +18,6 @@
 
 #include <stdint.h>
 
-#include <iostream>
 #include <vector>
 
 #include <glog/logging.h>
@@ -28,7 +27,6 @@
 
 #include <stout/foreach.hpp>
 #include <stout/strings.hpp>
-#include <stout/try.hpp>
 
 using std::ostream;
 using std::string;
@@ -59,14 +57,6 @@ bool operator != (const Resource& left, const Resource& 
right)
 }
 
 
-bool matches(const Resource& left, const Resource& right)
-{
-  return left.name() == right.name() &&
-    left.type() == right.type() &&
-    left.role() == right.role();
-}
-
-
 bool operator <= (const Resource& left, const Resource& right)
 {
   if (matches(left, right)) {
@@ -83,39 +73,37 @@ bool operator <= (const Resource& left, const Resource& 
right)
 }
 
 
-Resource operator + (const Resource& left, const Resource& right)
+Resource& operator += (Resource& left, const Resource& right)
 {
-  Resource result = left;
-
   if (matches(left, right)) {
     if (left.type() == Value::SCALAR) {
-      result.mutable_scalar()->MergeFrom(left.scalar() + right.scalar());
+      left.mutable_scalar()->MergeFrom(left.scalar() + right.scalar());
     } else if (left.type() == Value::RANGES) {
-      result.mutable_ranges()->Clear();
-      result.mutable_ranges()->MergeFrom(left.ranges() + right.ranges());
+      left.mutable_ranges()->Clear();
+      left.mutable_ranges()->MergeFrom(left.ranges() + right.ranges());
     } else if (left.type() == Value::SET) {
-      result.mutable_set()->Clear();
-      result.mutable_set()->MergeFrom(left.set() + right.set());
+      left.mutable_set()->Clear();
+      left.mutable_set()->MergeFrom(left.set() + right.set());
     }
   }
 
-  return result;
+  return left;
 }
 
 
-Resource operator - (const Resource& left, const Resource& right)
+Resource operator + (const Resource& left, const Resource& right)
 {
   Resource result = left;
 
   if (matches(left, right)) {
     if (left.type() == Value::SCALAR) {
-      result.mutable_scalar()->MergeFrom(left.scalar() - right.scalar());
+      result.mutable_scalar()->MergeFrom(left.scalar() + right.scalar());
     } else if (left.type() == Value::RANGES) {
       result.mutable_ranges()->Clear();
-      result.mutable_ranges()->MergeFrom(left.ranges() - right.ranges());
+      result.mutable_ranges()->MergeFrom(left.ranges() + right.ranges());
     } else if (left.type() == Value::SET) {
       result.mutable_set()->Clear();
-      result.mutable_set()->MergeFrom(left.set() - right.set());
+      result.mutable_set()->MergeFrom(left.set() + right.set());
     }
   }
 
@@ -123,17 +111,17 @@ Resource operator - (const Resource& left, const 
Resource& right)
 }
 
 
-Resource& operator += (Resource& left, const Resource& right)
+Resource& operator -= (Resource& left, const Resource& right)
 {
   if (matches(left, right)) {
     if (left.type() == Value::SCALAR) {
-      left.mutable_scalar()->MergeFrom(left.scalar() + right.scalar());
+      left.mutable_scalar()->MergeFrom(left.scalar() - right.scalar());
     } else if (left.type() == Value::RANGES) {
       left.mutable_ranges()->Clear();
-      left.mutable_ranges()->MergeFrom(left.ranges() + right.ranges());
+      left.mutable_ranges()->MergeFrom(left.ranges() - right.ranges());
     } else if (left.type() == Value::SET) {
       left.mutable_set()->Clear();
-      left.mutable_set()->MergeFrom(left.set() + right.set());
+      left.mutable_set()->MergeFrom(left.set() - right.set());
     }
   }
 
@@ -141,188 +129,223 @@ Resource& operator += (Resource& left, const Resource& 
right)
 }
 
 
-Resource& operator -= (Resource& left, const Resource& right)
+Resource operator - (const Resource& left, const Resource& right)
 {
+  Resource result = left;
+
   if (matches(left, right)) {
     if (left.type() == Value::SCALAR) {
-      left.mutable_scalar()->MergeFrom(left.scalar() - right.scalar());
+      result.mutable_scalar()->MergeFrom(left.scalar() - right.scalar());
     } else if (left.type() == Value::RANGES) {
-      left.mutable_ranges()->Clear();
-      left.mutable_ranges()->MergeFrom(left.ranges() - right.ranges());
+      result.mutable_ranges()->Clear();
+      result.mutable_ranges()->MergeFrom(left.ranges() - right.ranges());
     } else if (left.type() == Value::SET) {
-      left.mutable_set()->Clear();
-      left.mutable_set()->MergeFrom(left.set() - right.set());
+      result.mutable_set()->Clear();
+      result.mutable_set()->MergeFrom(left.set() - right.set());
     }
   }
 
-  return left;
+  return result;
 }
 
 
-ostream& operator << (ostream& stream, const Resource& resource)
+bool matches(const Resource& left, const Resource& right)
 {
-  stream << resource.name() << "(" << resource.role() << "):";
+  return left.name() == right.name() &&
+    left.type() == right.type() &&
+    left.role() == right.role();
+}
 
-  switch (resource.type()) {
-    case Value::SCALAR: stream << resource.scalar(); break;
-    case Value::RANGES: stream << resource.ranges(); break;
-    case Value::SET:    stream << resource.set();    break;
-    default:
-      LOG(FATAL) << "Unexpected Value type: " << resource.type();
-      break;
+
+Try<Resource> Resources::parse(
+    const string& name,
+    const string& text,
+    const string& role)
+{
+  Resource resource;
+  Try<Value> result = internal::values::parse(text);
+
+  if (result.isError()) {
+    return Error("Failed to parse resource " + name +
+                 " text " + text +
+                 " error " + result.error());
+  } else{
+    Value value = result.get();
+    resource.set_name(name);
+    resource.set_role(role);
+
+    if (value.type() == Value::RANGES) {
+      resource.set_type(Value::RANGES);
+      resource.mutable_ranges()->MergeFrom(value.ranges());
+    } else if (value.type() == Value::SET) {
+      resource.set_type(Value::SET);
+      resource.mutable_set()->MergeFrom(value.set());
+    } else if (value.type() == Value::SCALAR) {
+      resource.set_type(Value::SCALAR);
+      resource.mutable_scalar()->MergeFrom(value.scalar());
+    } else {
+      return Error("Bad type for resource " + name +
+                   " text " + text +
+                   " type " + Value::Type_Name(value.type()));
+    }
   }
 
-  return stream;
+  return resource;
 }
 
 
-Resources Resources::allocatable() const
+Try<Resources> Resources::parse(const string& s, const string& defaultRole)
 {
-  Resources result;
+  Resources resources;
 
-  foreach (const Resource& resource, resources) {
-    if (isAllocatable(resource)) {
-      result.resources.Add()->MergeFrom(resource);
+  vector<string> tokens = strings::tokenize(s, ";");
+
+  foreach (const string& token, tokens) {
+    vector<string> pair = strings::tokenize(token, ":");
+    if (pair.size() != 2) {
+      return Error("Bad value for resources, missing or extra ':' in " + 
token);
+    }
+
+    string name;
+    string role;
+    size_t openParen = pair[0].find("(");
+    if (openParen == string::npos) {
+      name = strings::trim(pair[0]);
+      role = defaultRole;
+    } else {
+      size_t closeParen = pair[0].find(")");
+      if (closeParen == string::npos || closeParen < openParen) {
+        return Error("Bad value for resources, mismatched parentheses in " +
+                     token);
+      }
+
+      name = strings::trim(pair[0].substr(0, openParen));
+      role = strings::trim(pair[0].substr(openParen + 1,
+                                          closeParen - openParen - 1));
+    }
+
+    Try<Resource> resource = Resources::parse(name, pair[1], role);
+    if (resource.isError()) {
+      return Error(resource.error());
     }
+    resources += resource.get();
   }
 
-  return result;
+  return resources;
 }
 
 
-bool Resources::operator == (const Resources& that) const
+bool Resources::isValid(const Resource& resource)
 {
-  if (size() != that.size()) {
+  if (!resource.has_name() ||
+      resource.name() == "" ||
+      !resource.has_type() ||
+      !Value::Type_IsValid(resource.type())) {
     return false;
   }
 
-  foreach (const Resource& resource, resources) {
-    Option<Resource> option = that.get(resource);
-    if (option.isNone()) {
-      return false;
-      } else {
-      if (!(resource == option.get())) {
-        return false;
-      }
-    }
+  if (resource.type() == Value::SCALAR) {
+    return resource.has_scalar();
+  } else if (resource.type() == Value::RANGES) {
+    return resource.has_ranges();
+  } else if (resource.type() == Value::SET) {
+    return resource.has_set();
+  } else if (resource.type() == Value::TEXT) {
+    // Resources doesn't support text.
+    return false;
   }
 
-    return true;
+  return false;
 }
 
 
-bool Resources::operator <= (const Resources& that) const
+bool Resources::isAllocatable(const Resource& resource)
 {
-  foreach (const Resource& resource, resources) {
-    Option<Resource> option = that.get(resource);
-    if (option.isNone()) {
-      if (!isZero(resource)) {
+  if (isValid(resource)) {
+    if (resource.type() == Value::SCALAR) {
+      if (resource.scalar().value() <= 0) {
         return false;
       }
-    } else {
-      if (!(resource <= option.get())) {
+    } else if (resource.type() == Value::RANGES) {
+      if (resource.ranges().range_size() == 0) {
+        return false;
+      } else {
+        for (int i = 0; i < resource.ranges().range_size(); i++) {
+          const Value::Range& range = resource.ranges().range(i);
+
+          // Ensure the range make sense (isn't inverted).
+          if (range.begin() > range.end()) {
+            return false;
+          }
+
+          // Ensure ranges don't overlap (but not necessarily coalesced).
+          for (int j = i + 1; j < resource.ranges().range_size(); j++) {
+            if (range.begin() <= resource.ranges().range(j).begin() &&
+                resource.ranges().range(j).begin() <= range.end()) {
+              return false;
+            }
+          }
+        }
+      }
+    } else if (resource.type() == Value::SET) {
+      if (resource.set().item_size() == 0) {
         return false;
+      } else {
+        for (int i = 0; i < resource.set().item_size(); i++) {
+          const string& item = resource.set().item(i);
+
+          // Ensure no duplicates.
+          for (int j = i + 1; j < resource.set().item_size(); j++) {
+            if (item == resource.set().item(j)) {
+              return false;
+            }
+          }
+        }
       }
     }
+
+    return true;
   }
 
-  return true;
+  return false;
 }
 
 
-Resources Resources::operator + (const Resources& that) const
+bool Resources::isZero(const Resource& resource)
 {
-  Resources result(*this);
-
-  foreach (const Resource& resource, that.resources) {
-    result += resource;
+  if (resource.type() == Value::SCALAR) {
+    return resource.scalar().value() == 0;
+  } else if (resource.type() == Value::RANGES) {
+    return resource.ranges().range_size() == 0;
+  } else if (resource.type() == Value::SET) {
+    return resource.set().item_size() == 0;
   }
 
-  return result;
+  return false;
 }
 
 
-Resources Resources::operator - (const Resources& that) const
+Resources Resources::extract(const string& role) const
 {
-  Resources result(*this);
+  Resources r;
 
-  foreach (const Resource& resource, that.resources) {
-    result -= resource;
+  foreach (const Resource& resource, resources) {
+    if (resource.role() == role) {
+      r += resource;
+    }
   }
 
-  return result;
+  return r;
 }
 
 
-Resources& Resources::operator += (const Resources& that)
+Resources Resources::flatten(const string& role) const
 {
-  foreach (const Resource& resource, that.resources) {
-    *this += resource;
-  }
-
-  return *this;
-}
+  Resources flattened;
 
-
-Resources& Resources::operator -= (const Resources& that)
-{
-  foreach (const Resource& resource, that.resources) {
-    *this -= resource;
-  }
-
-  return *this;
-}
-
-
-Resources Resources::operator + (const Resource& that) const
-{
-  Resources result;
-
-  bool added = false;
-
-  foreach (const Resource& resource, resources) {
-    if (matches(resource, that)) {
-      result.resources.Add()->MergeFrom(resource + that);
-      added = true;
-    } else {
-      result.resources.Add()->MergeFrom(resource);
-    }
-  }
-
-  if (!added) {
-    result.resources.Add()->MergeFrom(that);
-  }
-
-  return result;
-}
-
-
-Resources Resources::operator - (const Resource& that) const
-{
-  Resources result;
-
-  foreach (const Resource& resource, resources) {
-    if (matches(resource, that)) {
-      Resource r = resource - that;
-      if (!isZero(r)) {
-        result.resources.Add()->MergeFrom(r);
-      }
-    } else {
-      result.resources.Add()->MergeFrom(resource);
-    }
-  }
-
-  return result;
-}
-
-
-Resources Resources::flatten(const string& role) const
-{
-  Resources flattened;
-
-  foreach (const Resource& r, resources) {
-    Resource toRemove = r;
-    toRemove.set_role(role);
+  foreach (const Resource& r, resources) {
+    Resource toRemove = r;
+    toRemove.set_role(role);
 
     bool found = false;
     for (int i = 0; i < flattened.resources.size(); i++) {
@@ -344,20 +367,6 @@ Resources Resources::flatten(const string& role) const
 }
 
 
-Resources Resources::extract(const string& role) const
-{
-  Resources r;
-
-  foreach (const Resource& resource, resources) {
-    if (resource.role() == role) {
-      r += resource;
-    }
-  }
-
-  return r;
-}
-
-
 Option<Resources> Resources::find(
     const Resources& toFind,
     const string& role) const
@@ -439,6 +448,92 @@ Option<Resources> Resources::getAll(const Resource& r) 
const
 }
 
 
+template <>
+Value::Scalar Resources::get(
+    const string& name,
+    const Value::Scalar& scalar) const
+{
+  Value::Scalar total;
+  bool found = false;
+
+  foreach (const Resource& resource, resources) {
+    if (resource.name() == name &&
+        resource.type() == Value::SCALAR) {
+      total += resource.scalar();
+      found = true;
+    }
+  }
+
+  if (found) {
+    return total;
+  }
+
+  return scalar;
+}
+
+
+template <>
+Value::Ranges Resources::get(
+    const string& name,
+    const Value::Ranges& ranges) const
+{
+  Value::Ranges total;
+  bool found = false;
+
+  foreach (const Resource& resource, resources) {
+    if (resource.name() == name &&
+        resource.type() == Value::RANGES) {
+      total += resource.ranges();
+      found = true;
+    }
+  }
+
+  if (found) {
+    return total;
+  }
+
+  return ranges;
+}
+
+
+template <>
+Value::Set Resources::get(
+    const string& name,
+    const Value::Set& set) const
+{
+  Value::Set total;
+  bool found = false;
+
+  foreach (const Resource& resource, resources) {
+    if (resource.name() == name &&
+        resource.type() == Value::SET) {
+      total += resource.set();
+      found = true;
+    }
+  }
+
+  if (found) {
+    return total;
+  }
+
+  return set;
+}
+
+
+Resources Resources::allocatable() const
+{
+  Resources result;
+
+  foreach (const Resource& resource, resources) {
+    if (isAllocatable(resource)) {
+      result.resources.Add()->MergeFrom(resource);
+    }
+  }
+
+  return result;
+}
+
+
 Option<double> Resources::cpus() const
 {
   double total= 0;
@@ -573,249 +668,176 @@ Option<Value::Ranges> Resources::ephemeral_ports() const
 }
 
 
-Try<Resource> Resources::parse(
-    const string& name,
-    const string& text,
-    const string& role)
+Resources::operator const google::protobuf::RepeatedPtrField<Resource>& () 
const
 {
-  Resource resource;
-  Try<Value> result = internal::values::parse(text);
+  return resources;
+}
 
-  if (result.isError()) {
-    return Error("Failed to parse resource " + name +
-                 " text " + text +
-                 " error " + result.error());
-  } else{
-    Value value = result.get();
-    resource.set_name(name);
-    resource.set_role(role);
 
-    if (value.type() == Value::RANGES) {
-      resource.set_type(Value::RANGES);
-      resource.mutable_ranges()->MergeFrom(value.ranges());
-    } else if (value.type() == Value::SET) {
-      resource.set_type(Value::SET);
-      resource.mutable_set()->MergeFrom(value.set());
-    } else if (value.type() == Value::SCALAR) {
-      resource.set_type(Value::SCALAR);
-      resource.mutable_scalar()->MergeFrom(value.scalar());
-    } else {
-      return Error("Bad type for resource " + name +
-                   " text " + text +
-                   " type " + Value::Type_Name(value.type()));
+bool Resources::operator == (const Resources& that) const
+{
+  if (size() != that.size()) {
+    return false;
+  }
+
+  foreach (const Resource& resource, resources) {
+    Option<Resource> option = that.get(resource);
+    if (option.isNone()) {
+      return false;
+      } else {
+      if (!(resource == option.get())) {
+        return false;
+      }
     }
   }
 
-  return resource;
+    return true;
 }
 
 
-Try<Resources> Resources::parse(const string& s, const string& defaultRole)
+bool Resources::operator != (const Resources& that) const
 {
-  Resources resources;
+  return !(*this == that);
+}
 
-  vector<string> tokens = strings::tokenize(s, ";");
 
-  foreach (const string& token, tokens) {
-    vector<string> pair = strings::tokenize(token, ":");
-    if (pair.size() != 2) {
-      return Error("Bad value for resources, missing or extra ':' in " + 
token);
-    }
-
-    string name;
-    string role;
-    size_t openParen = pair[0].find("(");
-    if (openParen == string::npos) {
-      name = strings::trim(pair[0]);
-      role = defaultRole;
+bool Resources::operator <= (const Resources& that) const
+{
+  foreach (const Resource& resource, resources) {
+    Option<Resource> option = that.get(resource);
+    if (option.isNone()) {
+      if (!isZero(resource)) {
+        return false;
+      }
     } else {
-      size_t closeParen = pair[0].find(")");
-      if (closeParen == string::npos || closeParen < openParen) {
-        return Error("Bad value for resources, mismatched parentheses in " +
-                     token);
+      if (!(resource <= option.get())) {
+        return false;
       }
-
-      name = strings::trim(pair[0].substr(0, openParen));
-      role = strings::trim(pair[0].substr(openParen + 1,
-                                          closeParen - openParen - 1));
     }
-
-    Try<Resource> resource = Resources::parse(name, pair[1], role);
-    if (resource.isError()) {
-      return Error(resource.error());
-    }
-    resources += resource.get();
   }
 
-  return resources;
+  return true;
 }
 
 
-bool Resources::isValid(const Resource& resource)
+Resources Resources::operator + (const Resource& that) const
 {
-  if (!resource.has_name() ||
-      resource.name() == "" ||
-      !resource.has_type() ||
-      !Value::Type_IsValid(resource.type())) {
-    return false;
+  Resources result;
+
+  bool added = false;
+
+  foreach (const Resource& resource, resources) {
+    if (matches(resource, that)) {
+      result.resources.Add()->MergeFrom(resource + that);
+      added = true;
+    } else {
+      result.resources.Add()->MergeFrom(resource);
+    }
   }
 
-  if (resource.type() == Value::SCALAR) {
-    return resource.has_scalar();
-  } else if (resource.type() == Value::RANGES) {
-    return resource.has_ranges();
-  } else if (resource.type() == Value::SET) {
-    return resource.has_set();
-  } else if (resource.type() == Value::TEXT) {
-    // Resources doesn't support text.
-    return false;
+  if (!added) {
+    result.resources.Add()->MergeFrom(that);
   }
 
-  return false;
+  return result;
 }
 
 
-bool Resources::isAllocatable(const Resource& resource)
+Resources Resources::operator + (const Resources& that) const
 {
-  if (isValid(resource)) {
-    if (resource.type() == Value::SCALAR) {
-      if (resource.scalar().value() <= 0) {
-        return false;
-      }
-    } else if (resource.type() == Value::RANGES) {
-      if (resource.ranges().range_size() == 0) {
-        return false;
-      } else {
-        for (int i = 0; i < resource.ranges().range_size(); i++) {
-          const Value::Range& range = resource.ranges().range(i);
-
-          // Ensure the range make sense (isn't inverted).
-          if (range.begin() > range.end()) {
-            return false;
-          }
+  Resources result(*this);
 
-          // Ensure ranges don't overlap (but not necessarily coalesced).
-          for (int j = i + 1; j < resource.ranges().range_size(); j++) {
-            if (range.begin() <= resource.ranges().range(j).begin() &&
-                resource.ranges().range(j).begin() <= range.end()) {
-              return false;
-            }
-          }
-        }
-      }
-    } else if (resource.type() == Value::SET) {
-      if (resource.set().item_size() == 0) {
-        return false;
-      } else {
-        for (int i = 0; i < resource.set().item_size(); i++) {
-          const std::string& item = resource.set().item(i);
+  foreach (const Resource& resource, that.resources) {
+    result += resource;
+  }
 
-          // Ensure no duplicates.
-          for (int j = i + 1; j < resource.set().item_size(); j++) {
-            if (item == resource.set().item(j)) {
-              return false;
-            }
-          }
-        }
-      }
-    }
+  return result;
+}
 
-    return true;
-  }
 
-  return false;
+Resources& Resources::operator += (const Resource& that)
+{
+  *this = *this + that;
+  return *this;
 }
 
 
-bool Resources::isZero(const Resource& resource)
+Resources& Resources::operator += (const Resources& that)
 {
-  if (resource.type() == Value::SCALAR) {
-    return resource.scalar().value() == 0;
-  } else if (resource.type() == Value::RANGES) {
-    return resource.ranges().range_size() == 0;
-  } else if (resource.type() == Value::SET) {
-    return resource.set().item_size() == 0;
+  foreach (const Resource& resource, that.resources) {
+    *this += resource;
   }
 
-  return false;
+  return *this;
 }
 
 
-template <>
-Value::Scalar Resources::get(
-    const std::string& name,
-    const Value::Scalar& scalar) const
+Resources Resources::operator - (const Resource& that) const
 {
-  Value::Scalar total;
-  bool found = false;
+  Resources result;
 
   foreach (const Resource& resource, resources) {
-    if (resource.name() == name &&
-        resource.type() == Value::SCALAR) {
-      total += resource.scalar();
-      found = true;
+    if (matches(resource, that)) {
+      Resource r = resource - that;
+      if (!isZero(r)) {
+        result.resources.Add()->MergeFrom(r);
+      }
+    } else {
+      result.resources.Add()->MergeFrom(resource);
     }
   }
 
-  if (found) {
-    return total;
+  return result;
+}
+
+
+Resources Resources::operator - (const Resources& that) const
+{
+  Resources result(*this);
+
+  foreach (const Resource& resource, that.resources) {
+    result -= resource;
   }
 
-  return scalar;
+  return result;
 }
 
 
-template <>
-Value::Ranges Resources::get(
-    const std::string& name,
-    const Value::Ranges& ranges) const
+Resources& Resources::operator -= (const Resource& that)
 {
-  Value::Ranges total;
-  bool found = false;
+  *this = *this - that;
+  return *this;
+}
 
-  foreach (const Resource& resource, resources) {
-    if (resource.name() == name &&
-        resource.type() == Value::RANGES) {
-      total += resource.ranges();
-      found = true;
-    }
-  }
 
-  if (found) {
-    return total;
+Resources& Resources::operator -= (const Resources& that)
+{
+  foreach (const Resource& resource, that.resources) {
+    *this -= resource;
   }
 
-  return ranges;
+  return *this;
 }
 
 
-template <>
-Value::Set Resources::get(
-    const std::string& name,
-    const Value::Set& set) const
+ostream& operator << (ostream& stream, const Resource& resource)
 {
-  Value::Set total;
-  bool found = false;
-
-  foreach (const Resource& resource, resources) {
-    if (resource.name() == name &&
-        resource.type() == Value::SET) {
-      total += resource.set();
-      found = true;
-    }
-  }
+  stream << resource.name() << "(" << resource.role() << "):";
 
-  if (found) {
-    return total;
+  switch (resource.type()) {
+    case Value::SCALAR: stream << resource.scalar(); break;
+    case Value::RANGES: stream << resource.ranges(); break;
+    case Value::SET:    stream << resource.set();    break;
+    default:
+      LOG(FATAL) << "Unexpected Value type: " << resource.type();
+      break;
   }
 
-  return set;
+  return stream;
 }
 
 
-std::ostream& operator << (
-    std::ostream& stream,
-    const Resources& resources)
+ostream& operator << (ostream& stream, const Resources& resources)
 {
   mesos::Resources::const_iterator it = resources.begin();
 
@@ -829,5 +851,4 @@ std::ostream& operator << (
   return stream;
 }
 
-
 } // namespace mesos {

Reply via email to