<commit_before>#include "Graph.h"
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
vertex* Graph::at(const std::string& name)const
{
    auto it = m_V.find(name);
    if(it != m_V.end())
    {
        return it->second;
    }
    else throw;
}
std::vector<std::string> Graph::getkeys()const
{
    std::vector<std::string> ret;
    ret.resize(size());
    int ind = 0;
    for(auto& i : m_V)
    {
        ret[ind++] = i.first;
    }
    return ret;
}
void Graph::filladj(const std::vector<std::string>& names, const Graph& g)
{
    for(size_t i = 0; i < m_V.size(); i++)
    {
        auto it = m_V.find(names[i]);
        vertex* tmp = g.at(names[i]);
        vertex* pIt = it->second;
        for(auto& j : tmp->adj)
        {
            //1.cost
            //2.vertex* in this graph
            pIt->adj.push_back(std::make_pair(j.first,
                                              m_V.find(j.second->name)->second));
        }
    }
}
Graph::Graph(const Graph& g)
{
    std::vector<std::string> names = g.getkeys();
    for(size_t i = 0; i < g.size(); i++)
        addvertex(names[i]);
    filladj(names,g);
}
/*
    As long as there are vertexes
    change name,clean adjacency list.   x
    After that create new vertexes.     x
    Then fill adjacency lists.
    Clean remaining not needed vertexes x
*/
Graph& Graph::operator=(const Graph& g)
{
    int n = m_V.size() - g.size();
    ///if there are more vertexes than needed: n > 0
    ///if it is just the right size: n = 0
    ///if there are not enough vertexes: n < 0
    std::vector<std::string> names = getkeys();
    std::vector<std::string> namesTO = g.getkeys();
    if(!(n<0))
    {
        for(size_t i = 0; i < g.size(); i++)
        {
            auto it = m_V.find(names[i]);
            it->second->name = namesTO[i];
            it->second->adj.clear();
        }
        //Clean remaining not needed vertexes
        for(int i = g.size(); i < n; i++)
            removevertex(names[i]);
    }
    else
    {
        for(size_t i = 0; i < g.size(); i++)
            addvertex(namesTO[i]);
    }
    //Filling adjacency list
    filladj(namesTO,g);
    return *this;
}

Graph::~Graph()
{
    if(!m_V.empty())
    {
        for(auto& i : m_V)
            delete i.second;
    }
}

Graph::vmap::iterator Graph::addvertex(const std::string& name)
{
	auto it=m_V.find(name);
	if(it==m_V.end())
	{
		vertex *v;
		v = new vertex(name);
		m_V[name]=v;
		return it;
	}
	return m_V.end();
}

void Graph::addedge(const std::string& from, const std::string& to, int cost)
{
    auto fromIt = m_V.find(from);
    auto toIt   = m_V.find(to);
    if(fromIt != m_V.end() && toIt != m_V.end())
    {
        vertex *f = (fromIt->second);
        vertex *t = (toIt->second);
        std::pair<int,vertex*> edge = std::make_pair(cost,t);
        f->adj.push_back(edge);
    }
}
//Currently fixed(Use removeedge in later versions?)
void Graph::removevertex(const std::string& name)
{
    auto it = m_V.find(name);
    if(it != m_V.end())
    {
        for(auto& i : m_V)
        {
            if(i.second != it->second)
            {
                vertex* v = i.second;
                for(auto& j : v->adj)
                {
                    if(j.second->name == name)
                    {
                        v->adj.erase(std::find(v->adj.begin(),v->adj.end(), j));
                    }
                }
            }
        }
        delete it->second;
        m_V.erase(it);
    }
}
//works correctly
void Graph::removeedge(const std::string& from, const std::string& to)
{
    auto fromIt = m_V.find(from);
    auto toIt   = m_V.find(to);
    if(fromIt != m_V.end() && toIt != m_V.end())
    {
        vertex* v = fromIt->second;
        size_t i = 0;
        while(i < v->adj.size() && !(v->adj[i].second->name == to))
            i++;
        if(i < v->adj.size())
        {
            v->adj.erase(v->adj.begin()+i);
        }
    }
}

bool Graph::adjacent(const std::string& from, const std::string& to)
{
    auto fromIt = m_V.find(from);
    auto toIt   = m_V.find(to);
    if(fromIt != m_V.end() && toIt != m_V.end())
    {
        for(auto& i : fromIt->second->adj)
        {
            if(i.second->name == to)
            {
                return true;
            }
        }
    }
    return false;
}

std::vector<std::string> Graph::neighbours(const std::string& name)
{
    auto it = m_V.find(name);
    std::vector<std::string> ret;
    if(it != m_V.end())
    {
        for(auto& i : it->second->adj)
            ret.push_back(i.second->name);
    }
    return ret;
}

std::string Graph::bfs(const std::string& name)
{
    std::string ret = "";
    auto it = m_V.find(name);
    if(it != m_V.end())
    {
        std::queue<vertex*> Queue;
        vertex* curr = it->second;
        Queue.push(curr);
        curr->visited = true;
        ret += curr->name + " ";

        while(!Queue.empty())
        {
            for(auto& i : curr->adj)
            {
                if(i.second->visited == false)
                {
                    Queue.push(i.second);
                    i.second->visited = true;
                    ret+= i.second->name + " ";
                }
            }
            Queue.pop();
            if(!Queue.empty())
            {
                curr = Queue.front();
            }
        }
        //reset the visited var
        for(auto& i : m_V)
            i.second->visited = false;
    }
    return ret;
}

std::string Graph::dfs(const std::string& name, bool topo)
{
    std::string ret = "";
    auto it = m_V.find(name);
    if(it != m_V.end())
    {
        std::stack<vertex*> Stack;
        vertex* curr = it->second;
        Stack.push(curr);
        curr->visited = true;
        if(!topo)
            ret += curr->name + " ";

        while(!Stack.empty())
        {
            bool found = false;
            size_t i = 0;
            while(i < curr->adj.size() && !found)
            {
                if(curr->adj[i].second->visited == false)
                {
                    found = true;
                    curr = curr->adj[i].second;
                    curr->visited = true;
                    if(!topo)
                        ret += curr->name + " ";
                    Stack.push(curr);
                }
                i++;
            }
            if(!found)
            {
                Stack.pop();
                if(topo)
                {
                    ret += curr->name + " ";
                }
                if(!Stack.empty())
                {
                    curr = Stack.top();
                }
            }
        }
        if(topo)
        {
            std::reverse(ret.begin(),ret.end());
            ret.erase(ret.begin());//remove space at the beginning
        }
        else ret.erase(ret.end()-1);//remove space at the end
        for(auto& i : m_V)
            i.second->visited = false;
    }
    return ret;
}
/*
There are 3 sets. White set is used for those vertexes that haven't been visited yet,
grey is for those which we are currently visiting, and Black is used for those that we already visited.
Using depth first search we go through one of the starting vertexes child, and move it to the grey set.
If on this way we find a vertex that has a child in the grey set we found a cycle.
If a vertex has no more children that haven't been visited yet, it is moved into the black set and if
possible we go back to the parent. If no parent can be found(nullptr) we pick the first element in the
white set.(if it has any.)
If there is no cycle every vertex will be moved to the black set.
*/
std::string Graph::cycle(bool& found)
{
    std::string ret = "";
    std::set<vertex*> white;
    std::set<vertex*> grey;
    std::set<vertex*> black;
    std::map<vertex*,vertex*> parentMap;
    ///Init all vertexes into white
    for(auto& i : m_V)
        white.insert(i.second);
    vertex* curr = *white.begin();
    vertex* prev = nullptr;
    grey.insert(curr);
    white.erase(curr);
    parentMap[curr] = prev;
    while(black.size() != m_V.size())
    {
        found = false;
        size_t i = 0;
        while(i < curr->adj.size() && !found)
        {
            vertex* v = curr->adj[i].second;
            if(white.find(v) != white.end())
            {
                prev = curr;
                curr = v;
                grey.insert(curr);
                white.erase(curr);
                parentMap[curr] = prev;
                found = true;
                i = 0;
            }
            else if(grey.find(v) != grey.end())
            {
                found = true;
                ret += v->name + " " + curr->name + " ";
                while(curr != nullptr)
                {
                    curr = parentMap.find(curr)->second;
                    if(curr != nullptr)
                        ret += curr->name + " ";
                }
                std::reverse(ret.begin(),ret.end());
                ret.erase(ret.begin());
                return ret;
            }
            else
                i++;
        }
        if(!found)
        {
            black.insert(curr);
            grey.erase(curr);
            prev = nullptr;
            curr = parentMap.find(curr)->second;
            if(curr == nullptr && !white.empty())
            {
                curr = *white.begin();
                grey.insert(curr);
                white.erase(curr);
                parentMap[curr] = prev;
            }
        }
    }
    return ret;
}
<commit_msg>Minor changes.<commit_after>#include "Graph.h"
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
vertex* Graph::at(const std::string& name)const
{
    auto it = m_V.find(name);
    if(it != m_V.end())
    {
        return it->second;
    }
    else throw;
}
std::vector<std::string> Graph::getkeys()const
{
    std::vector<std::string> ret;
    ret.resize(size());
    int ind = 0;
    for(auto& i : m_V)
    {
        ret[ind++] = i.first;
    }
    return ret;
}
void Graph::filladj(const std::vector<std::string>& names, const Graph& g)
{
    for(size_t i = 0; i < m_V.size(); i++)
    {
        auto it = m_V.find(names[i]);
        vertex* tmp = g.at(names[i]);
        vertex* pIt = it->second;
        for(auto& j : tmp->adj)
        {
            //1.cost
            //2.vertex* in this graph
            pIt->adj.push_back(std::make_pair(j.first,
                                              m_V.find(j.second->name)->second));
        }
    }
}
Graph::Graph(const Graph& g)
{
    std::vector<std::string> names = g.getkeys();
    for(size_t i = 0; i < g.size(); i++)
        addvertex(names[i]);
    filladj(names,g);
}
/*
    As long as there are vertexes
    change name,clean adjacency list.   x
    After that create new vertexes.     x
    Then fill adjacency lists.
    Clean remaining not needed vertexes x
*/
Graph& Graph::operator=(const Graph& g)
{
    int n = m_V.size() - g.size();
    ///if there are more vertexes than needed: n > 0
    ///if it is just the right size: n = 0
    ///if there are not enough vertexes: n < 0
    std::vector<std::string> names = getkeys();
    std::vector<std::string> namesTO = g.getkeys();
    if(!(n<0))
    {
        for(size_t i = 0; i < g.size(); i++)
        {
            auto it = m_V.find(names[i]);
            it->second->name = namesTO[i];
            it->second->adj.clear();
        }
        //Clean remaining not needed vertexes
        for(int i = g.size(); i < n; i++)
            removevertex(names[i]);
    }
    else
    {
        for(size_t i = 0; i < g.size(); i++)
            addvertex(namesTO[i]);
    }
    //Filling adjacency list
    filladj(namesTO,g);
    return *this;
}

