<commit_before>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     Guido Tack <guido.tack@monash.edu>
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef __MINIZINC_VALUES_HH__
#define __MINIZINC_VALUES_HH__

#include <minizinc/gc.hh>
#include <algorithm>
#include <functional>
#include <vector>

namespace MiniZinc {

  class IntVal {
  private:
    long long int _v;
    bool _infinity;
  public:
    IntVal(void) : _v(0), _infinity(false) {}
    IntVal(long long int v) : _v(v), _infinity(false) {}

    long long int toInt(void) const { return _v; }

    bool isFinite(void) const { return !_infinity; }
    bool isPlusInfinity(void) const { return _infinity && _v==1; }
    bool isMinusInfinity(void) const { return _infinity && _v==-1; }

    IntVal& operator +=(const IntVal& x) {
      if (_infinity)
        return *this;
      _v += x._v;
      return *this;
    }
    IntVal& operator -=(const IntVal& x) {
      _v -= x._v;
      return *this;
    }
    IntVal& operator *=(const IntVal& x) {
      _v *= x._v;
      return *this;
    }
    IntVal& operator /=(const IntVal& x) {
      _v /= x._v;
      return *this;
    }
    IntVal operator -() {
      return -_v;
    }
    void operator ++() {
      ++_v;
    }
    void operator ++(int) {
      ++_v;
    }
    void operator --() {
      --_v;
    }
    void operator --(int) {
      --_v;
    }
    static const IntVal minint;
    static const IntVal maxint;
  };

  inline
  bool operator ==(const IntVal& x, const IntVal& y) {
    return x.isFinite()==y.isFinite() && x.toInt() == y.toInt();
  }
  inline
  bool operator <=(const IntVal& x, const IntVal& y) {
    return x.toInt() <= y.toInt();
  }
  inline
  bool operator <(const IntVal& x, const IntVal& y) {
    return x.toInt() < y.toInt();
  }
  inline
  bool operator >=(const IntVal& x, const IntVal& y) {
    return x.toInt() >= y.toInt();
  }
  inline
  bool operator >(const IntVal& x, const IntVal& y) {
    return x.toInt() > y.toInt();
  }
  inline
  bool operator !=(const IntVal& x, const IntVal& y) {
    return x.toInt() != y.toInt();
  }
  inline
  IntVal operator +(const IntVal& x, const IntVal& y) {
    return x.toInt()+y.toInt();
  }
  inline
  IntVal operator -(const IntVal& x, const IntVal& y) {
    return x.toInt()-y.toInt();
  }
  inline
  IntVal operator *(const IntVal& x, const IntVal& y) {
    return x.toInt()*y.toInt();
  }
  inline
  IntVal operator /(const IntVal& x, const IntVal& y) {
    return x.toInt()/y.toInt();
  }
  inline
  IntVal operator %(const IntVal& x, const IntVal& y) {
    return x.toInt()%y.toInt();
  }
  template<class Char, class Traits>
  std::basic_ostream<Char,Traits>&
  operator <<(std::basic_ostream<Char,Traits>& os, const IntVal& s) {
    return os << s.toInt();
  }
}

namespace std {
  inline
  MiniZinc::IntVal abs(const MiniZinc::IntVal& x) {
    return abs(x.toInt());
  }

  inline
  MiniZinc::IntVal min(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) {
    return min(x.toInt(),y.toInt());
  }
  inline
  MiniZinc::IntVal max(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) {
    return max(x.toInt(),y.toInt());
  }

  template<>
  struct hash<MiniZinc::IntVal> {
  public:
    size_t operator()(const MiniZinc::IntVal& s) const {
      std::hash<long long int> h;
      return h(s.toInt());
    }
  };
  template<>
  struct equal_to<MiniZinc::IntVal> {
  public:
    bool operator()(const MiniZinc::IntVal& s0,
                    const MiniZinc::IntVal& s1) const {
      return s0==s1;
    }
  };
}

namespace MiniZinc {

  typedef unsigned long long int UIntVal;

  typedef double FloatVal;

  /// An integer set value
  class IntSetVal : public ASTChunk {
  private:
    /// Contiguous range
    struct Range {
      /// Range minimum
      IntVal min;
      /// Range maximum
      IntVal max;
      /// Construct range from \a m to \a n
      Range(IntVal m, IntVal n) : min(m), max(n) {}
      /// Default constructor
      Range(void) {}
    };
    /// Return range at position \a i
    Range& get(int i) {
      return reinterpret_cast<Range*>(_data)[i];
    }
    /// Return range at position \a i
    const Range& get(int i) const {
      return reinterpret_cast<const Range*>(_data)[i];
    }
    /// Construct empty set
    IntSetVal(void) : ASTChunk(0) {}
    /// Construct set of single range
    IntSetVal(IntVal m, IntVal n) : ASTChunk(sizeof(Range)) {
      get(0).min = m;
      get(0).max = n;
    }
    /// Construct set from \a s
    IntSetVal(const std::vector<Range>& s)
      : ASTChunk(sizeof(Range)*s.size()) {
      for (unsigned int i=s.size(); i--;)
        get(i) = s[i];
    }

    /// Disabled
    IntSetVal(const IntSetVal& r);
    /// Disabled
    IntSetVal& operator =(const IntSetVal& r);
  public:
    /// Return number of ranges
    int size(void) const { return _size / sizeof(Range); }
    /// Return minimum of range \a i
    IntVal min(int i) const { assert(i<size()); return get(i).min; }
    /// Return maximum of range \a i
    IntVal max(int i) const { assert(i<size()); return get(i).max; }
    /// Return width of range \a i
    IntVal width(int i) const { assert(i<size()); return max(i)-min(i)+1; }
    /// Return cardinality
    IntVal card(void) const {
      IntVal c = 0;
      for (unsigned int i=size(); i--;)
        c += width(i);
      return c;
    }

    /// Allocate empty set from context
    static IntSetVal* a(void) {
      IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(0));
      new (r) IntSetVal();
      return r;
    }

    /// Allocate set \f$\{m,n\}\f$ from context
    static IntSetVal* a(IntVal m, IntVal n) {
      if (m>n) {
        return a();
      } else {
        IntSetVal* r =
          static_cast<IntSetVal*>(ASTChunk::alloc(sizeof(Range)));
        new (r) IntSetVal(m,n);
        return r;
      }
    }

    /// Allocate set using iterator \a i
    template<class I>
    static IntSetVal* ai(I& i) {
      std::vector<Range> s;
      for (; i(); ++i)
        s.push_back(Range(i.min(),i.max()));
      IntSetVal* r = static_cast<IntSetVal*>(
          ASTChunk::alloc(sizeof(Range)*s.size()));
      new (r) IntSetVal(s);
      return r;
    }

    /// Allocate set from vector \a s0 (may contain duplicates)
    static IntSetVal* a(const std::vector<IntVal>& s0) {
      if (s0.size()==0)
        return a();
      std::vector<IntVal> s=s0;
      std::sort(s.begin(),s.end());
      std::vector<Range> ranges;
      IntVal min=s[0];
      IntVal max=min;
      for (unsigned int i=1; i<s.size(); i++) {
        if (s[i]>max+1) {
          ranges.push_back(Range(min,max));
          min=s[i]; max=min;
        } else {
          max=s[i];
        }
      }
      ranges.push_back(Range(min,max));
      IntSetVal* r = static_cast<IntSetVal*>(
          ASTChunk::alloc(sizeof(Range)*ranges.size()));
      new (r) IntSetVal(ranges);
      return r;
    }

    /// Check if set contains \a v
    bool contains(const IntVal& v) {
      for (int i=0; i<size(); i++) {
        if (v < min(i))
          return false;
        if (v <= max(i))
          return true;
      }
      return false;
    }

    /// Check if it is equal to \a s
    bool equal(const IntSetVal* s) {
      if (size()!=s->size())
        return false;
      for (int i=0; i<size(); i++)
        if (min(i)!=s->min(i) || max(i)!=s->max(i))
          return false;
      return true;
    }

    /// Mark for garbage collection
    void mark(void) {
      _gc_mark = 1;
    }
  };

  /// Iterator over an IntSetVal
  class IntSetRanges {
    /// The set value
    const IntSetVal* rs;
    /// The current range
    int n;
  public:
    /// Constructor
    IntSetRanges(const IntSetVal* r) : rs(r), n(0) {}
    /// Check if iterator is still valid
    bool operator()(void) const { return n<rs->size(); }
    /// Move to next range
    void operator++(void) { ++n; }
    /// Return minimum of current range
    IntVal min(void) const { return rs->min(n); }
    /// Return maximum of current range
    IntVal max(void) const { return rs->max(n); }
    /// Return width of current range
    IntVal width(void) const { return rs->width(n); }
  };

}

#endif
<commit_msg>Add output operator for IntSetVal<commit_after>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     Guido Tack <guido.tack@monash.edu>
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef __MINIZINC_VALUES_HH__
#define __MINIZINC_VALUES_HH__

#include <minizinc/gc.hh>
#include <algorithm>
#include <functional>
#include <vector>

namespace MiniZinc {

  class IntVal {
  private:
    long long int _v;
    bool _infinity;
  public:
    IntVal(void) : _v(0), _infinity(false) {}
    IntVal(long long int v) : _v(v), _infinity(false) {}

    long long int toInt(void) const { return _v; }

    bool isFinite(void) const { return !_infinity; }
    bool isPlusInfinity(void) const { return _infinity && _v==1; }
    bool isMinusInfinity(void) const { return _infinity && _v==-1; }

    IntVal& operator +=(const IntVal& x) {
      if (_infinity)
        return *this;
      _v += x._v;
      return *this;
    }
    IntVal& operator -=(const IntVal& x) {
      _v -= x._v;
      return *this;
    }
    IntVal& operator *=(const IntVal& x) {
      _v *= x._v;
      return *this;
    }
    IntVal& operator /=(const IntVal& x) {
      _v /= x._v;
      return *this;
    }
    IntVal operator -() {
      return -_v;
    }
    void operator ++() {
      ++_v;
    }
    void operator ++(int) {
      ++_v;
    }
    void operator --() {
      --_v;
    }
    void operator --(int) {
      --_v;
    }
    static const IntVal minint;
    static const IntVal maxint;
  };

  inline
  bool operator ==(const IntVal& x, const IntVal& y) {
    return x.isFinite()==y.isFinite() && x.toInt() == y.toInt();
  }
  inline
  bool operator <=(const IntVal& x, const IntVal& y) {
    return x.toInt() <= y.toInt();
  }
  inline
  bool operator <(const IntVal& x, const IntVal& y) {
    return x.toInt() < y.toInt();
  }
  inline
  bool operator >=(const IntVal& x, const IntVal& y) {
    return x.toInt() >= y.toInt();
  }
  inline
  bool operator >(const IntVal& x, const IntVal& y) {
    return x.toInt() > y.toInt();
  }
  inline
  bool operator !=(const IntVal& x, const IntVal& y) {
    return x.toInt() != y.toInt();
  }
  inline
  IntVal operator +(const IntVal& x, const IntVal& y) {
    return x.toInt()+y.toInt();
  }
  inline
  IntVal operator -(const IntVal& x, const IntVal& y) {
    return x.toInt()-y.toInt();
  }
  inline
  IntVal operator *(const IntVal& x, const IntVal& y) {
    return x.toInt()*y.toInt();
  }
  inline
  IntVal operator /(const IntVal& x, const IntVal& y) {
    return x.toInt()/y.toInt();
  }
  inline
  IntVal operator %(const IntVal& x, const IntVal& y) {
    return x.toInt()%y.toInt();
  }
  template<class Char, class Traits>
  std::basic_ostream<Char,Traits>&
  operator <<(std::basic_ostream<Char,Traits>& os, const IntVal& s) {
    return os << s.toInt();
  }
}

