<commit_before>/*=========================================================================

  Program:   Visualization Library
  Module:    Decimate.hh
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

This file is part of the Visualization Library. No part of this file
or its contents may be copied, reproduced or altered in any way
without the express written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
// .NAME vlDecimate - reduce the number of triangles in a mesh
// .SECTION Description
// vlDecimate is a filter to reduce the number of triangles in a triangle
// mesh, while preserving the original topology and a good approximation
// to the original geometry. The input to vlDecimate is a vlPolyData object,
// and only triangles are treated. If you desire to decimate polygonal
// meshes, first triangulate the polygons with the vlTriangleFilter object.
//    The algorithm proceeds as follows. Each vertex in the triangle
// list is evaluated for local planarity (i.e., the triangles using
// the vertex are gathered and compared to an "average" plane). If the
// region is locally planar, that is if the target vertex is within a
// certain distance of the average plane (i.e., the criterion), and
// there are no edges radiating from the vertex that have a dihedral angle
// greater than a user-specified edge angle (i.e., feature angle), and
// topology is not altered, then that vertex is deleted. The resulting
// hole is then patched by retriangulation. The process creates over
// the entire vertex list (this constitutes an iteration). Iterations
// proceed until a target reduction is reached or a maximum iteration
// count is exceeded.
//    There are a number of additional parameters you can set to control the
// decimation algorithm. The criterion may be increased over each iteration
// with a criterion increment. Edge preservation may be disabled or enabled.
// You can turn on/off edge vertex deletion. (Edge vertices are vertices that
// lie along boundaries of meshes). Sub iterations are iterations that are
// performed without changing the decimation criterion. The aspect ration
// controls the shape of the triangles that are created, and is
// the ratio of maximum edge length to minimum edge length. The degree
// is the number of triangles using a single vertex. Vertices of high degree
// are considered "complex" and are never deleted.

#ifndef __vlDecimate_h
#define __vlDecimate_h

#include "P2PF.hh"

#define NUMBER_STATISTICS 12

typedef struct vlVertex    Vertex, *VertexPtr;
struct vlVertex
  {
  int     id;
  float   FAngle;
  int     deRefs; //monitor memory requirements; new only when necessary
  int     newRefs;
  };

typedef struct vlTri    Tri, *TriPtr;
struct vlTri
  {
  int     id;
  float   area;
  float   n[3];
  int     verts[3];
  };

class vlDecimate : public vlPolyToPolyFilter
{
public:
  vlDecimate();
  ~vlDecimate() {};
  char *GetClassName() {return "vlDecimate";};
  void PrintSelf(ostream& os, vlIndent indent);

  // Description:
  // Set the decimation criterion. Expressed as a fraction of the diagonal
  // of the input data's bounding box.
  vlSetClampMacro(Criterion,float,0.0,1.0);
  vlGetMacro(Criterion,float);

  // Description:
  // Set the value of the increment by which to increase the decimation
  // criterion after each iteration.
  vlSetClampMacro(CriterionIncrement,float,0.0,1.0);
  vlGetMacro(CriterionIncrement,float);

  // Description:
  // Set the largest decimation criterion that can be achieved during
  // by incrementing criterion.
  vlSetClampMacro(MaximumCriterion,float,0.0,1.0);
  vlGetMacro(MaximumCriterion,float);

  // Description:
  // Specify the desired reduction in the total number of polygons. Because
  // of various constraints, this level of reduction may not be realizable.
  vlSetClampMacro(TargetReduction,float,0.0,1.0);
  vlGetMacro(TargetReduction,float);

  // Description:
  // Specify the maximum number of iterations to attempt. If decimation target
  // is reached first, this value will not be reached.
  vlSetClampMacro(MaximumIterations,int,1,LARGE_INTEGER);
  vlGetMacro(MaximumIterations,int);

  // Description:
  // Specify the maximum sub-iterations to perform. If no triangles are deleted
  // in a sub-iteration, the sub-iteration process is stopped.
  vlSetClampMacro(MaximumSubIterations,int,1,LARGE_INTEGER);
  vlGetMacro(MaximumSubIterations,int);

  // Description:
  // Specify the mesh feature angles.
  vlSetClampMacro(FeatureAngle,float,0.0,180.0);
  vlGetMacro(FeatureAngle,float);

  // Description:
  // Increment by which to increase feature angle over each iteration.
  vlSetClampMacro(FeatureAngleIncrement,float,0.0,180.0);
  vlGetMacro(FeatureAngleIncrement,float);

  // Description:
  // Set the largest permissable feature angle.
  vlSetClampMacro(MaximumFeatureAngle,float,0.0,180.0);
  vlGetMacro(MaximumFeatureAngle,float);

  // Description:
  // Turn on/off the preservation of feature edges.
  vlSetMacro(PreserveEdges,int);
  vlGetMacro(PreserveEdges,int);
  vlBooleanMacro(PreserveEdges,int);

  // Description:
  // Turn on/off the deletion of vertices on the boundary of a mesh.
  vlSetMacro(BoundaryVertexDeletion,int);
  vlGetMacro(BoundaryVertexDeletion,int);
  vlBooleanMacro(BoundaryVertexDeletion,int);

  // Description:
  // Specify the maximum allowable feature angle during triangulation.
  vlSetClampMacro(AspectRatio,float,1.0,1000.0);
  vlGetMacro(AspectRatio,float);

  // Description:
  // If the number of triangles connected to a vertex exceeds "Degree", then
  // the vertex is considered complex and is never deleted. (NOTE: the
  // complexity of the triangulation algorithm is proportional to Degree^2.)
  vlSetClampMacro(Degree,int,25,MAX_CELL_SIZE);
  vlGetMacro(Degree,int);

protected:
  void Execute();

  float FeatureAngle; // dihedral angle constraint
  float FeatureAngleIncrement;
  float MaximumFeatureAngle;
  int PreserveEdges; // do/don't worry about feature edges
  int BoundaryVertexDeletion;
  float Criterion; // decimation criterion in fraction of bounding box
  float CriterionIncrement; // each iteration will bump criterion this amount
  float MaximumCriterion; // maximum criterion
  float TargetReduction; //target reduction of mesh (fraction)
  int MaximumIterations; // maximum number of passes over data
  int MaximumSubIterations; // maximum non-incrementing passes
  float AspectRatio; // control triangle shape during triangulation
  int Degree; // maximum number of triangles incident on vertex
  int Stats[NUMBER_STATISTICS]; // keep track of interesting statistics

  int BuildLoop(int ptId, unsigned short int nTris, int* tris);
  void EvaluateLoop(int ptId, int& vtype, int& numFEdges, VertexPtr fedges[]);
  int CanSplitLoop(VertexPtr fedges[2], int numVerts, VertexPtr verts[],
                  int& n1, VertexPtr l1[], int& n2, VertexPtr l2[], float& ar);
  void SplitLoop(VertexPtr fedges[2], int numVerts, VertexPtr *verts,
                   int& n1, VertexPtr *l1, int& n2, VertexPtr *l2);
  void Triangulate(int numVerts, VertexPtr verts[]);
};

#endif

<commit_msg>ENH: Made subclassable.<commit_after>/*=========================================================================

  Program:   Visualization Library
  Module:    Decimate.hh
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

This file is part of the Visualization Library. No part of this file
or its contents may be copied, reproduced or altered in any way
without the express written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
// .NAME vlDecimate - reduce the number of triangles in a mesh
// .SECTION Description
// vlDecimate is a filter to reduce the number of triangles in a triangle
// mesh, while preserving the original topology and a good approximation
// to the original geometry. The input to vlDecimate is a vlPolyData object,
// and only triangles are treated. If you desire to decimate polygonal
// meshes, first triangulate the polygons with the vlTriangleFilter object.
//    The algorithm proceeds as follows. Each vertex in the triangle
// list is evaluated for local planarity (i.e., the triangles using
// the vertex are gathered and compared to an "average" plane). If the
// region is locally planar, that is if the target vertex is within a
// certain distance of the average plane (i.e., the criterion), and
// there are no edges radiating from the vertex that have a dihedral angle
// greater than a user-specified edge angle (i.e., feature angle), and
// topology is not altered, then that vertex is deleted. The resulting
// hole is then patched by retriangulation. The process creates over
// the entire vertex list (this constitutes an iteration). Iterations
// proceed until a target reduction is reached or a maximum iteration
// count is exceeded.
//    There are a number of additional parameters you can set to control the
// decimation algorithm. The criterion may be increased over each iteration
// with a criterion increment. Edge preservation may be disabled or enabled.
// You can turn on/off edge vertex deletion. (Edge vertices are vertices that
// lie along boundaries of meshes). Sub iterations are iterations that are
// performed without changing the decimation criterion. The aspect ration
// controls the shape of the triangles that are created, and is
// the ratio of maximum edge length to minimum edge length. The degree
// is the number of triangles using a single vertex. Vertices of high degree
// are considered "complex" and are never deleted.

#ifndef __vlDecimate_h
#define __vlDecimate_h

#include "P2PF.hh"
#include "vlMath.hh"
#include "Triangle.hh"
#include "Plane.hh"
#include "Polygon.hh"
#include "Line.hh"

#define NUMBER_STATISTICS 12
#define TOLERANCE 1.0e-05

#define MAX_TRIS_PER_VERTEX MAX_CELL_SIZE
#define MAX_SQUAWKS 10

#define COMPLEX_VERTEX 0
#define SIMPLE_VERTEX 1
#define BOUNDARY_VERTEX 2
#define INTERIOR_EDGE_VERTEX 3
#define CORNER_VERTEX 4

#define ELIMINATED_DISTANCE_TO_PLANE 5
#define ELIMINATED_DISTANCE_TO_EDGE 6
#define FAILED_DEGREE_TEST 7
#define FAILED_NON_MANIFOLD 8
#define FAILED_ZERO_AREA_TEST 9
#define FAILED_ZERO_NORMAL_TEST 10
#define FAILED_TO_TRIANGULATE 11

// Special structures for building loops
typedef struct vlVertex    Vertex, *VertexPtr;
struct vlVertex
  {
  int     id;
  float   FAngle;
  int     deRefs; //monitor memory requirements; new only when necessary
  int     newRefs;
  };

typedef struct vlTri    Tri, *TriPtr;
struct vlTri
  {
  int     id;
  float   area;
  float   n[3];
  int     verts[3];
  };

//
// Special classes for manipulating data
//
class vlVertexArray { //;prevent man page generation
public:
  vlVertexArray(const int sz)
    {this->MaxId = -1; this->Array = new struct vlVertex[sz];};
  ~vlVertexArray() {if (this->Array) delete [] this->Array;};
  int GetNumberOfVertices() {return this->MaxId + 1;};
  void InsertNextVertex(vlVertex& v)
    {this->MaxId++; this->Array[this->MaxId] = v;};
  struct vlVertex& GetVertex(int i) {return this->Array[i];};
  void Reset() {this->MaxId = -1;};

  struct vlVertex *Array;  // pointer to data
  int MaxId;             // maximum index inserted thus far
};

class vlTriArray { //;prevent man page generation
public:
  vlTriArray(const int sz)
    {this->MaxId = -1; this->Array = new struct vlTri[sz];};
  ~vlTriArray() {if (this->Array) delete [] this->Array;};
  int GetNumberOfTriangles() {return this->MaxId + 1;};
  void InsertNextTriangle(vlTri& t)
    {this->MaxId++; this->Array[this->MaxId] = t;};
  struct vlTri& GetTriangle(int i) {return this->Array[i];};
  void Reset() {this->MaxId = -1;};

  struct vlTri *Array;  // pointer to data
  int MaxId;            // maximum index inserted thus far
};

//
//  Static variables used by object
//
static vlPlane plane; // eliminate constructor overhead
static vlLine line;
static vlTriangle triangle;
static vlMath math;

static vlPolyData *Mesh; // operate on this data structure
static float Pt[3], Normal[3]; // least squares plane point & normal
static float Angle, Distance; // current feature angle and distance
static float CosAngle; // Cosine of dihedral angle

static float Tolerance; // Intersection tolerance
static float AspectRatio2; // Allowable aspect ratio
static int ContinueTriangulating; // Stops recursive tri. if necessary
static int Squawks; // Control output

// temporary working arrays
static vlVertexArray V(MAX_TRIS_PER_VERTEX+1);//cycle of vertices around point
static vlTriArray T(MAX_TRIS_PER_VERTEX+1); //cycle of triangles around point

class vlDecimate : public vlPolyToPolyFilter
{
public:
  vlDecimate();
  ~vlDecimate() {};
  char *GetClassName() {return "vlDecimate";};
  void PrintSelf(ostream& os, vlIndent indent);

  // Description:
  // Set the decimation criterion. Expressed as a fraction of the diagonal
  // of the input data's bounding box.
  vlSetClampMacro(Criterion,float,0.0,1.0);
  vlGetMacro(Criterion,float);

  // Description:
  // Set the value of the increment by which to increase the decimation
  // criterion after each iteration.
  vlSetClampMacro(CriterionIncrement,float,0.0,1.0);
  vlGetMacro(CriterionIncrement,float);

  // Description:
  // Set the largest decimation criterion that can be achieved during
  // by incrementing criterion.
  vlSetClampMacro(MaximumCriterion,float,0.0,1.0);
  vlGetMacro(MaximumCriterion,float);

  // Description:
  // Specify the desired reduction in the total number of polygons. Because
  // of various constraints, this level of reduction may not be realizable.
  vlSetClampMacro(TargetReduction,float,0.0,1.0);
  vlGetMacro(TargetReduction,float);

  // Description:
  // Specify the maximum number of iterations to attempt. If decimation target
  // is reached first, this value will not be reached.
  vlSetClampMacro(MaximumIterations,int,1,LARGE_INTEGER);
  vlGetMacro(MaximumIterations,int);

  // Description:
  // Specify the maximum sub-iterations to perform. If no triangles are deleted
  // in a sub-iteration, the sub-iteration process is stopped.
  vlSetClampMacro(MaximumSubIterations,int,1,LARGE_INTEGER);
  vlGetMacro(MaximumSubIterations,int);

  // Description:
  // Specify the mesh feature angles.
  vlSetClampMacro(FeatureAngle,float,0.0,180.0);
  vlGetMacro(FeatureAngle,float);

  // Description:
  // Increment by which to increase feature angle over each iteration.
  vlSetClampMacro(FeatureAngleIncrement,float,0.0,180.0);
  vlGetMacro(FeatureAngleIncrement,float);

  // Description:
  // Set the largest permissable feature angle.
  vlSetClampMacro(MaximumFeatureAngle,float,0.0,180.0);
  vlGetMacro(MaximumFeatureAngle,float);

  // Description:
  // Turn on/off the preservation of feature edges.
  vlSetMacro(PreserveEdges,int);
  vlGetMacro(PreserveEdges,int);
  vlBooleanMacro(PreserveEdges,int);

  // Description:
  // Turn on/off the deletion of vertices on the boundary of a mesh.
  vlSetMacro(BoundaryVertexDeletion,int);
  vlGetMacro(BoundaryVertexDeletion,int);
  vlBooleanMacro(BoundaryVertexDeletion,int);

  // Description:
  // Specify the maximum allowable feature angle during triangulation.
  vlSetClampMacro(AspectRatio,float,1.0,1000.0);
  vlGetMacro(AspectRatio,float);

  // Description:
  // If the number of triangles connected to a vertex exceeds "Degree", then
  // the vertex is considered complex and is never deleted. (NOTE: the
  // complexity of the triangulation algorithm is proportional to Degree^2.)
  vlSetClampMacro(Degree,int,25,MAX_CELL_SIZE);
  vlGetMacro(Degree,int);

protected:
  void Execute();

  float FeatureAngle; // dihedral angle constraint
  float FeatureAngleIncrement;
  float MaximumFeatureAngle;
  int PreserveEdges; // do/don't worry about feature edges
  int BoundaryVertexDeletion;
  float Criterion; // decimation criterion in fraction of bounding box
  float CriterionIncrement; // each iteration will bump criterion this amount
  float MaximumCriterion; // maximum criterion
  float TargetReduction; //target reduction of mesh (fraction)
  int MaximumIterations; // maximum number of passes over data
  int MaximumSubIterations; // maximum non-incrementing passes
  float AspectRatio; // control triangle shape during triangulation
  int Degree; // maximum number of triangles incident on vertex
  int Stats[NUMBER_STATISTICS]; // keep track of interesting statistics

  void CreateOutput(int numPts, int numTris, int numEliminated,
                    vlPointData *pd, vlPoints *inPts);
  int BuildLoop(int ptId, unsigned short int nTris, int* tris);
  void EvaluateLoop(int ptId, int& vtype, int& numFEdges, VertexPtr fedges[]);
  int CanSplitLoop(VertexPtr fedges[2], int numVerts, VertexPtr verts[],
                  int& n1, VertexPtr l1[], int& n2, VertexPtr l2[], float& ar);
  void SplitLoop(VertexPtr fedges[2], int numVerts, VertexPtr *verts,
                   int& n1, VertexPtr *l1, int& n2, VertexPtr *l2);
  void Triangulate(int numVerts, VertexPtr verts[]);
};

#endif

<|endoftext|>


<commit_before>#include <avr/io.h>
#include <util/delay.h>
#include <avr/sleep.h>
#include <stdio.h>

#include "testHooks.h"
#include "TestStreams.h"

#include "comms/NMEA.h"
//TESTING "comms/NMEA.cpp"
//TESTING "math/GreatCircle.cpp"
//TESTING "math/Waypoint.cpp"
//TESTING "math/SpatialMath.cpp"

typedef struct GPRMC{
    const char * desc;
    const char * str;
    float time;
    bool  active;
    float latitude;
    float longitude;
    float speed;
    float trackAngle;
    long  date;
    float magVar;
} GPRMC;

/*
lat/lon is in degrees+decimal minutes, code spec is decimal degrees
function decimalDegrees(degreeDecimalMinutes)
    minutes = degreeDecimalMinutes % 100.0
    degrees = (degreeDecimalMinutes - minutes) / 100.0
    decimalDegrees = degrees + minutes/60.0
    return decimalDegrees
end

speed in GPRMC is in knots, code spec returns mph
mph(knots) = knots * 1.15077945
*/

