<commit_before>// Copyright 2013 Sean McKenna
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
//

// object sub-classes (e.g. sphere, plane, triangular mesh OBJ)

// import triangular mesh & BVH storage class
#include "cyCodeBase/cyTriMesh.h"
#include "cyCodeBase/cyBVH.h"

// namespace
using namespace scene;

// Sphere definition
class Sphere: public Object{
  public:

    // constructor
    Sphere(){
      center.Set(0, 0, 0);
      radius = 1.0;
    }

    // intsersect a ray against the unit sphere
    // ray must be transformed into model space, first
    bool intersectRay(Ray &r, HitInfo &h, int face=HIT_FRONT){

      // pre-compute values for quadratic solution
      Point pos = r.pos - center;
      float A = r.dir % r.dir;
      float B = 2.0 * pos % r.dir;
      float C = pos % pos - radius * radius;
      float det = (B * B) - (4 * A * C);

      // if the ray intersects, compute the z-buffer value
      if(det >= 0){
        float z1 = (-B - sqrt(det)) / (2.0 * A);
        float z2 = (-B + sqrt(det)) / (2.0 * A);

        // determine if we have a back hit
        if(z1 * z2 < 0.0)
          h.front = false;

        // if hit is too close, assume it is a back-face hit
        else if(z1 <= getBias())
          h.front = false;

        // check closest z-buffer value, if positive (ahead of our ray)
        if(z1 > getBias()){
          h.z = z1;

          // compute surface intersection and normal
          h.p = r.pos + z1 * r.dir;
          h.n = h.p.GetNormalized();

          // return true, ray is hit
          return true;

        // check the next ray, if necessary
        }else if(z2 > getBias()){
          h.z = z2;

          // compute surface intersection and normal
          h.p = r.pos + z2 * r.dir;
          h.n = h.p.GetNormalized();

          // return true, ray is hit
          return true;

        // otherwise, all z-buffer values are negative, return false
        }else
          return false;
      }

      // otherwise, return false (no ray hit)
      else
        return false;
    }

    // get sphere bounding box
    BoundingBox getBoundBox(){
      return BoundingBox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0);
    }

  private:

    // sphere center and its radius
    Point center;
    float radius;
};

// Plane definition (a "unit" plane)
class Plane: public Object{
  public:

    // intersect a ray against the "unit" plane
    bool intersectRay(Ray &r, HitInfo &h, int face = HIT_FRONT){

      // only compute for rays not parallel to the unit plane
      if(r.dir.z > getBias() || r.dir.z < getBias()){

        // compute distance along ray direction to plane
        float t = -r.pos.z / r.dir.z;

        // only accept hits in front of ray (with some bias)
        if(t > getBias()){

          // compute the hit point
          Point hit = r.pos + t * r.dir;

          // only allow a hit to occur if on the "unit" plane
          if(hit.x >= -1.0 && hit.y >= -1.0 && hit.x <= 1.0 && hit.y <= 1.0){

            // detect back face hits
            if(r.pos.z < 0.0)
              h.front = false;

            // distance to hit
            h.z = t;

            // set hit point, normal, and return hit info
            h.p = hit;
            h.n = Point(0.0, 0.0, 1.0);
            return true;
          }
        }
      }

      // when no ray hits the "unit" plane
      return false;
    }

    // get plane bounding box
    BoundingBox getBoundBox(){
      return BoundingBox(-1.0, -1.0, 0.0, 1.0, 1.0, 0.0);
    }
};

// Triangular Mesh Object definition (from an OBJ file)
class TriObj: public Object, private cyTriMesh{
  public:

    // intersect a ray against the triangular mesh
    bool intersectRay(Ray &r, HitInfo &h, int face = HIT_FRONT){

      // check our BVH for triangular faces, update hit info
      bool triang = traceBVHNode(r, h, face, bvh.GetRootNodeID());

      // return hit info from intersecting rays in the BVH faces
      return triang;
    }

    // get triangular mesh bounding box
    BoundingBox getBoundBox(){
      return BoundingBox(GetBoundMin(), GetBoundMax());
    }

    // when loading a triangular mesh, get its bounding box
    bool load(const char *file){
      bvh.Clear();
      if(!LoadFromFileObj(file))
        return false;
      if(!HasNormals())
        ComputeNormals();
      ComputeBoundingBox();
      bvh.SetMesh(this,4);
      return true;
    }

  private:

    // add BVH for each triangular mesh
    cyBVHTriMesh bvh;

    // intersect a ray with a single triangle (Moller-Trumbore algorithm)
    bool intersectTriangle(Ray &r, HitInfo &h, int face, int faceID){

      bool mt = false;

      if(mt){

      // grab vertex points
      Point a = V(F(faceID).v[0]);
      Point b = V(F(faceID).v[1]);
      Point c = V(F(faceID).v[2]);

      // compute edge vectors
      Point e1 = b - a;
      Point e2 = c - a;

      // calculate first vector, P
      Point P = r.dir ^ e2;

      // calculate the determinant of the matrix equation
      float determ = e1 % P;

      // only continue for valid determinant ranges
      if(abs(determ) > getBias()){

        // calculate second vector, T
        Point T = r.pos - a;

        // calculate a barycentric component (u)
        float u = T % P;

        // only allow valid barycentric values
        if(u > -getBias() && u < determ * (1.0 + getBias())){

          // calculate a normal of the ray with an edge vector
          Point Q = T ^ e1;

          // calculate a barycentric component (v)
          float v = r.dir % Q;

          // only allow valid barycentric values
          if(v > -getBias() && v + u < determ * (1.0 + getBias())){

            // update barycentric coordinates
            v /= determ;
            u /= determ;

            // compute the barycentric coordinates for interpolating values
            Point bc = Point(1.0 - u - v, u, v);

            // calculate the distance to hit the triangle
            float t = (e2 % Q) / determ;

            // only allow valid distances to hit
            if(t > getBias() && t < h.z){

              // distance to hit
              h.z = t;

              // set hit point, normal
              h.p = GetPoint(faceID, bc);
              h.n = GetNormal(faceID, bc);

              // detect back face hits
              if(determ < 0.0)
                h.front = false;

              // return hit info
              return true;
            }
          }
        }
      }

      // when no ray hits the triangular face
      return false;

      // normal ray tracing
      }else{

      // ignore rays nearly parallel to surface
      Point n = VN(faceID);
      if(r.dir % n > getBias() || r.dir % n < -getBias()){

        // compute distance along ray direction to plane
        Point a = V(F(faceID).v[0]);
        float t = -((r.pos - a) % n) / (r.dir % n);

        // only accept hits in front of ray (with some bias) & closer hits
        if(t > getBias() && t < h.z){

          // compute hit point
          Point hit = r.pos + t * r.dir;

          // grab vertex points
          Point b = V(F(faceID).v[1]);
          Point c = V(F(faceID).v[2]);

          // simplify problem into 2D by removing the greatest normal component
          Point2 a2;
          Point2 b2;
          Point2 c2;
          Point2 hit2;
          if(abs(n.x) > abs(n.y) && abs(n.x) > abs(n.z)){
            a2 = Point2(a.y, a.z);
            b2 = Point2(b.y, b.z);
            c2 = Point2(c.y, c.z);
            hit2 = Point2(hit.y, hit.z);
          }else if(abs(n.y) > abs(n.x) && abs(n.y) > abs(n.z)){
            a2 = Point2(a.x, a.z);
            b2 = Point2(b.x, b.z);
            c2 = Point2(c.x, c.z);
            hit2 = Point2(hit.x, hit.z);
          }else{
            a2 = Point2(a.x, a.y);
            b2 = Point2(b.x, b.y);
            c2 = Point2(c.x, c.y);
            hit2 = Point2(hit.x, hit.y);
          }

          // compute the area of the triangular face (in 2D)
          float area = (b2 - a2) ^ (c2 - a2);

          // compute smaller areas of the face, relative to the full area, in 2D
          // ensure that we are only calculating positive areas
          // aka, computation of the barycentric coordinates
          float alpha = ((b2 - a2) ^ (hit2 - a2)) / area;
          if(alpha > -getBias() && alpha < 1.0 + getBias()){
            float beta = ((hit2 - a2) ^ (c2 - a2)) / area;
            if(beta > -getBias() && beta < 1.0 + getBias()){
              if(alpha + beta < 1.0 + getBias()){

                // interpolate the normal based on barycentric coordinates
                Point bc = Point(1.0 - alpha - beta, beta, alpha);

                // distance to hit
                h.z = t;

                // set hit point, normal
                h.p = GetPoint(faceID, bc);
                h.n = GetNormal(faceID, bc);

                // detect back face hits
                if(r.dir % h.n < 0.0)
                  h.front = false;

                // return hit info
                return true;
              }
            }
          }
        }
      }

      // when no ray hits the triangular face
      return false;

      }
    }

    // cast a ray into a BVH node, seeing which triangular faces may get hit
    bool traceBVHNode(Ray &r, HitInfo &h, int face, int nodeID){

      // grab node's bounding box
      BoundingBox b = BoundingBox(bvh.GetNodeBounds(nodeID));

      // does ray hit the node bounding box?
      bool hit = b.intersectRay(r, h.z);

      // recurse through child nodes if we hit node
      if(hit){

        // only recursively call function if not at a leaf node
        if(!bvh.IsLeafNode(nodeID)){

          // keep traversing the BVH hierarchy for hits
          int c1 = bvh.GetFirstChildNode(nodeID);
          int c2 = bvh.GetSecondChildNode(nodeID);
          bool hit1 = traceBVHNode(r, h, face, c1);
          bool hit2 = traceBVHNode(r, h, face, c2);

          // if we get no hit
          if(!hit1 && !hit2)
            hit = false;

        // for leaf nodes, trace ray into each triangular face
        }else{

          // get triangular faces of the hit BVH node
          const unsigned int* faces = bvh.GetNodeElements(nodeID);
          int size = bvh.GetNodeElementCount(nodeID);

          // trace the ray into each triangular face, tracking hits
          hit = false;
          for(int i = 0; i < size; i++){
            bool hit1 = intersectTriangle(r, h, face, faces[i]);
            if(!hit && hit1)
              hit = true;
          }
        }
      }

      // return if we hit a face within this node
      return hit;
    }
};
<commit_msg>fix initial bugs in ray-tracing algorithm<commit_after>// Copyright 2013 Sean McKenna
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
//

// object sub-classes (e.g. sphere, plane, triangular mesh OBJ)

// import triangular mesh & BVH storage class
#include "cyCodeBase/cyTriMesh.h"
#include "cyCodeBase/cyBVH.h"

// namespace
using namespace scene;

// Sphere definition
class Sphere: public Object{
  public:

    // constructor
    Sphere(){
      center.Set(0, 0, 0);
      radius = 1.0;
    }

    // intsersect a ray against the unit sphere
    // ray must be transformed into model space, first
    bool intersectRay(Ray &r, HitInfo &h, int face=HIT_FRONT){

      // pre-compute values for quadratic solution
      Point pos = r.pos - center;
      float A = r.dir % r.dir;
      float B = 2.0 * pos % r.dir;
      float C = pos % pos - radius * radius;
      float det = (B * B) - (4 * A * C);

      // if the ray intersects, compute the z-buffer value
      if(det >= 0){
        float z1 = (-B - sqrt(det)) / (2.0 * A);
        float z2 = (-B + sqrt(det)) / (2.0 * A);

        // determine if we have a back hit
        if(z1 * z2 < 0.0)
          h.front = false;

        // if hit is too close, assume it is a back-face hit
        else if(z1 <= getBias())
          h.front = false;

        // check closest z-buffer value, if positive (ahead of our ray)
        if(z1 > getBias()){
          h.z = z1;

          // compute surface intersection and normal
          h.p = r.pos + z1 * r.dir;
          h.n = h.p.GetNormalized();

          // return true, ray is hit
          return true;

        // check the next ray, if necessary
        }else if(z2 > getBias()){
          h.z = z2;

          // compute surface intersection and normal
          h.p = r.pos + z2 * r.dir;
          h.n = h.p.GetNormalized();

          // return true, ray is hit
          return true;

        // otherwise, all z-buffer values are negative, return false
        }else
          return false;
      }

      // otherwise, return false (no ray hit)
      else
        return false;
    }

    // get sphere bounding box
    BoundingBox getBoundBox(){
      return BoundingBox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0);
    }

  private:

    // sphere center and its radius
    Point center;
    float radius;
};

// Plane definition (a "unit" plane)
class Plane: public Object{
  public:

    // intersect a ray against the "unit" plane
    bool intersectRay(Ray &r, HitInfo &h, int face = HIT_FRONT){

      // only compute for rays not parallel to the unit plane
      if(r.dir.z > getBias() || r.dir.z < getBias()){

        // compute distance along ray direction to plane
        float t = -r.pos.z / r.dir.z;

        // only accept hits in front of ray (with some bias)
        if(t > getBias()){

          // compute the hit point
          Point hit = r.pos + t * r.dir;

          // only allow a hit to occur if on the "unit" plane
          if(hit.x >= -1.0 && hit.y >= -1.0 && hit.x <= 1.0 && hit.y <= 1.0){

            // detect back face hits
            if(r.pos.z < 0.0)
              h.front = false;

            // distance to hit
            h.z = t;

            // set hit point, normal, and return hit info
            h.p = hit;
            h.n = Point(0.0, 0.0, 1.0);
            return true;
          }
        }
      }

      // when no ray hits the "unit" plane
      return false;
    }