Graph::~Graph()
{
    if(!m_V.empty())
    {
        for(auto& i : m_V)
            delete i.second;
    }
}

Graph::vmap::iterator Graph::addvertex(const std::string& name)
{
	auto it=m_V.find(name);
	if(it==m_V.end())
	{
		vertex *v;
		v = new vertex(name);
		m_V[name]=v;
		return it;
	}
	return m_V.end();
}

void Graph::addedge(const std::string& from, const std::string& to, int cost)
{
    auto fromIt = m_V.find(from);
    auto toIt   = m_V.find(to);
    if(fromIt != m_V.end() && toIt != m_V.end())
    {
        vertex *f = (fromIt->second);
        vertex *t = (toIt->second);
        std::pair<int,vertex*> edge = std::make_pair(cost,t);
        f->adj.push_back(edge);
    }
}

void Graph::removevertex(const std::string& name)
{
    auto it = m_V.find(name);
    if(it != m_V.end())
    {
        for(auto& i : m_V)
        {
            if(i.second != it->second)
            {
                vertex* v = i.second;
                for(auto& j : v->adj)
                {
                    if(j.second->name == name)
                    {
                        v->adj.erase(std::find(v->adj.begin(),v->adj.end(), j));
                    }
                }
            }
        }
        delete it->second;
        m_V.erase(it);
    }
}

void Graph::removeedge(const std::string& from, const std::string& to)
{
    auto fromIt = m_V.find(from);
    auto toIt   = m_V.find(to);
    if(fromIt != m_V.end() && toIt != m_V.end())
    {
        vertex* v = fromIt->second;
        size_t i = 0;
        while(i < v->adj.size() && !(v->adj[i].second->name == to))
            i++;
        if(i < v->adj.size())
        {
            v->adj.erase(v->adj.begin()+i);
        }
    }
}

bool Graph::adjacent(const std::string& from, const std::string& to)
{
    auto fromIt = m_V.find(from);
    auto toIt   = m_V.find(to);
    if(fromIt != m_V.end() && toIt != m_V.end())
    {
        for(auto& i : fromIt->second->adj)
        {
            if(i.second->name == to)
            {
                return true;
            }
        }
    }
    return false;
}

std::vector<std::string> Graph::neighbours(const std::string& name)
{
    auto it = m_V.find(name);
    std::vector<std::string> ret;
    if(it != m_V.end())
    {
        for(auto& i : it->second->adj)
            ret.push_back(i.second->name);
    }
    return ret;
}

std::string Graph::bfs(const std::string& name)
{
    std::string ret = "";
    auto it = m_V.find(name);
    if(it != m_V.end())
    {
        std::queue<vertex*> Queue;
        vertex* curr = it->second;
        Queue.push(curr);
        curr->visited = true;
        ret += curr->name + " ";

        while(!Queue.empty())
        {
            for(auto& i : curr->adj)
            {
                if(i.second->visited == false)
                {
                    Queue.push(i.second);
                    i.second->visited = true;
                    ret+= i.second->name + " ";
                }
            }
            Queue.pop();
            if(!Queue.empty())
                curr = Queue.front();
        }
        //reset the visited var
        for(auto& i : m_V)
            i.second->visited = false;
    }
    return ret;
}

std::string Graph::dfs(const std::string& name, bool topo)
{
    std::string ret = "";
    auto it = m_V.find(name);
    if(it != m_V.end())
    {
        std::stack<vertex*> Stack;
        vertex* curr = it->second;
        Stack.push(curr);
        curr->visited = true;
        if(!topo)
            ret += curr->name + " ";

        while(!Stack.empty())
        {
            bool found = false;
            size_t i = 0;
            while(i < curr->adj.size() && !found)
            {
                if(curr->adj[i].second->visited == false)
                {
                    found = true;
                    curr = curr->adj[i].second;
                    curr->visited = true;
                    if(!topo)
                        ret += curr->name + " ";
                    Stack.push(curr);
                }
                i++;
            }
            if(!found)
            {
                Stack.pop();
                if(topo)
                    ret += curr->name + " ";
                if(!Stack.empty())
                    curr = Stack.top();
            }
        }
        if(topo)
        {
            std::reverse(ret.begin(),ret.end());
            ret.erase(ret.begin());//remove space at the beginning
        }
        else ret.erase(ret.end()-1);//remove space at the end
        for(auto& i : m_V)
            i.second->visited = false;
    }
    return ret;
}
/*
There are 3 sets. White set is used for those vertexes that haven't been visited yet,
grey is for those which we are currently visiting, and Black is used for those that we already visited.
Using depth first search we go through one of the starting vertexes child, and move it to the grey set.
If on this way we find a vertex that has a child in the grey set we found a cycle.
If a vertex has no more children that haven't been visited yet, it is moved into the black set and if
possible we go back to the parent. If no parent can be found(nullptr) we pick the first element in the
white set.(if it has any.)
If there is no cycle every vertex will be moved to the black set.
*/
std::string Graph::cycle(bool& found)
{
    std::string ret = "";
    std::set<vertex*> white;
    std::set<vertex*> grey;
    std::set<vertex*> black;
    std::map<vertex*,vertex*> parentMap;
    ///Init all vertexes into white
    for(auto& i : m_V)
        white.insert(i.second);
    vertex* curr = *white.begin();
    vertex* prev = nullptr;
    grey.insert(curr);
    white.erase(curr);
    parentMap[curr] = prev;
    while(black.size() != m_V.size())
    {
        found = false;
        size_t i = 0;
        while(i < curr->adj.size() && !found)
        {
            vertex* v = curr->adj[i].second;
            if(white.find(v) != white.end())
            {
                prev = curr;
                curr = v;
                grey.insert(curr);
                white.erase(curr);
                parentMap[curr] = prev;
                found = true;
                i = 0;
            }
            else if(grey.find(v) != grey.end())
            {
                found = true;
                ret += v->name + " " + curr->name + " ";
                while(curr != nullptr)
                {
                    curr = parentMap.find(curr)->second;
                    if(curr != nullptr)
                        ret += curr->name + " ";
                }
                std::reverse(ret.begin(),ret.end());
                ret.erase(ret.begin());
                return ret;
            }
            else
                i++;
        }
        if(!found)
        {
            black.insert(curr);
            grey.erase(curr);
            prev = nullptr;
            curr = parentMap.find(curr)->second;
            if(curr == nullptr && !white.empty())
            {
                curr = *white.begin();
                grey.insert(curr);
                white.erase(curr);
                parentMap[curr] = prev;
            }
        }
    }
    return ret;
}
<|endoftext|>


<commit_before>/*
 * Graph.hpp
 *
 *  Created on: Nov 4, 2014
 *      Author: Pimenta
 */

#ifndef GRAPH_HPP_
#define GRAPH_HPP_

#include <memory>
#include <map>
#include <functional>
#include <cstdio>

typedef int Size;
typedef int Vertex;
typedef int Weight;
enum { INFINITE = 0x7fffffff };

class Edge {
  public:
    Vertex vertex;
    Weight weight;
    Edge(Vertex vertex = 0, Weight weight = INFINITE);
    bool operator<(const Edge& other) const;
};

class Neighbourhood {
  public:
    class Iterator : public std::iterator<std::forward_iterator_tag, Edge> {
      private:
        std::shared_ptr<Iterator> it, itend;
      public:
        Iterator(Iterator* it, Iterator* itend);
        virtual ~Iterator();
        virtual bool operator!=(const Iterator& other) const;
        virtual Edge operator*();
        virtual Iterator& operator++();
    };
    Vertex vertex;
    Neighbourhood(Vertex vertex = 0);
    virtual ~Neighbourhood();
    virtual Iterator begin() const = 0;
    virtual Iterator end() const = 0;
    virtual Edge operator[](Vertex v) const = 0;
    virtual Size degree() const = 0;
    virtual void edge(Vertex v, Weight w) = 0;
};

class Graph {
  public:
    class Iterator : public std::iterator<std::forward_iterator_tag, Neighbourhood> {
      private:
        std::shared_ptr<Iterator> it;
      public:
        Iterator(Iterator* it);
        virtual ~Iterator();
        virtual bool operator!=(const Iterator& other) const;
        virtual Neighbourhood& operator*();
        virtual Iterator& operator++();
    };
    virtual ~Graph();
    virtual Iterator begin() const = 0;
    virtual Iterator end() const = 0;
    virtual Neighbourhood& operator[](Vertex v) const = 0;
    virtual Size order() const = 0;
    virtual void order(Size new_order) = 0;
};

class ArrayNeighbourhood : public Neighbourhood {
  public:
    class Iterator : public Neighbourhood::Iterator {
      private:
        Edge* ptr;
      public:
        Iterator(Edge* ptr);
        bool operator!=(const Neighbourhood::Iterator& other) const;
        Edge operator*();
        Neighbourhood::Iterator& operator++();
    };
  private:
    Size size_;
    Edge* data;
    Size degree_;
  public:
    ArrayNeighbourhood();
    ~ArrayNeighbourhood();
    Neighbourhood::Iterator begin() const;
    Neighbourhood::Iterator end() const;
    Edge operator[](Vertex v) const;
    Size degree() const;
    void resize(Size new_size);
    void edge(Vertex v, Weight w);
};