//examples taken from http://www.gpsinformation.org/dale/nmea.htm
const GPRMC goodData[] {
    { "NE GPRMC",
      "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A",
      123519, true, 48.11729, 11.51666, 25.77746, 84.4, 230394, 3.1
    },
    { "NW GPRMC",
      "$GPRMC,183729,A,3907.356,N,12102.482,W,000.0,360.0,080301,015.5,E*6F",
      183729, true, 39.12260, -121.04136, 0.0, 360.0, 80301, 15.5
    },
    { "Bad Status",
      "$GPRMC,152926,V,6027.8259,N,02225.6713,E,10.8,0.0,190803,5.9,E,S*22",
      152926, false, 60.46376, 22.42786, 12.428418, 0.0, 190803, 5.9
    },
    { "Empty Fields",
      "$GPRMC,162254.00,A,3723.02837,N,12159.39853,W,0.820,188.36,110706,,,A*74",
      162254, true, 37.38380, -121.98998, 0.94364, 188.36, 110706, 0.0
    },
    { "DecimalTime",
      "$GPRMC,230611.016,V,3907.3813,N,12102.4635,W,0.14,136.40,041002,,*04",
      230611.016, false, 39.12302, -121.04106, 0.161109, 136.40, 41002, 0.0
    },
    { "Surrounded GPRMC",
      "$GPGSV,3,3,09,24,12,282,00*4D"
      "$GPGLL,3553.5295,N,13938.6570,E,002454,A,A*4F"
      "$GPBOD,,T,,M,,*47"
      "$PGRME,8.6,M,9.6,M,12.9,M*15"
      "$PGRMZ,51,f*30"
      "$HCHDG,101.1,,,7.1,W*3C"
      "$GPRTE,1,1,c,*37"
      "$GPRMC,002456,A,3553.5295,N,13938.6570,E,0.0,43.1,180700,7.1,W,A*3D"
      "$GPGGA,002454,3553.5295,N,13938.6570,E,1,05,2.2,18.3,M,39.0,M,,*7F"
      "$GPGSA,A,3,01,04,07,16,20,,,,,,,,3.6,2.2,2.7*35"
      "$GPGSV,3,1,09,01,38,103,37,02,23,215,00,04,38,297,37,05,00,328,00*70"
      "$GPGSV,3,2,09,07,77,299,47,11,07,087,00,16,74,041,47,20,38,044,43*73",
      2456, true, 35.89215, 139.64428, 0.0, 43.1, 180700,7.1
    },
};
const int numGoodData = sizeof(goodData)/sizeof(goodData[0]);

const char * badStrings[] {
    "4807.038,N,01131.00000-100.4,E,022.4,084.4,2303946544563217896,003.1,W*6A",
    "$$$$$$$$$$$",
    "$,,,,,,,,,,,,,,,,,,,",
    "$GPRMC,,,,,,,,,,,,,,,,,,",
    "$GPRMC$",
    "$GPRMC,123519,X,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A",
    "$GPRMC,X,X,X,X,X,X,X,X,X,X,XXXX",
    "$GPRMC,123519549631488436214567/89321456,A,",
    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
};
const int numBadStrings = sizeof(badStrings)/sizeof(badStrings[0]);

#define nmeaOfString(s) \
    StringStream ss(s); \
    NMEA nmea(ss); \
    nmea.update();

bool parseTime(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        FPASSERT(nmea.getTimeOfFix(), goodData[i].time);
    }
    return true;
}
bool parseActive(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        CASSERT(nmea.getWarning(), !goodData[i].active);
    }
    return true;
}
bool parseLatitude(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        FPASSERT(nmea.getLatitude(), goodData[i].latitude);
    }
    return true;
}
bool parseLongitude(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        FPASSERT(nmea.getLongitude(), goodData[i].longitude);
    }
    return true;
}
bool parseSpeed(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        FPASSERT(nmea.getGroundSpeed(), goodData[i].speed);
    }
    return true;
}
bool parseTrackAngle(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        FPASSERT(nmea.getCourse(), goodData[i].trackAngle);
    }
    return true;
}
bool parseDate(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        CASSERT(nmea.getDateOfFix(), goodData[i].date);
    }
    return true;
}
bool parseMagVar(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        FPASSERT(nmea.getMagVar(), goodData[i].magVar);
    }
    return true;
}
bool delayedInput(){
    char charContainer[] = {'_', '\0'};
    StringStream ss(charContainer);
    NMEA nmea(ss);
    for(int i=0; i<strlen(goodData[0].str); i++){
        charContainer[0] = goodData[0].str[i];
        ss.reset(charContainer);
        nmea.update();
    }
    FPASSERT(goodData[0].time, nmea.getTimeOfFix());
    CASSERT( goodData[0].active, !nmea.getWarning());
    FPASSERT(goodData[0].latitude, nmea.getLatitude());
    FPASSERT(goodData[0].longitude, nmea.getLongitude());
    FPASSERT(goodData[0].speed, nmea.getGroundSpeed());
    FPASSERT(goodData[0].trackAngle, nmea.getCourse());
    CASSERT( goodData[0].date, nmea.getDateOfFix());
    FPASSERT(goodData[0].magVar, nmea.getMagVar());
    return true;
}
bool testNewInput(){
    StringStream ss(goodData[0].str);
    NMEA nmea(ss);
    ASSERT(!nmea.newData());
    nmea.update();
    ASSERT(nmea.newData());
    nmea.getLatitude();
    ASSERT(!nmea.newData());
    nmea.update();
    ASSERT(!nmea.newData());
    return true;
}
bool badStringFirst(){
    // test that the parser can recover from getting a bunch of bad data first
    for(int i=0; i<numBadStrings; i++){
        StringStream ss(badStrings[i]);
        NMEA nmea(ss);
        nmea.update();
        ss.reset(goodData[0].str);
        nmea.update();

        FPASSERT(goodData[0].time, nmea.getTimeOfFix());
        CASSERT( goodData[0].active, !nmea.getWarning());
        FPASSERT(goodData[0].latitude, nmea.getLatitude());
        FPASSERT(goodData[0].longitude, nmea.getLongitude());
        FPASSERT(goodData[0].speed, nmea.getGroundSpeed());
        FPASSERT(goodData[0].trackAngle, nmea.getCourse());
        CASSERT( goodData[0].date, nmea.getDateOfFix());
        FPASSERT(goodData[0].magVar, nmea.getMagVar());
    }
    return true;
}
bool skipEmptyFields(){
    StringStream ss("$GPRMC,000523.036,V,,,,,0.00,0.00,060180,,,N*43");
    NMEA nmea(ss);
    nmea.update();

    CASSERT(true, nmea.getWarning());
    CASSERT(60180, nmea.getDateOfFix());
    FPASSERT(523.036, nmea.getTimeOfFix());
    FPASSERT(0.0, nmea.getGroundSpeed());
    FPASSERT(0.0, nmea.getCourse());
    return true;
}
void benchmark(){
    for(int i=0; i<numGoodData; i++){
        StringStream ss(goodData[i].str);
        NMEA nmea(ss);
        beginTest("parse %s", goodData[i].desc);
        nmea.update();
        benchFinish();
    }
}

