Repository: mesos
Updated Branches:
  refs/heads/master b3293b28f -> b923cb529


http://git-wip-us.apache.org/repos/asf/mesos/blob/b923cb52/src/v1/values.cpp
----------------------------------------------------------------------
diff --git a/src/v1/values.cpp b/src/v1/values.cpp
new file mode 100644
index 0000000..daa98b8
--- /dev/null
+++ b/src/v1/values.cpp
@@ -0,0 +1,588 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <iostream>
+#include <vector>
+
+#include <glog/logging.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include <mesos/v1/resources.hpp>
+#include <mesos/v1/values.hpp>
+
+#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 {
+namespace v1 {
+
+namespace internal {
+namespace values {
+
+Try<Value> parse(const std::string& text)
+{
+  Value value;
+
+  // Remove any spaces from the text.
+  string temp;
+  foreach (const char c, text) {
+    if (c != ' ') {
+      temp += c;
+    }
+  }
+
+  if (temp.length() == 0) {
+    return Error("Expecting non-empty string");
+  }
+
+  // TODO(ynie): Find a better way to check brackets.
+  if (!strings::checkBracketsMatching(temp, '{', '}') ||
+      !strings::checkBracketsMatching(temp, '[', ']') ||
+      !strings::checkBracketsMatching(temp, '(', ')')) {
+    return Error("Mismatched brackets");
+  }
+
+  size_t index = temp.find('[');
+  if (index == 0) {
+    // This is a ranges.
+    Value::Ranges 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] + "'");
+        }
+      }
+
+      value.set_type(Value::RANGES);
+      value.mutable_ranges()->MergeFrom(ranges);
+      return value;
+    }
+  } else if (index == string::npos) {
+    size_t index = temp.find('{');
+    if (index == 0) {
+      // This is a set.
+      Value::Set set;
+      const vector<string>& tokens = strings::tokenize(temp, "{},\n");
+      for (size_t i = 0; i < tokens.size(); i++) {
+        set.add_item(tokens[i]);
+      }
+
+      value.set_type(Value::SET);
+      value.mutable_set()->MergeFrom(set);
+      return value;
+    } else if (index == string::npos) {
+      try {
+        Value::Scalar scalar;
+        scalar.set_value(boost::lexical_cast<double>(temp));
+        // This is a Scalar.
+        value.set_type(Value::SCALAR);
+        value.mutable_scalar()->MergeFrom(scalar);
+        return value;
+      } catch (const boost::bad_lexical_cast&) {
+        // This is a Text.
+        Value::Text text;
+        text.set_value(temp);
+        value.set_type(Value::TEXT);
+        value.mutable_text()->MergeFrom(text);
+        return value;
+      }
+    } else {
+      return Error("Unexpected '{' found");
+    }
+  }
+
+  return Error("Unexpected '[' found");
+}
+
+} // namespace values {
+} // namespace internal {
+
+
+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 ranges {
+
+static void add(Value::Ranges* result, int64_t begin, int64_t end)
+{
+  if (begin > end) {
+    return;
+  }
+  Value::Range* range = result->add_range();
+  range->set_begin(begin);
+  range->set_end(end);
+}
+
+} // namespace ranges {
+
+
+// Coalesce the given 'range' into already coalesced 'ranges'.
+static void coalesce(Value::Ranges* ranges, const Value::Range& range)
+{
+  // Note that we assume that ranges has already been coalesced.
+
+  Value::Ranges result;
+  Value::Range temp = range;
+
+  for (int i = 0; i < ranges->range_size(); i++) {
+    const Value::Range& current = ranges->range(i);
+
+    // Check if current and range overlap. Note, we only need to
+    // compare with range and not with temp to check for overlap
+    // because we expect ranges to be coalesced to begin with!
+    if (current.begin() <= range.end() + 1 &&
+        current.end() >= range.begin() - 1) {
+      // current:   |   |
+      // range:       |   |
+      // range:   |   |
+      // Update temp with new boundaries.
+      temp.set_begin(min(temp.begin(), min(range.begin(), current.begin())));
+      temp.set_end(max(temp.end(), max(range.end(), current.end())));
+    } else { // No overlap.
+      result.add_range()->MergeFrom(current);
+    }
+  }
+
+  result.add_range()->MergeFrom(temp);
+  *ranges = result;
+}
+
+
+// Coalesce the given un-coalesced 'uranges' into already coalesced 'ranges'.
+static void coalesce(Value::Ranges* ranges, const Value::Ranges& uranges)
+{
+  // Note that we assume that ranges has already been coalesced.
+
+  for (int i = 0; i < uranges.range_size(); i++) {
+    coalesce(ranges, uranges.range(i));
+  }
+}
+
+
+static void remove(Value::Ranges* ranges, const Value::Range& range)
+{
+  // Note that we assume that ranges has already been coalesced.
+
+  Value::Ranges result;
+
+  for (int i = 0; i < ranges->range_size(); i++) {
+    const Value::Range& current = ranges->range(i);
+
+    // Note that these if/else if conditionals are in a particular
+    // order. In particular, the last two assume that the "subsumes"
+    // checks have already occurred.
+    if (range.begin() <= current.begin() && range.end() >= current.end()) {
+      // Range subsumes current.
+      // current:  |     |
+      // range:  |         |
+      // range:  |       |
+      // range:    |       |
+      // range:    |     |
+    } else if (range.begin() >= current.begin() &&
+               range.end() <= current.end()) {
+      // Range is subsumed by current.
+      // current:  |     |
+      // range:      | |
+      // range:    |   |
+      // range:      |   |
+      ranges::add(&result, current.begin(), range.begin() - 1);
+      ranges::add(&result, range.end() + 1, current.end());
+    } else if (range.begin() <= current.begin() &&
+               range.end() >= current.begin()) {
+      // Range overlaps to the left.
+      // current:  |     |
+      // range:  |     |
+      // range:  | |
+      ranges::add(&result, range.end() + 1, current.end());
+    } else if (range.begin() <= current.end() && range.end() >= current.end()) 
{
+      // Range overlaps to the right.
+      // current:  |     |
+      // range:      |      |
+      // range:          |  |
+      ranges::add(&result, current.begin(), range.begin() - 1);
+    } else {
+      // Range doesn't overlap current.
+      // current:        |   |
+      // range:   |   |
+      // range:                |   |
+      ranges::add(&result, current.begin(), current.end());
+    }
+  }
+
+  *ranges = result;
+}
+
+
+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++) {
+      // Make sure this range is equal to a range in the right.
+      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++) {
+    // Make sure this range is a subset of a range in right.
+    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);
+  coalesce(&result, right);
+
+  return result;
+}
+
+
+Value::Ranges operator - (const Value::Ranges& left, const Value::Ranges& 
right)
+{
+  Value::Ranges result;
+
+  coalesce(&result, left);
+  coalesce(&result, right);
+
+  for (int i = 0; i < right.range_size(); i++) {
+    remove(&result, right.range(i));
+  }
+
+  return result;
+}
+
+
+Value::Ranges& operator += (Value::Ranges& left, const Value::Ranges& right)
+{
+  Value::Ranges temp;
+
+  coalesce(&temp, left);
+
+  left = temp;
+
+  coalesce(&left, right);
+
+  return left;
+}
+
+
+Value::Ranges& operator -= (Value::Ranges& left, const Value::Ranges& right)
+{
+  Value::Ranges temp;
+
+  coalesce(&temp, left);
+  coalesce(&temp, right);
+
+  left = temp;
+
+  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++) {
+      // Make sure this item is equal to an item in the right.
+      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++) {
+      // Make sure this item is equal to an item in the right.
+      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));
+  }
+
+  // A little bit of extra logic to avoid adding duplicates from right.
+  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;
+
+  // Look for the same item in right as we add left to 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)
+{
+  // A little bit of extra logic to avoid adding duplicates from 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 each item in right, remove it if it's in left.
+  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 v1 {
+} // namespace mesos {

Reply via email to