<commit_before>//                       PUMI Example 1 - Parallel Version
//
// Compile with: Add pumi_ex1p.cpp in the CMakeLists.txt
//
// Sample runs:  mpirun -np 4 ./pumi_ex1p -m ../data/pumi/Kova/Kova4.smb
//                    -p ../data/pumi/Kova/Kova.x_t -o 1 -go 2
//
// Description:  This example is the counterpart of ex1 in the MFEM examples list
//               with the difference that pumi Api's are used to load a parallel
//               pumi mesh classified on a geometric model and then generate the
//               corresponding parallel  MFEM meshes.
//
//               This example also performs a "uniform" refinement, similar to
//               MFEM examples, for coarse meshes. However, the refinement is
//               performed using the PUMi Api's and by defning a size field.
//
//               The inputs for this example are a Parasolid model, "*.xmt_txt"
//               and SCOREC parallel meshes "*.smb". Switch "-o" is used for
//               the Finite Element order and switch "-go" for the geometry order.
//               Note that they can be used independently. i.e. "-o 8 -go 3"
//               solves for 8th order FE on a third order geometry.

#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <SimUtil.h>

using namespace std;
using namespace mfem;

class UniformRefinement : public ma::IsotropicFunction
{
  public:
    UniformRefinement(ma::Mesh* m, int level)
    {
      mesh = m;
      fac = ((level > 0) ? level : 1.0);
      average = ma::getAverageEdgeLength(m);
    }
    virtual double getValue(ma::Entity* v)
    {
      double invfac = pow(1. / double(fac), mesh->getDimension());
      return average*invfac;
    }
  private:
    ma::Mesh* mesh;
    double average;
    double fac;
};

int main(int argc, char *argv[])
{
   // 1. Initialize MPI.
   int num_procs, myid;
   MPI_Init(&argc, &argv);
   MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
   MPI_Comm_rank(MPI_COMM_WORLD, &myid);

   // 2. Parse command-line options.
   const char *mesh_file = "../data/pumi/parallel/Kova4/Kova_4.smb";
   const char *model_file = "../data/pumi/geom/Kova.x_t";
   int order = 1;
   bool static_cond = false;
   bool visualization = 1;
   int geom_order = 1;

   OptionsParser args(argc, argv);
   args.AddOption(&mesh_file, "-m", "--mesh",
                  "Mesh file to use.");
   args.AddOption(&order, "-o", "--order",
                  "Finite element order (polynomial degree) or -1 for"
                  " isoparametric space.");
   args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
                  "--no-static-condensation", "Enable static condensation.");
   args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
                  "--no-visualization",
                  "Enable or disable GLVis visualization.");
   args.AddOption(&model_file, "-p", "--parasolid",
                  "Parasolid model to use.");
   args.AddOption(&geom_order, "-go", "--geometry_order",
                  "Geometric order of the model");

   args.Parse();
   if (!args.Good())
   {
      if (myid == 0)
      {
         args.PrintUsage(cout);
      }
      MPI_Finalize();
      return 1;
   }
   if (myid == 0)
   {
      args.PrintOptions(cout);
   }

   //3. Read the SCOREC Mesh
   PCU_Comm_Init();
   SimUtil_start();
   Sim_readLicenseFile(0);

   gmi_sim_start();
   gmi_register_mesh();
   gmi_register_sim();

   apf::Mesh2* pumi_mesh;
   pumi_mesh = apf::loadMdsMesh(model_file, mesh_file);

   //4. Increase the geometry order and refine the mesh if necessary.
   //   Parallel uniform refinement is performed if the total numebr of
   //   elements is less than 10000.
   int dim = pumi_mesh->getDimension();
   int nEle = pumi_mesh->count(dim);
   int ref_levels = (int)floor(log(10000./nEle)/log(2.)/dim);

   UniformRefinement uniField(pumi_mesh,ref_levels);
   ma::Input* uniInput = ma::configure(pumi_mesh, &uniField);
   uniInput->shouldFixShape = true;
   uniInput->shouldSnap = true;
   uniInput->shouldTransferParametric = true;

   if (geom_order > 1){
       crv::BezierCurver bc(pumi_mesh, geom_order, 2);
       bc.run();

       //Uniform refinement
       if (ref_levels > 1) crv::adapt(uniInput);
   }
   else if (ref_levels > 1)
       ma::adapt(uniInput);

   pumi_mesh->verify();

   // 5. Create the parallel MFEM mesh object from the parallel PUMI mesh.
   //    We can handle triangular and tetrahedral meshes. Note that the
   //    mesh resolution is performed on the PUMI mesh.
   ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, pumi_mesh);

   // 6. Define a parallel finite element space on the parallel mesh. Here we
   //    use continuous Lagrange finite elements of the specified order. If
   //    order < 1, we instead use an isoparametric/isogeometric space.
   FiniteElementCollection *fec;
   if (order > 0)
   {
      fec = new H1_FECollection(order, dim);
   }
   else if (pmesh->GetNodes())
   {
      fec = pmesh->GetNodes()->OwnFEC();
      if (myid == 0)
      {
         cout << "Using isoparametric FEs: " << fec->Name() << endl;
      }
   }
   else
   {
      fec = new H1_FECollection(order = 1, dim);
   }
   ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
   HYPRE_Int size = fespace->GlobalTrueVSize();
   if (myid == 0)
   {
      cout << "Number of finite element unknowns: " << size << endl;
   }

   // 7. Determine the list of true (i.e. parallel conforming) essential
   //    boundary dofs. In this example, the boundary conditions are defined
   //    by marking all the boundary attributes from the mesh as essential
   //    (Dirichlet) and converting them to a list of true dofs.
   Array<int> ess_tdof_list;
   if (pmesh->bdr_attributes.Size())
   {
      Array<int> ess_bdr(pmesh->bdr_attributes.Max());
      ess_bdr = 1;
      fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
   }

   // 8. Set up the parallel linear form b(.) which corresponds to the
   //    right-hand side of the FEM linear system, which in this case is
   //    (1,phi_i) where phi_i are the basis functions in fespace.
   ParLinearForm *b = new ParLinearForm(fespace);
   ConstantCoefficient one(1.0);
   b->AddDomainIntegrator(new DomainLFIntegrator(one));
   b->Assemble();

   // 9. Define the solution vector x as a parallel finite element grid function
   //    corresponding to fespace. Initialize x with initial guess of zero,
   //    which satisfies the boundary conditions.
   ParGridFunction x(fespace);
   x = 0.0;

   // 10. Set up the parallel bilinear form a(.,.) on the finite element space
   //     corresponding to the Laplacian operator -Delta, by adding the Diffusion
   //     domain integrator.
   ParBilinearForm *a = new ParBilinearForm(fespace);
   a->AddDomainIntegrator(new DiffusionIntegrator(one));

   // 11. Assemble the parallel bilinear form and the corresponding linear
   //     system, applying any necessary transformations such as: parallel
   //     assembly, eliminating boundary conditions, applying conforming
   //     constraints for non-conforming AMR, static condensation, etc.
   if (static_cond) { a->EnableStaticCondensation(); }
   a->Assemble();

   HypreParMatrix A;
   Vector B, X;
   a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);

   if (myid == 0)
   {
      cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
   }

   // 12. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
   //     preconditioner from hypre.
   HypreSolver *amg = new HypreBoomerAMG(A);
   HyprePCG *pcg = new HyprePCG(A);
   pcg->SetTol(1e-12);
   pcg->SetMaxIter(200);
   pcg->SetPrintLevel(2);
   pcg->SetPreconditioner(*amg);
   pcg->Mult(B, X);

   // 13. Recover the parallel grid function corresponding to X. This is the
   //     local finite element solution on each processor.
   a->RecoverFEMSolution(X, *b, x);

   // 14. Save the refined mesh and the solution in parallel. This output can
   //     be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
   {
      ostringstream mesh_name, sol_name;
      mesh_name << "mesh." << setfill('0') << setw(6) << myid;
      sol_name << "sol." << setfill('0') << setw(6) << myid;

      ofstream mesh_ofs(mesh_name.str().c_str());
      mesh_ofs.precision(8);
      pmesh->Print(mesh_ofs);

      ofstream sol_ofs(sol_name.str().c_str());
      sol_ofs.precision(8);
      x.Save(sol_ofs);
   }

   // 15. Send the solution by socket to a GLVis server.
   if (visualization)
   {
      char vishost[] = "localhost";
      int  visport   = 19916;
      socketstream sol_sock(vishost, visport);
      sol_sock << "parallel " << num_procs << " " << myid << "\n";
      sol_sock.precision(8);
      sol_sock << "solution\n" << *pmesh << x << flush;
   }

   // 16. Free the used memory.
   delete pcg;
   delete amg;
   delete a;
   delete b;
   delete fespace;
   if (order > 0) { delete fec; }
   delete pmesh;

   pumi_mesh->destroyNative();
   apf::destroyMesh(pumi_mesh);
   PCU_Comm_Free();
   gmi_sim_stop();

   Sim_unregisterAllKeys();
   SimUtil_stop();

   MPI_Finalize();

   return 0;
}
<commit_msg>Clean unifor refinement (wo size field)<commit_after>//                       PUMI Example 1 - Parallel Version
//
// Compile with: Add pumi_ex1p.cpp in the CMakeLists.txt
//
// Sample runs:  mpirun -np 4 ./pumi_ex1p -m ../data/pumi/Kova/Kova4.smb
//                    -p ../data/pumi/Kova/Kova.x_t -o 1 -go 2
//
// Description:  This example is the counterpart of ex1 in the MFEM examples list
//               with the difference that pumi Api's are used to load a parallel
//               pumi mesh classified on a geometric model and then generate the
//               corresponding parallel  MFEM meshes.
//
//               This example also performs a "uniform" refinement, similar to
//               MFEM examples, for coarse meshes. However, the refinement is
//               performed using the PUMi Api's.
//
//               The inputs for this example are a Parasolid model, "*.xmt_txt"
//               and SCOREC parallel meshes "*.smb". Switch "-o" is used for
//               the Finite Element order and switch "-go" for the geometry order.
//               Note that they can be used independently. i.e. "-o 8 -go 3"
//               solves for 8th order FE on a third order geometry.

#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <SimUtil.h>

using namespace std;
using namespace mfem;