    // get plane bounding box
    BoundingBox getBoundBox(){
      return BoundingBox(-1.0, -1.0, 0.0, 1.0, 1.0, 0.0);
    }
};

// Triangular Mesh Object definition (from an OBJ file)
class TriObj: public Object, private cyTriMesh{
  public:

    // intersect a ray against the triangular mesh
    bool intersectRay(Ray &r, HitInfo &h, int face = HIT_FRONT){

      // check our BVH for triangular faces, update hit info
      bool triang = traceBVHNode(r, h, face, bvh.GetRootNodeID());

      // return hit info from intersecting rays in the BVH faces
      return triang;
    }

    // get triangular mesh bounding box
    BoundingBox getBoundBox(){
      return BoundingBox(GetBoundMin(), GetBoundMax());
    }

    // when loading a triangular mesh, get its bounding box
    bool load(const char *file){
      bvh.Clear();
      if(!LoadFromFileObj(file))
        return false;
      if(!HasNormals())
        ComputeNormals();
      ComputeBoundingBox();
      bvh.SetMesh(this,4);
      return true;
    }

  private:

    // add BVH for each triangular mesh
    cyBVHTriMesh bvh;

    // intersect a ray with a single triangle (Moller-Trumbore algorithm)
    bool intersectTriangle(Ray &r, HitInfo &h, int face, int faceID){

      bool mt = false;

      if(mt){

      // grab vertex points
      Point a = V(F(faceID).v[0]);
      Point b = V(F(faceID).v[1]);
      Point c = V(F(faceID).v[2]);

      // compute edge vectors
      Point e1 = b - a;
      Point e2 = c - a;

      // calculate first vector, P
      Point P = r.dir ^ e2;

      // calculate the determinant of the matrix equation
      float determ = e1 % P;

      // only continue for valid determinant ranges
      if(abs(determ) > getBias()){

        // calculate second vector, T
        Point T = r.pos - a;

        // calculate a barycentric component (u)
        float u = T % P;

        // only allow valid barycentric values
        if(u > -getBias() && u < determ * (1.0 + getBias())){

          // calculate a normal of the ray with an edge vector
          Point Q = T ^ e1;

          // calculate a barycentric component (v)
          float v = r.dir % Q;

          // only allow valid barycentric values
          if(v > -getBias() && v + u < determ * (1.0 + getBias())){

            // update barycentric coordinates
            v /= determ;
            u /= determ;

            // compute the barycentric coordinates for interpolating values
            Point bc = Point(1.0 - u - v, u, v);

            // calculate the distance to hit the triangle
            float t = (e2 % Q) / determ;

            // only allow valid distances to hit
            if(t > getBias() && t < h.z){

              // distance to hit
              h.z = t;

              // set hit point, normal
              h.p = GetPoint(faceID, bc);
              h.n = GetNormal(faceID, bc);

              // detect back face hits
              if(determ < 0.0)
                h.front = false;

              // return hit info
              return true;
            }
          }
        }
      }

      // when no ray hits the triangular face
      return false;

      // normal ray tracing
      }else{

      // ignore rays nearly parallel to surface
      Point a = V(F(faceID).v[0]);
      Point b = V(F(faceID).v[1]);
      Point c = V(F(faceID).v[2]);
      Point n = (b - a) ^ (c - a);
      if(r.dir % n > getBias() || r.dir % n < -getBias()){

        // compute distance along ray direction to plane
        Point a = V(F(faceID).v[0]);
        float t = -((r.pos - a) % n) / (r.dir % n);

        // only accept hits in front of ray (with some bias) & closer hits
        if(t > getBias() && t < h.z){

          // compute hit point
          Point hit = r.pos + t * r.dir;

          // simplify problem into 2D by removing the greatest normal component
          Point2 a2;
          Point2 b2;
          Point2 c2;
          Point2 hit2;
          if(abs(n.x) > abs(n.y) && abs(n.x) > abs(n.z)){
            a2 = Point2(a.y, a.z);
            b2 = Point2(b.y, b.z);
            c2 = Point2(c.y, c.z);
            hit2 = Point2(hit.y, hit.z);
          }else if(abs(n.y) > abs(n.x) && abs(n.y) > abs(n.z)){
            a2 = Point2(a.x, a.z);
            b2 = Point2(b.x, b.z);
            c2 = Point2(c.x, c.z);
            hit2 = Point2(hit.x, hit.z);
          }else{
            a2 = Point2(a.x, a.y);
            b2 = Point2(b.x, b.y);
            c2 = Point2(c.x, c.y);
            hit2 = Point2(hit.x, hit.y);
          }

          // compute the area of the triangular face (in 2D)
          float area = (b2 - a2) ^ (c2 - a2);

          // compute smaller areas of the face, relative to the full area, in 2D
          // ensure that we are only calculating positive areas
          // aka, computation of the barycentric coordinates
          float alpha = ((b2 - a2) ^ (hit2 - a2)) / area;
          if(alpha > -getBias() && alpha < 1.0 + getBias()){
            float beta = ((hit2 - a2) ^ (c2 - a2)) / area;
            if(beta > -getBias() && beta < 1.0 + getBias()){
              if(alpha + beta < 1.0 + getBias()){

                // interpolate the normal based on barycentric coordinates
                Point bc = Point(1.0 - alpha - beta, beta, alpha);

                // distance to hit
                h.z = t;

                // set hit point, normal
                h.p = GetPoint(faceID, bc);
                h.n = GetNormal(faceID, bc);

                // detect back face hits
                if(r.dir % h.n > 0.0)
                  h.front = false;

                // return hit info
                return true;
              }
            }
          }
        }
      }

      // when no ray hits the triangular face
      return false;

      }
    }

    // cast a ray into a BVH node, seeing which triangular faces may get hit
    bool traceBVHNode(Ray &r, HitInfo &h, int face, int nodeID){

      // grab node's bounding box
      BoundingBox b = BoundingBox(bvh.GetNodeBounds(nodeID));

      // does ray hit the node bounding box?
      bool hit = b.intersectRay(r, h.z);

      // recurse through child nodes if we hit node
      if(hit){

        // only recursively call function if not at a leaf node
        if(!bvh.IsLeafNode(nodeID)){

          // keep traversing the BVH hierarchy for hits
          int c1 = bvh.GetFirstChildNode(nodeID);
          int c2 = bvh.GetSecondChildNode(nodeID);
          bool hit1 = traceBVHNode(r, h, face, c1);
          bool hit2 = traceBVHNode(r, h, face, c2);

          // if we get no hit
          if(!hit1 && !hit2)
            hit = false;

        // for leaf nodes, trace ray into each triangular face
        }else{

          // get triangular faces of the hit BVH node
          const unsigned int* faces = bvh.GetNodeElements(nodeID);
          int size = bvh.GetNodeElementCount(nodeID);

          // trace the ray into each triangular face, tracking hits
          hit = false;
          for(int i = 0; i < size; i++){
            bool hit1 = intersectTriangle(r, h, face, faces[i]);
            if(!hit && hit1)
              hit = true;
          }
        }
      }

      // return if we hit a face within this node
      return hit;
    }
};
<|endoftext|>