int main(void){
    TEST(parseTime       );
    TEST(parseActive     );
    TEST(parseLatitude   );
    TEST(parseLongitude  );
    TEST(parseSpeed      );
    TEST(parseTrackAngle );
    TEST(parseDate       );
    TEST(parseMagVar     );
    TEST(badStringFirst  );
    TEST(delayedInput    );
    TEST(testNewInput    );
    TEST(skipEmptyFields );
    benchmark();
    return 0;
}
<commit_msg>Last direction character should invert magnetic variation angle<commit_after>#include <avr/io.h>
#include <util/delay.h>
#include <avr/sleep.h>
#include <stdio.h>

#include "testHooks.h"
#include "TestStreams.h"

#include "comms/NMEA.h"
//TESTING "comms/NMEA.cpp"
//TESTING "math/GreatCircle.cpp"
//TESTING "math/Waypoint.cpp"
//TESTING "math/SpatialMath.cpp"

typedef struct GPRMC{
    const char * desc;
    const char * str;
    float time;
    bool  active;
    float latitude;
    float longitude;
    float speed;
    float trackAngle;
    long  date;
    float magVar;
} GPRMC;

/*
lat/lon is in degrees+decimal minutes, code spec is decimal degrees
function decimalDegrees(degreeDecimalMinutes)
    minutes = degreeDecimalMinutes % 100.0
    degrees = (degreeDecimalMinutes - minutes) / 100.0
    decimalDegrees = degrees + minutes/60.0
    return decimalDegrees
end

speed in GPRMC is in knots, code spec returns mph
mph(knots) = knots * 1.15077945
*/

//examples taken from http://www.gpsinformation.org/dale/nmea.htm
const GPRMC goodData[] {
    { "NE GPRMC",
      "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A",
      123519, true, 48.11729, 11.51666, 25.77746, 84.4, 230394, 3.1
    },
    { "NW GPRMC",
      "$GPRMC,183729,A,3907.356,N,12102.482,W,000.0,360.0,080301,015.5,E*6F",
      183729, true, 39.12260, -121.04136, 0.0, 360.0, 80301, -15.5
    },
    { "Bad Status",
      "$GPRMC,152926,V,6027.8259,N,02225.6713,E,10.8,0.0,190803,5.9,E,S*22",
      152926, false, 60.46376, 22.42786, 12.428418, 0.0, 190803, -5.9
    },
    { "Empty Fields",
      "$GPRMC,162254.00,A,3723.02837,N,12159.39853,W,0.820,188.36,110706,,,A*74",
      162254, true, 37.38380, -121.98998, 0.94364, 188.36, 110706, 0.0
    },
    { "DecimalTime",
      "$GPRMC,230611.016,V,3907.3813,N,12102.4635,W,0.14,136.40,041002,,*04",
      230611.016, false, 39.12302, -121.04106, 0.161109, 136.40, 41002, 0.0
    },
    { "Surrounded GPRMC",
      "$GPGSV,3,3,09,24,12,282,00*4D"
      "$GPGLL,3553.5295,N,13938.6570,E,002454,A,A*4F"
      "$GPBOD,,T,,M,,*47"
      "$PGRME,8.6,M,9.6,M,12.9,M*15"
      "$PGRMZ,51,f*30"
      "$HCHDG,101.1,,,7.1,W*3C"
      "$GPRTE,1,1,c,*37"
      "$GPRMC,002456,A,3553.5295,N,13938.6570,E,0.0,43.1,180700,7.1,W,A*3D"
      "$GPGGA,002454,3553.5295,N,13938.6570,E,1,05,2.2,18.3,M,39.0,M,,*7F"
      "$GPGSA,A,3,01,04,07,16,20,,,,,,,,3.6,2.2,2.7*35"
      "$GPGSV,3,1,09,01,38,103,37,02,23,215,00,04,38,297,37,05,00,328,00*70"
      "$GPGSV,3,2,09,07,77,299,47,11,07,087,00,16,74,041,47,20,38,044,43*73",
      2456, true, 35.89215, 139.64428, 0.0, 43.1, 180700,7.1
    },
};
const int numGoodData = sizeof(goodData)/sizeof(goodData[0]);

const char * badStrings[] {
    "4807.038,N,01131.00000-100.4,E,022.4,084.4,2303946544563217896,003.1,W*6A",
    "$$$$$$$$$$$",
    "$,,,,,,,,,,,,,,,,,,,",
    "$GPRMC,,,,,,,,,,,,,,,,,,",
    "$GPRMC$",
    "$GPRMC,123519,X,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A",
    "$GPRMC,X,X,X,X,X,X,X,X,X,X,XXXX",
    "$GPRMC,123519549631488436214567/89321456,A,",
    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
};
const int numBadStrings = sizeof(badStrings)/sizeof(badStrings[0]);

#define nmeaOfString(s) \
    StringStream ss(s); \
    NMEA nmea(ss); \
    nmea.update();

bool parseTime(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        FPASSERT(nmea.getTimeOfFix(), goodData[i].time);
    }
    return true;
}
bool parseActive(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        CASSERT(nmea.getWarning(), !goodData[i].active);
    }
    return true;
}
bool parseLatitude(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        FPASSERT(nmea.getLatitude(), goodData[i].latitude);
    }
    return true;
}
bool parseLongitude(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        FPASSERT(nmea.getLongitude(), goodData[i].longitude);
    }
    return true;
}
bool parseSpeed(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        FPASSERT(nmea.getGroundSpeed(), goodData[i].speed);
    }
    return true;
}
bool parseTrackAngle(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        FPASSERT(nmea.getCourse(), goodData[i].trackAngle);
    }
    return true;
}
bool parseDate(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        CASSERT(nmea.getDateOfFix(), goodData[i].date);
    }
    return true;
}
bool parseMagVar(){
    for(int i=0; i<numGoodData; i++){
        nmeaOfString(goodData[i].str);
        FPASSERT(nmea.getMagVar(), goodData[i].magVar);
    }
    return true;
}
bool delayedInput(){
    char charContainer[] = {'_', '\0'};
    StringStream ss(charContainer);
    NMEA nmea(ss);
    for(int i=0; i<strlen(goodData[0].str); i++){
        charContainer[0] = goodData[0].str[i];
        ss.reset(charContainer);
        nmea.update();
    }
    FPASSERT(goodData[0].time, nmea.getTimeOfFix());
    CASSERT( goodData[0].active, !nmea.getWarning());
    FPASSERT(goodData[0].latitude, nmea.getLatitude());
    FPASSERT(goodData[0].longitude, nmea.getLongitude());
    FPASSERT(goodData[0].speed, nmea.getGroundSpeed());
    FPASSERT(goodData[0].trackAngle, nmea.getCourse());
    CASSERT( goodData[0].date, nmea.getDateOfFix());
    FPASSERT(goodData[0].magVar, nmea.getMagVar());
    return true;
}
bool testNewInput(){
    StringStream ss(goodData[0].str);
    NMEA nmea(ss);
    ASSERT(!nmea.newData());
    nmea.update();
    ASSERT(nmea.newData());
    nmea.getLatitude();
    ASSERT(!nmea.newData());
    nmea.update();
    ASSERT(!nmea.newData());
    return true;
}
bool badStringFirst(){
    // test that the parser can recover from getting a bunch of bad data first
    for(int i=0; i<numBadStrings; i++){
        StringStream ss(badStrings[i]);
        NMEA nmea(ss);
        nmea.update();
        ss.reset(goodData[0].str);
        nmea.update();

        FPASSERT(goodData[0].time, nmea.getTimeOfFix());
        CASSERT( goodData[0].active, !nmea.getWarning());
        FPASSERT(goodData[0].latitude, nmea.getLatitude());
        FPASSERT(goodData[0].longitude, nmea.getLongitude());
        FPASSERT(goodData[0].speed, nmea.getGroundSpeed());
        FPASSERT(goodData[0].trackAngle, nmea.getCourse());
        CASSERT( goodData[0].date, nmea.getDateOfFix());
        FPASSERT(goodData[0].magVar, nmea.getMagVar());
    }
    return true;
}
bool skipEmptyFields(){
    StringStream ss("$GPRMC,000523.036,V,,,,,0.00,0.00,060180,,,N*43");
    NMEA nmea(ss);
    nmea.update();

    CASSERT(true, nmea.getWarning());
    CASSERT(60180, nmea.getDateOfFix());
    FPASSERT(523.036, nmea.getTimeOfFix());
    FPASSERT(0.0, nmea.getGroundSpeed());
    FPASSERT(0.0, nmea.getCourse());
    return true;
}
void benchmark(){
    for(int i=0; i<numGoodData; i++){
        StringStream ss(goodData[i].str);
        NMEA nmea(ss);
        beginTest("parse %s", goodData[i].desc);
        nmea.update();
        benchFinish();
    }
}

int main(void){
    TEST(parseTime       );
    TEST(parseActive     );
    TEST(parseLatitude   );
    TEST(parseLongitude  );
    TEST(parseSpeed      );
    TEST(parseTrackAngle );
    TEST(parseDate       );
    TEST(parseMagVar     );
    TEST(badStringFirst  );
    TEST(delayedInput    );
    TEST(testNewInput    );
    TEST(skipEmptyFields );
    benchmark();
    return 0;
}
<|endoftext|>


<commit_before>#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
#include <time.h>
#include <vector>

#include <deal.II/base/mpi.h>
#include "gtest/gtest.h"

#include "test_helpers/gmock_wrapper.h"
#include "test_helpers/bart_test_helper.h"

int main(int argc, char** argv) {
  // Parse optional arguments

  int option_index = 0, c = 0;
  bool use_mpi = false;
  std::string filter = "";

  const struct option longopts[] =
  {
    {"filter", no_argument, NULL, 'f'},
    {"report", no_argument, NULL, 'r'},
    {"mpi",    no_argument, NULL, 'm'},
    {NULL,     0,           NULL,   0}
  };

  while ((c = getopt_long (argc, argv, "rmd:f:", longopts, &option_index)) != -1) {
    switch(c) {
      case 'r': {
        btest::GlobalBARTTestHelper().SetReport(true);
        break;
      }
      case 'd': {
        btest::GlobalBARTTestHelper().SetGoldFilesDirectory(optarg);
        break;
      }
      case 'm': {
        use_mpi = true;
        break;
      }
      case 'f': {
        filter = optarg;
        break;
      }
      default:
        break;
    }
  }

  std::vector<const char*> new_argv(argv, argv + argc);
  if (filter != "") {
    filter = "--gtest_filter=" + filter;
    new_argv.push_back(filter.c_str());
  } else if (use_mpi) {
      new_argv.push_back("--gtest_filter=*MPI*");
  } else {
    new_argv.push_back("--gtest_filter=-*MPIOnly*");
  }

  new_argv.push_back(nullptr);
  argv = const_cast<char**>(new_argv.data());
  argc += 1;

  dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);
  ::testing::InitGoogleMock(&argc, argv);

  ::testing::TestEventListeners& listeners =
      ::testing::UnitTest::GetInstance()->listeners();

  int world_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);

  if (world_rank != 0) {
    delete listeners.Release(listeners.default_result_printer());
  }

  // Re-seed random number generator for random number tests
  std::srand(time(NULL));
  return RUN_ALL_TESTS();
}