namespace std {
  inline
  MiniZinc::IntVal abs(const MiniZinc::IntVal& x) {
    return abs(x.toInt());
  }

  inline
  MiniZinc::IntVal min(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) {
    return min(x.toInt(),y.toInt());
  }
  inline
  MiniZinc::IntVal max(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) {
    return max(x.toInt(),y.toInt());
  }

  template<>
  struct hash<MiniZinc::IntVal> {
  public:
    size_t operator()(const MiniZinc::IntVal& s) const {
      std::hash<long long int> h;
      return h(s.toInt());
    }
  };
  template<>
  struct equal_to<MiniZinc::IntVal> {
  public:
    bool operator()(const MiniZinc::IntVal& s0,
                    const MiniZinc::IntVal& s1) const {
      return s0==s1;
    }
  };
}

namespace MiniZinc {

  typedef unsigned long long int UIntVal;

  typedef double FloatVal;

  /// An integer set value
  class IntSetVal : public ASTChunk {
  private:
    /// Contiguous range
    struct Range {
      /// Range minimum
      IntVal min;
      /// Range maximum
      IntVal max;
      /// Construct range from \a m to \a n
      Range(IntVal m, IntVal n) : min(m), max(n) {}
      /// Default constructor
      Range(void) {}
    };
    /// Return range at position \a i
    Range& get(int i) {
      return reinterpret_cast<Range*>(_data)[i];
    }
    /// Return range at position \a i
    const Range& get(int i) const {
      return reinterpret_cast<const Range*>(_data)[i];
    }
    /// Construct empty set
    IntSetVal(void) : ASTChunk(0) {}
    /// Construct set of single range
    IntSetVal(IntVal m, IntVal n) : ASTChunk(sizeof(Range)) {
      get(0).min = m;
      get(0).max = n;
    }
    /// Construct set from \a s
    IntSetVal(const std::vector<Range>& s)
      : ASTChunk(sizeof(Range)*s.size()) {
      for (unsigned int i=s.size(); i--;)
        get(i) = s[i];
    }

    /// Disabled
    IntSetVal(const IntSetVal& r);
    /// Disabled
    IntSetVal& operator =(const IntSetVal& r);
  public:
    /// Return number of ranges
    int size(void) const { return _size / sizeof(Range); }
    /// Return minimum of range \a i
    IntVal min(int i) const { assert(i<size()); return get(i).min; }
    /// Return maximum of range \a i
    IntVal max(int i) const { assert(i<size()); return get(i).max; }
    /// Return width of range \a i
    IntVal width(int i) const { assert(i<size()); return max(i)-min(i)+1; }
    /// Return cardinality
    IntVal card(void) const {
      IntVal c = 0;
      for (unsigned int i=size(); i--;)
        c += width(i);
      return c;
    }

    /// Allocate empty set from context
    static IntSetVal* a(void) {
      IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(0));
      new (r) IntSetVal();
      return r;
    }

    /// Allocate set \f$\{m,n\}\f$ from context
    static IntSetVal* a(IntVal m, IntVal n) {
      if (m>n) {
        return a();
      } else {
        IntSetVal* r =
          static_cast<IntSetVal*>(ASTChunk::alloc(sizeof(Range)));
        new (r) IntSetVal(m,n);
        return r;
      }
    }

    /// Allocate set using iterator \a i
    template<class I>
    static IntSetVal* ai(I& i) {
      std::vector<Range> s;
      for (; i(); ++i)
        s.push_back(Range(i.min(),i.max()));
      IntSetVal* r = static_cast<IntSetVal*>(
          ASTChunk::alloc(sizeof(Range)*s.size()));
      new (r) IntSetVal(s);
      return r;
    }

    /// Allocate set from vector \a s0 (may contain duplicates)
    static IntSetVal* a(const std::vector<IntVal>& s0) {
      if (s0.size()==0)
        return a();
      std::vector<IntVal> s=s0;
      std::sort(s.begin(),s.end());
      std::vector<Range> ranges;
      IntVal min=s[0];
      IntVal max=min;
      for (unsigned int i=1; i<s.size(); i++) {
        if (s[i]>max+1) {
          ranges.push_back(Range(min,max));
          min=s[i]; max=min;
        } else {
          max=s[i];
        }
      }
      ranges.push_back(Range(min,max));
      IntSetVal* r = static_cast<IntSetVal*>(
          ASTChunk::alloc(sizeof(Range)*ranges.size()));
      new (r) IntSetVal(ranges);
      return r;
    }

    /// Check if set contains \a v
    bool contains(const IntVal& v) {
      for (int i=0; i<size(); i++) {
        if (v < min(i))
          return false;
        if (v <= max(i))
          return true;
      }
      return false;
    }

    /// Check if it is equal to \a s
    bool equal(const IntSetVal* s) {
      if (size()!=s->size())
        return false;
      for (int i=0; i<size(); i++)
        if (min(i)!=s->min(i) || max(i)!=s->max(i))
          return false;
      return true;
    }

    /// Mark for garbage collection
    void mark(void) {
      _gc_mark = 1;
    }
  };

  /// Iterator over an IntSetVal
  class IntSetRanges {
    /// The set value
    const IntSetVal* rs;
    /// The current range
    int n;
  public:
    /// Constructor
    IntSetRanges(const IntSetVal* r) : rs(r), n(0) {}
    /// Check if iterator is still valid
    bool operator()(void) const { return n<rs->size(); }
    /// Move to next range
    void operator++(void) { ++n; }
    /// Return minimum of current range
    IntVal min(void) const { return rs->min(n); }
    /// Return maximum of current range
    IntVal max(void) const { return rs->max(n); }
    /// Return width of current range
    IntVal width(void) const { return rs->width(n); }
  };

  template<class Char, class Traits>
  std::basic_ostream<Char,Traits>&
  operator <<(std::basic_ostream<Char,Traits>& os, const IntSetVal& s) {
    for (IntSetRanges isr(&s); isr(); ++isr)
      os << isr.min() << ".." << isr.max() << " ";
    return os;
  }

}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2017-, Rohan Budhiraja, CNRS
 *
 * This file is part of sot-core.
 * sot-core is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * sot-core is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.  You should
 * have received a copy of the GNU Lesser General Public License along
 * with sot-core.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __SOT_SWITCH_H__
#define __SOT_SWITCH_H__

/* --------------------------------------------------------------------- */
/* --- INCLUDE --------------------------------------------------------- */
/* --------------------------------------------------------------------- */

/* SOT */
#include <dynamic-graph/command-bind.h>
#include <sot/core/pool.hh>
#include <dynamic-graph/entity.h>
#include <dynamic-graph/all-signals.h>

/* STD */
#include <string>

namespace dynamicgraph {
  namespace sot {

    /* --------------------------------------------------------------------- */
    /* --- CLASS ----------------------------------------------------------- */
    /* --------------------------------------------------------------------- */
    using dynamicgraph::Entity;
    using dynamicgraph::command::makeCommandVoid0;
    using dynamicgraph::command::docCommandVoid0;

    class Switch : public Entity
    {

    public: /* --- SIGNAL --- */
      DYNAMIC_GRAPH_ENTITY_DECL();
      dynamicgraph::Signal<bool,int> outSOUT;

    protected:
      bool signalOutput;
      void turnOn(){ signalOutput = true; }

      void turnOff(){ signalOutput = false; }

      bool& switchOutput(bool& res, int){ res = signalOutput; return res; }

    public:
      Switch( const std::string& name )
	: Entity(name)
	,outSOUT("Switch("+name+")::output(bool)::out")
      {
        outSOUT.setFunction(boost::bind(&Switch::switchOutput,this,_1,_2));
        signalOutput = false;
        signalRegistration (outSOUT );
        addCommand ("turnOn",
                    makeCommandVoid0 (*this, &Switch::turnOn,
                                      docCommandVoid0 ("Turn on the switch")));
        addCommand ("turnOff",
                    makeCommandVoid0 (*this, &Switch::turnOff,
                                      docCommandVoid0 ("Turn off the switch")));
      }

        virtual ~Switch( void ) {};

};
} /* namespace sot */
} /* namespace dynamicgraph */

#endif // #ifndef __SOT_SWITCH_H__
<commit_msg>Add signal to Switch entity<commit_after>/*
 * Copyright 2017-, Rohan Budhiraja, CNRS
 *
 * This file is part of sot-core.
 * sot-core is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * sot-core is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.  You should
 * have received a copy of the GNU Lesser General Public License along
 * with sot-core.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __SOT_SWITCH_H__
#define __SOT_SWITCH_H__

/* --------------------------------------------------------------------- */
/* --- INCLUDE --------------------------------------------------------- */
/* --------------------------------------------------------------------- */

/* SOT */
#include <dynamic-graph/command-bind.h>
#include <sot/core/pool.hh>
#include <dynamic-graph/entity.h>
#include <dynamic-graph/all-signals.h>

/* STD */
#include <string>

namespace dynamicgraph {
  namespace sot {

    /* --------------------------------------------------------------------- */
    /* --- CLASS ----------------------------------------------------------- */
    /* --------------------------------------------------------------------- */
    using dynamicgraph::Entity;
    using dynamicgraph::command::makeCommandVoid0;
    using dynamicgraph::command::docCommandVoid0;

    class Switch : public Entity
    {

    public: /* --- SIGNAL --- */
      DYNAMIC_GRAPH_ENTITY_DECL();
      Signal<bool,int> outSOUT;
      Signal<bool,int> turnOnSOUT;
      Signal<bool,int> turnOffSOUT;

    protected:
      bool signalOutput;
      void turnOn(){ signalOutput = true; }
      bool& turnOnSwitch(bool& res, int){ res = signalOutput = true; return res; }

      void turnOff(){ signalOutput = false; }
      bool& turnOffSwitch(bool& res, int){ res = signalOutput = false; return res; }

      bool& switchOutput(bool& res, int){ res = signalOutput; return res; }

    public:
      Switch( const std::string& name )
	: Entity(name)
	,outSOUT("Switch("+name+")::output(bool)::out")
	,turnOnSOUT ("Switch("+name+")::output(bool)::turnOnSout")
	,turnOffSOUT("Switch("+name+")::output(bool)::turnOffSout")
      {
        outSOUT.setFunction(boost::bind(&Switch::switchOutput,this,_1,_2));
        turnOnSOUT .setFunction(boost::bind(&Switch::turnOnSwitch ,this,_1,_2));
        turnOffSOUT.setFunction(boost::bind(&Switch::turnOffSwitch,this,_1,_2));
        signalOutput = false;
        signalRegistration (outSOUT << turnOnSOUT << turnOffSOUT);
        addCommand ("turnOn",
                    makeCommandVoid0 (*this, &Switch::turnOn,
                                      docCommandVoid0 ("Turn on the switch")));
        addCommand ("turnOff",
                    makeCommandVoid0 (*this, &Switch::turnOff,
                                      docCommandVoid0 ("Turn off the switch")));
      }