<commit_before>/*
 Copyright 2016 Nervana Systems Inc.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

#include <algorithm>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

#include "manifest.hpp"

using namespace std;

Manifest::Manifest(string filename, const bool shuffle)
: _filename(filename), _shuffle(shuffle) {
    // for now parse the entire manifest on creation
    parse();
}

string Manifest::hash() {
    // TODO
    return "42";
}

void Manifest::parse() {
    ifstream infile(_filename);

    if(!infile.is_open()) {
        stringstream ss;
        ss << "Manifest file " << _filename << " doesnt exit.";
        throw std::runtime_error(ss.str());
    }

    parseStream(infile);
}

size_t Manifest::getSize() const {
    return _filename_pairs.size();
}

void Manifest::parseStream(istream& is) {
    // parse istream is and load the entire thing into _filename_pairs
    string line;
    pair<string, string> filename_pair;

    // TODO: could probably do this more cleanly ...
    while(std::getline(is, line)) {
        istringstream lineis(line);
        std::getline(lineis, filename_pair.first, ',');
        std::getline(lineis, filename_pair.second);

        _filename_pairs.push_back(filename_pair);
    }

    // TODO: only optionally shuffle.  If we don't need to shuffle,
    // there may be small performance benefits in some situations to
    // stream the filename_pairs instead of loading them all at once.
    // That said, in the event that there is no cache and we are
    // resuming training at a specific epoch, we may need to be able to
    // jump around and read random blocks of the file, so a purely
    // stream based interface is not sufficient.
    if(_shuffle) {
        shuffleFilenamePairs();
    }
}

void Manifest::shuffleFilenamePairs() {
    // shuffles _filename_pairs.  It is possible that the order of the
    // filenames in the manifest file were in some sorted order and we
    // don't want our blocks to be biased by that order.
    std::random_device rd;
    std::shuffle(_filename_pairs.begin(), _filename_pairs.end(), std::mt19937(rd()));
}

Manifest::iter Manifest::begin() const {
    return _filename_pairs.begin();
}

Manifest::iter Manifest::end() const {
    return _filename_pairs.end();
}
<commit_msg>fix comment<commit_after>/*
 Copyright 2016 Nervana Systems Inc.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

#include <algorithm>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

#include "manifest.hpp"

using namespace std;

Manifest::Manifest(string filename, const bool shuffle)
: _filename(filename), _shuffle(shuffle) {
    // for now parse the entire manifest on creation
    parse();
}

string Manifest::hash() {
    // TODO
    return "42";
}

void Manifest::parse() {
    ifstream infile(_filename);

    if(!infile.is_open()) {
        stringstream ss;
        ss << "Manifest file " << _filename << " doesnt exit.";
        throw std::runtime_error(ss.str());
    }

    parseStream(infile);
}

size_t Manifest::getSize() const {
    return _filename_pairs.size();
}

void Manifest::parseStream(istream& is) {
    // parse istream is and load the entire thing into _filename_pairs
    string line;
    pair<string, string> filename_pair;

    // read in each line, then from that istringstream, read in up to
    // the comma, then everything after.
    while(std::getline(is, line)) {
        istringstream lineis(line);
        std::getline(lineis, filename_pair.first, ',');
        std::getline(lineis, filename_pair.second);

        _filename_pairs.push_back(filename_pair);
    }

    // If we don't need to shuffle, there may be small performance
    // benefits in some situations to stream the filename_pairs instead
    // of loading them all at once.  That said, in the event that there
    // is no cache and we are resuming training at a specific epoch, we
    // may need to be able to jump around and read random blocks of the
    // file, so a purely stream based interface is not sufficient.
    if(_shuffle) {
        shuffleFilenamePairs();
    }
}

void Manifest::shuffleFilenamePairs() {
    // shuffles _filename_pairs.  It is possible that the order of the
    // filenames in the manifest file were in some sorted order and we
    // don't want our blocks to be biased by that order.
    std::random_device rd;
    std::shuffle(_filename_pairs.begin(), _filename_pairs.end(), std::mt19937(rd()));
}

Manifest::iter Manifest::begin() const {
    return _filename_pairs.begin();
}

Manifest::iter Manifest::end() const {
    return _filename_pairs.end();
}
<|endoftext|>


<commit_before>#include "ASCIIShade.h"
#include <iostream>
using namespace std;

namespace Math {

const static int kNumAsciiShades = 15;
const static char kAsciiShades[15] = {
  'W',
  'w',
  '#',
  '%',
  '&',
  '*',
  '+',
  ' ',  //0 is element 7
  '.',
  ':',
  'o',
  '0',
  '8',
  'O',
  '@',
};

char ASCIIShade(double x)
{
  if(IsNaN(x)) return 'E';
  if(IsInf(x)==1) return 'I';
  else if(IsInf(x)==-1) return 'i';
  int index = (int)Trunc(x*8) + 7;
  if(index < 0) index=0;
  if(index >= kNumAsciiShades) index=kNumAsciiShades-1;
  if(index == 7) {
    if(x > 0) return kAsciiShades[8];
    else if(x < 0) return kAsciiShades[6];
    else return kAsciiShades[7];
  }
  return kAsciiShades[index];
}

void OutputASCIIShade(ostream& out,double x)
{
  out<<ASCIIShade(x);
}

void OutputASCIIShade(ostream& out,const fVector& x,float scale)
{
  if(scale == 0) scale = x.maxAbsElement();
  out<<scale<<" x ";
  if(scale == 0) scale = 1;
  out<<'[';
  for(int i=0;i<x.n;i++)
    out<<ASCIIShade(x(i)/scale);
  out<<']';
}

void OutputASCIIShade(ostream& out,const dVector& x,double scale)
{
  if(scale == 0) scale = x.maxAbsElement();
  out<<scale<<" x ";
  if(scale == 0) scale = 1;
  out<<'[';
  for(int i=0;i<x.n;i++)
    out<<ASCIIShade(x(i)/scale);
  out<<']';
}

void OutputASCIIShade(ostream& out,const fMatrix& A,float scale,int indent)
{
  if(scale == 0) scale = A.maxAbsElement();
  out<<scale<<" x"<<endl;
  if(scale == 0) scale = 1;
  for(int i=0;i<A.m;i++) {
    if(i && indent) out<<string(indent,' ');
    out<<'[';
    for(int j=0;j<A.n;j++)
      out<<ASCIIShade(A(i,j)/scale);
    out<<']';
    if(i+1 < A.m)
      out<<endl;
  }
}

void OutputASCIIShade(ostream& out,const dMatrix& A,double scale,int indent)
{
  if(scale == 0) scale = A.maxAbsElement();
  out<<scale<<" x"<<endl;
  if(scale == 0) scale = 1;
  for(int i=0;i<A.m;i++) {
    if(i && indent) out<<string(indent,' ');
    out<<'[';
    for(int j=0;j<A.n;j++)
      out<<ASCIIShade(A(i,j)/scale);
    out<<']';
    if(i+1 < A.m)
      out<<endl;
  }
}

} //namespace Math
<commit_msg>Added <string> include for MSVC<commit_after>#include "ASCIIShade.h"
#include <iostream>
#include <string>
using namespace std;

namespace Math {

const static int kNumAsciiShades = 15;
const static char kAsciiShades[15] = {
  'W',
  'w',
  '#',
  '%',
  '&',
  '*',
  '+',
  ' ',  //0 is element 7
  '.',
  ':',
  'o',
  '0',
  '8',
  'O',
  '@',
};

char ASCIIShade(double x)
{
  if(IsNaN(x)) return 'E';
  if(IsInf(x)==1) return 'I';
  else if(IsInf(x)==-1) return 'i';
  int index = (int)Trunc(x*8) + 7;
  if(index < 0) index=0;
  if(index >= kNumAsciiShades) index=kNumAsciiShades-1;
  if(index == 7) {
    if(x > 0) return kAsciiShades[8];
    else if(x < 0) return kAsciiShades[6];
    else return kAsciiShades[7];
  }
  return kAsciiShades[index];
}

void OutputASCIIShade(ostream& out,double x)
{
  out<<ASCIIShade(x);
}

void OutputASCIIShade(ostream& out,const fVector& x,float scale)
{
  if(scale == 0) scale = x.maxAbsElement();
  out<<scale<<" x ";
  if(scale == 0) scale = 1;
  out<<'[';
  for(int i=0;i<x.n;i++)
    out<<ASCIIShade(x(i)/scale);
  out<<']';
}

void OutputASCIIShade(ostream& out,const dVector& x,double scale)
{
  if(scale == 0) scale = x.maxAbsElement();
  out<<scale<<" x ";
  if(scale == 0) scale = 1;
  out<<'[';
  for(int i=0;i<x.n;i++)
    out<<ASCIIShade(x(i)/scale);
  out<<']';
}

void OutputASCIIShade(ostream& out,const fMatrix& A,float scale,int indent)
{
  if(scale == 0) scale = A.maxAbsElement();
  out<<scale<<" x"<<endl;
  if(scale == 0) scale = 1;
  for(int i=0;i<A.m;i++) {
    if(i && indent) out<<string(indent,' ');
    out<<'[';
    for(int j=0;j<A.n;j++)
      out<<ASCIIShade(A(i,j)/scale);
    out<<']';
    if(i+1 < A.m)
      out<<endl;
  }
}

void OutputASCIIShade(ostream& out,const dMatrix& A,double scale,int indent)
{
  if(scale == 0) scale = A.maxAbsElement();
  out<<scale<<" x"<<endl;
  if(scale == 0) scale = 1;
  for(int i=0;i<A.m;i++) {
    if(i && indent) out<<string(indent,' ');
    out<<'[';
    for(int j=0;j<A.n;j++)
      out<<ASCIIShade(A(i,j)/scale);
    out<<']';
    if(i+1 < A.m)
      out<<endl;
  }
}

} //namespace Math
<|endoftext|>


<commit_before>/*
  microbit_Screen.cpp - LED Screen library for micro:bit
  (for "Arduino Core for Nordic Semiconductor nRF5 based boards")
  Copyright (c) 2017 Hideaki Tominaga. All rights reserved.

  This library 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 2.1 of the License, or (at your option) any later version.

  This library 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 this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "microbit_Screen.h"

microbit_Screen::microbit_Screen() {
}

void microbit_Screen::begin() {
  for (uint8_t i = 0; i < max_cols; i++)
    pinMode(cols[i], OUTPUT);
  for (uint8_t i = 0; i < max_rows; i++)
    pinMode(rows[i], OUTPUT);
  clearScreen();
}

void microbit_Screen::clearScreen() {
  for (uint8_t i = 0; i < max_cols; i++)
    digitalWrite(cols[i], HIGH);
  for (uint8_t i = 0; i < max_rows; i++)
    digitalWrite(rows[i], LOW);
  for (uint8_t l = 0; l < rowCount; l++) {
    for (uint8_t i = 0; i < colCount; i++) {
      screenArr[i][l] = false;
    }
  }
}

void microbit_Screen::pset(const uint8_t x, const uint8_t y, const uint8_t mode) {
  LED_POINT position = LED_POS[y][x];
  digitalWrite(cols[position.x], !mode);
  digitalWrite(rows[position.y], mode);
  screenArr[x][y] = (mode == HIGH) ;
}

void microbit_Screen::plot(const uint8_t x, const uint8_t y) {
  pset(x, y, HIGH);
}

void microbit_Screen::unplot(const uint8_t x, const uint8_t y) {
  pset(x, y, LOW);
}

void microbit_Screen::toggle(const uint8_t x, const uint8_t y) {
  screenArr[x][y] = !screenArr[x][y];
  pset(x, y, screenArr[x][y]);
}

bool microbit_Screen::point(const uint8_t x, const uint8_t y) {
  return (screenArr[x][y]);
}

void microbit_Screen::showData(const uint8_t *DataArray) {
  for (uint8_t x = 0; x < colCount; x++) {
    uint8_t data = DataArray[x];
    for (uint8_t y = 0; y < rowCount; y++) {
      if (data & 1) {
        LED_POINT position = LED_POS[y][x];
        digitalWrite(cols[position.x], LOW );
        digitalWrite(rows[position.y], HIGH);
        delay(1);
        digitalWrite(cols[position.x], HIGH);
        digitalWrite(rows[position.y], LOW );
      } else {
        delay(1);
      }
      data = data >> 1;
    }
  }
}

void microbit_Screen::showString(const String text, const uint32_t interval) {
  clearScreen();

  String dStr;
  if (text.length() == 0)
    dStr = " ";
  else if (text.length() == 1)
    dStr = text;
  else
    dStr = " " + text + " ";
  bool isSingleChar = (dStr.length() == 1);
  uint8_t* strBuf = new uint8_t[dStr.length() * colCount + colCount - 1];

  uint32_t idx = 0;
  for (uint32_t c = 0; c < dStr.length(); c++) {
    uint32_t charidx = dStr.charAt(c);
    if ((charidx < 0x20) || (charidx > 0x7f))
      charidx = 0x00;
    else
      charidx = charidx - 0x20;
    for (uint8_t x = 0; x < colCount; x++) {
      strBuf[idx] = LED_FONT[charidx][x];
      idx++;
    }
    if (c < dStr.length() - 1) {
      strBuf[idx] = 0x00;
      idx++;
    }
  }

  idx = 0;
  do {
    uint32_t tick = millis();
    do {
      showData(&strBuf[idx]);
    } while ((millis() - tick) < interval);
    idx++;
  } while ((idx < dStr.length() * colCount + colCount) && !isSingleChar);

  delete[] strBuf;
}

void microbit_Screen::showNumber(const int32_t value, const uint32_t interval) {
  String dStr = String(value, DEC);
  showString(dStr, interval);
}

void microbit_Screen::showIcon(const IconNames icon, const uint32_t interval) {
  uint32_t tick = millis();
  do {
    showData(LED_ICON[(int)icon]);
  } while ((millis() - tick) < interval);
}

void microbit_Screen::showArrow(const ArrowNames direction, const uint32_t interval) {
  uint8_t d = (int)direction % 8;
  uint32_t tick = millis();
  do {
    showData(LED_ARROW[d]);
  } while ((millis() - tick) < interval);
}

void microbit_Screen::showLeds(const String str, const uint32_t interval) {
  uint8_t LED_DATA[colCount] = {0, 0, 0, 0, 0};

  for (int y=0; y<rowCount; y++) {
    for (int x=0; x<colCount; x++) {
      if (str.charAt(y * colCount + x) == 0x23) {
        LED_DATA[x] |= (1 << y);
      }
    }
  }

  uint32_t tick = millis();
  do {
    showData(LED_DATA);
  } while ((millis() - tick) < interval);
}

microbit_Screen SCREEN;
<commit_msg>add plotBarGraph()<commit_after>/*
  microbit_Screen.cpp - LED Screen library for micro:bit
  (for "Arduino Core for Nordic Semiconductor nRF5 based boards")
  Copyright (c) 2017 Hideaki Tominaga. All rights reserved.

  This library 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 2.1 of the License, or (at your option) any later version.

  This library 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 this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "microbit_Screen.h"

microbit_Screen::microbit_Screen() {
}

void microbit_Screen::begin() {
  for (uint8_t i = 0; i < max_cols; i++)
    pinMode(cols[i], OUTPUT);
  for (uint8_t i = 0; i < max_rows; i++)
    pinMode(rows[i], OUTPUT);
  clearScreen();
}

void microbit_Screen::clearScreen() {
  for (uint8_t i = 0; i < max_cols; i++)
    digitalWrite(cols[i], HIGH);
  for (uint8_t i = 0; i < max_rows; i++)
    digitalWrite(rows[i], LOW);
  for (uint8_t l = 0; l < rowCount; l++) {
    for (uint8_t i = 0; i < colCount; i++) {
      screenArr[i][l] = false;
    }
  }
}

void microbit_Screen::pset(const uint8_t x, const uint8_t y, const uint8_t mode) {
  LED_POINT position = LED_POS[y][x];
  digitalWrite(cols[position.x], !mode);
  digitalWrite(rows[position.y], mode);
  screenArr[x][y] = (mode == HIGH) ;
}

void microbit_Screen::plot(const uint8_t x, const uint8_t y) {
  pset(x, y, HIGH);
}

void microbit_Screen::unplot(const uint8_t x, const uint8_t y) {
  pset(x, y, LOW);
}

void microbit_Screen::toggle(const uint8_t x, const uint8_t y) {
  screenArr[x][y] = !screenArr[x][y];
  pset(x, y, screenArr[x][y]);
}

bool microbit_Screen::point(const uint8_t x, const uint8_t y) {
  return (screenArr[x][y]);
}

void microbit_Screen::showData(const uint8_t *DataArray) {
  for (uint8_t x = 0; x < colCount; x++) {
    uint8_t data = DataArray[x];
    for (uint8_t y = 0; y < rowCount; y++) {
      if (data & 1) {
        LED_POINT position = LED_POS[y][x];
        digitalWrite(cols[position.x], LOW );
        digitalWrite(rows[position.y], HIGH);
        delay(1);
        digitalWrite(cols[position.x], HIGH);
        digitalWrite(rows[position.y], LOW );
      } else {
        delay(1);
      }
      data = data >> 1;
    }
  }
}

void microbit_Screen::showString(const String text, const uint32_t interval) {
  clearScreen();

  String dStr;
  if (text.length() == 0)
    dStr = " ";
  else if (text.length() == 1)
    dStr = text;
  else
    dStr = " " + text + " ";
  bool isSingleChar = (dStr.length() == 1);
  uint8_t* strBuf = new uint8_t[dStr.length() * colCount + colCount - 1];

  uint32_t idx = 0;
  for (uint32_t c = 0; c < dStr.length(); c++) {
    uint32_t charidx = dStr.charAt(c);
    if ((charidx < 0x20) || (charidx > 0x7f))
      charidx = 0x00;
    else
      charidx = charidx - 0x20;
    for (uint8_t x = 0; x < colCount; x++) {
      strBuf[idx] = LED_FONT[charidx][x];
      idx++;
    }
    if (c < dStr.length() - 1) {
      strBuf[idx] = 0x00;
      idx++;
    }
  }

  idx = 0;
  do {
    uint32_t tick = millis();
    do {
      showData(&strBuf[idx]);
    } while ((millis() - tick) < interval);
    idx++;
  } while ((idx < dStr.length() * colCount + colCount) && !isSingleChar);

  delete[] strBuf;
}

void microbit_Screen::showNumber(const int32_t value, const uint32_t interval) {
  String dStr = String(value, DEC);
  showString(dStr, interval);
}

void microbit_Screen::showIcon(const IconNames icon, const uint32_t interval) {
  uint32_t tick = millis();
  do {
    showData(LED_ICON[(int)icon]);
  } while ((millis() - tick) < interval);
}

void microbit_Screen::showArrow(const ArrowNames direction, const uint32_t interval) {
  uint8_t d = (int)direction % 8;
  uint32_t tick = millis();
  do {
    showData(LED_ARROW[d]);
  } while ((millis() - tick) < interval);
}

void microbit_Screen::showLeds(const String str, const uint32_t interval) {
  uint8_t LED_DATA[colCount] = {0, 0, 0, 0, 0};

  for (int y=0; y<rowCount; y++) {
    for (int x=0; x<colCount; x++) {
      if (str.charAt(y * colCount + x) == 0x23) {
        LED_DATA[x] |= (1 << y);
      }
    }
  }

  uint32_t tick = millis();
  do {
    showData(LED_DATA);
  } while ((millis() - tick) < interval);
}

void microbit_Screen::plotBarGraph(const uint32_t value, const uint32_t high) {
  uint8_t LED_DATA[colCount] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  uint32_t dValue = value;
  uint32_t dHigh = high;
  if (dHigh < 15)
    dHigh = 15;
  if (dValue > dHigh)
    dValue = dHigh;

  uint8_t percentage = dValue * 100 / dHigh;
  uint8_t shiftBit = 5 - (percentage / 20);
  uint8_t remainder = (percentage % 20);
  uint8_t remainderBit = 1 << (shiftBit - 1);
  for (uint8_t i=0; i<colCount; i++)
    LED_DATA[i] = LED_DATA[i] << shiftBit;
  if (remainder > 13) {
      LED_DATA[0] |= remainderBit;
      LED_DATA[4] |= remainderBit;
  }
  if (remainder > 6) {
      LED_DATA[1] |= remainderBit;
      LED_DATA[3] |= remainderBit;
  }
  LED_DATA[2] |= remainderBit;

  showData(LED_DATA);
}

microbit_Screen SCREEN;
<|endoftext|>


<commit_before>//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

/*++

Module Name:

    sysinfo.c

Abstract:

    Implements GetSystemInfo.

Revision History:

--*/