int main(int argc, char *argv[])
{
   // 1. Initialize MPI.
   int num_procs, myid;
   MPI_Init(&argc, &argv);
   MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
   MPI_Comm_rank(MPI_COMM_WORLD, &myid);

   // 2. Parse command-line options.
   const char *mesh_file = "../data/pumi/parallel/Kova4/Kova_4.smb";
   const char *model_file = "../data/pumi/geom/Kova.x_t";
   int order = 1;
   bool static_cond = false;
   bool visualization = 1;
   int geom_order = 1;

   OptionsParser args(argc, argv);
   args.AddOption(&mesh_file, "-m", "--mesh",
                  "Mesh file to use.");
   args.AddOption(&order, "-o", "--order",
                  "Finite element order (polynomial degree) or -1 for"
                  " isoparametric space.");
   args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
                  "--no-static-condensation", "Enable static condensation.");
   args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
                  "--no-visualization",
                  "Enable or disable GLVis visualization.");
   args.AddOption(&model_file, "-p", "--parasolid",
                  "Parasolid model to use.");
   args.AddOption(&geom_order, "-go", "--geometry_order",
                  "Geometric order of the model");

   args.Parse();
   if (!args.Good())
   {
      if (myid == 0)
      {
         args.PrintUsage(cout);
      }
      MPI_Finalize();
      return 1;
   }
   if (myid == 0)
   {
      args.PrintOptions(cout);
   }

   //3. Read the SCOREC Mesh
   PCU_Comm_Init();
   SimUtil_start();
   Sim_readLicenseFile(0);

   gmi_sim_start();
   gmi_register_mesh();
   gmi_register_sim();

   apf::Mesh2* pumi_mesh;
   pumi_mesh = apf::loadMdsMesh(model_file, mesh_file);

   //4. Increase the geometry order and refine the mesh if necessary.
   //   Parallel uniform refinement is performed if the total numebr of
   //   elements is less than 10000.
   int dim = pumi_mesh->getDimension();
   int nEle = pumi_mesh->count(dim);
   int ref_levels = (int)floor(log(10000./nEle)/log(2.)/dim);

   if (geom_order > 1){
       crv::BezierCurver bc(pumi_mesh, geom_order, 2);
       bc.run();
   }

   // Perform Uniform refinement
   if (ref_levels > 1){
       ma::Input* uniInput = ma::configureUniformRefine(pumi_mesh, ref_levels);

       if ( geom_order > 1)
           crv::adapt(uniInput);
       else
           ma::adapt(uniInput);
   }

   pumi_mesh->verify();

   // 5. Create the parallel MFEM mesh object from the parallel PUMI mesh.
   //    We can handle triangular and tetrahedral meshes. Note that the
   //    mesh resolution is performed on the PUMI mesh.
   ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, pumi_mesh);

   // 6. Define a parallel finite element space on the parallel mesh. Here we
   //    use continuous Lagrange finite elements of the specified order. If
   //    order < 1, we instead use an isoparametric/isogeometric space.
   FiniteElementCollection *fec;
   if (order > 0)
   {
      fec = new H1_FECollection(order, dim);
   }
   else if (pmesh->GetNodes())
   {
      fec = pmesh->GetNodes()->OwnFEC();
      if (myid == 0)
      {
         cout << "Using isoparametric FEs: " << fec->Name() << endl;
      }
   }
   else
   {
      fec = new H1_FECollection(order = 1, dim);
   }
   ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
   HYPRE_Int size = fespace->GlobalTrueVSize();
   if (myid == 0)
   {
      cout << "Number of finite element unknowns: " << size << endl;
   }

   // 7. Determine the list of true (i.e. parallel conforming) essential
   //    boundary dofs. In this example, the boundary conditions are defined
   //    by marking all the boundary attributes from the mesh as essential
   //    (Dirichlet) and converting them to a list of true dofs.
   Array<int> ess_tdof_list;
   if (pmesh->bdr_attributes.Size())
   {
      Array<int> ess_bdr(pmesh->bdr_attributes.Max());
      ess_bdr = 1;
      fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
   }

   // 8. Set up the parallel linear form b(.) which corresponds to the
   //    right-hand side of the FEM linear system, which in this case is
   //    (1,phi_i) where phi_i are the basis functions in fespace.
   ParLinearForm *b = new ParLinearForm(fespace);
   ConstantCoefficient one(1.0);
   b->AddDomainIntegrator(new DomainLFIntegrator(one));
   b->Assemble();

   // 9. Define the solution vector x as a parallel finite element grid function
   //    corresponding to fespace. Initialize x with initial guess of zero,
   //    which satisfies the boundary conditions.
   ParGridFunction x(fespace);
   x = 0.0;

   // 10. Set up the parallel bilinear form a(.,.) on the finite element space
   //     corresponding to the Laplacian operator -Delta, by adding the Diffusion
   //     domain integrator.
   ParBilinearForm *a = new ParBilinearForm(fespace);
   a->AddDomainIntegrator(new DiffusionIntegrator(one));

   // 11. Assemble the parallel bilinear form and the corresponding linear
   //     system, applying any necessary transformations such as: parallel
   //     assembly, eliminating boundary conditions, applying conforming
   //     constraints for non-conforming AMR, static condensation, etc.
   if (static_cond) { a->EnableStaticCondensation(); }
   a->Assemble();

   HypreParMatrix A;
   Vector B, X;
   a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);

   if (myid == 0)
   {
      cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
   }

   // 12. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
   //     preconditioner from hypre.
   HypreSolver *amg = new HypreBoomerAMG(A);
   HyprePCG *pcg = new HyprePCG(A);
   pcg->SetTol(1e-12);
   pcg->SetMaxIter(200);
   pcg->SetPrintLevel(2);
   pcg->SetPreconditioner(*amg);
   pcg->Mult(B, X);

   // 13. Recover the parallel grid function corresponding to X. This is the
   //     local finite element solution on each processor.
   a->RecoverFEMSolution(X, *b, x);

   // 14. Save the refined mesh and the solution in parallel. This output can
   //     be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
   {
      ostringstream mesh_name, sol_name;
      mesh_name << "mesh." << setfill('0') << setw(6) << myid;
      sol_name << "sol." << setfill('0') << setw(6) << myid;

      ofstream mesh_ofs(mesh_name.str().c_str());
      mesh_ofs.precision(8);
      pmesh->Print(mesh_ofs);

      ofstream sol_ofs(sol_name.str().c_str());
      sol_ofs.precision(8);
      x.Save(sol_ofs);
   }

   // 15. Send the solution by socket to a GLVis server.
   if (visualization)
   {
      char vishost[] = "localhost";
      int  visport   = 19916;
      socketstream sol_sock(vishost, visport);
      sol_sock << "parallel " << num_procs << " " << myid << "\n";
      sol_sock.precision(8);
      sol_sock << "solution\n" << *pmesh << x << flush;
   }

   // 16. Free the used memory.
   delete pcg;
   delete amg;
   delete a;
   delete b;
   delete fespace;
   if (order > 0) { delete fec; }
   delete pmesh;

   pumi_mesh->destroyNative();
   apf::destroyMesh(pumi_mesh);
   PCU_Comm_Free();
   gmi_sim_stop();

   Sim_unregisterAllKeys();
   SimUtil_stop();

   MPI_Finalize();

   return 0;
}
<|endoftext|>


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

/**
* Add each element in `X` to a corresponding element in `Y` and assigns the result to an element in `Z`.
*/
#include <stdint.h>
#include <nan.h>
#include "stdlib/ndarray/base/bytes_per_element.h"
#include "stdlib/ndarray/dtypes.h"
#include "stdlib/strided_binary.h"

/**
* Add-on namespace.
*/
namespace addon_strided_add {

	using Nan::FunctionCallbackInfo;
	using Nan::TypedArrayContents;
	using Nan::ThrowTypeError;
	using Nan::ThrowError;
	using v8::Local;
	using v8::Value;

	/**
	* Adds two doubles.
	*
	* @private
	* @param x  first double
	* @param y  second double
	* @return   sum
	*/
	double add( double x, double y ) {
		return x + y;
	}

	/**
	* Returns a typed array data type.
	*
	* @private
	* @param x  typed array
	* @return   data type
	*/
	enum STDLIB_NDARRAY_DTYPE typed_array_data_type( Local<Value> x ) {
		if ( x->IsFloat64Array() ) {
			return STDLIB_NDARRAY_FLOAT64;
		}
		if ( x->IsFloat32Array() ) {
			return STDLIB_NDARRAY_FLOAT32;
		}
		if ( x->IsInt32Array() ) {
			return STDLIB_NDARRAY_INT32;
		}
		if ( x->IsUint32Array() ) {
			return STDLIB_NDARRAY_UINT32;
		}
		if ( x->IsInt16Array() ) {
			return STDLIB_NDARRAY_INT16;
		}
		if ( x->IsUint16Array() ) {
			return STDLIB_NDARRAY_UINT16;
		}
		if ( x->IsInt8Array() ) {
			return STDLIB_NDARRAY_INT8;
		}
		if ( x->IsUint8Array() ) {
			return STDLIB_NDARRAY_UINT8;
		}
		return STDLIB_NDARRAY_UINT8; // Uint8ClampedArray
	}

	/**
	* Adds each element in `X` to a corresponding element in `Y` and assigns the result to an element in `Z`.
	*
	* When called from JavaScript, the function expects the following arguments:
	*
	* * __N__: number of elements.
	* * __X__: input typed array.
	* * __strideX__: `X` stride length.
	* * __Y__: input typed array.
	* * __strideY__: `Y` typed array stride length.
	* * __Z__: destination typed array.
	* * __strideZ__: destination typed array stride length.
	*
	* @param info   arguments
	*/
	void node_add( const FunctionCallbackInfo<Value>& info ) {
		enum STDLIB_NDARRAY_DTYPE types[3];
		uint8_t *arrays[3];
		int64_t strides[3];
		int64_t shape[1];
		int64_t nsargs;
		int64_t sargs; // WARNING: we assume no more than 64 input strided array arguments, which seems a reasonable assumption
		int64_t nargs;
		int64_t nout;
		int64_t iout;
		int64_t nin;
		int64_t i;
		int64_t j;

		nargs = 7;

		// Number of input and output strided array arguments:
		nin = 2;
		nout = 1;

		// Compute the index of the first output strided array argument:
		iout = ( nin*2 ) + 1;

		// Initialize variables used to track scalar input arguments:
		nsargs = 0;
		sargs = 0;

		if ( info.Length() != nargs ) {
			ThrowError( "invalid invocation. Incorrect number of arguments." );
			return;
		}

		// The first argument is always the number of elements over which to iterate...
		if ( !info[ 0 ]->IsNumber() ) {
			ThrowTypeError( "invalid input argument. First argument must be a number." );
			return;
		} else {
			shape[ 0 ] = static_cast<int64_t>( info[ 0 ]->IntegerValue() );
		}

		// Stride arguments for both input and output strided arrays are every other argument beginning from the third argument...
		for ( i = 2; i < nargs; i += 2 ) {
			if ( !info[ i ]->IsNumber() ) {
				ThrowTypeError( "invalid input argument. Stride argument must be a number." );
				return;
			}
			j = ( i-2 ) / 2;
			strides[ j ] = static_cast<int64_t>( info[ i ]->IntegerValue() );
		}

#if defined(V8_MAJOR_VERSION) && ( V8_MAJOR_VERSION > 4 || ( V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3 ) )

		// Input strided array arguments are every other argument beginning from the second argument...
		for ( i = 1; i < iout; i += 2 ) {
			j = ( i-1 ) / 2;
			if ( info[ i ]->IsArrayBufferView() ) {
				TypedArrayContents<uint8_t> TypedArray( info[ i ] );
				arrays[ j ] = *TypedArray;
				types[ j ] = typed_array_data_type( info[ i ] );
				strides[ j ] *= stdlib_ndarray_bytes_per_element( types[ j ] );
			} else if ( info[ i ]->IsNumber() ) {
				sargs |= (1<<j);
				nsargs += 1;
			} else {
				ThrowTypeError( "invalid input argument. Input strided array argument must be a typed array or scalar." );
				return;
			}
		}

		// Output strided array arguments are every other argument beginning from the argument following the last input strided array stride argument...
		for ( i = iout; i < nargs; i += 2 ) {
			j = ( i-1 ) / 2;
			if ( !info[ i ]->IsArrayBufferView() ) {
				ThrowTypeError( "invalid input argument. Output strided array arguments must be typed arrays." );
				return;
			} else {
				TypedArrayContents<uint8_t> TypedArray( info[ i ] );
				arrays[ j ] = *TypedArray;
				types[ j ] = typed_array_data_type( info[ i ] );
				strides[ j ] *= stdlib_ndarray_bytes_per_element( types[ j ] );
			}
		}

#else

		// TODO: add support for older Node versions (type verification and strides; see https://github.com/nodejs/node/blob/v0.10.39-release/src/v8_typed_array.cc and https://github.com/nodejs/nan/blob/master/nan_typedarray_contents.h)

		// Input strided array arguments are every other argument beginning from the second argument...
		for ( i = 1; i < iout; i += 2 ) {
			j = ( i-1 ) / 2;
			if ( info[ i ]->IsNumber() ) {
				sargs |= (1<<j);
				nsargs += 1;
			} else if ( info[ i ]->IsObject() && !info[ i ]->IsNull() ) {
				// Assume a typed array:
				TypedArrayContents<uint8_t> TypedArray( info[ i ] );
				arrays[ j ] = *TypedArray;

				types[ j ] = STDLIB_NDARRAY_FLOAT64; // TODO: determine data type (will require determining the typed array "class"; see https://github.com/nodejs/node/blob/v0.10.39-release/src/v8_typed_array.cc#L462)
				strides[ j ] *= 8; // TODO: compute based on data type (or glean directly from the typed array instance)
			} else {
				ThrowTypeError( "invalid input argument. Input strided array argument must be a typed array or scalar." );
				return;
			}
		}

		// Output strided array arguments are every other argument beginning from the argument following the last input strided array stride argument...
		for ( i = iout; i < nargs; i += 2 ) {
			j = ( i-1 ) / 2;
			if ( info[ i ]->IsObject() && !info[ i ]->IsNull() ) {
				// Assume a typed array:
				TypedArrayContents<uint8_t> TypedArray( info[ i ] );
				arrays[ j ] = *TypedArray;

				types[ j ] = STDLIB_NDARRAY_FLOAT64; // TODO: determine data type (will require determining the typed array "class"; see https://github.com/nodejs/node/blob/v0.10.39-release/src/v8_typed_array.cc#L462)
				strides[ j ] *= 8; // TODO: compute based on data type (or glean directly from typed array instance)
			} else {
				ThrowTypeError( "invalid input argument. Output strided array arguments must be typed arrays." );
				return;
			}
		}

#endif

		// Check if we have been provided only scalar input arguments...
		if ( nsargs == nin ) {
			ThrowError( "invalid input arguments. Must provide at least one input strided array argument." );
			return;
		}
		// Broadcasting...

		// Create an array having the closest "compatible" type...
		// arrays[ 0 ] = broadcast( static_cast<double>( info[ 1 ]->NumberValue() ), types[ 0 ] );

		// Perform addition:
		stdlib_strided_dd_d( arrays, shape, strides, (void *)add );
	}