        virtual ~Switch( void ) {};

};
} /* namespace sot */
} /* namespace dynamicgraph */

#endif // #ifndef __SOT_SWITCH_H__
<|endoftext|>


<commit_before>// Copyright: 2014, 2015, Ableton AG, Berlin. All rights reserved.

#pragma once

#include <atria/xform/functional.hpp>
#include <atria/xform/state.hpp>

#include <atria/estd/type_traits.hpp>
#include <atria/estd/utility.hpp>

#include <algorithm>
#include <numeric>
#include <tuple>

//!
// When defined to 1, std::accumulate will be used as an
// implementation for reduce() over one single collection.  In that
// case, halting reducers (e.g. take) might not work.
//
#ifndef ABL_REDUCE_WITH_ACCUMULATE
#define ABL_REDUCE_WITH_ACCUMULATE 0
#endif

//!
// When defined to 1, reduce will be defined separately for the
// non-variadic version.
//
#ifndef ABL_REDUCE_NON_VARIADIC
#define ABL_REDUCE_NON_VARIADIC 1
#endif

namespace atria {
namespace xform {

namespace detail {

template <typename ReducerT,
          typename StateT,
          typename InputRangeT>
auto reduce_nested_accumulate(ReducerT&& reducer, StateT&& state, InputRangeT&& range)
  -> estd::decay_t<StateT>
{
  return std::accumulate(
    std::begin(range),
    std::end(range),
    std::forward<StateT>(state),
    std::forward<ReducerT>(reducer));
}

template <typename ReducerT,
          typename StateT,
          typename InputRangeT>
auto reduce_nested_non_variadic(ReducerT&& reducer,
                                StateT&& initial,
                                InputRangeT&& range)
  -> estd::decay_t<decltype(reducer(initial, *std::begin(range)))>
{
  using result_t = estd::decay_t<decltype(reducer(initial, *std::begin(range)))>;

  auto first = std::begin(range);
  auto last  = std::end(range);
  if (first != last) {
    auto state = reducer(std::forward<StateT>(initial), *first);
    while (!state_is_reduced(state) && ++first != last) {
      state = reducer(std::move(state), *first);
    }
    return state;
  }

  return result_t { initial };
}

template <typename ReducerT,
          typename StateT,
          std::size_t ...Indices,
          typename ...InputRangeTs>
auto reduce_nested_variadic_impl(ReducerT&& reducer,
                                 StateT&& initial,
                                 estd::index_sequence<Indices...>,
                                 InputRangeTs&& ...ranges)
  -> estd::decay_t<decltype(reducer(initial, *std::begin(ranges)...))>
{
  using result_t = estd::decay_t<decltype(
    reducer(initial, *std::begin(ranges)...))>;

  auto firsts = std::make_tuple(std::begin(ranges)...);
  auto lasts  = std::make_tuple(std::end(ranges)...);
  if (std::min({std::get<Indices>(firsts) !=
                std::get<Indices>(lasts)...}))
  {
    auto state = reducer(std::forward<StateT>(initial),
                         *std::get<Indices>(firsts)...);
    while (!state_is_reduced(state)
           && std::min({ ++std::get<Indices>(firsts) !=
                         std::get<Indices>(lasts)... })) {
      state = reducer(std::move(state), *std::get<Indices>(firsts)...);
    }
    return state;
  }

  return result_t { initial };
}

template <typename ReducerT,
          typename StateT,
          typename ...InputRangeTs>
auto reduce_nested_variadic(ReducerT&& reducer, StateT&& state, InputRangeTs&& ...ranges)
  -> decltype(detail::reduce_nested_variadic_impl(
                std::forward<ReducerT>(reducer),
                std::forward<StateT>(state),
                estd::make_index_sequence<sizeof...(InputRangeTs)> {},
                std::forward<InputRangeTs>(ranges)...))
{
  return detail::reduce_nested_variadic_impl(
    std::forward<ReducerT>(reducer),
    std::forward<StateT>(state),
    estd::make_index_sequence<sizeof...(InputRangeTs)> {},
    std::forward<InputRangeTs>(ranges)...);
}

} // namespace detail

#if ABL_REDUCE_WITH_ACCUMULATE
#  define ABL_REDUCE_NESTED_NON_VARIADIC_IMPL \
  ::atria::xform::detail::reduce_nested_accumulate
#elif ABL_REDUCE_NON_VARIADIC
#  define ABL_REDUCE_NESTED_NON_VARIADIC_IMPL \
  ::atria::xform::detail::reduce_nested_non_variadic
#else
#  define ABL_REDUCE_NESTED_NON_VARIADIC_IMPL \
  ::atria::xform::detail::reduce_nested_variadic
#endif

//!
// Similar to @a reduce, but does not unwrap `reduced` values.  This is
// useful when calling reduce recursively inside a transducer.
// @see take
//
template <typename ReducerT,
          typename StateT,
          typename InputRangeT>
auto reduce_nested(ReducerT&& reducer, StateT&& state, InputRangeT&& range)
  -> decltype(ABL_REDUCE_NESTED_NON_VARIADIC_IMPL(
                std::forward<ReducerT>(reducer),
                std::forward<StateT>(state),
                std::forward<InputRangeT>(range)))
{
  return ABL_REDUCE_NESTED_NON_VARIADIC_IMPL(
    std::forward<ReducerT>(reducer),
    std::forward<StateT>(state),
    std::forward<InputRangeT>(range));
}

template <typename ReducerT,
          typename StateT,
          typename InputRangeT,
          typename ...InputRangeTs>
auto reduce_nested(ReducerT&& reducer, StateT&& state, InputRangeT&& range,
                   InputRangeTs&& ...ranges)
  -> decltype(detail::reduce_nested_variadic(
                std::forward<ReducerT>(reducer),
                std::forward<StateT>(state),
                std::forward<InputRangeT>(range),
                std::forward<InputRangeTs>(ranges)...))
{
  return detail::reduce_nested_variadic(
    std::forward<ReducerT>(reducer),
    std::forward<StateT>(state),
    std::forward<InputRangeT>(range),
    std::forward<InputRangeTs>(ranges)...);
}

//!
// Similar to clojure.core/reduce.  Unlike `std::accumulate`, this
// reduces over a range (doesn't take to distinct iterators) and can
// reduce over several ranges at the same time.  It also supports
// early termination for transducers.
//
template <typename ReducerT,
          typename StateT,
          typename ...InputRangeTs>
auto reduce(ReducerT&& reducer, StateT&& state, InputRangeTs&& ...ranges)
  -> estd::decay_t<StateT>
{
  return state_complete(
    reduce_nested(
      std::forward<ReducerT>(reducer),
      std::forward<StateT>(state),
      std::forward<InputRangeTs>(ranges)...));
}

} // namespace xform
} // namespace atria
<commit_msg>xform: reduce with `for` loop instead of `while` loop<commit_after>// Copyright: 2014, 2015, Ableton AG, Berlin. All rights reserved.

#pragma once

#include <atria/xform/functional.hpp>
#include <atria/xform/state.hpp>

#include <atria/estd/type_traits.hpp>
#include <atria/estd/utility.hpp>

#include <algorithm>
#include <numeric>
#include <tuple>

//!
// When defined to 1, std::accumulate will be used as an
// implementation for reduce() over one single collection.  In that
// case, halting reducers (e.g. take) might not work.
//
#ifndef ABL_REDUCE_WITH_ACCUMULATE
#define ABL_REDUCE_WITH_ACCUMULATE 0
#endif

//!
// When defined to 1, reduce will be defined separately for the
// non-variadic version.
//
#ifndef ABL_REDUCE_NON_VARIADIC
#define ABL_REDUCE_NON_VARIADIC 1
#endif

namespace atria {
namespace xform {

namespace detail {

template <typename ReducerT,
          typename StateT,
          typename InputRangeT>
auto reduce_nested_accumulate(ReducerT&& reducer, StateT&& state, InputRangeT&& range)
  -> estd::decay_t<StateT>
{
  return std::accumulate(
    std::begin(range),
    std::end(range),
    std::forward<StateT>(state),
    std::forward<ReducerT>(reducer));
}

template <typename ReducerT,
          typename StateT,
          typename InputRangeT>
auto reduce_nested_non_variadic(ReducerT&& reducer,
                                StateT&& initial,
                                InputRangeT&& range)
  -> estd::decay_t<decltype(reducer(initial, *std::begin(range)))>
{
  using result_t = estd::decay_t<decltype(reducer(initial, *std::begin(range)))>;

  auto first = std::begin(range);
  auto last  = std::end(range);
  if (first != last) {
    auto state = reducer(std::forward<StateT>(initial), *first);
    // This may be expressed more brief with a:
    //    while(++first != last)
    // but the for loop seems to make compilers generate better code.
    for (++first; !state_is_reduced(state) && first != last; ++first) {
      state = reducer(std::move(state), *first);
    }
    return state;
  }

  return result_t { initial };
}

template <typename ReducerT,
          typename StateT,
          std::size_t ...Indices,
          typename ...InputRangeTs>
auto reduce_nested_variadic_impl(ReducerT&& reducer,
                                 StateT&& initial,
                                 estd::index_sequence<Indices...>,
                                 InputRangeTs&& ...ranges)
  -> estd::decay_t<decltype(reducer(initial, *std::begin(ranges)...))>
{
  using result_t = estd::decay_t<decltype(
    reducer(initial, *std::begin(ranges)...))>;

  auto firsts = std::make_tuple(std::begin(ranges)...);
  auto lasts  = std::make_tuple(std::end(ranges)...);
  if (std::min({std::get<Indices>(firsts) !=
                std::get<Indices>(lasts)...}))
  {
    auto state = reducer(std::forward<StateT>(initial),
                         *std::get<Indices>(firsts)...);
    while (!state_is_reduced(state)
           && std::min({ ++std::get<Indices>(firsts) !=
                         std::get<Indices>(lasts)... })) {
      state = reducer(std::move(state), *std::get<Indices>(firsts)...);
    }
    return state;
  }

  return result_t { initial };
}

template <typename ReducerT,
          typename StateT,
          typename ...InputRangeTs>
auto reduce_nested_variadic(ReducerT&& reducer, StateT&& state, InputRangeTs&& ...ranges)
  -> decltype(detail::reduce_nested_variadic_impl(
                std::forward<ReducerT>(reducer),
                std::forward<StateT>(state),
                estd::make_index_sequence<sizeof...(InputRangeTs)> {},
                std::forward<InputRangeTs>(ranges)...))
{
  return detail::reduce_nested_variadic_impl(
    std::forward<ReducerT>(reducer),
    std::forward<StateT>(state),
    estd::make_index_sequence<sizeof...(InputRangeTs)> {},
    std::forward<InputRangeTs>(ranges)...);
}

} // namespace detail

#if ABL_REDUCE_WITH_ACCUMULATE
#  define ABL_REDUCE_NESTED_NON_VARIADIC_IMPL \
  ::atria::xform::detail::reduce_nested_accumulate
#elif ABL_REDUCE_NON_VARIADIC
#  define ABL_REDUCE_NESTED_NON_VARIADIC_IMPL \
  ::atria::xform::detail::reduce_nested_non_variadic
#else
#  define ABL_REDUCE_NESTED_NON_VARIADIC_IMPL \
  ::atria::xform::detail::reduce_nested_variadic
#endif

//!
// Similar to @a reduce, but does not unwrap `reduced` values.  This is
// useful when calling reduce recursively inside a transducer.
// @see take
//
template <typename ReducerT,
          typename StateT,
          typename InputRangeT>
auto reduce_nested(ReducerT&& reducer, StateT&& state, InputRangeT&& range)
  -> decltype(ABL_REDUCE_NESTED_NON_VARIADIC_IMPL(
                std::forward<ReducerT>(reducer),
                std::forward<StateT>(state),
                std::forward<InputRangeT>(range)))
{
  return ABL_REDUCE_NESTED_NON_VARIADIC_IMPL(
    std::forward<ReducerT>(reducer),
    std::forward<StateT>(state),
    std::forward<InputRangeT>(range));
}

template <typename ReducerT,
          typename StateT,
          typename InputRangeT,
          typename ...InputRangeTs>
auto reduce_nested(ReducerT&& reducer, StateT&& state, InputRangeT&& range,
                   InputRangeTs&& ...ranges)
  -> decltype(detail::reduce_nested_variadic(
                std::forward<ReducerT>(reducer),
                std::forward<StateT>(state),
                std::forward<InputRangeT>(range),
                std::forward<InputRangeTs>(ranges)...))
{
  return detail::reduce_nested_variadic(
    std::forward<ReducerT>(reducer),
    std::forward<StateT>(state),
    std::forward<InputRangeT>(range),
    std::forward<InputRangeTs>(ranges)...);
}

//!
// Similar to clojure.core/reduce.  Unlike `std::accumulate`, this
// reduces over a range (doesn't take to distinct iterators) and can
// reduce over several ranges at the same time.  It also supports
// early termination for transducers.
//
template <typename ReducerT,
          typename StateT,
          typename ...InputRangeTs>
auto reduce(ReducerT&& reducer, StateT&& state, InputRangeTs&& ...ranges)
  -> estd::decay_t<StateT>
{
  return state_complete(
    reduce_nested(
      std::forward<ReducerT>(reducer),
      std::forward<StateT>(state),
      std::forward<InputRangeTs>(ranges)...));
}

} // namespace xform
} // namespace atria
<|endoftext|>