#include "pal/palinternal.h"

#include <sched.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#if HAVE_SYSCTL
#include <sys/sysctl.h>
#elif !HAVE_SYSCONF && !defined(__ANDROID__)
#error Either sysctl or sysconf is required for GetSystemInfo.
#endif

#include <sys/param.h>
#if HAVE_SYS_VMPARAM_H
#include <sys/vmparam.h>
#endif  // HAVE_SYS_VMPARAM_H

#if HAVE_MACH_VM_TYPES_H
#include <mach/vm_types.h>
#endif // HAVE_MACH_VM_TYPES_H

#if HAVE_MACH_VM_PARAM_H
#include <mach/vm_param.h>
#endif  // HAVE_MACH_VM_PARAM_H

#if defined(__APPLE__)
#include <mach/vm_statistics.h>
#include <mach/mach_types.h>
#include <mach/mach_init.h>
#include <mach/mach_host.h>
#endif // defined(__APPLE__)

// On some platforms sys/user.h ends up defining _DEBUG; if so
// remove the definition before including the header and put
// back our definition afterwards
#if USER_H_DEFINES_DEBUG
#define OLD_DEBUG _DEBUG
#undef _DEBUG
#endif
#include <sys/user.h>
#if USER_H_DEFINES_DEBUG
#undef _DEBUG
#define _DEBUG OLD_DEBUG
#undef OLD_DEBUG
#endif

#include "pal/dbgmsg.h"

SET_DEFAULT_DEBUG_CHANNEL(MISC);

#if defined(__hppa__) || ( defined (_IA64_) && defined (_HPUX_) )
#include <sys/pstat.h>
#include <sys/vmparam.h>
#endif

#ifndef __APPLE__
#if HAVE_SYSCONF && HAVE__SC_AVPHYS_PAGES
#define SYSCONF_PAGES _SC_AVPHYS_PAGES
#elif HAVE_SYSCONF && HAVE__SC_PHYS_PAGES
#define SYSCONF_PAGES _SC_PHYS_PAGES
#elif !defined(__ANDROID__)
#error Dont know how to get page-size on this architecture!
#endif
#endif // __APPLE__

#ifdef __LINUX__
// There is no reasonable way to get the max. value for the VAS on
// Linux, so just hardcode the ABI values for 64 and 32bits.
#ifdef LINUX64
// The hardware limit for x86-64 CPUs is 256TB, but the practical
// limit at the moment for Linux kernels is 128TB.  See for example:
// https://access.redhat.com/articles/rhel-limits
#define MAX_PROCESS_VA_SPACE_LINUX (128ull * 1024 * 1024 * 1024 * 1024)
#else
// This is unsupported at the moment, but the x32 ABI has a 4GB limit.
#define MAX_PROCESS_VA_SPACE_LINUX (4ull * 1024 * 1024 * 1024)
#endif
#endif // __LINUX__

/*++
Function:
  GetSystemInfo

GetSystemInfo

The GetSystemInfo function returns information about the current system.

Parameters

lpSystemInfo
       [out] Pointer to a SYSTEM_INFO structure that receives the information.

Return Values

This function does not return a value.

Note:
  fields returned by this function are:
    dwNumberOfProcessors
    dwPageSize
Others are set to zero.

--*/
VOID
PALAPI
GetSystemInfo(
          OUT LPSYSTEM_INFO lpSystemInfo)
{
    int nrcpus = 0;
    long pagesize;

    PERF_ENTRY(GetSystemInfo);
    ENTRY("GetSystemInfo (lpSystemInfo=%p)\n", lpSystemInfo);

    pagesize = getpagesize();

    lpSystemInfo->wProcessorArchitecture_PAL_Undefined = 0;
    lpSystemInfo->wReserved_PAL_Undefined = 0;
    lpSystemInfo->dwPageSize = pagesize;
    lpSystemInfo->dwActiveProcessorMask_PAL_Undefined = 0;

#if HAVE_SYSCONF
    nrcpus = sysconf(_SC_NPROCESSORS_ONLN);
    if (nrcpus < 1)
    {
        ASSERT("sysconf failed for _SC_NPROCESSORS_ONLN (%d)\n", errno);
    }
#elif HAVE_SYSCTL
    int rc;
    size_t sz;
    int mib[2];

    sz = sizeof(nrcpus);
    mib[0] = CTL_HW;
    mib[1] = HW_NCPU;
    rc = sysctl(mib, 2, &nrcpus, &sz, NULL, 0);
    if (rc != 0)
    {
        ASSERT("sysctl failed for HW_NCPU (%d)\n", errno);
    }
#endif // HAVE_SYSCONF

    TRACE("dwNumberOfProcessors=%d\n", nrcpus);
    lpSystemInfo->dwNumberOfProcessors = nrcpus;

#ifdef VM_MAXUSER_ADDRESS
    lpSystemInfo->lpMaximumApplicationAddress = (PVOID) VM_MAXUSER_ADDRESS;
#elif defined(__LINUX__)
    lpSystemInfo->lpMaximumApplicationAddress = (PVOID) MAX_PROCESS_VA_SPACE_LINUX;
#elif defined(USERLIMIT)
    lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USERLIMIT;
#elif defined(_WIN64)
#if defined(USRSTACK64)
    lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USRSTACK64;
#else // !USRSTACK64
#error How come USRSTACK64 is not defined for 64bit?
#endif // USRSTACK64
#elif defined(USRSTACK)
    lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USRSTACK;
#else
#error The maximum application address is not known on this platform.
#endif

    lpSystemInfo->lpMinimumApplicationAddress = (PVOID) pagesize;

    lpSystemInfo->dwProcessorType_PAL_Undefined = 0;

    lpSystemInfo->dwAllocationGranularity = pagesize;

    lpSystemInfo->wProcessorLevel_PAL_Undefined = 0;
    lpSystemInfo->wProcessorRevision_PAL_Undefined = 0;

    LOGEXIT("GetSystemInfo returns VOID\n");
    PERF_EXIT(GetSystemInfo);
}

/*++
Function:
  GlobalMemoryStatusEx

GlobalMemoryStatusEx

Retrieves information about the system's current usage of both physical and virtual memory.

Return Values

This function returns a BOOL to indicate its success status.

--*/
BOOL
PALAPI
GlobalMemoryStatusEx(
            IN OUT LPMEMORYSTATUSEX lpBuffer)
{

    PERF_ENTRY(GlobalMemoryStatusEx);
    ENTRY("GlobalMemoryStatusEx (lpBuffer=%p)\n", lpBuffer);

    lpBuffer->dwMemoryLoad = 0;
    lpBuffer->ullTotalPhys = 0;
    lpBuffer->ullAvailPhys = 0;
    lpBuffer->ullTotalPageFile = 0;
    lpBuffer->ullAvailPageFile = 0;
    lpBuffer->ullTotalVirtual = 0;
    lpBuffer->ullAvailVirtual = 0;
    lpBuffer->ullAvailExtendedVirtual = 0;

    BOOL fRetVal = FALSE;

    // Get the physical memory size
#if HAVE_SYSCONF && HAVE__SC_PHYS_PAGES
    int64_t physical_memory;

    // Get the Physical memory size
    physical_memory = sysconf( _SC_PHYS_PAGES ) * sysconf( _SC_PAGE_SIZE );
    lpBuffer->ullTotalPhys = (DWORDLONG)physical_memory;
    fRetVal = TRUE;
#elif HAVE_SYSCTL
    int mib[2];
    int64_t physical_memory;
    size_t length;

    // Get the Physical memory size
    mib[0] = CTL_HW;
    mib[1] = HW_MEMSIZE;
    length = sizeof(INT64);
    int rc = sysctl(mib, 2, &physical_memory, &length, NULL, 0);
    if (rc != 0)
    {
        ASSERT("sysctl failed for HW_MEMSIZE (%d)\n", errno);
    }
    else
    {
        lpBuffer->ullTotalPhys = (DWORDLONG)physical_memory;
        fRetVal = TRUE;
    }
#else // HAVE_SYSINFO
    // TODO: implement getting memory details via sysinfo. On Linux, it provides swap file details that
    // we can use to fill in the xxxPageFile members.

#endif // HAVE_SYSCONF

    // Get the physical memory in use - from it, we can get the physical memory available.
    // We do this only when we have the total physical memory available.
    if (lpBuffer->ullTotalPhys > 0)
    {
#if defined(__ANDROID__)
        lpBuffer->ullAvailPhys = sysconf(_SC_AVPHYS_PAGES) * sysconf( _SC_PAGE_SIZE );
        INT64 used_memory = lpBuffer->ullTotalPhys - lpBuffer->ullAvailPhys;
        lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys);
#elif defined(__LINUX__)
        lpBuffer->ullAvailPhys = sysconf(SYSCONF_PAGES) * sysconf(_SC_PAGE_SIZE);
        INT64 used_memory = lpBuffer->ullTotalPhys - lpBuffer->ullAvailPhys;
        lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys);
#elif defined(__APPLE__)
        vm_size_t page_size;
        mach_port_t mach_port;
        mach_msg_type_number_t count;
        vm_statistics_data_t vm_stats;
        mach_port = mach_host_self();
        count = sizeof(vm_stats) / sizeof(natural_t);
        if (KERN_SUCCESS == host_page_size(mach_port, &page_size))
        {
            if (KERN_SUCCESS == host_statistics(mach_port, HOST_VM_INFO, (host_info_t)&vm_stats, &count))
            {
                lpBuffer->ullAvailPhys = (int64_t)vm_stats.free_count * (int64_t)page_size;
                INT64 used_memory = ((INT64)vm_stats.active_count + (INT64)vm_stats.inactive_count + (INT64)vm_stats.wire_count) *  (INT64)page_size;
                lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys);
            }
        }
        mach_port_deallocate(mach_task_self(), mach_port);
#endif // __APPLE__
    }

#ifdef __LINUX__
    lpBuffer->ullTotalVirtual = MAX_PROCESS_VA_SPACE_LINUX;
#else
    // xplat-todo: for all the other unices just use 128TB for now.
    static const UINT64 _128TB = (1ull << 47);
    lpBuffer->ullTotalVirtual = _128TB;
#endif
    lpBuffer->ullAvailVirtual = lpBuffer->ullAvailPhys;

    LOGEXIT("GlobalMemoryStatusEx returns %d\n", fRetVal);
    PERF_EXIT(GlobalMemoryStatusEx);

    return fRetVal;
}

PALIMPORT
DWORD
PALAPI
GetCurrentProcessorNumber()
{
#if HAVE_SCHED_GETCPU
    return sched_getcpu();
#else //HAVE_SCHED_GETCPU
    return -1;
#endif //HAVE_SCHED_GETCPU
}