	NAN_MODULE_INIT( Init ) {
		Nan::Export( target, "add", node_add );
	}

	NODE_MODULE( addon, Init )
} // end namespace addon_strided_add
<commit_msg>Fix check when only output strided array arguments<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* Add each element in `X` to a corresponding element in `Y` and assigns the result to an element in `Z`.
*/
#include <stdint.h>
#include <nan.h>
#include "stdlib/ndarray/base/bytes_per_element.h"
#include "stdlib/ndarray/dtypes.h"
#include "stdlib/strided_binary.h"

/**
* Add-on namespace.
*/
namespace addon_strided_add {

	using Nan::FunctionCallbackInfo;
	using Nan::TypedArrayContents;
	using Nan::ThrowTypeError;
	using Nan::ThrowError;
	using v8::Local;
	using v8::Value;

	/**
	* Adds two doubles.
	*
	* @private
	* @param x  first double
	* @param y  second double
	* @return   sum
	*/
	double add( double x, double y ) {
		return x + y;
	}

	/**
	* Returns a typed array data type.
	*
	* @private
	* @param x  typed array
	* @return   data type
	*/
	enum STDLIB_NDARRAY_DTYPE typed_array_data_type( Local<Value> x ) {
		if ( x->IsFloat64Array() ) {
			return STDLIB_NDARRAY_FLOAT64;
		}
		if ( x->IsFloat32Array() ) {
			return STDLIB_NDARRAY_FLOAT32;
		}
		if ( x->IsInt32Array() ) {
			return STDLIB_NDARRAY_INT32;
		}
		if ( x->IsUint32Array() ) {
			return STDLIB_NDARRAY_UINT32;
		}
		if ( x->IsInt16Array() ) {
			return STDLIB_NDARRAY_INT16;
		}
		if ( x->IsUint16Array() ) {
			return STDLIB_NDARRAY_UINT16;
		}
		if ( x->IsInt8Array() ) {
			return STDLIB_NDARRAY_INT8;
		}
		if ( x->IsUint8Array() ) {
			return STDLIB_NDARRAY_UINT8;
		}
		return STDLIB_NDARRAY_UINT8; // Uint8ClampedArray
	}

	/**
	* Adds each element in `X` to a corresponding element in `Y` and assigns the result to an element in `Z`.
	*
	* When called from JavaScript, the function expects the following arguments:
	*
	* * __N__: number of elements.
	* * __X__: input typed array.
	* * __strideX__: `X` stride length.
	* * __Y__: input typed array.
	* * __strideY__: `Y` typed array stride length.
	* * __Z__: destination typed array.
	* * __strideZ__: destination typed array stride length.
	*
	* @param info   arguments
	*/
	void node_add( const FunctionCallbackInfo<Value>& info ) {
		enum STDLIB_NDARRAY_DTYPE types[3];
		uint8_t *arrays[3];
		int64_t strides[3];
		int64_t shape[1];
		int64_t nsargs;
		int64_t sargs; // WARNING: we assume no more than 64 input strided array arguments, which seems a reasonable assumption
		int64_t nargs;
		int64_t nout;
		int64_t iout;
		int64_t nin;
		int64_t i;
		int64_t j;

		// Total number of input arguments:
		nargs = 7;

		// Number of input and output strided array arguments:
		nin = 2;
		nout = 1;

		// Compute the index of the first output strided array argument:
		iout = ( nin*2 ) + 1;

		// Initialize variables used to track scalar input arguments:
		nsargs = 0;
		sargs = 0;

		if ( info.Length() != nargs ) {
			ThrowError( "invalid invocation. Incorrect number of arguments." );
			return;
		}

		// The first argument is always the number of elements over which to iterate...
		if ( !info[ 0 ]->IsNumber() ) {
			ThrowTypeError( "invalid input argument. First argument must be a number." );
			return;
		} else {
			shape[ 0 ] = static_cast<int64_t>( info[ 0 ]->IntegerValue() );
		}

		// Stride arguments for both input and output strided arrays are every other argument beginning from the third argument...
		for ( i = 2; i < nargs; i += 2 ) {
			if ( !info[ i ]->IsNumber() ) {
				ThrowTypeError( "invalid input argument. Stride argument must be a number." );
				return;
			}
			j = ( i-2 ) / 2;
			strides[ j ] = static_cast<int64_t>( info[ i ]->IntegerValue() );
		}

#if defined(V8_MAJOR_VERSION) && ( V8_MAJOR_VERSION > 4 || ( V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3 ) )

		// Input strided array arguments are every other argument beginning from the second argument...
		for ( i = 1; i < iout; i += 2 ) {
			j = ( i-1 ) / 2;
			if ( info[ i ]->IsArrayBufferView() ) {
				TypedArrayContents<uint8_t> TypedArray( info[ i ] );
				arrays[ j ] = *TypedArray;
				types[ j ] = typed_array_data_type( info[ i ] );
				strides[ j ] *= stdlib_ndarray_bytes_per_element( types[ j ] );
			} else if ( info[ i ]->IsNumber() ) {
				sargs |= (1<<j);
				nsargs += 1;
			} else {
				ThrowTypeError( "invalid input argument. Input strided array argument must be a typed array or scalar." );
				return;
			}
		}

		// Output strided array arguments are every other argument beginning from the argument following the last input strided array stride argument...
		for ( i = iout; i < nargs; i += 2 ) {
			j = ( i-1 ) / 2;
			if ( !info[ i ]->IsArrayBufferView() ) {
				ThrowTypeError( "invalid input argument. Output strided array arguments must be typed arrays." );
				return;
			} else {
				TypedArrayContents<uint8_t> TypedArray( info[ i ] );
				arrays[ j ] = *TypedArray;
				types[ j ] = typed_array_data_type( info[ i ] );
				strides[ j ] *= stdlib_ndarray_bytes_per_element( types[ j ] );
			}
		}

#else

		// TODO: add support for older Node versions (type verification and strides; see https://github.com/nodejs/node/blob/v0.10.39-release/src/v8_typed_array.cc and https://github.com/nodejs/nan/blob/master/nan_typedarray_contents.h)

		// Input strided array arguments are every other argument beginning from the second argument...
		for ( i = 1; i < iout; i += 2 ) {
			j = ( i-1 ) / 2;
			if ( info[ i ]->IsNumber() ) {
				sargs |= (1<<j);
				nsargs += 1;
			} else if ( info[ i ]->IsObject() && !info[ i ]->IsNull() ) {
				// Assume a typed array:
				TypedArrayContents<uint8_t> TypedArray( info[ i ] );
				arrays[ j ] = *TypedArray;

				types[ j ] = STDLIB_NDARRAY_FLOAT64; // TODO: determine data type (will require determining the typed array "class"; see https://github.com/nodejs/node/blob/v0.10.39-release/src/v8_typed_array.cc#L462)
				strides[ j ] *= 8; // TODO: compute based on data type (or glean directly from the typed array instance)
			} else {
				ThrowTypeError( "invalid input argument. Input strided array argument must be a typed array or scalar." );
				return;
			}
		}

		// Output strided array arguments are every other argument beginning from the argument following the last input strided array stride argument...
		for ( i = iout; i < nargs; i += 2 ) {
			j = ( i-1 ) / 2;
			if ( info[ i ]->IsObject() && !info[ i ]->IsNull() ) {
				// Assume a typed array:
				TypedArrayContents<uint8_t> TypedArray( info[ i ] );
				arrays[ j ] = *TypedArray;

				types[ j ] = STDLIB_NDARRAY_FLOAT64; // TODO: determine data type (will require determining the typed array "class"; see https://github.com/nodejs/node/blob/v0.10.39-release/src/v8_typed_array.cc#L462)
				strides[ j ] *= 8; // TODO: compute based on data type (or glean directly from typed array instance)
			} else {
				ThrowTypeError( "invalid input argument. Output strided array arguments must be typed arrays." );
				return;
			}
		}

#endif

		// Check if we have been provided only scalar input arguments...
		if ( nin > 0 && nsargs == nin ) {
			ThrowError( "invalid input arguments. Must provide at least one input strided array argument." );
			return;
		}
		// Broadcasting...

		// Create an array having the closest "compatible" type...
		// arrays[ 0 ] = broadcast( static_cast<double>( info[ 1 ]->NumberValue() ), types[ 0 ] );

		// Perform addition:
		stdlib_strided_dd_d( arrays, shape, strides, (void *)add );
	}

	NAN_MODULE_INIT( Init ) {
		Nan::Export( target, "add", node_add );
	}

	NODE_MODULE( addon, Init )
} // end namespace addon_strided_add
<|endoftext|>


<commit_before>
#include "message.h"
#include "serialization.h"

#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include <sys/time.h>