<commit_msg>added option to limit listeners to test_main<commit_after>#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
#include <time.h>
#include <vector>

#include <deal.II/base/mpi.h>
#include "gtest/gtest.h"

#include "test_helpers/gmock_wrapper.h"
#include "test_helpers/bart_test_helper.h"

int main(int argc, char** argv) {
  // Parse optional arguments

  int option_index = 0, c = 0, listener = -1;
  bool use_mpi = false;
  std::string filter = "";

  const struct option longopts[] =
  {
    {"filter",    no_argument,       NULL, 'f'},
    {"report",    no_argument,       NULL, 'r'},
    {"mpi",       no_argument,       NULL, 'm'},
    {"listeners", required_argument, NULL, 'l'},
    {NULL,        0,                 NULL,   0}
  };

  while ((c = getopt_long (argc, argv, "rmd:f:l:", longopts, &option_index)) != -1) {
    switch(c) {
      case 'r': {
        btest::GlobalBARTTestHelper().SetReport(true);
        break;
      }
      case 'd': {
        btest::GlobalBARTTestHelper().SetGoldFilesDirectory(optarg);
        break;
      }
      case 'm': {
        use_mpi = true;
        break;
      }
      case 'f': {
        filter = optarg;
        break;
      }
      case 'l': {
        listener = atoi(optarg);
        break;
      }
      default:
        break;
    }
  }

  std::vector<const char*> new_argv(argv, argv + argc);
  if (filter != "") {
    filter = "--gtest_filter=" + filter;
    new_argv.push_back(filter.c_str());
  } else if (use_mpi) {
      new_argv.push_back("--gtest_filter=*MPI*");
  } else {
    new_argv.push_back("--gtest_filter=-*MPIOnly*");
  }

  new_argv.push_back(nullptr);
  argv = const_cast<char**>(new_argv.data());
  argc += 1;

  dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);
  ::testing::InitGoogleMock(&argc, argv);

  ::testing::TestEventListeners& listeners =
      ::testing::UnitTest::GetInstance()->listeners();

  int world_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);

  if (listener != -1) {
    if (world_rank != listener) {
      delete listeners.Release(listeners.default_result_printer());
    }
  }

  // Re-seed random number generator for random number tests
  std::srand(time(NULL));
  return RUN_ALL_TESTS();
}

<|endoftext|>


<commit_before>///
/// @file  PhiTiny.hpp
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#ifndef PHITINY_HPP
#define PHITINY_HPP

#include <int128.hpp>

#include <stdint.h>
#include <cassert>
#include <vector>

namespace primecount {

class PhiTiny {
public:
  PhiTiny();
  static int64_t max_a() { return 6; }
  static bool is_tiny(int64_t a) { return a <= max_a(); }

  /// Partial sieve function (a.k.a. Legendre-sum).
  /// phi(x, a) counts the numbers <= x that are not divisible
  /// by any of the first a primes.
  /// @pre is_tiny(a).
  ///
  template <typename X, typename A>
  X phi(X x, A a) const
  {
    assert(is_tiny(a));
    // phi(x, a) = (x / pp) * φ(pp) + phi(x % pp, a)
    // with pp = 2 * 3 * ... * prime[a]
    X pp = prime_products[a];
    X x_div_pp = x / pp;
    X x_mod_pp = x - pp * x_div_pp;
    return x_div_pp * totients[a] + phi_cache_[a][x_mod_pp];
  }

  private:
  std::vector<int16_t> phi_cache_[7];
  static const int primes[7];
  static const int prime_products[7];
  static const int totients[7];
};

inline bool is_phi_tiny(int64_t a)
{
  return PhiTiny::is_tiny(a);
}

#if __cplusplus >= 201103L

#include <type_traits>

template <typename X, typename A>
std::make_signed<X>::type phi_tiny(X x, A a)
{
  extern const PhiTiny& phiTiny;
  return phiTiny.phi(x, a);
}

#else /* C++98 */

template <typename X, typename A>
X phi_tiny(X x, A a)
{
  extern const PhiTiny& phiTiny;
  return phiTiny.phi(x, a);
}

#endif

} // namespace primecount

#endif
<commit_msg>Update phiTiny type<commit_after>///
/// @file  PhiTiny.hpp
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#ifndef PHITINY_HPP
#define PHITINY_HPP

#include <int128.hpp>

#include <stdint.h>
#include <cassert>
#include <vector>

namespace primecount {

class PhiTiny {
public:
  PhiTiny();
  static int64_t max_a() { return 6; }
  static bool is_tiny(int64_t a) { return a <= max_a(); }

  /// Partial sieve function (a.k.a. Legendre-sum).
  /// phi(x, a) counts the numbers <= x that are not divisible
  /// by any of the first a primes.
  /// @pre is_tiny(a).
  ///
  template <typename X, typename A>
  X phi(X x, A a) const
  {
    assert(is_tiny(a));
    // phi(x, a) = (x / pp) * φ(pp) + phi(x % pp, a)
    // with pp = 2 * 3 * ... * prime[a]
    X pp = prime_products[a];
    X x_div_pp = x / pp;
    X x_mod_pp = x - pp * x_div_pp;
    return x_div_pp * totients[a] + phi_cache_[a][x_mod_pp];
  }

  private:
  std::vector<int16_t> phi_cache_[7];
  static const int primes[7];
  static const int prime_products[7];
  static const int totients[7];
};

inline bool is_phi_tiny(int64_t a)
{
  return PhiTiny::is_tiny(a);
}

#if __cplusplus >= 201103L

#include <type_traits>

template <typename X, typename A>
std::make_signed<X>::type phi_tiny(X x, A a)
{
  extern const PhiTiny phiTiny;
  return phiTiny.phi(x, a);
}

#else /* C++98 */

template <typename X, typename A>
X phi_tiny(X x, A a)
{
  extern const PhiTiny phiTiny;
  return phiTiny.phi(x, a);
}

#endif

} // namespace primecount

#endif
<|endoftext|>


<commit_before>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2011-2014 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// 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 Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "local_storage.hpp"
#include <cmath>
#include <map>
#include <string>
#include <vector>
#include <glog/logging.h>
#include "jubatus/util/data/intern.h"

using std::string;
using std::vector;

namespace jubatus {
namespace core {
namespace storage {

local_storage::local_storage() {
}

local_storage::~local_storage() {
}

void local_storage::get(const string& feature, feature_val1_t& ret) const {
  ret.clear();
  id_features3_t::const_iterator cit = tbl_.find(feature);
  if (cit == tbl_.end()) {
    return;
  }
  const id_feature_val3_t& m = cit->second;
  for (id_feature_val3_t::const_iterator it = m.begin(); it != m.end(); ++it) {
    ret.push_back(make_pair(class2id_.get_key(it->first), it->second.v1));
  }
}

void local_storage::get2(const string& feature, feature_val2_t& ret) const {
  ret.clear();
  id_features3_t::const_iterator cit = tbl_.find(feature);
  if (cit == tbl_.end()) {
    return;
  }
  const id_feature_val3_t& m = cit->second;
  for (id_feature_val3_t::const_iterator it = m.begin(); it != m.end(); ++it) {
    ret.push_back(make_pair(class2id_.get_key(it->first),
                            val2_t(it->second.v1, it->second.v2)));
  }
}

void local_storage::get3(const string& feature, feature_val3_t& ret) const {
  ret.clear();
  id_features3_t::const_iterator cit = tbl_.find(feature);
  if (cit == tbl_.end()) {
    return;
  }
  const id_feature_val3_t& m = cit->second;
  for (id_feature_val3_t::const_iterator it = m.begin(); it != m.end(); ++it) {
    ret.push_back(make_pair(class2id_.get_key(it->first), it->second));
  }
}

void local_storage::inp(const common::sfv_t& sfv, map_feature_val1_t& ret)
    const {
  ret.clear();

  vector<float> ret_id(class2id_.size());
  for (common::sfv_t::const_iterator it = sfv.begin(); it != sfv.end(); ++it) {
    const string& feature = it->first;
    const float val = it->second;
    id_features3_t::const_iterator it2 = tbl_.find(feature);
    if (it2 == tbl_.end()) {
      continue;
    }
    const id_feature_val3_t& m = it2->second;
    for (id_feature_val3_t::const_iterator it3 = m.begin(); it3 != m.end();
        ++it3) {
      ret_id[it3->first] += it3->second.v1 * val;
    }
  }

  for (size_t i = 0; i < ret_id.size(); ++i) {
    ret[class2id_.get_key(i)] = ret_id[i];
  }
}

void local_storage::set(
    const string& feature,
    const string& klass,
    const val1_t& w) {
  tbl_[feature][class2id_.get_id(klass)].v1 = w;
}

void local_storage::set2(
    const string& feature,
    const string& klass,
    const val2_t& w) {
  val3_t& val3 = tbl_[feature][class2id_.get_id(klass)];
  val3.v1 = w.v1;
  val3.v2 = w.v2;
}

void local_storage::set3(
    const string& feature,
    const string& klass,
    const val3_t& w) {
  tbl_[feature][class2id_.get_id(klass)] = w;
}

void local_storage::get_status(std::map<string, std::string>& status) const {
  status["num_features"] =
    jubatus::util::lang::lexical_cast<std::string>(tbl_.size());
  status["num_classes"] =
    jubatus::util::lang::lexical_cast<std::string>(class2id_.size());
}

float feature_fabssum(const id_feature_val3_t& f) {
  float sum = 0.f;
  for (id_feature_val3_t::const_iterator it = f.begin(); it != f.end(); ++it) {
    sum += std::fabs(it->second.v1);
  }
  return sum;
}

void local_storage::bulk_update(
    const common::sfv_t& sfv,
    float step_width,
    const string& inc_class,
    const string& dec_class) {
  uint64_t inc_id = class2id_.get_id(inc_class);
  typedef common::sfv_t::const_iterator iter_t;
  if (dec_class != "") {
    uint64_t dec_id = class2id_.get_id(dec_class);
    for (iter_t it = sfv.begin(); it != sfv.end(); ++it) {
      float val = it->second * step_width;
      id_feature_val3_t& feature_row = tbl_[it->first];
      feature_row[inc_id].v1 += val;
      feature_row[dec_id].v1 -= val;
    }
  } else {
    for (iter_t it = sfv.begin(); it != sfv.end(); ++it) {
      float val = it->second * step_width;
      id_feature_val3_t& feature_row = tbl_[it->first];
      feature_row[inc_id].v1 += val;
    }
  }
}

void local_storage::update(
    const string& feature,
    const string& inc_class,
    const string& dec_class,
    const val1_t& v) {
  id_feature_val3_t& feature_row = tbl_[feature];
  feature_row[class2id_.get_id(inc_class)].v1 += v;
  feature_row[class2id_.get_id(dec_class)].v1 -= v;
}

void local_storage::register_label(const std::string& label) {
  // get_id method creates an entry when the label doesn't exist
  class2id_.get_id(label);
}

vector<string> local_storage::get_labels() const {
  return class2id_.get_all_id2key();
}

bool local_storage::set_label(const std::string& label) {
  return class2id_.set_key(label);
}
void local_storage::delete_label(const std::string& label) {
  uint64_t delete_id = class2id_.get_id_const(label);
  if (delete_id == common::key_manager::NOTFOUND)
    return;
  for (id_features3_t::iterator it = tbl_.begin();
       it != tbl_.end();
       ++it) {
    it->second.erase(delete_id);
    if (it->second.empty()) {
      tbl_.erase(it);
    }
  }
  class2id_.delete_key(label);
}

void local_storage::clear() {
  // Clear and minimize
  id_features3_t().swap(tbl_);
  common::key_manager().swap(class2id_);
}

void local_storage::pack(msgpack::packer<msgpack::sbuffer>& packer) const {
  packer.pack(*this);
}

void local_storage::unpack(msgpack::object o) {
  o.convert(this);
}

std::string local_storage::type() const {
  return "local_storage";
}

}  // namespace storage
}  // namespace core
}  // namespace jubatus
<commit_msg>Use unordered_map in inp function of local_storage instead of vector<commit_after>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2011-2014 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// 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 Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "local_storage.hpp"
#include <cmath>
#include <map>
#include <string>
#include <vector>
#include <glog/logging.h>
#include "jubatus/util/data/intern.h"