BOOL
PALAPI
PAL_HasGetCurrentProcessorNumber()
{
    return HAVE_SCHED_GETCPU;
}

DWORD
PALAPI
PAL_GetLogicalCpuCountFromOS()
{
    DWORD numLogicalCores = 0;

#if HAVE_SYSCONF
    numLogicalCores = sysconf(_SC_NPROCESSORS_ONLN);
#endif

    return numLogicalCores;
}

size_t
PALAPI
PAL_GetLogicalProcessorCacheSizeFromOS()
{
    size_t cacheSize = 0;

#if HAVE_SYSCONF && defined(__LINUX__) && !defined(__ANDROID__)
    cacheSize = max(cacheSize, sysconf(_SC_LEVEL1_DCACHE_SIZE));
    cacheSize = max(cacheSize, sysconf(_SC_LEVEL1_ICACHE_SIZE));
    cacheSize = max(cacheSize, sysconf(_SC_LEVEL2_CACHE_SIZE));
    cacheSize = max(cacheSize, sysconf(_SC_LEVEL3_CACHE_SIZE));
    cacheSize = max(cacheSize, sysconf(_SC_LEVEL4_CACHE_SIZE));
#endif

    return cacheSize;
}
<commit_msg>[1.7>master] [MERGE #3806 @obastemur] OSX: Use the max between rsp vs USRSTACK**<commit_after>//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

/*++

Module Name:

    sysinfo.c

Abstract:

    Implements GetSystemInfo.

Revision History:

--*/

#include "pal/palinternal.h"

#include <sched.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#if HAVE_SYSCTL
#include <sys/sysctl.h>
#elif !HAVE_SYSCONF && !defined(__ANDROID__)
#error Either sysctl or sysconf is required for GetSystemInfo.
#endif

#include <sys/param.h>
#if HAVE_SYS_VMPARAM_H
#include <sys/vmparam.h>
#endif  // HAVE_SYS_VMPARAM_H

#if HAVE_MACH_VM_TYPES_H
#include <mach/vm_types.h>
#endif // HAVE_MACH_VM_TYPES_H

#if HAVE_MACH_VM_PARAM_H
#include <mach/vm_param.h>
#endif  // HAVE_MACH_VM_PARAM_H

#if defined(__APPLE__)
#include <mach/vm_statistics.h>
#include <mach/mach_types.h>
#include <mach/mach_init.h>
#include <mach/mach_host.h>
#endif // defined(__APPLE__)

// On some platforms sys/user.h ends up defining _DEBUG; if so
// remove the definition before including the header and put
// back our definition afterwards
#if USER_H_DEFINES_DEBUG
#define OLD_DEBUG _DEBUG
#undef _DEBUG
#endif
#include <sys/user.h>
#if USER_H_DEFINES_DEBUG
#undef _DEBUG
#define _DEBUG OLD_DEBUG
#undef OLD_DEBUG
#endif

#include "pal/dbgmsg.h"

SET_DEFAULT_DEBUG_CHANNEL(MISC);

#if defined(__hppa__) || ( defined (_IA64_) && defined (_HPUX_) )
#include <sys/pstat.h>
#include <sys/vmparam.h>
#endif

#ifndef __APPLE__
#if HAVE_SYSCONF && HAVE__SC_AVPHYS_PAGES
#define SYSCONF_PAGES _SC_AVPHYS_PAGES
#elif HAVE_SYSCONF && HAVE__SC_PHYS_PAGES
#define SYSCONF_PAGES _SC_PHYS_PAGES
#elif !defined(__ANDROID__)
#error Dont know how to get page-size on this architecture!
#endif
#endif // __APPLE__

#ifdef __LINUX__
// There is no reasonable way to get the max. value for the VAS on
// Linux, so just hardcode the ABI values for 64 and 32bits.
#ifdef LINUX64
// The hardware limit for x86-64 CPUs is 256TB, but the practical
// limit at the moment for Linux kernels is 128TB.  See for example:
// https://access.redhat.com/articles/rhel-limits
#define MAX_PROCESS_VA_SPACE_LINUX (128ull * 1024 * 1024 * 1024 * 1024)
#else
// This is unsupported at the moment, but the x32 ABI has a 4GB limit.
#define MAX_PROCESS_VA_SPACE_LINUX (4ull * 1024 * 1024 * 1024)
#endif
#endif // __LINUX__

/*++
Function:
  GetSystemInfo

GetSystemInfo

The GetSystemInfo function returns information about the current system.

Parameters

lpSystemInfo
       [out] Pointer to a SYSTEM_INFO structure that receives the information.

Return Values

This function does not return a value.

Note:
  fields returned by this function are:
    dwNumberOfProcessors
    dwPageSize
Others are set to zero.

--*/

int GetCurrentThreadStackLimits(ULONG_PTR* lowLimit, ULONG_PTR* highLimit);

VOID
PALAPI
GetSystemInfo(
          OUT LPSYSTEM_INFO lpSystemInfo)
{
    int nrcpus = 0;
    long pagesize;

    PERF_ENTRY(GetSystemInfo);
    ENTRY("GetSystemInfo (lpSystemInfo=%p)\n", lpSystemInfo);

    pagesize = getpagesize();

    lpSystemInfo->wProcessorArchitecture_PAL_Undefined = 0;
    lpSystemInfo->wReserved_PAL_Undefined = 0;
    lpSystemInfo->dwPageSize = pagesize;
    lpSystemInfo->dwActiveProcessorMask_PAL_Undefined = 0;

#if HAVE_SYSCONF
    nrcpus = sysconf(_SC_NPROCESSORS_ONLN);
    if (nrcpus < 1)
    {
        ASSERT("sysconf failed for _SC_NPROCESSORS_ONLN (%d)\n", errno);
    }
#elif HAVE_SYSCTL
    int rc;
    size_t sz;
    int mib[2];

    sz = sizeof(nrcpus);
    mib[0] = CTL_HW;
    mib[1] = HW_NCPU;
    rc = sysctl(mib, 2, &nrcpus, &sz, NULL, 0);
    if (rc != 0)
    {
        ASSERT("sysctl failed for HW_NCPU (%d)\n", errno);
    }
#endif // HAVE_SYSCONF

    TRACE("dwNumberOfProcessors=%d\n", nrcpus);
    lpSystemInfo->dwNumberOfProcessors = nrcpus;

// TODO: (BSD) is it a good idea to take maxOf(GetCurrentThreadStackLimits, USRSTACKXX) ?
#ifdef __APPLE__ // defined(USRSTACK64) || defined(USRSTACK)
ULONG_PTR lowl, highl;
GetCurrentThreadStackLimits(&lowl, &highl);
#ifndef PAL_MAX
#define PAL_MAX(a, b) ((a > b) ? (a) : (b))
#endif
#endif

#ifdef VM_MAXUSER_ADDRESS
    lpSystemInfo->lpMaximumApplicationAddress = (PVOID) VM_MAXUSER_ADDRESS;
#elif defined(__LINUX__)
    lpSystemInfo->lpMaximumApplicationAddress = (PVOID) MAX_PROCESS_VA_SPACE_LINUX;
#elif defined(USERLIMIT)
    lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USERLIMIT;
#elif defined(_WIN64)
#if defined(USRSTACK64)
    lpSystemInfo->lpMaximumApplicationAddress = (PVOID) PAL_MAX(highl, USRSTACK64);
#else // !USRSTACK64
#error How come USRSTACK64 is not defined for 64bit?
#endif // USRSTACK64
#elif defined(USRSTACK)
    lpSystemInfo->lpMaximumApplicationAddress = (PVOID) PAL_MAX(highl, USRSTACK);
#else
#error The maximum application address is not known on this platform.
#endif

    lpSystemInfo->lpMinimumApplicationAddress = (PVOID) pagesize;

    lpSystemInfo->dwProcessorType_PAL_Undefined = 0;

    lpSystemInfo->dwAllocationGranularity = pagesize;

    lpSystemInfo->wProcessorLevel_PAL_Undefined = 0;
    lpSystemInfo->wProcessorRevision_PAL_Undefined = 0;

    LOGEXIT("GetSystemInfo returns VOID\n");
    PERF_EXIT(GetSystemInfo);
}

/*++
Function:
  GlobalMemoryStatusEx

GlobalMemoryStatusEx

Retrieves information about the system's current usage of both physical and virtual memory.

Return Values

This function returns a BOOL to indicate its success status.

--*/
BOOL
PALAPI
GlobalMemoryStatusEx(
            IN OUT LPMEMORYSTATUSEX lpBuffer)
{

    PERF_ENTRY(GlobalMemoryStatusEx);
    ENTRY("GlobalMemoryStatusEx (lpBuffer=%p)\n", lpBuffer);

    lpBuffer->dwMemoryLoad = 0;
    lpBuffer->ullTotalPhys = 0;
    lpBuffer->ullAvailPhys = 0;
    lpBuffer->ullTotalPageFile = 0;
    lpBuffer->ullAvailPageFile = 0;
    lpBuffer->ullTotalVirtual = 0;
    lpBuffer->ullAvailVirtual = 0;
    lpBuffer->ullAvailExtendedVirtual = 0;

    BOOL fRetVal = FALSE;

    // Get the physical memory size
#if HAVE_SYSCONF && HAVE__SC_PHYS_PAGES
    int64_t physical_memory;

    // Get the Physical memory size
    physical_memory = sysconf( _SC_PHYS_PAGES ) * sysconf( _SC_PAGE_SIZE );
    lpBuffer->ullTotalPhys = (DWORDLONG)physical_memory;
    fRetVal = TRUE;
#elif HAVE_SYSCTL
    int mib[2];
    int64_t physical_memory;
    size_t length;

    // Get the Physical memory size
    mib[0] = CTL_HW;
    mib[1] = HW_MEMSIZE;
    length = sizeof(INT64);
    int rc = sysctl(mib, 2, &physical_memory, &length, NULL, 0);
    if (rc != 0)
    {
        ASSERT("sysctl failed for HW_MEMSIZE (%d)\n", errno);
    }
    else
    {
        lpBuffer->ullTotalPhys = (DWORDLONG)physical_memory;
        fRetVal = TRUE;
    }
#else // HAVE_SYSINFO
    // TODO: implement getting memory details via sysinfo. On Linux, it provides swap file details that
    // we can use to fill in the xxxPageFile members.

#endif // HAVE_SYSCONF

    // Get the physical memory in use - from it, we can get the physical memory available.
    // We do this only when we have the total physical memory available.
    if (lpBuffer->ullTotalPhys > 0)
    {
#if defined(__ANDROID__)
        lpBuffer->ullAvailPhys = sysconf(_SC_AVPHYS_PAGES) * sysconf( _SC_PAGE_SIZE );
        INT64 used_memory = lpBuffer->ullTotalPhys - lpBuffer->ullAvailPhys;
        lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys);
#elif defined(__LINUX__)
        lpBuffer->ullAvailPhys = sysconf(SYSCONF_PAGES) * sysconf(_SC_PAGE_SIZE);
        INT64 used_memory = lpBuffer->ullTotalPhys - lpBuffer->ullAvailPhys;
        lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys);
#elif defined(__APPLE__)
        vm_size_t page_size;
        mach_port_t mach_port;
        mach_msg_type_number_t count;
        vm_statistics_data_t vm_stats;
        mach_port = mach_host_self();
        count = sizeof(vm_stats) / sizeof(natural_t);
        if (KERN_SUCCESS == host_page_size(mach_port, &page_size))
        {
            if (KERN_SUCCESS == host_statistics(mach_port, HOST_VM_INFO, (host_info_t)&vm_stats, &count))
            {
                lpBuffer->ullAvailPhys = (int64_t)vm_stats.free_count * (int64_t)page_size;
                INT64 used_memory = ((INT64)vm_stats.active_count + (INT64)vm_stats.inactive_count + (INT64)vm_stats.wire_count) *  (INT64)page_size;
                lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys);
            }
        }
        mach_port_deallocate(mach_task_self(), mach_port);
#endif // __APPLE__
    }

#ifdef __LINUX__
    lpBuffer->ullTotalVirtual = MAX_PROCESS_VA_SPACE_LINUX;
#else
    // xplat-todo: for all the other unices just use 128TB for now.
    static const UINT64 _128TB = (1ull << 47);
    lpBuffer->ullTotalVirtual = _128TB;
#endif
    lpBuffer->ullAvailVirtual = lpBuffer->ullAvailPhys;

    LOGEXIT("GlobalMemoryStatusEx returns %d\n", fRetVal);
    PERF_EXIT(GlobalMemoryStatusEx);

    return fRetVal;
}

PALIMPORT
DWORD
PALAPI
GetCurrentProcessorNumber()
{
#if HAVE_SCHED_GETCPU
    return sched_getcpu();
#else //HAVE_SCHED_GETCPU
    return -1;
#endif //HAVE_SCHED_GETCPU
}

BOOL
PALAPI
PAL_HasGetCurrentProcessorNumber()
{
    return HAVE_SCHED_GETCPU;
}

