text: /**
   * 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.
   */
  
  #ifndef __RESOURCES_HPP__
  #define __RESOURCES_HPP__
  
  #include <map>
  #include <iostream>
  #include <set>
  #include <string>
  #include <vector>
  
  #include <mesos/mesos.hpp>
  #include <mesos/type_utils.hpp>
  #include <mesos/values.hpp>
  
  #include <stout/bytes.hpp>
  #include <stout/check.hpp>
  #include <stout/error.hpp>
  #include <stout/foreach.hpp>
  #include <stout/hashmap.hpp>
  #include <stout/lambda.hpp>
  #include <stout/option.hpp>
  #include <stout/try.hpp>
  
  
  // Resources come in three types: scalar, ranges, and sets. These are
  // represented using protocol buffers. To make manipulation of
  // resources easier within the Mesos core and for scheduler writers,
  // we provide generic overloaded operators (see below) as well as a
  // general Resources class that encapsulates a collection of protocol
  // buffer Resource objects. The Resources class also provides a few
  // static routines to allow parsing resources (e.g., from the command
  // line), as well as determining whether or not a Resource object is
  // valid. Note that many of these operations have not been optimized
  // but instead just written for correct semantics.
  
  namespace mesos {
  
  // NOTE: Resource objects stored in the class are always valid and
  // kept combined if possible. It is the caller's responsibility to
  // validate any Resource object or repeated Resource protobufs before
  // constructing a Resources object. Otherwise, invalid Resource
  // objects will be silently stripped. Invalid Resource objects will
  // also be silently ignored when used in arithmetic operations (e.g.,
  // +=, -=, etc.).
  class Resources
  {
  public:
    // Parses the text and returns a Resource object with the given name
    // and role. For example, "Resource r = parse("mem", "1024", "*");".
    static Try<Resource> parse(
        const std::string& name,
        const std::string& value,
        const std::string& role);
  
    // Parses Resources from text 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& text,
        const std::string& defaultRole = "*");
  
    // Validates the given Resource object. Returns Error if it is not
    // valid. A Resource object is valid if it has a name, a valid type,
    // i.e. scalar, range, or set, has the appropriate value set, and
    // a valid (role, reservation) pair for dynamic reservation.
    static Option<Error> validate(const Resource& resource);
  
    // Validates the given protobufs.
    // TODO(jieyu): Right now, it's the same as checking each individual
    // Resource object in the protobufs. In the future, we could add
    // more checks that are not possible if checking each Resource
    // object individually. For example, we could check multiple usage
    // of an item in a set or a ranges, etc.
    static Option<Error> validate(
        const google::protobuf::RepeatedPtrField<Resource>& resources);
  
    // NOTE: The following predicate functions assume that the given
    // resource is validated.
    //
    // Valid states of (role, reservation) pair in the Resource object.
    //   Unreserved         : ("*", None)
    //   Static reservation : (R, None)
    //   Dynamic reservation: (R, { principal: <framework_principal> })
    //
    // NOTE: ("*", { principal: <framework_principal> }) is invalid.
  
    // Tests if the given Resource object is empty.
    static bool isEmpty(const Resource& resource);
  
    // Tests if the given Resource object is a persistent volume.
    static bool isPersistentVolume(const Resource& resource);
  
    // Tests if the given Resource object is reserved. If the role is
    // specified, tests that it's reserved for the given role.
    static bool isReserved(
        const Resource& resource,
        const Option<std::string>& role = None());
  
    // Tests if the given Resource object is unreserved.
    static bool isUnreserved(const Resource& resource);
  
    // Tests if the given Resource object is dynamically reserved.
    static bool isDynamicallyReserved(const Resource& resource);
  
    // Tests if the given Resource object is revocable.
    static bool isRevocable(const Resource& resource);
  
    // Returns the summed up Resources given a hashmap<Key, Resources>.
    //
    // NOTE: While scalar resources such as "cpus" sum correctly,
    // non-scalar resources such as "ports" do not.
    //   e.g. "cpus:2" + "cpus:1" = "cpus:3"
    //        "ports:[0-100]" + "ports:[0-100]" = "ports:[0-100]"
    //
    // TODO(mpark): Deprecate this function once we introduce the
    // concept of "cluster-wide" resources which provides correct
    // semantics for summation over all types of resources. (e.g.
    // non-scalar)
    template <typename Key>
    static Resources sum(const hashmap<Key, Resources>& _resources)
    {
      Resources result;
  
      foreachvalue (const Resources& resources, _resources) {
        result += resources;
      }
  
      return result;
    }
  
    Resources() {}
  
    // TODO(jieyu): Consider using C++11 initializer list.
    /*implicit*/ Resources(const Resource& resource);
  
    /*implicit*/
    Resources(const std::vector<Resource>& _resources);
  
    /*implicit*/
    Resources(const google::protobuf::RepeatedPtrField<Resource>& _resources);
  
    Resources(const Resources& that) : resources(that.resources) {}
  
    Resources& operator = (const Resources& that)
    {
      if (this != &that) {
        resources = that.resources;
      }
      return *this;
    }
  
    bool empty() const { return resources.size() == 0; }
  
    // Checks if this Resources is a superset of the given Resources.
    bool contains(const Resources& that) const;
  
    // Checks if this Resources contains the given Resource.
    bool contains(const Resource& that) const;
  
    // Filter resources based on the given predicate.
    Resources filter(
        const lambda::function<bool(const Resource&)>& predicate) const;
  
    // Returns the reserved resources, by role.
    hashmap<std::string, Resources> reserved() const;
  
    // Returns the reserved resources for the role. Note that the "*"
    // role represents unreserved resources, and will be ignored.
    Resources reserved(const std::string& role) const;
  
    // Returns the unreserved resources.
    Resources unreserved() const;
  
    // Returns the persistent volumes.
    Resources persistentVolumes() const;
  
    // Returns the revocable resources.
    Resources revocable() const;
  
    // Returns a Resources object with the same amount of each resource
    // type as these Resources, but with all Resource objects marked as
    // the specified (role, reservation) pair. This is used to cross
    // reservation boundaries without affecting the actual resources.
    // If the optional ReservationInfo is given, the resource's
    // 'reservation' field is set. Otherwise, the resource's
    // 'reservation' field is cleared.
    Resources flatten(
        const std::string& role = "*",
        const Option<Resource::ReservationInfo>& reservation = None()) const;
  
    // Finds a Resources object with the same amount of each resource
    // type as "targets" from these Resources. The roles specified in
    // "targets" set the preference order. For each resource type,
    // resources are first taken from the specified role, then from '*',
    // then from any other role.
    // TODO(jieyu): 'find' contains some allocation logic for scalars and
    // fixed set / range elements. However, this is not sufficient for
    // schedulers that want, say, any N available ports. We should
    // consider moving this to an internal "allocation" library for our
    // example frameworks to leverage.
    Option<Resources> find(const Resources& targets) const;
  
    // Certain offer operations (e.g., RESERVE, UNRESERVE, CREATE or
    // DESTROY) alter the offered resources. The following methods
    // provide a convenient way to get the transformed resources by
    // applying the given offer operation(s). Returns an Error if the
    // offer operation(s) cannot be applied.
    Try<Resources> apply(const Offer::Operation& operation) const;
  
    template <typename Iterable>
    Try<Resources> apply(const Iterable& operations) const
    {
      Resources result = *this;
  
      foreach (const Offer::Operation& operation, operations) {
        Try<Resources> transformed = result.apply(operation);
        if (transformed.isError()) {
          return Error(transformed.error());
        }
  
        result = transformed.get();
      }
  
      return result;
    }
  
    // Helpers to get resource values. We consider all roles here.
    template <typename T>
    Option<T> get(const std::string& name) const;
  
    // Get resources of the given name.
    Resources get(const std::string& name) const;
  
    // Get all the resources that are scalars.
    Resources scalars() const;
  
    // Get the set of unique resource names.
    std::set<std::string> names() const;
  
    // Get the types of resources associated with each resource name.
    // NOTE: Resources of the same name must have the same type, as
    // enforced by Resources::parse().
    std::map<std::string, Value_Type> types() const;
  
    // Helpers to get known resource types.
    // TODO(vinod): Fix this when we make these types as first class
    // protobufs.
    Option<double> cpus() const;
    Option<Bytes> mem() const;
    Option<Bytes> disk() const;
  
    // TODO(vinod): Provide a Ranges abstraction.
    Option<Value::Ranges> ports() const;
  
    // TODO(jieyu): Consider returning an EphemeralPorts abstraction
    // which holds the ephemeral ports allocation logic.
    Option<Value::Ranges> ephemeral_ports() const;
  
    typedef google::protobuf::RepeatedPtrField<Resource>::iterator
    iterator;
  
    typedef google::protobuf::RepeatedPtrField<Resource>::const_iterator
    const_iterator;
  
    iterator begin() { return resources.begin(); }
    iterator end() { return resources.end(); }
  
    const_iterator begin() const { return resources.begin(); }
    const_iterator end() const { return resources.end(); }
  
    // Using this operator makes it easy to copy a resources object into
    // a protocol buffer field.
    operator const google::protobuf::RepeatedPtrField<Resource>& () const;
  
    bool operator == (const Resources& that) const;
    bool operator != (const Resources& that) const;
  
    // NOTE: If any error occurs (e.g., input Resource is not valid or
    // the first operand is not a superset of the second oprand while
    // doing subtraction), the semantics is as though the second operand
    // was actually just an empty resource (as though you didn't do the
    // operation at all).
    Resources operator + (const Resource& that) const;
    Resources operator + (const Resources& that) const;
    Resources& operator += (const Resource& that);
    Resources& operator += (const Resources& that);
  
    Resources operator - (const Resource& that) const;
    Resources operator - (const Resources& that) const;
    Resources& operator -= (const Resource& that);
    Resources& operator -= (const Resources& that);
  
  private:
    // Similar to 'contains(const Resource&)' but skips the validity
    // check. This can be used to avoid the performance overhead of
    // calling 'contains(const Resource&)' when the resource can be
    // assumed valid (e.g. it's inside a Resources).
    //
    // TODO(jieyu): Measure performance overhead of validity check to
    // ensure this is warranted.
    bool _contains(const Resource& that) const;
  
    // Similar to the public 'find', but only for a single Resource
    // object. The target resource may span multiple roles, so this
    // returns Resources.
    Option<Resources> find(const Resource& target) const;
  
    google::protobuf::RepeatedPtrField<Resource> resources;
  };
  
  
  std::ostream& operator << (std::ostream& stream, const Resource& resource);
  std::ostream& operator << (std::ostream& stream, const Resources& resources);
  
  
  inline std::ostream& operator << (
      std::ostream& stream,
      const google::protobuf::RepeatedPtrField<Resource>& resources)
  {
    return stream << Resources(resources);
  }
  
  
  inline Resources operator + (
      const google::protobuf::RepeatedPtrField<Resource>& left,
      const Resources& right)
  {
    return Resources(left) + right;
  }
  
  
  inline Resources operator - (
      const google::protobuf::RepeatedPtrField<Resource>& left,
      const Resources& right)
  {
    return Resources(left) - right;
  }
  
  
  inline bool operator == (
      const google::protobuf::RepeatedPtrField<Resource>& left,
      const Resources& right)
  {
    return Resources(left) == right;
  }
  
  
  template <typename Key>
  hashmap<Key, Resources>& operator += (
      hashmap<Key, Resources>& left,
      const hashmap<Key, Resources>& right)
  {
    foreachpair (const Key& key, const Resources& resources, right) {
      left[key] += resources;
    }
    return left;
  }
  
  
  template <typename Key>
  hashmap<Key, Resources> operator + (
      const hashmap<Key, Resources>& left,
      const hashmap<Key, Resources>& right)
  {
    hashmap<Key, Resources> result = left;
    result += right;
    return result;
  }
  
  } // namespace mesos {
  
  #endif // __RESOURCES_HPP__
  