<commit_before>#include "OS.h"
#include "Log.h"
//#include <cstdio>
#include <stdexcept>
#include <X11/Xlib.h>
#include <X11/cursorfont.h>
#include <X11/extensions/xf86vmode.h>
#include <GL/glx.h>
//#include <GL/glu.h>

static Display*             dpy;
static Window                   win;
static Window                   root;
static GLXFBConfig*         fbConfigs;
static GLXContext               ctx;
static XVisualInfo*         vi;
static Colormap             cmap;
static XSetWindowAttributes swa;
static XF86VidModeModeInfo **vidmodes;
static Atom                     wm_delete_window;
static Atom                     fullScreen;
static Atom                     wmState;
Cursor                          default_cursor = 0;
Cursor                          no_cursor = 0;

GLXDrawable glx_drawable;

enum
{
  _NET_WM_STATE_REMOVE =0,
  _NET_WM_STATE_ADD = 1,
  _NET_WM_STATE_TOGGLE =2

};

int doubleBufferAttributes[] = {
    GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
    GLX_RENDER_TYPE,
    GLX_RGBA_BIT,
    GLX_DOUBLEBUFFER,  True,
    GLX_RED_SIZE,      1,
    GLX_BLUE_SIZE,     1,
    None
};

void OS::init_view(int width, int height, bool fullscreen){
    dpy = XOpenDisplay(NULL);

    if( !dpy ) {
    	throw std::runtime_error("Could not connect to an X server\n");
    }

    root = DefaultRootWindow(dpy);

    int numReturned = 0;
    fbConfigs = glXChooseFBConfig( dpy, DefaultScreen(dpy), doubleBufferAttributes, &numReturned );

    if ( !fbConfigs ) {
    	throw std::runtime_error( "No double buffered config available\n" );
    }

    vi = glXGetVisualFromFBConfig(dpy, fbConfigs[0]);

    if( !vi ) {
    	throw std::runtime_error("No appropriate visual found\n");
    }

    unsigned long mask = CWColormap | CWEventMask;

    if ( fullscreen ){
    	Log::message(Log::Verbose, "Graphics: Going fullscreen\n");
    	width = DisplayWidth(dpy, DefaultScreen(dpy));
    	height = DisplayHeight(dpy, DefaultScreen(dpy));
    }

    cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);
    swa.colormap = cmap;
    swa.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask ;

    win = XCreateWindow(dpy, root, 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, mask, &swa);

    XStoreName(dpy, win, "Slideshow");

    XMapWindow(dpy, win);

    ctx = glXCreateContext(dpy, vi, NULL, GL_TRUE);
    glXMakeCurrent(dpy, win, ctx);

    wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", 0);
    fullScreen = XInternAtom(dpy,"_NET_WM_STATE_FULLSCREEN", False);
    wmState = XInternAtom(dpy, "_NET_WM_STATE", False);

    XSetWMProtocols(dpy, win, &wm_delete_window, 1);

    Pixmap blank;
    XColor dummy;
    char data[1] = {0};
    //Cursor cursor;

    /* make a blank cursor */
    blank = XCreateBitmapFromData (dpy, win, data, 1, 1);
    //if(blank == None) fprintf(stderr, "error: out of memory.\n");
    no_cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0);
    XFreePixmap (dpy, blank);

    default_cursor = XCreateFontCursor(dpy, XC_left_ptr);

    /*XGrabPointer(dpy, win,
             True,
             0,
             GrabModeAsync, GrabModeAsync,
             win,
             cursor,
             CurrentTime);*/

             //lockAndHideMouse(true);

    if ( fullscreen ){
        XEvent xev;
        xev.xclient.type=ClientMessage;
        xev.xclient.serial = 0;
        xev.xclient.send_event=True;
        xev.xclient.window=win;
        xev.xclient.message_type=wmState;
        xev.xclient.format=32;
        xev.xclient.data.l[0] = (_NET_WM_STATE_ADD);
        xev.xclient.data.l[1] = fullScreen;
        xev.xclient.data.l[2] = 0;

        XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureRedirectMask | SubstructureNotifyMask,&xev);
    }

    glx_drawable = glXGetCurrentDrawable();
}

void OS::swap_gl_buffers(){
    glXSwapBuffers(dpy, glx_drawable);
}

void OS::cleanup(){
	glXDestroyContext(dpy, ctx);

    if( win && dpy ){
        XDestroyWindow( dpy, win );
        win = (Window) 0;
    }

    if ( dpy )
    {
        XCloseDisplay( dpy );
        dpy = 0;
    }

}

void OS::poll_events(bool& running){
    XEvent event;

    while ( XPending(dpy) > 0 ){
        XNextEvent(dpy, &event);
        switch (event.type){
            case KeyPress:
                if ( event.xkey.state == 24 && event.xkey.keycode == 36 ){
                    XEvent xev;
                    xev.xclient.type=ClientMessage;
                    xev.xclient.serial = 0;
                    xev.xclient.send_event=True;
                    xev.xclient.window=win;
                    xev.xclient.message_type=wmState;
                    xev.xclient.format=32;
                    xev.xclient.data.l[0] = (_NET_WM_STATE_TOGGLE);
                    xev.xclient.data.l[1] = fullScreen;
                    xev.xclient.data.l[2] = 0;

                    XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureRedirectMask | SubstructureNotifyMask,&xev);

                    continue;
                }

                if ( event.xkey.keycode == 9 ){
                	running = false;

                	continue;
                }

                break;

            case ClientMessage:
                if( (unsigned int)event.xclient.data.l[0] == wm_delete_window ){
                	running = false;
                	continue;
                }
                break;
        }
    }
}
<commit_msg>Hiding mouse cursor<commit_after>#include "OS.h"
#include "Log.h"
//#include <cstdio>
#include <stdexcept>
#include <X11/Xlib.h>
#include <X11/cursorfont.h>
#include <X11/extensions/xf86vmode.h>
#include <GL/glx.h>
//#include <GL/glu.h>

static Display*             dpy;
static Window                   win;
static Window                   root;
static GLXFBConfig*         fbConfigs;
static GLXContext               ctx;
static XVisualInfo*         vi;
static Colormap             cmap;
static XSetWindowAttributes swa;
static XF86VidModeModeInfo **vidmodes;
static Atom                     wm_delete_window;
static Atom                     fullScreen;
static Atom                     wmState;
Cursor                          default_cursor = 0;
Cursor                          no_cursor = 0;

GLXDrawable glx_drawable;

enum
{
  _NET_WM_STATE_REMOVE =0,
  _NET_WM_STATE_ADD = 1,
  _NET_WM_STATE_TOGGLE =2

};

int doubleBufferAttributes[] = {
    GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
    GLX_RENDER_TYPE,
    GLX_RGBA_BIT,
    GLX_DOUBLEBUFFER,  True,
    GLX_RED_SIZE,      1,
    GLX_BLUE_SIZE,     1,
    None
};

void OS::init_view(int width, int height, bool fullscreen){
    dpy = XOpenDisplay(NULL);

    if( !dpy ) {
    	throw std::runtime_error("Could not connect to an X server\n");
    }

    root = DefaultRootWindow(dpy);

    int numReturned = 0;
    fbConfigs = glXChooseFBConfig( dpy, DefaultScreen(dpy), doubleBufferAttributes, &numReturned );

    if ( !fbConfigs ) {
    	throw std::runtime_error( "No double buffered config available\n" );
    }

    vi = glXGetVisualFromFBConfig(dpy, fbConfigs[0]);

    if( !vi ) {
    	throw std::runtime_error("No appropriate visual found\n");
    }

    unsigned long mask = CWColormap | CWEventMask;

    if ( fullscreen ){
    	Log::message(Log::Verbose, "Graphics: Going fullscreen\n");
    	width = DisplayWidth(dpy, DefaultScreen(dpy));
    	height = DisplayHeight(dpy, DefaultScreen(dpy));
    }

    cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);
    swa.colormap = cmap;
    swa.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask ;

    win = XCreateWindow(dpy, root, 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, mask, &swa);

    XStoreName(dpy, win, "Slideshow");

    XMapWindow(dpy, win);

    ctx = glXCreateContext(dpy, vi, NULL, GL_TRUE);
    glXMakeCurrent(dpy, win, ctx);

    wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", 0);
    fullScreen = XInternAtom(dpy,"_NET_WM_STATE_FULLSCREEN", False);
    wmState = XInternAtom(dpy, "_NET_WM_STATE", False);

    XSetWMProtocols(dpy, win, &wm_delete_window, 1);

    Pixmap blank;
    XColor dummy;
    char data[1] = {0};
    //Cursor cursor;

    /* make a blank cursor */
    blank = XCreateBitmapFromData (dpy, win, data, 1, 1);
    //if(blank == None) fprintf(stderr, "error: out of memory.\n");
    no_cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0);
    XFreePixmap (dpy, blank);

    default_cursor = XCreateFontCursor(dpy, XC_left_ptr);

    /*XGrabPointer(dpy, win,
             True,
             0,
             GrabModeAsync, GrabModeAsync,
             win,
             cursor,
             CurrentTime);*/

    XDefineCursor(dpy, win, no_cursor);

    if ( fullscreen ){
        XEvent xev;
        xev.xclient.type=ClientMessage;
        xev.xclient.serial = 0;
        xev.xclient.send_event=True;
        xev.xclient.window=win;
        xev.xclient.message_type=wmState;
        xev.xclient.format=32;
        xev.xclient.data.l[0] = (_NET_WM_STATE_ADD);
        xev.xclient.data.l[1] = fullScreen;
        xev.xclient.data.l[2] = 0;

        XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureRedirectMask | SubstructureNotifyMask,&xev);
    }

    glx_drawable = glXGetCurrentDrawable();
}