namespace job_stream {
namespace message {

uint64_t Location::getCurrentTimeMs() {
    timeval ts; gettimeofday(&ts, 0);
    return (uint64_t)(ts.tv_sec * 1000 + ts.tv_usec / 1000);
}

WorkRecord::WorkRecord(const std::string& serialized) {
    serialization::decode(serialized, *this);

    //We were received, so...
    this->source.tsReceived = Location::getCurrentTimeMs();
}

WorkRecord::WorkRecord(const std::vector<std::string>& target,
        const std::string& work) : reduceTag(0), reduceHomeRank(0), work(work) {
    this->source.hostname = boost::asio::ip::host_name();
    this->source.target = target;
    this->source.tsSent = Location::getCurrentTimeMs();
}

WorkRecord::WorkRecord(const std::vector<std::string>& target,
        void* work) : reduceTag(0), reduceHomeRank(0) {
    this->source.hostname = boost::asio::ip::host_name();
    this->source.target = target;
    this->source.tsSent = Location::getCurrentTimeMs();
    //work will be set in derived constructor
}

void WorkRecord::chainFrom(const WorkRecord& wr) {
    this->route.insert(this->route.end(), wr.route.begin(), wr.route.end());
    this->route.push_back(wr.source);
    this->reduceHomeRank = wr.reduceHomeRank;
    this->reduceTag = wr.reduceTag;
}

template<typename T>
std::string getAsString(const std::string& payload) {
    T decoded;
    serialization::decode(payload, decoded);
    return boost::lexical_cast<std::string>(decoded);
}

std::string WorkRecord::getWorkAsString() const {
    this->serializeTypedWork();

#define TRY_TYPE(T) \
        try { \
            return getAsString<T>(this->work); \
        } \
        catch (const std::exception& e) { \
            /* Do nothing, conversion failed */ \
        }

    TRY_TYPE(std::string);
    TRY_TYPE(uint64_t);
    TRY_TYPE(int64_t);
    TRY_TYPE(int);
    TRY_TYPE(unsigned short);
    TRY_TYPE(short);
    TRY_TYPE(unsigned char);
    TRY_TYPE(char);
    TRY_TYPE(float);
    TRY_TYPE(double);

    std::ostringstream ss;
    ss << "Unrecognized work type for string output: " << this->work;
    throw std::runtime_error(ss.str());

#undef TRY_TYPE
}

} //message
} //job_stream
<commit_msg>Missed unsigned int!<commit_after>
#include "message.h"
#include "serialization.h"

#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include <sys/time.h>

namespace job_stream {
namespace message {

uint64_t Location::getCurrentTimeMs() {
    timeval ts; gettimeofday(&ts, 0);
    return (uint64_t)(ts.tv_sec * 1000 + ts.tv_usec / 1000);
}

WorkRecord::WorkRecord(const std::string& serialized) {
    serialization::decode(serialized, *this);

    //We were received, so...
    this->source.tsReceived = Location::getCurrentTimeMs();
}

WorkRecord::WorkRecord(const std::vector<std::string>& target,
        const std::string& work) : reduceTag(0), reduceHomeRank(0), work(work) {
    this->source.hostname = boost::asio::ip::host_name();
    this->source.target = target;
    this->source.tsSent = Location::getCurrentTimeMs();
}

WorkRecord::WorkRecord(const std::vector<std::string>& target,
        void* work) : reduceTag(0), reduceHomeRank(0) {
    this->source.hostname = boost::asio::ip::host_name();
    this->source.target = target;
    this->source.tsSent = Location::getCurrentTimeMs();
    //work will be set in derived constructor
}

void WorkRecord::chainFrom(const WorkRecord& wr) {
    this->route.insert(this->route.end(), wr.route.begin(), wr.route.end());
    this->route.push_back(wr.source);
    this->reduceHomeRank = wr.reduceHomeRank;
    this->reduceTag = wr.reduceTag;
}

template<typename T>
std::string getAsString(const std::string& payload) {
    T decoded;
    serialization::decode(payload, decoded);
    return boost::lexical_cast<std::string>(decoded);
}

std::string WorkRecord::getWorkAsString() const {
    this->serializeTypedWork();

#define TRY_TYPE(T) \
        try { \
            return getAsString<T>(this->work); \
        } \
        catch (const std::exception& e) { \
            /* Do nothing, conversion failed */ \
        }

    TRY_TYPE(std::string);
    TRY_TYPE(uint64_t);
    TRY_TYPE(int64_t);
    TRY_TYPE(unsigned int);
    TRY_TYPE(int);
    TRY_TYPE(unsigned short);
    TRY_TYPE(short);
    TRY_TYPE(unsigned char);
    TRY_TYPE(char);
    TRY_TYPE(float);
    TRY_TYPE(double);

    std::ostringstream ss;
    ss << "Unrecognized work type for string output: " << this->work;
    throw std::runtime_error(ss.str());

#undef TRY_TYPE
}

} //message
} //job_stream
<|endoftext|>


<commit_before>//===-- sanitizer_allocator_test.cc ---------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
// Tests for sanitizer_allocator.h.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_common.h"

#include "gtest/gtest.h"

#include <stdlib.h>
#include <algorithm>
#include <vector>

#if SANITIZER_WORDSIZE == 64
static const uptr kAllocatorSpace = 0x700000000000ULL;
static const uptr kAllocatorSize  = 0x010000000000ULL;  // 1T.
static const u64 kAddressSpaceSize = 1ULL << 47;

typedef SizeClassAllocator64<
  kAllocatorSpace, kAllocatorSize, 16, DefaultSizeClassMap> Allocator64;

typedef SizeClassAllocator64<
  kAllocatorSpace, kAllocatorSize, 16, CompactSizeClassMap> Allocator64Compact;
#else
static const u64 kAddressSpaceSize = 1ULL << 32;
#endif

typedef SizeClassAllocator32<
  0, kAddressSpaceSize, 16, CompactSizeClassMap> Allocator32Compact;

template <class SizeClassMap>
void TestSizeClassMap() {
  typedef SizeClassMap SCMap;
#if 0
  for (uptr i = 0; i < SCMap::kNumClasses; i++) {
    printf("c%ld => %ld (%lx) cached=%ld(%ld)\n",
        i, SCMap::Size(i), SCMap::Size(i), SCMap::MaxCached(i) * SCMap::Size(i),
        SCMap::MaxCached(i));
  }
#endif
  for (uptr c = 0; c < SCMap::kNumClasses; c++) {
    uptr s = SCMap::Size(c);
    CHECK_EQ(SCMap::ClassID(s), c);
    if (c != SCMap::kNumClasses - 1)
      CHECK_EQ(SCMap::ClassID(s + 1), c + 1);
    CHECK_EQ(SCMap::ClassID(s - 1), c);
    if (c)
      CHECK_GT(SCMap::Size(c), SCMap::Size(c-1));
  }
  CHECK_EQ(SCMap::ClassID(SCMap::kMaxSize + 1), 0);

  for (uptr s = 1; s <= SCMap::kMaxSize; s++) {
    uptr c = SCMap::ClassID(s);
    CHECK_LT(c, SCMap::kNumClasses);
    CHECK_GE(SCMap::Size(c), s);
    if (c > 0)
      CHECK_LT(SCMap::Size(c-1), s);
  }
}

TEST(SanitizerCommon, DefaultSizeClassMap) {
  TestSizeClassMap<DefaultSizeClassMap>();
}

TEST(SanitizerCommon, CompactSizeClassMap) {
  TestSizeClassMap<CompactSizeClassMap>();
}

template <class Allocator>
void TestSizeClassAllocator() {
  Allocator *a = new Allocator;
  a->Init();

  static const uptr sizes[] = {1, 16, 30, 40, 100, 1000, 10000,
    50000, 60000, 100000, 300000, 500000, 1000000, 2000000};

  std::vector<void *> allocated;

  uptr last_total_allocated = 0;
  for (int i = 0; i < 5; i++) {
    // Allocate a bunch of chunks.
    for (uptr s = 0; s < ARRAY_SIZE(sizes); s++) {
      uptr size = sizes[s];
      if (!a->CanAllocate(size, 1)) continue;
      // printf("s = %ld\n", size);
      uptr n_iter = std::max((uptr)2, 1000000 / size);
      for (uptr i = 0; i < n_iter; i++) {
        void *x = a->Allocate(size, 1);
        allocated.push_back(x);
        CHECK(a->PointerIsMine(x));
        CHECK_GE(a->GetActuallyAllocatedSize(x), size);
        uptr class_id = a->GetSizeClass(x);
        CHECK_EQ(class_id, Allocator::SizeClassMapT::ClassID(size));
        uptr *metadata = reinterpret_cast<uptr*>(a->GetMetaData(x));
        metadata[0] = reinterpret_cast<uptr>(x) + 1;
        metadata[1] = 0xABCD;
      }
    }
    // Deallocate all.
    for (uptr i = 0; i < allocated.size(); i++) {
      void *x = allocated[i];
      uptr *metadata = reinterpret_cast<uptr*>(a->GetMetaData(x));
      CHECK_EQ(metadata[0], reinterpret_cast<uptr>(x) + 1);
      CHECK_EQ(metadata[1], 0xABCD);
      a->Deallocate(x);
    }
    allocated.clear();
    uptr total_allocated = a->TotalMemoryUsed();
    if (last_total_allocated == 0)
      last_total_allocated = total_allocated;
    CHECK_EQ(last_total_allocated, total_allocated);
  }

  a->TestOnlyUnmap();
  delete a;
}

#if SANITIZER_WORDSIZE == 64
TEST(SanitizerCommon, SizeClassAllocator64) {
  TestSizeClassAllocator<Allocator64>();
}

TEST(SanitizerCommon, SizeClassAllocator64Compact) {
  TestSizeClassAllocator<Allocator64Compact>();
}
#endif

TEST(SanitizerCommon, SizeClassAllocator32Compact) {
  TestSizeClassAllocator<Allocator32Compact>();
}

template <class Allocator>
void SizeClassAllocator64MetadataStress() {
  Allocator a;
  a.Init();
  static volatile void *sink;

  const uptr kNumAllocs = 10000;
  void *allocated[kNumAllocs];
  for (uptr i = 0; i < kNumAllocs; i++) {
    uptr size = (i % 4096) + 1;
    void *x = a.Allocate(size, 1);
    allocated[i] = x;
  }
  // Get Metadata kNumAllocs^2 times.
  for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) {
    sink = a.GetMetaData(allocated[i % kNumAllocs]);
  }
  for (uptr i = 0; i < kNumAllocs; i++) {
    a.Deallocate(allocated[i]);
  }

  a.TestOnlyUnmap();
  (void)sink;
}

#if SANITIZER_WORDSIZE == 64
TEST(SanitizerCommon, SizeClassAllocator64MetadataStress) {
  SizeClassAllocator64MetadataStress<Allocator64>();
}

TEST(SanitizerCommon, SizeClassAllocator64CompactMetadataStress) {
  SizeClassAllocator64MetadataStress<Allocator64Compact>();
}
#endif

template<class Allocator>
void FailInAssertionOnOOM() {
  Allocator a;
  a.Init();
  const uptr size = 1 << 20;
  for (int i = 0; i < 1000000; i++) {
    a.Allocate(size, 1);
  }

  a.TestOnlyUnmap();
}

#if SANITIZER_WORDSIZE == 64
TEST(SanitizerCommon, SizeClassAllocator64Overflow) {
  EXPECT_DEATH(FailInAssertionOnOOM<Allocator64>(), "Out of memory");
}
#endif

