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

#include <iostream>
#include <string>
#include <vector>
#include <exception>
#include <fstream>
#include <iomanip>
#include <limits>
#include <algorithm>

#include <ArgumentList.hpp>
#include <Observation.hpp>
#include <InitializeOpenCL.hpp>
#include <Kernel.hpp>
#include <Bins.hpp>
#include <Folding.hpp>
#include <utils.hpp>
#include <Timer.hpp>
#include <Stats.hpp>

typedef float dataType;
string typeName("float");

int main(int argc, char * argv[]) {
	unsigned int nrIterations = 0;
	unsigned int clPlatformID = 0;
	unsigned int clDeviceID = 0;
	unsigned int minThreads = 0;
	unsigned int maxThreadsPerBlock = 0;
	unsigned int maxItemsPerThread = 0;
	unsigned int maxColumns = 0;
	unsigned int maxRows = 0;
  unsigned int maxVector = 0;
  AstroData::Observation< dataType > observation("FoldingTuning", typeName);

	try {
    isa::utils::ArgumentList args(argc, argv);

		nrIterations = args.getSwitchArgument< unsigned int >("-iterations");
		clPlatformID = args.getSwitchArgument< unsigned int >("-opencl_platform");
		clDeviceID = args.getSwitchArgument< unsigned int >("-opencl_device");
		observation.setPadding(args.getSwitchArgument< unsigned int >("-padding"));
		minThreads = args.getSwitchArgument< unsigned int >("-min_threads");
		maxThreadsPerBlock = args.getSwitchArgument< unsigned int >("-max_threads");
		maxItemsPerThread = args.getSwitchArgument< unsigned int >("-max_items");
		maxColumns = args.getSwitchArgument< unsigned int >("-max_columns");
		maxRows = args.getSwitchArgument< unsigned int >("-max_rows");
    maxVector = args.getSwitchArgument< unsigned int >("-max_vector");
    observation.setNrSamplesPerSecond(args.getSwitchArgument< unsigned int >("-samples"));
		observation.setNrDMs(args.getSwitchArgument< unsigned int >("-dms"));
    observation.setNrPeriods(args.getSwitchArgument< unsigned int >("-periods"));
    observation.setNrBins(args.getSwitchArgument< unsigned int >("-bins"));
    observation.setFirstPeriod(args.getSwitchArgument< unsigned int >("-first_period"));
    observation.setPeriodStep(args.getSwitchArgument< unsigned int >("-period_step"));
	} catch ( isa::utils::EmptyCommandLine &err ) {
		std::cerr << argv[0] << " -iterations ... -opencl_platform ... -opencl_device ... -padding ... -min_threads ... -max_threads ... -max_items ... -max_columns ... -max_rows ... -max_vector ... -samples ... -dms ... -periods ... -bins ... -first_period ... -period_step ..." << std::endl;
		return 1;
	} catch ( std::exception &err ) {
		std::cerr << err.what() << std::endl;
		return 1;
	}

	// Initialize OpenCL
	cl::Context * clContext = new cl::Context();
	std::vector< cl::Platform > * clPlatforms = new std::vector< cl::Platform >();
	std::vector< cl::Device > * clDevices = new std::vector< cl::Device >();
	std::vector< std::vector< cl::CommandQueue > > * clQueues = new std::vector< std::vector < cl::CommandQueue > >();

  isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, clContext, clDevices, clQueues);
  std::vector< unsigned int > * samplesPerBin = PulsarSearch::getSamplesPerBin(observation);

	// Allocate memory
  cl::Buffer samplesPerBin_d;
  std::vector< dataType > dedispersedData = std::vector< dataType >(observation.getNrSamplesPerSecond() * observation.getNrPaddedDMs());
  cl::Buffer dedispersedData_d;
  std::vector< dataType > foldedData = std::vector< dataType >(observation.getNrBins() * observation.getNrPeriods() * observation.getNrPaddedDMs());
  cl::Buffer foldedData_d;
  std::vector< unsigned int > readCounters = std::vector< unsigned int >(observation.getNrBins() * observation.getNrPeriods() * observation.getNrPaddedDMs());
  cl::Buffer readCounters_d;
  std::vector< unsigned int > writeCounters = std::vector< unsigned int >(observation.getNrBins() * observation.getNrPeriods() * observation.getNrPaddedDMs());
  cl::Buffer writeCounters_d;
  try {
    samplesPerBin_d = cl::Buffer(*clContext, CL_MEM_READ_ONLY, samplesPerBin->size() * sizeof(unsigned int), NULL, NULL);
    dedispersedData_d = cl::Buffer(*clContext, CL_MEM_READ_WRITE, dedispersedData.size() * sizeof(dataType), NULL, NULL);
    foldedData_d = cl::Buffer(*clContext, CL_MEM_READ_WRITE, foldedData.size() * sizeof(dataType), NULL, NULL);
    readCounters_d = cl::Buffer(*clContext, CL_MEM_READ_WRITE, readCounters.size() * sizeof(unsigned int), NULL, NULL);
    writeCounters_d = cl::Buffer(*clContext, CL_MEM_READ_WRITE, writeCounters.size() * sizeof(unsigned int), NULL, NULL);
  } catch ( cl::Error &err ) {
    std::cerr << "OpenCL error allocating memory: " << isa::utils::toString< cl_int >(err.err()) << "." << std::endl;
    return 1;
  }

	srand(time(NULL));
  for ( unsigned int sample = 0; sample < observation.getNrSamplesPerSecond(); sample++ ) {
    for ( unsigned int DM = 0; DM < observation.getNrDMs(); DM++ ) {
      dedispersedData[(sample * observation.getNrPaddedDMs()) + DM] = static_cast< dataType >(rand() % 10);
		}
	}
  std::fill(foldedData.begin(), foldedData.end(), static_cast< dataType >(0));
  std::fill(readCounters.begin(), readCounters.end(), 0);
  std::fill(writeCounters.begin(), writeCounters.end(), 0);

  // Copy data structures to device
  try {
    clQueues->at(clDeviceID)[0].enqueueWriteBuffer(samplesPerBin_d, CL_FALSE, 0, samplesPerBin->size() * sizeof(unsigned int), reinterpret_cast< void * >(samplesPerBin->data()));
    clQueues->at(clDeviceID)[0].enqueueWriteBuffer(dedispersedData_d, CL_FALSE, 0, dedispersedData.size() * sizeof(dataType), reinterpret_cast< void * >(dedispersedData.data()));
    clQueues->at(clDeviceID)[0].enqueueWriteBuffer(foldedData_d, CL_FALSE, 0, foldedData.size() * sizeof(dataType), reinterpret_cast< void * >(foldedData.data()));
    clQueues->at(clDeviceID)[0].enqueueWriteBuffer(readCounters_d, CL_FALSE, 0, readCounters.size() * sizeof(unsigned int), reinterpret_cast< void * >(readCounters.data()));
    clQueues->at(clDeviceID)[0].enqueueWriteBuffer(writeCounters_d, CL_FALSE, 0, writeCounters.size() * sizeof(unsigned int), reinterpret_cast< void * >(writeCounters.data()));
  } catch ( cl::Error &err ) {
    std::cerr << "OpenCL error H2D transfer: " << isa::utils::toString< cl_int >(err.err()) << "." << std::endl;
    return 1;
  }

	// Find the parameters
	std::vector< unsigned int > DMsPerBlock;
	for ( unsigned int DMs = minThreads; DMs <= maxColumns; DMs += minThreads ) {
		if ( (observation.getNrPaddedDMs() % DMs) == 0 ) {
			DMsPerBlock.push_back(DMs);
		}
	}
	std::vector< unsigned int > periodsPerBlock;
	for ( unsigned int periods = 1; periods <= maxRows; periods++ ) {
		if ( (observation.getNrPeriods() % periods) == 0 ) {
			periodsPerBlock.push_back(periods);
		}
	}
	std::vector< unsigned int > binsPerBlock;
	for ( unsigned int bins = 1; bins <= maxRows; bins++ ) {
		if ( (observation.getNrBins() % bins) == 0 ) {
			binsPerBlock.push_back(bins);
		}
	}

	std::cout << std::fixed << std::endl;
	std::cout << "# nrDMs nrSamples nrPeriods nrBins firstPeriod periodStep DMsPerBlock periodsPerBlock binsPerBlock DMsPerThread periodsPerThread binsPerThread vector GFLOP/s err time err" << std::endl << std::endl;

  for ( std::vector< unsigned int >::iterator DMs = DMsPerBlock.begin(); DMs != DMsPerBlock.end(); ++DMs ) {
    for ( std::vector< unsigned int >::iterator periods = periodsPerBlock.begin(); periods != periodsPerBlock.end(); ++periods ) {
      for ( std::vector< unsigned int >::iterator bins = binsPerBlock.begin(); bins != binsPerBlock.end(); ++bins ) {
        if ( (*DMs * *periods * *bins) > maxThreadsPerBlock ) {
          break;
        } else if ( *periods * *bins > maxRows ) {
          break;
        }
        for ( unsigned int DMsPerThread = 1; DMsPerThread <= maxItemsPerThread; DMsPerThread++ ) {
          if ( observation.getNrPaddedDMs() % (*DMs * DMsPerThread) != 0 ) {
            continue;
          }
          for ( unsigned int periodsPerThread = 1; periodsPerThread <= maxItemsPerThread; periodsPerThread++ ) {
            if ( observation.getNrPeriods() % (*periods * periodsPerThread) != 0 ) {
              continue;
            }
            for ( unsigned int binsPerThread = 1; binsPerThread <= maxItemsPerThread; binsPerThread++ ) {
              if ( observation.getNrBins() % (*bins * binsPerThread) != 0 ) {
                continue;
              }
              for ( unsigned int vector = 1; vector <= maxVector; vector *= 2 ) {
                if ( observation.getNrPaddedDMs() % (*DMs * DMsPerThread * vector) != 0 ) {
                  continue;
                }
                if ( 1 + (2 * periodsPerThread) + binsPerThread + DMsPerThread + (4 * periodsPerThread * binsPerThread) + (vector * periodsPerThread * binsPerThread * DMsPerThread) > maxItemsPerThread ) {
                  break;
                }

                // Generate kernel
                cl::Kernel * kernel;
                std::string * code = PulsarSearch::getFoldingOpenCL(*DMs, *periods, *bins, DMsPerThread, periodsPerThread, binsPerThread, vector, typeName, observation);

                try {
                  kernel = isa::OpenCL::compile("folding", *code, "-cl-mad-enable -Werror", *clContext, clDevices->at(clDeviceID));
                } catch ( isa::OpenCL::OpenCLError &err ) {
                  std::cerr << err.what() << std::endl;
                  continue;
                }

                cl::NDRange global(observation.getNrPaddedDMs() / vector / DMsPerThread, observation.getNrPeriods() / periodsPerThread, observation.getNrBins() / binsPerThread);
                cl::NDRange local(*DMs, *periods, *bins);

                kernel->setArg(0, 0);
                kernel->setArg(1, dedispersedData_d);
                kernel->setArg(2, foldedData_d);
                kernel->setArg(3, readCounters_d);
                kernel->setArg(4, writeCounters_d);
                kernel->setArg(5, samplesPerBin_d);

                // Warm-up run
                try {
                  clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local);
                } catch ( cl::Error &err ) {
                  std::cerr << "OpenCL error kernel execution: " << isa::utils::toString< cl_int >(err.err()) << "." << std::endl;
                  continue;
                }
                // Tuning runs
                double flops = isa::utils::giga(static_cast< long long unsigned int >(observation.getNrDMs()) * observation.getNrPeriods() * observation.getNrSamplesPerSecond());
                isa::utils::Timer timer("Kernel Timer");
                isa::utils::Stats< double > stats;
                cl::Event event;

                try {
                  for ( unsigned int iteration = 0; iteration < nrIterations; iteration++ ) {
                    timer.start();
                    clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, NULL, &event);
                    event.wait();
                    timer.stop();
                    stats.addElement(flops / timer.getLastRunTime());
                  }
                } catch ( cl::Error &err ) {
                  std::cerr << "OpenCL error kernel execution: " << isa::utils::toString< cl_int >(err.err()) << "." << std::endl;
                  continue;
                }

                std::cout << observation.getNrDMs() << " " << observation.getNrSamplesPerSecond() << " " << observation.getNrPeriods() << " " << observation.getNrBins() << " " << observation.getFirstPeriod() << " " << observation.getPeriodStep() << " " << *DMs << " " << *periods << " " << *bins << " " << DMsPerThread << " " << periodsPerThread << " " << binsPerThread << " " << vector << " " << std::setprecision(3) << stats.getAverage() << " " << stats.getStdDev() << " " << std::setprecision(6) << timer.getAverageTime() << " " << timer.getStdDev() << std::endl;
              }
            }
          }
        }
      }
    }
  }

	std::cout << std::endl;

	return 0;
}

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