void OS::swap_gl_buffers(){
    glXSwapBuffers(dpy, glx_drawable);
}

void OS::cleanup(){
  XDefineCursor(dpy, win, default_cursor);
  glXDestroyContext(dpy, ctx);

  if( win && dpy ){
    XDestroyWindow( dpy, win );
    win = (Window) 0;
  }

  if ( dpy ){
    XCloseDisplay( dpy );
    dpy = 0;
  }
}

void OS::poll_events(bool& running){
    XEvent event;

    while ( XPending(dpy) > 0 ){
        XNextEvent(dpy, &event);
        switch (event.type){
            case KeyPress:
                if ( event.xkey.state == 24 && event.xkey.keycode == 36 ){
                    XEvent xev;
                    xev.xclient.type=ClientMessage;
                    xev.xclient.serial = 0;
                    xev.xclient.send_event=True;
                    xev.xclient.window=win;
                    xev.xclient.message_type=wmState;
                    xev.xclient.format=32;
                    xev.xclient.data.l[0] = (_NET_WM_STATE_TOGGLE);
                    xev.xclient.data.l[1] = fullScreen;
                    xev.xclient.data.l[2] = 0;

                    XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureRedirectMask | SubstructureNotifyMask,&xev);

                    continue;
                }

                if ( event.xkey.keycode == 9 ){
                	running = false;

                	continue;
                }

                break;

            case ClientMessage:
                if( (unsigned int)event.xclient.data.l[0] == wm_delete_window ){
                	running = false;
                	continue;
                }
                break;
        }
    }
}
<|endoftext|>


<commit_before>#include "routing/vehicle_model.hpp"

#include "indexer/classificator.hpp"
#include "indexer/feature.hpp"
#include "indexer/ftypes_matcher.hpp"

#include "base/macros.hpp"

#include "std/limits.hpp"
#include "std/initializer_list.hpp"

namespace routing
{

VehicleModel::InitListT const s_carLimits =
{
  { {"highway", "motorway"},       90 },
  { {"highway", "trunk"},          85 },
  { {"highway", "motorway_link"},  75 },
  { {"highway", "trunk_link"},     70 },
  { {"highway", "primary"},        65 },
  { {"highway", "primary_link"},   60 },
  { {"highway", "secondary"},      55 },
  { {"highway", "secondary_link"}, 50 },
  { {"highway", "tertiary"},       40 },
  { {"highway", "tertiary_link"},  30 },
  { {"highway", "residential"},    25 },
  { {"highway", "pedestrian"},     25 },
  { {"highway", "unclassified"},   25 },
  { {"highway", "service"},        15 },
  { {"highway", "living_street"},  10 },
  { {"highway", "road"},           10 },
  { {"highway", "track"},          5  },
  /// @todo: Add to classificator
  //{ {"highway", "shuttle_train"},  10 },
  //{ {"highway", "ferry"},          5  },
  //{ {"highway", "default"},        10 },
  /// @todo: Check type
  //{ {"highway", "construction"},   40 },
};

static int const kPedestrianSpeedVerySlowKMpH = 2;
static int const kPedestrianSpeedSlowKMpH = 3;
static int const kPedestrianSpeedBelowNormalKMpH = 4;
static int const kPedestrianSpeedNormalKMpH = 5;

VehicleModel::InitListT const s_pedestrianLimits =
{
  // see road pictures here - http://wiki.openstreetmap.org/wiki/Key:highway
  { {"highway", "motorway"},       kPedestrianSpeedVerySlowKMpH },
  { {"highway", "trunk"},          kPedestrianSpeedSlowKMpH },
  { {"highway", "motorway_link"},  kPedestrianSpeedVerySlowKMpH },
  { {"highway", "trunk_link"},     kPedestrianSpeedSlowKMpH },
  { {"highway", "primary"},        kPedestrianSpeedSlowKMpH },
  { {"highway", "primary_link"},   kPedestrianSpeedSlowKMpH },
  { {"highway", "secondary"},      kPedestrianSpeedSlowKMpH },
  { {"highway", "secondary_link"}, kPedestrianSpeedSlowKMpH },
  { {"highway", "tertiary"},       kPedestrianSpeedSlowKMpH },
  { {"highway", "tertiary_link"},  kPedestrianSpeedSlowKMpH },
  { {"highway", "residential"},    kPedestrianSpeedBelowNormalKMpH },
  { {"highway", "pedestrian"},     kPedestrianSpeedNormalKMpH },
  { {"highway", "unclassified"},   kPedestrianSpeedBelowNormalKMpH },
  { {"highway", "service"},        kPedestrianSpeedSlowKMpH },
  { {"highway", "living_street"},  kPedestrianSpeedNormalKMpH },
  { {"highway", "road"},           kPedestrianSpeedBelowNormalKMpH },
  { {"highway", "track"},          kPedestrianSpeedBelowNormalKMpH },
  { {"highway", "path"},           kPedestrianSpeedBelowNormalKMpH },
  { {"highway", "steps"},          kPedestrianSpeedBelowNormalKMpH },
  { {"highway", "pedestrian"},     kPedestrianSpeedNormalKMpH },
  { {"highway", "footway"},        kPedestrianSpeedNormalKMpH },
  // all other are restricted
};

VehicleModel::VehicleModel(Classificator const & c, VehicleModel::InitListT const & speedLimits)
  : m_maxSpeedKMpH(0),
    m_onewayType(c.GetTypeByPath({ "hwtag", "oneway" }))
{
  for (auto const & v : speedLimits)
  {
    m_maxSpeedKMpH = max(m_maxSpeedKMpH, v.m_speedKMpH);
    m_types[c.GetTypeByPath(vector<string>(v.m_types, v.m_types + 2))] = v.m_speedKMpH;
  }
}

void VehicleModel::SetAdditionalRoadTypes(Classificator const & c,
                                          initializer_list<char const *> const * arr, size_t sz)
{
  for (size_t i = 0; i < sz; ++i)
    m_addRoadTypes.push_back(c.GetTypeByPath(arr[i]));
}

double VehicleModel::GetSpeed(FeatureType const & f) const
{
  return GetSpeed(feature::TypesHolder(f));
}

double VehicleModel::GetSpeed(feature::TypesHolder const & types) const
{
  double speed = m_maxSpeedKMpH * 2;
  for (uint32_t t : types)
  {
    uint32_t const type = ftypes::BaseChecker::PrepareToMatch(t, 2);
    auto it = m_types.find(type);
    if (it != m_types.end())
      speed = min(speed, it->second);
  }
  if (speed <= m_maxSpeedKMpH)
    return speed;

  return 0.0;
}

bool VehicleModel::IsOneWay(FeatureType const & f) const
{
  return IsOneWay(feature::TypesHolder(f));
}

bool VehicleModel::IsOneWay(feature::TypesHolder const & types) const
{
  return types.Has(m_onewayType);
}

bool VehicleModel::IsRoad(FeatureType const & f) const
{
  return IsRoad(feature::TypesHolder(f));
}

bool VehicleModel::IsRoad(uint32_t type) const
{
  return find(m_addRoadTypes.begin(), m_addRoadTypes.end(), type) != m_addRoadTypes.end() ||
         m_types.find(ftypes::BaseChecker::PrepareToMatch(type, 2)) != m_types.end();
}

CarModel::CarModel()
  : VehicleModel(classif(), s_carLimits)
{
  initializer_list<char const *> arr[] =
  {
    { "route", "ferry", "motorcar" },
    { "route", "ferry", "motor_vehicle" },
    { "railway", "rail", "motor_vehicle" },
  };

  SetAdditionalRoadTypes(classif(), arr, ARRAY_SIZE(arr));
}

PedestrianModel::PedestrianModel()
  : VehicleModel(classif(), s_pedestrianLimits),
    m_noFootType(classif().GetTypeByPath({ "hwtag", "nofoot" }))
{
  initializer_list<char const *> arr[] =
  {
    { "route", "ferry" },
    { "man_made", "pier" },
  };

  SetAdditionalRoadTypes(classif(), arr, ARRAY_SIZE(arr));
}

bool PedestrianModel::IsFoot(feature::TypesHolder const & types) const
{
  return find(types.begin(), types.end(), m_noFootType) == types.end();
}

double PedestrianModel::GetSpeed(FeatureType const & f) const
{
  feature::TypesHolder types(f);

  if (IsFoot(types) && IsRoad(types))
    return VehicleModel::GetSpeed(f);
  else
    return 0.0;
}

}  // namespace routing
<commit_msg>Updated table of pedestrian speed by road type<commit_after>#include "routing/vehicle_model.hpp"

#include "indexer/classificator.hpp"
#include "indexer/feature.hpp"
#include "indexer/ftypes_matcher.hpp"

#include "base/macros.hpp"

#include "std/limits.hpp"
#include "std/initializer_list.hpp"