TEST(SanitizerCommon, LargeMmapAllocator) {
  LargeMmapAllocator a;
  a.Init();

  static const int kNumAllocs = 100;
  void *allocated[kNumAllocs];
  static const uptr size = 1000;
  // Allocate some.
  for (int i = 0; i < kNumAllocs; i++) {
    allocated[i] = a.Allocate(size, 1);
  }
  // Deallocate all.
  CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs);
  for (int i = 0; i < kNumAllocs; i++) {
    void *p = allocated[i];
    CHECK(a.PointerIsMine(p));
    a.Deallocate(p);
  }
  // Check that non left.
  CHECK_EQ(a.TotalMemoryUsed(), 0);

  // Allocate some more, also add metadata.
  for (int i = 0; i < kNumAllocs; i++) {
    void *x = a.Allocate(size, 1);
    CHECK_GE(a.GetActuallyAllocatedSize(x), size);
    uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
    *meta = i;
    allocated[i] = x;
  }
  CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs);
  // Deallocate all in reverse order.
  for (int i = 0; i < kNumAllocs; i++) {
    int idx = kNumAllocs - i - 1;
    void *p = allocated[idx];
    uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(p));
    CHECK_EQ(*meta, idx);
    CHECK(a.PointerIsMine(p));
    a.Deallocate(p);
  }
  CHECK_EQ(a.TotalMemoryUsed(), 0);
  uptr max_alignment = SANITIZER_WORDSIZE == 64 ? (1 << 28) : (1 << 24);
  for (uptr alignment = 8; alignment <= max_alignment; alignment *= 2) {
    for (int i = 0; i < kNumAllocs; i++) {
      uptr size = ((i % 10) + 1) * 4096;
      allocated[i] = a.Allocate(size, alignment);
      CHECK_EQ(0, (uptr)allocated[i] % alignment);
      char *p = (char*)allocated[i];
      p[0] = p[size - 1] = 0;
    }
    for (int i = 0; i < kNumAllocs; i++) {
      a.Deallocate(allocated[i]);
    }
  }
}

template
<class PrimaryAllocator, class SecondaryAllocator, class AllocatorCache>
void TestCombinedAllocator() {
  CombinedAllocator<PrimaryAllocator, AllocatorCache, SecondaryAllocator> a;
  a.Init();

  AllocatorCache cache;
  cache.Init();

  EXPECT_EQ(a.Allocate(&cache, -1, 1), (void*)0);
  EXPECT_EQ(a.Allocate(&cache, -1, 1024), (void*)0);
  EXPECT_EQ(a.Allocate(&cache, (uptr)-1 - 1024, 1), (void*)0);
  EXPECT_EQ(a.Allocate(&cache, (uptr)-1 - 1024, 1024), (void*)0);
  EXPECT_EQ(a.Allocate(&cache, (uptr)-1 - 1023, 1024), (void*)0);

  const uptr kNumAllocs = 100000;
  const uptr kNumIter = 10;
  for (uptr iter = 0; iter < kNumIter; iter++) {
    std::vector<void*> allocated;
    for (uptr i = 0; i < kNumAllocs; i++) {
      uptr size = (i % (1 << 14)) + 1;
      if ((i % 1024) == 0)
        size = 1 << (10 + (i % 14));
      void *x = a.Allocate(&cache, size, 1);
      uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
      CHECK_EQ(*meta, 0);
      *meta = size;
      allocated.push_back(x);
    }

    random_shuffle(allocated.begin(), allocated.end());

    for (uptr i = 0; i < kNumAllocs; i++) {
      void *x = allocated[i];
      uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
      CHECK_NE(*meta, 0);
      CHECK(a.PointerIsMine(x));
      *meta = 0;
      a.Deallocate(&cache, x);
    }
    allocated.clear();
    a.SwallowCache(&cache);
  }
  a.TestOnlyUnmap();
}

#if SANITIZER_WORDSIZE == 64
TEST(SanitizerCommon, CombinedAllocator) {
  TestCombinedAllocator<Allocator64,
      LargeMmapAllocator,
      SizeClassAllocatorLocalCache<Allocator64> > ();
}
#endif

template <class AllocatorCache>
void TestSizeClassAllocatorLocalCache() {
  static THREADLOCAL AllocatorCache static_allocator_cache;
  static_allocator_cache.Init();
  AllocatorCache cache;
  typename AllocatorCache::Allocator a;

  a.Init();
  cache.Init();

  const uptr kNumAllocs = 10000;
  const int kNumIter = 100;
  uptr saved_total = 0;
  for (int i = 0; i < kNumIter; i++) {
    void *allocated[kNumAllocs];
    for (uptr i = 0; i < kNumAllocs; i++) {
      allocated[i] = cache.Allocate(&a, 0);
    }
    for (uptr i = 0; i < kNumAllocs; i++) {
      cache.Deallocate(&a, 0, allocated[i]);
    }
    cache.Drain(&a);
    uptr total_allocated = a.TotalMemoryUsed();
    if (saved_total)
      CHECK_EQ(saved_total, total_allocated);
    saved_total = total_allocated;
  }

  a.TestOnlyUnmap();
}

#if SANITIZER_WORDSIZE == 64
TEST(SanitizerCommon, SizeClassAllocator64LocalCache) {
  TestSizeClassAllocatorLocalCache<
      SizeClassAllocatorLocalCache<Allocator64> >();
}
#endif

TEST(Allocator, Basic) {
  char *p = (char*)InternalAlloc(10);
  EXPECT_NE(p, (char*)0);
  char *p2 = (char*)InternalAlloc(20);
  EXPECT_NE(p2, (char*)0);
  EXPECT_NE(p2, p);
  InternalFree(p);
  InternalFree(p2);
}

TEST(Allocator, Stress) {
  const int kCount = 1000;
  char *ptrs[kCount];
  unsigned rnd = 42;
  for (int i = 0; i < kCount; i++) {
    uptr sz = rand_r(&rnd) % 1000;
    char *p = (char*)InternalAlloc(sz);
    EXPECT_NE(p, (char*)0);
    ptrs[i] = p;
  }
  for (int i = 0; i < kCount; i++) {
    InternalFree(ptrs[i]);
  }
}

TEST(Allocator, ScopedBuffer) {
  const int kSize = 512;
  {
    InternalScopedBuffer<int> int_buf(kSize);
    EXPECT_EQ(sizeof(int) * kSize, int_buf.size());  // NOLINT
  }
  InternalScopedBuffer<char> char_buf(kSize);
  EXPECT_EQ(sizeof(char) * kSize, char_buf.size());  // NOLINT
  memset(char_buf.data(), 'c', kSize);
  for (int i = 0; i < kSize; i++) {
    EXPECT_EQ('c', char_buf[i]);
  }
}
<commit_msg>[asan/msan] one more test for 32-bit allocator<commit_after>//===-- sanitizer_allocator_test.cc ---------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
// Tests for sanitizer_allocator.h.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_common.h"

#include "gtest/gtest.h"

#include <stdlib.h>
#include <algorithm>
#include <vector>

#if SANITIZER_WORDSIZE == 64
static const uptr kAllocatorSpace = 0x700000000000ULL;
static const uptr kAllocatorSize  = 0x010000000000ULL;  // 1T.
static const u64 kAddressSpaceSize = 1ULL << 47;

typedef SizeClassAllocator64<
  kAllocatorSpace, kAllocatorSize, 16, DefaultSizeClassMap> Allocator64;

typedef SizeClassAllocator64<
  kAllocatorSpace, kAllocatorSize, 16, CompactSizeClassMap> Allocator64Compact;
#else
static const u64 kAddressSpaceSize = 1ULL << 32;
#endif

typedef SizeClassAllocator32<
  0, kAddressSpaceSize, 16, CompactSizeClassMap> Allocator32Compact;

template <class SizeClassMap>
void TestSizeClassMap() {
  typedef SizeClassMap SCMap;
#if 0
  for (uptr i = 0; i < SCMap::kNumClasses; i++) {
    printf("c%ld => %ld (%lx) cached=%ld(%ld)\n",
        i, SCMap::Size(i), SCMap::Size(i), SCMap::MaxCached(i) * SCMap::Size(i),
        SCMap::MaxCached(i));
  }
#endif
  for (uptr c = 0; c < SCMap::kNumClasses; c++) {
    uptr s = SCMap::Size(c);
    CHECK_EQ(SCMap::ClassID(s), c);
    if (c != SCMap::kNumClasses - 1)
      CHECK_EQ(SCMap::ClassID(s + 1), c + 1);
    CHECK_EQ(SCMap::ClassID(s - 1), c);
    if (c)
      CHECK_GT(SCMap::Size(c), SCMap::Size(c-1));
  }
  CHECK_EQ(SCMap::ClassID(SCMap::kMaxSize + 1), 0);

  for (uptr s = 1; s <= SCMap::kMaxSize; s++) {
    uptr c = SCMap::ClassID(s);
    CHECK_LT(c, SCMap::kNumClasses);
    CHECK_GE(SCMap::Size(c), s);
    if (c > 0)
      CHECK_LT(SCMap::Size(c-1), s);
  }
}

TEST(SanitizerCommon, DefaultSizeClassMap) {
  TestSizeClassMap<DefaultSizeClassMap>();
}

TEST(SanitizerCommon, CompactSizeClassMap) {
  TestSizeClassMap<CompactSizeClassMap>();
}

template <class Allocator>
void TestSizeClassAllocator() {
  Allocator *a = new Allocator;
  a->Init();

  static const uptr sizes[] = {1, 16, 30, 40, 100, 1000, 10000,
    50000, 60000, 100000, 300000, 500000, 1000000, 2000000};

  std::vector<void *> allocated;

  uptr last_total_allocated = 0;
  for (int i = 0; i < 5; i++) {
    // Allocate a bunch of chunks.
    for (uptr s = 0; s < ARRAY_SIZE(sizes); s++) {
      uptr size = sizes[s];
      if (!a->CanAllocate(size, 1)) continue;
      // printf("s = %ld\n", size);
      uptr n_iter = std::max((uptr)2, 1000000 / size);
      for (uptr i = 0; i < n_iter; i++) {
        void *x = a->Allocate(size, 1);
        allocated.push_back(x);
        CHECK(a->PointerIsMine(x));
        CHECK_GE(a->GetActuallyAllocatedSize(x), size);
        uptr class_id = a->GetSizeClass(x);
        CHECK_EQ(class_id, Allocator::SizeClassMapT::ClassID(size));
        uptr *metadata = reinterpret_cast<uptr*>(a->GetMetaData(x));
        metadata[0] = reinterpret_cast<uptr>(x) + 1;
        metadata[1] = 0xABCD;
      }
    }
    // Deallocate all.
    for (uptr i = 0; i < allocated.size(); i++) {
      void *x = allocated[i];
      uptr *metadata = reinterpret_cast<uptr*>(a->GetMetaData(x));
      CHECK_EQ(metadata[0], reinterpret_cast<uptr>(x) + 1);
      CHECK_EQ(metadata[1], 0xABCD);
      a->Deallocate(x);
    }
    allocated.clear();
    uptr total_allocated = a->TotalMemoryUsed();
    if (last_total_allocated == 0)
      last_total_allocated = total_allocated;
    CHECK_EQ(last_total_allocated, total_allocated);
  }

  a->TestOnlyUnmap();
  delete a;
}

#if SANITIZER_WORDSIZE == 64
TEST(SanitizerCommon, SizeClassAllocator64) {
  TestSizeClassAllocator<Allocator64>();
}

TEST(SanitizerCommon, SizeClassAllocator64Compact) {
  TestSizeClassAllocator<Allocator64Compact>();
}
#endif

TEST(SanitizerCommon, SizeClassAllocator32Compact) {
  TestSizeClassAllocator<Allocator32Compact>();
}

template <class Allocator>
void SizeClassAllocatorMetadataStress() {
  Allocator *a = new Allocator;
  a->Init();
  static volatile void *sink;

  const uptr kNumAllocs = 10000;
  void *allocated[kNumAllocs];
  for (uptr i = 0; i < kNumAllocs; i++) {
    uptr size = (i % 4096) + 1;
    void *x = a->Allocate(size, 1);
    allocated[i] = x;
  }
  // Get Metadata kNumAllocs^2 times.
  for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) {
    sink = a->GetMetaData(allocated[i % kNumAllocs]);
  }
  for (uptr i = 0; i < kNumAllocs; i++) {
    a->Deallocate(allocated[i]);
  }

  a->TestOnlyUnmap();
  (void)sink;
  delete a;
}