class MapNeighbourhood : public Neighbourhood {
  public:
    class Iterator : public Neighbourhood::Iterator {
      private:
        std::map<Vertex, Edge>::const_iterator mapit;
      public:
        Iterator(std::map<Vertex, Edge>::const_iterator mapit);
        bool operator!=(const Neighbourhood::Iterator& other) const;
        Edge operator*();
        Neighbourhood::Iterator& operator++();
    };
  private:
    std::map<Vertex, Edge> data;
  public:
    Neighbourhood::Iterator begin() const;
    Neighbourhood::Iterator end() const;
    Edge operator[](Vertex v) const;
    Size degree() const;
    void edge(Vertex v, Weight w);
};

template <class NeighbourhoodType>
class ArrayGraph : public Graph {
  public:
    class Iterator : public Graph::Iterator {
      private:
        NeighbourhoodType* ptr;
      public:
        Iterator(NeighbourhoodType* ptr) : Graph::Iterator(nullptr), ptr(ptr) {

        }
        bool operator!=(const Graph::Iterator& other) const {
          return ptr != ((Iterator&)other).ptr;
        }
        Neighbourhood& operator*() {
          return *ptr;
        }
        Graph::Iterator& operator++() {
          ptr++;
          return *this;
        }
    };
  private:
    Size order_;
    NeighbourhoodType* data;
  public:
    ArrayGraph() : order_(0), data(new NeighbourhoodType[0]) {

    }
    ~ArrayGraph() {
      delete[] data;
    }
    Graph::Iterator begin() const {
      return Graph::Iterator(new Iterator(data));
    }
    Graph::Iterator end() const {
      return Graph::Iterator(new Iterator(data + order_));
    }
    Neighbourhood& operator[](Vertex v) const {
      return data[v - 1];
    }
    Size order() const {
      return order_;
    }
    void order(Size new_order) {
      order_ = new_order;
      delete[] data;
      data = new NeighbourhoodType[order_];
      for (Size i = 0; i < order_; i++) {
        data[i].vertex = i + 1;
      }
    }
};

template <> inline void ArrayGraph<ArrayNeighbourhood>::order(Size new_order) {
  order_ = new_order;
  delete[] data;
  data = new ArrayNeighbourhood[order_];
  for (Size i = 0; i < order_; i++) {
    data[i].vertex = i + 1;
    data[i].resize(order_);
  }
}

template <class NeighbourhoodType>
class MapGraph : public Graph {
  public:
    class Iterator : public Graph::Iterator {
      private:
        typename std::map<Vertex, NeighbourhoodType>::const_iterator mapit;
      public:
        Iterator(typename std::map<Vertex, NeighbourhoodType>::const_iterator mapit) :
        Graph::Iterator(nullptr), mapit(mapit)
        {

        }
        bool operator!=(const Graph::Iterator& other) const {
          return mapit != ((Iterator&)other).mapit;
        }
        Neighbourhood& operator*() {
          return (Neighbourhood&)mapit->second;
        }
        Graph::Iterator& operator++() {
          mapit++;
          return *this;
        }
    };
  private:
    std::map<Vertex, NeighbourhoodType> data;
  public:
    Graph::Iterator begin() const {
      return Graph::Iterator(new Iterator(data.begin()));
    }
    Graph::Iterator end() const {
      return Graph::Iterator(new Iterator(data.end()));
    }
    Neighbourhood& operator[](Vertex v) const {
      return (Neighbourhood&)data.at(v);
    }
    Size order() const {
      return data.size();
    }
    void order(Size new_order) {
      data.clear();
      for (Vertex u = 1; u <= new_order; u++) {
        data[u].vertex = u;
      }
    }
};

template <> inline void MapGraph<ArrayNeighbourhood>::order(Size new_order) {
  data.clear();
  for (Vertex u = 1; u <= new_order; u++) {
    data[u].vertex = u;
    data[u].resize(new_order);
  }
}

template <int maxN>
class AllPairsShortestPaths {
  private:
    struct Data {
      Weight data[maxN][maxN];
    };

    int N;
    Data* res;
  public:
    AllPairsShortestPaths(
      const Graph& G,
      std::function<void(const Graph&, Vertex, Weight*)> spfunc
    ) : N(G.order()), res(new Data) {
      Weight* shortest_path_tree = new Weight[G.order() + 1];
      for (auto& u : G) {
        spfunc(G, u.vertex, shortest_path_tree);
        for (auto& v : G) {
          res->data[u.vertex][v.vertex] = shortest_path_tree[v.vertex];
        }
      }
      delete[] shortest_path_tree;
    }

    ~AllPairsShortestPaths() {
      delete res;
    }

    bool operator==(const AllPairsShortestPaths& other) {
      if (N != other.N) {
        return false;
      }

      for (Vertex source = 1; source <= N; source++) {
        for (Vertex target = 1; target <= N; target++) {
          if (res->data[source][target] != other.res->data[source][target]) {
            return false;
          }
        }
      }

      return true;
    }

    bool operator!=(const AllPairsShortestPaths& other) {
      if (N != other.N) {
        return true;
      }

      for (Vertex source = 1; source <= N; source++) {
        for (Vertex target = 1; target <= N; target++) {
          if (res->data[source][target] != other.res->data[source][target]) {
            return true;
          }
        }
      }

      return false;
    }

    void print(FILE* fp, const char* funcname) {
      fprintf(fp, "%s:\n", funcname);
      for (Vertex source = 1; source <= N; source++) {
        for (Vertex target = 1; target <= N; target++) {
          Weight w = res->data[source][target];
          if (w == INFINITE) {
            fprintf(fp, "  inf ");
          }
          else {
            fprintf(fp, "%5d ", w);
          }
        }
        fprintf(fp, "\n");
      }
    }
};

void scanUndirectedGraph(Graph& G, FILE* fp);
void scanDirectedGraph(Graph& G, FILE* fp);
void printDirectedGraph(const Graph& G, FILE* fp);

/**
 * Generates loop-free weighted undirected graphs without multiple edges, using
 * a uniform distribution.
 * G: container
 * N: number of vertices
 * maxWeight: will generate weights in [1, maxWeight]
 */
void generateGraph(Graph& G, int N, Weight maxWeight);

#endif /* GRAPH_HPP_ */
<commit_msg>Breaking line<commit_after>/*
 * Graph.hpp
 *
 *  Created on: Nov 4, 2014
 *      Author: Pimenta
 */

#ifndef GRAPH_HPP_
#define GRAPH_HPP_

#include <memory>
#include <map>
#include <functional>
#include <cstdio>

typedef int Size;
typedef int Vertex;
typedef int Weight;
enum { INFINITE = 0x7fffffff };

class Edge {
  public:
    Vertex vertex;
    Weight weight;
    Edge(Vertex vertex = 0, Weight weight = INFINITE);
    bool operator<(const Edge& other) const;
};

class Neighbourhood {
  public:
    class Iterator : public std::iterator<std::forward_iterator_tag, Edge> {
      private:
        std::shared_ptr<Iterator> it, itend;
      public:
        Iterator(Iterator* it, Iterator* itend);
        virtual ~Iterator();
        virtual bool operator!=(const Iterator& other) const;
        virtual Edge operator*();
        virtual Iterator& operator++();
    };
    Vertex vertex;
    Neighbourhood(Vertex vertex = 0);
    virtual ~Neighbourhood();
    virtual Iterator begin() const = 0;
    virtual Iterator end() const = 0;
    virtual Edge operator[](Vertex v) const = 0;
    virtual Size degree() const = 0;
    virtual void edge(Vertex v, Weight w) = 0;
};

class Graph {
  public:
    class Iterator : public std::iterator<std::forward_iterator_tag, Neighbourhood> {
      private:
        std::shared_ptr<Iterator> it;
      public:
        Iterator(Iterator* it);
        virtual ~Iterator();
        virtual bool operator!=(const Iterator& other) const;
        virtual Neighbourhood& operator*();
        virtual Iterator& operator++();
    };
    virtual ~Graph();
    virtual Iterator begin() const = 0;
    virtual Iterator end() const = 0;
    virtual Neighbourhood& operator[](Vertex v) const = 0;
    virtual Size order() const = 0;
    virtual void order(Size new_order) = 0;
};

class ArrayNeighbourhood : public Neighbourhood {
  public:
    class Iterator : public Neighbourhood::Iterator {
      private:
        Edge* ptr;
      public:
        Iterator(Edge* ptr);
        bool operator!=(const Neighbourhood::Iterator& other) const;
        Edge operator*();
        Neighbourhood::Iterator& operator++();
    };
  private:
    Size size_;
    Edge* data;
    Size degree_;
  public:
    ArrayNeighbourhood();
    ~ArrayNeighbourhood();
    Neighbourhood::Iterator begin() const;
    Neighbourhood::Iterator end() const;
    Edge operator[](Vertex v) const;
    Size degree() const;
    void resize(Size new_size);
    void edge(Vertex v, Weight w);
};

class MapNeighbourhood : public Neighbourhood {
  public:
    class Iterator : public Neighbourhood::Iterator {
      private:
        std::map<Vertex, Edge>::const_iterator mapit;
      public:
        Iterator(std::map<Vertex, Edge>::const_iterator mapit);
        bool operator!=(const Neighbourhood::Iterator& other) const;
        Edge operator*();
        Neighbourhood::Iterator& operator++();
    };
  private:
    std::map<Vertex, Edge> data;
  public:
    Neighbourhood::Iterator begin() const;
    Neighbourhood::Iterator end() const;
    Edge operator[](Vertex v) const;
    Size degree() const;
    void edge(Vertex v, Weight w);
};