namespace routing
{

VehicleModel::InitListT const s_carLimits =
{
  { {"highway", "motorway"},       90 },
  { {"highway", "trunk"},          85 },
  { {"highway", "motorway_link"},  75 },
  { {"highway", "trunk_link"},     70 },
  { {"highway", "primary"},        65 },
  { {"highway", "primary_link"},   60 },
  { {"highway", "secondary"},      55 },
  { {"highway", "secondary_link"}, 50 },
  { {"highway", "tertiary"},       40 },
  { {"highway", "tertiary_link"},  30 },
  { {"highway", "residential"},    25 },
  { {"highway", "pedestrian"},     25 },
  { {"highway", "unclassified"},   25 },
  { {"highway", "service"},        15 },
  { {"highway", "living_street"},  10 },
  { {"highway", "road"},           10 },
  { {"highway", "track"},          5  },
  /// @todo: Add to classificator
  //{ {"highway", "shuttle_train"},  10 },
  //{ {"highway", "ferry"},          5  },
  //{ {"highway", "default"},        10 },
  /// @todo: Check type
  //{ {"highway", "construction"},   40 },
};

static double const kPedestrianSpeedVerySlowKMpH = 4.25;
static double const kPedestrianSpeedSlowKMpH = 4.5;
static double const kPedestrianSpeedBelowNormalKMpH = 5;
static double const kPedestrianSpeedNormalKMpH = 5;

VehicleModel::InitListT const s_pedestrianLimits =
{
  // see road pictures here - http://wiki.openstreetmap.org/wiki/Key:highway
  { {"highway", "motorway"},       kPedestrianSpeedVerySlowKMpH },
  { {"highway", "trunk"},          kPedestrianSpeedVerySlowKMpH },
  { {"highway", "motorway_link"},  kPedestrianSpeedVerySlowKMpH },
  { {"highway", "trunk_link"},     kPedestrianSpeedVerySlowKMpH },
  { {"highway", "primary"},        kPedestrianSpeedSlowKMpH },
  { {"highway", "primary_link"},   kPedestrianSpeedSlowKMpH },
  { {"highway", "secondary"},      kPedestrianSpeedSlowKMpH },
  { {"highway", "secondary_link"}, kPedestrianSpeedSlowKMpH },
  { {"highway", "tertiary"},       kPedestrianSpeedSlowKMpH },
  { {"highway", "tertiary_link"},  kPedestrianSpeedSlowKMpH },
  { {"highway", "service"},        kPedestrianSpeedSlowKMpH },
  { {"highway", "unclassified"},   kPedestrianSpeedBelowNormalKMpH },
  { {"highway", "road"},           kPedestrianSpeedBelowNormalKMpH },
  { {"highway", "track"},          kPedestrianSpeedBelowNormalKMpH },
  { {"highway", "path"},           kPedestrianSpeedBelowNormalKMpH },
  { {"highway", "residential"},    kPedestrianSpeedNormalKMpH },
  { {"highway", "living_street"},  kPedestrianSpeedNormalKMpH },
  { {"highway", "steps"},          kPedestrianSpeedNormalKMpH },
  { {"highway", "pedestrian"},     kPedestrianSpeedNormalKMpH },
  { {"highway", "footway"},        kPedestrianSpeedNormalKMpH },
  // all other are restricted
};

VehicleModel::VehicleModel(Classificator const & c, VehicleModel::InitListT const & speedLimits)
  : m_maxSpeedKMpH(0),
    m_onewayType(c.GetTypeByPath({ "hwtag", "oneway" }))
{
  for (auto const & v : speedLimits)
  {
    m_maxSpeedKMpH = max(m_maxSpeedKMpH, v.m_speedKMpH);
    m_types[c.GetTypeByPath(vector<string>(v.m_types, v.m_types + 2))] = v.m_speedKMpH;
  }
}

void VehicleModel::SetAdditionalRoadTypes(Classificator const & c,
                                          initializer_list<char const *> const * arr, size_t sz)
{
  for (size_t i = 0; i < sz; ++i)
    m_addRoadTypes.push_back(c.GetTypeByPath(arr[i]));
}

double VehicleModel::GetSpeed(FeatureType const & f) const
{
  return GetSpeed(feature::TypesHolder(f));
}

double VehicleModel::GetSpeed(feature::TypesHolder const & types) const
{
  double speed = m_maxSpeedKMpH * 2;
  for (uint32_t t : types)
  {
    uint32_t const type = ftypes::BaseChecker::PrepareToMatch(t, 2);
    auto it = m_types.find(type);
    if (it != m_types.end())
      speed = min(speed, it->second);
  }
  if (speed <= m_maxSpeedKMpH)
    return speed;

  return 0.0;
}

bool VehicleModel::IsOneWay(FeatureType const & f) const
{
  return IsOneWay(feature::TypesHolder(f));
}

bool VehicleModel::IsOneWay(feature::TypesHolder const & types) const
{
  return types.Has(m_onewayType);
}

bool VehicleModel::IsRoad(FeatureType const & f) const
{
  return IsRoad(feature::TypesHolder(f));
}

bool VehicleModel::IsRoad(uint32_t type) const
{
  return find(m_addRoadTypes.begin(), m_addRoadTypes.end(), type) != m_addRoadTypes.end() ||
         m_types.find(ftypes::BaseChecker::PrepareToMatch(type, 2)) != m_types.end();
}

CarModel::CarModel()
  : VehicleModel(classif(), s_carLimits)
{
  initializer_list<char const *> arr[] =
  {
    { "route", "ferry", "motorcar" },
    { "route", "ferry", "motor_vehicle" },
    { "railway", "rail", "motor_vehicle" },
  };

  SetAdditionalRoadTypes(classif(), arr, ARRAY_SIZE(arr));
}

PedestrianModel::PedestrianModel()
  : VehicleModel(classif(), s_pedestrianLimits),
    m_noFootType(classif().GetTypeByPath({ "hwtag", "nofoot" }))
{
  initializer_list<char const *> arr[] =
  {
    { "route", "ferry" },
    { "man_made", "pier" },
  };

  SetAdditionalRoadTypes(classif(), arr, ARRAY_SIZE(arr));
}

bool PedestrianModel::IsFoot(feature::TypesHolder const & types) const
{
  return find(types.begin(), types.end(), m_noFootType) == types.end();
}

double PedestrianModel::GetSpeed(FeatureType const & f) const
{
  feature::TypesHolder types(f);

  if (IsFoot(types) && IsRoad(types))
    return VehicleModel::GetSpeed(f);
  else
    return 0.0;
}

}  // namespace routing
<|endoftext|>


<commit_before>// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include <bin/elf_loader.h>
#include <bin/file.h>
#include <platform/elf.h>
#include <platform/globals.h>
#include <vm/cpu.h>
#include <vm/virtual_memory.h>

#include <memory>

namespace dart {
namespace bin {

namespace elf {

/// A loader for a subset of ELF which may be used to load objects produced by
/// Dart_CreateAppAOTSnapshotAsElf.
class LoadedElf {
 public:
  explicit LoadedElf(const char* filename)
      : filename_(strdup(filename), std::free) {}
  ~LoadedElf();

  /// Loads the ELF object into memory. Returns whether the load was successful.
  /// On failure, the error may be retrieved by 'error()'.
  bool Load();

  /// Reads Dart-specific symbols from the loaded ELF.
  ///
  /// Stores the address of the corresponding symbol in each non-null output
  /// parameter.
  ///
  /// Fails if any output parameter is non-null but points to null and the
  /// corresponding symbol was not found, or if the dynamic symbol table could
  /// not be decoded.
  ///
  /// On failure, the error may be retrieved by 'error()'.
  bool ResolveSymbols(const uint8_t** vm_data,
                      const uint8_t** vm_instrs,
                      const uint8_t** isolate_data,
                      const uint8_t** isolate_instrs);

  const char* error() { return error_; }

 private:
  bool ReadHeader();
  bool ReadProgramTable();
  bool LoadSegments();
  bool ReadSectionTable();
  bool ReadSectionStringTable();
  bool ReadSections();

  static uword PageSize() { return VirtualMemory::PageSize(); }

  // Unlike File::Map, allows non-aligned 'start' and 'length'.
  MappedMemory* MapFilePiece(uword start,
                             uword length,
                             const void** mapping_start);

  std::unique_ptr<char, decltype(std::free)*> filename_;

  // Initialized on a successful Load().
  File* file_;

  // Initialized on error.
  const char* error_ = nullptr;

  // Initialized by ReadHeader().
  dart::elf::ElfHeader header_;

  // Initialized by ReadProgramTable().
  std::unique_ptr<MappedMemory> program_table_mapping_;
  const dart::elf::ProgramHeader* program_table_ = nullptr;

  // Initialized by LoadSegments().
  std::unique_ptr<VirtualMemory> base_;

  // Initialized by ReadSectionTable().
  std::unique_ptr<MappedMemory> section_table_mapping_;
  const dart::elf::SectionHeader* section_table_ = nullptr;

  // Initialized by ReadSectionStringTable().
  std::unique_ptr<MappedMemory> section_string_table_mapping_;
  const char* section_string_table_ = nullptr;

  // Initialized by ReadSections().
  const char* dynamic_string_table_ = nullptr;
  const dart::elf::Symbol* dynamic_symbol_table_ = nullptr;
  uword dynamic_symbol_count_ = 0;