DWORD
PALAPI
PAL_GetLogicalCpuCountFromOS()
{
    DWORD numLogicalCores = 0;

#if HAVE_SYSCONF
    numLogicalCores = sysconf(_SC_NPROCESSORS_ONLN);
#endif

    return numLogicalCores;
}

size_t
PALAPI
PAL_GetLogicalProcessorCacheSizeFromOS()
{
    size_t cacheSize = 0;

#if HAVE_SYSCONF && defined(__LINUX__) && !defined(__ANDROID__)
    cacheSize = max(cacheSize, sysconf(_SC_LEVEL1_DCACHE_SIZE));
    cacheSize = max(cacheSize, sysconf(_SC_LEVEL1_ICACHE_SIZE));
    cacheSize = max(cacheSize, sysconf(_SC_LEVEL2_CACHE_SIZE));
    cacheSize = max(cacheSize, sysconf(_SC_LEVEL3_CACHE_SIZE));
    cacheSize = max(cacheSize, sysconf(_SC_LEVEL4_CACHE_SIZE));
#endif

    return cacheSize;
}
<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/log.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/consteval.h"
#include "kernel/celltypes.h"
#include "fsmdata.h"
#include <string.h>

struct FsmExpand
{
	RTLIL::Module *module;
	RTLIL::Cell *fsm_cell;
	SigMap assign_map;
	SigSet<RTLIL::Cell*> sig2driver, sig2user;
	CellTypes ct;

	std::set<RTLIL::Cell*> merged_set;
	std::set<RTLIL::Cell*> current_set;
	std::set<RTLIL::Cell*> no_candidate_set;

	bool already_optimized;
	int limit_transitions;

	bool is_cell_merge_candidate(RTLIL::Cell *cell)
	{
		RTLIL::SigSpec new_signals;
		if (cell->connections.count("\\A") > 0)
			new_signals.append(assign_map(cell->connections["\\A"]));
		if (cell->connections.count("\\B") > 0)
			new_signals.append(assign_map(cell->connections["\\B"]));
		if (cell->connections.count("\\S") > 0)
			new_signals.append(assign_map(cell->connections["\\S"]));

		new_signals.sort_and_unify();
		new_signals.remove_const();

		if (new_signals.width > 4)
			return false;

		new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_IN"]));
		new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_OUT"]));

		if (cell->connections.count("\\Y") > 0) {
			new_signals.append(assign_map(cell->connections["\\Y"]));
			new_signals.sort_and_unify();
			new_signals.remove_const();
			new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_IN"]));
			new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_OUT"]));
		}

		if (new_signals.width > 2)
			return false;

		return true;
	}

	void create_current_set()
	{
		std::vector<RTLIL::Cell*> cell_list;

		for (auto c : sig2driver.find(assign_map(fsm_cell->connections["\\CTRL_IN"])))
			cell_list.push_back(c);

		for (auto c : sig2user.find(assign_map(fsm_cell->connections["\\CTRL_OUT"])))
			cell_list.push_back(c);

		current_set.clear();
		for (auto c : cell_list)
		{
			if (merged_set.count(c) > 0 || current_set.count(c) > 0 || no_candidate_set.count(c) > 0)
				continue;
			for (auto &p : c->connections) {
				if (p.first != "\\A" && p.first != "\\B" && p.first != "\\S" && p.first != "\\Y")
					goto next_cell;
			}
			if (!is_cell_merge_candidate(c)) {
				no_candidate_set.insert(c);
				continue;
			}
			current_set.insert(c);
		next_cell:;
		}
	}

	void optimze_as_needed()
	{
		if (already_optimized)
			return;

		int trans_num = fsm_cell->parameters["\\TRANS_NUM"].as_int();
		if (trans_num > limit_transitions)
		{
			log("  grown transition table to %d entries -> optimize.\n", trans_num);
			FsmData::optimize_fsm(fsm_cell, module);
			already_optimized = true;

			trans_num = fsm_cell->parameters["\\TRANS_NUM"].as_int();
			log("  transition table size after optimizaton: %d\n", trans_num);
			limit_transitions = 16 * trans_num;
		}
	}

	void merge_cell_into_fsm(RTLIL::Cell *cell)
	{
		optimze_as_needed();

		log("  merging %s cell %s.\n", cell->type.c_str(), cell->name.c_str());
		merged_set.insert(cell);
		already_optimized = false;

		RTLIL::SigSpec input_sig, output_sig;

		for (auto &p : cell->connections)
			if (ct.cell_output(cell->type, p.first))
				output_sig.append(assign_map(p.second));
			else
				input_sig.append(assign_map(p.second));
		input_sig.sort_and_unify();
		input_sig.remove_const();

		assert(input_sig.width <= 4);
		std::vector<RTLIL::Const> truth_tab;

		for (int i = 0; i < (1 << input_sig.width); i++) {
			RTLIL::Const in_val(i, input_sig.width);
			RTLIL::SigSpec A, B, S;
			if (cell->connections.count("\\A") > 0)
				A = assign_map(cell->connections["\\A"]);
			if (cell->connections.count("\\B") > 0)
				B = assign_map(cell->connections["\\B"]);
			if (cell->connections.count("\\S") > 0)
				S = assign_map(cell->connections["\\S"]);
			A.replace(input_sig, RTLIL::SigSpec(in_val));
			B.replace(input_sig, RTLIL::SigSpec(in_val));
			S.replace(input_sig, RTLIL::SigSpec(in_val));
			assert(A.is_fully_const());
			assert(B.is_fully_const());
			assert(S.is_fully_const());
			truth_tab.push_back(ct.eval(cell, A.as_const(), B.as_const(), S.as_const()));
		}

		FsmData fsm_data;
		fsm_data.copy_from_cell(fsm_cell);

		fsm_data.num_inputs += input_sig.width;
		fsm_cell->connections["\\CTRL_IN"].append(input_sig);

		fsm_data.num_outputs += output_sig.width;
		fsm_cell->connections["\\CTRL_OUT"].append(output_sig);

		std::vector<FsmData::transition_t> new_transition_table;
		for (auto &tr : fsm_data.transition_table) {
			for (int i = 0; i < (1 << input_sig.width); i++) {
				FsmData::transition_t new_tr = tr;
				RTLIL::Const in_val(i, input_sig.width);
				RTLIL::Const out_val = truth_tab[i];
				RTLIL::SigSpec ctrl_in = new_tr.ctrl_in;
				RTLIL::SigSpec ctrl_out = new_tr.ctrl_out;
				ctrl_in.append(in_val);
				ctrl_out.append(out_val);
				new_tr.ctrl_in = ctrl_in.as_const();
				new_tr.ctrl_out = ctrl_out.as_const();
				new_transition_table.push_back(new_tr);
			}
		}
		fsm_data.transition_table.swap(new_transition_table);
		new_transition_table.clear();

		fsm_data.copy_to_cell(fsm_cell);
	}

	FsmExpand(RTLIL::Cell *cell, RTLIL::Design *design, RTLIL::Module *mod)
	{
		module = mod;
		fsm_cell = cell;

		assign_map.set(module);
		ct.setup_internals();

		for (auto &cell_it : module->cells) {
			RTLIL::Cell *c = cell_it.second;
			if (ct.cell_known(c->type) && design->selected(mod, c))
				for (auto &p : c->connections) {
					if (ct.cell_output(c->type, p.first))
						sig2driver.insert(assign_map(p.second), c);
					else
						sig2user.insert(assign_map(p.second), c);
				}
		}
	}

	void execute()
	{
		log("\n");
		log("Expanding FSM `%s' from module `%s':\n", fsm_cell->name.c_str(), module->name.c_str());

		already_optimized = false;
		limit_transitions =  16 * fsm_cell->parameters["\\TRANS_NUM"].as_int();

		for (create_current_set(); current_set.size() > 0; create_current_set()) {
			for (auto c : current_set)
				merge_cell_into_fsm(c);
		}

		for (auto c : merged_set) {
			module->cells.erase(c->name);
			delete c;
		}

		if (merged_set.size() > 0 && !already_optimized)
			FsmData::optimize_fsm(fsm_cell, module);

		log("  merged %zd cells into FSM.\n", merged_set.size());
	}
};

struct FsmExpandPass : public Pass {
	FsmExpandPass() : Pass("fsm_expand", "expand FSM cells by merging logic into it") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    fsm_expand [selection]\n");
		log("\n");
		log("The fsm_extract pass is conservative about the cells that belong to a finite\n");
		log("state machine. This pass can be used to merge additional auxiliary gates into\n");
		log("the finate state machine.\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		log_header("Executing FSM_EXPAND pass (merging auxiliary logic into FSMs).\n");
		extra_args(args, 1, design);

		for (auto &mod_it : design->modules) {
			if (!design->selected(mod_it.second))
				continue;
			std::vector<RTLIL::Cell*> fsm_cells;
			for (auto &cell_it : mod_it.second->cells)
				if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second))
					fsm_cells.push_back(cell_it.second);
			for (auto c : fsm_cells) {
				FsmExpand fsm_expand(c, design, mod_it.second);
				fsm_expand.execute();
			}
		}
	}
} FsmExpandPass;

<commit_msg>Changed fsm_expand to merge multiplexers more aggressively<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/log.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/consteval.h"
#include "kernel/celltypes.h"
#include "fsmdata.h"
#include <string.h>

struct FsmExpand
{
	RTLIL::Module *module;
	RTLIL::Cell *fsm_cell;
	SigMap assign_map;
	SigSet<RTLIL::Cell*> sig2driver, sig2user;
	CellTypes ct;

	std::set<RTLIL::Cell*> merged_set;
	std::set<RTLIL::Cell*> current_set;
	std::set<RTLIL::Cell*> no_candidate_set;

	bool already_optimized;
	int limit_transitions;

	bool is_cell_merge_candidate(RTLIL::Cell *cell)
	{
		if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux")
			return cell->connections.at("\\A").width < 2;

		RTLIL::SigSpec new_signals;
		if (cell->connections.count("\\A") > 0)
			new_signals.append(assign_map(cell->connections["\\A"]));
		if (cell->connections.count("\\B") > 0)
			new_signals.append(assign_map(cell->connections["\\B"]));
		if (cell->connections.count("\\S") > 0)
			new_signals.append(assign_map(cell->connections["\\S"]));

		new_signals.sort_and_unify();
		new_signals.remove_const();

		if (new_signals.width > 4)
			return false;

		new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_IN"]));
		new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_OUT"]));

		if (cell->connections.count("\\Y") > 0) {
			new_signals.append(assign_map(cell->connections["\\Y"]));
			new_signals.sort_and_unify();
			new_signals.remove_const();
			new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_IN"]));
			new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_OUT"]));
		}

		if (new_signals.width > 2)
			return false;

		return true;
	}

	void create_current_set()
	{
		std::vector<RTLIL::Cell*> cell_list;

		for (auto c : sig2driver.find(assign_map(fsm_cell->connections["\\CTRL_IN"])))
			cell_list.push_back(c);

		for (auto c : sig2user.find(assign_map(fsm_cell->connections["\\CTRL_OUT"])))
			cell_list.push_back(c);

		current_set.clear();
		for (auto c : cell_list)
		{
			if (merged_set.count(c) > 0 || current_set.count(c) > 0 || no_candidate_set.count(c) > 0)
				continue;
			for (auto &p : c->connections) {
				if (p.first != "\\A" && p.first != "\\B" && p.first != "\\S" && p.first != "\\Y")
					goto next_cell;
			}
			if (!is_cell_merge_candidate(c)) {
				no_candidate_set.insert(c);
				continue;
			}
			current_set.insert(c);
		next_cell:;
		}
	}

	void optimze_as_needed()
	{
		if (already_optimized)
			return;

		int trans_num = fsm_cell->parameters["\\TRANS_NUM"].as_int();
		if (trans_num > limit_transitions)
		{
			log("  grown transition table to %d entries -> optimize.\n", trans_num);
			FsmData::optimize_fsm(fsm_cell, module);
			already_optimized = true;

			trans_num = fsm_cell->parameters["\\TRANS_NUM"].as_int();
			log("  transition table size after optimizaton: %d\n", trans_num);
			limit_transitions = 16 * trans_num;
		}
	}