#if SANITIZER_WORDSIZE == 64
TEST(SanitizerCommon, SizeClassAllocator64MetadataStress) {
  SizeClassAllocatorMetadataStress<Allocator64>();
}

TEST(SanitizerCommon, SizeClassAllocator64CompactMetadataStress) {
  SizeClassAllocatorMetadataStress<Allocator64Compact>();
}
#endif
TEST(SanitizerCommon, SizeClassAllocator32CompactMetadataStress) {
  SizeClassAllocatorMetadataStress<Allocator32Compact>();
}

template<class Allocator>
void FailInAssertionOnOOM() {
  Allocator a;
  a.Init();
  const uptr size = 1 << 20;
  for (int i = 0; i < 1000000; i++) {
    a.Allocate(size, 1);
  }

  a.TestOnlyUnmap();
}

#if SANITIZER_WORDSIZE == 64
TEST(SanitizerCommon, SizeClassAllocator64Overflow) {
  EXPECT_DEATH(FailInAssertionOnOOM<Allocator64>(), "Out of memory");
}
#endif

TEST(SanitizerCommon, LargeMmapAllocator) {
  LargeMmapAllocator a;
  a.Init();

  static const int kNumAllocs = 100;
  void *allocated[kNumAllocs];
  static const uptr size = 1000;
  // Allocate some.
  for (int i = 0; i < kNumAllocs; i++) {
    allocated[i] = a.Allocate(size, 1);
  }
  // Deallocate all.
  CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs);
  for (int i = 0; i < kNumAllocs; i++) {
    void *p = allocated[i];
    CHECK(a.PointerIsMine(p));
    a.Deallocate(p);
  }
  // Check that non left.
  CHECK_EQ(a.TotalMemoryUsed(), 0);

  // Allocate some more, also add metadata.
  for (int i = 0; i < kNumAllocs; i++) {
    void *x = a.Allocate(size, 1);
    CHECK_GE(a.GetActuallyAllocatedSize(x), size);
    uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
    *meta = i;
    allocated[i] = x;
  }
  CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs);
  // Deallocate all in reverse order.
  for (int i = 0; i < kNumAllocs; i++) {
    int idx = kNumAllocs - i - 1;
    void *p = allocated[idx];
    uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(p));
    CHECK_EQ(*meta, idx);
    CHECK(a.PointerIsMine(p));
    a.Deallocate(p);
  }
  CHECK_EQ(a.TotalMemoryUsed(), 0);
  uptr max_alignment = SANITIZER_WORDSIZE == 64 ? (1 << 28) : (1 << 24);
  for (uptr alignment = 8; alignment <= max_alignment; alignment *= 2) {
    for (int i = 0; i < kNumAllocs; i++) {
      uptr size = ((i % 10) + 1) * 4096;
      allocated[i] = a.Allocate(size, alignment);
      CHECK_EQ(0, (uptr)allocated[i] % alignment);
      char *p = (char*)allocated[i];
      p[0] = p[size - 1] = 0;
    }
    for (int i = 0; i < kNumAllocs; i++) {
      a.Deallocate(allocated[i]);
    }
  }
}

template
<class PrimaryAllocator, class SecondaryAllocator, class AllocatorCache>
void TestCombinedAllocator() {
  CombinedAllocator<PrimaryAllocator, AllocatorCache, SecondaryAllocator> a;
  a.Init();

  AllocatorCache cache;
  cache.Init();

  EXPECT_EQ(a.Allocate(&cache, -1, 1), (void*)0);
  EXPECT_EQ(a.Allocate(&cache, -1, 1024), (void*)0);
  EXPECT_EQ(a.Allocate(&cache, (uptr)-1 - 1024, 1), (void*)0);
  EXPECT_EQ(a.Allocate(&cache, (uptr)-1 - 1024, 1024), (void*)0);
  EXPECT_EQ(a.Allocate(&cache, (uptr)-1 - 1023, 1024), (void*)0);

  const uptr kNumAllocs = 100000;
  const uptr kNumIter = 10;
  for (uptr iter = 0; iter < kNumIter; iter++) {
    std::vector<void*> allocated;
    for (uptr i = 0; i < kNumAllocs; i++) {
      uptr size = (i % (1 << 14)) + 1;
      if ((i % 1024) == 0)
        size = 1 << (10 + (i % 14));
      void *x = a.Allocate(&cache, size, 1);
      uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
      CHECK_EQ(*meta, 0);
      *meta = size;
      allocated.push_back(x);
    }

    random_shuffle(allocated.begin(), allocated.end());

    for (uptr i = 0; i < kNumAllocs; i++) {
      void *x = allocated[i];
      uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x));
      CHECK_NE(*meta, 0);
      CHECK(a.PointerIsMine(x));
      *meta = 0;
      a.Deallocate(&cache, x);
    }
    allocated.clear();
    a.SwallowCache(&cache);
  }
  a.TestOnlyUnmap();
}

#if SANITIZER_WORDSIZE == 64
TEST(SanitizerCommon, CombinedAllocator) {
  TestCombinedAllocator<Allocator64,
      LargeMmapAllocator,
      SizeClassAllocatorLocalCache<Allocator64> > ();
}
#endif

template <class AllocatorCache>
void TestSizeClassAllocatorLocalCache() {
  static THREADLOCAL AllocatorCache static_allocator_cache;
  static_allocator_cache.Init();
  AllocatorCache cache;
  typename AllocatorCache::Allocator a;

  a.Init();
  cache.Init();

  const uptr kNumAllocs = 10000;
  const int kNumIter = 100;
  uptr saved_total = 0;
  for (int i = 0; i < kNumIter; i++) {
    void *allocated[kNumAllocs];
    for (uptr i = 0; i < kNumAllocs; i++) {
      allocated[i] = cache.Allocate(&a, 0);
    }
    for (uptr i = 0; i < kNumAllocs; i++) {
      cache.Deallocate(&a, 0, allocated[i]);
    }
    cache.Drain(&a);
    uptr total_allocated = a.TotalMemoryUsed();
    if (saved_total)
      CHECK_EQ(saved_total, total_allocated);
    saved_total = total_allocated;
  }

  a.TestOnlyUnmap();
}

#if SANITIZER_WORDSIZE == 64
TEST(SanitizerCommon, SizeClassAllocator64LocalCache) {
  TestSizeClassAllocatorLocalCache<
      SizeClassAllocatorLocalCache<Allocator64> >();
}
#endif

TEST(Allocator, Basic) {
  char *p = (char*)InternalAlloc(10);
  EXPECT_NE(p, (char*)0);
  char *p2 = (char*)InternalAlloc(20);
  EXPECT_NE(p2, (char*)0);
  EXPECT_NE(p2, p);
  InternalFree(p);
  InternalFree(p2);
}

TEST(Allocator, Stress) {
  const int kCount = 1000;
  char *ptrs[kCount];
  unsigned rnd = 42;
  for (int i = 0; i < kCount; i++) {
    uptr sz = rand_r(&rnd) % 1000;
    char *p = (char*)InternalAlloc(sz);
    EXPECT_NE(p, (char*)0);
    ptrs[i] = p;
  }
  for (int i = 0; i < kCount; i++) {
    InternalFree(ptrs[i]);
  }
}

TEST(Allocator, ScopedBuffer) {
  const int kSize = 512;
  {
    InternalScopedBuffer<int> int_buf(kSize);
    EXPECT_EQ(sizeof(int) * kSize, int_buf.size());  // NOLINT
  }
  InternalScopedBuffer<char> char_buf(kSize);
  EXPECT_EQ(sizeof(char) * kSize, char_buf.size());  // NOLINT
  memset(char_buf.data(), 'c', kSize);
  for (int i = 0; i < kSize; i++) {
    EXPECT_EQ('c', char_buf[i]);
  }
}
<|endoftext|>


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

#include "IECore/CompoundData.h"
#include "IECore/TypedData.inl"

#include <iostream>
using namespace std;
using namespace IECore;

namespace IECore
{

IECORE_RUNTIMETYPED_DEFINETEMPLATESPECIALISATION( CompoundData, CompoundDataTypeId, Data );

template<>
void CompoundData::memoryUsage( Object::MemoryAccumulator &accumulator ) const
{
	Data::memoryUsage( accumulator );
	const CompoundDataMap &data = readable();
	CompoundDataMap::const_iterator iter = data.begin();
	while (iter != data.end())
	{
		accumulator.accumulate( iter->second );
		iter++;
	}
}

template<>
void CompoundData::copyFrom( ConstObjectPtr other, CopyContext *context )
{
	Data::copyFrom( other, context );
	const CompoundData *tOther = static_cast<const CompoundData *>( other.get() );
	CompoundDataMap &data = writable();
	data.clear();
	const CompoundDataMap &otherData = tOther->readable();
	for( CompoundDataMap::const_iterator it = otherData.begin(); it!=otherData.end(); it++ )
	{
		data[it->first] = context->copy<Data>( it->second );
	}
}

template<>
bool CompoundData::isEqualTo( ConstObjectPtr other ) const
{
	if( !Data::isEqualTo( other ) )
	{
		return false;
	}
	ConstCompoundDataPtr tOther = boost::static_pointer_cast<const CompoundData>( other );
	const CompoundDataMap &m1 = readable();
	const CompoundDataMap &m2 = tOther->readable();
	if( m1.size()!=m2.size() )
	{
		return false;
	}
	CompoundDataMap::const_iterator it1 = m1.begin();
	CompoundDataMap::const_iterator it2 = m2.begin();
	while( it1!=m1.end() )
	{
		if( it1->first!=it2->first )
		{
			return false;
		}
		if( ! it1->second->isEqualTo( it2->second ) )
		{
			return false;
		}
		it1++;
		it2++;
	}
	return true;
}

template<>
void CompoundData::save( SaveContext *context ) const
{
	Data::save( context );
	IndexedIOInterfacePtr container = context->container( staticTypeName(), 0 );
	container->mkdir( "members" );
	container->chdir( "members" );
		const CompoundDataMap &m = readable();
		CompoundDataMap::const_iterator it;
		for( it=m.begin(); it!=m.end(); it++ )
		{
			context->save( it->second, container, it->first );
		}
	container->chdir( ".." );
}

template<>
void CompoundData::load( LoadContextPtr context )
{
	Data::load( context );
	unsigned int v = 0;
	IndexedIOInterfacePtr container = context->container( staticTypeName(), v );
	CompoundDataMap &m = writable();
	m.clear();
	container->chdir( "members" );
		IndexedIO::EntryList members = container->ls();
		IndexedIO::EntryList::const_iterator it;
		for( it=members.begin(); it!=members.end(); it++ )
		{
			m[it->id()] = context->load<Data>( container, it->id() );
		}
	container->chdir( ".." );
}

IE_CORE_DEFINETYPEDDATANOBASESIZE( CompoundData )

}

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

#include "IECore/CompoundData.h"
#include "IECore/TypedData.inl"

#include <iostream>
using namespace std;
using namespace IECore;