  DISALLOW_COPY_AND_ASSIGN(LoadedElf);
};

#define CHECK(value)                                                           \
  if (!(value)) {                                                              \
    ASSERT(error_ != nullptr);                                                 \
    return false;                                                              \
  }

#define ERROR(message)                                                         \
  {                                                                            \
    error_ = (message);                                                        \
    return false;                                                              \
  }

#define CHECK_ERROR(value, message)                                            \
  if (!(value)) {                                                              \
    error_ = (message);                                                        \
    return false;                                                              \
  }

bool LoadedElf::Load() {
  VirtualMemory::Init();

  if (error_ != nullptr) {
    return false;
  }

  file_ = File::Open(/*namespc=*/nullptr, filename_.get(),
                     bin::File::FileOpenMode::kRead);
  CHECK_ERROR(file_ != nullptr, "Cannot open ELF object file.");

  CHECK(ReadHeader());
  CHECK(ReadProgramTable());
  CHECK(LoadSegments());
  CHECK(ReadSectionTable());
  CHECK(ReadSectionStringTable());
  CHECK(ReadSections());

  return true;
}

LoadedElf::~LoadedElf() {
  // Unmap the image.
  base_.reset();

  // Explicitly destroy all the mappings before closing the file.
  program_table_mapping_.reset();
  section_table_mapping_.reset();
  section_string_table_mapping_.reset();

  if (file_ != nullptr) {
    file_->Close();
    file_->Release();
  }
}

bool LoadedElf::ReadHeader() {
  CHECK_ERROR(file_->ReadFully(&header_, sizeof(dart::elf::ElfHeader)),
              "Could not read ELF file.");

  CHECK_ERROR(header_.ident[dart::elf::EI_DATA] == dart::elf::ELFDATA2LSB,
              "Expected little-endian ELF object.");

  CHECK_ERROR(header_.type == dart::elf::ET_DYN,
              "Can only load dynamic libraries.");

#if defined(TARGET_ARCH_IA32)
  CHECK_ERROR(header_.machine == dart::elf::EM_386, "Architecture mismatch.");
#elif defined(TARGET_ARCH_X64)
  CHECK_ERROR(header_.machine == dart::elf::EM_X86_64,
              "Architecture mismatch.");
#elif defined(TARGET_ARCH_ARM)
  CHECK_ERROR(header_.machine == dart::elf::EM_ARM, "Architecture mismatch.");
#elif defined(TARGET_ARCH_ARM64)
  CHECK_ERROR(header_.machine == dart::elf::EM_AARCH64,
              "Architecture mismatch.");
#else
#error Unsupported architecture architecture.
#endif

  CHECK_ERROR(header_.version == dart::elf::EV_CURRENT,
              "Unexpected ELF version.");
  CHECK_ERROR(header_.header_size == sizeof(dart::elf::ElfHeader),
              "Unexpected header size.");
  CHECK_ERROR(
      header_.program_table_entry_size == sizeof(dart::elf::ProgramHeader),
      "Unexpected program header size.");
  CHECK_ERROR(
      header_.section_table_entry_size == sizeof(dart::elf::SectionHeader),
      "Unexpected section header size.");

  return true;
}

bool LoadedElf::ReadProgramTable() {
  const uword file_start = header_.program_table_offset;
  const uword file_length =
      header_.num_program_headers * sizeof(dart::elf::ProgramHeader);
  program_table_mapping_.reset(
      MapFilePiece(file_start, file_length,
                   reinterpret_cast<const void**>(&program_table_)));
  CHECK_ERROR(program_table_mapping_ != nullptr,
              "Could not mmap the program table.");
  return true;
}

bool LoadedElf::ReadSectionTable() {
  const uword file_start = header_.section_table_offset;
  const uword file_length =
      header_.num_section_headers * sizeof(dart::elf::SectionHeader);
  section_table_mapping_.reset(
      MapFilePiece(file_start, file_length,
                   reinterpret_cast<const void**>(&section_table_)));
  CHECK_ERROR(section_table_mapping_ != nullptr,
              "Could not mmap the section table.");
  return true;
}

bool LoadedElf::ReadSectionStringTable() {
  const dart::elf::SectionHeader header =
      section_table_[header_.shstrtab_section_index];
  section_string_table_mapping_.reset(
      MapFilePiece(header.file_offset, header.file_size,
                   reinterpret_cast<const void**>(&section_string_table_)));
  CHECK_ERROR(section_string_table_mapping_ != nullptr,
              "Could not mmap the section string table.");
  return true;
}

bool LoadedElf::LoadSegments() {
  // Calculate the total amount of virtual memory needed.
  uword total_memory = 0;
  uword maximum_alignment = PageSize();
  for (uword i = 0; i < header_.num_program_headers; ++i) {
    const dart::elf::ProgramHeader header = program_table_[i];

    // Only PT_LOAD segments need to be loaded.
    if (header.type != dart::elf::ProgramHeaderType::PT_LOAD) continue;

    total_memory = Utils::Maximum(
        static_cast<uword>(header.memory_offset + header.memory_size),
        total_memory);
    CHECK_ERROR(Utils::IsPowerOfTwo(header.alignment),
                "Alignment must be a power of two.");
    maximum_alignment = Utils::Maximum(maximum_alignment, header.alignment);
  }
  total_memory = Utils::RoundUp(total_memory, PageSize());

  base_.reset(VirtualMemory::AllocateAligned(
      total_memory, /*alignment=*/maximum_alignment,
      /*is_executable=*/false, /*mapping name=*/filename_.get()));
  CHECK_ERROR(base_ != nullptr, "Could not reserve virtual memory.");

  for (uword i = 0; i < header_.num_program_headers; ++i) {
    const dart::elf::ProgramHeader header = program_table_[i];

    // Only PT_LOAD segments need to be loaded.
    if (header.type != dart::elf::ProgramHeaderType::PT_LOAD) continue;

    const uword memory_offset = header.memory_offset,
                file_offset = header.file_offset;
    CHECK_ERROR(
        (memory_offset % PageSize()) == (file_offset % PageSize()),
        "Difference between file and memory offset must be page-aligned.");

    const intptr_t adjustment = header.memory_offset % PageSize();

    void* const memory_start =
        static_cast<char*>(base_->address()) + memory_offset - adjustment;
    const uword file_start = file_offset - adjustment;
    const uword length = header.memory_size + adjustment;

    File::MapType map_type = File::kReadOnly;
    if (header.flags == (dart::elf::PF_R | dart::elf::PF_W)) {
      map_type = File::kReadWrite;
    } else if (header.flags == (dart::elf::PF_R | dart::elf::PF_X)) {
      map_type = File::kReadExecute;
    } else if (header.flags == dart::elf::PF_R) {
      map_type = File::kReadOnly;
    } else {
      ERROR("Unsupported segment flag set.");
    }

    std::unique_ptr<MappedMemory> memory(
        file_->Map(map_type, file_start, length, memory_start));
    CHECK_ERROR(memory != nullptr, "Could not map segment.");
    CHECK_ERROR(memory->address() == memory_start,
                "Mapping not at requested address.");
  }

  return true;
}

bool LoadedElf::ReadSections() {
  for (uword i = 0; i < header_.num_section_headers; ++i) {
    const dart::elf::SectionHeader header = section_table_[i];
    const char* const name = section_string_table_ + header.name;
    if (strcmp(name, ".dynstr") == 0) {
      CHECK_ERROR(header.memory_offset != 0, ".dynstr must be loaded.");
      dynamic_string_table_ =
          static_cast<const char*>(base_->address()) + header.memory_offset;
    } else if (strcmp(name, ".dynsym") == 0) {
      CHECK_ERROR(header.memory_offset != 0, ".dynsym must be loaded.");
      dynamic_symbol_table_ = reinterpret_cast<const dart::elf::Symbol*>(
          base_->start() + header.memory_offset);
      dynamic_symbol_count_ = header.file_size / sizeof(dart::elf::Symbol);
    }
  }

  CHECK_ERROR(dynamic_string_table_ != nullptr, "Couldn't find .dynstr.");
  CHECK_ERROR(dynamic_symbol_table_ != nullptr, "Couldn't find .dynsym.");
  return true;
}

bool LoadedElf::ResolveSymbols(const uint8_t** vm_data,
                               const uint8_t** vm_instrs,
                               const uint8_t** isolate_data,
                               const uint8_t** isolate_instrs) {
  if (error_ != nullptr) {
    return false;
  }

  // The first entry of the symbol table is reserved.
  for (uword i = 1; i < dynamic_symbol_count_; ++i) {
    const dart::elf::Symbol sym = dynamic_symbol_table_[i];
    const char* name = dynamic_string_table_ + sym.name;
    const uint8_t** output = nullptr;

    if (strcmp(name, kVmSnapshotDataSymbolName) == 0) {
      output = vm_data;
    } else if (strcmp(name, kVmSnapshotInstructionsSymbolName) == 0) {
      output = vm_instrs;
    } else if (strcmp(name, kIsolateSnapshotDataSymbolName) == 0) {
      output = isolate_data;
    } else if (strcmp(name, kIsolateSnapshotInstructionsSymbolName) == 0) {
      output = isolate_instrs;
    }

    if (output != nullptr) {
      *output = reinterpret_cast<const uint8_t*>(base_->start() + sym.value);
    }
  }

  CHECK_ERROR(vm_data == nullptr || *vm_data != nullptr,
              "Could not find VM snapshot data.");
  CHECK_ERROR(vm_instrs == nullptr || *vm_instrs != nullptr,
              "Could not find VM snapshot instructions.");
  CHECK_ERROR(isolate_data == nullptr || *isolate_data != nullptr,
              "Could not find isolate snapshot data.");
  CHECK_ERROR(isolate_instrs == nullptr || *isolate_instrs != nullptr,
              "Could not find isolate instructions.");
  return true;
}

MappedMemory* LoadedElf::MapFilePiece(uword file_start,
                                      uword file_length,
                                      const void** mem_start) {
  const uword mapping_offset = Utils::RoundDown(file_start, PageSize());
  const uword mapping_length =
      Utils::RoundUp(file_length + file_start % PageSize(), PageSize());
  MappedMemory* const mapping =
      file_->Map(bin::File::kReadOnly, mapping_offset, mapping_length);

  if (mapping != nullptr) {
    *mem_start = reinterpret_cast<uint8_t*>(mapping->start() +
                                            (file_start % PageSize()));
  }

  return mapping;
}

}  // namespace elf
}  // namespace bin
}  // namespace dart

DART_EXPORT void* Dart_LoadELF(const char* filename,
                               const char** error,
                               const uint8_t** vm_snapshot_data,
                               const uint8_t** vm_snapshot_instrs,
                               const uint8_t** vm_isolate_data,
                               const uint8_t** vm_isolate_instrs) {
  std::unique_ptr<dart::bin::elf::LoadedElf> elf(
      new dart::bin::elf::LoadedElf(filename));

  if (!elf->Load() ||
      !elf->ResolveSymbols(vm_snapshot_data, vm_snapshot_instrs,
                           vm_isolate_data, vm_isolate_instrs)) {
    *error = elf->error();
    return nullptr;
  }

  return elf.release();
}

DART_EXPORT void Dart_UnloadELF(void* loaded) {
  delete reinterpret_cast<dart::bin::elf::LoadedElf*>(loaded);
}
<commit_msg>[vm] Fix Mac build.<commit_after>// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include <bin/elf_loader.h>
#include <bin/file.h>
#include <platform/elf.h>
#include <platform/globals.h>
#include <vm/cpu.h>
#include <vm/virtual_memory.h>

#include <memory>

namespace dart {
namespace bin {

namespace elf {

/// A loader for a subset of ELF which may be used to load objects produced by
/// Dart_CreateAppAOTSnapshotAsElf.
class LoadedElf {
 public:
  explicit LoadedElf(const char* filename)
      : filename_(strdup(filename), std::free) {}
  ~LoadedElf();

  /// Loads the ELF object into memory. Returns whether the load was successful.
  /// On failure, the error may be retrieved by 'error()'.
  bool Load();

  /// Reads Dart-specific symbols from the loaded ELF.
  ///
  /// Stores the address of the corresponding symbol in each non-null output
  /// parameter.
  ///
  /// Fails if any output parameter is non-null but points to null and the
  /// corresponding symbol was not found, or if the dynamic symbol table could
  /// not be decoded.
  ///
  /// On failure, the error may be retrieved by 'error()'.
  bool ResolveSymbols(const uint8_t** vm_data,
                      const uint8_t** vm_instrs,
                      const uint8_t** isolate_data,
                      const uint8_t** isolate_instrs);

  const char* error() { return error_; }

 private:
  bool ReadHeader();
  bool ReadProgramTable();
  bool LoadSegments();
  bool ReadSectionTable();
  bool ReadSectionStringTable();
  bool ReadSections();

  static uword PageSize() { return VirtualMemory::PageSize(); }

  // Unlike File::Map, allows non-aligned 'start' and 'length'.
  MappedMemory* MapFilePiece(uword start,
                             uword length,
                             const void** mapping_start);

  std::unique_ptr<char, decltype(std::free)*> filename_;

  // Initialized on a successful Load().
  File* file_;

  // Initialized on error.
  const char* error_ = nullptr;

  // Initialized by ReadHeader().
  dart::elf::ElfHeader header_;

  // Initialized by ReadProgramTable().
  std::unique_ptr<MappedMemory> program_table_mapping_;
  const dart::elf::ProgramHeader* program_table_ = nullptr;

  // Initialized by LoadSegments().
  std::unique_ptr<VirtualMemory> base_;

  // Initialized by ReadSectionTable().
  std::unique_ptr<MappedMemory> section_table_mapping_;
  const dart::elf::SectionHeader* section_table_ = nullptr;

  // Initialized by ReadSectionStringTable().
  std::unique_ptr<MappedMemory> section_string_table_mapping_;
  const char* section_string_table_ = nullptr;

  // Initialized by ReadSections().
  const char* dynamic_string_table_ = nullptr;
  const dart::elf::Symbol* dynamic_symbol_table_ = nullptr;
  uword dynamic_symbol_count_ = 0;