using std::string;
using std::vector;

namespace jubatus {
namespace core {
namespace storage {

local_storage::local_storage() {
}

local_storage::~local_storage() {
}

void local_storage::get(const string& feature, feature_val1_t& ret) const {
  ret.clear();
  id_features3_t::const_iterator cit = tbl_.find(feature);
  if (cit == tbl_.end()) {
    return;
  }
  const id_feature_val3_t& m = cit->second;
  for (id_feature_val3_t::const_iterator it = m.begin(); it != m.end(); ++it) {
    ret.push_back(make_pair(class2id_.get_key(it->first), it->second.v1));
  }
}

void local_storage::get2(const string& feature, feature_val2_t& ret) const {
  ret.clear();
  id_features3_t::const_iterator cit = tbl_.find(feature);
  if (cit == tbl_.end()) {
    return;
  }
  const id_feature_val3_t& m = cit->second;
  for (id_feature_val3_t::const_iterator it = m.begin(); it != m.end(); ++it) {
    ret.push_back(make_pair(class2id_.get_key(it->first),
                            val2_t(it->second.v1, it->second.v2)));
  }
}

void local_storage::get3(const string& feature, feature_val3_t& ret) const {
  ret.clear();
  id_features3_t::const_iterator cit = tbl_.find(feature);
  if (cit == tbl_.end()) {
    return;
  }
  const id_feature_val3_t& m = cit->second;
  for (id_feature_val3_t::const_iterator it = m.begin(); it != m.end(); ++it) {
    ret.push_back(make_pair(class2id_.get_key(it->first), it->second));
  }
}

void local_storage::inp(const common::sfv_t& sfv, map_feature_val1_t& ret)
    const {
  ret.clear();

  // Use uin64_t map instead of string map as hash function for string is slow
  jubatus::util::data::unordered_map<uint64_t, float> ret_id;
  for (common::sfv_t::const_iterator it = sfv.begin(); it != sfv.end(); ++it) {
    const string& feature = it->first;
    const float val = it->second;
    id_features3_t::const_iterator it2 = tbl_.find(feature);
    if (it2 == tbl_.end()) {
      continue;
    }
    const id_feature_val3_t& m = it2->second;
    for (id_feature_val3_t::const_iterator it3 = m.begin(); it3 != m.end();
        ++it3) {
      ret_id[it3->first] += it3->second.v1 * val;
    }
  }

  std::vector<std::string> labels = class2id_.get_all_id2key();
  for (size_t i = 0; i < labels.size(); ++i) {
    const std::string& label = labels[i];
    uint64_t id = class2id_.get_id_const(label);
    if (id == common::key_manager::NOTFOUND || ret_id.count(id) == 0) {
      ret[label] = 0.0;
    } else {
      ret[label] = ret_id[id];
    }
  }
}

void local_storage::set(
    const string& feature,
    const string& klass,
    const val1_t& w) {
  tbl_[feature][class2id_.get_id(klass)].v1 = w;
}

void local_storage::set2(
    const string& feature,
    const string& klass,
    const val2_t& w) {
  val3_t& val3 = tbl_[feature][class2id_.get_id(klass)];
  val3.v1 = w.v1;
  val3.v2 = w.v2;
}

void local_storage::set3(
    const string& feature,
    const string& klass,
    const val3_t& w) {
  tbl_[feature][class2id_.get_id(klass)] = w;
}

void local_storage::get_status(std::map<string, std::string>& status) const {
  status["num_features"] =
    jubatus::util::lang::lexical_cast<std::string>(tbl_.size());
  status["num_classes"] =
    jubatus::util::lang::lexical_cast<std::string>(class2id_.size());
}

float feature_fabssum(const id_feature_val3_t& f) {
  float sum = 0.f;
  for (id_feature_val3_t::const_iterator it = f.begin(); it != f.end(); ++it) {
    sum += std::fabs(it->second.v1);
  }
  return sum;
}

void local_storage::bulk_update(
    const common::sfv_t& sfv,
    float step_width,
    const string& inc_class,
    const string& dec_class) {
  uint64_t inc_id = class2id_.get_id(inc_class);
  typedef common::sfv_t::const_iterator iter_t;
  if (dec_class != "") {
    uint64_t dec_id = class2id_.get_id(dec_class);
    for (iter_t it = sfv.begin(); it != sfv.end(); ++it) {
      float val = it->second * step_width;
      id_feature_val3_t& feature_row = tbl_[it->first];
      feature_row[inc_id].v1 += val;
      feature_row[dec_id].v1 -= val;
    }
  } else {
    for (iter_t it = sfv.begin(); it != sfv.end(); ++it) {
      float val = it->second * step_width;
      id_feature_val3_t& feature_row = tbl_[it->first];
      feature_row[inc_id].v1 += val;
    }
  }
}

void local_storage::update(
    const string& feature,
    const string& inc_class,
    const string& dec_class,
    const val1_t& v) {
  id_feature_val3_t& feature_row = tbl_[feature];
  feature_row[class2id_.get_id(inc_class)].v1 += v;
  feature_row[class2id_.get_id(dec_class)].v1 -= v;
}

void local_storage::register_label(const std::string& label) {
  // get_id method creates an entry when the label doesn't exist
  class2id_.get_id(label);
}

vector<string> local_storage::get_labels() const {
  return class2id_.get_all_id2key();
}

bool local_storage::set_label(const std::string& label) {
  return class2id_.set_key(label);
}
void local_storage::delete_label(const std::string& label) {
  uint64_t delete_id = class2id_.get_id_const(label);
  if (delete_id == common::key_manager::NOTFOUND)
    return;
  for (id_features3_t::iterator it = tbl_.begin();
       it != tbl_.end();
       ++it) {
    it->second.erase(delete_id);
    if (it->second.empty()) {
      tbl_.erase(it);
    }
  }
  class2id_.delete_key(label);
}

void local_storage::clear() {
  // Clear and minimize
  id_features3_t().swap(tbl_);
  common::key_manager().swap(class2id_);
}

void local_storage::pack(msgpack::packer<msgpack::sbuffer>& packer) const {
  packer.pack(*this);
}

void local_storage::unpack(msgpack::object o) {
  o.convert(this);
}

std::string local_storage::type() const {
  return "local_storage";
}

}  // namespace storage
}  // namespace core
}  // namespace jubatus
<|endoftext|>


<commit_before>#ifndef KFUSION_WARP_FIELD_HPP
#define KFUSION_WARP_FIELD_HPP

#include <dual_quaternion.hpp>
#include <kfusion/types.hpp>
#include <nanoflann/nanoflann.hpp>
#include <knn_point_cloud.hpp>
#include <kfusion/cuda/tsdf_volume.hpp>
#define KNN_NEIGHBOURS 8

namespace kfusion
{
    typedef nanoflann::KDTreeSingleIndexAdaptor<
            nanoflann::L2_Simple_Adaptor<float, utils::PointCloud>,
            utils::PointCloud,
            3 /* dim */
    > kd_tree_t;

    /*!
     * \struct node
     * \brief A node of the warp field
     * \details The state of the warp field Wt at time t is defined by the values of a set of n
     * deformation nodes Nt_warp = {dg_v, dg_w, dg_se3}_t. Here, this is represented as follows
     *
     * \var node::vertex
     * Position of the vertex in space. This will be used when computing KNN for warping points.
     *
     * \var node::transform
     * Transformation for each vertex to warp it into the live frame, equivalent to dg_se in the paper.
     *
     * \var node::weight
     * Equivalent to dg_w
     */
    struct deformation_node
    {
        Vec3f vertex;
        kfusion::utils::DualQuaternion<float> transform;
        float weight = 0;
    };
    class WarpField
    {
    public:
        WarpField();
        ~WarpField();

        void init(const cv::Mat& first_frame);
        void init(const std::vector<Vec3f>& first_frame);
        void energy(const cuda::Cloud &frame,
                    const cuda::Normals &normals,
                    const Affine3f &pose,
                    const cuda::TsdfVolume &tsdfVolume,
                    const std::vector<std::pair<kfusion::utils::DualQuaternion<float>,
                            kfusion::utils::DualQuaternion<float>>> &edges
        );

        void energy_data(const std::vector<Vec3f> &canonical_vertices,
                          const std::vector<Vec3f> &canonical_normals,
                          const std::vector<Vec3f> &live_vertices,
                          const std::vector<Vec3f> &live_normals);
        void energy_reg(const std::vector<std::pair<kfusion::utils::DualQuaternion<float>,
                kfusion::utils::DualQuaternion<float>>> &edges);

        void warp(std::vector<Vec3f>& points, std::vector<Vec3f>& normals) const;
        void warp(cuda::Cloud& points) const;

        utils::DualQuaternion<float> DQB(const Vec3f& vertex) const;
        utils::DualQuaternion<float> DQB(const Vec3f& vertex, const std::vector<double*> epsilon) const;
        void update_nodes(const double *epsilon);

        void getWeightsAndUpdateKNN(const Vec3f& vertex, float weights[KNN_NEIGHBOURS]) const;

        float weighting(float squared_dist, float weight) const;
        void KNN(Vec3f point) const;

        void clear();

        const std::vector<deformation_node>* getNodes() const;
        const cv::Mat getNodesAsMat() const;
        void setWarpToLive(const Affine3f &pose);
        std::vector<float>* getDistSquared() const;

    private:
        std::vector<deformation_node>* nodes_;
        kd_tree_t* index_;
        Affine3f warp_to_live_;
        void buildKDTree();
    };
}
#endif //KFUSION_WARP_FIELD_HPP
<commit_msg>Added method to get deformation indices. Will be removed later<commit_after>#ifndef KFUSION_WARP_FIELD_HPP
#define KFUSION_WARP_FIELD_HPP

#include <dual_quaternion.hpp>
#include <kfusion/types.hpp>
#include <nanoflann/nanoflann.hpp>
#include <knn_point_cloud.hpp>
#include <kfusion/cuda/tsdf_volume.hpp>
#define KNN_NEIGHBOURS 6

namespace kfusion
{
    typedef nanoflann::KDTreeSingleIndexAdaptor<
            nanoflann::L2_Simple_Adaptor<float, utils::PointCloud>,
            utils::PointCloud,
            3 /* dim */
    > kd_tree_t;

    /*!
     * \struct node
     * \brief A node of the warp field
     * \details The state of the warp field Wt at time t is defined by the values of a set of n
     * deformation nodes Nt_warp = {dg_v, dg_w, dg_se3}_t. Here, this is represented as follows
     *
     * \var node::vertex
     * Position of the vertex in space. This will be used when computing KNN for warping points.
     *
     * \var node::transform
     * Transformation for each vertex to warp it into the live frame, equivalent to dg_se in the paper.
     *
     * \var node::weight
     * Equivalent to dg_w
     */
    struct deformation_node
    {
        Vec3f vertex;
        kfusion::utils::DualQuaternion<float> transform;
        float weight = 0;
    };
    class WarpField
    {
    public:
        WarpField();
        ~WarpField();

