[ 
https://issues.apache.org/jira/browse/MESOS-3404?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14952863#comment-14952863
 ] 

Benjamin Bannier commented on MESOS-3404:
-----------------------------------------

Here is the full list of duplicates found by duplo(-fork),

{code}
% duplo src/v1/*cpp src/common/*cpp
{code}

----

{code}
src/v1/attributes.cpp(30)
src/v1/resources.cpp(38)
using std::string;
using std::vector;
namespace mesos {
namespace v1 {

src/v1/attributes.cpp(29)
src/v1/values.cpp(41)
using std::ostream;
using std::string;
using std::vector;
namespace mesos {
namespace v1 {

src/v1/attributes.cpp(26)
src/common/attributes.cpp(26)
#include <stout/foreach.hpp>
#include <stout/strings.hpp>
using std::ostream;
using std::string;
using std::vector;
namespace mesos {

src/v1/attributes.cpp(36)
src/common/attributes.cpp(36)
std::ostream& operator<<(std::ostream& stream, const Attribute& attribute)
  stream << attribute.name() << "=";
  switch (attribute.type()) {
    case Value::SCALAR: stream << attribute.scalar(); break;
    case Value::RANGES: stream << attribute.ranges(); break;
    case Value::SET:    stream << attribute.set();    break;
    case Value::TEXT:   stream << attribute.text();   break;
    default:
      LOG(FATAL) << "Unexpected Value type: " << attribute.type();
      break;
  return stream;
bool Attributes::operator==(const Attributes& that) const
  if (size() != that.size()) {
    return false;
  foreach (const Attribute& attribute, attributes) {
    Option<Attribute> maybeAttribute = that.get(attribute);
    if (maybeAttribute.isNone()) {
        return false;
    const Attribute& thatAttribute = maybeAttribute.get();
    switch (attribute.type()) {
    case Value::SCALAR:
      if (!(attribute.scalar() == thatAttribute.scalar())) {
        return false;
      break;
    case Value::RANGES:
      if (!(attribute.ranges() == thatAttribute.ranges())) {
        return false;
      break;
    case Value::TEXT:
      if (!(attribute.text() == thatAttribute.text())) {
        return false;
      break;
    case Value::SET:
      LOG(FATAL) << "Sets not supported for attributes";
  return true;
const Option<Attribute> Attributes::get(const Attribute& thatAttribute) const
  foreach (const Attribute& attribute, attributes) {
    if (attribute.name() == thatAttribute.name() &&
        attribute.type() == thatAttribute.type()) {
      return attribute;
  return None();
Attribute Attributes::parse(const string& name, const string& text)
  Attribute attribute;
  Try<Value> result = internal::values::parse(text);
  if (result.isError()) {
    LOG(FATAL) << "Failed to parse attribute " << name
               << " text " << text
               << " error " << result.error();
  } else {
    Value value = result.get();
    attribute.set_name(name);
    if (value.type() == Value::RANGES) {
      attribute.set_type(Value::RANGES);
      attribute.mutable_ranges()->MergeFrom(value.ranges());
    } else if (value.type() == Value::TEXT) {
      attribute.set_type(Value::TEXT);
      attribute.mutable_text()->MergeFrom(value.text());
    } else if (value.type() == Value::SCALAR) {
      attribute.set_type(Value::SCALAR);
      attribute.mutable_scalar()->MergeFrom(value.scalar());
    } else {
      LOG(FATAL) << "Bad type for attribute " << name
                 << " text " << text
                 << " type " << value.type();
  return attribute;
Attributes Attributes::parse(const string& s)
  Attributes attributes;
  vector<string> tokens = strings::tokenize(s, ";\n");
  for (size_t i = 0; i < tokens.size(); i++) {
    const vector<string>& pairs = strings::split(tokens[i], ":", 2);
    if (pairs.size() != 2 || pairs[0].empty() || pairs[1].empty()) {
      LOG(FATAL) << "Invalid attribute key:value pair '" << tokens[i] << "'";
    attributes.add(parse(pairs[0], pairs[1]));
  return attributes;
bool Attributes::isValid(const Attribute& attribute)
  if (!attribute.has_name() ||
      attribute.name() == "" ||
      !attribute.has_type() ||
      !Value::Type_IsValid(attribute.type())) {
    return false;
  if (attribute.type() == Value::SCALAR) {
    return attribute.has_scalar();
  } else if (attribute.type() == Value::RANGES) {
    return attribute.has_ranges();
  } else if (attribute.type() == Value::TEXT) {
    return attribute.has_text();
  } else if (attribute.type() == Value::SET) {
    return false;
    return false;
template <>
Value::Scalar Attributes::get(
    const string& name,
    const Value::Scalar& scalar) const
  foreach (const Attribute& attribute, attributes) {
    if (attribute.name() == name &&
        attribute.type() == Value::SCALAR) {
      return attribute.scalar();
  return scalar;
template <>
Value::Ranges Attributes::get(
    const string& name,
    const Value::Ranges& ranges) const
  foreach (const Attribute& attribute, attributes) {
    if (attribute.name() == name &&
        attribute.type() == Value::RANGES) {
      return attribute.ranges();
  return ranges;
template <>
Value::Text Attributes::get(
    const string& name,
    const Value::Text& text) const
  foreach (const Attribute& attribute, attributes) {
    if (attribute.name() == name &&
        attribute.type() == Value::TEXT) {
      return attribute.text();
  return text;

src/v1/attributes.cpp(29)
src/common/values.cpp(41)
using std::ostream;
using std::string;
using std::vector;
namespace mesos {

src/v1/mesos.cpp(270)
src/v1/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(240)
src/v1/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(206)
src/v1/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(179)
src/v1/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(270)
src/v1/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(161)
src/v1/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(270)
src/v1/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(240)
src/v1/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(240)
src/v1/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(206)
src/v1/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(104)
src/v1/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(206)
src/v1/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(179)
src/v1/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(161)
src/v1/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(179)
src/v1/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(39)
src/v1/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(161)
src/v1/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(104)
src/v1/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(104)
src/v1/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(39)
src/v1/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(39)
src/v1/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(179)
src/common/type_utils.cpp(163)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(270)
src/common/type_utils.cpp(242)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(206)
src/common/type_utils.cpp(181)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(240)
src/common/type_utils.cpp(208)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(206)
src/common/type_utils.cpp(163)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(161)
src/common/type_utils.cpp(106)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(104)
src/common/type_utils.cpp(41)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(270)
src/common/type_utils.cpp(208)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(240)
src/common/type_utils.cpp(181)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(179)
src/common/type_utils.cpp(106)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(240)
src/common/type_utils.cpp(163)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(270)
src/common/type_utils.cpp(181)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(206)
src/common/type_utils.cpp(106)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(270)
src/common/type_utils.cpp(163)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(161)
src/common/type_utils.cpp(41)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(179)
src/common/type_utils.cpp(41)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(240)
src/common/type_utils.cpp(106)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(206)
src/common/type_utils.cpp(41)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(270)
src/common/type_utils.cpp(106)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(240)
src/common/type_utils.cpp(41)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(270)
src/common/type_utils.cpp(41)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(28)
src/common/type_utils.cpp(30)
bool operator==(const CommandInfo& left, const CommandInfo& right)
  if (left.uris().size() != right.uris().size()) {
    return false;
  for (int i = 0; i < left.uris().size(); i++) {
    bool found = false;
    for (int j = 0; j < right.uris().size(); j++) {
      if (left.uris().Get(i) == right.uris().Get(j)) {
        found = true;
        break;
    if (!found) {
      return false;
  if (left.arguments().size() != right.arguments().size()) {
    return false;
  for (int i = 0; i < left.arguments().size(); i++) {
    if (left.arguments().Get(i) != right.arguments().Get(i)) {
      return false;
  return left.environment() == right.environment() &&
    left.value() == right.value() &&
    left.user() == right.user() &&
    left.shell() == right.shell();
bool operator==(const CommandInfo::URI& left, const CommandInfo::URI& right)
  return left.value() == right.value() &&
    left.executable() == right.executable() &&
    left.extract() == right.extract();
bool operator==(const Credential& left, const Credential& right)
  return left.principal() == right.principal() &&
    left.secret() == right.secret();
bool operator==(
    const Environment::Variable& left,
    const Environment::Variable& right)
  return left.name() == right.name() && left.value() == right.value();
bool operator==(const Environment& left, const Environment& right)
  if (left.variables().size() != right.variables().size()) {
    return false;
  for (int i = 0; i < left.variables().size(); i++) {
    bool found = false;
    for (int j = 0; j < right.variables().size(); j++) {
      if (left.variables().Get(i) == right.variables().Get(j)) {
        found = true;
        break;
    if (!found) {
      return false;
  return true;
bool operator==(const Volume& left, const Volume& right)
  return left.container_path() == right.container_path() &&
    left.host_path() == right.host_path() &&
    left.mode() == right.mode();
bool operator==(const URL& left, const URL& right)
  return left.SerializeAsString() == right.SerializeAsString();
bool operator==(
    const ContainerInfo::DockerInfo::PortMapping& left,
    const ContainerInfo::DockerInfo::PortMapping& right)
  return left.host_port() == right.host_port() &&
    left.container_port() == right.container_port() &&
    left.protocol() == right.protocol();
bool operator==(const Parameter& left, const Parameter& right)
  return left.key() == right.key() && left.value() == right.value();
bool operator==(
    const ContainerInfo::DockerInfo& left,
    const ContainerInfo::DockerInfo& right)
  if (left.port_mappings().size() != right.port_mappings().size()) {
    return false;
  for (int i = 0; i < left.port_mappings().size(); i++) {
    bool found = false;
    for (int j = 0; j < right.port_mappings().size(); j++) {
      if (left.port_mappings().Get(i) == right.port_mappings().Get(j)) {
        found = true;
        break;
    if (!found) {
      return false;
  if (left.parameters().size() != right.parameters().size()) {
    return false;
  for (int i = 0; i < left.parameters().size(); i++) {
    bool found = false;
    for (int j = 0; j < right.parameters().size(); j++) {
      if (left.parameters().Get(i) == right.parameters().Get(j)) {
        found = true;
        break;
    if (!found) {
      return false;
  return left.image() == right.image() &&
    left.network() == right.network() &&
    left.privileged() == right.privileged() &&
    left.force_pull_image() == right.force_pull_image();
bool operator==(const ContainerInfo& left, const ContainerInfo& right)
  if (left.volumes().size() != right.volumes().size()) {
    return false;
  for (int i = 0; i < left.volumes().size(); i++) {
    bool found = false;
    for (int j = 0; j < right.volumes().size(); j++) {
      if (left.volumes().Get(i) == right.volumes().Get(j)) {
        found = true;
        break;
    if (!found) {
      return false;
  return left.type() == right.type() &&
    left.hostname() == right.hostname() &&
    left.docker() == right.docker();
bool operator==(const Port& left, const Port& right)
  return left.number() == right.number() &&
    left.name() == right.name() &&
    left.protocol() == right.protocol();
bool operator==(const Ports& left, const Ports& right)
  if (left.ports().size() != right.ports().size()) {
    return false;
  for (int i = 0; i < left.ports().size(); i++) {
    bool found = false;
    for (int j = 0; j < right.ports().size(); j++) {
      if (left.ports().Get(i) == right.ports().Get(j)) {
        found = true;
        break;
    if (!found) {
      return false;
  return true;
bool operator==(const Label& left, const Label& right)
  return left.key() == right.key() && left.value() == right.value();
bool operator==(const Labels& left, const Labels& right)
  if (left.labels().size() != right.labels().size()) {
    return false;
  for (int i = 0; i < left.labels().size(); i++) {
    bool found = false;
    for (int j = 0; j < right.labels().size(); j++) {
      if (left.labels().Get(i) == right.labels().Get(j)) {
        found = true;
        break;
    if (!found) {
      return false;
  return true;
bool operator==(const DiscoveryInfo& left, const DiscoveryInfo& right)
  return left.visibility() == right.visibility() &&
    left.name() == right.name() &&
    left.environment() == right.environment() &&
    left.location() == right.location() &&
    left.version() == right.version() &&
    left.ports() == right.ports() &&
    left.labels() == right.labels();
bool operator==(const ExecutorInfo& left, const ExecutorInfo& right)
  return left.executor_id() == right.executor_id() &&
    left.data() == right.data() &&
    Resources(left.resources()) == Resources(right.resources()) &&
    left.command() == right.command() &&
    left.framework_id() == right.framework_id() &&
    left.name() == right.name() &&
    left.source() == right.source() &&
    left.container() == right.container() &&
    left.discovery() == right.discovery();
bool operator==(const MasterInfo& left, const MasterInfo& right)
  return left.id() == right.id() &&
    left.ip() == right.ip() &&
    left.port() == right.port() &&
    left.pid() == right.pid() &&
    left.hostname() == right.hostname() &&
    left.version() == right.version();
bool operator==(
    const ResourceStatistics& left,
    const ResourceStatistics& right)
  return left.SerializeAsString() == right.SerializeAsString();

src/v1/mesos.cpp(330)
src/common/type_utils.cpp(332)
  return left.hostname() == right.hostname() &&
    Resources(left.resources()) == Resources(right.resources()) &&
    Attributes(left.attributes()) == Attributes(right.attributes()) &&
    left.id() == right.id() &&

src/v1/mesos.cpp(334)
src/common/type_utils.cpp(337)
    left.port() == right.port();
bool operator==(const TaskStatus& left, const TaskStatus& right)
  return left.task_id() == right.task_id() &&
    left.state() == right.state() &&
    left.data() == right.data() &&
    left.message() == right.message() &&

src/v1/mesos.cpp(346)
src/common/type_utils.cpp(349)
    left.timestamp() == right.timestamp() &&
    left.executor_id() == right.executor_id() &&
    left.healthy() == right.healthy() &&
    left.source() == right.source() &&
    left.reason() == right.reason() &&
    left.uuid() == right.uuid();
bool operator!=(const TaskStatus& left, const TaskStatus& right)
  return !(left == right);

src/v1/mesos.cpp(161)
src/common/type_utils.cpp(181)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(240)
src/common/type_utils.cpp(272)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(179)
src/common/type_utils.cpp(208)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(206)
src/common/type_utils.cpp(242)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(161)
src/common/type_utils.cpp(208)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(104)
src/common/type_utils.cpp(163)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(39)
src/common/type_utils.cpp(106)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(206)
src/common/type_utils.cpp(272)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(179)
src/common/type_utils.cpp(242)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(104)
src/common/type_utils.cpp(181)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(161)
src/common/type_utils.cpp(242)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(179)
src/common/type_utils.cpp(272)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(104)
src/common/type_utils.cpp(208)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(161)
src/common/type_utils.cpp(272)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(39)
src/common/type_utils.cpp(163)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(39)
src/common/type_utils.cpp(181)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(104)
src/common/type_utils.cpp(242)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(39)
src/common/type_utils.cpp(208)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(104)
src/common/type_utils.cpp(272)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(39)
src/common/type_utils.cpp(242)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(39)
src/common/type_utils.cpp(272)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(270)
src/common/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(240)
src/common/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(206)
src/common/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(179)
src/common/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(270)
src/common/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(161)
src/common/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(270)
src/common/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(240)
src/common/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(240)
src/common/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(206)
src/common/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(104)
src/common/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(206)
src/common/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(179)
src/common/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(161)
src/common/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(179)
src/common/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(39)
src/common/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(161)
src/common/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(104)
src/common/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(104)
src/common/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/v1/mesos.cpp(39)
src/common/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/mesos.cpp(39)
src/common/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;

src/v1/resources.cpp(38)
src/v1/values.cpp(42)
using std::string;
using std::vector;
namespace mesos {
namespace v1 {

src/v1/resources.cpp(37)
src/common/http.cpp(37)
using std::set;
using std::string;
using std::vector;
namespace mesos {

src/v1/resources.cpp(18)
src/common/resources.cpp(18)
#include <stdint.h>
#include <set>
#include <string>
#include <vector>
#include <glog/logging.h>

src/v1/resources.cpp(30)
src/common/resources.cpp(30)
#include <stout/foreach.hpp>
#include <stout/hashmap.hpp>
#include <stout/lambda.hpp>
#include <stout/strings.hpp>
using std::map;
using std::ostream;
using std::set;
using std::string;
using std::vector;
namespace mesos {

src/v1/resources.cpp(49)
src/common/resources.cpp(48)
bool operator==(
    const Resource::ReservationInfo& left,
    const Resource::ReservationInfo& right)
  return left.principal() == right.principal();
bool operator!=(
    const Resource::ReservationInfo& left,
    const Resource::ReservationInfo& right)
  return !(left == right);
bool operator==(const Resource::DiskInfo& left, const Resource::DiskInfo& right)
  if (left.has_persistence() != right.has_persistence()) {
    return false;
  if (left.has_persistence()) {
    return left.persistence().id() == right.persistence().id();
  return true;
bool operator!=(const Resource::DiskInfo& left, const Resource::DiskInfo& right)
  return !(left == right);
bool operator==(const Resource& left, const Resource& right)
  if (left.name() != right.name() ||
      left.type() != right.type() ||
      left.role() != right.role()) {
    return false;
  if (left.has_reservation() != right.has_reservation()) {
    return false;
  if (left.has_reservation() && left.reservation() != right.reservation()) {
    return false;
  if (left.has_disk() != right.has_disk()) {
    return false;
  if (left.has_disk() && left.disk() != right.disk()) {
    return false;
  if (left.has_revocable() != right.has_revocable()) {
    return false;
  if (left.type() == Value::SCALAR) {
    return left.scalar() == right.scalar();
  } else if (left.type() == Value::RANGES) {
    return left.ranges() == right.ranges();
  } else if (left.type() == Value::SET) {
    return left.set() == right.set();
  } else {
    return false;
bool operator!=(const Resource& left, const Resource& right)
  return !(left == right);
namespace internal {
static bool addable(const Resource& left, const Resource& right)
  if (left.name() != right.name() ||
      left.type() != right.type() ||
      left.role() != right.role()) {
    return false;
  if (left.has_reservation() != right.has_reservation()) {
    return false;
  if (left.has_reservation() && left.reservation() != right.reservation()) {
    return false;
  if (left.has_disk() != right.has_disk()) {
    return false;
  if (left.has_disk() && left.disk() != right.disk()) {
    return false;
  if (left.has_disk() && left.disk().has_persistence()) {
    return false;
  if (left.has_revocable() != right.has_revocable()) {
    return false;
  return true;
static bool subtractable(const Resource& left, const Resource& right)
  if (left.name() != right.name() ||
      left.type() != right.type() ||
      left.role() != right.role()) {
    return false;
  if (left.has_reservation() != right.has_reservation()) {
    return false;
  if (left.has_reservation() && left.reservation() != right.reservation()) {
    return false;
  if (left.has_disk() != right.has_disk()) {
    return false;
  if (left.has_disk() && left.disk() != right.disk()) {
    return false;
  if (left.has_disk() && left.disk().has_persistence() && left != right) {
    return false;
  if (left.has_revocable() != right.has_revocable()) {
    return false;
  return true;
static bool contains(const Resource& left, const Resource& right)
  if (!subtractable(left, right)) {
    return false;
  if (left.type() == Value::SCALAR) {
    return right.scalar() <= left.scalar();
  } else if (left.type() == Value::RANGES) {
    return right.ranges() <= left.ranges();
  } else if (left.type() == Value::SET) {
    return right.set() <= left.set();
  } else {
    return false;
Resource& operator+=(Resource& left, const Resource& right)
  if (left.type() == Value::SCALAR) {
    *left.mutable_scalar() += right.scalar();
  } else if (left.type() == Value::RANGES) {
    *left.mutable_ranges() += right.ranges();
  } else if (left.type() == Value::SET) {
    *left.mutable_set() += right.set();
  return left;
Resource operator+(const Resource& left, const Resource& right)
  Resource result = left;
  result += right;
  return result;
Resource& operator-=(Resource& left, const Resource& right)
  if (left.type() == Value::SCALAR) {
    *left.mutable_scalar() -= right.scalar();
  } else if (left.type() == Value::RANGES) {
    *left.mutable_ranges() -= right.ranges();
  } else if (left.type() == Value::SET) {
    *left.mutable_set() -= right.set();
  return left;
Resource operator-(const Resource& left, const Resource& right)
  Resource result = left;
  result -= right;
  return result;
Try<Resource> Resources::parse(
    const string& name,
    const string& value,
    const string& role)
  Try<Value> result = internal::values::parse(value);
  if (result.isError()) {
    return Error(
        "Failed to parse resource " + name +
        " value " + value + " error " + result.error());
  Resource resource;
  Value _value = result.get();
  resource.set_name(name);
  resource.set_role(role);
  if (_value.type() == Value::SCALAR) {
    resource.set_type(Value::SCALAR);
    resource.mutable_scalar()->CopyFrom(_value.scalar());
  } else if (_value.type() == Value::RANGES) {
    resource.set_type(Value::RANGES);
    resource.mutable_ranges()->CopyFrom(_value.ranges());
  } else if (_value.type() == Value::SET) {
    resource.set_type(Value::SET);
    resource.mutable_set()->CopyFrom(_value.set());
  } else {
    return Error(
        "Bad type for resource " + name + " value " + value +
        " type " + Value::Type_Name(_value.type()));
  return resource;
Try<Resources> Resources::parse(
    const string& text,
    const string& defaultRole)
  Resources resources;
  hashmap<string, Value_Type> nameTypes;
  foreach (const string& token, strings::tokenize(text, ";")) {
    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());
    if (nameTypes.contains(name) && nameTypes[name] != resource.get().type()) {
      return Error(
          "Resources with the same name ('" + name + "') but different types "
          "are not allowed");
    } else if (!nameTypes.contains(name)) {
      nameTypes[name] = resource.get().type();
    resources += resource.get();
  return resources;
Option<Error> Resources::validate(const Resource& resource)
  if (resource.name().empty()) {
    return Error("Empty resource name");
  if (!Value::Type_IsValid(resource.type())) {
    return Error("Invalid resource type");
  if (resource.type() == Value::SCALAR) {
    if (!resource.has_scalar() ||
        resource.has_ranges() ||
        resource.has_set()) {
      return Error("Invalid scalar resource");
    if (resource.scalar().value() < 0) {
      return Error("Invalid scalar resource: value < 0");
  } else if (resource.type() == Value::RANGES) {
    if (resource.has_scalar() ||
        !resource.has_ranges() ||
        resource.has_set()) {
      return Error("Invalid ranges resource");
    for (int i = 0; i < resource.ranges().range_size(); i++) {
      const Value::Range& range = resource.ranges().range(i);
      if (range.begin() > range.end()) {
        return Error("Invalid ranges resource: begin > end");
      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 Error("Invalid ranges resource: overlapping ranges");
  } else if (resource.type() == Value::SET) {
    if (resource.has_scalar() ||
        resource.has_ranges() ||
        !resource.has_set()) {
      return Error("Invalid set resource");
    for (int i = 0; i < resource.set().item_size(); i++) {
      const string& item = resource.set().item(i);
      for (int j = i + 1; j < resource.set().item_size(); j++) {
        if (item == resource.set().item(j)) {
          return Error("Invalid set resource: duplicated elements");
  } else {
    return Error("Unsupported resource type");
  if (resource.has_disk() && resource.name() != "disk") {
    return Error(
        "DiskInfo should not be set for " + resource.name() + " resource");
  if (resource.role() == "*" && resource.has_reservation()) {
    return Error(
        "Invalid reservation: role \"*\" cannot be dynamically reserved");
  return None();
Option<Error> Resources::validate(
    const google::protobuf::RepeatedPtrField<Resource>& resources)
  foreach (const Resource& resource, resources) {
    Option<Error> error = validate(resource);
    if (error.isSome()) {
      return Error(
          "Resource '" + stringify(resource) +
          "' is invalid: " + error.get().message);
  return None();
bool Resources::isEmpty(const Resource& 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;
  } else {
    return false;
bool Resources::isPersistentVolume(const Resource& resource)
  return resource.has_disk() && resource.disk().has_persistence();
bool Resources::isReserved(
    const Resource& resource,
    const Option<std::string>& role)
  if (role.isSome()) {
    return !isUnreserved(resource) && role.get() == resource.role();
  } else {
    return !isUnreserved(resource);
bool Resources::isUnreserved(const Resource& resource)
  return resource.role() == "*" && !resource.has_reservation();
bool Resources::isDynamicallyReserved(const Resource& resource)
  return resource.has_reservation();
bool Resources::isRevocable(const Resource& resource)
  return resource.has_revocable();
Resources::Resources(const Resource& resource)
  *this += resource;
Resources::Resources(const vector<Resource>& _resources)
  foreach (const Resource& resource, _resources) {
    *this += resource;
Resources::Resources(
    const google::protobuf::RepeatedPtrField<Resource>& _resources)
  foreach (const Resource& resource, _resources) {
    *this += resource;
bool Resources::contains(const Resources& that) const
  Resources remaining = *this;
  foreach (const Resource& resource, that.resources) {
    if (!remaining._contains(resource)) {
      return false;
    remaining -= resource;
  return true;
bool Resources::contains(const Resource& that) const
  return validate(that).isNone() && _contains(that);
Resources Resources::filter(
    const lambda::function<bool(const Resource&)>& predicate) const
  Resources result;
  foreach (const Resource& resource, resources) {
    if (predicate(resource)) {
      result += resource;
  return result;
hashmap<string, Resources> Resources::reserved() const
  hashmap<string, Resources> result;
  foreach (const Resource& resource, resources) {
    if (isReserved(resource)) {
      result[resource.role()] += resource;
  return result;
Resources Resources::reserved(const string& role) const
  return filter(lambda::bind(isReserved, lambda::_1, role));
Resources Resources::unreserved() const
  return filter(isUnreserved);
Resources Resources::persistentVolumes() const
  return filter(isPersistentVolume);
Resources Resources::revocable() const
  return filter(isRevocable);
Resources Resources::flatten(
    const string& role,
    const Option<Resource::ReservationInfo>& reservation) const
  Resources flattened;
  foreach (Resource resource, resources) {
    resource.set_role(role);
    if (reservation.isNone()) {
      resource.clear_reservation();
    } else {
      resource.mutable_reservation()->CopyFrom(reservation.get());
    flattened += resource;
  return flattened;
static bool any(const Resource&) { return true; }
Option<Resources> Resources::find(const Resource& target) const
  Resources found;
  Resources total = *this;
  Resources remaining = Resources(target).flatten();
  vector<lambda::function<bool(const Resource&)>> predicates = {
    lambda::bind(isReserved, lambda::_1, target.role()),
    isUnreserved,
    any
  foreach (const auto& predicate, predicates) {
    foreach (const Resource& resource, total.filter(predicate)) {
      Resources flattened = Resources(resource).flatten();
      if (flattened.contains(remaining)) {
        if (!resource.has_reservation()) {
          return found + remaining.flatten(resource.role());
        } else {
          return found +
                 remaining.flatten(resource.role(), resource.reservation());
      } else if (remaining.contains(flattened)) {
        found += resource;
        total -= resource;
        remaining -= flattened;
        break;
  return None();
Option<Resources> Resources::find(const Resources& targets) const
  Resources total;
  foreach (const Resource& target, targets) {
    Option<Resources> found = find(target);
    if (found.isNone()) {
      return None();
    total += found.get();
  return total;
Try<Resources> Resources::apply(const Offer::Operation& operation) const
  Resources result = *this;
  switch (operation.type()) {
    case Offer::Operation::LAUNCH:
      break;
    case Offer::Operation::RESERVE: {
      Option<Error> error = validate(operation.reserve().resources());
      if (error.isSome()) {
        return Error("Invalid RESERVE Operation: " + error.get().message);
      foreach (const Resource& reserved, operation.reserve().resources()) {
        if (!Resources::isReserved(reserved)) {
          return Error("Invalid RESERVE Operation: Resource must be reserved");
        } else if (!reserved.has_reservation()) {
          return Error("Invalid RESERVE Operation: Missing 'reservation'");
        Resources unreserved = Resources(reserved).flatten();
        if (!result.contains(unreserved)) {
          return Error("Invalid RESERVE Operation: " + stringify(result) +
                       " does not contain " + stringify(unreserved));
        result -= unreserved;
        result += reserved;
      break;
    case Offer::Operation::UNRESERVE: {
      Option<Error> error = validate(operation.unreserve().resources());
      if (error.isSome()) {
        return Error("Invalid UNRESERVE Operation: " + error.get().message);
      foreach (const Resource& reserved, operation.unreserve().resources()) {
        if (!Resources::isReserved(reserved)) {
          return Error("Invalid UNRESERVE Operation: Resource is not reserved");
        } else if (!reserved.has_reservation()) {
          return Error("Invalid UNRESERVE Operation: Missing 'reservation'");
        if (!result.contains(reserved)) {
          return Error("Invalid UNRESERVE Operation: " + stringify(result) +
                       " does not contain " + stringify(reserved));
        Resources unreserved = Resources(reserved).flatten();
        result -= reserved;
        result += unreserved;
      break;
    case Offer::Operation::CREATE: {
      Option<Error> error = validate(operation.create().volumes());
      if (error.isSome()) {
        return Error("Invalid CREATE Operation: " + error.get().message);
      foreach (const Resource& volume, operation.create().volumes()) {
        if (!volume.has_disk()) {
          return Error("Invalid CREATE Operation: Missing 'disk'");
        } else if (!volume.disk().has_persistence()) {
          return Error("Invalid CREATE Operation: Missing 'persistence'");
        Resource stripped = volume;
        stripped.clear_disk();
        if (!result.contains(stripped)) {
          return Error("Invalid CREATE Operation: Insufficient disk resources");
        result -= stripped;
        result += volume;
      break;
    case Offer::Operation::DESTROY: {
      Option<Error> error = validate(operation.destroy().volumes());
      if (error.isSome()) {
        return Error("Invalid DESTROY Operation: " + error.get().message);
      foreach (const Resource& volume, operation.destroy().volumes()) {
        if (!volume.has_disk()) {
          return Error("Invalid DESTROY Operation: Missing 'disk'");
        } else if (!volume.disk().has_persistence()) {
          return Error("Invalid DESTROY Operation: Missing 'persistence'");
        if (!result.contains(volume)) {
          return Error(
              "Invalid DESTROY Operation: Persistent volume does not exist");
        Resource stripped = volume;
        stripped.clear_disk();
        result -= volume;
        result += stripped;
      break;
    default:
      return Error("Unknown offer operation " + stringify(operation.type()));
  CHECK(result.cpus() == cpus() &&
        result.mem() == mem() &&
        result.disk() == disk() &&
        result.ports() == ports());
  return result;
template <>
Option<Value::Scalar> Resources::get(const string& name) 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 None();
template <>
Option<Value::Set> Resources::get(const string& name) 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 None();
template <>
Option<Value::Ranges> Resources::get(const string& name) 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 None();
Resources Resources::get(const string& name) const
  return filter([=](const Resource& resource) {
    return resource.name() == name;
  });
Resources Resources::scalars() const
  return filter([=](const Resource& resource) {
    return resource.type() == Value::SCALAR;
  });
set<string> Resources::names() const
  set<string> result;
  foreach (const Resource& resource, resources) {
    result.insert(resource.name());
  return result;
map<string, Value_Type> Resources::types() const
  map<string, Value_Type> result;
  foreach (const Resource& resource, resources) {
    result[resource.name()] = resource.type();
  return result;
Option<double> Resources::cpus() const
  Option<Value::Scalar> value = get<Value::Scalar>("cpus");
  if (value.isSome()) {
    return value.get().value();
  } else {
    return None();
Option<Bytes> Resources::mem() const
  Option<Value::Scalar> value = get<Value::Scalar>("mem");
  if (value.isSome()) {
    return Megabytes(static_cast<uint64_t>(value.get().value()));
  } else {
    return None();
Option<Bytes> Resources::disk() const
  Option<Value::Scalar> value = get<Value::Scalar>("disk");
  if (value.isSome()) {
    return Megabytes(static_cast<uint64_t>(value.get().value()));
  } else {
    return None();
Option<Value::Ranges> Resources::ports() const
  Option<Value::Ranges> value = get<Value::Ranges>("ports");
  if (value.isSome()) {
    return value.get();
  } else {
    return None();
Option<Value::Ranges> Resources::ephemeral_ports() const
  Option<Value::Ranges> value = get<Value::Ranges>("ephemeral_ports");
  if (value.isSome()) {
    return value.get();
  } else {
    return None();
bool Resources::_contains(const Resource& that) const
  foreach (const Resource& resource, resources) {
    if (internal::contains(resource, that)) {
      return true;
  return false;
Resources::operator const google::protobuf::RepeatedPtrField<Resource>&() const
  return resources;
bool Resources::operator==(const Resources& that) const
  return this->contains(that) && that.contains(*this);
bool Resources::operator!=(const Resources& that) const
  return !(*this == that);
Resources Resources::operator+(const Resource& that) const
  Resources result = *this;
  result += that;
  return result;
Resources Resources::operator+(const Resources& that) const
  Resources result = *this;
  result += that;
  return result;
Resources& Resources::operator+=(const Resource& that)
  if (validate(that).isNone() && !isEmpty(that)) {
    bool found = false;
    foreach (Resource& resource, resources) {
      if (internal::addable(resource, that)) {
        resource += that;
        found = true;
        break;
    if (!found) {
      resources.Add()->CopyFrom(that);
  return *this;
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 = *this;
  result -= that;
  return result;
Resources Resources::operator-(const Resources& that) const
  Resources result = *this;
  result -= that;
  return result;
Resources& Resources::operator-=(const Resource& that)
  if (validate(that).isNone() && !isEmpty(that)) {
    for (int i = 0; i < resources.size(); i++) {
      Resource* resource = resources.Mutable(i);
      if (internal::subtractable(*resource, that)) {
        *resource -= that;
        if (validate(*resource).isSome() || isEmpty(*resource)) {
          resources.DeleteSubrange(i, 1);
        break;
  return *this;
Resources& Resources::operator-=(const Resources& that)
  foreach (const Resource& resource, that.resources) {
    *this -= resource;
  return *this;
ostream& operator<<(ostream& stream, const Volume& volume)
  string volumeConfig = volume.container_path();
  if (volume.has_host_path()) {
    volumeConfig = volume.host_path() + ":" + volumeConfig;
    if (volume.has_mode()) {
      switch (volume.mode()) {
        case Volume::RW: volumeConfig += ":rw"; break;
        case Volume::RO: volumeConfig += ":ro"; break;
        default:
          LOG(FATAL) << "Unknown Volume mode: " << volume.mode();
          break;
  stream << volumeConfig;
  return stream;
ostream& operator<<(ostream& stream, const Resource::DiskInfo& disk)
  if (disk.has_persistence()) {
    stream << disk.persistence().id();
  if (disk.has_volume()) {
    stream << ":" << disk.volume();
  return stream;
ostream& operator<<(ostream& stream, const Resource& resource)
  stream << resource.name();
  stream << "(" << resource.role();
  if (resource.has_reservation()) {
    stream << ", " << resource.reservation().principal();
  stream << ")";
  if (resource.has_disk()) {
    stream << "[" << resource.disk() << "]";
  if (resource.has_revocable()) {
    stream << "{REV}";
  stream << ":";
  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 stream;
ostream& operator<<(ostream& stream, const Resources& resources)
  Resources::const_iterator it = resources.begin();
  while (it != resources.end()) {
    stream << *it;
    if (++it != resources.end()) {
      stream << "; ";
  return stream;

src/v1/resources.cpp(1007)
src/common/resources.cpp(995)
  if (value.isSome()) {
    return Megabytes(static_cast<uint64_t>(value.get().value()));
  } else {
    return None();

src/v1/resources.cpp(1029)
src/common/resources.cpp(1017)
  if (value.isSome()) {
    return value.get();
  } else {
    return None();

src/v1/resources.cpp(910)
src/common/resources.cpp(887)
      found = true;
  if (found) {
    return total;
  return None();
template <>

src/v1/resources.cpp(932)
src/common/resources.cpp(909)
      found = true;
  if (found) {
    return total;
  return None();

src/v1/resources.cpp(197)
src/common/resources.cpp(145)
  if (left.name() != right.name() ||
      left.type() != right.type() ||
      left.role() != right.role()) {
    return false;
  if (left.has_reservation() != right.has_reservation()) {
    return false;
  if (left.has_reservation() && left.reservation() != right.reservation()) {
    return false;
  if (left.has_disk() != right.has_disk()) {
    return false;
  if (left.has_disk() && left.disk() != right.disk()) {
    return false;

src/v1/resources.cpp(224)
src/common/resources.cpp(174)
    return false;
  if (left.has_revocable() != right.has_revocable()) {
    return false;
  return true;

src/v1/resources.cpp(932)
src/common/resources.cpp(887)
      found = true;
  if (found) {
    return total;
  return None();

src/v1/resources.cpp(146)
src/common/resources.cpp(91)
  if (left.name() != right.name() ||
      left.type() != right.type() ||
      left.role() != right.role()) {
    return false;
  if (left.has_reservation() != right.has_reservation()) {
    return false;
  if (left.has_reservation() && left.reservation() != right.reservation()) {
    return false;
  if (left.has_disk() != right.has_disk()) {
    return false;
  if (left.has_disk() && left.disk() != right.disk()) {
    return false;

src/v1/resources.cpp(197)
src/common/resources.cpp(91)
  if (left.name() != right.name() ||
      left.type() != right.type() ||
      left.role() != right.role()) {
    return false;
  if (left.has_reservation() != right.has_reservation()) {
    return false;
  if (left.has_reservation() && left.reservation() != right.reservation()) {
    return false;
  if (left.has_disk() != right.has_disk()) {
    return false;
  if (left.has_disk() && left.disk() != right.disk()) {
    return false;

src/v1/resources.cpp(996)
src/common/resources.cpp(1006)
  if (value.isSome()) {
    return Megabytes(static_cast<uint64_t>(value.get().value()));
  } else {
    return None();

src/v1/resources.cpp(1018)
src/common/resources.cpp(1028)
  if (value.isSome()) {
    return value.get();
  } else {
    return None();

src/v1/resources.cpp(888)
src/common/resources.cpp(909)
      found = true;
  if (found) {
    return total;
  return None();
template <>

src/v1/resources.cpp(910)
src/common/resources.cpp(931)
      found = true;
  if (found) {
    return total;
  return None();

src/v1/resources.cpp(146)
src/common/resources.cpp(196)
  if (left.name() != right.name() ||
      left.type() != right.type() ||
      left.role() != right.role()) {
    return false;
  if (left.has_reservation() != right.has_reservation()) {
    return false;
  if (left.has_reservation() && left.reservation() != right.reservation()) {
    return false;
  if (left.has_disk() != right.has_disk()) {
    return false;
  if (left.has_disk() && left.disk() != right.disk()) {
    return false;

src/v1/resources.cpp(175)
src/common/resources.cpp(223)
    return false;
  if (left.has_revocable() != right.has_revocable()) {
    return false;
  return true;

src/v1/resources.cpp(888)
src/common/resources.cpp(931)
      found = true;
  if (found) {
    return total;
  return None();

src/v1/resources.cpp(92)
src/common/resources.cpp(145)
  if (left.name() != right.name() ||
      left.type() != right.type() ||
      left.role() != right.role()) {
    return false;
  if (left.has_reservation() != right.has_reservation()) {
    return false;
  if (left.has_reservation() && left.reservation() != right.reservation()) {
    return false;
  if (left.has_disk() != right.has_disk()) {
    return false;
  if (left.has_disk() && left.disk() != right.disk()) {
    return false;

src/v1/resources.cpp(92)
src/common/resources.cpp(196)
  if (left.name() != right.name() ||
      left.type() != right.type() ||
      left.role() != right.role()) {
    return false;
  if (left.has_reservation() != right.has_reservation()) {
    return false;
  if (left.has_reservation() && left.reservation() != right.reservation()) {
    return false;
  if (left.has_disk() != right.has_disk()) {
    return false;
  if (left.has_disk() && left.disk() != right.disk()) {
    return false;

src/v1/values.cpp(41)
src/common/attributes.cpp(29)
using std::ostream;
using std::string;
using std::vector;
namespace mesos {

src/v1/values.cpp(310)
src/common/type_utils.cpp(272)
          found = true;
          break;
      if (!found) {
        return false;
    return true;

src/v1/values.cpp(310)
src/common/type_utils.cpp(242)
          found = true;
          break;
      if (!found) {
        return false;
    return true;

src/v1/values.cpp(310)
src/common/type_utils.cpp(208)
          found = true;
          break;
      if (!found) {
        return false;

src/v1/values.cpp(310)
src/common/type_utils.cpp(181)
          found = true;
          break;
      if (!found) {
        return false;

src/v1/values.cpp(409)
src/common/type_utils.cpp(272)
          found = true;
          break;
      if (!found) {
        return false;
    return true;

src/v1/values.cpp(310)
src/common/type_utils.cpp(163)
          found = true;
          break;
      if (!found) {
        return false;

src/v1/values.cpp(434)
src/common/type_utils.cpp(272)
          found = true;
          break;
      if (!found) {
        return false;
    return true;

src/v1/values.cpp(409)
src/common/type_utils.cpp(242)
          found = true;
          break;
      if (!found) {
        return false;
    return true;

src/v1/values.cpp(434)
src/common/type_utils.cpp(242)
          found = true;
          break;
      if (!found) {
        return false;
    return true;

src/v1/values.cpp(409)
src/common/type_utils.cpp(208)
          found = true;
          break;
      if (!found) {
        return false;

src/v1/values.cpp(310)
src/common/type_utils.cpp(106)
          found = true;
          break;
      if (!found) {
        return false;
    return true;

src/v1/values.cpp(434)
src/common/type_utils.cpp(208)
          found = true;
          break;
      if (!found) {
        return false;

src/v1/values.cpp(409)
src/common/type_utils.cpp(181)
          found = true;
          break;
      if (!found) {
        return false;

src/v1/values.cpp(409)
src/common/type_utils.cpp(163)
          found = true;
          break;
      if (!found) {
        return false;

src/v1/values.cpp(434)
src/common/type_utils.cpp(181)
          found = true;
          break;
      if (!found) {
        return false;

src/v1/values.cpp(310)
src/common/type_utils.cpp(41)
          found = true;
          break;
      if (!found) {
        return false;

src/v1/values.cpp(434)
src/common/type_utils.cpp(163)
          found = true;
          break;
      if (!found) {
        return false;

src/v1/values.cpp(409)
src/common/type_utils.cpp(106)
          found = true;
          break;
      if (!found) {
        return false;
    return true;

src/v1/values.cpp(434)
src/common/type_utils.cpp(106)
          found = true;
          break;
      if (!found) {
        return false;
    return true;

src/v1/values.cpp(409)
src/common/type_utils.cpp(41)
          found = true;
          break;
      if (!found) {
        return false;

src/v1/values.cpp(434)
src/common/type_utils.cpp(41)
          found = true;
          break;
      if (!found) {
        return false;

src/v1/values.cpp(18)
src/common/values.cpp(18)
#include <stdint.h>
#include <algorithm>
#include <initializer_list>
#include <ostream>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include <glog/logging.h>
#include <boost/lexical_cast.hpp>

src/v1/values.cpp(35)
src/common/values.cpp(35)
#include <stout/error.hpp>
#include <stout/foreach.hpp>
#include <stout/strings.hpp>
using std::max;
using std::min;
using std::ostream;
using std::string;
using std::vector;
namespace mesos {

src/v1/values.cpp(48)
src/common/values.cpp(47)
ostream& operator<<(ostream& stream, const Value::Scalar& scalar)
  return stream << scalar.value();
bool operator==(const Value::Scalar& left, const Value::Scalar& right)
  return left.value() == right.value();
bool operator<=(const Value::Scalar& left, const Value::Scalar& right)
  return left.value() <= right.value();
Value::Scalar operator+(const Value::Scalar& left, const Value::Scalar& right)
  Value::Scalar result;
  result.set_value(left.value() + right.value());
  return result;
Value::Scalar operator-(const Value::Scalar& left, const Value::Scalar& right)
  Value::Scalar result;
  result.set_value(left.value() - right.value());
  return result;
Value::Scalar& operator+=(Value::Scalar& left, const Value::Scalar& right)
  left.set_value(left.value() + right.value());
  return left;
Value::Scalar& operator-=(Value::Scalar& left, const Value::Scalar& right)
  left.set_value(left.value() - right.value());
  return left;
namespace internal {
struct Range
  uint64_t start;
  uint64_t end;
void coalesce(Value::Ranges* result, vector<Range> ranges)
  if (ranges.empty()) {
    result->clear_range();
    return;
  std::sort(
      ranges.begin(),
      ranges.end(),
      [](const Range& left, const Range& right) {
        return std::tie(left.start, left.end) <
               std::tie(right.start, right.end);
      });
  CHECK(!ranges.empty());
  int count = 1;
  Range current = ranges.front();
  foreach (const Range& range, ranges) {
    if (range.start == current.start && range.end == current.end) {
      continue;
    if (range.start == current.start && range.end > current.end) {
      current.end = range.end;
    } else if (range.start > current.start) {
      if (range.start <= current.end + 1) {
        current.end = max(current.end, range.end);
      } else {
        ranges[count - 1] = current;
        ++count;
        current = range;
  ranges[count - 1] = current;
  CHECK(count <= static_cast<int>(ranges.size()));
  if (count < result->range_size()) {
    result->mutable_range()->DeleteSubrange(
        count, result->range_size() - count);
  result->mutable_range()->Reserve(count);
  for (int i = 0; i < count; ++i) {
    if (i >= result->range_size()) {
      result->add_range();
    CHECK(i < result->range_size());
    result->mutable_range(i)->set_begin(ranges[i].start);
    result->mutable_range(i)->set_end(ranges[i].end);
  CHECK_EQ(result->range_size(), count);
void coalesce(
    Value::Ranges* result,
    std::initializer_list<Value::Ranges> addedRanges)
  size_t rangesSum = result->range_size();
  foreach (const Value::Ranges& range, addedRanges) {
    rangesSum += range.range_size();
  vector<internal::Range> ranges;
  ranges.reserve(rangesSum);
  auto fill = [&ranges](const Value::Ranges& inputs) {
    foreach (const Value::Range& range, inputs.range()) {
      ranges.push_back({range.begin(), range.end()});
  fill(*result);
  foreach (const Value::Ranges& range, addedRanges) {
    fill(range);
  internal::coalesce(result, std::move(ranges));
void coalesce(Value::Ranges* result)
  coalesce(result, {Value::Ranges()});
void coalesce(Value::Ranges* result, const Value::Range& addedRange)
  Value::Ranges ranges;
  Value::Range* range = ranges.add_range();
  range->CopyFrom(addedRange);
  coalesce(result, {ranges});
static void remove(Value::Ranges* _ranges, const Value::Range& removal)
  vector<internal::Range> ranges;
  ranges.reserve(_ranges->range_size());
  foreach (const Value::Range& range, _ranges->range()) {
    if (range.begin() >= removal.begin() && range.end() <= removal.end()) {
      continue;
    if (range.begin() < removal.begin() && range.end() > removal.end()) {
      ranges.emplace_back(internal::Range{range.begin(), removal.begin() - 1});
      ranges.emplace_back(internal::Range{removal.end() + 1, range.end()});
    if (range.end() < removal.begin() || range.begin() > removal.end()) {
      ranges.emplace_back(internal::Range{range.begin(), range.end()});
    } else {
      if (range.end() > removal.end()) {
        ranges.emplace_back(internal::Range{removal.end() + 1, range.end()});
      } else {
        CHECK(range.begin() < removal.begin());
        ranges.emplace_back(
            internal::Range{range.begin(), removal.begin() - 1});
  internal::coalesce(_ranges, std::move(ranges));
ostream& operator<<(ostream& stream, const Value::Ranges& ranges)
  stream << "[";
  for (int i = 0; i < ranges.range_size(); i++) {
    stream << ranges.range(i).begin() << "-" << ranges.range(i).end();
    if (i + 1 < ranges.range_size()) {
      stream << ", ";
  stream << "]";
  return stream;
bool operator==(const Value::Ranges& _left, const Value::Ranges& _right)
  Value::Ranges left;
  coalesce(&left, {_left});
  Value::Ranges right;
  coalesce(&right, {_right});
  if (left.range_size() == right.range_size()) {
    for (int i = 0; i < left.range_size(); i++) {
      bool found = false;
      for (int j = 0; j < right.range_size(); j++) {
        if (left.range(i).begin() == right.range(j).begin() &&
            left.range(i).end() == right.range(j).end()) {
          found = true;
          break;
      if (!found) {
        return false;
    return true;
  return false;
bool operator<=(const Value::Ranges& _left, const Value::Ranges& _right)
  Value::Ranges left;
  coalesce(&left, {_left});
  Value::Ranges right;
  coalesce(&right, {_right});
  for (int i = 0; i < left.range_size(); i++) {
    bool matched = false;
    for (int j = 0; j < right.range_size(); j++) {
      if (left.range(i).begin() >= right.range(j).begin() &&
          left.range(i).end() <= right.range(j).end()) {
        matched = true;
        break;
    if (!matched) {
      return false;
  return true;
Value::Ranges operator+(const Value::Ranges& left, const Value::Ranges& right)
  Value::Ranges result;
  coalesce(&result, {left, right});
  return result;
Value::Ranges operator-(const Value::Ranges& left, const Value::Ranges& right)
  Value::Ranges result;
  coalesce(&result, {left});
  return result -= right;
Value::Ranges& operator+=(Value::Ranges& left, const Value::Ranges& right)
  coalesce(&left, {right});
  return left;
Value::Ranges& operator-=(Value::Ranges& left, const Value::Ranges& right)
  coalesce(&left);
  for (int i = 0; i < right.range_size(); ++i) {
    remove(&left, right.range(i));
  return left;
ostream& operator<<(ostream& stream, const Value::Set& set)
  stream << "{";
  for (int i = 0; i < set.item_size(); i++) {
    stream << set.item(i);
    if (i + 1 < set.item_size()) {
      stream << ", ";
  stream << "}";
  return stream;
bool operator==(const Value::Set& left, const Value::Set& right)
  if (left.item_size() == right.item_size()) {
    for (int i = 0; i < left.item_size(); i++) {
      bool found = false;
      for (int j = 0; j < right.item_size(); j++) {
        if (left.item(i) == right.item(i)) {
          found = true;
          break;
      if (!found) {
        return false;
    return true;
  return false;
bool operator<=(const Value::Set& left, const Value::Set& right)
  if (left.item_size() <= right.item_size()) {
    for (int i = 0; i < left.item_size(); i++) {
      bool found = false;
      for (int j = 0; j < right.item_size(); j++) {
        if (left.item(i) == right.item(j)) {
          found = true;
          break;
      if (!found) {
        return false;
    return true;
  return false;
Value::Set operator+(const Value::Set& left, const Value::Set& right)
  Value::Set result;
  for (int i = 0; i < left.item_size(); i++) {
    result.add_item(left.item(i));
  for (int i = 0; i < right.item_size(); i++) {
    bool found = false;
    for (int j = 0; j < result.item_size(); j++) {
      if (right.item(i) == result.item(j)) {
        found = true;
        break;
    if (!found) {
      result.add_item(right.item(i));
  return result;
Value::Set operator-(const Value::Set& left, const Value::Set& right)
  Value::Set result;
  for (int i = 0; i < left.item_size(); i++) {
    bool found = false;
    for (int j = 0; j < right.item_size(); j++) {
      if (left.item(i) == right.item(j)) {
        found = true;
        break;
    if (!found) {
      result.add_item(left.item(i));
  return result;
Value::Set& operator+=(Value::Set& left, const Value::Set& right)
  for (int i = 0; i < right.item_size(); i++) {
    bool found = false;
    for (int j = 0; j < left.item_size(); j++) {
      if (right.item(i) == left.item(j)) {
        found = true;
        break;
    if (!found) {
      left.add_item(right.item(i));
  return left;
Value::Set& operator-=(Value::Set& left, const Value::Set& right)
  for (int i = 0; i < right.item_size(); i++) {
    for (int j = 0; j < left.item_size(); j++) {
      if (right.item(i) == left.item(j)) {
        left.mutable_item()->DeleteSubrange(j, 1);
        break;
  return left;
ostream& operator<<(ostream& stream, const Value::Text& value)
  return stream << value.value();
bool operator==(const Value::Text& left, const Value::Text& right)
  return left.value() == right.value();
namespace internal {
namespace values {
Try<Value> parse(const string& text)
  Value value;
  string temp;
  foreach (const char c, text) {
    if (c != ' ') {
      temp += c;
  if (temp.length() == 0) {
    return Error("Expecting non-empty string");
  if (!strings::checkBracketsMatching(temp, '{', '}') ||
      !strings::checkBracketsMatching(temp, '[', ']') ||
      !strings::checkBracketsMatching(temp, '(', ')')) {
    return Error("Mismatched brackets");
  size_t index = temp.find('[');
  if (index == 0) {
    value.set_type(Value::RANGES);
    Value::Ranges* ranges = value.mutable_ranges();
    const vector<string>& tokens = strings::tokenize(temp, "[]-,\n");
    if (tokens.size() % 2 != 0) {
      return Error("Expecting one or more \"ranges\"");
    } else {
      for (size_t i = 0; i < tokens.size(); i += 2) {
        Value::Range* range = ranges->add_range();
        int j = i;
        try {
          range->set_begin(boost::lexical_cast<uint64_t>((tokens[j++])));
          range->set_end(boost::lexical_cast<uint64_t>(tokens[j++]));
        } catch (const boost::bad_lexical_cast&) {
          return Error(
              "Expecting non-negative integers in '" + tokens[j - 1] + "'");
      coalesce(ranges);
      return value;
  } else if (index == string::npos) {
    size_t index = temp.find('{');
    if (index == 0) {
      value.set_type(Value::SET);
      Value::Set* set = value.mutable_set();
      const vector<string>& tokens = strings::tokenize(temp, "{},\n");
      for (size_t i = 0; i < tokens.size(); i++) {
        set->add_item(tokens[i]);
      return value;
    } else if (index == string::npos) {
      try {
        value.set_type(Value::SCALAR);
        Value::Scalar* scalar = value.mutable_scalar();
        scalar->set_value(boost::lexical_cast<double>(temp));
        return value;
      } catch (const boost::bad_lexical_cast&) {
        value.set_type(Value::TEXT);
        Value::Text* text = value.mutable_text();
        text->set_value(temp);
        return value;
    } else {
      return Error("Unexpected '{' found");
  return Error("Unexpected '[' found");

src/v1/values.cpp(434)
src/common/values.cpp(409)
          found = true;
          break;
      if (!found) {
        return false;
    return true;
  return false;

src/v1/values.cpp(329)
src/common/values.cpp(297)
  Value::Ranges left;
  coalesce(&left, {_left});
  Value::Ranges right;
  coalesce(&right, {_right});

src/v1/values.cpp(483)
src/common/values.cpp(429)
  for (int i = 0; i < left.item_size(); i++) {
    bool found = false;
    for (int j = 0; j < right.item_size(); j++) {
      if (left.item(i) == right.item(j)) {
        found = true;
        break;
    if (!found) {

src/v1/values.cpp(409)
src/common/values.cpp(310)
          found = true;
          break;
      if (!found) {
        return false;
    return true;
  return false;

src/v1/values.cpp(434)
src/common/values.cpp(310)
          found = true;
          break;
      if (!found) {
        return false;
    return true;
  return false;

src/v1/values.cpp(409)
src/common/values.cpp(434)
          found = true;
          break;
      if (!found) {
        return false;
    return true;
  return false;

src/v1/values.cpp(297)
src/common/values.cpp(329)
  Value::Ranges left;
  coalesce(&left, {_left});
  Value::Ranges right;
  coalesce(&right, {_right});

src/v1/values.cpp(429)
src/common/values.cpp(483)
    for (int i = 0; i < left.item_size(); i++) {
      bool found = false;
      for (int j = 0; j < right.item_size(); j++) {
        if (left.item(i) == right.item(j)) {
          found = true;
          break;
      if (!found) {

src/v1/values.cpp(310)
src/common/values.cpp(409)
          found = true;
          break;
      if (!found) {
        return false;
    return true;
  return false;

src/v1/values.cpp(310)
src/common/values.cpp(434)
          found = true;
          break;
      if (!found) {
        return false;
    return true;
  return false;

src/common/attributes.cpp(29)
src/common/values.cpp(41)
using std::ostream;
using std::string;
using std::vector;
namespace mesos {

src/common/http.cpp(37)
src/common/resources.cpp(37)
using std::set;
using std::string;
using std::vector;
namespace mesos {

src/common/type_utils.cpp(272)
src/common/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/common/type_utils.cpp(242)
src/common/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/common/type_utils.cpp(208)
src/common/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;

src/common/type_utils.cpp(181)
src/common/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;

src/common/type_utils.cpp(272)
src/common/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/common/type_utils.cpp(163)
src/common/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;

src/common/type_utils.cpp(272)
src/common/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/common/type_utils.cpp(242)
src/common/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/common/type_utils.cpp(242)
src/common/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/common/type_utils.cpp(208)
src/common/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;

src/common/type_utils.cpp(106)
src/common/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/common/type_utils.cpp(208)
src/common/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;

src/common/type_utils.cpp(181)
src/common/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;

src/common/type_utils.cpp(163)
src/common/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;

src/common/type_utils.cpp(181)
src/common/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;

src/common/type_utils.cpp(41)
src/common/values.cpp(310)
        found = true;
        break;
    if (!found) {
      return false;

src/common/type_utils.cpp(163)
src/common/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;

src/common/type_utils.cpp(106)
src/common/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/common/type_utils.cpp(106)
src/common/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;
  return true;

src/common/type_utils.cpp(41)
src/common/values.cpp(409)
        found = true;
        break;
    if (!found) {
      return false;

src/common/type_utils.cpp(41)
src/common/values.cpp(434)
        found = true;
        break;
    if (!found) {
      return false;

Configuration: 
  Number of files: 13
  Minimal block size: 4
  Minimal characters in line: 3
  Ignore preprocessor directives: 0
  Ignore same filenames: 0

Results: 
  Lines of code: 2910
  Duplicate lines of code: 1980
  Total 174 duplicate block(s) found.

  Time: 0.043474 seconds
{code}


> Merge duplicated code of Http V1
> --------------------------------
>
>                 Key: MESOS-3404
>                 URL: https://issues.apache.org/jira/browse/MESOS-3404
>             Project: Mesos
>          Issue Type: Bug
>          Components: HTTP API
>            Reporter: Klaus Ma
>
> After HTTP v1, there is a directory {{src/v1}} including all HTTP v1 related 
> code; but there some duplicated logic/code. The target of this ticket is to 
> draft a design to merge them. Refer to the following diff as an example:
> {code}
> klaus@klaus-ThinkPad-T420:~/Workspace/mesos-3063$ diff src/v1/values.cpp 
> src/common/values.cpp 
> 28,29c28,29
> < #include <mesos/v1/resources.hpp>
> < #include <mesos/v1/values.hpp>
> ---
> > #include <mesos/resources.hpp>
> > #include <mesos/values.hpp>
> 42d41
> < namespace v1 {
> 587d585
> < } // namespace v1 {
> {code}



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to