  DISALLOW_COPY_AND_ASSIGN(LoadedElf);
};

#define CHECK(value)                                                           \
  if (!(value)) {                                                              \
    ASSERT(error_ != nullptr);                                                 \
    return false;                                                              \
  }

#define ERROR(message)                                                         \
  {                                                                            \
    error_ = (message);                                                        \
    return false;                                                              \
  }

#define CHECK_ERROR(value, message)                                            \
  if (!(value)) {                                                              \
    error_ = (message);                                                        \
    return false;                                                              \
  }

bool LoadedElf::Load() {
  VirtualMemory::Init();

  if (error_ != nullptr) {
    return false;
  }

  file_ = File::Open(/*namespc=*/nullptr, filename_.get(),
                     bin::File::FileOpenMode::kRead);
  CHECK_ERROR(file_ != nullptr, "Cannot open ELF object file.");

  CHECK(ReadHeader());
  CHECK(ReadProgramTable());
  CHECK(LoadSegments());
  CHECK(ReadSectionTable());
  CHECK(ReadSectionStringTable());
  CHECK(ReadSections());

  return true;
}

LoadedElf::~LoadedElf() {
  // Unmap the image.
  base_.reset();

  // Explicitly destroy all the mappings before closing the file.
  program_table_mapping_.reset();
  section_table_mapping_.reset();
  section_string_table_mapping_.reset();

  if (file_ != nullptr) {
    file_->Close();
    file_->Release();
  }
}

bool LoadedElf::ReadHeader() {
  CHECK_ERROR(file_->ReadFully(&header_, sizeof(dart::elf::ElfHeader)),
              "Could not read ELF file.");

  CHECK_ERROR(header_.ident[dart::elf::EI_DATA] == dart::elf::ELFDATA2LSB,
              "Expected little-endian ELF object.");

  CHECK_ERROR(header_.type == dart::elf::ET_DYN,
              "Can only load dynamic libraries.");

#if defined(TARGET_ARCH_IA32)
  CHECK_ERROR(header_.machine == dart::elf::EM_386, "Architecture mismatch.");
#elif defined(TARGET_ARCH_X64)
  CHECK_ERROR(header_.machine == dart::elf::EM_X86_64,
              "Architecture mismatch.");
#elif defined(TARGET_ARCH_ARM)
  CHECK_ERROR(header_.machine == dart::elf::EM_ARM, "Architecture mismatch.");
#elif defined(TARGET_ARCH_ARM64)
  CHECK_ERROR(header_.machine == dart::elf::EM_AARCH64,
              "Architecture mismatch.");
#else
#error Unsupported architecture architecture.
#endif

  CHECK_ERROR(header_.version == dart::elf::EV_CURRENT,
              "Unexpected ELF version.");
  CHECK_ERROR(header_.header_size == sizeof(dart::elf::ElfHeader),
              "Unexpected header size.");
  CHECK_ERROR(
      header_.program_table_entry_size == sizeof(dart::elf::ProgramHeader),
      "Unexpected program header size.");
  CHECK_ERROR(
      header_.section_table_entry_size == sizeof(dart::elf::SectionHeader),
      "Unexpected section header size.");

  return true;
}

bool LoadedElf::ReadProgramTable() {
  const uword file_start = header_.program_table_offset;
  const uword file_length =
      header_.num_program_headers * sizeof(dart::elf::ProgramHeader);
  program_table_mapping_.reset(
      MapFilePiece(file_start, file_length,
                   reinterpret_cast<const void**>(&program_table_)));
  CHECK_ERROR(program_table_mapping_ != nullptr,
              "Could not mmap the program table.");
  return true;
}

bool LoadedElf::ReadSectionTable() {
  const uword file_start = header_.section_table_offset;
  const uword file_length =
      header_.num_section_headers * sizeof(dart::elf::SectionHeader);
  section_table_mapping_.reset(
      MapFilePiece(file_start, file_length,
                   reinterpret_cast<const void**>(&section_table_)));
  CHECK_ERROR(section_table_mapping_ != nullptr,
              "Could not mmap the section table.");
  return true;
}

bool LoadedElf::ReadSectionStringTable() {
  const dart::elf::SectionHeader header =
      section_table_[header_.shstrtab_section_index];
  section_string_table_mapping_.reset(
      MapFilePiece(header.file_offset, header.file_size,
                   reinterpret_cast<const void**>(&section_string_table_)));
  CHECK_ERROR(section_string_table_mapping_ != nullptr,
              "Could not mmap the section string table.");
  return true;
}

bool LoadedElf::LoadSegments() {
  // Calculate the total amount of virtual memory needed.
  uword total_memory = 0;
  uint64_t maximum_alignment = PageSize();
  for (uword i = 0; i < header_.num_program_headers; ++i) {
    const dart::elf::ProgramHeader header = program_table_[i];

    // Only PT_LOAD segments need to be loaded.
    if (header.type != dart::elf::ProgramHeaderType::PT_LOAD) continue;

    total_memory = Utils::Maximum(
        static_cast<uword>(header.memory_offset + header.memory_size),
        total_memory);
    CHECK_ERROR(Utils::IsPowerOfTwo(header.alignment),
                "Alignment must be a power of two.");
    maximum_alignment = Utils::Maximum(maximum_alignment, header.alignment);
  }
  total_memory = Utils::RoundUp(total_memory, PageSize());

  base_.reset(VirtualMemory::AllocateAligned(
      total_memory, /*alignment=*/maximum_alignment,
      /*is_executable=*/false, /*mapping name=*/filename_.get()));
  CHECK_ERROR(base_ != nullptr, "Could not reserve virtual memory.");

  for (uword i = 0; i < header_.num_program_headers; ++i) {
    const dart::elf::ProgramHeader header = program_table_[i];

    // Only PT_LOAD segments need to be loaded.
    if (header.type != dart::elf::ProgramHeaderType::PT_LOAD) continue;

    const uword memory_offset = header.memory_offset,
                file_offset = header.file_offset;
    CHECK_ERROR(
        (memory_offset % PageSize()) == (file_offset % PageSize()),
        "Difference between file and memory offset must be page-aligned.");

    const intptr_t adjustment = header.memory_offset % PageSize();

    void* const memory_start =
        static_cast<char*>(base_->address()) + memory_offset - adjustment;
    const uword file_start = file_offset - adjustment;
    const uword length = header.memory_size + adjustment;

    File::MapType map_type = File::kReadOnly;
    if (header.flags == (dart::elf::PF_R | dart::elf::PF_W)) {
      map_type = File::kReadWrite;
    } else if (header.flags == (dart::elf::PF_R | dart::elf::PF_X)) {
      map_type = File::kReadExecute;
    } else if (header.flags == dart::elf::PF_R) {
      map_type = File::kReadOnly;
    } else {
      ERROR("Unsupported segment flag set.");
    }

    std::unique_ptr<MappedMemory> memory(
        file_->Map(map_type, file_start, length, memory_start));
    CHECK_ERROR(memory != nullptr, "Could not map segment.");
    CHECK_ERROR(memory->address() == memory_start,
                "Mapping not at requested address.");
  }

  return true;
}

bool LoadedElf::ReadSections() {
  for (uword i = 0; i < header_.num_section_headers; ++i) {
    const dart::elf::SectionHeader header = section_table_[i];
    const char* const name = section_string_table_ + header.name;
    if (strcmp(name, ".dynstr") == 0) {
      CHECK_ERROR(header.memory_offset != 0, ".dynstr must be loaded.");
      dynamic_string_table_ =
          static_cast<const char*>(base_->address()) + header.memory_offset;
    } else if (strcmp(name, ".dynsym") == 0) {
      CHECK_ERROR(header.memory_offset != 0, ".dynsym must be loaded.");
      dynamic_symbol_table_ = reinterpret_cast<const dart::elf::Symbol*>(
          base_->start() + header.memory_offset);
      dynamic_symbol_count_ = header.file_size / sizeof(dart::elf::Symbol);
    }
  }

  CHECK_ERROR(dynamic_string_table_ != nullptr, "Couldn't find .dynstr.");
  CHECK_ERROR(dynamic_symbol_table_ != nullptr, "Couldn't find .dynsym.");
  return true;
}

bool LoadedElf::ResolveSymbols(const uint8_t** vm_data,
                               const uint8_t** vm_instrs,
                               const uint8_t** isolate_data,
                               const uint8_t** isolate_instrs) {
  if (error_ != nullptr) {
    return false;
  }

  // The first entry of the symbol table is reserved.
  for (uword i = 1; i < dynamic_symbol_count_; ++i) {
    const dart::elf::Symbol sym = dynamic_symbol_table_[i];
    const char* name = dynamic_string_table_ + sym.name;
    const uint8_t** output = nullptr;

    if (strcmp(name, kVmSnapshotDataSymbolName) == 0) {
      output = vm_data;
    } else if (strcmp(name, kVmSnapshotInstructionsSymbolName) == 0) {
      output = vm_instrs;
    } else if (strcmp(name, kIsolateSnapshotDataSymbolName) == 0) {
      output = isolate_data;
    } else if (strcmp(name, kIsolateSnapshotInstructionsSymbolName) == 0) {
      output = isolate_instrs;
    }

    if (output != nullptr) {
      *output = reinterpret_cast<const uint8_t*>(base_->start() + sym.value);
    }
  }

  CHECK_ERROR(vm_data == nullptr || *vm_data != nullptr,
              "Could not find VM snapshot data.");
  CHECK_ERROR(vm_instrs == nullptr || *vm_instrs != nullptr,
              "Could not find VM snapshot instructions.");
  CHECK_ERROR(isolate_data == nullptr || *isolate_data != nullptr,
              "Could not find isolate snapshot data.");
  CHECK_ERROR(isolate_instrs == nullptr || *isolate_instrs != nullptr,
              "Could not find isolate instructions.");
  return true;
}

MappedMemory* LoadedElf::MapFilePiece(uword file_start,
                                      uword file_length,
                                      const void** mem_start) {
  const uword mapping_offset = Utils::RoundDown(file_start, PageSize());
  const uword mapping_length =
      Utils::RoundUp(file_length + file_start % PageSize(), PageSize());
  MappedMemory* const mapping =
      file_->Map(bin::File::kReadOnly, mapping_offset, mapping_length);

  if (mapping != nullptr) {
    *mem_start = reinterpret_cast<uint8_t*>(mapping->start() +
                                            (file_start % PageSize()));
  }

  return mapping;
}

}  // namespace elf
}  // namespace bin
}  // namespace dart

DART_EXPORT void* Dart_LoadELF(const char* filename,
                               const char** error,
                               const uint8_t** vm_snapshot_data,
                               const uint8_t** vm_snapshot_instrs,
                               const uint8_t** vm_isolate_data,
                               const uint8_t** vm_isolate_instrs) {
  std::unique_ptr<dart::bin::elf::LoadedElf> elf(
      new dart::bin::elf::LoadedElf(filename));

  if (!elf->Load() ||
      !elf->ResolveSymbols(vm_snapshot_data, vm_snapshot_instrs,
                           vm_isolate_data, vm_isolate_instrs)) {
    *error = elf->error();
    return nullptr;
  }

  return elf.release();
}

DART_EXPORT void Dart_UnloadELF(void* loaded) {
  delete reinterpret_cast<dart::bin::elf::LoadedElf*>(loaded);
}
<|endoftext|>