	void merge_cell_into_fsm(RTLIL::Cell *cell)
	{
		optimze_as_needed();

		log("  merging %s cell %s.\n", cell->type.c_str(), cell->name.c_str());
		merged_set.insert(cell);
		already_optimized = false;

		RTLIL::SigSpec input_sig, output_sig;

		for (auto &p : cell->connections)
			if (ct.cell_output(cell->type, p.first))
				output_sig.append(assign_map(p.second));
			else
				input_sig.append(assign_map(p.second));
		input_sig.sort_and_unify();
		input_sig.remove_const();

		assert(input_sig.width <= 4 || cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux");
		std::vector<RTLIL::Const> truth_tab;

		for (int i = 0; i < (1 << input_sig.width); i++) {
			RTLIL::Const in_val(i, input_sig.width);
			RTLIL::SigSpec A, B, S;
			if (cell->connections.count("\\A") > 0)
				A = assign_map(cell->connections["\\A"]);
			if (cell->connections.count("\\B") > 0)
				B = assign_map(cell->connections["\\B"]);
			if (cell->connections.count("\\S") > 0)
				S = assign_map(cell->connections["\\S"]);
			A.replace(input_sig, RTLIL::SigSpec(in_val));
			B.replace(input_sig, RTLIL::SigSpec(in_val));
			S.replace(input_sig, RTLIL::SigSpec(in_val));
			assert(A.is_fully_const());
			assert(B.is_fully_const());
			assert(S.is_fully_const());
			truth_tab.push_back(ct.eval(cell, A.as_const(), B.as_const(), S.as_const()));
		}

		FsmData fsm_data;
		fsm_data.copy_from_cell(fsm_cell);

		fsm_data.num_inputs += input_sig.width;
		fsm_cell->connections["\\CTRL_IN"].append(input_sig);

		fsm_data.num_outputs += output_sig.width;
		fsm_cell->connections["\\CTRL_OUT"].append(output_sig);

		std::vector<FsmData::transition_t> new_transition_table;
		for (auto &tr : fsm_data.transition_table) {
			for (int i = 0; i < (1 << input_sig.width); i++) {
				FsmData::transition_t new_tr = tr;
				RTLIL::Const in_val(i, input_sig.width);
				RTLIL::Const out_val = truth_tab[i];
				RTLIL::SigSpec ctrl_in = new_tr.ctrl_in;
				RTLIL::SigSpec ctrl_out = new_tr.ctrl_out;
				ctrl_in.append(in_val);
				ctrl_out.append(out_val);
				new_tr.ctrl_in = ctrl_in.as_const();
				new_tr.ctrl_out = ctrl_out.as_const();
				new_transition_table.push_back(new_tr);
			}
		}
		fsm_data.transition_table.swap(new_transition_table);
		new_transition_table.clear();

		fsm_data.copy_to_cell(fsm_cell);
	}

	FsmExpand(RTLIL::Cell *cell, RTLIL::Design *design, RTLIL::Module *mod)
	{
		module = mod;
		fsm_cell = cell;

		assign_map.set(module);
		ct.setup_internals();

		for (auto &cell_it : module->cells) {
			RTLIL::Cell *c = cell_it.second;
			if (ct.cell_known(c->type) && design->selected(mod, c))
				for (auto &p : c->connections) {
					if (ct.cell_output(c->type, p.first))
						sig2driver.insert(assign_map(p.second), c);
					else
						sig2user.insert(assign_map(p.second), c);
				}
		}
	}

	void execute()
	{
		log("\n");
		log("Expanding FSM `%s' from module `%s':\n", fsm_cell->name.c_str(), module->name.c_str());

		already_optimized = false;
		limit_transitions =  16 * fsm_cell->parameters["\\TRANS_NUM"].as_int();

		for (create_current_set(); current_set.size() > 0; create_current_set()) {
			for (auto c : current_set)
				merge_cell_into_fsm(c);
		}

		for (auto c : merged_set) {
			module->cells.erase(c->name);
			delete c;
		}

		if (merged_set.size() > 0 && !already_optimized)
			FsmData::optimize_fsm(fsm_cell, module);

		log("  merged %zd cells into FSM.\n", merged_set.size());
	}
};

struct FsmExpandPass : public Pass {
	FsmExpandPass() : Pass("fsm_expand", "expand FSM cells by merging logic into it") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    fsm_expand [selection]\n");
		log("\n");
		log("The fsm_extract pass is conservative about the cells that belong to a finite\n");
		log("state machine. This pass can be used to merge additional auxiliary gates into\n");
		log("the finate state machine.\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		log_header("Executing FSM_EXPAND pass (merging auxiliary logic into FSMs).\n");
		extra_args(args, 1, design);

		for (auto &mod_it : design->modules) {
			if (!design->selected(mod_it.second))
				continue;
			std::vector<RTLIL::Cell*> fsm_cells;
			for (auto &cell_it : mod_it.second->cells)
				if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second))
					fsm_cells.push_back(cell_it.second);
			for (auto c : fsm_cells) {
				FsmExpand fsm_expand(c, design, mod_it.second);
				fsm_expand.execute();
			}
		}
	}
} FsmExpandPass;

<|endoftext|>


<commit_before>//
// Copyright (c) 2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef TWSM_ECON_HPP
#define TWSM_ECON_HPP

#include "ui_main_window.h"

#include <twl/network/network.hpp>

#include <QObject>

namespace Ui
{class main_window;}

namespace twsm
{
	class econ : public QObject
	{
		Q_OBJECT

		Ui::main_window& m_ui;

		std::map<std::size_t, twl::econ_client> m_clients;
		mlk::uint m_current_id{0};

	public:
		econ(Ui::main_window& ui) :
			m_ui{ui}
		{ }

		void update()
		{
			for(auto& a : m_clients)
				a.second.update();
		}

		void init()
		{
			QObject::connect(m_ui.m_cb_ec_servers, SIGNAL(currentIndexChanged(int)), this, SLOT(switch_server(int)));

			QObject::connect(m_ui.m_pb_ec_connect, SIGNAL(clicked()), this, SLOT(connect()));
			QObject::connect(m_ui.m_pb_ec_change_map, SIGNAL(clicked()), this, SLOT(send_map_change()));
			QObject::connect(m_ui.m_pb_ec_reload_map, SIGNAL(clicked()), this, SLOT(send_reload_map()));
			QObject::connect(m_ui.m_pb_ec_start_recording, SIGNAL(clicked()), this, SLOT(send_start_recording()));
			QObject::connect(m_ui.m_pb_ec_stop_recording, SIGNAL(clicked()), this, SLOT(send_stop_recording()));
			QObject::connect(m_ui.m_pb_ec_set_broadcast, SIGNAL(clicked()), this, SLOT(send_broadcast()));
			QObject::connect(m_ui.m_pb_ec_restart_round, SIGNAL(clicked()), this, SLOT(send_restart()));
			QObject::connect(m_ui.m_pb_ec_send_chatmsg, SIGNAL(clicked()), this, SLOT(send_chat()));
			QObject::connect(m_ui.m_pb_ec_send_custom_cmd, SIGNAL(clicked()), this, SLOT(send_custom_cmd()));
			QObject::connect(m_ui.m_pb_ec_shutdown, SIGNAL(clicked()), this, SLOT(send_shutdown()));
		}

		void connect(const mlk::ntw::ip_address& addr, const std::string& passwd)
		{
			auto iter(mlk::cnt::find_in_if([&addr](const decltype(m_clients)::value_type& c){return c.second.address() == addr;}, m_clients));

			// connected, client needs login
			if(iter != std::end(m_clients))
			{
				if(!iter->second.connected())
					iter->second.connect(addr);

				if(!iter->second.logged_in())
					iter->second.login(passwd);
			}

			// not connected, client needs connection and login
			else
			{
				// create new client
				m_clients.emplace(m_current_id, addr);
				auto& cl(m_clients[m_current_id]);
				cl.on_log_added =
				[this, id = m_current_id](const std::string& str)
				{
					if((m_ui.m_cb_ec_servers->currentIndex() == 0) ||
					   (m_ui.m_cb_ec_servers->currentData().toInt() != static_cast<int>(id)))
						return;

					m_ui.m_te_ec_log->moveCursor(QTextCursor::End);
					m_ui.m_te_ec_log->insertPlainText(str.c_str());
					m_ui.m_te_ec_log->moveCursor(QTextCursor::End);
				};
				cl.on_connection = [this, id = m_current_id]{this->_on_connection(id);};
				cl.on_login = [this, id = m_current_id]{this->_on_login(id);};
				cl.on_connection_timeout = []{std::cout << "timeout" << std::endl;};
				cl.login(passwd);
				++m_current_id;

			}
		}

		void send_command(const twl::econ_command& cmd)
		{
			auto index(m_ui.m_cb_ec_servers->currentIndex());
			if(index == 0)
			{
				// apply on all connected servers
				for(auto& a : m_clients)
					a.second.send_command(cmd);
			}
			else if(index > 0)
			{
				// get id (index != id)
				auto id(m_ui.m_cb_ec_servers->itemData(index).toInt());
				m_clients[id].send_command(cmd);
			}
		}

	private:
		void _on_connection(mlk::uint id)
		{
			for(auto i(1); i < m_ui.m_cb_ec_servers->count(); ++i)
				if(m_ui.m_cb_ec_servers->itemData(i).toInt() == static_cast<int>(id))
				{
					// we were already connected, choose right item
					m_ui.m_cb_ec_servers->setCurrentIndex(i);
					return;
				}

			// new connection
			m_ui.m_cb_ec_servers->addItem(m_clients[id].address().to_string().c_str(), id);
			m_ui.m_cb_ec_servers->setCurrentIndex(m_ui.m_cb_ec_servers->count() - 1);
		}

		void _on_login(mlk::uint id)
		{

		}

	private slots:
		void switch_server(int index)
		{
			if(index == 0)
				return;
			auto id(m_ui.m_cb_ec_servers->itemData(index).toInt());

			// switch server, reset ui
			m_ui.m_te_ec_log->setText(m_clients[id].log().c_str());
		}

		void connect()
		{this->connect({QString{m_ui.m_le_ec_host->text() + ":" + m_ui.m_sb_ec_port->text()}.toStdString()}, m_ui.m_le_ec_passwd->text().toStdString());}

		void send_map_change()
		{this->send_command("change_map " + m_ui.m_le_ec_mapname->text().toStdString());}

		void send_reload_map()
		{this->send_command("reload");}

		void send_start_recording()
		{this->send_command("record " + m_ui.m_le_ec_recording_filename->text().toStdString());}

		void send_stop_recording()
		{this->send_command("stoprecord");}

		void send_broadcast()
		{this->send_command("broadcast " + m_ui.m_le_ec_broadcast->text().toStdString());}

		void send_restart()
		{this->send_command("restart " + m_ui.m_le_ec_restart_time->text().toStdString());}

		void send_chat()
		{this->send_command("say " + m_ui.m_le_ec_chatmsg->text().toStdString());}

		void send_custom_cmd()
		{this->send_command(m_ui.m_le_ec_custom_cmd->text().toStdString());}

		void send_shutdown()
		{this->send_command("shutdown");}
	};
}

#endif // TWSM_ECON_HPP

<commit_msg>econ: new stuff playertable ...<commit_after>//
// Copyright (c) 2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef TWSM_ECON_HPP
#define TWSM_ECON_HPP

#include "popup_manager.hpp"
#include "ui_main_window.h"

#include <twl/network/network.hpp>
#include <mlk/types/types.h>

#include <QObject>

namespace Ui
{class main_window;}

namespace twsm
{
	class econ : public QObject
	{
		Q_OBJECT

		Ui::main_window& m_ui;
		popup_manager& m_popupmgr;

		std::map<std::size_t, twl::econ_client> m_clients;
		mlk::uint m_current_id{0};

	public:
		econ(Ui::main_window& ui, popup_manager& pm) :
			m_ui(ui),
			m_popupmgr(pm)
		{ }

		void update()
		{
			for(auto& a : m_clients)
				a.second.update();
		}

		void init()
		{
			// static objects
			QObject::connect(m_ui.m_cb_ec_servers, SIGNAL(currentIndexChanged(int)), this, SLOT(switch_server(int)));
			QObject::connect(m_ui.m_pb_ec_connect, SIGNAL(clicked()), this, SLOT(connect()));

			// main page
			QObject::connect(m_ui.m_pb_ec_change_map, SIGNAL(clicked()), this, SLOT(send_map_change()));
			QObject::connect(m_ui.m_pb_ec_reload_map, SIGNAL(clicked()), this, SLOT(send_reload_map()));
			QObject::connect(m_ui.m_pb_ec_start_recording, SIGNAL(clicked()), this, SLOT(send_start_recording()));
			QObject::connect(m_ui.m_pb_ec_stop_recording, SIGNAL(clicked()), this, SLOT(send_stop_recording()));
			QObject::connect(m_ui.m_pb_ec_set_broadcast, SIGNAL(clicked()), this, SLOT(send_broadcast()));
			QObject::connect(m_ui.m_pb_ec_restart_round, SIGNAL(clicked()), this, SLOT(send_restart()));
			QObject::connect(m_ui.m_pb_ec_send_chatmsg, SIGNAL(clicked()), this, SLOT(send_chat()));
			QObject::connect(m_ui.m_pb_ec_send_custom_cmd, SIGNAL(clicked()), this, SLOT(send_custom_cmd()));
			QObject::connect(m_ui.m_pb_ec_shutdown, SIGNAL(clicked()), this, SLOT(send_shutdown()));

			// players page
			QObject::connect(m_ui.m_pb_ec_refresh_palyers, SIGNAL(clicked()), this, SLOT(request_playerinfo()));
		}