template <class NeighbourhoodType>
class ArrayGraph : public Graph {
  public:
    class Iterator : public Graph::Iterator {
      private:
        NeighbourhoodType* ptr;
      public:
        Iterator(NeighbourhoodType* ptr) : Graph::Iterator(nullptr), ptr(ptr) {

        }
        bool operator!=(const Graph::Iterator& other) const {
          return ptr != ((Iterator&)other).ptr;
        }
        Neighbourhood& operator*() {
          return *ptr;
        }
        Graph::Iterator& operator++() {
          ptr++;
          return *this;
        }
    };
  private:
    Size order_;
    NeighbourhoodType* data;
  public:
    ArrayGraph() : order_(0), data(new NeighbourhoodType[0]) {

    }
    ~ArrayGraph() {
      delete[] data;
    }
    Graph::Iterator begin() const {
      return Graph::Iterator(new Iterator(data));
    }
    Graph::Iterator end() const {
      return Graph::Iterator(new Iterator(data + order_));
    }
    Neighbourhood& operator[](Vertex v) const {
      return data[v - 1];
    }
    Size order() const {
      return order_;
    }
    void order(Size new_order) {
      order_ = new_order;
      delete[] data;
      data = new NeighbourhoodType[order_];
      for (Size i = 0; i < order_; i++) {
        data[i].vertex = i + 1;
      }
    }
};

template <> inline void ArrayGraph<ArrayNeighbourhood>::order(Size new_order) {
  order_ = new_order;
  delete[] data;
  data = new ArrayNeighbourhood[order_];
  for (Size i = 0; i < order_; i++) {
    data[i].vertex = i + 1;
    data[i].resize(order_);
  }
}

template <class NeighbourhoodType>
class MapGraph : public Graph {
  public:
    class Iterator : public Graph::Iterator {
      private:
        typename std::map<Vertex, NeighbourhoodType>::const_iterator mapit;
      public:
        Iterator(
          typename std::map<Vertex, NeighbourhoodType>::const_iterator mapit
        ) : Graph::Iterator(nullptr), mapit(mapit) {

        }
        bool operator!=(const Graph::Iterator& other) const {
          return mapit != ((Iterator&)other).mapit;
        }
        Neighbourhood& operator*() {
          return (Neighbourhood&)mapit->second;
        }
        Graph::Iterator& operator++() {
          mapit++;
          return *this;
        }
    };
  private:
    std::map<Vertex, NeighbourhoodType> data;
  public:
    Graph::Iterator begin() const {
      return Graph::Iterator(new Iterator(data.begin()));
    }
    Graph::Iterator end() const {
      return Graph::Iterator(new Iterator(data.end()));
    }
    Neighbourhood& operator[](Vertex v) const {
      return (Neighbourhood&)data.at(v);
    }
    Size order() const {
      return data.size();
    }
    void order(Size new_order) {
      data.clear();
      for (Vertex u = 1; u <= new_order; u++) {
        data[u].vertex = u;
      }
    }
};

template <> inline void MapGraph<ArrayNeighbourhood>::order(Size new_order) {
  data.clear();
  for (Vertex u = 1; u <= new_order; u++) {
    data[u].vertex = u;
    data[u].resize(new_order);
  }
}

template <int maxN>
class AllPairsShortestPaths {
  private:
    struct Data {
      Weight data[maxN][maxN];
    };

    int N;
    Data* res;
  public:
    AllPairsShortestPaths(
      const Graph& G,
      std::function<void(const Graph&, Vertex, Weight*)> spfunc
    ) : N(G.order()), res(new Data) {
      Weight* shortest_path_tree = new Weight[G.order() + 1];
      for (auto& u : G) {
        spfunc(G, u.vertex, shortest_path_tree);
        for (auto& v : G) {
          res->data[u.vertex][v.vertex] = shortest_path_tree[v.vertex];
        }
      }
      delete[] shortest_path_tree;
    }

    ~AllPairsShortestPaths() {
      delete res;
    }

    bool operator==(const AllPairsShortestPaths& other) {
      if (N != other.N) {
        return false;
      }

      for (Vertex source = 1; source <= N; source++) {
        for (Vertex target = 1; target <= N; target++) {
          if (res->data[source][target] != other.res->data[source][target]) {
            return false;
          }
        }
      }

      return true;
    }

    bool operator!=(const AllPairsShortestPaths& other) {
      if (N != other.N) {
        return true;
      }

      for (Vertex source = 1; source <= N; source++) {
        for (Vertex target = 1; target <= N; target++) {
          if (res->data[source][target] != other.res->data[source][target]) {
            return true;
          }
        }
      }

      return false;
    }

    void print(FILE* fp, const char* funcname) {
      fprintf(fp, "%s:\n", funcname);
      for (Vertex source = 1; source <= N; source++) {
        for (Vertex target = 1; target <= N; target++) {
          Weight w = res->data[source][target];
          if (w == INFINITE) {
            fprintf(fp, "  inf ");
          }
          else {
            fprintf(fp, "%5d ", w);
          }
        }
        fprintf(fp, "\n");
      }
    }
};

void scanUndirectedGraph(Graph& G, FILE* fp);
void scanDirectedGraph(Graph& G, FILE* fp);
void printDirectedGraph(const Graph& G, FILE* fp);

/**
 * Generates loop-free weighted undirected graphs without multiple edges, using
 * a uniform distribution.
 * G: container
 * N: number of vertices
 * maxWeight: will generate weights in [1, maxWeight]
 */
void generateGraph(Graph& G, int N, Weight maxWeight);

#endif /* GRAPH_HPP_ */
<|endoftext|>


<commit_before>#include "Layer.h"

// Generate random float for initial weight
float Layer::randomFloat() {
  int randInt = rand() % (INITIALWEIGHTRANGE * 1000) - (INITIALWEIGHTRANGE * 500);
  float randFl = (float) randInt / 1000;
  return randFl;
}

// Public constructor
Layer::Layer(int numNodes, int numPrevNodes, std::vector<float> weights)
{
  setNumNodes(numNodes);
  setNumPrevNodes(numPrevNodes);
  // Initialize nodes
  for (int n = 0; n < numNodes; n++) {
    Node newNode = Node(0);
    nodes.push_back(newNode);
  }
  // Skip adding links to input layer
  if (numPrevNodes > 0) {
    int w = 0;
    // Initialize links
    for (int n = 0; n < numNodes; n++) {
      std::vector<Link> newVector;
      links.push_back(newVector);
      // Push back numPrevNodes + 1 to incorperate bias node
      for (int pn = 0; pn < numPrevNodes + 1; pn++) {
        if (weights.empty() == true) {
	  Link newLink = Link(randomFloat());
	  links[n].push_back(newLink);
        }
        else {
          Link newLink = Link(weights[w]);
	  links[n].push_back(newLink);
          w++;
        }
      }
    }
  }
}

// Calculate the weighted input for node in layer
float Layer::calculateWeightedInput(std::vector<Link> inputLinks) {
  float sum = 0.0;
  for (int pn = 0; pn < getNumPrevNodes(); pn++) {
    sum = sum + getInputs()[pn] * inputLinks[pn].getWeight();
  }
  sum = sum + BIASINPUT * inputLinks[getNumPrevNodes()].getWeight();
  return sum;
}

// Feed inputs through Network
std::vector<float> Layer::feedForward(std::vector<float> in) {
  // Update inputs vector instance variable
  setInputs(in);

  std::vector<float> outputs;
  // Outputs are equivilent to inputs in the first layer
  if (getNumPrevNodes() == 0) {
    outputs = getInputs();
  }
  else {
    // Set new values and obtain output for the input to the next layer
    for (int n = 0; n < getNumNodes(); n++) {
      nodes[n].setValue(calculateWeightedInput(links[n]));
      outputs.push_back(nodes[n].getOutput());
    }
  }
  return outputs;
}

// Calculate and update delta values for each node from next layer deltinis
void Layer::updateDeltas(std::vector<float> deltinis) {
  for (int n = 0; n < getNumNodes(); n++) {
    nodes[n].setDelta(deltinis[n] * nodes[n].getOutput() * (1 - nodes[n].getOutput()));
  }
}

// Calculate and update weight values for each link
void Layer::updateWeights() {
  for (int n = 0; n < getNumNodes(); n++) {
    for (int pn = 0; pn < getNumPrevNodes(); pn++) {
      links[n][pn].updateWeight(nodes[n].getDelta(), getInputs()[pn]);
    }
    links[n][getNumPrevNodes()].updateWeight(nodes[n].getDelta(), BIASINPUT);
  }
}

// Calculate the deltini for each node in the previous layer
std::vector<float> Layer::calculateDeltinis() {
  std::vector<float> deltinis;
  for (int pn = 0; pn < getNumPrevNodes() + 1; pn++) {
    float deltini = 0.0;
    for (int n = 0; n < getNumNodes(); n++) {
      deltini = deltini + links[n][pn].getWeight() * nodes[n].getDelta();
    }
    deltinis.push_back(deltini);
  }
  return deltinis;
}

// Back propegation algorithm to update weights
std::vector<float> Layer::backPropegation(std::vector<float> deltinis) {
    // Calculate and update delta values for each node from next layer deltinis
    updateDeltas(deltinis);

    // Calculate deltinis for use in previous layer's delta calculations
    deltinis = calculateDeltinis();

    // Update weights after calculating deltinis to preserve original weights
    // in deltini calculation
    updateWeights();

    return deltinis;
}

// Print node values in the layer
void Layer::printNodes()
{
  std::cout << "===========================\n";
  for (std::vector<Node>::iterator it = nodes.begin() ; it != nodes.end(); ++it) {
    std::cout << " Node: " << it - nodes.begin() << " = " << it->getValue() << std::endl;
  }
}

// Print link weights in the layer
void Layer::printLinks()
{
  std::cout << "===========================\n";
  for (int n = 0; n < getNumNodes(); n++) {
    for (int pn = 0; pn < getNumPrevNodes() + 1; pn++) {
      std::cout << " Link: " << pn << "->" << n << " = " << links[n][pn].getWeight() << std::endl;
    }
  }
}
<commit_msg>fixing spacing<commit_after>#include "Layer.h"

// Generate random float for initial weight
float Layer::randomFloat() {
  int randInt = rand() % (INITIALWEIGHTRANGE * 1000) - (INITIALWEIGHTRANGE * 500);
  float randFl = (float) randInt / 1000;
  return randFl;
}