#include <iostream>
#include <string>
#include <vector>
#include <exception>
#include <fstream>
#include <iomanip>
#include <limits>
#include <algorithm>

#include <ArgumentList.hpp>
#include <Observation.hpp>
#include <InitializeOpenCL.hpp>
#include <Kernel.hpp>
#include <Bins.hpp>
#include <Folding.hpp>
#include <utils.hpp>
#include <Timer.hpp>
#include <Stats.hpp>

typedef float dataType;
string typeName("float");

int main(int argc, char * argv[]) {
	unsigned int nrIterations = 0;
	unsigned int clPlatformID = 0;
	unsigned int clDeviceID = 0;
	unsigned int minThreads = 0;
	unsigned int maxThreadsPerBlock = 0;
	unsigned int maxItemsPerThread = 0;
	unsigned int maxColumns = 0;
	unsigned int maxRows = 0;
  unsigned int maxVector = 0;
  AstroData::Observation< dataType > observation("FoldingTuning", typeName);

	try {
    isa::utils::ArgumentList args(argc, argv);

		nrIterations = args.getSwitchArgument< unsigned int >("-iterations");
		clPlatformID = args.getSwitchArgument< unsigned int >("-opencl_platform");
		clDeviceID = args.getSwitchArgument< unsigned int >("-opencl_device");
		observation.setPadding(args.getSwitchArgument< unsigned int >("-padding"));
		minThreads = args.getSwitchArgument< unsigned int >("-min_threads");
		maxThreadsPerBlock = args.getSwitchArgument< unsigned int >("-max_threads");
		maxItemsPerThread = args.getSwitchArgument< unsigned int >("-max_items");
		maxColumns = args.getSwitchArgument< unsigned int >("-max_columns");
		maxRows = args.getSwitchArgument< unsigned int >("-max_rows");
    maxVector = args.getSwitchArgument< unsigned int >("-max_vector");
    observation.setNrSamplesPerSecond(args.getSwitchArgument< unsigned int >("-samples"));
		observation.setNrDMs(args.getSwitchArgument< unsigned int >("-dms"));
    observation.setNrPeriods(args.getSwitchArgument< unsigned int >("-periods"));
    observation.setNrBins(args.getSwitchArgument< unsigned int >("-bins"));
    observation.setFirstPeriod(args.getSwitchArgument< unsigned int >("-first_period"));
    observation.setPeriodStep(args.getSwitchArgument< unsigned int >("-period_step"));
	} catch ( isa::utils::EmptyCommandLine &err ) {
		std::cerr << argv[0] << " -iterations ... -opencl_platform ... -opencl_device ... -padding ... -min_threads ... -max_threads ... -max_items ... -max_columns ... -max_rows ... -max_vector ... -samples ... -dms ... -periods ... -bins ... -first_period ... -period_step ..." << std::endl;
		return 1;
	} catch ( std::exception &err ) {
		std::cerr << err.what() << std::endl;
		return 1;
	}

	// Initialize OpenCL
	cl::Context * clContext = new cl::Context();
	std::vector< cl::Platform > * clPlatforms = new std::vector< cl::Platform >();
	std::vector< cl::Device > * clDevices = new std::vector< cl::Device >();
	std::vector< std::vector< cl::CommandQueue > > * clQueues = new std::vector< std::vector < cl::CommandQueue > >();

  isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, clContext, clDevices, clQueues);
  std::vector< unsigned int > * samplesPerBin = PulsarSearch::getSamplesPerBin(observation);

	// Allocate memory
  cl::Buffer samplesPerBin_d;
  std::vector< dataType > dedispersedData = std::vector< dataType >(observation.getNrSamplesPerSecond() * observation.getNrPaddedDMs());
  cl::Buffer dedispersedData_d;
  std::vector< dataType > foldedData = std::vector< dataType >(observation.getNrBins() * observation.getNrPeriods() * observation.getNrPaddedDMs());
  cl::Buffer foldedData_d;
  std::vector< unsigned int > readCounters = std::vector< unsigned int >(observation.getNrBins() * observation.getNrPeriods() * observation.getNrPaddedDMs());
  cl::Buffer readCounters_d;
  std::vector< unsigned int > writeCounters = std::vector< unsigned int >(observation.getNrBins() * observation.getNrPeriods() * observation.getNrPaddedDMs());
  cl::Buffer writeCounters_d;
  try {
    samplesPerBin_d = cl::Buffer(*clContext, CL_MEM_READ_ONLY, samplesPerBin->size() * sizeof(unsigned int), 0, 0);
    dedispersedData_d = cl::Buffer(*clContext, CL_MEM_READ_WRITE, dedispersedData.size() * sizeof(dataType), 0, 0);
    foldedData_d = cl::Buffer(*clContext, CL_MEM_READ_WRITE, foldedData.size() * sizeof(dataType), 0, 0);
    readCounters_d = cl::Buffer(*clContext, CL_MEM_READ_WRITE, readCounters.size() * sizeof(unsigned int), 0, 0);
    writeCounters_d = cl::Buffer(*clContext, CL_MEM_READ_WRITE, writeCounters.size() * sizeof(unsigned int), 0, 0);
  } catch ( cl::Error &err ) {
    std::cerr << "OpenCL error allocating memory: " << isa::utils::toString(err.err()) << "." << std::endl;
    return 1;
  }

	srand(time(0));
  for ( unsigned int sample = 0; sample < observation.getNrSamplesPerSecond(); sample++ ) {
    for ( unsigned int DM = 0; DM < observation.getNrDMs(); DM++ ) {
      dedispersedData[(sample * observation.getNrPaddedDMs()) + DM] = static_cast< dataType >(rand() % 10);
		}
	}
  std::fill(foldedData.begin(), foldedData.end(), static_cast< dataType >(0));
  std::fill(readCounters.begin(), readCounters.end(), 0);
  std::fill(writeCounters.begin(), writeCounters.end(), 0);

  // Copy data structures to device
  try {
    clQueues->at(clDeviceID)[0].enqueueWriteBuffer(samplesPerBin_d, CL_FALSE, 0, samplesPerBin->size() * sizeof(unsigned int), reinterpret_cast< void * >(samplesPerBin->data()));
    clQueues->at(clDeviceID)[0].enqueueWriteBuffer(dedispersedData_d, CL_FALSE, 0, dedispersedData.size() * sizeof(dataType), reinterpret_cast< void * >(dedispersedData.data()));
    clQueues->at(clDeviceID)[0].enqueueWriteBuffer(foldedData_d, CL_FALSE, 0, foldedData.size() * sizeof(dataType), reinterpret_cast< void * >(foldedData.data()));
    clQueues->at(clDeviceID)[0].enqueueWriteBuffer(readCounters_d, CL_FALSE, 0, readCounters.size() * sizeof(unsigned int), reinterpret_cast< void * >(readCounters.data()));
    clQueues->at(clDeviceID)[0].enqueueWriteBuffer(writeCounters_d, CL_FALSE, 0, writeCounters.size() * sizeof(unsigned int), reinterpret_cast< void * >(writeCounters.data()));
  } catch ( cl::Error &err ) {
    std::cerr << "OpenCL error H2D transfer: " << isa::utils::toString(err.err()) << "." << std::endl;
    return 1;
  }

	// Find the parameters
	std::vector< unsigned int > DMsPerBlock;
	for ( unsigned int DMs = minThreads; DMs <= maxColumns; DMs += minThreads ) {
		if ( (observation.getNrPaddedDMs() % DMs) == 0 ) {
			DMsPerBlock.push_back(DMs);
		}
	}
	std::vector< unsigned int > periodsPerBlock;
	for ( unsigned int periods = 1; periods <= maxRows; periods++ ) {
		if ( (observation.getNrPeriods() % periods) == 0 ) {
			periodsPerBlock.push_back(periods);
		}
	}
	std::vector< unsigned int > binsPerBlock;
	for ( unsigned int bins = 1; bins <= maxRows; bins++ ) {
		if ( (observation.getNrBins() % bins) == 0 ) {
			binsPerBlock.push_back(bins);
		}
	}

	std::cout << std::fixed << std::endl;
	std::cout << "# nrDMs nrSamples nrPeriods nrBins firstPeriod periodStep DMsPerBlock periodsPerBlock binsPerBlock DMsPerThread periodsPerThread binsPerThread vector GFLOP/s err time err" << std::endl << std::endl;

  for ( std::vector< unsigned int >::iterator DMs = DMsPerBlock.begin(); DMs != DMsPerBlock.end(); ++DMs ) {
    for ( std::vector< unsigned int >::iterator periods = periodsPerBlock.begin(); periods != periodsPerBlock.end(); ++periods ) {
      for ( std::vector< unsigned int >::iterator bins = binsPerBlock.begin(); bins != binsPerBlock.end(); ++bins ) {
        if ( (*DMs * *periods * *bins) > maxThreadsPerBlock ) {
          break;
        } else if ( *periods * *bins > maxRows ) {
          break;
        }
        for ( unsigned int DMsPerThread = 1; DMsPerThread <= maxItemsPerThread; DMsPerThread++ ) {
          if ( observation.getNrPaddedDMs() % (*DMs * DMsPerThread) != 0 ) {
            continue;
          }
          for ( unsigned int periodsPerThread = 1; periodsPerThread <= maxItemsPerThread; periodsPerThread++ ) {
            if ( observation.getNrPeriods() % (*periods * periodsPerThread) != 0 ) {
              continue;
            }
            for ( unsigned int binsPerThread = 1; binsPerThread <= maxItemsPerThread; binsPerThread++ ) {
              if ( observation.getNrBins() % (*bins * binsPerThread) != 0 ) {
                continue;
              }
              for ( unsigned int vector = 1; vector <= maxVector; vector *= 2 ) {
                if ( observation.getNrPaddedDMs() % (*DMs * DMsPerThread * vector) != 0 ) {
                  continue;
                }
                if ( 1 + (2 * periodsPerThread) + binsPerThread + DMsPerThread + (4 * periodsPerThread * binsPerThread) + (vector * periodsPerThread * binsPerThread * DMsPerThread) > maxItemsPerThread ) {
                  break;
                }

                // Generate kernel
                double flops = isa::utils::giga(static_cast< long long unsigned int >(observation.getNrDMs()) * observation.getNrPeriods() * observation.getNrSamplesPerSecond());
                isa::utils::Timer timer("Kernel Timer");
                isa::utils::Stats< double > stats;
                cl::Event event;
                cl::Kernel * kernel;
                std::string * code = PulsarSearch::getFoldingOpenCL(*DMs, *periods, *bins, DMsPerThread, periodsPerThread, binsPerThread, vector, typeName, observation);

                try {
                  kernel = isa::OpenCL::compile("folding", *code, "-cl-mad-enable -Werror", *clContext, clDevices->at(clDeviceID));
                } catch ( isa::OpenCL::OpenCLError &err ) {
                  std::cerr << err.what() << std::endl;
                  continue;
                }

                cl::NDRange global(observation.getNrPaddedDMs() / vector / DMsPerThread, observation.getNrPeriods() / periodsPerThread, observation.getNrBins() / binsPerThread);
                cl::NDRange local(*DMs, *periods, *bins);

                kernel->setArg(0, 0);
                kernel->setArg(1, dedispersedData_d);
                kernel->setArg(2, foldedData_d);
                kernel->setArg(3, readCounters_d);
                kernel->setArg(4, writeCounters_d);
                kernel->setArg(5, samplesPerBin_d);

                // Warm-up run
                try {
                  clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &event);
                  event.wait();
                } catch ( cl::Error &err ) {
                  std::cerr << "OpenCL error kernel execution: " << isa::utils::toString(err.err()) << "." << std::endl;
                  continue;
                }
                // Tuning runs

                try {
                  for ( unsigned int iteration = 0; iteration < nrIterations; iteration++ ) {
                    timer.start();
                    clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &event);
                    event.wait();
                    timer.stop();
                    stats.addElement(flops / timer.getLastRunTime());
                  }
                } catch ( cl::Error &err ) {
                  std::cerr << "OpenCL error kernel execution: " << isa::utils::toString(err.err()) << "." << std::endl;
                  continue;
                }

                std::cout << observation.getNrDMs() << " " << observation.getNrSamplesPerSecond() << " " << observation.getNrPeriods() << " " << observation.getNrBins() << " " << observation.getFirstPeriod() << " " << observation.getPeriodStep() << " " << *DMs << " " << *periods << " " << *bins << " " << DMsPerThread << " " << periodsPerThread << " " << binsPerThread << " " << vector << " " << std::setprecision(3) << stats.getAverage() << " " << stats.getStdDev() << " " << std::setprecision(6) << timer.getAverageTime() << " " << timer.getStdDev() << std::endl;
              }
            }
          }
        }
      }
    }
  }

	std::cout << std::endl;

	return 0;
}