        void init(const cv::Mat& first_frame);
        void init(const std::vector<Vec3f>& first_frame);
        void energy(const cuda::Cloud &frame,
                    const cuda::Normals &normals,
                    const Affine3f &pose,
                    const cuda::TsdfVolume &tsdfVolume,
                    const std::vector<std::pair<kfusion::utils::DualQuaternion<float>,
                            kfusion::utils::DualQuaternion<float>>> &edges
        );

        void energy_data(const std::vector<Vec3f> &canonical_vertices,
                          const std::vector<Vec3f> &canonical_normals,
                          const std::vector<Vec3f> &live_vertices,
                          const std::vector<Vec3f> &live_normals);
        void energy_reg(const std::vector<std::pair<kfusion::utils::DualQuaternion<float>,
                kfusion::utils::DualQuaternion<float>>> &edges);

        void warp(std::vector<Vec3f>& points, std::vector<Vec3f>& normals) const;
        void warp(cuda::Cloud& points) const;

        utils::DualQuaternion<float> DQB(const Vec3f& vertex) const;
        utils::DualQuaternion<float> DQB(const Vec3f& vertex, const std::vector<double*> epsilon) const;
        void update_nodes(const double *epsilon);

        void getWeightsAndUpdateKNN(const Vec3f& vertex, float weights[KNN_NEIGHBOURS]) const;

        float weighting(float squared_dist, float weight) const;
        void KNN(Vec3f point) const;

        void clear();

        const std::vector<deformation_node>* getNodes() const;
        const cv::Mat getNodesAsMat() const;
        void setWarpToLive(const Affine3f &pose);
        std::vector<float>* getDistSquared() const;
        std::vector<size_t>* getRetIndex() const;

    private:
        std::vector<deformation_node>* nodes_;
        kd_tree_t* index_;
        Affine3f warp_to_live_;
        void buildKDTree();
    };
}
#endif //KFUSION_WARP_FIELD_HPP
<|endoftext|>


<commit_before>#pragma once

#include "BitstreamGeneric.hpp"

#include <vector>
#include <memory>
#include <unordered_map>
#include <numeric>
#include <queue>
#include <iostream>
#include <assert.h>
#include <iterator>

using std::unordered_map;
using std::priority_queue;
using std::vector;

class Node {
public:
    Node(double probability, Node* left, Node* right);
    Node(double probability, int symbol);
    ~Node();

    // longest path to a child
    int height() const;

public:
    double probability;

    // bit hacky for now..
    int symbol;
    bool is_leaf;

    Node* left;
    Node* right;
};

// a huffman code for a symbol
struct Code {
    using CodeType = uint32_t;
    static const auto max_code_length = sizeof(CodeType)* 8;

    Code() : code(0), length(0) {}
    Code(CodeType code, uint8_t length)
        : code(code), length(length)
    {
        assert(length <= max_code_length);

        // make the leftmost bit of the code the MSB
        auto shift = max_code_length - length;
        this->code <<= shift;
    }

    Code(Bitstream bitstream) {
        length = bitstream.size();
        assert(length <= max_code_length);

        code = bitstream.extract(length, 0);
    }

    // like bistreams, the code begins at the msb
    CodeType code;
    uint8_t length;
};

using SymbolCodeMap = std::unordered_map<int, Code>;

// takes a text, caluclates the probability of every symbol and returns a map from symbols to huffman codes
SymbolCodeMap generateCodeMap(std::vector<int> text);

Node* generateHuffTree(unordered_map<int, int> symbol_counts, size_t total_symbols);
// generate a list of symbols grouped by code length
void generateSymbolsPerCodelength(Node* node, vector<vector<int>>& symbols, int depth = 0);
SymbolCodeMap generateCodes(vector<vector<int>>& symbols);

// en- and decoding
Bitstream huffmanEncode(vector<int> text, SymbolCodeMap code_map);
vector<int> huffmanDecode(Bitstream bitstream, SymbolCodeMap code_map);

struct DecodeEntry {
    DecodeEntry(uint32_t code, uint8_t code_length, int symbol);

    // code starting at msb, rest filled with 1s
    uint32_t code;
    uint8_t code_length;
    int symbol;

    bool operator<(const DecodeEntry& other) {
        return code < other.code;
    }
};

struct Symbol {
    int symbol, frequency;

    Symbol()
        : symbol{},
        frequency{}
    {}
    Symbol(int _symbol, int _freq)
        : symbol(_symbol),
        frequency(_freq)
    {}
};

inline bool operator<(const Symbol& lhs, const Symbol& rhs) {
    return lhs.symbol < rhs.symbol;
}

struct Package {
    int weight;
    vector<Symbol> symbols;

    Package(const Symbol& _symbol) {
        symbols.push_back(_symbol);
        weight = _symbol.frequency;
    }

    Package(const Package& p1, const Package& p2) {
        weight = p1.weight + p2.weight;
        std::merge(begin(p1.symbols), end(p1.symbols),
                   begin(p2.symbols), end(p2.symbols),
                   back_inserter(symbols));
    }
};

// input: list of symbols (with its frequency)
//        maximum code length
// output: a code length for each symbol
inline vector<vector<int>> package_merge(vector<Symbol> symbols, int length_limit) {
    auto comp = [](const Package& lhs, const Package& rhs) {
        return lhs.weight > rhs.weight;
    };
    using Level = priority_queue<Package, vector<Package>, decltype(comp)>;

    // blueprint level
    Level level;
    for (const auto& sym : symbols)
        level.push(sym);

    // allocate number of levels 2^-1 up to 2^-length_limit
    // levels[0] should be 2^-length_limit and levels[length_limit] should be 2^0
    vector<Level> levels;
    levels.reserve(length_limit);
    for (auto i = 0; i < length_limit; ++i)
        levels.push_back(level);
    levels.push_back(Level()); // last list is empty (level 2^0 or 1)

    for (auto i = 0; i < length_limit; ++i) {
        auto& level = levels[i];
        auto& next_level = levels[i + 1];

        // package the least 2 packages if there are more than 2
        while (level.size() > 1) {
            auto p1 = level.top();
            level.pop();
            auto p2 = level.top();
            level.pop();

            // package & merge
            next_level.push(Package{ p1, p2 });
        }
    }

    // count the occurences of the symbols in the remaining packages
    // the count is the code length for that symbol
    unordered_map<int, int> code_lengths;
    auto& final_level = levels[length_limit];
    while (final_level.size()) {
        const auto package = final_level.top();
        final_level.pop();

        int codelength = 0;

        for (const auto& sym : package.symbols)
            code_lengths[sym.symbol]++;
    }

    // put it in a vector for easy usage
    vector<vector<int>> symbolsByCodeLength(length_limit+1);
    for (auto it = code_lengths.begin(); it != code_lengths.end(); ++it){
        symbolsByCodeLength[it->second].push_back(it->first);
    }

    return symbolsByCodeLength;
}<commit_msg>removed unnecessary code, added comments<commit_after>#pragma once

#include "BitstreamGeneric.hpp"

#include <vector>
#include <memory>
#include <unordered_map>
#include <numeric>
#include <queue>
#include <iostream>
#include <assert.h>
#include <iterator>

using std::unordered_map;
using std::priority_queue;
using std::vector;

class Node {
public:
    Node(double probability, Node* left, Node* right);
    Node(double probability, int symbol);
    ~Node();

    // longest path to a child
    int height() const;

public:
    double probability;

    // bit hacky for now..
    int symbol;
    bool is_leaf;

    Node* left;
    Node* right;
};

// a huffman code for a symbol
struct Code {
    using CodeType = uint32_t;
    static const auto max_code_length = sizeof(CodeType)* 8;

    Code() : code(0), length(0) {}
    Code(CodeType code, uint8_t length)
        : code(code), length(length)
    {
        assert(length <= max_code_length);

        // make the leftmost bit of the code the MSB
        auto shift = max_code_length - length;
        this->code <<= shift;
    }

    Code(Bitstream bitstream) {
        length = bitstream.size();
        assert(length <= max_code_length);

        code = bitstream.extract(length, 0);
    }

    // like bistreams, the code begins at the msb
    CodeType code;
    uint8_t length;
};

using SymbolCodeMap = std::unordered_map<int, Code>;

// takes a text, caluclates the probability of every symbol and returns a map from symbols to huffman codes
SymbolCodeMap generateCodeMap(std::vector<int> text);

Node* generateHuffTree(unordered_map<int, int> symbol_counts, size_t total_symbols);
// generate a list of symbols grouped by code length
void generateSymbolsPerCodelength(Node* node, vector<vector<int>>& symbols, int depth = 0);
SymbolCodeMap generateCodes(vector<vector<int>>& symbols);

// en- and decoding
Bitstream huffmanEncode(vector<int> text, SymbolCodeMap code_map);
vector<int> huffmanDecode(Bitstream bitstream, SymbolCodeMap code_map);

struct DecodeEntry {
    DecodeEntry(uint32_t code, uint8_t code_length, int symbol);

    // code starting at msb, rest filled with 1s
    uint32_t code;
    uint8_t code_length;
    int symbol;

    bool operator<(const DecodeEntry& other) {
        return code < other.code;
    }
};

struct Symbol {
    int symbol, frequency;

    Symbol()
        : symbol{},
        frequency{}
    {}
    Symbol(int _symbol, int _freq)
        : symbol(_symbol),
        frequency(_freq)
    {}
};

inline bool operator<(const Symbol& lhs, const Symbol& rhs) {
    return lhs.symbol < rhs.symbol;
}

struct Package {
    int weight;
    vector<Symbol> symbols;

    Package(const Symbol& _symbol) {
        symbols.push_back(_symbol);
        weight = _symbol.frequency;
    }

    Package(const Package& p1, const Package& p2) {
        weight = p1.weight + p2.weight;
        std::merge(begin(p1.symbols), end(p1.symbols),
                   begin(p2.symbols), end(p2.symbols),
                   back_inserter(symbols));
    }
};

// input: list of symbols (with its frequency)
//        maximum code length
// output: a code length for each symbol
inline vector<vector<int>> package_merge(vector<Symbol> symbols, int length_limit) {
    auto comp = [](const Package& lhs, const Package& rhs) {
        return lhs.weight > rhs.weight;
    };
    using Level = priority_queue<Package, vector<Package>, decltype(comp)>;

    // blueprint level
    Level level;
    for (const auto& sym : symbols)
        level.push(sym);

    // allocate number of levels 2^-1 up to 2^-length_limit
    // levels[0] should be 2^-length_limit and levels[length_limit] should be 2^0
    vector<Level> levels;
    levels.reserve(length_limit);
    for (auto i = 0; i < length_limit; ++i)
        levels.push_back(level);
    levels.push_back(Level()); // last list is empty (level 2^0 or 1)

    for (auto i = 0; i < length_limit; ++i) {
        auto& level = levels[i];
        auto& next_level = levels[i + 1];

        // package the least 2 packages if there are more than 2
        while (level.size() > 1) {
            auto p1 = level.top();
            level.pop();
            auto p2 = level.top();
            level.pop();

            // package & merge
            next_level.push(Package{ p1, p2 });
        }
    }

    // count the occurences of the symbols in the remaining packages
    // the count is the code length for that symbol
    unordered_map<int, int> code_lengths;
    auto& final_level = levels[length_limit];
    while (final_level.size()) {
        const auto package = final_level.top();
        final_level.pop();

        for (const auto& sym : package.symbols)
            code_lengths[sym.symbol]++;
    }

    // put it in a vector for easy usage
    vector<vector<int>> symbolsByCodeLength(length_limit+1);
    for (auto it = code_lengths.begin(); it != code_lengths.end(); ++it){
        // second: code length
        // first: symbol
        symbolsByCodeLength[it->second].push_back(it->first);
    }

    return symbolsByCodeLength;
}<|endoftext|>