		void connect(const mlk::ntw::ip_address& addr, const std::string& passwd)
		{
			auto iter(mlk::cnt::find_in_if([&addr](const decltype(m_clients)::value_type& c){return c.second.address() == addr;}, m_clients));

			// connected, client needs login
			if(iter != std::end(m_clients))
			{
				if(!iter->second.connected())
					iter->second.connect(addr);

				if(!iter->second.logged_in())
					iter->second.login(passwd);
			}

			// not connected, client needs connection and login
			else
				this->create_new_client(addr, passwd);
		}

		void send_command(const twl::econ_command& cmd)
		{
			auto index(m_ui.m_cb_ec_servers->currentIndex());
			if(index == 0)
			{
				// apply on all connected servers
				for(auto& a : m_clients)
					a.second.send_command(cmd);
			}
			else if(index > 0)
			{
				// get id (index != id)
				auto id(m_ui.m_cb_ec_servers->itemData(index).toInt());
				m_clients[id].send_command(cmd);
			}
		}

	private:
		void create_new_client(const mlk::ntw::ip_address& addr, const std::string& passwd)
		{
			// create new client
			m_clients.emplace(m_current_id, addr);
			auto& cl(m_clients[m_current_id]);

			// setup the events
			cl.on_log_added = [this, id = m_current_id](const std::string& str){this->_on_log_added(id, str);};
			cl.on_connection = [this, id = m_current_id]{this->_on_connection(id);};
			cl.on_login = [this, id = m_current_id]{this->_on_login(id);};
			cl.on_connection_timeout = [this, id = m_current_id]{this->_on_connection_timeout(id);};
			cl.on_connection_lost = [this, id = m_current_id]{this->_on_connection_lost(id);};
			cl.on_playerinfo = [this, id = m_current_id](const twl::econ_player_infos& i){this->_on_playerinfo(id, i);};

			// login
			cl.login(passwd);
			++m_current_id;
		}

		// on client events
		void _on_log_added(mlk::uint id, const std::string& str)
		{
			// check if we need to log (is the 'id' the current active server?)
			if(!this->is_current_active(id))
				return;

			m_ui.m_te_ec_log->moveCursor(QTextCursor::End);
			m_ui.m_te_ec_log->insertPlainText(str.c_str());
			m_ui.m_te_ec_log->moveCursor(QTextCursor::End);
		}

		void _on_connection(mlk::uint id)
		{
			m_popupmgr.create_popup<popup_type::info>("Econ connected to " + this->addr_from_id(id));

			for(auto i(1); i < m_ui.m_cb_ec_servers->count(); ++i)
				if(m_ui.m_cb_ec_servers->itemData(i).toInt() == static_cast<int>(id))
				{
					// we were already connected, choose right item
					m_ui.m_cb_ec_servers->setCurrentIndex(i);
					return;
				}

			// new connection
			m_ui.m_cb_ec_servers->addItem(m_clients[id].address().to_string().c_str(), id);
			m_ui.m_cb_ec_servers->setCurrentIndex(m_ui.m_cb_ec_servers->count() - 1);
		}

		void _on_login(mlk::uint id)
		{
			m_popupmgr.create_popup<popup_type::info>("Econ logged in on " + this->addr_from_id(id));
		}

		void _on_connection_timeout(mlk::uint id)
		{
			m_popupmgr.create_popup<popup_type::warning>("Connection attempt timed out for " + this->addr_from_id(id));
		}

		void _on_connection_lost(mlk::uint id)
		{
			m_popupmgr.create_popup<popup_type::error>("Connection to " + this->addr_from_id(id) + " lost", 5000);
		}

		void _on_playerinfo(mlk::uint id, const twl::econ_player_infos&)
		{
			if(!this->is_current_active(id))
				return;
			this->load_playerinfos_to_table();
		}

		// utils
		bool is_current_active(mlk::uint id)
		{
			return ((m_ui.m_cb_ec_servers->currentIndex() != 0) &&
					(m_ui.m_cb_ec_servers->currentData().toInt() == static_cast<int>(id)));
		}

		std::string addr_from_id(mlk::uint id) const
		{return m_clients.at(id).address().to_string();}

	private slots:
		// ui events
		void switch_server(int index)
		{
			// load last playerinfos
			this->load_playerinfos_to_table();

			if(index <= 0)
				return;

			auto id(m_ui.m_cb_ec_servers->itemData(index).toInt());

			// switch server, reset ui
			m_ui.m_te_ec_log->setText(m_clients[id].log().c_str());
		}

		void load_playerinfos_to_table()
		{
			m_ui.m_tw_ec_players->clearContents();
			m_ui.m_tw_ec_players->setRowCount(0);

			if(m_ui.m_cb_ec_servers->currentIndex() == 0)
				return;

			// get needed infos
			auto id(m_ui.m_cb_ec_servers->currentData().toInt());
			const auto& infos(m_clients[id].last_playerinfos());

			// insert...
			for(const auto& a : infos)
			{
				auto row(m_ui.m_tw_ec_players->rowCount());
				m_ui.m_tw_ec_players->insertRow(row);

				auto* id(new QTableWidgetItem{a.id().c_str()});
				auto* name(new QTableWidgetItem{a.name().c_str()});
				auto* score(new QTableWidgetItem{a.score().c_str()});
				auto* addr(new QTableWidgetItem{a.addr().c_str()});
				m_ui.m_tw_ec_players->setItem(row, 0, id);
				m_ui.m_tw_ec_players->setItem(row, 1, name);
				m_ui.m_tw_ec_players->setItem(row, 2, score);
				m_ui.m_tw_ec_players->setItem(row, 3, addr);
			}
		}

		void connect()
		{this->connect({QString{m_ui.m_le_ec_host->text() + ":" + m_ui.m_sb_ec_port->text()}.toStdString()}, m_ui.m_le_ec_passwd->text().toStdString());}

		void send_map_change()
		{this->send_command("change_map " + m_ui.m_le_ec_mapname->text().toStdString());}

		void send_reload_map()
		{this->send_command("reload");}

		void send_start_recording()
		{this->send_command("record " + m_ui.m_le_ec_recording_filename->text().toStdString());}

		void send_stop_recording()
		{this->send_command("stoprecord");}

		void send_broadcast()
		{this->send_command("broadcast " + m_ui.m_le_ec_broadcast->text().toStdString());}

		void send_restart()
		{this->send_command("restart " + m_ui.m_le_ec_restart_time->text().toStdString());}

		void send_chat()
		{this->send_command("say " + m_ui.m_le_ec_chatmsg->text().toStdString());}

		void send_custom_cmd()
		{this->send_command(m_ui.m_le_ec_custom_cmd->text().toStdString());}

		void send_shutdown()
		{this->send_command("shutdown");}

		void request_playerinfo()
		{
			if(m_ui.m_cb_ec_servers->currentIndex() == 0)
				return;

			// clear old infos
			m_ui.m_tw_ec_players->clearContents();
			m_ui.m_tw_ec_players->setRowCount(0);

			auto id(m_ui.m_cb_ec_servers->currentData().toInt());
			m_clients[id].request_playerinfo();
		}
	};
}

#endif // TWSM_ECON_HPP

<|endoftext|>


<commit_before>#pragma once

#include <functional>

#include "geometry/affine_map.hpp"
#include "geometry/named_quantities.hpp"
#include "geometry/orthogonal_map.hpp"
#include "geometry/rotation.hpp"
#include "physics/degrees_of_freedom.hpp"
#include "quantities/quantities.hpp"

namespace principia {

using geometry::AffineMap;
using geometry::AngularVelocity;
using geometry::Instant;
using geometry::OrthogonalMap;
using geometry::Position;
using geometry::Vector;
using quantities::Acceleration;
using quantities::Length;

namespace physics {

// An arbitrary rigid transformation.  Simultaneous positions between two frames
// are always related by such a transformation.
template<typename FromFrame, typename ToFrame>
using RigidTransformation =
    AffineMap<FromFrame, ToFrame, Length, OrthogonalMap>;

// The instantaneous motion of |ToFrame| with respect to |FromFrame|.
// This is the derivative of a |RigidTransformation<FromFrame, ToFrame>|.
// In order to invert, the |RigidTransformation| is needed, and we need its
// linear part anyway, so we store it (and we forward its action on positions).
template<typename FromFrame, typename ToFrame>
class RigidMotion {
 public:
  RigidMotion(
      RigidTransformation<FromFrame, ToFrame> const& rigid_transformation,
      AngularVelocity<ToFrame> const& rotation,
      Velocity<ToFrame> const& translation);
  ~RigidMotion() = default;

  RigidTransformation<FromFrame, ToFrame> const& rigid_transformation() const;
  // Returns |rigid_transformation().linear_map()|.
  OrthogonalMap<FromFrame, ToFrame> const& orthogonal_map() const;

  DegreesOfFreedom<ToFrame> operator()(
      DegreesOfFreedom<FromFrame> const& degrees_of_freedom) const;

  RigidMotion<ToFrame, FromFrame> Inverse() const;

  template<typename From, typename Through, typename To>
  friend RigidMotion<From, To> operator*(
      RigidMotion<Through, To> const& left,
      RigidMotion<From, Through> const& right);

 private:
  RigidTransformation<FromFrame, ToFrame> rigid_transformation_;
  // d/dt rigid_transformation(basis of FromFrame). The positively oriented
  // orthogonal bases of |ToFrame| are acted upon faithfully and transitively by
  // SO(ToFrame), so this lies in the tangent space, i.e., the Lie algebra
  // 𝖘𝔬(ToFrame) ≅ ToFrame ∧ ToFrame.
  AngularVelocity<ToFrame> rotation_;
  // d/dt rigid_transformation(FromFrame::origin).
  Velocity<ToFrame> translation_;
};

template<typename FromFrame, typename ThroughFrame, typename ToFrame>
RigidMotion<FromFrame, ToFrame> operator*(
    RigidMotion<ThroughFrame, ToFrame> const& left,
    RigidMotion<FromFrame, ThroughFrame> const& right);

}  // namespace physics
}  // namespace principia

#include "physics/rigid_motion_body.hpp"
<commit_msg>after pleroy's second review<commit_after>#pragma once

#include <functional>

#include "geometry/affine_map.hpp"
#include "geometry/named_quantities.hpp"
#include "geometry/orthogonal_map.hpp"
#include "geometry/rotation.hpp"
#include "physics/degrees_of_freedom.hpp"
#include "quantities/quantities.hpp"

namespace principia {

using geometry::AffineMap;
using geometry::AngularVelocity;
using geometry::Instant;
using geometry::OrthogonalMap;
using geometry::Position;
using geometry::Vector;
using quantities::Acceleration;
using quantities::Length;

namespace physics {

// An arbitrary rigid transformation.  Simultaneous positions between two frames
// are always related by such a transformation.
template<typename FromFrame, typename ToFrame>
using RigidTransformation =
    AffineMap<FromFrame, ToFrame, Length, OrthogonalMap>;

// The instantaneous motion of |ToFrame| with respect to |FromFrame|.
// This is the derivative of a |RigidTransformation<FromFrame, ToFrame>|.
// In order to invert, the |RigidTransformation| is needed, and we need its
// linear part anyway, so we store it (and we forward its action on positions).
template<typename FromFrame, typename ToFrame>
class RigidMotion {
 public:
  RigidMotion(
      RigidTransformation<FromFrame, ToFrame> const& rigid_transformation,
      AngularVelocity<ToFrame> const& rotation,
      Velocity<ToFrame> const& translation);
  ~RigidMotion() = default;

  RigidTransformation<FromFrame, ToFrame> const& rigid_transformation() const;
  // Returns |rigid_transformation().linear_map()|.
  OrthogonalMap<FromFrame, ToFrame> const& orthogonal_map() const;

  DegreesOfFreedom<ToFrame> operator()(
      DegreesOfFreedom<FromFrame> const& degrees_of_freedom) const;

  RigidMotion<ToFrame, FromFrame> Inverse() const;

 private:
  RigidTransformation<FromFrame, ToFrame> rigid_transformation_;
  // d/dt rigid_transformation(basis of FromFrame). The positively oriented
  // orthogonal bases of |ToFrame| are acted upon faithfully and transitively by
  // SO(ToFrame), so this lies in the tangent space, i.e., the Lie algebra
  // 𝖘𝔬(ToFrame) ≅ ToFrame ∧ ToFrame.
  AngularVelocity<ToFrame> rotation_;
  // d/dt rigid_transformation(FromFrame::origin).
  Velocity<ToFrame> translation_;

  template<typename From, typename Through, typename To>
  friend RigidMotion<From, To> operator*(
      RigidMotion<Through, To> const& left,
      RigidMotion<From, Through> const& right);
};

template<typename FromFrame, typename ThroughFrame, typename ToFrame>
RigidMotion<FromFrame, ToFrame> operator*(
    RigidMotion<ThroughFrame, ToFrame> const& left,
    RigidMotion<FromFrame, ThroughFrame> const& right);

}  // namespace physics
}  // namespace principia

#include "physics/rigid_motion_body.hpp"
<|endoftext|>