<|endoftext|>


<commit_before>// Ouzel by Elviss Strazdins

#ifndef OUZEL_STORAGE_STORAGEERROR_HPP
#define OUZEL_STORAGE_STORAGEERROR_HPP

#include <stdexcept>

namespace ouzel::audio
{
    class Error final: public std::runtime_error
    {
    public:
        using std::runtime_error::runtime_error;
    };
}

#endif // OUZEL_STORAGE_STORAGEERROR_HPP
<commit_msg>Fix the include guard<commit_after>// Ouzel by Elviss Strazdins

#ifndef OUZEL_STORAGE_AUDIOERROR_HPP
#define OUZEL_STORAGE_AUDIOERROR_HPP

#include <stdexcept>

namespace ouzel::audio
{
    class Error final: public std::runtime_error
    {
    public:
        using std::runtime_error::runtime_error;
    };
}

#endif // OUZEL_STORAGE_AUDIOERROR_HPP
<|endoftext|>


<commit_before>// Filename: rollDirectory.cxx
// Created by:  drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////

#include "rollDirectory.h"
#include "photo.h"
#include "indexImage.h"
#include "indent.h"
#include "notify.h"
#include "string_utils.h"
#include "indexParameters.h"

#include <ctype.h>
#include <algorithm>

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::Constructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
RollDirectory::
RollDirectory(const Filename &dir) :
  _dir(dir)
{
  _basename = _dir.get_basename();
  if (format_rose) {
    _name = format_basename(_basename);
  } else {
    _name = _basename;
  }
  _prev = (RollDirectory *)NULL;
  _next = (RollDirectory *)NULL;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::Destructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
RollDirectory::
~RollDirectory() {
  IndexImages::iterator ii;
  for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
    IndexImage *index_image = (*ii);
    delete index_image;
  }

  Photos::iterator pi;
  for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
    Photo *photo = (*pi);
    delete photo;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_dir
//       Access: Public
//  Description: Returns the filename of the directory.
////////////////////////////////////////////////////////////////////
const Filename &RollDirectory::
get_dir() const {
  return _dir;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_basename
//       Access: Public
//  Description: Returns the base name of the directory.
////////////////////////////////////////////////////////////////////
const string &RollDirectory::
get_basename() const {
  return _basename;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_name
//       Access: Public
//  Description: Returns the formatted name of the directory.  This is
//               often the same as the basename, but if -r is
//               specified on the command line it might be a somewhat
//               different, reformatted name.  In any case, it is the
//               name of the roll as it should be presented to the
//               user.
////////////////////////////////////////////////////////////////////
const string &RollDirectory::
get_name() const {
  return _name;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::scan
//       Access: Public
//  Description: Scans the directory for all the listed photos.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
scan(const string &extension) {
  bool reverse_order = false;
  bool explicit_list = false;

  // Check for an .ls file in the roll directory, which may give an
  // explicit ordering, or if empty, it specifies reverse ordering.
  Filename ls_filename(_dir, _basename + ".ls");
  if (ls_filename.exists()) {
    add_contributing_filename(ls_filename);
    ls_filename.set_text();
    ifstream ls;
    if (!ls_filename.open_read(ls)) {
      nout << "Could not read " << ls_filename << "\n";
    } else {
      bool any_words = false;
      string word;
      ls >> word;
      while (!ls.eof() && !ls.fail()) {
	any_words = true;
	Filename try_filename(_dir, word);
	if (!try_filename.exists()) {
	  try_filename = Filename(_dir, word + "." + extension);
	}
	if (!try_filename.exists()) {
	  try_filename = Filename(_dir, _basename + word + "." + extension);
	}
	if (!try_filename.exists()) {
	  try_filename = Filename(_dir, _basename + "0" + word + "." + extension);
	}
	if (try_filename.exists()) {
	  _photos.push_back(new Photo(this, try_filename.get_basename()));
	} else {
	  nout << "Frame " << word << " not found in " << _name << "\n";
	}
	ls >> word;
      }

      if (!any_words) {
	// An empty .ls file just means reverse the order.
	reverse_order = true;
      } else {
	// A non-empty .ls file has listed all the files we need; no
	// need to scan the directory.
	explicit_list = true;
      }
    }
  }

  if (!explicit_list) {
    vector_string contents;

    if (!_dir.scan_directory(contents)) {
      nout << "Could not read " << _dir << "\n";
      return false;
    }

    if (reverse_order) {
      reverse(contents.begin(), contents.end());
    }

    vector_string::iterator ci;
    for (ci = contents.begin(); ci != contents.end(); ++ci) {
      Filename basename = (*ci);
      if (basename.get_extension() == extension) {
	_photos.push_back(new Photo(this, basename));
      }
    }
  }

  if (_photos.empty()) {
    nout << _dir << " contains no photos.\n";
    return false;
  }

  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::collect_index_images
//       Access: Public
//  Description: Groups the photos into one or more IndexImages.
////////////////////////////////////////////////////////////////////
void RollDirectory::
collect_index_images() {
  // Don't call this twice.
  nassertv(_index_images.empty());

  IndexImage *index_image = new IndexImage(this, _index_images.size());
  _index_images.push_back(index_image);

  size_t i;
  for (i = 0; i < _photos.size(); i++) {
    if (!index_image->add_photo(i)) {
      // Oops, that one's full.
      index_image = new IndexImage(this, _index_images.size());
      _index_images.push_back(index_image);
      bool result = index_image->add_photo(i);
      nassertv(result);
    }
  }
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_newest_contributing_filename
//       Access: Public
//  Description: Returns the Filename with the newest timestamp that
//               contributes to the contents of the index images in
//               this directory, if any (other than the images
//               themselves).  This is used by the IndexImage code to
//               determine if it needs to regenerate the index image.
////////////////////////////////////////////////////////////////////
const Filename &RollDirectory::
get_newest_contributing_filename() const {
  return _newest_contributing_filename;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_num_photos
//       Access: Public
//  Description: Returns the number of photos in the roll.
////////////////////////////////////////////////////////////////////
int RollDirectory::
get_num_photos() const {
  return _photos.size();
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_photo
//       Access: Public
//  Description: Returns the nth photo in the roll.
////////////////////////////////////////////////////////////////////
Photo *RollDirectory::
get_photo(int n) const {
  nassertr(n >= 0 && n < (int)_photos.size(), NULL);
  return _photos[n];
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_num_index_images
//       Access: Public
//  Description: Returns the number of index images in the roll.
////////////////////////////////////////////////////////////////////
int RollDirectory::
get_num_index_images() const {
  return _index_images.size();
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_index_image
//       Access: Public
//  Description: Returns the nth index image in the roll.
////////////////////////////////////////////////////////////////////
IndexImage *RollDirectory::
get_index_image(int n) const {
  nassertr(n >= 0 && n < (int)_index_images.size(), NULL);
  return _index_images[n];
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::generate_images
//       Access: Public
//  Description: Generates image files appropriate to this directory
//               to the indicated archive dir.  Returns true on
//               success, false on failure.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
  nassertr(!_index_images.empty(), false);

  IndexImages::iterator ii;
  for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
    IndexImage *index_image = (*ii);
    if (!index_image->generate_images(archive_dir, text_maker)) {
      return false;
    }
  }

  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::generate_html
//       Access: Public
//  Description: Generates all appropriate HTML files for this
//               directory, and generate the appropriate HTML code
//               into the root_html file.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
generate_html(ostream &root_html, const Filename &archive_dir,
              const Filename &roll_dir_root) {
  nassertr(!_index_images.empty(), false);

  if (!omit_roll_headers) {
    Filename cm_filename(_dir, _basename);
    cm_filename.set_extension("cm");
    if (cm_filename.exists()) {
      // If the comment file for the roll exists, insert its contents
      // here instead of the generic header.
      if (!insert_html_comment(root_html, cm_filename)) {
	return false;
      }

    } else {
      root_html
	<< "
" << _name << "
\n";
    }
  }

  nout << "Generating " << Filename(archive_dir, "html/")
       << _basename << "/*\n";

  IndexImages::iterator ii;
  for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
    IndexImage *index_image = (*ii);
    if (!index_image->generate_html(root_html, archive_dir, roll_dir_root)) {
      return false;
    }
  }

  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::output
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void RollDirectory::
output(ostream &out) const {
  out << _name;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::write
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void RollDirectory::
write(ostream &out, int indent_level) const {
  indent(out, indent_level)
    << _dir << "\n";

  if (!_index_images.empty()) {
    // If we have any index images, output those.
    IndexImages::const_iterator ii;
    for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
      const IndexImage *index_image = (*ii);
      index_image->write(out, indent_level + 2);
    }

  } else {
    // Otherwise, just output the photos.
    Photos::const_iterator pi;
    for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
      const Photo *photo = (*pi);
      indent(out, indent_level + 2)
        << *photo << "\n";
    }
  }
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::insert_html_comment
//       Access: Public, Static
//  Description: Reads the indicated comment file and inserts its
//               contents (after the header) within the indicated
//               ostream at the current point.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
insert_html_comment(ostream &html, Filename cm_filename) {
  cm_filename.set_text();
  ifstream cm;
  if (!cm_filename.open_read(cm)) {
    nout << "Unable to read " << cm_filename << "\n";
    return false;
  }

  // First, scan through the file looking for  or .
  string line;
  getline(cm, line);
  while (!cm.eof() && !cm.fail()) {
    string lower = downcase(line);
    size_t body = lower.find("");
    if (body != string::npos) {
      return insert_html_comment_body(html, cm);
    }
    getline(cm, line);
  }

  // We didn't find it.  Insert the whole file.
  cm.clear();
  cm.seekg(0);
  int ch = cm.get();
  while (ch != EOF) {
    html.put(ch);
    ch = cm.get();
  }

  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::add_contributing_filename
//       Access: Private
//  Description: Specifies an additional filename that contributes to
//               the index image.
////////////////////////////////////////////////////////////////////
void RollDirectory::
add_contributing_filename(const Filename &filename) {
  if (_newest_contributing_filename.empty() ||
      _newest_contributing_filename.compare_timestamps(filename) < 0) {
    _newest_contributing_filename = filename;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::insert_html_comment_body
//       Access: Private, Static
//  Description: Copies from the comment file up until the next
//               , or until the end of file.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
insert_html_comment_body(ostream &html, istream &cm) {
  string line;
  getline(cm, line);
  while (!cm.eof() && !cm.fail()) {
    string lower = downcase(line);
    size_t body = lower.find("");
    if (body != string::npos) {
      // Here's the end; we're done.
      return true;
    }
    html << line << "\n";
    getline(cm, line);
  }

  // Reached end of file; good enough.
  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::format_basename
//       Access: Private, Static
//  Description: Reformats the roll directory into a user-friendly
//               name based on its encoded directory name.
////////////////////////////////////////////////////////////////////
string RollDirectory::
format_basename(const string &basename) {
  if (basename.length() <= 4) {
    return basename;
  }

  // The first four characters must be digits.
  for (size_t i = 0; i < 4; i++) {
    if (!isdigit(basename[i])) {
      return basename;
    }
  }

  string mm = basename.substr(0, 2);
  string yy = basename.substr(2, 2);
  string ss = basename.substr(4);

  if (mm[0] == '0') {
    mm = mm[1];
  }
  while (ss.length() > 1 && ss[0] == '0') {
    ss = ss.substr(1);
  }

  return mm + "-" + yy + "/" + ss;
}
<commit_msg>index images within a paragraph<commit_after>// Filename: rollDirectory.cxx
// Created by:  drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////

#include "rollDirectory.h"
#include "photo.h"
#include "indexImage.h"
#include "indent.h"
#include "notify.h"
#include "string_utils.h"
#include "indexParameters.h"

#include <ctype.h>
#include <algorithm>

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::Constructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
RollDirectory::
RollDirectory(const Filename &dir) :
  _dir(dir)
{
  _basename = _dir.get_basename();
  if (format_rose) {
    _name = format_basename(_basename);
  } else {
    _name = _basename;
  }
  _prev = (RollDirectory *)NULL;
  _next = (RollDirectory *)NULL;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::Destructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
RollDirectory::
~RollDirectory() {
  IndexImages::iterator ii;
  for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
    IndexImage *index_image = (*ii);
    delete index_image;
  }

  Photos::iterator pi;
  for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
    Photo *photo = (*pi);
    delete photo;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_dir
//       Access: Public
//  Description: Returns the filename of the directory.
////////////////////////////////////////////////////////////////////
const Filename &RollDirectory::
get_dir() const {
  return _dir;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_basename
//       Access: Public
//  Description: Returns the base name of the directory.
////////////////////////////////////////////////////////////////////
const string &RollDirectory::
get_basename() const {
  return _basename;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_name
//       Access: Public
//  Description: Returns the formatted name of the directory.  This is
//               often the same as the basename, but if -r is
//               specified on the command line it might be a somewhat
//               different, reformatted name.  In any case, it is the
//               name of the roll as it should be presented to the
//               user.
////////////////////////////////////////////////////////////////////
const string &RollDirectory::
get_name() const {
  return _name;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::scan
//       Access: Public
//  Description: Scans the directory for all the listed photos.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
scan(const string &extension) {
  bool reverse_order = false;
  bool explicit_list = false;

  // Check for an .ls file in the roll directory, which may give an
  // explicit ordering, or if empty, it specifies reverse ordering.
  Filename ls_filename(_dir, _basename + ".ls");
  if (ls_filename.exists()) {
    add_contributing_filename(ls_filename);
    ls_filename.set_text();
    ifstream ls;
    if (!ls_filename.open_read(ls)) {
      nout << "Could not read " << ls_filename << "\n";
    } else {
      bool any_words = false;
      string word;
      ls >> word;
      while (!ls.eof() && !ls.fail()) {
	any_words = true;
	Filename try_filename(_dir, word);
	if (!try_filename.exists()) {
	  try_filename = Filename(_dir, word + "." + extension);
	}
	if (!try_filename.exists()) {
	  try_filename = Filename(_dir, _basename + word + "." + extension);
	}
	if (!try_filename.exists()) {
	  try_filename = Filename(_dir, _basename + "0" + word + "." + extension);
	}
	if (try_filename.exists()) {
	  _photos.push_back(new Photo(this, try_filename.get_basename()));
	} else {
	  nout << "Frame " << word << " not found in " << _name << "\n";
	}
	ls >> word;
      }

      if (!any_words) {
	// An empty .ls file just means reverse the order.
	reverse_order = true;
      } else {
	// A non-empty .ls file has listed all the files we need; no
	// need to scan the directory.
	explicit_list = true;
      }
    }
  }

  if (!explicit_list) {
    vector_string contents;

    if (!_dir.scan_directory(contents)) {
      nout << "Could not read " << _dir << "\n";
      return false;
    }

    if (reverse_order) {
      reverse(contents.begin(), contents.end());
    }

    vector_string::iterator ci;
    for (ci = contents.begin(); ci != contents.end(); ++ci) {
      Filename basename = (*ci);
      if (basename.get_extension() == extension) {
	_photos.push_back(new Photo(this, basename));
      }
    }
  }

  if (_photos.empty()) {
    nout << _dir << " contains no photos.\n";
    return false;
  }

  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::collect_index_images
//       Access: Public
//  Description: Groups the photos into one or more IndexImages.
////////////////////////////////////////////////////////////////////
void RollDirectory::
collect_index_images() {
  // Don't call this twice.
  nassertv(_index_images.empty());

  IndexImage *index_image = new IndexImage(this, _index_images.size());
  _index_images.push_back(index_image);

  size_t i;
  for (i = 0; i < _photos.size(); i++) {
    if (!index_image->add_photo(i)) {
      // Oops, that one's full.
      index_image = new IndexImage(this, _index_images.size());
      _index_images.push_back(index_image);
      bool result = index_image->add_photo(i);
      nassertv(result);
    }
  }
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_newest_contributing_filename
//       Access: Public
//  Description: Returns the Filename with the newest timestamp that
//               contributes to the contents of the index images in
//               this directory, if any (other than the images
//               themselves).  This is used by the IndexImage code to
//               determine if it needs to regenerate the index image.
////////////////////////////////////////////////////////////////////
const Filename &RollDirectory::
get_newest_contributing_filename() const {
  return _newest_contributing_filename;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_num_photos
//       Access: Public
//  Description: Returns the number of photos in the roll.
////////////////////////////////////////////////////////////////////
int RollDirectory::
get_num_photos() const {
  return _photos.size();
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_photo
//       Access: Public
//  Description: Returns the nth photo in the roll.
////////////////////////////////////////////////////////////////////
Photo *RollDirectory::
get_photo(int n) const {
  nassertr(n >= 0 && n < (int)_photos.size(), NULL);
  return _photos[n];
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_num_index_images
//       Access: Public
//  Description: Returns the number of index images in the roll.
////////////////////////////////////////////////////////////////////
int RollDirectory::
get_num_index_images() const {
  return _index_images.size();
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::get_index_image
//       Access: Public
//  Description: Returns the nth index image in the roll.
////////////////////////////////////////////////////////////////////
IndexImage *RollDirectory::
get_index_image(int n) const {
  nassertr(n >= 0 && n < (int)_index_images.size(), NULL);
  return _index_images[n];
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::generate_images
//       Access: Public
//  Description: Generates image files appropriate to this directory
//               to the indicated archive dir.  Returns true on
//               success, false on failure.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
  nassertr(!_index_images.empty(), false);

  IndexImages::iterator ii;
  for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
    IndexImage *index_image = (*ii);
    if (!index_image->generate_images(archive_dir, text_maker)) {
      return false;
    }
  }

  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::generate_html
//       Access: Public
//  Description: Generates all appropriate HTML files for this
//               directory, and generate the appropriate HTML code
//               into the root_html file.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
generate_html(ostream &root_html, const Filename &archive_dir,
              const Filename &roll_dir_root) {
  nassertr(!_index_images.empty(), false);

  if (!omit_roll_headers) {
    Filename cm_filename(_dir, _basename);
    cm_filename.set_extension("cm");
    if (cm_filename.exists()) {
      // If the comment file for the roll exists, insert its contents
      // here instead of the generic header.
      if (!insert_html_comment(root_html, cm_filename)) {
	return false;
      }

    } else {
      root_html
	<< "
" << _name << "
\n";
    }
  }

  nout << "Generating " << Filename(archive_dir, "html/")
       << _basename << "/*\n";

  root_html << "
\n";
  IndexImages::iterator ii;
  for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
    IndexImage *index_image = (*ii);
    if (!index_image->generate_html(root_html, archive_dir, roll_dir_root)) {
      return false;
    }
  }
  root_html << "
\n";

  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::output
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void RollDirectory::
output(ostream &out) const {
  out << _name;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::write
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void RollDirectory::
write(ostream &out, int indent_level) const {
  indent(out, indent_level)
    << _dir << "\n";

  if (!_index_images.empty()) {
    // If we have any index images, output those.
    IndexImages::const_iterator ii;
    for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
      const IndexImage *index_image = (*ii);
      index_image->write(out, indent_level + 2);
    }

  } else {
    // Otherwise, just output the photos.
    Photos::const_iterator pi;
    for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
      const Photo *photo = (*pi);
      indent(out, indent_level + 2)
        << *photo << "\n";
    }
  }
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::insert_html_comment
//       Access: Public, Static
//  Description: Reads the indicated comment file and inserts its
//               contents (after the header) within the indicated
//               ostream at the current point.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
insert_html_comment(ostream &html, Filename cm_filename) {
  cm_filename.set_text();
  ifstream cm;
  if (!cm_filename.open_read(cm)) {
    nout << "Unable to read " << cm_filename << "\n";
    return false;
  }

  // First, scan through the file looking for  or .
  string line;
  getline(cm, line);
  while (!cm.eof() && !cm.fail()) {
    string lower = downcase(line);
    size_t body = lower.find("");
    if (body != string::npos) {
      return insert_html_comment_body(html, cm);
    }
    getline(cm, line);
  }

  // We didn't find it.  Insert the whole file.
  cm.clear();
  cm.seekg(0);
  int ch = cm.get();
  while (ch != EOF) {
    html.put(ch);
    ch = cm.get();
  }

  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::add_contributing_filename
//       Access: Private
//  Description: Specifies an additional filename that contributes to
//               the index image.
////////////////////////////////////////////////////////////////////
void RollDirectory::
add_contributing_filename(const Filename &filename) {
  if (_newest_contributing_filename.empty() ||
      _newest_contributing_filename.compare_timestamps(filename) < 0) {
    _newest_contributing_filename = filename;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::insert_html_comment_body
//       Access: Private, Static
//  Description: Copies from the comment file up until the next
//               , or until the end of file.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
insert_html_comment_body(ostream &html, istream &cm) {
  string line;
  getline(cm, line);
  while (!cm.eof() && !cm.fail()) {
    string lower = downcase(line);
    size_t body = lower.find("");
    if (body != string::npos) {
      // Here's the end; we're done.
      return true;
    }
    html << line << "\n";
    getline(cm, line);
  }

  // Reached end of file; good enough.
  return true;
}

////////////////////////////////////////////////////////////////////
//     Function: RollDirectory::format_basename
//       Access: Private, Static
//  Description: Reformats the roll directory into a user-friendly
//               name based on its encoded directory name.
////////////////////////////////////////////////////////////////////
string RollDirectory::
format_basename(const string &basename) {
  if (basename.length() <= 4) {
    return basename;
  }

  // The first four characters must be digits.
  for (size_t i = 0; i < 4; i++) {
    if (!isdigit(basename[i])) {
      return basename;
    }
  }

  string mm = basename.substr(0, 2);
  string yy = basename.substr(2, 2);
  string ss = basename.substr(4);

  if (mm[0] == '0') {
    mm = mm[1];
  }
  while (ss.length() > 1 && ss[0] == '0') {
    ss = ss.substr(1);
  }

  return mm + "-" + yy + "/" + ss;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008 Apple 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:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "config.h"
#include "NetworkStateNotifier.h"

#include <wtf/MainThread.h>
#include <wtf/Vector.h>

#include <winsock2.h>
#include <iphlpapi.h>

namespace WebCore {

void NetworkStateNotifier::updateState()
{
    // Assume that we're online until proven otherwise.
    m_isOnLine = true;

    Vector<char> buffer;
    DWORD size = 0;

    if (::GetAdaptersAddresses(AF_UNSPEC, 0, 0, 0, &size) != ERROR_BUFFER_OVERFLOW)
        return;

    buffer.resize(size);
    PIP_ADAPTER_ADDRESSES addresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(buffer.data());

    if (::GetAdaptersAddresses(AF_UNSPEC, 0, 0, addresses, &size) != ERROR_SUCCESS) {
        // We couldn't determine whether we're online or not, so assume that we are.
        return;
    }

    for (; addresses; addresses = addresses->Next) {
        if (addresses->IfType == MIB_IF_TYPE_LOOPBACK)
            continue;

        if (addresses->OperStatus != IfOperStatusUp)
            continue;

        // We found an interface that was up.
        return;
    }

    // We didn't find any valid interfaces, so we must be offline.
    m_isOnLine = false;
}

void NetworkStateNotifier::addressChanged()
{
    bool oldOnLine = m_isOnLine;

    updateState();

    if (m_isOnLine == oldOnLine)
        return;

    if (m_networkStateChangedFunction)
        m_networkStateChangedFunction();
}

void NetworkStateNotifier::callAddressChanged(void* context)
{
    static_cast<NetworkStateNotifier*>(context)->addressChanged();
}

void CALLBACK NetworkStateNotifier::addrChangeCallback(void* context, BOOLEAN timedOut)
{
    callOnMainThread(callAddressChanged, context);
}

void NetworkStateNotifier::registerForAddressChange()
{
    HANDLE handle;
    ::NotifyAddrChange(&handle, &m_overlapped);
}

NetworkStateNotifier::NetworkStateNotifier()
    : m_isOnLine(false)
{
    updateState();

    memset(&m_overlapped, 0, sizeof(m_overlapped));

    m_overlapped.hEvent = ::CreateEvent(0, false, false, 0);

    ::RegisterWaitForSingleObject(&m_waitHandle, m_overlapped.hEvent, addrChangeCallback, this, INFINITE, 0);

    registerForAddressChange();
}

}
<commit_msg>Test to see if getting the network status on startup is expensive, and causing a performance startup regression. Review URL: http://codereview.chromium.org/5672<commit_after>/*
 * Copyright (C) 2008 Apple 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:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "config.h"
#include "NetworkStateNotifier.h"

#include <wtf/MainThread.h>
#include <wtf/Vector.h>

#include <winsock2.h>
#include <iphlpapi.h>

namespace WebCore {

void NetworkStateNotifier::updateState()
{
    // Assume that we're online until proven otherwise.
    m_isOnLine = true;
    return;

    Vector<char> buffer;
    DWORD size = 0;

    if (::GetAdaptersAddresses(AF_UNSPEC, 0, 0, 0, &size) != ERROR_BUFFER_OVERFLOW)
        return;

    buffer.resize(size);
    PIP_ADAPTER_ADDRESSES addresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(buffer.data());

    if (::GetAdaptersAddresses(AF_UNSPEC, 0, 0, addresses, &size) != ERROR_SUCCESS) {
        // We couldn't determine whether we're online or not, so assume that we are.
        return;
    }

    for (; addresses; addresses = addresses->Next) {
        if (addresses->IfType == MIB_IF_TYPE_LOOPBACK)
            continue;

        if (addresses->OperStatus != IfOperStatusUp)
            continue;

        // We found an interface that was up.
        return;
    }

    // We didn't find any valid interfaces, so we must be offline.
    m_isOnLine = false;
}

void NetworkStateNotifier::addressChanged()
{
    bool oldOnLine = m_isOnLine;

    updateState();

    if (m_isOnLine == oldOnLine)
        return;

    if (m_networkStateChangedFunction)
        m_networkStateChangedFunction();
}

void NetworkStateNotifier::callAddressChanged(void* context)
{
    static_cast<NetworkStateNotifier*>(context)->addressChanged();
}

void CALLBACK NetworkStateNotifier::addrChangeCallback(void* context, BOOLEAN timedOut)
{
    callOnMainThread(callAddressChanged, context);
}

void NetworkStateNotifier::registerForAddressChange()
{
    HANDLE handle;
    ::NotifyAddrChange(&handle, &m_overlapped);
}

NetworkStateNotifier::NetworkStateNotifier()
    : m_isOnLine(false)
{
    updateState();

    memset(&m_overlapped, 0, sizeof(m_overlapped));

    m_overlapped.hEvent = ::CreateEvent(0, false, false, 0);

    ::RegisterWaitForSingleObject(&m_waitHandle, m_overlapped.hEvent, addrChangeCallback, this, INFINITE, 0);

    registerForAddressChange();
}

}
<|endoftext|>


<commit_before>#include "photoeffects.hpp"
#include <iostream>

using namespace cv;
using namespace std;

const char *helper =
"./warmify_sample <img>\n\
\t<img> - file name contained the processed image\n\
";

int processArguments(int argc, char **argv, Mat &img);

int main(int argc, char** argv)
{
    const char *srcImgWinName = "Initial image",
               *dstImgWinName = "Processed image";
    Mat image, warmifyImg;

    if (processArguments(argc, argv, image))
    {
        cout << helper << endl;
        return 1;
    }

    try
    {
        warmify(image, warmifyImg, 30);
    }
    catch(...)
    {
        cout << "Incorrect image type." << endl;
        return 2;
    }

    namedWindow(srcImgWinName, 2);
    namedWindow(dstImgWinName, 2);
    imshow(srcImgWinName, image);
    imshow(dstImgWinName, warmifyImg);
    waitKey();
    destroyAllWindows();
    return 0;
}

int processArguments(int argc, char **argv, Mat &img)
{
    if (argc < 2)
    {
        return 1;
    }
    img = imread(argv[1], CV_LOAD_IMAGE_COLOR);
    return 0;
}
<commit_msg>warmify_sample was changed<commit_after>#include "photoeffects.hpp"
#include <iostream>

using namespace cv;
using namespace std;

const char *helper =
"./warmify_sample <img>\n\
\t<img> - file name contained the processed image\n\
";

int processArguments(int argc, char **argv, Mat &img);

int main(int argc, char** argv)
{
    const char *srcImgWinName = "Initial image",
               *dstImgWinName = "Processed image";
    Mat image, warmifyImg;

    if (processArguments(argc, argv, image))
    {
        cout << helper << endl;
        return 1;
    }

    try
    {
        warmify(image, warmifyImg, 30);
    }
    catch(...)
    {
        cout << "Incorrect image type." << endl;
        return 2;
    }

    namedWindow(srcImgWinName);
    namedWindow(dstImgWinName);
    imshow(srcImgWinName, image);
    imshow(dstImgWinName, warmifyImg);
    waitKey();
    destroyAllWindows();
    return 0;
}

int processArguments(int argc, char **argv, Mat &img)
{
    if (argc < 2)
    {
        return 1;
    }
    img = imread(argv[1], CV_LOAD_IMAGE_COLOR);
    return 0;
}
<|endoftext|>


<commit_before>/**
 * 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.
 */
#ifndef __STOUT_JSON__
#define __STOUT_JSON__

#include <picojson.h>

#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <string>
#include <vector>

#include <boost/type_traits/is_arithmetic.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/variant.hpp>

#include <stout/check.hpp>
#include <stout/foreach.hpp>
#include <stout/result.hpp>
#include <stout/strings.hpp>
#include <stout/try.hpp>
#include <stout/unreachable.hpp>

namespace JSON {

// Implementation of the JavaScript Object Notation (JSON) grammar
// using boost::variant. We explicitly define each "type" of the
// grammar, including 'true' (json::True), 'false' (json::False), and
// 'null' (json::Null), for clarity and also because boost::variant
// "picks" the wrong type when we try and use std::string, long (or
// int), double (or float), and bool all in the same variant (while it
// does work with explicit casts, it seemed bad style to force people
// to put those casts in place). We could have avoided using
// json::String or json::Number and just used std::string and double
// respectively, but we choose to include them for completeness
// (although, this does pay a 2x cost when compiling thanks to all the
// extra template instantiations).

// Note that all of these forward declarations are not necessary
// but it serves to document the set of types which are available.
struct String;
struct Number;
struct Object;
struct Array;
struct True;
struct False;
struct Boolean;
struct Null;
struct Value;

struct String
{
  String() {}
  String(const char* _value) : value(_value) {}
  String(const std::string& _value) : value(_value) {}
  std::string value;
};

struct Number
{
  Number() : value(0) {}
  Number(double _value) : value(_value) {}
  double value;
};

struct Object
{
  // Returns the JSON value (specified by the type) given a "path"
  // into the structure, for example:
  //
  //   Result<JSON::Array> array = object.find<JSON::Array>("nested.array");
  //
  // Will return 'None' if no field could be found called 'array'
  // within a field called 'nested' of 'object' (where 'nested' must
  // also be a JSON object).
  //
  // Returns an error if a JSON value of the wrong type is found, or
  // an intermediate JSON value is not an object that we can do a
  // recursive find on.
  //
  // TODO(benh): Support paths that index, e.g., 'nested.array[4].field'.
  template <typename T>
  Result<T> find(const std::string& path) const;

  std::map<std::string, Value> values;
};

struct Array
{
  std::list<Value> values;
};

struct Boolean
{
  Boolean() : value(false) {}
  Boolean(bool _value) : value(_value) {}
  bool value;
};

// This is a helper so you can say JSON::True() instead of
// JSON::Boolean(true).
struct True : Boolean
{
  True() : Boolean(true) {};
};

// This is a helper so you can say JSON::False() instead of
// JSON::Boolean(false).
struct False : Boolean
{
  False() : Boolean(false) {}
};

struct Null {};

namespace internal {

// Only Object and Array require recursive_wrapper, not sure
// if there is a reason to wrap the others or not.
// Null needs to be first so that it is the default value.
typedef boost::variant<boost::recursive_wrapper<Null>,
                       boost::recursive_wrapper<String>,
                       boost::recursive_wrapper<Number>,
                       boost::recursive_wrapper<Object>,
                       boost::recursive_wrapper<Array>,
                       boost::recursive_wrapper<Boolean> > Variant;

} // namespace internal {

struct Value : internal::Variant
{
  // Empty constructor gets the variant default.
  Value() {}

  Value(bool value) : internal::Variant(JSON::Boolean(value)) {}

  Value(char* value) : internal::Variant(JSON::String(value)) {}
  Value(const char* value) : internal::Variant(JSON::String(value)) {}

  // Arithmetic types are specifically routed through Number because
  // there would be ambiguity between JSON::Bool and JSON::Number
  // otherwise.
  template <typename T>
  Value(
      const T& value,
      typename boost::enable_if<boost::is_arithmetic<T>, int>::type = 0)
    : internal::Variant(Number(value)) {}

  // Non-arithmetic types are passed to the default constructor of
  // Variant.
  template <typename T>
  Value(
      const T& value,
      typename boost::disable_if<boost::is_arithmetic<T>, int>::type = 0)
    : internal::Variant(value) {}

  template <typename T>
  bool is() const;

  template <typename T>
  const T& as() const;
};

template <typename T>
bool Value::is() const
{
  const T* t = boost::get<T>(this);
  return t != NULL;
}

template <>
inline bool Value::is<Value>() const
{
  return true;
}

template <typename T>
const T& Value::as() const
{
  return *CHECK_NOTNULL(boost::get<T>(this));
}

template <>
inline const Value& Value::as<Value>() const
{
  return *this;
}

template <typename T>
Result<T> Object::find(const std::string& path) const
{
  const std::vector<std::string>& names = strings::split(path, ".", 2);

  if (names.empty()) {
    return None();
  }

  std::map<std::string, Value>::const_iterator entry = values.find(names[0]);

  if (entry == values.end()) {
    return None();
  }

  const Value& value = entry->second;

  if (names.size() == 1) {
    if (!value.is<T>()) {
      // TODO(benh): Use a visitor to print out the type found.
      return Error("Found JSON value of wrong type");
    }
    return value.as<T>();
  } else if (!value.is<Object>()) {
    // TODO(benh): Use a visitor to print out the intermediate type.
    return Error("Intermediate JSON value not an object");
  }

  return value.as<Object>().find<T>(names[1]);
}

struct Comparator : boost::static_visitor<bool>
{
  Comparator(const Value& _value)
    : value(_value) {}

  bool operator () (const Object& object) const
  {
    if (value.is<Object>()) {
      return value.as<Object>().values == object.values;
    }
    return false;
  }

  bool operator () (const String& string) const
  {
    if (value.is<String>()) {
      return value.as<String>().value == string.value;
    }
    return false;
  }

  bool operator () (const Number& number) const
  {
    if (value.is<Number>()) {
      return value.as<Number>().value == number.value;
    }
    return false;
  }

  bool operator () (const Array& array) const
  {
    if (value.is<Array>()) {
      return value.as<Array>().values == array.values;
    }
    return false;
  }

  bool operator () (const Boolean& boolean) const
  {
    if (value.is<Boolean>()) {
      return value.as<Boolean>().value == boolean.value;
    }
    return false;
  }

  bool operator () (const Null&) const
  {
    return value.is<Null>();
  }

private:
  const Value& value;
};

inline bool operator == (const Value& lhs, const Value& rhs)
{
  return boost::apply_visitor(Comparator(lhs), rhs);
}

inline std::ostream& operator << (std::ostream& out, const String& string)
{
  // TODO(benh): This escaping DOES NOT handle unicode, it encodes as ASCII.
  // See RFC4627 for the JSON string specificiation.
  out << "\"";
  foreach (unsigned char c, string.value) {
    switch (c) {
      case '"':  out << "\\\""; break;
      case '\\': out << "\\\\"; break;
      case '/':  out << "\\/";  break;
      case '\b': out << "\\b";  break;
      case '\f': out << "\\f";  break;
      case '\n': out << "\\n";  break;
      case '\r': out << "\\r";  break;
      case '\t': out << "\\t";  break;
      default:
        // See RFC4627 for these ranges.
        if ((c >= 0x20 && c <= 0x21) ||
            (c >= 0x23 && c <= 0x5B) ||
            (c >= 0x5D && c < 0x7F)) {
          out << c;
        } else {
          // NOTE: We also escape all bytes > 0x7F since they imply more than
          // 1 byte in UTF-8. This is why we don't escape UTF-8 properly.
          // See RFC4627 for the escaping format: \uXXXX (X is a hex digit).
          // Each byte here will be of the form: \u00XX (this is why we need
          // setw and the cast to unsigned int).
          out << "\\u" << std::setfill('0') << std::setw(4)
              << std::hex << std::uppercase << (unsigned int) c;
        }
        break;
    }
  }
  out << "\"";
  return out;
}

inline std::ostream& operator << (std::ostream& out, const Number& number)
{
  // Use the guaranteed accurate precision, see:
  // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2005.pdf
  return out << std::setprecision(std::numeric_limits<double>::digits10)
             << number.value;
}

inline std::ostream& operator << (std::ostream& out, const Object& object)
{
  out << "{";
  std::map<std::string, Value>::const_iterator iterator;
  iterator = object.values.begin();
  while (iterator != object.values.end()) {
    out << "\"" << (*iterator).first << "\":" << (*iterator).second;
    if (++iterator != object.values.end()) {
      out << ",";
    }
  }
  out << "}";
  return out;
}

inline std::ostream& operator << (std::ostream& out, const Array& array)
{
  out << "[";
  std::list<Value>::const_iterator iterator;
  iterator = array.values.begin();
  while (iterator != array.values.end()) {
    out << *iterator;
    if (++iterator != array.values.end()) {
      out << ",";
    }
  }
  out << "]";
  return out;
}

inline std::ostream& operator << (std::ostream& out, const Boolean& boolean)
{
  return out << (boolean.value ? "true" : "false");
}

inline std::ostream& operator << (std::ostream& out, const Null&)
{
  return out << "null";
}

namespace internal {

inline Value convert(const picojson::value& value)
{
  if (value.is<picojson::null>()) {
    return Null();
  } else if (value.is<bool>()) {
    return Boolean(value.get<bool>());
  } else if (value.is<picojson::value::object>()) {
    Object object;
    foreachpair (const std::string& name,
                 const picojson::value& value,
                 value.get<picojson::value::object>()) {
      object.values[name] = convert(value);
    }
    return object;
  } else if (value.is<picojson::value::array>()) {
    Array array;
    foreach (const picojson::value& value,
             value.get<picojson::value::array>()) {
      array.values.push_back(convert(value));
    }
    return array;
  } else if (value.is<double>()) {
    return Number(value.get<double>());
  } else if (value.is<std::string>()) {
    return String(value.get<std::string>());
  }
  return Null();
}

} // namespace internal {

inline Try<Value> parse(const std::string& s)
{
  picojson::value value;
  std::string error;

  picojson::parse(value, s.c_str(), s.c_str() + s.size(), &error);

  if (!error.empty()) {
    return Error(error);
  }

  return internal::convert(value);
}

template <typename T>
Try<T> parse(const std::string& s)
{
  Try<Value> value = parse(s);

  if (value.isError()) {
    return Error(value.error());
  }

  if (!value.get().is<T>()) {
    return Error("Unexpected JSON type parsed");
  }

  return value.get().as<T>();
}

template <>
inline Try<Value> parse(const std::string& s)
{
  return parse(s);
}

} // namespace JSON {

#endif // __STOUT_JSON__
<commit_msg>Escaped JSON object keys.<commit_after>/**
 * 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.
 */
#ifndef __STOUT_JSON__
#define __STOUT_JSON__

#include <picojson.h>

#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <string>
#include <vector>

#include <boost/type_traits/is_arithmetic.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/variant.hpp>

#include <stout/check.hpp>
#include <stout/foreach.hpp>
#include <stout/result.hpp>
#include <stout/strings.hpp>
#include <stout/try.hpp>
#include <stout/unreachable.hpp>

namespace JSON {

// Implementation of the JavaScript Object Notation (JSON) grammar
// using boost::variant. We explicitly define each "type" of the
// grammar, including 'true' (json::True), 'false' (json::False), and
// 'null' (json::Null), for clarity and also because boost::variant
// "picks" the wrong type when we try and use std::string, long (or
// int), double (or float), and bool all in the same variant (while it
// does work with explicit casts, it seemed bad style to force people
// to put those casts in place). We could have avoided using
// json::String or json::Number and just used std::string and double
// respectively, but we choose to include them for completeness
// (although, this does pay a 2x cost when compiling thanks to all the
// extra template instantiations).

// Note that all of these forward declarations are not necessary
// but it serves to document the set of types which are available.
struct String;
struct Number;
struct Object;
struct Array;
struct True;
struct False;
struct Boolean;
struct Null;
struct Value;

struct String
{
  String() {}
  String(const char* _value) : value(_value) {}
  String(const std::string& _value) : value(_value) {}
  std::string value;
};

struct Number
{
  Number() : value(0) {}
  Number(double _value) : value(_value) {}
  double value;
};

struct Object
{
  // Returns the JSON value (specified by the type) given a "path"
  // into the structure, for example:
  //
  //   Result<JSON::Array> array = object.find<JSON::Array>("nested.array");
  //
  // Will return 'None' if no field could be found called 'array'
  // within a field called 'nested' of 'object' (where 'nested' must
  // also be a JSON object).
  //
  // Returns an error if a JSON value of the wrong type is found, or
  // an intermediate JSON value is not an object that we can do a
  // recursive find on.
  //
  // TODO(benh): Support paths that index, e.g., 'nested.array[4].field'.
  template <typename T>
  Result<T> find(const std::string& path) const;

  std::map<std::string, Value> values;
};

struct Array
{
  std::list<Value> values;
};

struct Boolean
{
  Boolean() : value(false) {}
  Boolean(bool _value) : value(_value) {}
  bool value;
};

// This is a helper so you can say JSON::True() instead of
// JSON::Boolean(true).
struct True : Boolean
{
  True() : Boolean(true) {};
};

// This is a helper so you can say JSON::False() instead of
// JSON::Boolean(false).
struct False : Boolean
{
  False() : Boolean(false) {}
};

struct Null {};

namespace internal {

// Only Object and Array require recursive_wrapper, not sure
// if there is a reason to wrap the others or not.
// Null needs to be first so that it is the default value.
typedef boost::variant<boost::recursive_wrapper<Null>,
                       boost::recursive_wrapper<String>,
                       boost::recursive_wrapper<Number>,
                       boost::recursive_wrapper<Object>,
                       boost::recursive_wrapper<Array>,
                       boost::recursive_wrapper<Boolean> > Variant;

} // namespace internal {

struct Value : internal::Variant
{
  // Empty constructor gets the variant default.
  Value() {}

  Value(bool value) : internal::Variant(JSON::Boolean(value)) {}

  Value(char* value) : internal::Variant(JSON::String(value)) {}
  Value(const char* value) : internal::Variant(JSON::String(value)) {}

  // Arithmetic types are specifically routed through Number because
  // there would be ambiguity between JSON::Bool and JSON::Number
  // otherwise.
  template <typename T>
  Value(
      const T& value,
      typename boost::enable_if<boost::is_arithmetic<T>, int>::type = 0)
    : internal::Variant(Number(value)) {}

  // Non-arithmetic types are passed to the default constructor of
  // Variant.
  template <typename T>
  Value(
      const T& value,
      typename boost::disable_if<boost::is_arithmetic<T>, int>::type = 0)
    : internal::Variant(value) {}

  template <typename T>
  bool is() const;

  template <typename T>
  const T& as() const;
};

template <typename T>
bool Value::is() const
{
  const T* t = boost::get<T>(this);
  return t != NULL;
}

template <>
inline bool Value::is<Value>() const
{
  return true;
}

template <typename T>
const T& Value::as() const
{
  return *CHECK_NOTNULL(boost::get<T>(this));
}

template <>
inline const Value& Value::as<Value>() const
{
  return *this;
}

template <typename T>
Result<T> Object::find(const std::string& path) const
{
  const std::vector<std::string>& names = strings::split(path, ".", 2);

  if (names.empty()) {
    return None();
  }

  std::map<std::string, Value>::const_iterator entry = values.find(names[0]);

  if (entry == values.end()) {
    return None();
  }

  const Value& value = entry->second;

  if (names.size() == 1) {
    if (!value.is<T>()) {
      // TODO(benh): Use a visitor to print out the type found.
      return Error("Found JSON value of wrong type");
    }
    return value.as<T>();
  } else if (!value.is<Object>()) {
    // TODO(benh): Use a visitor to print out the intermediate type.
    return Error("Intermediate JSON value not an object");
  }

  return value.as<Object>().find<T>(names[1]);
}

struct Comparator : boost::static_visitor<bool>
{
  Comparator(const Value& _value)
    : value(_value) {}

  bool operator () (const Object& object) const
  {
    if (value.is<Object>()) {
      return value.as<Object>().values == object.values;
    }
    return false;
  }

  bool operator () (const String& string) const
  {
    if (value.is<String>()) {
      return value.as<String>().value == string.value;
    }
    return false;
  }

  bool operator () (const Number& number) const
  {
    if (value.is<Number>()) {
      return value.as<Number>().value == number.value;
    }
    return false;
  }

  bool operator () (const Array& array) const
  {
    if (value.is<Array>()) {
      return value.as<Array>().values == array.values;
    }
    return false;
  }

  bool operator () (const Boolean& boolean) const
  {
    if (value.is<Boolean>()) {
      return value.as<Boolean>().value == boolean.value;
    }
    return false;
  }

  bool operator () (const Null&) const
  {
    return value.is<Null>();
  }

private:
  const Value& value;
};

inline bool operator == (const Value& lhs, const Value& rhs)
{
  return boost::apply_visitor(Comparator(lhs), rhs);
}

inline std::ostream& operator << (std::ostream& out, const String& string)
{
  // TODO(benh): This escaping DOES NOT handle unicode, it encodes as ASCII.
  // See RFC4627 for the JSON string specificiation.
  out << "\"";
  foreach (unsigned char c, string.value) {
    switch (c) {
      case '"':  out << "\\\""; break;
      case '\\': out << "\\\\"; break;
      case '/':  out << "\\/";  break;
      case '\b': out << "\\b";  break;
      case '\f': out << "\\f";  break;
      case '\n': out << "\\n";  break;
      case '\r': out << "\\r";  break;
      case '\t': out << "\\t";  break;
      default:
        // See RFC4627 for these ranges.
        if ((c >= 0x20 && c <= 0x21) ||
            (c >= 0x23 && c <= 0x5B) ||
            (c >= 0x5D && c < 0x7F)) {
          out << c;
        } else {
          // NOTE: We also escape all bytes > 0x7F since they imply more than
          // 1 byte in UTF-8. This is why we don't escape UTF-8 properly.
          // See RFC4627 for the escaping format: \uXXXX (X is a hex digit).
          // Each byte here will be of the form: \u00XX (this is why we need
          // setw and the cast to unsigned int).
          out << "\\u" << std::setfill('0') << std::setw(4)
              << std::hex << std::uppercase << (unsigned int) c;
        }
        break;
    }
  }
  out << "\"";
  return out;
}

inline std::ostream& operator << (std::ostream& out, const Number& number)
{
  // Use the guaranteed accurate precision, see:
  // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2005.pdf
  return out << std::setprecision(std::numeric_limits<double>::digits10)
             << number.value;
}

inline std::ostream& operator << (std::ostream& out, const Object& object)
{
  out << "{";
  std::map<std::string, Value>::const_iterator iterator;
  iterator = object.values.begin();
  while (iterator != object.values.end()) {
    out << String((*iterator).first) << ":" << (*iterator).second;
    if (++iterator != object.values.end()) {
      out << ",";
    }
  }
  out << "}";
  return out;
}

inline std::ostream& operator << (std::ostream& out, const Array& array)
{
  out << "[";
  std::list<Value>::const_iterator iterator;
  iterator = array.values.begin();
  while (iterator != array.values.end()) {
    out << *iterator;
    if (++iterator != array.values.end()) {
      out << ",";
    }
  }
  out << "]";
  return out;
}

inline std::ostream& operator << (std::ostream& out, const Boolean& boolean)
{
  return out << (boolean.value ? "true" : "false");
}

inline std::ostream& operator << (std::ostream& out, const Null&)
{
  return out << "null";
}

namespace internal {

inline Value convert(const picojson::value& value)
{
  if (value.is<picojson::null>()) {
    return Null();
  } else if (value.is<bool>()) {
    return Boolean(value.get<bool>());
  } else if (value.is<picojson::value::object>()) {
    Object object;
    foreachpair (const std::string& name,
                 const picojson::value& value,
                 value.get<picojson::value::object>()) {
      object.values[name] = convert(value);
    }
    return object;
  } else if (value.is<picojson::value::array>()) {
    Array array;
    foreach (const picojson::value& value,
             value.get<picojson::value::array>()) {
      array.values.push_back(convert(value));
    }
    return array;
  } else if (value.is<double>()) {
    return Number(value.get<double>());
  } else if (value.is<std::string>()) {
    return String(value.get<std::string>());
  }
  return Null();
}

} // namespace internal {

inline Try<Value> parse(const std::string& s)
{
  picojson::value value;
  std::string error;

  picojson::parse(value, s.c_str(), s.c_str() + s.size(), &error);

  if (!error.empty()) {
    return Error(error);
  }

  return internal::convert(value);
}

template <typename T>
Try<T> parse(const std::string& s)
{
  Try<Value> value = parse(s);

  if (value.isError()) {
    return Error(value.error());
  }

  if (!value.get().is<T>()) {
    return Error("Unexpected JSON type parsed");
  }

  return value.get().as<T>();
}

template <>
inline Try<Value> parse(const std::string& s)
{
  return parse(s);
}

} // namespace JSON {

#endif // __STOUT_JSON__
<|endoftext|>


<commit_before><commit_msg>Added Insertion Sort<commit_after><|endoftext|>