// Public constructor
Layer::Layer(int numNodes, int numPrevNodes, std::vector<float> weights)
{
  setNumNodes(numNodes);
  setNumPrevNodes(numPrevNodes);
  // Initialize nodes
  for (int n = 0; n < numNodes; n++) {
    Node newNode = Node(0);
    nodes.push_back(newNode);
  }
  // Skip adding links to input layer
  if (numPrevNodes > 0) {
    int w = 0;
    // Initialize links
    for (int n = 0; n < numNodes; n++) {
      std::vector<Link> newVector;
      links.push_back(newVector);
      // Push back numPrevNodes + 1 to incorperate bias node
      for (int pn = 0; pn < numPrevNodes + 1; pn++) {
        if (weights.empty() == true) {
	  Link newLink = Link(randomFloat());
	  links[n].push_back(newLink);
        }
        else {
          Link newLink = Link(weights[w]);
          links[n].push_back(newLink);
          w++;
        }
      }
    }
  }
}

// Calculate the weighted input for node in layer
float Layer::calculateWeightedInput(std::vector<Link> inputLinks) {
  float sum = 0.0;
  for (int pn = 0; pn < getNumPrevNodes(); pn++) {
    sum = sum + getInputs()[pn] * inputLinks[pn].getWeight();
  }
  sum = sum + BIASINPUT * inputLinks[getNumPrevNodes()].getWeight();
  return sum;
}

// Feed inputs through Network
std::vector<float> Layer::feedForward(std::vector<float> in) {
  // Update inputs vector instance variable
  setInputs(in);

  std::vector<float> outputs;
  // Outputs are equivilent to inputs in the first layer
  if (getNumPrevNodes() == 0) {
    outputs = getInputs();
  }
  else {
    // Set new values and obtain output for the input to the next layer
    for (int n = 0; n < getNumNodes(); n++) {
      nodes[n].setValue(calculateWeightedInput(links[n]));
      outputs.push_back(nodes[n].getOutput());
    }
  }
  return outputs;
}

// Calculate and update delta values for each node from next layer deltinis
void Layer::updateDeltas(std::vector<float> deltinis) {
  for (int n = 0; n < getNumNodes(); n++) {
    nodes[n].setDelta(deltinis[n] * nodes[n].getOutput() * (1 - nodes[n].getOutput()));
  }
}

// Calculate and update weight values for each link
void Layer::updateWeights() {
  for (int n = 0; n < getNumNodes(); n++) {
    for (int pn = 0; pn < getNumPrevNodes(); pn++) {
      links[n][pn].updateWeight(nodes[n].getDelta(), getInputs()[pn]);
    }
    links[n][getNumPrevNodes()].updateWeight(nodes[n].getDelta(), BIASINPUT);
  }
}

// Calculate the deltini for each node in the previous layer
std::vector<float> Layer::calculateDeltinis() {
  std::vector<float> deltinis;
  for (int pn = 0; pn < getNumPrevNodes() + 1; pn++) {
    float deltini = 0.0;
    for (int n = 0; n < getNumNodes(); n++) {
      deltini = deltini + links[n][pn].getWeight() * nodes[n].getDelta();
    }
    deltinis.push_back(deltini);
  }
  return deltinis;
}

// Back propegation algorithm to update weights
std::vector<float> Layer::backPropegation(std::vector<float> deltinis) {
    // Calculate and update delta values for each node from next layer deltinis
    updateDeltas(deltinis);

    // Calculate deltinis for use in previous layer's delta calculations
    deltinis = calculateDeltinis();

    // Update weights after calculating deltinis to preserve original weights
    // in deltini calculation
    updateWeights();

    return deltinis;
}

// Print node values in the layer
void Layer::printNodes()
{
  std::cout << "===========================\n";
  for (std::vector<Node>::iterator it = nodes.begin() ; it != nodes.end(); ++it) {
    std::cout << " Node: " << it - nodes.begin() << " = " << it->getValue() << std::endl;
  }
}