<commit_before>/* -*- mode: c++; c-basic-offset:4 -*-
    uiserver/keyselectionjob.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

    Kleopatra is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Kleopatra 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
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "keyselectionjob.h"
#include "keyselectiondialog.h"
#include "kleo-assuan.h"
#include "assuancommand.h" // for AssuanCommand::makeError()

#include <kleo/keylistjob.h>

#include <QPointer>
#include <QStringList>

#include <gpgme++/error.h>
#include <gpgme++/key.h>
#include <gpgme++/keylistresult.h>

using namespace Kleo;

class KeySelectionJob::Private
{
public:
    Private( KeySelectionJob* qq ) : q( qq ), m_secretKeysOnly( false ), m_silent( false ), m_keyListings( 0 ), m_started( false ) {}
    ~Private();

    void startKeyListing();
    void showKeySelectionDialog();

    std::vector<GpgME::Key> m_keys;
    QStringList m_patterns;
    bool m_secretKeysOnly;
    bool m_silent;
    QPointer<KeySelectionDialog> m_keySelector;
    int m_keyListings;
    GpgME::KeyListResult m_listResult;
    bool m_started;

    void nextKey( const GpgME::Key& key );
    void keyListingDone( const GpgME::KeyListResult& result );
    void keySelectionDialogClosed();

private:
    void emitError( int error,
                    const GpgME::KeyListResult& result );
    void emitResult( const std::vector<GpgME::Key>& keys );

private:
    KeySelectionJob* q;
};

KeySelectionJob::Private::~Private()
{
    delete m_keySelector;
}

void KeySelectionJob::Private::emitError( int error, const GpgME::KeyListResult& result )
{
    emit q->error( GpgME::Error( AssuanCommand::makeError( error ) ), result );
    q->deleteLater();
}

void KeySelectionJob::Private::emitResult( const std::vector<GpgME::Key>& keys )
{
    emit q->result( keys );
    q->deleteLater();
}

void KeySelectionJob::Private::keyListingDone( const GpgME::KeyListResult& result )
{
    m_listResult = result;
    if ( result.error() ) {
        emitError( result.error(), result );
        return;
    }
    --m_keyListings;
    assert( m_keyListings >= 0 );

    if ( m_keyListings == 0 ) {
        showKeySelectionDialog();
    }

}

void KeySelectionJob::Private::nextKey( const GpgME::Key& key )
{
    m_keys.push_back( key );
}

KeySelectionJob::KeySelectionJob( QObject* parent ) : QObject( parent ), d( new Private( this ) )
{
}

void KeySelectionJob::Private::keySelectionDialogClosed()
{
    if ( m_keySelector->result() == QDialog::Rejected ) {
        emitError( GPG_ERR_CANCELED, m_listResult );
    } else {
        emitResult( m_keySelector->selectedKeys() );
    }
}

void KeySelectionJob::Private::startKeyListing()
{
    m_keyListings = 2; // openpgp and cms
    KeyListJob *keylisting = CryptoBackendFactory::instance()->protocol( "openpgp" )->keyListJob();
    QObject::connect( keylisting, SIGNAL( result( GpgME::KeyListResult ) ),
             q, SLOT( keyListingDone( GpgME::KeyListResult ) ) );
    QObject::connect( keylisting, SIGNAL( nextKey( GpgME::Key ) ),
             q, SLOT( nextKey( GpgME::Key ) ) );
    if ( const GpgME::Error err = keylisting->start( m_patterns, m_secretKeysOnly ) ) {
        q->deleteLater();
        throw assuan_exception( err, "Unable to start keylisting" );
    }
    keylisting = Kleo::CryptoBackendFactory::instance()->protocol( "smime" )->keyListJob();
    QObject::connect( keylisting, SIGNAL( result( GpgME::KeyListResult ) ),
                      q, SLOT( keyListingDone( GpgME::KeyListResult ) ) );
    QObject::connect( keylisting, SIGNAL( nextKey( GpgME::Key ) ),
                      q, SLOT( nextKey( GpgME::Key ) ) );
    if ( const GpgME::Error err = keylisting->start( m_patterns, m_secretKeysOnly ) ) {
        q->deleteLater();
        throw assuan_exception( err, "Unable to start keylisting" );
    }
}

void KeySelectionJob::Private::showKeySelectionDialog()
{
    assert( !m_keySelector );
    if ( m_silent ) {
        emitResult( m_keys );
        return;
    }
    m_keySelector = new KeySelectionDialog();
    QObject::connect( m_keySelector, SIGNAL( accepted() ), q, SLOT( keySelectionDialogClosed() ) );
    QObject::connect( m_keySelector, SIGNAL( rejected() ), q, SLOT( keySelectionDialogClosed() ) );
    m_keySelector->addKeys( m_keys );
    m_keySelector->show();
}

void KeySelectionJob::start()
{
    assert( !d->m_started );
    if ( d->m_started )
        return;
    d->m_started = true;
    d->startKeyListing();
}

void KeySelectionJob::setPatterns( const QStringList& patterns )
{
    d->m_patterns = patterns;
}

QStringList KeySelectionJob::patterns() const
{
    return d->m_patterns;
}

void KeySelectionJob::setSecretKeysOnly( bool secretOnly )
{
    d->m_secretKeysOnly = secretOnly;
}

bool KeySelectionJob::secretKeysOnly() const
{
    return d->m_secretKeysOnly;
}

void KeySelectionJob::setSilent( bool silent )
{
    d->m_silent = silent;
}

bool KeySelectionJob::silent() const
{
    return d->m_silent;
}

#include "keyselectionjob.moc"

<commit_msg>some cleanup; hunting a sporadic crash<commit_after>/* -*- mode: c++; c-basic-offset:4 -*-
    uiserver/keyselectionjob.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

    Kleopatra is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Kleopatra 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
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "keyselectionjob.h"
#include "keyselectiondialog.h"
#include "kleo-assuan.h"
#include "assuancommand.h" // for AssuanCommand::makeError()

#include <kleo/keylistjob.h>

#include <QPointer>
#include <QStringList>

#include <gpgme++/error.h>
#include <gpgme++/key.h>
#include <gpgme++/keylistresult.h>

using namespace Kleo;

class KeySelectionJob::Private
{
public:
    Private( KeySelectionJob* qq ) : q( qq ), m_secretKeysOnly( false ), m_silent( false ), m_keyListings( 0 ), m_started( false ) {}
    ~Private();

    void startKeyListing();
    void showKeySelectionDialog();

    std::vector<GpgME::Key> m_keys;
    QStringList m_patterns;
    bool m_secretKeysOnly;
    bool m_silent;
    QPointer<KeySelectionDialog> m_keySelector;
    int m_keyListings;
    GpgME::KeyListResult m_listResult;
    bool m_started;

    void nextKey( const GpgME::Key& key );
    void keyListingDone( const GpgME::KeyListResult& result );
    void keySelectionDialogClosed();

private:
    void emitError( int error,
                    const GpgME::KeyListResult& result );
    void emitResult( const std::vector<GpgME::Key>& keys );

private:
    KeySelectionJob* q;
};

KeySelectionJob::Private::~Private()
{
    delete m_keySelector;
}

void KeySelectionJob::Private::emitError( int error, const GpgME::KeyListResult& result )
{
    q->deleteLater();
    emit q->error( GpgME::Error( AssuanCommand::makeError( error ) ), result );
}

void KeySelectionJob::Private::emitResult( const std::vector<GpgME::Key>& keys )
{
    q->deleteLater();
    emit q->result( keys );
}

void KeySelectionJob::Private::keyListingDone( const GpgME::KeyListResult& result )
{
    m_listResult = result;
    if ( result.error() ) {
        emitError( result.error(), result );
        return;
    }
    --m_keyListings;
    assert( m_keyListings >= 0 );

    if ( m_keyListings == 0 ) {
        showKeySelectionDialog();
    }

}

void KeySelectionJob::Private::nextKey( const GpgME::Key& key )
{
    m_keys.push_back( key );
}

KeySelectionJob::KeySelectionJob( QObject* parent ) : QObject( parent ), d( new Private( this ) )
{
}

void KeySelectionJob::Private::keySelectionDialogClosed()
{
    if ( m_keySelector->result() == QDialog::Rejected ) {
        emitError( GPG_ERR_CANCELED, m_listResult );
        return;
    }
    emitResult( m_keySelector->selectedKeys() );
}

void KeySelectionJob::Private::startKeyListing()
{
    m_keyListings = 2; // openpgp and cms
    KeyListJob *keylisting = CryptoBackendFactory::instance()->protocol( "openpgp" )->keyListJob();
    QObject::connect( keylisting, SIGNAL( result( GpgME::KeyListResult ) ),
             q, SLOT( keyListingDone( GpgME::KeyListResult ) ) );
    QObject::connect( keylisting, SIGNAL( nextKey( GpgME::Key ) ),
             q, SLOT( nextKey( GpgME::Key ) ) );
    if ( const GpgME::Error err = keylisting->start( m_patterns, m_secretKeysOnly ) ) {
        q->deleteLater();
        throw assuan_exception( err, "Unable to start keylisting" );
    }
    keylisting = Kleo::CryptoBackendFactory::instance()->protocol( "smime" )->keyListJob();
    QObject::connect( keylisting, SIGNAL( result( GpgME::KeyListResult ) ),
                      q, SLOT( keyListingDone( GpgME::KeyListResult ) ) );
    QObject::connect( keylisting, SIGNAL( nextKey( GpgME::Key ) ),
                      q, SLOT( nextKey( GpgME::Key ) ) );
    if ( const GpgME::Error err = keylisting->start( m_patterns, m_secretKeysOnly ) ) {
        q->deleteLater();
        throw assuan_exception( err, "Unable to start keylisting" );
    }
}

void KeySelectionJob::Private::showKeySelectionDialog()
{
    assert( !m_keySelector );
    if ( m_silent ) {
        emitResult( m_keys );
        return;
    }
    m_keySelector = new KeySelectionDialog();
    QObject::connect( m_keySelector, SIGNAL( accepted() ), q, SLOT( keySelectionDialogClosed() ) );
    QObject::connect( m_keySelector, SIGNAL( rejected() ), q, SLOT( keySelectionDialogClosed() ) );
    m_keySelector->addKeys( m_keys );
    m_keySelector->show();
}

void KeySelectionJob::start()
{
    assert( !d->m_started );
    if ( d->m_started )
        return;
    d->m_started = true;
    d->startKeyListing();
}

void KeySelectionJob::setPatterns( const QStringList& patterns )
{
    d->m_patterns = patterns;
}

QStringList KeySelectionJob::patterns() const
{
    return d->m_patterns;
}

void KeySelectionJob::setSecretKeysOnly( bool secretOnly )
{
    d->m_secretKeysOnly = secretOnly;
}

bool KeySelectionJob::secretKeysOnly() const
{
    return d->m_secretKeysOnly;
}

void KeySelectionJob::setSilent( bool silent )
{
    d->m_silent = silent;
}

bool KeySelectionJob::silent() const
{
    return d->m_silent;
}

#include "keyselectionjob.moc"

<|endoftext|>


<commit_before>/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "config.h"
#include "core/css/resolver/MatchedPropertiesCache.h"

#include "core/css/StylePropertySet.h"
#include "core/css/resolver/StyleResolverState.h"
#include "core/rendering/style/RenderStyle.h"

namespace blink {

#if ENABLE(OILPAN)
bool CachedMatchedPropertiesHashTraits::traceInCollection(Visitor* visitor, Member<CachedMatchedProperties>& cachedProperties, WTF::ShouldWeakPointersBeMarkedStrongly strongify)
{
    // Only honor the cache's weakness semantics if the collection is traced
    // with WeakPointersActWeak. Otherwise just trace the cachedProperties
    // strongly, ie. call trace on it.
    if (cachedProperties && strongify == WTF::WeakPointersActWeak) {
        // A given cache entry is only kept alive if none of the MatchedProperties
        // in the CachedMatchedProperties value contain a dead "properties" field.
        // If there is a dead field the entire cache entry is removed.
        for (const auto& cachedProperties : cachedProperties->matchedProperties) {
            if (!visitor->isAlive(cachedProperties.properties)) {
                // For now report the cache entry as dead. This might not
                // be the final result if in a subsequent call for this entry,
                // the "properties" field has been marked via another path.
                return true;
            }
        }
    }
    // At this point none of the entries in the matchedProperties vector
    // had a dead "properties" field so trace CachedMatchedProperties strongly.
    visitor->trace(cachedProperties);
    return false;
}
#endif

void CachedMatchedProperties::set(const RenderStyle* style, const RenderStyle* parentStyle, const MatchResult& matchResult)
{
    matchedProperties.appendVector(matchResult.matchedProperties);
    ranges = matchResult.ranges;

    // Note that we don't cache the original RenderStyle instance. It may be further modified.
    // The RenderStyle in the cache is really just a holder for the substructures and never used as-is.
    this->renderStyle = RenderStyle::clone(style);
    this->parentRenderStyle = RenderStyle::clone(parentStyle);
}

void CachedMatchedProperties::clear()
{
    matchedProperties.clear();
    renderStyle = nullptr;
    parentRenderStyle = nullptr;
}

MatchedPropertiesCache::MatchedPropertiesCache()
#if !ENABLE(OILPAN)
    : m_additionsSinceLastSweep(0)
    , m_sweepTimer(this, &MatchedPropertiesCache::sweep)
#endif
{
}

const CachedMatchedProperties* MatchedPropertiesCache::find(unsigned hash, const StyleResolverState& styleResolverState, const MatchResult& matchResult)
{
    ASSERT(hash);

    Cache::iterator it = m_cache.find(hash);
    if (it == m_cache.end())
        return 0;
    CachedMatchedProperties* cacheItem = it->value.get();
    ASSERT(cacheItem);

    size_t size = matchResult.matchedProperties.size();
    if (size != cacheItem->matchedProperties.size())
        return 0;
    if (cacheItem->renderStyle->insideLink() != styleResolverState.style()->insideLink())
        return 0;
    for (size_t i = 0; i < size; ++i) {
        if (matchResult.matchedProperties[i] != cacheItem->matchedProperties[i])
            return 0;
    }
    if (cacheItem->ranges != matchResult.ranges)
        return 0;
    return cacheItem;
}

void MatchedPropertiesCache::add(const RenderStyle* style, const RenderStyle* parentStyle, unsigned hash, const MatchResult& matchResult)
{
#if !ENABLE(OILPAN)
    static const unsigned maxAdditionsBetweenSweeps = 100;
    if (++m_additionsSinceLastSweep >= maxAdditionsBetweenSweeps
        && !m_sweepTimer.isActive()) {
        static const unsigned sweepTimeInSeconds = 60;
        m_sweepTimer.startOneShot(sweepTimeInSeconds, FROM_HERE);
    }
#endif

    ASSERT(hash);
    Cache::AddResult addResult = m_cache.add(hash, nullptr);
    if (addResult.isNewEntry)
        addResult.storedValue->value = adoptPtrWillBeNoop(new CachedMatchedProperties);

    CachedMatchedProperties* cacheItem = addResult.storedValue->value.get();
    if (!addResult.isNewEntry)
        cacheItem->clear();

    cacheItem->set(style, parentStyle, matchResult);
}

void MatchedPropertiesCache::clear()
{
    m_cache.clear();
}

void MatchedPropertiesCache::clearViewportDependent()
{
    Vector<unsigned, 16> toRemove;
    for (const auto& cacheEntry : m_cache) {
        CachedMatchedProperties* cacheItem = cacheEntry.value.get();
        if (cacheItem->renderStyle->hasViewportUnits())
            toRemove.append(cacheEntry.key);
    }
    m_cache.removeAll(toRemove);
}

#if !ENABLE(OILPAN)
void MatchedPropertiesCache::sweep(Timer<MatchedPropertiesCache>*)
{
    // Look for cache entries containing a style declaration with a single ref and remove them.
    // This may happen when an element attribute mutation causes it to generate a new inlineStyle()
    // or presentationAttributeStyle(), potentially leaving this cache with the last ref on the old one.
    Vector<unsigned, 16> toRemove;
    for (const auto& cacheEntry : m_cache) {
        CachedMatchedProperties* cacheItem = cacheEntry.value.get();
        Vector<MatchedProperties>& matchedProperties = cacheItem->matchedProperties;
        for (size_t i = 0; i < matchedProperties.size(); ++i) {
            if (matchedProperties[i].properties->hasOneRef()) {
                toRemove.append(cacheEntry.key);
                break;
            }
        }
    }
    m_cache.removeAll(toRemove);
    m_additionsSinceLastSweep = 0;
}
#endif

bool MatchedPropertiesCache::isCacheable(const Element* element, const RenderStyle* style, const RenderStyle* parentStyle)
{
    // FIXME: CSSPropertyWebkitWritingMode modifies state when applying to document element. We can't skip the applying by caching.
    if (element == element->document().documentElement() && element->document().writingModeSetOnDocumentElement())
        return false;
    if (style->unique() || (style->styleType() != NOPSEUDO && parentStyle->unique()))
        return false;
    if (style->hasAppearance())
        return false;
    if (style->zoom() != RenderStyle::initialZoom())
        return false;
    if (style->writingMode() != RenderStyle::initialWritingMode())
        return false;
    // The cache assumes static knowledge about which properties are inherited.
    if (parentStyle->hasExplicitlyInheritedProperties())
        return false;
    return true;
}

void MatchedPropertiesCache::trace(Visitor* visitor)
{
#if ENABLE(OILPAN)
    visitor->trace(m_cache);
#endif
}

}
<commit_msg>Steer clear of g++ scoping bug in range-based for loop.<commit_after>/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "config.h"
#include "core/css/resolver/MatchedPropertiesCache.h"

#include "core/css/StylePropertySet.h"
#include "core/css/resolver/StyleResolverState.h"
#include "core/rendering/style/RenderStyle.h"

namespace blink {

#if ENABLE(OILPAN)
bool CachedMatchedPropertiesHashTraits::traceInCollection(Visitor* visitor, Member<CachedMatchedProperties>& cachedProperties, WTF::ShouldWeakPointersBeMarkedStrongly strongify)
{
    // Only honor the cache's weakness semantics if the collection is traced
    // with WeakPointersActWeak. Otherwise just trace the cachedProperties
    // strongly, ie. call trace on it.
    if (cachedProperties && strongify == WTF::WeakPointersActWeak) {
        // A given cache entry is only kept alive if none of the MatchedProperties
        // in the CachedMatchedProperties value contain a dead "properties" field.
        // If there is a dead field the entire cache entry is removed.
        for (const auto& matchedProperties : cachedProperties->matchedProperties) {
            if (!visitor->isAlive(matchedProperties.properties)) {
                // For now report the cache entry as dead. This might not
                // be the final result if in a subsequent call for this entry,
                // the "properties" field has been marked via another path.
                return true;
            }
        }
    }
    // At this point none of the entries in the matchedProperties vector
    // had a dead "properties" field so trace CachedMatchedProperties strongly.
    visitor->trace(cachedProperties);
    return false;
}
#endif

void CachedMatchedProperties::set(const RenderStyle* style, const RenderStyle* parentStyle, const MatchResult& matchResult)
{
    matchedProperties.appendVector(matchResult.matchedProperties);
    ranges = matchResult.ranges;

    // Note that we don't cache the original RenderStyle instance. It may be further modified.
    // The RenderStyle in the cache is really just a holder for the substructures and never used as-is.
    this->renderStyle = RenderStyle::clone(style);
    this->parentRenderStyle = RenderStyle::clone(parentStyle);
}

void CachedMatchedProperties::clear()
{
    matchedProperties.clear();
    renderStyle = nullptr;
    parentRenderStyle = nullptr;
}

MatchedPropertiesCache::MatchedPropertiesCache()
#if !ENABLE(OILPAN)
    : m_additionsSinceLastSweep(0)
    , m_sweepTimer(this, &MatchedPropertiesCache::sweep)
#endif
{
}

const CachedMatchedProperties* MatchedPropertiesCache::find(unsigned hash, const StyleResolverState& styleResolverState, const MatchResult& matchResult)
{
    ASSERT(hash);

    Cache::iterator it = m_cache.find(hash);
    if (it == m_cache.end())
        return 0;
    CachedMatchedProperties* cacheItem = it->value.get();
    ASSERT(cacheItem);

    size_t size = matchResult.matchedProperties.size();
    if (size != cacheItem->matchedProperties.size())
        return 0;
    if (cacheItem->renderStyle->insideLink() != styleResolverState.style()->insideLink())
        return 0;
    for (size_t i = 0; i < size; ++i) {
        if (matchResult.matchedProperties[i] != cacheItem->matchedProperties[i])
            return 0;
    }
    if (cacheItem->ranges != matchResult.ranges)
        return 0;
    return cacheItem;
}

void MatchedPropertiesCache::add(const RenderStyle* style, const RenderStyle* parentStyle, unsigned hash, const MatchResult& matchResult)
{
#if !ENABLE(OILPAN)
    static const unsigned maxAdditionsBetweenSweeps = 100;
    if (++m_additionsSinceLastSweep >= maxAdditionsBetweenSweeps
        && !m_sweepTimer.isActive()) {
        static const unsigned sweepTimeInSeconds = 60;
        m_sweepTimer.startOneShot(sweepTimeInSeconds, FROM_HERE);
    }
#endif

    ASSERT(hash);
    Cache::AddResult addResult = m_cache.add(hash, nullptr);
    if (addResult.isNewEntry)
        addResult.storedValue->value = adoptPtrWillBeNoop(new CachedMatchedProperties);

    CachedMatchedProperties* cacheItem = addResult.storedValue->value.get();
    if (!addResult.isNewEntry)
        cacheItem->clear();

    cacheItem->set(style, parentStyle, matchResult);
}

void MatchedPropertiesCache::clear()
{
    m_cache.clear();
}

void MatchedPropertiesCache::clearViewportDependent()
{
    Vector<unsigned, 16> toRemove;
    for (const auto& cacheEntry : m_cache) {
        CachedMatchedProperties* cacheItem = cacheEntry.value.get();
        if (cacheItem->renderStyle->hasViewportUnits())
            toRemove.append(cacheEntry.key);
    }
    m_cache.removeAll(toRemove);
}

#if !ENABLE(OILPAN)
void MatchedPropertiesCache::sweep(Timer<MatchedPropertiesCache>*)
{
    // Look for cache entries containing a style declaration with a single ref and remove them.
    // This may happen when an element attribute mutation causes it to generate a new inlineStyle()
    // or presentationAttributeStyle(), potentially leaving this cache with the last ref on the old one.
    Vector<unsigned, 16> toRemove;
    for (const auto& cacheEntry : m_cache) {
        CachedMatchedProperties* cacheItem = cacheEntry.value.get();
        Vector<MatchedProperties>& matchedProperties = cacheItem->matchedProperties;
        for (size_t i = 0; i < matchedProperties.size(); ++i) {
            if (matchedProperties[i].properties->hasOneRef()) {
                toRemove.append(cacheEntry.key);
                break;
            }
        }
    }
    m_cache.removeAll(toRemove);
    m_additionsSinceLastSweep = 0;
}
#endif

bool MatchedPropertiesCache::isCacheable(const Element* element, const RenderStyle* style, const RenderStyle* parentStyle)
{
    // FIXME: CSSPropertyWebkitWritingMode modifies state when applying to document element. We can't skip the applying by caching.
    if (element == element->document().documentElement() && element->document().writingModeSetOnDocumentElement())
        return false;
    if (style->unique() || (style->styleType() != NOPSEUDO && parentStyle->unique()))
        return false;
    if (style->hasAppearance())
        return false;
    if (style->zoom() != RenderStyle::initialZoom())
        return false;
    if (style->writingMode() != RenderStyle::initialWritingMode())
        return false;
    // The cache assumes static knowledge about which properties are inherited.
    if (parentStyle->hasExplicitlyInheritedProperties())
        return false;
    return true;
}

void MatchedPropertiesCache::trace(Visitor* visitor)
{
#if ENABLE(OILPAN)
    visitor->trace(m_cache);
#endif
}

}
<|endoftext|>