namespace IECore
{

IECORE_RUNTIMETYPED_DEFINETEMPLATESPECIALISATION( CompoundData, CompoundDataTypeId, Data );

template<>
void CompoundData::memoryUsage( Object::MemoryAccumulator &accumulator ) const
{
	Data::memoryUsage( accumulator );
	const CompoundDataMap &data = readable();
	CompoundDataMap::const_iterator iter = data.begin();
	while (iter != data.end())
	{
		/// \todo Accumulate size of keys, too (iter->first), as this
		/// can be significant
		accumulator.accumulate( iter->second );
		iter++;
	}
}

template<>
void CompoundData::copyFrom( ConstObjectPtr other, CopyContext *context )
{
	Data::copyFrom( other, context );
	const CompoundData *tOther = static_cast<const CompoundData *>( other.get() );
	CompoundDataMap &data = writable();
	data.clear();
	const CompoundDataMap &otherData = tOther->readable();
	for( CompoundDataMap::const_iterator it = otherData.begin(); it!=otherData.end(); it++ )
	{
		data[it->first] = context->copy<Data>( it->second );
	}
}

template<>
bool CompoundData::isEqualTo( ConstObjectPtr other ) const
{
	if( !Data::isEqualTo( other ) )
	{
		return false;
	}
	ConstCompoundDataPtr tOther = boost::static_pointer_cast<const CompoundData>( other );
	const CompoundDataMap &m1 = readable();
	const CompoundDataMap &m2 = tOther->readable();
	if( m1.size()!=m2.size() )
	{
		return false;
	}
	CompoundDataMap::const_iterator it1 = m1.begin();
	CompoundDataMap::const_iterator it2 = m2.begin();
	while( it1!=m1.end() )
	{
		if( it1->first!=it2->first )
		{
			return false;
		}
		if( ! it1->second->isEqualTo( it2->second ) )
		{
			return false;
		}
		it1++;
		it2++;
	}
	return true;
}

template<>
void CompoundData::save( SaveContext *context ) const
{
	Data::save( context );
	IndexedIOInterfacePtr container = context->container( staticTypeName(), 0 );
	container->mkdir( "members" );
	container->chdir( "members" );
		const CompoundDataMap &m = readable();
		CompoundDataMap::const_iterator it;
		for( it=m.begin(); it!=m.end(); it++ )
		{
			context->save( it->second, container, it->first );
		}
	container->chdir( ".." );
}

template<>
void CompoundData::load( LoadContextPtr context )
{
	Data::load( context );
	unsigned int v = 0;
	IndexedIOInterfacePtr container = context->container( staticTypeName(), v );
	CompoundDataMap &m = writable();
	m.clear();
	container->chdir( "members" );
		IndexedIO::EntryList members = container->ls();
		IndexedIO::EntryList::const_iterator it;
		for( it=members.begin(); it!=members.end(); it++ )
		{
			m[it->id()] = context->load<Data>( container, it->id() );
		}
	container->chdir( ".." );
}

IE_CORE_DEFINETYPEDDATANOBASESIZE( CompoundData )

}

// Instantiate that bad boy.
template class TypedData<CompoundDataMap>;
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/gtk/bookmark_utils_gtk.h"

#include "app/gtk_dnd_util.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/gfx/gtk_util.h"
#include "base/pickle.h"
#include "base/string_util.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/profile.h"
#include "chrome/common/gtk_util.h"

namespace {

// Used in gtk_selection_data_set(). (I assume from this parameter that gtk has
// to some really exotic hardware...)
const int kBitsInAByte = 8;

// Maximum number of characters on a bookmark button.
const size_t kMaxCharsOnAButton = 15;

// Max size of each component of the button tooltips.
const size_t kMaxTooltipTitleLength = 100;
const size_t kMaxTooltipURLLength = 400;

// Only used for the background of the drag widget.
const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xe6, 0xed, 0xf4);

// Padding between the chrome button highlight border and the contents (favicon,
// text).
// TODO(estade): we need to adjust the top and bottom padding, but first we need
// to give the bookmark bar more space (at the expense of the toolbar).
const int kButtonPaddingTop = 0;
const int kButtonPaddingBottom = 0;
const int kButtonPaddingLeft = 2;
const int kButtonPaddingRight = 0;

void* AsVoid(const BookmarkNode* node) {
  return const_cast<BookmarkNode*>(node);
}

}  // namespace

namespace bookmark_utils {

const char kBookmarkNode[] = "bookmark-node";

// Spacing between the buttons on the bar.
const int kBarButtonPadding = 4;

GdkPixbuf* GetPixbufForNode(const BookmarkNode* node, BookmarkModel* model,
                            bool native) {
  GdkPixbuf* pixbuf;

  if (node->is_url()) {
    if (model->GetFavIcon(node).width() != 0) {
      pixbuf = gfx::GdkPixbufFromSkBitmap(&model->GetFavIcon(node));
    } else {
      pixbuf = GtkThemeProvider::GetDefaultFavicon(native);
      g_object_ref(pixbuf);
    }
  } else {
    pixbuf = GtkThemeProvider::GetFolderIcon(native);
    g_object_ref(pixbuf);
  }

  return pixbuf;
}

GtkWidget* GetDragRepresentation(const BookmarkNode* node,
                                 BookmarkModel* model,
                                 GtkThemeProvider* provider) {
  // Build a windowed representation for our button.
  GtkWidget* window = gtk_window_new(GTK_WINDOW_POPUP);
  if (!provider->UseGtkTheme()) {
    // TODO(erg): Theme wise, which color should I be picking here?
    // COLOR_BUTTON_BACKGROUND doesn't match the default theme!
    gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &kBackgroundColor);
  }
  gtk_widget_realize(window);

  GtkWidget* frame = gtk_frame_new(NULL);
  gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
  gtk_container_add(GTK_CONTAINER(window), frame);
  gtk_widget_show(frame);

  GtkWidget* floating_button = provider->BuildChromeButton();
  bookmark_utils::ConfigureButtonForNode(node, model, floating_button,
                                         provider);
  gtk_container_add(GTK_CONTAINER(frame), floating_button);
  gtk_widget_show(floating_button);

  return window;
}

void ConfigureButtonForNode(const BookmarkNode* node, BookmarkModel* model,
                            GtkWidget* button, GtkThemeProvider* provider) {
  GtkWidget* former_child = gtk_bin_get_child(GTK_BIN(button));
  if (former_child)
    gtk_container_remove(GTK_CONTAINER(button), former_child);

  std::string tooltip = BuildTooltipFor(node);
  if (!tooltip.empty())
    gtk_widget_set_tooltip_markup(button, tooltip.c_str());

  // We pack the button manually (rather than using gtk_button_set_*) so that
  // we can have finer control over its label.
  GdkPixbuf* pixbuf = bookmark_utils::GetPixbufForNode(node, model,
                                                       provider->UseGtkTheme());
  GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf);
  g_object_unref(pixbuf);

  GtkWidget* box = gtk_hbox_new(FALSE, kBarButtonPadding);
  gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0);

  std::string label_string = WideToUTF8(node->GetTitle());
  if (!label_string.empty()) {
    GtkWidget* label = gtk_label_new(label_string.c_str());
    gtk_label_set_max_width_chars(GTK_LABEL(label), kMaxCharsOnAButton);
    gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
    gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
    SetButtonTextColors(label, provider);
  }

  GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
  // If we are not showing the label, don't set any padding, so that the icon
  // will just be centered.
  if (label_string.c_str()) {
    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
        kButtonPaddingTop, kButtonPaddingBottom,
        kButtonPaddingLeft, kButtonPaddingRight);
  }
  gtk_container_add(GTK_CONTAINER(alignment), box);
  gtk_container_add(GTK_CONTAINER(button), alignment);

  g_object_set_data(G_OBJECT(button), bookmark_utils::kBookmarkNode,
                    AsVoid(node));

  gtk_widget_show_all(alignment);
}

std::string BuildTooltipFor(const BookmarkNode* node) {
  const std::string& url = node->GetURL().possibly_invalid_spec();
  const std::string& title = WideToUTF8(node->GetTitle());

  std::string truncated_url = WideToUTF8(l10n_util::TruncateString(
      UTF8ToWide(url), kMaxTooltipURLLength));
  gchar* escaped_url_cstr = g_markup_escape_text(truncated_url.c_str(),
                                                 truncated_url.size());
  std::string escaped_url(escaped_url_cstr);
  g_free(escaped_url_cstr);

  std::string tooltip;
  if (url == title || title.empty()) {
    return escaped_url;
  } else {
    std::string truncated_title = WideToUTF8(l10n_util::TruncateString(
      node->GetTitle(), kMaxTooltipTitleLength));
    gchar* escaped_title_cstr = g_markup_escape_text(truncated_title.c_str(),
                                                     truncated_title.size());
    std::string escaped_title(escaped_title_cstr);
    g_free(escaped_title_cstr);

    if (!escaped_url.empty())
      return std::string("") + escaped_title + "\n" + escaped_url;
    else
      return std::string("") + escaped_title + "";
  }
}

const BookmarkNode* BookmarkNodeForWidget(GtkWidget* widget) {
  return reinterpret_cast<const BookmarkNode*>(
      g_object_get_data(G_OBJECT(widget), bookmark_utils::kBookmarkNode));
}

void SetButtonTextColors(GtkWidget* label, GtkThemeProvider* provider) {
  if (provider->UseGtkTheme()) {
    gtk_util::SetLabelColor(label, NULL);
  } else {
    GdkColor color = provider->GetGdkColor(
        BrowserThemeProvider::COLOR_BOOKMARK_TEXT);
    gtk_util::SetLabelColor(label, &color);
  }
}

// DnD-related -----------------------------------------------------------------

void WriteBookmarkToSelection(const BookmarkNode* node,
                              GtkSelectionData* selection_data,
                              guint target_type,
                              Profile* profile) {
  DCHECK(node);
  std::vector<const BookmarkNode*> nodes;
  nodes.push_back(node);
  WriteBookmarksToSelection(nodes, selection_data, target_type, profile);
}

void WriteBookmarksToSelection(const std::vector<const BookmarkNode*>& nodes,
                               GtkSelectionData* selection_data,
                               guint target_type,
                               Profile* profile) {
  switch (target_type) {
    case GtkDndUtil::CHROME_BOOKMARK_ITEM: {
      BookmarkDragData data(nodes);
      Pickle pickle;
      data.WriteToPickle(profile, &pickle);

      gtk_selection_data_set(selection_data, selection_data->target,
                             kBitsInAByte,
                             static_cast<const guchar*>(pickle.data()),
                             pickle.size());
      break;
    }
    case GtkDndUtil::TEXT_URI_LIST: {
      gchar** uris = reinterpret_cast<gchar**>(malloc(sizeof(gchar*) *
                                               (nodes.size() + 1)));
      for (size_t i = 0; i < nodes.size(); ++i) {
        // If the node is a folder, this will be empty. TODO(estade): figure out
        // if there are any ramifications to passing an empty URI. After a
        // little testing, it seems fine.
        const GURL& url = nodes[i]->GetURL();
        // This const cast should be safe as gtk_selection_data_set_uris()
        // makes copies.
        uris[i] = const_cast<gchar*>(url.spec().c_str());
      }
      uris[nodes.size()] = NULL;

      gtk_selection_data_set_uris(selection_data, uris);
      free(uris);
      break;
    }
    default: {
      DLOG(ERROR) << "Unsupported drag get type!";
    }
  }
}

std::vector<const BookmarkNode*> GetNodesFromSelection(
    GdkDragContext* context,
    GtkSelectionData* selection_data,
    guint target_type,
    Profile* profile,
    gboolean* delete_selection_data,
    gboolean* dnd_success) {
  *delete_selection_data = FALSE;
  *dnd_success = FALSE;

  if ((selection_data != NULL) && (selection_data->length >= 0)) {
    if (context->action == GDK_ACTION_MOVE) {
      *delete_selection_data = TRUE;
    }

    switch (target_type) {
      case GtkDndUtil::CHROME_BOOKMARK_ITEM: {
        *dnd_success = TRUE;
        Pickle pickle(reinterpret_cast<char*>(selection_data->data),
                      selection_data->length);
        BookmarkDragData drag_data;
        drag_data.ReadFromPickle(&pickle);
        return drag_data.GetNodes(profile);
      }
      default: {
        DLOG(ERROR) << "Unsupported drag received type: " << target_type;
      }
    }
  }

  return std::vector<const BookmarkNode*>();
}