// Print link weights in the layer
void Layer::printLinks()
{
  std::cout << "===========================\n";
  for (int n = 0; n < getNumNodes(); n++) {
    for (int pn = 0; pn < getNumPrevNodes() + 1; pn++) {
      std::cout << " Link: " << pn << "->" << n << " = " << links[n][pn].getWeight() << std::endl;
    }
  }
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "Lexer.hpp"

using std::pair;
using std::string;
using std::ios_base;

using namespace eddic;

void Lexer::lex(string file) {
	scanner.scan(file);

    currentType = NOTHING;
}

void Lexer::close() {
    scanner.close();
}

bool Lexer::next() {
    if(!buffer.empty()) {
        pair<string, TokenType> old = buffer.top();

        currentToken = old.first;
        currentType = old.second;

        buffer.pop();

        return true;
    } else if(readNext()) {
        read.push(make_pair(currentToken, currentType));

        return true;
    }

    return false;
}

void Lexer::pushBack() {
    pair<string, TokenType> old = read.top();

    buffer.push(old);

    read.pop();
}

bool Lexer::readNext() {
    if(!scanner.next()) {
        return false;
    }

    while(scanner.isSpace()) {
		if(!scanner.next()){
			return false;
		}
	}

    if(scanner.current() == '"') {
        currentToken = string(1, scanner.current());

        while(scanner.next() && scanner.current() != '"') {
            currentToken += scanner.current();
        }

        currentToken += scanner.current();

        currentType = LITTERAL;

        return true;
    } else if(scanner.isAlpha()) {
        currentToken = string(1, scanner.current());

        while(scanner.next() && scanner.isAlpha()) {
            currentToken += scanner.current();
        }

        scanner.pushBack();

        if(currentToken == "true") {
            currentType = TRUE;
        } else if(currentToken == "false") {
            currentType = FALSE;
        } else if(currentToken == "if") {
            currentType = IF;
        } else if(currentToken == "else") {
            currentType = ELSE;
        } else {
            currentType = WORD;
        }

        return true;
    } else if(scanner.isDigit()) {
        currentToken = string(1, scanner.current());

        while(scanner.next() && scanner.isDigit()) {
            currentToken += scanner.current();
        }

        scanner.pushBack();

        currentType = INTEGER;

        return true;
    }

    switch (scanner.current()) {
        case ';':
            currentType = STOP;
            currentToken = ";";
            return true;
        case '=':
            scanner.next();

            if(scanner.current() == '=') {
                currentType = EQUALS_TOKEN;
            } else {
                scanner.pushBack();

                currentType = ASSIGN;
            }

            return true;
        case '(':
            currentType = LEFT_PARENTH;
            return true;
        case ')':
            currentType = RIGHT_PARENTH;
            return true;
        case '{':
            currentType = LEFT_BRACE;
            return true;
        case '}':
            currentType = RIGHT_BRACE;
            return true;
        case '+':
            currentType = ADDITION;
            return true;
        case '-':
            currentType = SUBTRACTION;
            return true;
        case '*':
            currentType = MULTIPLICATION;
            return true;
        case '/':
            currentType = DIVISION;
            return true;
        case '%':
            currentType = MODULO;
            return true;
        case '!':
            scanner.next();

            if(scanner.current() == '=') {
                currentType = NOT_EQUALS_TOKEN;
            }

            return false;
        case '<':
            scanner.next();

            if(scanner.current() == '=') {
                scanner.next();

                if(scanner.current() == '>'){
                    currentType = SWAP;
                } else {
                    scanner.pushBack();
                    currentType = LESS_EQUALS_TOKEN;
                }
            } else {
                scanner.pushBack();

                currentType = LESS_TOKEN;
            }

            return true;
        case '>':
            scanner.next();

            if(scanner.current() == '=') {
                currentType = GREATER_EQUALS_TOKEN;
            } else {
                scanner.pushBack();

                currentType = GREATER_TOKEN;
            }

            return true;
    }

    return false;
}

string Lexer::getCurrentToken() const {
    return currentToken;
}

bool Lexer::isWord() const {
    return currentType == WORD;
}

bool Lexer::isLitteral() const {
    return currentType == LITTERAL;
}

bool Lexer::isAssign() const {
    return currentType == ASSIGN;
}

bool Lexer::isSwap() const {
    return currentType == SWAP;
}

bool Lexer::isLeftParenth() const {
    return currentType == LEFT_PARENTH;
}

bool Lexer::isRightParenth() const {
    return currentType == RIGHT_PARENTH;
}

bool Lexer::isLeftBrace() const {
    return currentType == LEFT_BRACE;
}

bool Lexer::isRightBrace() const {
    return currentType == RIGHT_BRACE;
}

bool Lexer::isStop() const {
    return currentType == STOP;
}

bool Lexer::isInteger() const {
    return currentType == INTEGER;
}

bool Lexer::isAddition() const {
    return currentType == ADDITION;
}

bool Lexer::isSubtraction() const {
    return currentType == SUBTRACTION;
}

bool Lexer::isMultiplication() const {
    return currentType == MULTIPLICATION;
}

bool Lexer::isModulo() const {
    return currentType == MODULO;
}

bool Lexer::isDivision() const {
    return currentType == DIVISION;
}

bool Lexer::isEquals() const {
    return currentType == EQUALS_TOKEN;
}

bool Lexer::isNotEquals() const {
    return currentType == NOT_EQUALS_TOKEN;
}

bool Lexer::isGreater() const {
    return currentType == GREATER_TOKEN;
}

bool Lexer::isLess() const {
    return currentType == LESS_TOKEN;
}

bool Lexer::isGreaterOrEquals() const {
    return currentType == GREATER_EQUALS_TOKEN;
}

bool Lexer::isLessOrEquals() const {
    return currentType == LESS_EQUALS_TOKEN;
}

bool Lexer::isIf() const {
    return currentType == IF;
}

bool Lexer::isElse() const {
    return currentType == ELSE;
}

bool Lexer::isBooleanOperator() const {
    return currentType >= EQUALS_TOKEN && currentType <= LESS_EQUALS_TOKEN;
}

bool Lexer::isBoolean() const {
    return currentType == TRUE || currentType == FALSE;
}

bool Lexer::isTrue() const {
    return currentType == TRUE;
}

bool Lexer::isFalse() const {
    return currentType == FALSE;
}
<commit_msg>Remove a useless assignement<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "Lexer.hpp"

using std::pair;
using std::string;
using std::ios_base;

using namespace eddic;

void Lexer::lex(string file) {
	scanner.scan(file);

    currentType = NOTHING;
}

void Lexer::close() {
    scanner.close();
}

bool Lexer::next() {
    if(!buffer.empty()) {
        pair<string, TokenType> old = buffer.top();

        currentToken = old.first;
        currentType = old.second;

        buffer.pop();

        return true;
    } else if(readNext()) {
        read.push(make_pair(currentToken, currentType));

        return true;
    }

    return false;
}

void Lexer::pushBack() {
    pair<string, TokenType> old = read.top();

    buffer.push(old);

    read.pop();
}

bool Lexer::readNext() {
    if(!scanner.next()) {
        return false;
    }

    while(scanner.isSpace()) {
		if(!scanner.next()){
			return false;
		}
	}

    if(scanner.current() == '"') {
        currentToken = string(1, scanner.current());

        while(scanner.next() && scanner.current() != '"') {
            currentToken += scanner.current();
        }

        currentToken += scanner.current();

        currentType = LITTERAL;

        return true;
    } else if(scanner.isAlpha()) {
        currentToken = string(1, scanner.current());

        while(scanner.next() && scanner.isAlpha()) {
            currentToken += scanner.current();
        }

        scanner.pushBack();

        if(currentToken == "true") {
            currentType = TRUE;
        } else if(currentToken == "false") {
            currentType = FALSE;
        } else if(currentToken == "if") {
            currentType = IF;
        } else if(currentToken == "else") {
            currentType = ELSE;
        } else {
            currentType = WORD;
        }

        return true;
    } else if(scanner.isDigit()) {
        currentToken = string(1, scanner.current());

        while(scanner.next() && scanner.isDigit()) {
            currentToken += scanner.current();
        }

        scanner.pushBack();

        currentType = INTEGER;

        return true;
    }

    switch (scanner.current()) {
        case ';':
            currentType = STOP;
            return true;
        case '=':
            scanner.next();

            if(scanner.current() == '=') {
                currentType = EQUALS_TOKEN;
            } else {
                scanner.pushBack();

                currentType = ASSIGN;
            }

            return true;
        case '(':
            currentType = LEFT_PARENTH;
            return true;
        case ')':
            currentType = RIGHT_PARENTH;
            return true;
        case '{':
            currentType = LEFT_BRACE;
            return true;
        case '}':
            currentType = RIGHT_BRACE;
            return true;
        case '+':
            currentType = ADDITION;
            return true;
        case '-':
            currentType = SUBTRACTION;
            return true;
        case '*':
            currentType = MULTIPLICATION;
            return true;
        case '/':
            currentType = DIVISION;
            return true;
        case '%':
            currentType = MODULO;
            return true;
        case '!':
            scanner.next();

            if(scanner.current() == '=') {
                currentType = NOT_EQUALS_TOKEN;
            }

            return false;
        case '<':
            scanner.next();

            if(scanner.current() == '=') {
                scanner.next();

                if(scanner.current() == '>'){
                    currentType = SWAP;
                } else {
                    scanner.pushBack();
                    currentType = LESS_EQUALS_TOKEN;
                }
            } else {
                scanner.pushBack();

                currentType = LESS_TOKEN;
            }

            return true;
        case '>':
            scanner.next();

            if(scanner.current() == '=') {
                currentType = GREATER_EQUALS_TOKEN;
            } else {
                scanner.pushBack();

                currentType = GREATER_TOKEN;
            }

            return true;
    }

    return false;
}

string Lexer::getCurrentToken() const {
    return currentToken;
}

bool Lexer::isWord() const {
    return currentType == WORD;
}

bool Lexer::isLitteral() const {
    return currentType == LITTERAL;
}

bool Lexer::isAssign() const {
    return currentType == ASSIGN;
}

bool Lexer::isSwap() const {
    return currentType == SWAP;
}

bool Lexer::isLeftParenth() const {
    return currentType == LEFT_PARENTH;
}

bool Lexer::isRightParenth() const {
    return currentType == RIGHT_PARENTH;
}

bool Lexer::isLeftBrace() const {
    return currentType == LEFT_BRACE;
}

bool Lexer::isRightBrace() const {
    return currentType == RIGHT_BRACE;
}

bool Lexer::isStop() const {
    return currentType == STOP;
}

bool Lexer::isInteger() const {
    return currentType == INTEGER;
}

bool Lexer::isAddition() const {
    return currentType == ADDITION;
}

bool Lexer::isSubtraction() const {
    return currentType == SUBTRACTION;
}

bool Lexer::isMultiplication() const {
    return currentType == MULTIPLICATION;
}

bool Lexer::isModulo() const {
    return currentType == MODULO;
}

bool Lexer::isDivision() const {
    return currentType == DIVISION;
}

bool Lexer::isEquals() const {
    return currentType == EQUALS_TOKEN;
}

bool Lexer::isNotEquals() const {
    return currentType == NOT_EQUALS_TOKEN;
}

bool Lexer::isGreater() const {
    return currentType == GREATER_TOKEN;
}

bool Lexer::isLess() const {
    return currentType == LESS_TOKEN;
}

bool Lexer::isGreaterOrEquals() const {
    return currentType == GREATER_EQUALS_TOKEN;
}

bool Lexer::isLessOrEquals() const {
    return currentType == LESS_EQUALS_TOKEN;
}

bool Lexer::isIf() const {
    return currentType == IF;
}

bool Lexer::isElse() const {
    return currentType == ELSE;
}

bool Lexer::isBooleanOperator() const {
    return currentType >= EQUALS_TOKEN && currentType <= LESS_EQUALS_TOKEN;
}

bool Lexer::isBoolean() const {
    return currentType == TRUE || currentType == FALSE;
}

bool Lexer::isTrue() const {
    return currentType == TRUE;
}

bool Lexer::isFalse() const {
    return currentType == FALSE;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015, 2016, 2017, 2018, 2019, Intel Corporation
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided with the
 *       distribution.
 *
 *     * Neither the name of Intel Corporation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "MSRIOImp.hpp"

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sstream>
#include <map>

#include "geopm_sched.h"
#include "Exception.hpp"
#include "Helper.hpp"
#include "config.h"

#define GEOPM_IOC_MSR_BATCH _IOWR('c', 0xA2, struct geopm::MSRIOImp::m_msr_batch_array_s)

namespace geopm
{
    std::unique_ptr<MSRIO> MSRIO::make_unique(void)
    {
        return geopm::make_unique<MSRIOImp>();
    }

    std::shared_ptr<MSRIO> MSRIO::make_shared(void)
    {
        return std::make_shared<MSRIOImp>();
    }

    MSRIOImp::MSRIOImp()
        : MSRIOImp(geopm_sched_num_cpu())
    {

    }

    MSRIOImp::MSRIOImp(int num_cpu)
        : m_num_cpu(num_cpu)
        , m_file_desc(m_num_cpu + 1, -1) // Last file descriptor is for the batch file
        , m_is_batch_enabled(true)
        , m_read_batch({0, NULL})
        , m_write_batch({0, NULL})
        , m_read_batch_op(0)
        , m_write_batch_op(0)
    {

    }

    MSRIOImp::~MSRIOImp()
    {
        for (int cpu_idx = 0; cpu_idx < m_num_cpu; ++cpu_idx) {
            close_msr(cpu_idx);
        }
        close_msr_batch();
    }

    uint64_t MSRIOImp::read_msr(int cpu_idx,
                                uint64_t offset)
    {
        uint64_t result = 0;
        size_t num_read = pread(msr_desc(cpu_idx), &result, sizeof(result), offset);
        if (num_read != sizeof(result)) {
            std::ostringstream err_str;
            err_str << "MSRIOImp::read_msr(): pread() failed at offset 0x" << std::hex << offset
                    << " system error: " << strerror(errno);
            throw Exception(err_str.str(), GEOPM_ERROR_MSR_WRITE, __FILE__, __LINE__);
        }
        return result;
    }

    void MSRIOImp::write_msr(int cpu_idx,
                             uint64_t offset,
                             uint64_t raw_value,
                             uint64_t write_mask)
    {
        if ((raw_value & write_mask) != raw_value) {
            std::ostringstream err_str;
            err_str << "MSRIOImp::write_msr(): raw_value does not obey write_mask, "
                    << "raw_value=0x" << std::hex << raw_value
                    << " write_mask=0x" << write_mask;
            throw Exception(err_str.str(), GEOPM_ERROR_INVALID, __FILE__, __LINE__);
        }
        uint64_t write_value = read_msr(cpu_idx, offset);
        write_value &= ~write_mask;
        write_value |= raw_value;
        size_t num_write = pwrite(msr_desc(cpu_idx), &write_value, sizeof(write_value), offset);
        if (num_write != sizeof(write_value)) {
            std::ostringstream err_str;
            err_str << "MSRIOImp::write_msr(): pwrite() failed at offset 0x" << std::hex << offset
                    << " system error: " << strerror(errno);
            throw Exception(err_str.str(), GEOPM_ERROR_MSR_WRITE, __FILE__, __LINE__);
        }
    }

    void MSRIOImp::config_batch(const std::vector<int> &read_cpu_idx,
                                const std::vector<uint64_t> &read_offset,
                                const std::vector<int> &write_cpu_idx,
                                const std::vector<uint64_t> &write_offset,
                                const std::vector<uint64_t> &write_mask)
    {
        if (read_cpu_idx.size() != read_offset.size() ||
            write_cpu_idx.size() != write_offset.size() ||
            write_offset.size() != write_mask.size()) {
            throw Exception("MSRIOImp::config_batch(): Input vector length mismatch",
                            GEOPM_ERROR_INVALID, __FILE__, __LINE__);
        }
        m_read_batch_op.resize(read_cpu_idx.size());
        {
            auto cpu_it = read_cpu_idx.begin();
            auto offset_it = read_offset.begin();
            for (auto batch_it = m_read_batch_op.begin();
                 batch_it != m_read_batch_op.end();
                 ++batch_it, ++cpu_it, ++offset_it) {
                batch_it->cpu = *cpu_it;
                batch_it->isrdmsr = 1;
                batch_it->err = 0;
                batch_it->msr = *offset_it;
                batch_it->msrdata = 0;
                batch_it->wmask = 0;
            }
        }
        m_read_batch.numops = m_read_batch_op.size();
        m_read_batch.ops = m_read_batch_op.data();

        m_write_batch_op.resize(write_cpu_idx.size());
        {
            auto cpu_it = write_cpu_idx.begin();
            auto offset_it = write_offset.begin();
            auto mask_it = write_mask.begin();
            for (auto batch_it = m_write_batch_op.begin();
                 batch_it != m_write_batch_op.end();
                 ++batch_it, ++cpu_it, ++offset_it, ++mask_it) {
                batch_it->cpu = *cpu_it;
                batch_it->isrdmsr = 0;
                batch_it->err = 0;
                batch_it->msr = *offset_it;
                batch_it->msrdata = 0;
                batch_it->wmask = *mask_it;
            }
        }
        m_write_batch.numops = m_write_batch_op.size();
        m_write_batch.ops = m_write_batch_op.data();
    }

    void MSRIOImp::msr_ioctl(bool is_read)
    {
        struct m_msr_batch_array_s *batch_ptr = is_read ? &m_read_batch : &m_write_batch;
        int err = ioctl(msr_batch_desc(), GEOPM_IOC_MSR_BATCH, batch_ptr);
        if (err) {
            throw Exception("MSRIOImp::msr_ioctl(): call to ioctl() for /dev/cpu/msr_batch failed: " +
                            std::string(" system error: ") + strerror(errno),
                            GEOPM_ERROR_MSR_READ, __FILE__, __LINE__);
        }
        for (uint32_t batch_idx = 0; batch_idx != m_write_batch.numops; ++batch_idx) {
            if (m_write_batch.ops[batch_idx].err) {
                std::ostringstream err_str;
                err_str << "MSRIOImp::msr_ioctl(): operation failed at offset 0x"
                        << std::hex << m_write_batch.ops[batch_idx].msr
                        << " system error: " << strerror(m_write_batch.ops[batch_idx].err);
                throw Exception(err_str.str(), GEOPM_ERROR_MSR_WRITE, __FILE__, __LINE__);
            }
        }
    }

    void MSRIOImp::read_batch(std::vector<uint64_t> &raw_value)
    {
        if (raw_value.size() < m_read_batch.numops) {
            raw_value.resize(m_read_batch.numops);
        }
        open_msr_batch();
        if (m_is_batch_enabled) {
            msr_ioctl(true);
            uint32_t batch_idx = 0;
            for (auto raw_it = raw_value.begin();
                 batch_idx != m_read_batch.numops;
                 ++raw_it, ++batch_idx) {
                *raw_it = m_read_batch.ops[batch_idx].msrdata;
            }
        }
        else {
            uint32_t batch_idx = 0;
            for (auto raw_it = raw_value.begin();
                 batch_idx != m_read_batch.numops;
                 ++raw_it, ++batch_idx) {
                *raw_it = read_msr(m_read_batch_op[batch_idx].cpu,
                                   m_read_batch_op[batch_idx].msr);
            }
        }
    }

    void MSRIOImp::write_batch(const std::vector<uint64_t> &raw_value)
    {
        if (raw_value.size() < m_write_batch.numops) {
            throw Exception("MSRIOImp::write_batch(): input vector smaller than configured number of operations",
                            GEOPM_ERROR_INVALID, __FILE__, __LINE__);
        }
        open_msr_batch();
#ifdef GEOPM_ENABLE_MSRSAFE_IOCTL_WRITE
        if (m_is_batch_enabled) {
            uint32_t batch_idx = 0;
            for (auto raw_it = raw_value.begin();
                 batch_idx != m_write_batch.numops;
                 ++raw_it, ++batch_idx) {
                m_write_batch.ops[batch_idx].msrdata = *raw_it;
            }
            msr_ioctl(false);
        }
        else
#endif
        {
            uint32_t batch_idx = 0;
            for (auto raw_it = raw_value.begin();
                 batch_idx != m_write_batch.numops;
                 ++raw_it, ++batch_idx) {
                write_msr(m_write_batch_op[batch_idx].cpu,
                          m_write_batch_op[batch_idx].msr,
                          *raw_it,
                          m_write_batch_op[batch_idx].wmask);
            }
        }
    }

    int MSRIOImp::msr_desc(int cpu_idx)
    {
        if (cpu_idx < 0 || cpu_idx > m_num_cpu) {
            throw Exception("MSRIOImp::msr_desc(): cpu_idx=" + std::to_string(cpu_idx) +
                            " out of range, num_cpu=" + std::to_string(m_num_cpu),
                            GEOPM_ERROR_INVALID, __FILE__, __LINE__);
        }
        open_msr(cpu_idx);
        return m_file_desc[cpu_idx];
    }

    int MSRIOImp::msr_batch_desc()
    {
        return m_file_desc[m_num_cpu];
    }

    void MSRIOImp::msr_path(int cpu_idx,
                            bool is_fallback,
                            std::string &path)
    {
        std::ostringstream msr_path;
        msr_path << "/dev/cpu/" << cpu_idx;
        if (!is_fallback) {
            msr_path << "/msr_safe";
        }
        else {
            msr_path << "/msr";
        }
        path = msr_path.str();
    }

    void MSRIOImp::msr_batch_path(std::string &path)
    {
        path = "/dev/cpu/msr_batch";
    }

    void MSRIOImp::open_msr(int cpu_idx)
    {
        if (m_file_desc[cpu_idx] == -1) {
            std::string path;
            msr_path(cpu_idx, false, path);
            m_file_desc[cpu_idx] = open(path.c_str(), O_RDWR);
            if (m_file_desc[cpu_idx] == -1) {
                errno = 0;
                msr_path(cpu_idx, true, path);
                m_file_desc[cpu_idx] = open(path.c_str(), O_RDWR);
                if (m_file_desc[cpu_idx] == -1) {
                    throw Exception("MSRIOImp::open_msr(): Failed to open \"" + path + "\": " +
                                    "system error: " + strerror(errno),
                                    GEOPM_ERROR_MSR_OPEN, __FILE__, __LINE__);
                }
            }
        }
        struct stat stat_buffer;
        int err = fstat(m_file_desc[cpu_idx], &stat_buffer);
        if (err) {
            throw Exception("MSRIOImp::open_msr(): file descriptor invalid",
                            GEOPM_ERROR_MSR_OPEN, __FILE__, __LINE__);
        }
    }

    void MSRIOImp::open_msr_batch(void)
    {
        if (m_is_batch_enabled && m_file_desc[m_num_cpu] == -1) {
            std::string path;
            msr_batch_path(path);
            m_file_desc[m_num_cpu] = open(path.c_str(), O_RDWR);
            if (m_file_desc[m_num_cpu] == -1) {
                m_is_batch_enabled = false;
            }
        }
        if (m_is_batch_enabled) {
            struct stat stat_buffer;
            int err = fstat(m_file_desc[m_num_cpu], &stat_buffer);
            if (err) {
                throw Exception("MSRIOImp::open_msr_batch(): file descriptor invalid",
                                GEOPM_ERROR_MSR_OPEN, __FILE__, __LINE__);
            }
        }
    }

    void MSRIOImp::close_msr(int cpu_idx)
    {
        if (m_file_desc[cpu_idx] != -1) {
            (void)close(m_file_desc[cpu_idx]);
            m_file_desc[cpu_idx] = -1;
        }
    }

    void MSRIOImp::close_msr_batch(void)
    {
        if (m_file_desc[m_num_cpu] != -1) {
            (void)close(m_file_desc[m_num_cpu]);
            m_file_desc[m_num_cpu] = -1;
        }
    }
}
<commit_msg>Fix error message when MSR read fails<commit_after>/*
 * Copyright (c) 2015, 2016, 2017, 2018, 2019, Intel Corporation
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided with the
 *       distribution.
 *
 *     * Neither the name of Intel Corporation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "MSRIOImp.hpp"

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sstream>
#include <map>

#include "geopm_sched.h"
#include "Exception.hpp"
#include "Helper.hpp"
#include "config.h"

#define GEOPM_IOC_MSR_BATCH _IOWR('c', 0xA2, struct geopm::MSRIOImp::m_msr_batch_array_s)

namespace geopm
{
    std::unique_ptr<MSRIO> MSRIO::make_unique(void)
    {
        return geopm::make_unique<MSRIOImp>();
    }

    std::shared_ptr<MSRIO> MSRIO::make_shared(void)
    {
        return std::make_shared<MSRIOImp>();
    }

    MSRIOImp::MSRIOImp()
        : MSRIOImp(geopm_sched_num_cpu())
    {

    }

    MSRIOImp::MSRIOImp(int num_cpu)
        : m_num_cpu(num_cpu)
        , m_file_desc(m_num_cpu + 1, -1) // Last file descriptor is for the batch file
        , m_is_batch_enabled(true)
        , m_read_batch({0, NULL})
        , m_write_batch({0, NULL})
        , m_read_batch_op(0)
        , m_write_batch_op(0)
    {

    }

    MSRIOImp::~MSRIOImp()
    {
        for (int cpu_idx = 0; cpu_idx < m_num_cpu; ++cpu_idx) {
            close_msr(cpu_idx);
        }
        close_msr_batch();
    }

    uint64_t MSRIOImp::read_msr(int cpu_idx,
                                uint64_t offset)
    {
        uint64_t result = 0;
        size_t num_read = pread(msr_desc(cpu_idx), &result, sizeof(result), offset);
        if (num_read != sizeof(result)) {
            std::ostringstream err_str;
            err_str << "MSRIOImp::read_msr(): pread() failed at offset 0x" << std::hex << offset
                    << " system error: " << strerror(errno);
            throw Exception(err_str.str(), GEOPM_ERROR_MSR_READ, __FILE__, __LINE__);
        }
        return result;
    }

    void MSRIOImp::write_msr(int cpu_idx,
                             uint64_t offset,
                             uint64_t raw_value,
                             uint64_t write_mask)
    {
        if ((raw_value & write_mask) != raw_value) {
            std::ostringstream err_str;
            err_str << "MSRIOImp::write_msr(): raw_value does not obey write_mask, "
                    << "raw_value=0x" << std::hex << raw_value
                    << " write_mask=0x" << write_mask;
            throw Exception(err_str.str(), GEOPM_ERROR_INVALID, __FILE__, __LINE__);
        }
        uint64_t write_value = read_msr(cpu_idx, offset);
        write_value &= ~write_mask;
        write_value |= raw_value;
        size_t num_write = pwrite(msr_desc(cpu_idx), &write_value, sizeof(write_value), offset);
        if (num_write != sizeof(write_value)) {
            std::ostringstream err_str;
            err_str << "MSRIOImp::write_msr(): pwrite() failed at offset 0x" << std::hex << offset
                    << " system error: " << strerror(errno);
            throw Exception(err_str.str(), GEOPM_ERROR_MSR_WRITE, __FILE__, __LINE__);
        }
    }

    void MSRIOImp::config_batch(const std::vector<int> &read_cpu_idx,
                                const std::vector<uint64_t> &read_offset,
                                const std::vector<int> &write_cpu_idx,
                                const std::vector<uint64_t> &write_offset,
                                const std::vector<uint64_t> &write_mask)
    {
        if (read_cpu_idx.size() != read_offset.size() ||
            write_cpu_idx.size() != write_offset.size() ||
            write_offset.size() != write_mask.size()) {
            throw Exception("MSRIOImp::config_batch(): Input vector length mismatch",
                            GEOPM_ERROR_INVALID, __FILE__, __LINE__);
        }
        m_read_batch_op.resize(read_cpu_idx.size());
        {
            auto cpu_it = read_cpu_idx.begin();
            auto offset_it = read_offset.begin();
            for (auto batch_it = m_read_batch_op.begin();
                 batch_it != m_read_batch_op.end();
                 ++batch_it, ++cpu_it, ++offset_it) {
                batch_it->cpu = *cpu_it;
                batch_it->isrdmsr = 1;
                batch_it->err = 0;
                batch_it->msr = *offset_it;
                batch_it->msrdata = 0;
                batch_it->wmask = 0;
            }
        }
        m_read_batch.numops = m_read_batch_op.size();
        m_read_batch.ops = m_read_batch_op.data();

        m_write_batch_op.resize(write_cpu_idx.size());
        {
            auto cpu_it = write_cpu_idx.begin();
            auto offset_it = write_offset.begin();
            auto mask_it = write_mask.begin();
            for (auto batch_it = m_write_batch_op.begin();
                 batch_it != m_write_batch_op.end();
                 ++batch_it, ++cpu_it, ++offset_it, ++mask_it) {
                batch_it->cpu = *cpu_it;
                batch_it->isrdmsr = 0;
                batch_it->err = 0;
                batch_it->msr = *offset_it;
                batch_it->msrdata = 0;
                batch_it->wmask = *mask_it;
            }
        }
        m_write_batch.numops = m_write_batch_op.size();
        m_write_batch.ops = m_write_batch_op.data();
    }

    void MSRIOImp::msr_ioctl(bool is_read)
    {
        struct m_msr_batch_array_s *batch_ptr = is_read ? &m_read_batch : &m_write_batch;
        int err = ioctl(msr_batch_desc(), GEOPM_IOC_MSR_BATCH, batch_ptr);
        if (err) {
            throw Exception("MSRIOImp::msr_ioctl(): call to ioctl() for /dev/cpu/msr_batch failed: " +
                            std::string(" system error: ") + strerror(errno),
                            GEOPM_ERROR_MSR_READ, __FILE__, __LINE__);
        }
        for (uint32_t batch_idx = 0; batch_idx != m_write_batch.numops; ++batch_idx) {
            if (m_write_batch.ops[batch_idx].err) {
                std::ostringstream err_str;
                err_str << "MSRIOImp::msr_ioctl(): operation failed at offset 0x"
                        << std::hex << m_write_batch.ops[batch_idx].msr
                        << " system error: " << strerror(m_write_batch.ops[batch_idx].err);
                throw Exception(err_str.str(), GEOPM_ERROR_MSR_WRITE, __FILE__, __LINE__);
            }
        }
    }

    void MSRIOImp::read_batch(std::vector<uint64_t> &raw_value)
    {
        if (raw_value.size() < m_read_batch.numops) {
            raw_value.resize(m_read_batch.numops);
        }
        open_msr_batch();
        if (m_is_batch_enabled) {
            msr_ioctl(true);
            uint32_t batch_idx = 0;
            for (auto raw_it = raw_value.begin();
                 batch_idx != m_read_batch.numops;
                 ++raw_it, ++batch_idx) {
                *raw_it = m_read_batch.ops[batch_idx].msrdata;
            }
        }
        else {
            uint32_t batch_idx = 0;
            for (auto raw_it = raw_value.begin();
                 batch_idx != m_read_batch.numops;
                 ++raw_it, ++batch_idx) {
                *raw_it = read_msr(m_read_batch_op[batch_idx].cpu,
                                   m_read_batch_op[batch_idx].msr);
            }
        }
    }

    void MSRIOImp::write_batch(const std::vector<uint64_t> &raw_value)
    {
        if (raw_value.size() < m_write_batch.numops) {
            throw Exception("MSRIOImp::write_batch(): input vector smaller than configured number of operations",
                            GEOPM_ERROR_INVALID, __FILE__, __LINE__);
        }
        open_msr_batch();
#ifdef GEOPM_ENABLE_MSRSAFE_IOCTL_WRITE
        if (m_is_batch_enabled) {
            uint32_t batch_idx = 0;
            for (auto raw_it = raw_value.begin();
                 batch_idx != m_write_batch.numops;
                 ++raw_it, ++batch_idx) {
                m_write_batch.ops[batch_idx].msrdata = *raw_it;
            }
            msr_ioctl(false);
        }
        else
#endif
        {
            uint32_t batch_idx = 0;
            for (auto raw_it = raw_value.begin();
                 batch_idx != m_write_batch.numops;
                 ++raw_it, ++batch_idx) {
                write_msr(m_write_batch_op[batch_idx].cpu,
                          m_write_batch_op[batch_idx].msr,
                          *raw_it,
                          m_write_batch_op[batch_idx].wmask);
            }
        }
    }

    int MSRIOImp::msr_desc(int cpu_idx)
    {
        if (cpu_idx < 0 || cpu_idx > m_num_cpu) {
            throw Exception("MSRIOImp::msr_desc(): cpu_idx=" + std::to_string(cpu_idx) +
                            " out of range, num_cpu=" + std::to_string(m_num_cpu),
                            GEOPM_ERROR_INVALID, __FILE__, __LINE__);
        }
        open_msr(cpu_idx);
        return m_file_desc[cpu_idx];
    }

    int MSRIOImp::msr_batch_desc()
    {
        return m_file_desc[m_num_cpu];
    }

    void MSRIOImp::msr_path(int cpu_idx,
                            bool is_fallback,
                            std::string &path)
    {
        std::ostringstream msr_path;
        msr_path << "/dev/cpu/" << cpu_idx;
        if (!is_fallback) {
            msr_path << "/msr_safe";
        }
        else {
            msr_path << "/msr";
        }
        path = msr_path.str();
    }

    void MSRIOImp::msr_batch_path(std::string &path)
    {
        path = "/dev/cpu/msr_batch";
    }

    void MSRIOImp::open_msr(int cpu_idx)
    {
        if (m_file_desc[cpu_idx] == -1) {
            std::string path;
            msr_path(cpu_idx, false, path);
            m_file_desc[cpu_idx] = open(path.c_str(), O_RDWR);
            if (m_file_desc[cpu_idx] == -1) {
                errno = 0;
                msr_path(cpu_idx, true, path);
                m_file_desc[cpu_idx] = open(path.c_str(), O_RDWR);
                if (m_file_desc[cpu_idx] == -1) {
                    throw Exception("MSRIOImp::open_msr(): Failed to open \"" + path + "\": " +
                                    "system error: " + strerror(errno),
                                    GEOPM_ERROR_MSR_OPEN, __FILE__, __LINE__);
                }
            }
        }
        struct stat stat_buffer;
        int err = fstat(m_file_desc[cpu_idx], &stat_buffer);
        if (err) {
            throw Exception("MSRIOImp::open_msr(): file descriptor invalid",
                            GEOPM_ERROR_MSR_OPEN, __FILE__, __LINE__);
        }
    }

    void MSRIOImp::open_msr_batch(void)
    {
        if (m_is_batch_enabled && m_file_desc[m_num_cpu] == -1) {
            std::string path;
            msr_batch_path(path);
            m_file_desc[m_num_cpu] = open(path.c_str(), O_RDWR);
            if (m_file_desc[m_num_cpu] == -1) {
                m_is_batch_enabled = false;
            }
        }
        if (m_is_batch_enabled) {
            struct stat stat_buffer;
            int err = fstat(m_file_desc[m_num_cpu], &stat_buffer);
            if (err) {
                throw Exception("MSRIOImp::open_msr_batch(): file descriptor invalid",
                                GEOPM_ERROR_MSR_OPEN, __FILE__, __LINE__);
            }
        }
    }

    void MSRIOImp::close_msr(int cpu_idx)
    {
        if (m_file_desc[cpu_idx] != -1) {
            (void)close(m_file_desc[cpu_idx]);
            m_file_desc[cpu_idx] = -1;
        }
    }

    void MSRIOImp::close_msr_batch(void)
    {
        if (m_file_desc[m_num_cpu] != -1) {
            (void)close(m_file_desc[m_num_cpu]);
            m_file_desc[m_num_cpu] = -1;
        }
    }
}
<|endoftext|>