bool CreateNewBookmarkFromNamedUrl(GtkSelectionData* selection_data,
    BookmarkModel* model, const BookmarkNode* parent, int idx) {
  GURL url;
  string16 title;
  if (!GtkDndUtil::ExtractNamedURL(selection_data, &url, &title))
    return false;

  model->AddURL(parent, idx, UTF16ToWideHack(title), url);
  return true;
}

bool CreateNewBookmarksFromURIList(GtkSelectionData* selection_data,
    BookmarkModel* model, const BookmarkNode* parent, int idx) {
  std::vector<GURL> urls;
  GtkDndUtil::ExtractURIList(selection_data, &urls);
  for (size_t i = 0; i < urls.size(); ++i) {
    std::string title = GetNameForURL(urls[i]);
    model->AddURL(parent, idx++, UTF8ToWide(title), urls[i]);
  }
  return true;
}

}  // namespace bookmark_utils
<commit_msg>GTK: Don't ellipsize the Other Bookmarks button.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/gtk/bookmark_utils_gtk.h"

#include "app/gtk_dnd_util.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/gfx/gtk_util.h"
#include "base/pickle.h"
#include "base/string_util.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/profile.h"
#include "chrome/common/gtk_util.h"

namespace {

// Used in gtk_selection_data_set(). (I assume from this parameter that gtk has
// to some really exotic hardware...)
const int kBitsInAByte = 8;

// Maximum number of characters on a bookmark button.
const size_t kMaxCharsOnAButton = 15;

// Max size of each component of the button tooltips.
const size_t kMaxTooltipTitleLength = 100;
const size_t kMaxTooltipURLLength = 400;

// Only used for the background of the drag widget.
const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xe6, 0xed, 0xf4);

// Padding between the chrome button highlight border and the contents (favicon,
// text).
// TODO(estade): we need to adjust the top and bottom padding, but first we need
// to give the bookmark bar more space (at the expense of the toolbar).
const int kButtonPaddingTop = 0;
const int kButtonPaddingBottom = 0;
const int kButtonPaddingLeft = 2;
const int kButtonPaddingRight = 0;

void* AsVoid(const BookmarkNode* node) {
  return const_cast<BookmarkNode*>(node);
}

}  // namespace

namespace bookmark_utils {

const char kBookmarkNode[] = "bookmark-node";

// Spacing between the buttons on the bar.
const int kBarButtonPadding = 4;

GdkPixbuf* GetPixbufForNode(const BookmarkNode* node, BookmarkModel* model,
                            bool native) {
  GdkPixbuf* pixbuf;

  if (node->is_url()) {
    if (model->GetFavIcon(node).width() != 0) {
      pixbuf = gfx::GdkPixbufFromSkBitmap(&model->GetFavIcon(node));
    } else {
      pixbuf = GtkThemeProvider::GetDefaultFavicon(native);
      g_object_ref(pixbuf);
    }
  } else {
    pixbuf = GtkThemeProvider::GetFolderIcon(native);
    g_object_ref(pixbuf);
  }

  return pixbuf;
}

GtkWidget* GetDragRepresentation(const BookmarkNode* node,
                                 BookmarkModel* model,
                                 GtkThemeProvider* provider) {
  // Build a windowed representation for our button.
  GtkWidget* window = gtk_window_new(GTK_WINDOW_POPUP);
  if (!provider->UseGtkTheme()) {
    // TODO(erg): Theme wise, which color should I be picking here?
    // COLOR_BUTTON_BACKGROUND doesn't match the default theme!
    gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &kBackgroundColor);
  }
  gtk_widget_realize(window);

  GtkWidget* frame = gtk_frame_new(NULL);
  gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
  gtk_container_add(GTK_CONTAINER(window), frame);
  gtk_widget_show(frame);

  GtkWidget* floating_button = provider->BuildChromeButton();
  bookmark_utils::ConfigureButtonForNode(node, model, floating_button,
                                         provider);
  gtk_container_add(GTK_CONTAINER(frame), floating_button);
  gtk_widget_show(floating_button);

  return window;
}

void ConfigureButtonForNode(const BookmarkNode* node, BookmarkModel* model,
                            GtkWidget* button, GtkThemeProvider* provider) {
  GtkWidget* former_child = gtk_bin_get_child(GTK_BIN(button));
  if (former_child)
    gtk_container_remove(GTK_CONTAINER(button), former_child);

  std::string tooltip = BuildTooltipFor(node);
  if (!tooltip.empty())
    gtk_widget_set_tooltip_markup(button, tooltip.c_str());

  // We pack the button manually (rather than using gtk_button_set_*) so that
  // we can have finer control over its label.
  GdkPixbuf* pixbuf = bookmark_utils::GetPixbufForNode(node, model,
                                                       provider->UseGtkTheme());
  GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf);
  g_object_unref(pixbuf);

  GtkWidget* box = gtk_hbox_new(FALSE, kBarButtonPadding);
  gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0);

  std::string label_string = WideToUTF8(node->GetTitle());
  if (!label_string.empty()) {
    GtkWidget* label = gtk_label_new(label_string.c_str());

    // Ellipsize long bookmark names.
    if (node != model->other_node()) {
      gtk_label_set_max_width_chars(GTK_LABEL(label), kMaxCharsOnAButton);
      gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
    }

    gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
    SetButtonTextColors(label, provider);
  }

  GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
  // If we are not showing the label, don't set any padding, so that the icon
  // will just be centered.
  if (label_string.c_str()) {
    gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
        kButtonPaddingTop, kButtonPaddingBottom,
        kButtonPaddingLeft, kButtonPaddingRight);
  }
  gtk_container_add(GTK_CONTAINER(alignment), box);
  gtk_container_add(GTK_CONTAINER(button), alignment);

  g_object_set_data(G_OBJECT(button), bookmark_utils::kBookmarkNode,
                    AsVoid(node));

  gtk_widget_show_all(alignment);
}

std::string BuildTooltipFor(const BookmarkNode* node) {
  const std::string& url = node->GetURL().possibly_invalid_spec();
  const std::string& title = WideToUTF8(node->GetTitle());

  std::string truncated_url = WideToUTF8(l10n_util::TruncateString(
      UTF8ToWide(url), kMaxTooltipURLLength));
  gchar* escaped_url_cstr = g_markup_escape_text(truncated_url.c_str(),
                                                 truncated_url.size());
  std::string escaped_url(escaped_url_cstr);
  g_free(escaped_url_cstr);

  std::string tooltip;
  if (url == title || title.empty()) {
    return escaped_url;
  } else {
    std::string truncated_title = WideToUTF8(l10n_util::TruncateString(
      node->GetTitle(), kMaxTooltipTitleLength));
    gchar* escaped_title_cstr = g_markup_escape_text(truncated_title.c_str(),
                                                     truncated_title.size());
    std::string escaped_title(escaped_title_cstr);
    g_free(escaped_title_cstr);

    if (!escaped_url.empty())
      return std::string("") + escaped_title + "\n" + escaped_url;
    else
      return std::string("") + escaped_title + "";
  }
}

const BookmarkNode* BookmarkNodeForWidget(GtkWidget* widget) {
  return reinterpret_cast<const BookmarkNode*>(
      g_object_get_data(G_OBJECT(widget), bookmark_utils::kBookmarkNode));
}

void SetButtonTextColors(GtkWidget* label, GtkThemeProvider* provider) {
  if (provider->UseGtkTheme()) {
    gtk_util::SetLabelColor(label, NULL);
  } else {
    GdkColor color = provider->GetGdkColor(
        BrowserThemeProvider::COLOR_BOOKMARK_TEXT);
    gtk_util::SetLabelColor(label, &color);
  }
}

// DnD-related -----------------------------------------------------------------

void WriteBookmarkToSelection(const BookmarkNode* node,
                              GtkSelectionData* selection_data,
                              guint target_type,
                              Profile* profile) {
  DCHECK(node);
  std::vector<const BookmarkNode*> nodes;
  nodes.push_back(node);
  WriteBookmarksToSelection(nodes, selection_data, target_type, profile);
}

void WriteBookmarksToSelection(const std::vector<const BookmarkNode*>& nodes,
                               GtkSelectionData* selection_data,
                               guint target_type,
                               Profile* profile) {
  switch (target_type) {
    case GtkDndUtil::CHROME_BOOKMARK_ITEM: {
      BookmarkDragData data(nodes);
      Pickle pickle;
      data.WriteToPickle(profile, &pickle);

      gtk_selection_data_set(selection_data, selection_data->target,
                             kBitsInAByte,
                             static_cast<const guchar*>(pickle.data()),
                             pickle.size());
      break;
    }
    case GtkDndUtil::TEXT_URI_LIST: {
      gchar** uris = reinterpret_cast<gchar**>(malloc(sizeof(gchar*) *
                                               (nodes.size() + 1)));
      for (size_t i = 0; i < nodes.size(); ++i) {
        // If the node is a folder, this will be empty. TODO(estade): figure out
        // if there are any ramifications to passing an empty URI. After a
        // little testing, it seems fine.
        const GURL& url = nodes[i]->GetURL();
        // This const cast should be safe as gtk_selection_data_set_uris()
        // makes copies.
        uris[i] = const_cast<gchar*>(url.spec().c_str());
      }
      uris[nodes.size()] = NULL;

      gtk_selection_data_set_uris(selection_data, uris);
      free(uris);
      break;
    }
    default: {
      DLOG(ERROR) << "Unsupported drag get type!";
    }
  }
}

std::vector<const BookmarkNode*> GetNodesFromSelection(
    GdkDragContext* context,
    GtkSelectionData* selection_data,
    guint target_type,
    Profile* profile,
    gboolean* delete_selection_data,
    gboolean* dnd_success) {
  *delete_selection_data = FALSE;
  *dnd_success = FALSE;

  if ((selection_data != NULL) && (selection_data->length >= 0)) {
    if (context->action == GDK_ACTION_MOVE) {
      *delete_selection_data = TRUE;
    }

    switch (target_type) {
      case GtkDndUtil::CHROME_BOOKMARK_ITEM: {
        *dnd_success = TRUE;
        Pickle pickle(reinterpret_cast<char*>(selection_data->data),
                      selection_data->length);
        BookmarkDragData drag_data;
        drag_data.ReadFromPickle(&pickle);
        return drag_data.GetNodes(profile);
      }
      default: {
        DLOG(ERROR) << "Unsupported drag received type: " << target_type;
      }
    }
  }

  return std::vector<const BookmarkNode*>();
}

bool CreateNewBookmarkFromNamedUrl(GtkSelectionData* selection_data,
    BookmarkModel* model, const BookmarkNode* parent, int idx) {
  GURL url;
  string16 title;
  if (!GtkDndUtil::ExtractNamedURL(selection_data, &url, &title))
    return false;

  model->AddURL(parent, idx, UTF16ToWideHack(title), url);
  return true;
}

bool CreateNewBookmarksFromURIList(GtkSelectionData* selection_data,
    BookmarkModel* model, const BookmarkNode* parent, int idx) {
  std::vector<GURL> urls;
  GtkDndUtil::ExtractURIList(selection_data, &urls);
  for (size_t i = 0; i < urls.size(); ++i) {
    std::string title = GetNameForURL(urls[i]);
    model->AddURL(parent, idx++, UTF8ToWide(title), urls[i]);
  }
  return true;
}

}  // namespace bookmark_utils
<|endoftext|>