<commit_before>/*
 Copyright (c) 2017 Tuukka Norri
 This code is licensed under MIT license (see LICENSE for details).
 */

#include <boost/format.hpp>
#include <cerrno>
#include <cmath>
#include <cstring>
#include <fcntl.h>
#include <iostream>
#include <map>
#include <vcf2multialign/check_overlapping_non_nested_variants.hh>
#include <vcf2multialign/generate_haplotypes.hh>
#include <vcf2multialign/read_single_fasta_seq.hh>
#include <vcf2multialign/types.hh>
#include <vcf2multialign/variant_handler.hh>

namespace ios	= boost::iostreams;
namespace v2m	= vcf2multialign;

namespace {

	void handle_file_error(char const *fname)
	{
		char const *errmsg(strerror(errno));
		std::cerr << "Got an error while trying to open '" << fname << "': " << errmsg << std::endl;
		exit(EXIT_FAILURE);
	}

	void open_file_for_reading(char const *fname, v2m::file_istream &stream)
	{
		int fd(open(fname, O_RDONLY));
		if (-1 == fd)
			handle_file_error(fname);

		ios::file_descriptor_source source(fd, ios::close_handle);
		stream.open(source);
		stream.exceptions(std::istream::badbit);
	}

	void open_file_for_writing(char const *fname, v2m::file_ostream &stream, bool const should_overwrite)
	{
		int fd(0);
		if (should_overwrite)
			fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
		else
			fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);

		if (-1 == fd)
			handle_file_error(fname);

		ios::file_descriptor_sink sink(fd, ios::close_handle);
		stream.open(sink);
	}

	bool compare_references(v2m::vector_type const &ref, std::string_view const &var_ref, std::size_t const var_pos, std::size_t /* out */ &idx)
	{
		char const *var_ref_data(var_ref.data());
		auto const var_ref_len(var_ref.size());

		char const *ref_data(ref.data());
		auto const ref_len(ref.size());

		if (! (var_pos + var_ref_len <= ref_len))
		{
			idx = 0;
			return false;
		}

		auto const var_ref_end(var_ref_data + var_ref_len);
		auto const p(std::mismatch(var_ref_data, var_ref_end, ref_data + var_pos));
		if (var_ref_end != p.first)
		{
			idx = p.first - var_ref_data;
			return false;
		}

		return true;
	}

	class generate_context
	{
	protected:
		typedef std::map <std::size_t, std::size_t> ploidy_map;

	protected:
		v2m::variant_handler								m_variant_handler;
		dispatch_queue_t									m_main_queue{};
		dispatch_queue_t									m_parsing_queue{};
		v2m::vector_type									m_reference;
		v2m::file_istream									m_vcf_stream;
		v2m::vcf_reader										m_vcf_reader;

		v2m::error_logger									m_error_logger;

		ploidy_map											m_ploidy;
		v2m::haplotype_map									m_haplotypes;
		v2m::variant_set									m_skipped_variants;

		std::string											m_null_allele_seq;
		v2m::vcf_reader::sample_name_map::const_iterator	m_sample_names_it{};
		v2m::vcf_reader::sample_name_map::const_iterator	m_sample_names_end{};
		std::size_t											m_chunk_size{0};
		std::size_t											m_current_round{0};
		std::size_t											m_total_rounds{0};
		bool												m_should_overwrite_files{false};

	public:
		generate_context(
			dispatch_queue_t main_queue,
			dispatch_queue_t parsing_queue,
			char const *null_allele_seq,
			std::size_t const chunk_size,
			bool const should_overwrite_files
		):
			m_main_queue(main_queue),
			m_parsing_queue(parsing_queue),
			m_null_allele_seq(null_allele_seq),
			m_chunk_size(chunk_size),
			m_should_overwrite_files(should_overwrite_files)
		{
			dispatch_retain(m_main_queue);
			dispatch_retain(m_parsing_queue);
		}

		generate_context(generate_context const &) = delete;
		generate_context(generate_context &&) = delete;

		~generate_context()
		{
			dispatch_release(m_main_queue);
			dispatch_release(m_parsing_queue);
		}

		void cleanup() { delete this; }

		void check_ploidy()
		{
			size_t i(0);
			m_vcf_reader.reset();
			m_vcf_reader.set_parsed_fields(v2m::vcf_field::ALL);
			v2m::variant var(m_vcf_reader.sample_count());
			var.add_format_field("GT");

			if (!m_vcf_reader.get_next_variant(var))
				throw std::runtime_error("Unable to read the first variant");

			var.prepare_samples();
			v2m::variant::sample_field_vector sample_fields;
			v2m::variant::genotype_vector gtv;
			bool is_phased(false);

			for (auto const &kv : m_vcf_reader.sample_names())
			{
				auto const sample_no(kv.second);
				var.parse_sample(sample_no, sample_fields);
				var.get_genotype(sample_fields, gtv, is_phased);
				m_ploidy[sample_no] = gtv.size();
			}
		}

		void check_ref()
		{
			m_vcf_reader.reset();
			m_vcf_reader.set_parsed_fields(v2m::vcf_field::REF);
			v2m::variant var;
			bool found_mismatch(false);
			std::size_t i(0);

			while (m_vcf_reader.get_next_variant(var))
			{
				auto const var_ref(var.ref());
				auto const var_pos(var.zero_based_pos());
				auto const lineno(var.lineno());
				std::size_t diff_pos{0};

				if (!compare_references(m_reference, var_ref, var_pos, diff_pos))
				{
					if (!found_mismatch)
					{
						found_mismatch = true;
						std::cerr << "Reference differs from the variant file on line " << lineno << " (and possibly others)." << std::endl;
					}

					m_error_logger.log_ref_mismatch(lineno, diff_pos);
				}

				++i;
				if (0 == i % 100000)
					std::cerr << "Handled " << i << " variants…" << std::endl;
			}
		}

		void update_haplotypes(char const *out_reference_fname)
		{
			m_haplotypes.clear();

			size_t i(1);
			while (m_sample_names_it != m_sample_names_end)
			{
				auto const &sample_name(m_sample_names_it->first);
				auto const sample_no(m_sample_names_it->second);
				auto const current_ploidy(m_ploidy.find(sample_no)->second);

				// Since file_ostream is not movable, check first if the vector has already been created.
				// If not, create it with the exact size to avoid resizing and thus moving later.
				auto it(m_haplotypes.find(sample_no));
				if (m_haplotypes.end() == it)
				{
					it = m_haplotypes.emplace(
						std::piecewise_construct,
						std::forward_as_tuple(sample_no),
						std::forward_as_tuple(current_ploidy)
					).first;
				}

				auto &haplotype_vec(it->second);

				for (size_t i(1); i <= current_ploidy; ++i)
				{
					auto const fname(boost::str(boost::format("%s-%u") % sample_name % i));
					open_file_for_writing(fname.c_str(), haplotype_vec[i - 1].output_stream, m_should_overwrite_files);
				}

				++m_sample_names_it;
				++i;

				if (i == m_chunk_size)
					break;
			}

			// Check if reference output was requested.
			if (out_reference_fname)
			{
				if (m_haplotypes.cend() != m_haplotypes.find(v2m::REF_SAMPLE_NUMBER))
					throw std::runtime_error("REF_SAMPLE_NUMBER already in use");

				auto it(m_haplotypes.emplace(
					std::piecewise_construct,
					std::forward_as_tuple(0),
					std::forward_as_tuple(1)
				).first);

				auto &haplotype_vec(it->second);
				open_file_for_writing(out_reference_fname, haplotype_vec[0].output_stream, m_should_overwrite_files);
			}
		}

		// Handle m_chunk_size samples.
		void generate_sequences(char const *out_reference_fname = nullptr)
		{
			// Open files for the samples. If no files were opened, exit.
			update_haplotypes(out_reference_fname);
			if (0 == m_haplotypes.size())
			{
				// After calling cleanup *this is no longer valid.
				//std::cerr << "Calling cleanup" << std::endl;
				cleanup();

				//std::cerr << "Calling exit" << std::endl;
				exit(EXIT_SUCCESS);
			}

			++m_current_round;
			std::cerr << "Round " << m_current_round << '/' << m_total_rounds << std::endl;
			m_variant_handler.process_variants(m_haplotypes);
		}

		void load_and_generate(
			char const *reference_fname,
			char const *variants_fname,
			char const *out_reference_fname,
			char const *report_fname,
			bool const should_check_ref
		)
		{
			// Open the files.
			std::cerr << "Opening files…" << std::endl;
			{
				v2m::file_istream ref_fasta_stream;

				open_file_for_reading(reference_fname, ref_fasta_stream);
				open_file_for_reading(variants_fname, m_vcf_stream);

				if (report_fname)
				{
					open_file_for_writing(report_fname, m_error_logger.output_stream(), m_should_overwrite_files);
					m_error_logger.write_header();
				}

				m_vcf_reader.set_stream(m_vcf_stream);
				m_vcf_reader.read_header();

				auto const &sample_names(m_vcf_reader.sample_names());
				m_sample_names_it = sample_names.cbegin();
				m_sample_names_end = sample_names.cend();

				auto const sample_count(sample_names.size());
				m_total_rounds = std::ceil(1.0 * sample_count / m_chunk_size);

				// Read the reference file and place its contents into reference.
				v2m::read_single_fasta_seq(ref_fasta_stream, m_reference);
			}

			// Check ploidy from the first record.
			std::cerr << "Checking ploidy…" << std::endl;
			check_ploidy();

			// Compare REF to the reference vector.
			if (should_check_ref)
			{
				std::cerr << "Comparing the REF column to the reference…" << std::endl;
				check_ref();
			}

			// List variants that conflict, i.e. overlap but are not nested.
			{
				std::cerr << "Checking overlapping variants…" << std::endl;
				auto const conflict_count(v2m::check_overlapping_non_nested_variants(
					m_vcf_reader,
					m_skipped_variants,
					m_error_logger
				));

				auto const skipped_count(m_skipped_variants.size());
				if (0 == skipped_count)
					std::cerr << "Found no conflicting variants." << std::endl;
				else
				{
					std::cerr << "Found " << conflict_count << " conflicts in total." << std::endl;
					std::cerr << "Number of variants to be skipped: " << m_skipped_variants.size() << std::endl;
				}
			}

			// Replace the placeholder variant_handler.
			{
				v2m::variant_handler temp(
					m_main_queue,
					m_parsing_queue,
					m_vcf_reader,
					m_reference,
					m_skipped_variants,
					m_null_allele_seq,
					m_error_logger,
					[this](){ generate_sequences(); }
				);

				m_variant_handler = std::move(temp);
			}

			std::cerr << "Generating haplotype sequences…" << std::endl;
			generate_sequences(out_reference_fname);
		}
	};
}

namespace vcf2multialign {

	void generate_haplotypes(
		char const *reference_fname,
		char const *variants_fname,
		char const *out_reference_fname,
		char const *report_fname,
		char const *null_allele_seq,
		std::size_t const chunk_size,
		bool const should_overwrite_files,
		bool const should_check_ref
	)
	{
		dispatch_queue_t main_queue(dispatch_get_main_queue());
		dispatch_queue_t parsing_queue(dispatch_queue_create("fi.iki.tsnorri.vcf2multialign.parsing_queue", DISPATCH_QUEUE_CONCURRENT));

		// generate_context needs to be allocated on the heap because later dispatch_main is called.
		// The class deallocates itself in cleanup().
		generate_context *ctx(new generate_context(
			main_queue,
			parsing_queue,
			null_allele_seq,
			chunk_size,
			should_overwrite_files
		));

		ctx->load_and_generate(
			reference_fname,
			variants_fname,
			out_reference_fname,
			report_fname,
			should_check_ref
		);

		// Calls pthread_exit.
		dispatch_main();
	}
}
<commit_msg>Fix off-by-one<commit_after>/*
 Copyright (c) 2017 Tuukka Norri
 This code is licensed under MIT license (see LICENSE for details).
 */

#include <boost/format.hpp>
#include <cerrno>
#include <cmath>
#include <cstring>
#include <fcntl.h>
#include <iostream>
#include <map>
#include <vcf2multialign/check_overlapping_non_nested_variants.hh>
#include <vcf2multialign/generate_haplotypes.hh>
#include <vcf2multialign/read_single_fasta_seq.hh>
#include <vcf2multialign/types.hh>
#include <vcf2multialign/variant_handler.hh>

namespace ios	= boost::iostreams;
namespace v2m	= vcf2multialign;

namespace {

	void handle_file_error(char const *fname)
	{
		char const *errmsg(strerror(errno));
		std::cerr << "Got an error while trying to open '" << fname << "': " << errmsg << std::endl;
		exit(EXIT_FAILURE);
	}

	void open_file_for_reading(char const *fname, v2m::file_istream &stream)
	{
		int fd(open(fname, O_RDONLY));
		if (-1 == fd)
			handle_file_error(fname);

		ios::file_descriptor_source source(fd, ios::close_handle);
		stream.open(source);
		stream.exceptions(std::istream::badbit);
	}

	void open_file_for_writing(char const *fname, v2m::file_ostream &stream, bool const should_overwrite)
	{
		int fd(0);
		if (should_overwrite)
			fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
		else
			fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);

		if (-1 == fd)
			handle_file_error(fname);

		ios::file_descriptor_sink sink(fd, ios::close_handle);
		stream.open(sink);
	}

	bool compare_references(v2m::vector_type const &ref, std::string_view const &var_ref, std::size_t const var_pos, std::size_t /* out */ &idx)
	{
		char const *var_ref_data(var_ref.data());
		auto const var_ref_len(var_ref.size());

		char const *ref_data(ref.data());
		auto const ref_len(ref.size());

		if (! (var_pos + var_ref_len <= ref_len))
		{
			idx = 0;
			return false;
		}

		auto const var_ref_end(var_ref_data + var_ref_len);
		auto const p(std::mismatch(var_ref_data, var_ref_end, ref_data + var_pos));
		if (var_ref_end != p.first)
		{
			idx = p.first - var_ref_data;
			return false;
		}

		return true;
	}

	class generate_context
	{
	protected:
		typedef std::map <std::size_t, std::size_t> ploidy_map;

	protected:
		v2m::variant_handler								m_variant_handler;
		dispatch_queue_t									m_main_queue{};
		dispatch_queue_t									m_parsing_queue{};
		v2m::vector_type									m_reference;
		v2m::file_istream									m_vcf_stream;
		v2m::vcf_reader										m_vcf_reader;

		v2m::error_logger									m_error_logger;

		ploidy_map											m_ploidy;
		v2m::haplotype_map									m_haplotypes;
		v2m::variant_set									m_skipped_variants;

		std::string											m_null_allele_seq;
		v2m::vcf_reader::sample_name_map::const_iterator	m_sample_names_it{};
		v2m::vcf_reader::sample_name_map::const_iterator	m_sample_names_end{};
		std::size_t											m_chunk_size{0};
		std::size_t											m_current_round{0};
		std::size_t											m_total_rounds{0};
		bool												m_should_overwrite_files{false};

	public:
		generate_context(
			dispatch_queue_t main_queue,
			dispatch_queue_t parsing_queue,
			char const *null_allele_seq,
			std::size_t const chunk_size,
			bool const should_overwrite_files
		):
			m_main_queue(main_queue),
			m_parsing_queue(parsing_queue),
			m_null_allele_seq(null_allele_seq),
			m_chunk_size(chunk_size),
			m_should_overwrite_files(should_overwrite_files)
		{
			dispatch_retain(m_main_queue);
			dispatch_retain(m_parsing_queue);
		}

		generate_context(generate_context const &) = delete;
		generate_context(generate_context &&) = delete;

		~generate_context()
		{
			dispatch_release(m_main_queue);
			dispatch_release(m_parsing_queue);
		}

		void cleanup() { delete this; }

		void check_ploidy()
		{
			size_t i(0);
			m_vcf_reader.reset();
			m_vcf_reader.set_parsed_fields(v2m::vcf_field::ALL);
			v2m::variant var(m_vcf_reader.sample_count());
			var.add_format_field("GT");

			if (!m_vcf_reader.get_next_variant(var))
				throw std::runtime_error("Unable to read the first variant");

			var.prepare_samples();
			v2m::variant::sample_field_vector sample_fields;
			v2m::variant::genotype_vector gtv;
			bool is_phased(false);

			for (auto const &kv : m_vcf_reader.sample_names())
			{
				auto const sample_no(kv.second);
				var.parse_sample(sample_no, sample_fields);
				var.get_genotype(sample_fields, gtv, is_phased);
				m_ploidy[sample_no] = gtv.size();
			}
		}

		void check_ref()
		{
			m_vcf_reader.reset();
			m_vcf_reader.set_parsed_fields(v2m::vcf_field::REF);
			v2m::variant var;
			bool found_mismatch(false);
			std::size_t i(0);

			while (m_vcf_reader.get_next_variant(var))
			{
				auto const var_ref(var.ref());
				auto const var_pos(var.zero_based_pos());
				auto const lineno(var.lineno());
				std::size_t diff_pos{0};

				if (!compare_references(m_reference, var_ref, var_pos, diff_pos))
				{
					if (!found_mismatch)
					{
						found_mismatch = true;
						std::cerr << "Reference differs from the variant file on line " << lineno << " (and possibly others)." << std::endl;
					}

					m_error_logger.log_ref_mismatch(lineno, diff_pos);
				}

				++i;
				if (0 == i % 100000)
					std::cerr << "Handled " << i << " variants…" << std::endl;
			}
		}

		void update_haplotypes(char const *out_reference_fname)
		{
			m_haplotypes.clear();

			size_t i(0);
			while (m_sample_names_it != m_sample_names_end)
			{
				auto const &sample_name(m_sample_names_it->first);
				auto const sample_no(m_sample_names_it->second);
				auto const current_ploidy(m_ploidy.find(sample_no)->second);

				// Since file_ostream is not movable, check first if the vector has already been created.
				// If not, create it with the exact size to avoid resizing and thus moving later.
				auto it(m_haplotypes.find(sample_no));
				if (m_haplotypes.end() == it)
				{
					it = m_haplotypes.emplace(
						std::piecewise_construct,
						std::forward_as_tuple(sample_no),
						std::forward_as_tuple(current_ploidy)
					).first;
				}

				auto &haplotype_vec(it->second);

				for (size_t i(1); i <= current_ploidy; ++i)
				{
					auto const fname(boost::str(boost::format("%s-%u") % sample_name % i));
					open_file_for_writing(fname.c_str(), haplotype_vec[i - 1].output_stream, m_should_overwrite_files);
				}

				++m_sample_names_it;
				++i;

				if (i == m_chunk_size)
					break;
			}

			// Check if reference output was requested.
			if (out_reference_fname)
			{
				if (m_haplotypes.cend() != m_haplotypes.find(v2m::REF_SAMPLE_NUMBER))
					throw std::runtime_error("REF_SAMPLE_NUMBER already in use");

				auto it(m_haplotypes.emplace(
					std::piecewise_construct,
					std::forward_as_tuple(0),
					std::forward_as_tuple(1)
				).first);

				auto &haplotype_vec(it->second);
				open_file_for_writing(out_reference_fname, haplotype_vec[0].output_stream, m_should_overwrite_files);
			}
		}

		// Handle m_chunk_size samples.
		void generate_sequences(char const *out_reference_fname = nullptr)
		{
			// Open files for the samples. If no files were opened, exit.
			update_haplotypes(out_reference_fname);
			if (0 == m_haplotypes.size())
			{
				// After calling cleanup *this is no longer valid.
				//std::cerr << "Calling cleanup" << std::endl;
				cleanup();

				//std::cerr << "Calling exit" << std::endl;
				exit(EXIT_SUCCESS);
			}

			++m_current_round;
			std::cerr << "Round " << m_current_round << '/' << m_total_rounds << std::endl;
			m_variant_handler.process_variants(m_haplotypes);
		}

		void load_and_generate(
			char const *reference_fname,
			char const *variants_fname,
			char const *out_reference_fname,
			char const *report_fname,
			bool const should_check_ref
		)
		{
			// Open the files.
			std::cerr << "Opening files…" << std::endl;
			{
				v2m::file_istream ref_fasta_stream;

				open_file_for_reading(reference_fname, ref_fasta_stream);
				open_file_for_reading(variants_fname, m_vcf_stream);

				if (report_fname)
				{
					open_file_for_writing(report_fname, m_error_logger.output_stream(), m_should_overwrite_files);
					m_error_logger.write_header();
				}

				m_vcf_reader.set_stream(m_vcf_stream);
				m_vcf_reader.read_header();

				auto const &sample_names(m_vcf_reader.sample_names());
				m_sample_names_it = sample_names.cbegin();
				m_sample_names_end = sample_names.cend();

				auto const sample_count(sample_names.size());
				m_total_rounds = std::ceil(1.0 * sample_count / m_chunk_size);

				// Read the reference file and place its contents into reference.
				v2m::read_single_fasta_seq(ref_fasta_stream, m_reference);
			}

			// Check ploidy from the first record.
			std::cerr << "Checking ploidy…" << std::endl;
			check_ploidy();

			// Compare REF to the reference vector.
			if (should_check_ref)
			{
				std::cerr << "Comparing the REF column to the reference…" << std::endl;
				check_ref();
			}

			// List variants that conflict, i.e. overlap but are not nested.
			{
				std::cerr << "Checking overlapping variants…" << std::endl;
				auto const conflict_count(v2m::check_overlapping_non_nested_variants(
					m_vcf_reader,
					m_skipped_variants,
					m_error_logger
				));

				auto const skipped_count(m_skipped_variants.size());
				if (0 == skipped_count)
					std::cerr << "Found no conflicting variants." << std::endl;
				else
				{
					std::cerr << "Found " << conflict_count << " conflicts in total." << std::endl;
					std::cerr << "Number of variants to be skipped: " << m_skipped_variants.size() << std::endl;
				}
			}

			// Replace the placeholder variant_handler.
			{
				v2m::variant_handler temp(
					m_main_queue,
					m_parsing_queue,
					m_vcf_reader,
					m_reference,
					m_skipped_variants,
					m_null_allele_seq,
					m_error_logger,
					[this](){ generate_sequences(); }
				);

				m_variant_handler = std::move(temp);
			}

			std::cerr << "Generating haplotype sequences…" << std::endl;
			generate_sequences(out_reference_fname);
		}
	};
}

namespace vcf2multialign {

	void generate_haplotypes(
		char const *reference_fname,
		char const *variants_fname,
		char const *out_reference_fname,
		char const *report_fname,
		char const *null_allele_seq,
		std::size_t const chunk_size,
		bool const should_overwrite_files,
		bool const should_check_ref
	)
	{
		dispatch_queue_t main_queue(dispatch_get_main_queue());
		dispatch_queue_t parsing_queue(dispatch_queue_create("fi.iki.tsnorri.vcf2multialign.parsing_queue", DISPATCH_QUEUE_CONCURRENT));

		// generate_context needs to be allocated on the heap because later dispatch_main is called.
		// The class deallocates itself in cleanup().
		generate_context *ctx(new generate_context(
			main_queue,
			parsing_queue,
			null_allele_seq,
			chunk_size,
			should_overwrite_files
		));

		ctx->load_and_generate(
			reference_fname,
			variants_fname,
			out_reference_fname,
			report_fname,
			should_check_ref
		);

		// Calls pthread_exit.
		dispatch_main();
	}
}
<|endoftext|>


<commit_before>#include <occa/io/output.hpp>
#include <occa/lang/modes/openmp.hpp>
#include <occa/modes/serial/device.hpp>
#include <occa/modes/openmp/device.hpp>
#include <occa/modes/openmp/utils.hpp>

namespace occa {
  namespace openmp {
    device::device(const occa::properties &properties_) :
      serial::device(properties_) {}

    hash_t device::kernelHash(const occa::properties &props) const {
      return (
        occa::hash(props["vendor"])
        ^ props["compiler"]
        ^ props["compiler_flags"]
        ^ props["compiler_env_script"]
      );
    }

    bool device::parseFile(const std::string &filename,
                           const std::string &outputFile,
                           const occa::properties &kernelProps,
                           lang::sourceMetadata_t &metadata) {
      lang::okl::openmpParser parser(kernelProps);
      parser.parseFile(filename);

      // Verify if parsing succeeded
      if (!parser.succeeded()) {
        if (!kernelProps.get("silent", false)) {
          OCCA_FORCE_ERROR("Unable to transform OKL kernel");
        }
        return false;
      }

      if (!io::isFile(outputFile)) {
        hash_t hash = occa::hash(outputFile);
        io::lock_t lock(hash, "openmp-parser");
        if (lock.isMine()) {
          parser.writeToFile(outputFile);
        }
      }

      parser.setSourceMetadata(metadata);

      return true;
    }

    modeKernel_t* device::buildKernel(const std::string &filename,
                                      const std::string &kernelName,
                                      const hash_t kernelHash,
                                      const occa::properties &kernelProps) {

      occa::properties allKernelProps = properties + kernelProps;

      std::string compiler = allKernelProps["compiler"];
      int vendor = allKernelProps["vendor"];
      // Check if we need to re-compute the vendor
      if (kernelProps.has("compiler")) {
        vendor = sys::compilerVendor(compiler);
      }

      if (compiler != lastCompiler) {
        lastCompiler = compiler;
        lastCompilerOpenMPFlag = openmp::compilerFlag(vendor, compiler);

        if (lastCompilerOpenMPFlag == openmp::notSupported) {
          io::stderr << "Compiler [" << (std::string) allKernelProps["compiler"]
                     << "] does not support OpenMP, defaulting to [Serial] mode\n";
        }
      }

      const bool usingOpenMP = (lastCompilerOpenMPFlag != openmp::notSupported);
      if (usingOpenMP) {
        allKernelProps["compiler_flags"] += " " + lastCompilerOpenMPFlag;
      }

      modeKernel_t *k = serial::device::buildKernel(filename,
                                                    kernelName,
                                                    kernelHash,
                                                    allKernelProps);

      if (k && usingOpenMP) {
        k->modeDevice->removeKernelRef(k);
        k->modeDevice = this;
        addKernelRef(k);
      }

      return k;
    }
  }
}
<commit_msg>[OpenMP] Avoid generating same kernel hash as Serial mode (#289)<commit_after>#include <occa/io/output.hpp>
#include <occa/lang/modes/openmp.hpp>
#include <occa/modes/serial/device.hpp>
#include <occa/modes/openmp/device.hpp>
#include <occa/modes/openmp/utils.hpp>

namespace occa {
  namespace openmp {
    device::device(const occa::properties &properties_) :
      serial::device(properties_) {}

    hash_t device::kernelHash(const occa::properties &props) const {
      return (
        occa::hash(props["vendor"])
        ^ occa::hash("openmp")
        ^ props["compiler"]
        ^ props["compiler_flags"]
        ^ props["compiler_env_script"]
      );
    }

    bool device::parseFile(const std::string &filename,
                           const std::string &outputFile,
                           const occa::properties &kernelProps,
                           lang::sourceMetadata_t &metadata) {
      lang::okl::openmpParser parser(kernelProps);
      parser.parseFile(filename);

      // Verify if parsing succeeded
      if (!parser.succeeded()) {
        if (!kernelProps.get("silent", false)) {
          OCCA_FORCE_ERROR("Unable to transform OKL kernel");
        }
        return false;
      }

      if (!io::isFile(outputFile)) {
        hash_t hash = occa::hash(outputFile);
        io::lock_t lock(hash, "openmp-parser");
        if (lock.isMine()) {
          parser.writeToFile(outputFile);
        }
      }

      parser.setSourceMetadata(metadata);

      return true;
    }

    modeKernel_t* device::buildKernel(const std::string &filename,
                                      const std::string &kernelName,
                                      const hash_t kernelHash,
                                      const occa::properties &kernelProps) {

      occa::properties allKernelProps = properties + kernelProps;

      std::string compiler = allKernelProps["compiler"];
      int vendor = allKernelProps["vendor"];
      // Check if we need to re-compute the vendor
      if (kernelProps.has("compiler")) {
        vendor = sys::compilerVendor(compiler);
      }

      if (compiler != lastCompiler) {
        lastCompiler = compiler;
        lastCompilerOpenMPFlag = openmp::compilerFlag(vendor, compiler);

        if (lastCompilerOpenMPFlag == openmp::notSupported) {
          io::stderr << "Compiler [" << (std::string) allKernelProps["compiler"]
                     << "] does not support OpenMP, defaulting to [Serial] mode\n";
        }
      }

      const bool usingOpenMP = (lastCompilerOpenMPFlag != openmp::notSupported);
      if (usingOpenMP) {
        allKernelProps["compiler_flags"] += " " + lastCompilerOpenMPFlag;
      }

      modeKernel_t *k = serial::device::buildKernel(filename,
                                                    kernelName,
                                                    kernelHash,
                                                    allKernelProps);

      if (k && usingOpenMP) {
        k->modeDevice->removeKernelRef(k);
        k->modeDevice = this;
        addKernelRef(k);
      }

      return k;
    }
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 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 "net/base/file_stream.h"

#include "base/location.h"
#include "base/message_loop_proxy.h"
#include "base/task_runner_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/worker_pool.h"
#include "net/base/file_stream_context.h"
#include "net/base/file_stream_net_log_parameters.h"
#include "net/base/net_errors.h"

namespace net {

FileStream::FileStream(NetLog* net_log)
      /* To allow never opened stream to be destroyed on any thread we set flags
         as if stream was opened asynchronously. */
    : open_flags_(base::PLATFORM_FILE_ASYNC),
      bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
      context_(new Context(bound_net_log_)) {
  bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
}

FileStream::FileStream(base::PlatformFile file, int flags, NetLog* net_log)
    : open_flags_(flags),
      bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
      context_(new Context(file, bound_net_log_, open_flags_)) {
  bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
}

FileStream::~FileStream() {
  if (!is_async()) {
    base::ThreadRestrictions::AssertIOAllowed();
    context_->CloseSync();
    context_.reset();
  } else {
    context_.release()->Orphan();
  }

  bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
}

int FileStream::Open(const FilePath& path, int open_flags,
                     const CompletionCallback& callback) {
  if (IsOpen()) {
    DLOG(FATAL) << "File is already open!";
    return ERR_UNEXPECTED;
  }

  open_flags_ = open_flags;
  DCHECK(is_async());
  context_->OpenAsync(path, open_flags, callback);
  return ERR_IO_PENDING;
}

int FileStream::OpenSync(const FilePath& path, int open_flags) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (IsOpen()) {
    DLOG(FATAL) << "File is already open!";
    return ERR_UNEXPECTED;
  }

  open_flags_ = open_flags;
  // TODO(satorux): Put a DCHECK once all async clients are migrated
  // to use Open(). crbug.com/114783
  //
  // DCHECK(!is_async());
  return context_->OpenSync(path, open_flags_);
}

bool FileStream::IsOpen() const {
  return context_->file() != base::kInvalidPlatformFileValue;
}

int FileStream::Seek(Whence whence,
                     int64 offset,
                     const Int64CompletionCallback& callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // Make sure we're async.
  DCHECK(is_async());
  context_->SeekAsync(whence, offset, callback);
  return ERR_IO_PENDING;
}

int64 FileStream::SeekSync(Whence whence, int64 offset) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  // If we're in async, make sure we don't have a request in flight.
  DCHECK(!is_async() || !context_->async_in_progress());
  return context_->SeekSync(whence, offset);
}

int64 FileStream::Available() {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  int64 cur_pos = SeekSync(FROM_CURRENT, 0);
  if (cur_pos < 0)
    return cur_pos;

  int64 size = context_->GetFileSize();
  if (size < 0)
    return size;

  DCHECK_GT(size, cur_pos);
  return size - cur_pos;
}

int FileStream::Read(IOBuffer* buf,
                     int buf_len,
                     const CompletionCallback& callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // read(..., 0) will return 0, which indicates end-of-file.
  DCHECK_GT(buf_len, 0);
  DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
  DCHECK(is_async());

  return context_->ReadAsync(buf, buf_len, callback);
}

int FileStream::ReadSync(char* buf, int buf_len) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  DCHECK(!is_async());
  // read(..., 0) will return 0, which indicates end-of-file.
  DCHECK_GT(buf_len, 0);
  DCHECK(open_flags_ & base::PLATFORM_FILE_READ);

  return context_->ReadSync(buf, buf_len);
}

int FileStream::ReadUntilComplete(char *buf, int buf_len) {
  base::ThreadRestrictions::AssertIOAllowed();

  int to_read = buf_len;
  int bytes_total = 0;

  do {
    int bytes_read = ReadSync(buf, to_read);
    if (bytes_read <= 0) {
      if (bytes_total == 0)
        return bytes_read;

      return bytes_total;
    }

    bytes_total += bytes_read;
    buf += bytes_read;
    to_read -= bytes_read;
  } while (bytes_total < buf_len);

  return bytes_total;
}

int FileStream::Write(IOBuffer* buf,
                      int buf_len,
                      const CompletionCallback& callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  DCHECK(is_async());
  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
  // write(..., 0) will return 0, which indicates end-of-file.
  DCHECK_GT(buf_len, 0);

  return context_->WriteAsync(buf, buf_len, callback);
}

int FileStream::WriteSync(const char* buf, int buf_len) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  DCHECK(!is_async());
  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
  // write(..., 0) will return 0, which indicates end-of-file.
  DCHECK_GT(buf_len, 0);

  return context_->WriteSync(buf, buf_len);
}

int64 FileStream::Truncate(int64 bytes) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  // We'd better be open for writing.
  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);

  // Seek to the position to truncate from.
  int64 seek_position = SeekSync(FROM_BEGIN, bytes);
  if (seek_position != bytes)
    return ERR_UNEXPECTED;

  // And truncate the file.
  return context_->Truncate(bytes);
}

int FileStream::Flush(const CompletionCallback& callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
  // Make sure we're async.
  DCHECK(is_async());

  context_->FlushAsync(callback);
  return ERR_IO_PENDING;
}

int FileStream::FlushSync() {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
  return context_->FlushSync();
}

void FileStream::EnableErrorStatistics() {
  context_->set_record_uma(true);
}

void FileStream::SetBoundNetLogSource(const BoundNetLog& owner_bound_net_log) {
  if ((owner_bound_net_log.source().id == NetLog::Source::kInvalidId) &&
      (bound_net_log_.source().id == NetLog::Source::kInvalidId)) {
    // Both |BoundNetLog|s are invalid.
    return;
  }

  // Should never connect to itself.
  DCHECK_NE(bound_net_log_.source().id, owner_bound_net_log.source().id);

  bound_net_log_.AddEvent(NetLog::TYPE_FILE_STREAM_BOUND_TO_OWNER,
      owner_bound_net_log.source().ToEventParametersCallback());

  owner_bound_net_log.AddEvent(NetLog::TYPE_FILE_STREAM_SOURCE,
      bound_net_log_.source().ToEventParametersCallback());
}

base::PlatformFile FileStream::GetPlatformFileForTesting() {
  return context_->file();
}

}  // namespace net
<commit_msg>net::FileStream::Available() should be callable when the available bytes = 0.<commit_after>// Copyright (c) 2012 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 "net/base/file_stream.h"

#include "base/location.h"
#include "base/message_loop_proxy.h"
#include "base/task_runner_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/worker_pool.h"
#include "net/base/file_stream_context.h"
#include "net/base/file_stream_net_log_parameters.h"
#include "net/base/net_errors.h"

namespace net {

FileStream::FileStream(NetLog* net_log)
      /* To allow never opened stream to be destroyed on any thread we set flags
         as if stream was opened asynchronously. */
    : open_flags_(base::PLATFORM_FILE_ASYNC),
      bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
      context_(new Context(bound_net_log_)) {
  bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
}

FileStream::FileStream(base::PlatformFile file, int flags, NetLog* net_log)
    : open_flags_(flags),
      bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
      context_(new Context(file, bound_net_log_, open_flags_)) {
  bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
}

FileStream::~FileStream() {
  if (!is_async()) {
    base::ThreadRestrictions::AssertIOAllowed();
    context_->CloseSync();
    context_.reset();
  } else {
    context_.release()->Orphan();
  }

  bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
}

int FileStream::Open(const FilePath& path, int open_flags,
                     const CompletionCallback& callback) {
  if (IsOpen()) {
    DLOG(FATAL) << "File is already open!";
    return ERR_UNEXPECTED;
  }

  open_flags_ = open_flags;
  DCHECK(is_async());
  context_->OpenAsync(path, open_flags, callback);
  return ERR_IO_PENDING;
}

int FileStream::OpenSync(const FilePath& path, int open_flags) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (IsOpen()) {
    DLOG(FATAL) << "File is already open!";
    return ERR_UNEXPECTED;
  }

  open_flags_ = open_flags;
  // TODO(satorux): Put a DCHECK once all async clients are migrated
  // to use Open(). crbug.com/114783
  //
  // DCHECK(!is_async());
  return context_->OpenSync(path, open_flags_);
}

bool FileStream::IsOpen() const {
  return context_->file() != base::kInvalidPlatformFileValue;
}

int FileStream::Seek(Whence whence,
                     int64 offset,
                     const Int64CompletionCallback& callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // Make sure we're async.
  DCHECK(is_async());
  context_->SeekAsync(whence, offset, callback);
  return ERR_IO_PENDING;
}

int64 FileStream::SeekSync(Whence whence, int64 offset) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  // If we're in async, make sure we don't have a request in flight.
  DCHECK(!is_async() || !context_->async_in_progress());
  return context_->SeekSync(whence, offset);
}

int64 FileStream::Available() {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  int64 cur_pos = SeekSync(FROM_CURRENT, 0);
  if (cur_pos < 0)
    return cur_pos;

  int64 size = context_->GetFileSize();
  if (size < 0)
    return size;

  DCHECK_GE(size, cur_pos);
  return size - cur_pos;
}

int FileStream::Read(IOBuffer* buf,
                     int buf_len,
                     const CompletionCallback& callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // read(..., 0) will return 0, which indicates end-of-file.
  DCHECK_GT(buf_len, 0);
  DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
  DCHECK(is_async());

  return context_->ReadAsync(buf, buf_len, callback);
}

int FileStream::ReadSync(char* buf, int buf_len) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  DCHECK(!is_async());
  // read(..., 0) will return 0, which indicates end-of-file.
  DCHECK_GT(buf_len, 0);
  DCHECK(open_flags_ & base::PLATFORM_FILE_READ);

  return context_->ReadSync(buf, buf_len);
}

int FileStream::ReadUntilComplete(char *buf, int buf_len) {
  base::ThreadRestrictions::AssertIOAllowed();

  int to_read = buf_len;
  int bytes_total = 0;

  do {
    int bytes_read = ReadSync(buf, to_read);
    if (bytes_read <= 0) {
      if (bytes_total == 0)
        return bytes_read;

      return bytes_total;
    }

    bytes_total += bytes_read;
    buf += bytes_read;
    to_read -= bytes_read;
  } while (bytes_total < buf_len);

  return bytes_total;
}

int FileStream::Write(IOBuffer* buf,
                      int buf_len,
                      const CompletionCallback& callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  DCHECK(is_async());
  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
  // write(..., 0) will return 0, which indicates end-of-file.
  DCHECK_GT(buf_len, 0);

  return context_->WriteAsync(buf, buf_len, callback);
}

int FileStream::WriteSync(const char* buf, int buf_len) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  DCHECK(!is_async());
  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
  // write(..., 0) will return 0, which indicates end-of-file.
  DCHECK_GT(buf_len, 0);

  return context_->WriteSync(buf, buf_len);
}

int64 FileStream::Truncate(int64 bytes) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  // We'd better be open for writing.
  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);

  // Seek to the position to truncate from.
  int64 seek_position = SeekSync(FROM_BEGIN, bytes);
  if (seek_position != bytes)
    return ERR_UNEXPECTED;

  // And truncate the file.
  return context_->Truncate(bytes);
}

int FileStream::Flush(const CompletionCallback& callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
  // Make sure we're async.
  DCHECK(is_async());

  context_->FlushAsync(callback);
  return ERR_IO_PENDING;
}

int FileStream::FlushSync() {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
  return context_->FlushSync();
}

void FileStream::EnableErrorStatistics() {
  context_->set_record_uma(true);
}

void FileStream::SetBoundNetLogSource(const BoundNetLog& owner_bound_net_log) {
  if ((owner_bound_net_log.source().id == NetLog::Source::kInvalidId) &&
      (bound_net_log_.source().id == NetLog::Source::kInvalidId)) {
    // Both |BoundNetLog|s are invalid.
    return;
  }

  // Should never connect to itself.
  DCHECK_NE(bound_net_log_.source().id, owner_bound_net_log.source().id);

  bound_net_log_.AddEvent(NetLog::TYPE_FILE_STREAM_BOUND_TO_OWNER,
      owner_bound_net_log.source().ToEventParametersCallback());

  owner_bound_net_log.AddEvent(NetLog::TYPE_FILE_STREAM_SOURCE,
      bound_net_log_.source().ToEventParametersCallback());
}

base::PlatformFile FileStream::GetPlatformFileForTesting() {
  return context_->file();
}

}  // namespace net
<|endoftext|>


<commit_before>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrRenderTarget.h"

#include "GrContext.h"
#include "GrGpu.h"
#include "GrStencilBuffer.h"

SK_DEFINE_INST_COUNT(GrRenderTarget)

bool GrRenderTarget::readPixels(int left, int top, int width, int height,
                                GrPixelConfig config,
                                void* buffer,
                                size_t rowBytes,
                                uint32_t pixelOpsFlags) {
    // go through context so that all necessary flushing occurs
    GrContext* context = this->getContext();
    if (NULL == context) {
        return false;
    }
    return context->readRenderTargetPixels(this,
                                           left, top, width, height,
                                           config, buffer, rowBytes,
                                           pixelOpsFlags);
}

void GrRenderTarget::writePixels(int left, int top, int width, int height,
                                 GrPixelConfig config,
                                 const void* buffer,
                                 size_t rowBytes,
                                 uint32_t pixelOpsFlags) {
    // go through context so that all necessary flushing occurs
    GrContext* context = this->getContext();
    if (NULL == context) {
        return;
    }
    context->writeRenderTargetPixels(this,
                                     left, top, width, height,
                                     config, buffer, rowBytes,
                                     pixelOpsFlags);
}

void GrRenderTarget::resolve() {
    // go through context so that all necessary flushing occurs
    GrContext* context = this->getContext();
    if (NULL == context) {
        return;
    }
    context->resolveRenderTarget(this);
}

size_t GrRenderTarget::sizeInBytes() const {
    int colorBits;
    if (kUnknown_GrPixelConfig == fDesc.fConfig) {
        colorBits = 32; // don't know, make a guess
    } else {
        colorBits = GrBytesPerPixel(fDesc.fConfig);
    }
    uint64_t size = fDesc.fWidth;
    size *= fDesc.fHeight;
    size *= colorBits;
    size *= GrMax(1, fDesc.fSampleCnt);
    return (size_t)(size / 8);
}

void GrRenderTarget::flagAsNeedingResolve(const GrIRect* rect) {
    if (kCanResolve_ResolveType == getResolveType()) {
        if (NULL != rect) {
            fResolveRect.join(*rect);
            if (!fResolveRect.intersect(0, 0, this->width(), this->height())) {
                fResolveRect.setEmpty();
            }
        } else {
            fResolveRect.setLTRB(0, 0, this->width(), this->height());
        }
    }
}

void GrRenderTarget::overrideResolveRect(const GrIRect rect) {
    fResolveRect = rect;
    if (fResolveRect.isEmpty()) {
        fResolveRect.setLargestInverted();
    } else {
        if (!fResolveRect.intersect(0, 0, this->width(), this->height())) {
            fResolveRect.setLargestInverted();
        }
    }
}

void GrRenderTarget::setStencilBuffer(GrStencilBuffer* stencilBuffer) {
    if (NULL != fStencilBuffer) {
        fStencilBuffer->unref();

        GrContext* context = this->getContext();
        if (NULL != context) {
            context->purgeCache();
        }

        if (NULL != context) {
            context->purgeCache();
        }
    }

    fStencilBuffer = stencilBuffer;

    if (NULL != fStencilBuffer) {
        fStencilBuffer->ref();
    }
}

void GrRenderTarget::onRelease() {
    this->setStencilBuffer(NULL);

    INHERITED::onRelease();
}

void GrRenderTarget::onAbandon() {
    this->setStencilBuffer(NULL);

    INHERITED::onAbandon();
}
<commit_msg>Protect against unref/ref of stencil buffer.<commit_after>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrRenderTarget.h"

#include "GrContext.h"
#include "GrGpu.h"
#include "GrStencilBuffer.h"

SK_DEFINE_INST_COUNT(GrRenderTarget)

bool GrRenderTarget::readPixels(int left, int top, int width, int height,
                                GrPixelConfig config,
                                void* buffer,
                                size_t rowBytes,
                                uint32_t pixelOpsFlags) {
    // go through context so that all necessary flushing occurs
    GrContext* context = this->getContext();
    if (NULL == context) {
        return false;
    }
    return context->readRenderTargetPixels(this,
                                           left, top, width, height,
                                           config, buffer, rowBytes,
                                           pixelOpsFlags);
}

void GrRenderTarget::writePixels(int left, int top, int width, int height,
                                 GrPixelConfig config,
                                 const void* buffer,
                                 size_t rowBytes,
                                 uint32_t pixelOpsFlags) {
    // go through context so that all necessary flushing occurs
    GrContext* context = this->getContext();
    if (NULL == context) {
        return;
    }
    context->writeRenderTargetPixels(this,
                                     left, top, width, height,
                                     config, buffer, rowBytes,
                                     pixelOpsFlags);
}

void GrRenderTarget::resolve() {
    // go through context so that all necessary flushing occurs
    GrContext* context = this->getContext();
    if (NULL == context) {
        return;
    }
    context->resolveRenderTarget(this);
}

size_t GrRenderTarget::sizeInBytes() const {
    int colorBits;
    if (kUnknown_GrPixelConfig == fDesc.fConfig) {
        colorBits = 32; // don't know, make a guess
    } else {
        colorBits = GrBytesPerPixel(fDesc.fConfig);
    }
    uint64_t size = fDesc.fWidth;
    size *= fDesc.fHeight;
    size *= colorBits;
    size *= GrMax(1, fDesc.fSampleCnt);
    return (size_t)(size / 8);
}

void GrRenderTarget::flagAsNeedingResolve(const GrIRect* rect) {
    if (kCanResolve_ResolveType == getResolveType()) {
        if (NULL != rect) {
            fResolveRect.join(*rect);
            if (!fResolveRect.intersect(0, 0, this->width(), this->height())) {
                fResolveRect.setEmpty();
            }
        } else {
            fResolveRect.setLTRB(0, 0, this->width(), this->height());
        }
    }
}

void GrRenderTarget::overrideResolveRect(const GrIRect rect) {
    fResolveRect = rect;
    if (fResolveRect.isEmpty()) {
        fResolveRect.setLargestInverted();
    } else {
        if (!fResolveRect.intersect(0, 0, this->width(), this->height())) {
            fResolveRect.setLargestInverted();
        }
    }
}

void GrRenderTarget::setStencilBuffer(GrStencilBuffer* stencilBuffer) {
    if (stencilBuffer == fStencilBuffer) {
        return;
    }

    if (NULL != fStencilBuffer) {
        fStencilBuffer->unref();

        GrContext* context = this->getContext();
        if (NULL != context) {
            context->purgeCache();
        }

        if (NULL != context) {
            context->purgeCache();
        }
    }

    fStencilBuffer = stencilBuffer;

    if (NULL != fStencilBuffer) {
        fStencilBuffer->ref();
    }
}

void GrRenderTarget::onRelease() {
    this->setStencilBuffer(NULL);

    INHERITED::onRelease();
}

void GrRenderTarget::onAbandon() {
    this->setStencilBuffer(NULL);

    INHERITED::onAbandon();
}
<|endoftext|>


<commit_before>#include "SDL/SDL.h"
#include "SDL_gfxPrimitives.h"

#include <string>

#include "circa.h"

const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

SDL_Surface* SCREEN = NULL;

void load_image(circa::Term* caller)
{
    // Temporary storage for the image that's loaded
    SDL_Surface* loadedImage = NULL;

    // The optimized image that will be used
    SDL_Surface* optimizedImage = NULL;

    std::string filename = circa::as_string(caller->input(0));

    // Load the image
    loadedImage = SDL_LoadBMP( filename.c_str() );

    // If nothing went wrong in loading the image
    if( loadedImage != NULL )
    {
        // Create an optimized image
        optimizedImage = SDL_DisplayFormat( loadedImage );

        // Free the old image
        SDL_FreeSurface( loadedImage );
    }

    // Return the optimized image
    circa::as<SDL_Surface*>(caller) = optimizedImage;
}

void apply_surface(circa::Term* caller)
{
    SDL_Surface* destination = circa::as<SDL_Surface*>(caller->input(0));
    SDL_Surface* source = circa::as<SDL_Surface*>(caller->input(1));
    int x = circa::as_int(caller->input(2));
    int y = circa::as_int(caller->input(3));

    // Make a temporary rectangle to hold the offsets
    SDL_Rect offset;

    // Give the offsets to the rectangle
    offset.x = x;
    offset.y = y;

    // Blit the surface
    SDL_BlitSurface( source, NULL, destination, &offset );
}

void rectangle(circa::Term* caller)
{
    rectangleColor(SCREEN,
        (int) as_float(caller->input(0)),
        (int) as_float(caller->input(1)),
        (int) as_float(caller->input(2)),
        (int) as_float(caller->input(3)),
        as_int(caller->input(4)));
}

void fill_rectangle(circa::Term* caller)
{
    boxColor(SCREEN,
        (int) as_float(caller->input(0)),
        (int) as_float(caller->input(1)),
        (int) as_float(caller->input(2)),
        (int) as_float(caller->input(3)),
        (unsigned int) as_int(caller->input(4)));
}

void line_to(circa::Term* caller)
{
    aalineColor(SCREEN,
        (int) as_float(caller->input(0)),
        (int) as_float(caller->input(1)),
        (int) as_float(caller->input(2)),
        (int) as_float(caller->input(3)),
        as_int(caller->input(4)));
}

void SDL_FreeSurface_c(circa::Term* caller)
{
    SDL_Surface* surface = circa::as<SDL_Surface*>(caller->input(0));
}

int main( int argc, char* args[] )
{
    circa::initialize();

    circa::import_type<SDL_Surface*>(*circa::KERNEL, "SDL_Surface");

    circa::import_function(*circa::KERNEL, load_image,
            "load-image(string) -> SDL_Surface");
    circa::import_function(*circa::KERNEL, apply_surface,
            "apply-surface(SDL_Surface,SDL_Surface,int,int)");
    circa::import_function(*circa::KERNEL, SDL_FreeSurface_c,
            "SDL_FreeSurface(SDL_Surface)");
    circa::import_function(*circa::KERNEL, line_to,
            "line_to(float,float,float,float,int)");
    circa::import_function(*circa::KERNEL, rectangle,
            "rectangle(float,float,float,float,int)");
    circa::import_function(*circa::KERNEL, fill_rectangle,
            "fill_rectangle(float,float,float,float,int)");

    // Set up the screen
    SCREEN = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT,
            SCREEN_BPP, SDL_SWSURFACE );

    // If there was an error in setting up the screen
    if( SCREEN == NULL )
        return 1;

    std::string filename;
    if (argc > 1)
        filename = args[1];
    else
        filename = "cgame/main.ca";

    std::cout << "loading file: " << filename << std::endl;

    circa::Branch script_main;
    circa::evaluate_file(script_main, filename);

    // Initialize all SDL subsystems
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1)
        return 1;

    // Set the window caption
    SDL_WM_SetCaption( "Hello World", NULL );

    // Main loop
    bool continueMainLoop = true;
    while (continueMainLoop) {
        SDL_Event event;
        SDL_PollEvent(&event);

        if (event.type == SDL_QUIT)
            continueMainLoop = false;

        if (event.type == SDL_MOUSEMOTION) {
            script_main["mouse_x"]->asFloat() = event.motion.x;
            script_main["mouse_y"]->asFloat() = event.motion.y;
        } else if (event.type == SDL_KEYDOWN) {
            switch(event.key.keysym.sym) {
            case SDLK_4:
                std::cout << "Script contents:" << std::endl;
                print_raw_branch(script_main, std::cout);
                break;
            case SDLK_5:
                circa::reload_branch_from_file(script_main);
                std::cout << "Script reloaded" << std::endl;
                break;
            case SDLK_UP:
                script_main["up_pressed"]->asBool() = true; break;
            case SDLK_DOWN:
                script_main["down_pressed"]->asBool() = true; break;
            case SDLK_LEFT:
                script_main["left_pressed"]->asBool() = true; break;
            case SDLK_RIGHT:
                script_main["right_pressed"]->asBool() = true; break;
            case SDLK_ESCAPE:
                continueMainLoop = false; break;
            }
        } else if (event.type == SDL_KEYUP) {
            switch(event.key.keysym.sym) {
            case SDLK_UP:
                script_main["up_pressed"]->asBool() = false; break;
            case SDLK_DOWN:
                script_main["down_pressed"]->asBool() = false; break;
            case SDLK_LEFT:
                script_main["left_pressed"]->asBool() = false; break;
            case SDLK_RIGHT:
                script_main["right_pressed"]->asBool() = false; break;
            }
        }

        try {
            script_main.eval();
        } catch (std::exception &e) {
            std::cout << e.what() << std::endl;
            return 0;
        }

        // Update the screen
        if( SDL_Flip(SCREEN) == -1 )
            return 1;

        SDL_Delay( 10 );
    }

    // Free the surfaces
    script_main.eval("SDL_FreeSurface(background)");

    // Quit SDL
    SDL_Quit();

    return 0;
}

<commit_msg>cgame now catches space keypress<commit_after>#include "SDL/SDL.h"
#include "SDL_gfxPrimitives.h"

#include <string>

#include "circa.h"

const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

SDL_Surface* SCREEN = NULL;

void load_image(circa::Term* caller)
{
    // Temporary storage for the image that's loaded
    SDL_Surface* loadedImage = NULL;

    // The optimized image that will be used
    SDL_Surface* optimizedImage = NULL;

    std::string filename = circa::as_string(caller->input(0));

    // Load the image
    loadedImage = SDL_LoadBMP( filename.c_str() );

    // If nothing went wrong in loading the image
    if( loadedImage != NULL )
    {
        // Create an optimized image
        optimizedImage = SDL_DisplayFormat( loadedImage );

        // Free the old image
        SDL_FreeSurface( loadedImage );
    }

    // Return the optimized image
    circa::as<SDL_Surface*>(caller) = optimizedImage;
}

void apply_surface(circa::Term* caller)
{
    SDL_Surface* destination = circa::as<SDL_Surface*>(caller->input(0));
    SDL_Surface* source = circa::as<SDL_Surface*>(caller->input(1));
    int x = circa::as_int(caller->input(2));
    int y = circa::as_int(caller->input(3));

    // Make a temporary rectangle to hold the offsets
    SDL_Rect offset;

    // Give the offsets to the rectangle
    offset.x = x;
    offset.y = y;

    // Blit the surface
    SDL_BlitSurface( source, NULL, destination, &offset );
}

void rectangle(circa::Term* caller)
{
    rectangleColor(SCREEN,
        (int) as_float(caller->input(0)),
        (int) as_float(caller->input(1)),
        (int) as_float(caller->input(2)),
        (int) as_float(caller->input(3)),
        as_int(caller->input(4)));
}

void fill_rectangle(circa::Term* caller)
{
    boxColor(SCREEN,
        (int) as_float(caller->input(0)),
        (int) as_float(caller->input(1)),
        (int) as_float(caller->input(2)),
        (int) as_float(caller->input(3)),
        (unsigned int) as_int(caller->input(4)));
}

void line_to(circa::Term* caller)
{
    aalineColor(SCREEN,
        (int) as_float(caller->input(0)),
        (int) as_float(caller->input(1)),
        (int) as_float(caller->input(2)),
        (int) as_float(caller->input(3)),
        as_int(caller->input(4)));
}

void SDL_FreeSurface_c(circa::Term* caller)
{
    SDL_Surface* surface = circa::as<SDL_Surface*>(caller->input(0));
}

int main( int argc, char* args[] )
{
    circa::initialize();

    circa::import_type<SDL_Surface*>(*circa::KERNEL, "SDL_Surface");

    circa::import_function(*circa::KERNEL, load_image,
            "load-image(string) -> SDL_Surface");
    circa::import_function(*circa::KERNEL, apply_surface,
            "apply-surface(SDL_Surface,SDL_Surface,int,int)");
    circa::import_function(*circa::KERNEL, SDL_FreeSurface_c,
            "SDL_FreeSurface(SDL_Surface)");
    circa::import_function(*circa::KERNEL, line_to,
            "line_to(float,float,float,float,int)");
    circa::import_function(*circa::KERNEL, rectangle,
            "rectangle(float,float,float,float,int)");
    circa::import_function(*circa::KERNEL, fill_rectangle,
            "fill_rectangle(float,float,float,float,int)");

    // Set up the screen
    SCREEN = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT,
            SCREEN_BPP, SDL_SWSURFACE );

    // If there was an error in setting up the screen
    if( SCREEN == NULL )
        return 1;

    std::string filename;
    if (argc > 1)
        filename = args[1];
    else
        filename = "cgame/main.ca";

    std::cout << "loading file: " << filename << std::endl;

    circa::Branch script_main;
    circa::evaluate_file(script_main, filename);

    // Initialize all SDL subsystems
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1)
        return 1;

    // Set the window caption
    SDL_WM_SetCaption( "Hello World", NULL );

    // Main loop
    bool continueMainLoop = true;
    while (continueMainLoop) {
        SDL_Event event;
        SDL_PollEvent(&event);

        if (event.type == SDL_QUIT)
            continueMainLoop = false;

        if (event.type == SDL_MOUSEMOTION) {
            script_main["mouse_x"]->asFloat() = event.motion.x;
            script_main["mouse_y"]->asFloat() = event.motion.y;
        } else if (event.type == SDL_KEYDOWN) {
            switch(event.key.keysym.sym) {
            case SDLK_4:
                std::cout << "Script contents:" << std::endl;
                print_raw_branch(script_main, std::cout);
                break;
            case SDLK_5:
                circa::reload_branch_from_file(script_main);
                std::cout << "Script reloaded" << std::endl;
                break;
            case SDLK_UP:
                script_main["up_pressed"]->asBool() = true; break;
            case SDLK_DOWN:
                script_main["down_pressed"]->asBool() = true; break;
            case SDLK_LEFT:
                script_main["left_pressed"]->asBool() = true; break;
            case SDLK_RIGHT:
                script_main["right_pressed"]->asBool() = true; break;
            case SDLK_SPACE:
                script_main["space_pressed"]->asBool() = true; break;
            case SDLK_ESCAPE:
                continueMainLoop = false; break;
            }
        } else if (event.type == SDL_KEYUP) {
            switch(event.key.keysym.sym) {
            case SDLK_UP:
                script_main["up_pressed"]->asBool() = false; break;
            case SDLK_DOWN:
                script_main["down_pressed"]->asBool() = false; break;
            case SDLK_LEFT:
                script_main["left_pressed"]->asBool() = false; break;
            case SDLK_RIGHT:
                script_main["right_pressed"]->asBool() = false; break;
            case SDLK_SPACE:
                script_main["space_pressed"]->asBool() = false; break;
            }
        }

        try {
            script_main.eval();
        } catch (std::exception &e) {
            std::cout << e.what() << std::endl;
            return 0;
        }

        // Update the screen
        if( SDL_Flip(SCREEN) == -1 )
            return 1;

        SDL_Delay( 10 );
    }

    // Free the surfaces
    script_main.eval("SDL_FreeSurface(background)");

    // Quit SDL
    SDL_Quit();

    return 0;
}

<|endoftext|>


<commit_before>#include <thread>

#include <boost/property_tree/json_parser.hpp>

#include <pdal/PipelineReader.hpp>
#include <pdal/PDALUtils.hpp>
#include <pdal/Dimension.hpp>
#include <pdal/Options.hpp>
#include <pdal/Metadata.hpp>

#include "pdal-session.hpp"
#include "read-command.hpp"

namespace
{
    bool rasterOmit(pdal::Dimension::Id::Enum id)
    {
        // These Dimensions are not explicitly placed in the output buffer
        // for rasterized requests.
        return id == pdal::Dimension::Id::X || id == pdal::Dimension::Id::Y;
    }
}

PdalSession::PdalSession()
    : m_pipelineManager()
    , m_pointBuffer()
    , m_initOnce()
    , m_pdalIndex(new PdalIndex())
{ }

void PdalSession::initialize(const std::string& pipeline, const bool execute)
{
    m_initOnce.ensure([this, &pipeline, execute]() {
        std::istringstream ssPipeline(pipeline);
        pdal::PipelineReader pipelineReader(m_pipelineManager);
        pipelineReader.readPipeline(ssPipeline);

        // This segment could take a substantial amount of time.  The
        // PdalBindings wrapper ensures that it will run in a non-blocking
        // manner in the uv_work_queue.
        if (execute)
        {
            pdal::Options options;
            options.add("do_sample", false);
            m_pipelineManager.addFilter(
                "filters.stats",
                m_pipelineManager.getStage(),
                options);

            m_pipelineManager.execute();

            m_pointContext = m_pipelineManager.context();
            const pdal::PointBufferSet& pbSet(m_pipelineManager.buffers());
            m_pointBuffer = *pbSet.begin();

            if (!m_pointBuffer->hasDim(pdal::Dimension::Id::X) ||
                !m_pointBuffer->hasDim(pdal::Dimension::Id::Y) ||
                !m_pointBuffer->hasDim(pdal::Dimension::Id::Z))
            {
                throw std::runtime_error(
                    "Pipeline output should contain X, Y and Z dimensions");
            }
        }
    });
}

std::size_t PdalSession::getNumPoints() const
{
    return m_pointBuffer->size();
}

std::string PdalSession::getSchema() const
{
    std::ostringstream oss;
    boost::property_tree::ptree tree(pdal::utils::toPTree(m_pointContext));
    boost::property_tree::write_json(oss, tree);
    return oss.str();
}

std::string PdalSession::getStats() const
{
    return m_pipelineManager.getMetadata().toJSON();
}

std::string PdalSession::getSrs() const
{
    return m_pointContext.spatialRef().getRawWKT();
}

std::size_t PdalSession::readDim(
        unsigned char* buffer,
        const DimInfo& dim,
        const std::size_t index) const
{
    if (dim.type == "floating")
    {
        if (dim.size == 4)
        {
            float val(m_pointBuffer->getFieldAs<float>(dim.id, index));
            std::memcpy(buffer, &val, dim.size);
        }
        else if (dim.size == 8)
        {
            double val(m_pointBuffer->getFieldAs<double>(dim.id, index));
            std::memcpy(buffer, &val, dim.size);
        }
        else
        {
            throw std::runtime_error("Invalid floating size requested");
        }
    }
    else
    {
        if (dim.size == 1)
        {
            uint8_t val(m_pointBuffer->getFieldAs<uint8_t>(dim.id, index));
            std::memcpy(buffer, &val, dim.size);
        }
        else if (dim.size == 2)
        {
            uint16_t val(m_pointBuffer->getFieldAs<uint16_t>(dim.id, index));
            std::memcpy(buffer, &val, dim.size);
        }
        else if (dim.size == 4)
        {
            uint32_t val(m_pointBuffer->getFieldAs<uint32_t>(dim.id, index));
            std::memcpy(buffer, &val, dim.size);
        }
        else if (dim.size == 8)
        {
            uint64_t val(m_pointBuffer->getFieldAs<uint64_t>(dim.id, index));
            std::memcpy(buffer, &val, dim.size);
        }
        else
        {
            throw std::runtime_error("Invalid integer size requested");
        }
    }

    return dim.size;
}

std::size_t PdalSession::readUnindexed(
        std::vector<unsigned char>& buffer,
        const Schema& schema,
        const std::size_t start,
        const std::size_t count) const
{
    if (start >= getNumPoints())
        throw std::runtime_error("Invalid starting offset in 'read'");

    // If zero points specified, read all points after 'start'.
    const std::size_t pointsToRead(
            count > 0 ?
                std::min<std::size_t>(count, getNumPoints() - start) :
                getNumPoints() - start);

    try
    {
        buffer.resize(pointsToRead * schema.stride());

        unsigned char* pos(buffer.data());

        for (boost::uint32_t i(start); i < start + pointsToRead; ++i)
        {
            for (const auto& dim : schema.dims)
            {
                pos += readDim(pos, dim, i);
            }
        }
    }
    catch (...)
    {
        throw std::runtime_error("Failed to read points from PDAL");
    }

    return pointsToRead;
}

std::size_t PdalSession::read(
        std::vector<unsigned char>& buffer,
        const Schema& schema,
        const double xMin,
        const double yMin,
        const double xMax,
        const double yMax,
        std::size_t depthBegin,
        std::size_t depthEnd)
{
    m_pdalIndex->ensureIndex(PdalIndex::QuadIndex, m_pointBuffer);
    const pdal::QuadIndex& quadIndex(m_pdalIndex->quadIndex());

    const std::vector<std::size_t> results(quadIndex.getPoints(
            xMin,
            yMin,
            xMax,
            yMax,
            depthBegin,
            depthEnd));

    return readIndexList(buffer, schema, results);
}

std::size_t PdalSession::read(
        std::vector<unsigned char>& buffer,
        const Schema& schema,
        const std::size_t depthBegin,
        const std::size_t depthEnd)
{
    m_pdalIndex->ensureIndex(PdalIndex::QuadIndex, m_pointBuffer);
    const pdal::QuadIndex& quadIndex(m_pdalIndex->quadIndex());

    const std::vector<std::size_t> results(quadIndex.getPoints(
            depthBegin,
            depthEnd));

    return readIndexList(buffer, schema, results);
}

std::size_t PdalSession::read(
        std::vector<unsigned char>& buffer,
        const Schema& schema,
        const std::size_t rasterize,
        RasterMeta& rasterMeta)
{
    m_pdalIndex->ensureIndex(PdalIndex::QuadIndex, m_pointBuffer);
    const pdal::QuadIndex& quadIndex(m_pdalIndex->quadIndex());

    const std::vector<std::size_t> results(quadIndex.getPoints(
            rasterize,
            rasterMeta.xBegin,
            rasterMeta.xEnd,
            rasterMeta.xStep,
            rasterMeta.yBegin,
            rasterMeta.yEnd,
            rasterMeta.yStep));

    return readIndexList(buffer, schema, results, true);
}

std::size_t PdalSession::read(
        std::vector<unsigned char>& buffer,
        const Schema& schema,
        const RasterMeta& rasterMeta)
{
    m_pdalIndex->ensureIndex(PdalIndex::QuadIndex, m_pointBuffer);
    const pdal::QuadIndex& quadIndex(m_pdalIndex->quadIndex());

    const std::vector<std::size_t> results(quadIndex.getPoints(
            rasterMeta.xBegin,
            rasterMeta.xEnd,
            rasterMeta.xStep,
            rasterMeta.yBegin,
            rasterMeta.yEnd,
            rasterMeta.yStep));

    return readIndexList(buffer, schema, results, true);
}

std::size_t PdalSession::read(
        std::vector<unsigned char>& buffer,
        const Schema& schema,
        const bool is3d,
        const double radius,
        const double x,
        const double y,
        const double z)
{
    m_pdalIndex->ensureIndex(
            is3d ? PdalIndex::KdIndex3d : PdalIndex::KdIndex2d,
            m_pointBuffer);

    const pdal::KDIndex& kdIndex(
            is3d ? m_pdalIndex->kdIndex3d() : m_pdalIndex->kdIndex2d());

    // KDIndex::radius() takes r^2.
    const std::vector<std::size_t> results(
            kdIndex.radius(x, y, z, radius * radius));

    return readIndexList(buffer, schema, results);
}

std::size_t PdalSession::readIndexList(
        std::vector<unsigned char>& buffer,
        const Schema& schema,
        const std::vector<std::size_t>& indexList,
        const bool rasterize) const
{
    const std::size_t pointsToRead(indexList.size());

    // Rasterization
    std::size_t stride(schema.stride());

    if (rasterize)
    {
        // Clientward rasterization schemas always contain a byte to specify
        // whether a point at this location in the raster exists.
        ++stride;

        for (auto dim : schema.dims)
        {
            if (rasterOmit(dim.id))
            {
                stride -= dim.size;
            }
        }
    }

    try
    {
        buffer.resize(pointsToRead * stride, 0);

        unsigned char* pos(buffer.data());

        for (std::size_t i : indexList)
        {
            if (i != std::numeric_limits<std::size_t>::max())
            {
                if (rasterize)
                {
                    // Mark this point as a valid point.
                    std::fill(pos, pos + 1, 1);
                    ++pos;
                }

                for (const auto& dim : schema.dims)
                {
                    if (!rasterize || !rasterOmit(dim.id))
                    {
                        pos += readDim(pos, dim, i);
                    }
                }
            }
            else
            {
                if (rasterize)
                {
                    // Mark this point as a hole.
                    std::fill(pos, pos + 1, 0);
                }

                pos += stride;
            }
        }
    }
    catch (...)
    {
        throw std::runtime_error("Failed to read points from PDAL");
    }

    return pointsToRead;
}

void PdalIndex::ensureIndex(
        const IndexType indexType,
        const pdal::PointBufferPtr pointBufferPtr)
{
    const pdal::PointBuffer& pointBuffer(*pointBufferPtr.get());

    switch (indexType)
    {
        case KdIndex2d:
            m_kd2dOnce.ensure([this, &pointBuffer]() {
                m_kdIndex2d.reset(new pdal::KDIndex(pointBuffer));
                m_kdIndex2d->build(false);
            });
            break;
        case KdIndex3d:
            m_kd3dOnce.ensure([this, &pointBuffer]() {
                m_kdIndex3d.reset(new pdal::KDIndex(pointBuffer));
                m_kdIndex3d->build(true);
            });
            break;
        case QuadIndex:
            m_quadOnce.ensure([this, &pointBuffer]() {
                m_quadIndex.reset(new pdal::QuadIndex(pointBuffer));
                m_quadIndex->build();
            });
            break;
        default:
            throw std::runtime_error("Invalid PDAL index type");
    }
}

//////////////////////////////////////////////////////////////////////////////

BufferTransmitter::BufferTransmitter(
        const std::string& host,
        const int port,
        const unsigned char* data,
        const std::size_t size)
    : m_socket()
    , m_data(data)
    , m_size(size)
{
    namespace asio = boost::asio;
    using boost::asio::ip::tcp;

    std::stringstream portStream;
    portStream << port;

    asio::io_service service;
    tcp::resolver resolver(service);

    tcp::resolver::query q(host, portStream.str());
    tcp::resolver::iterator iter = resolver.resolve(q), end;

    m_socket.reset(new tcp::socket(service));

    int retryCount = 0;
    boost::system::error_code ignored_error;

    // Don't fail yet, the setup service may be setting up the receiver.
    tcp::resolver::iterator connectIter;

    while (
        (connectIter = asio::connect(*m_socket, iter, ignored_error)) == end &&
            retryCount++ < 500)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    if (connectIter == end)
    {
        std::stringstream errStream;
        errStream << "Could not connect to " << host << ":" << port;
        throw std::runtime_error(errStream.str());
    }
}

void BufferTransmitter::transmit(
        const std::size_t offset,
        const std::size_t bytes)
{
    boost::system::error_code ignored_error;

    boost::asio::write(
            *m_socket,
            boost::asio::buffer(
                m_data + offset,
                bytes ?
                    std::min(bytes, m_size - offset) :
                    m_size - offset),
            ignored_error);
}

<commit_msg>Update to current PDAL interface.<commit_after>#include <thread>

#include <boost/property_tree/json_parser.hpp>

#include <pdal/PipelineReader.hpp>
#include <pdal/PDALUtils.hpp>
#include <pdal/Dimension.hpp>
#include <pdal/Options.hpp>
#include <pdal/Metadata.hpp>

#include "pdal-session.hpp"
#include "read-command.hpp"

namespace
{
    bool rasterOmit(pdal::Dimension::Id::Enum id)
    {
        // These Dimensions are not explicitly placed in the output buffer
        // for rasterized requests.
        return id == pdal::Dimension::Id::X || id == pdal::Dimension::Id::Y;
    }
}

PdalSession::PdalSession()
    : m_pipelineManager()
    , m_pointBuffer()
    , m_initOnce()
    , m_pdalIndex(new PdalIndex())
{ }

void PdalSession::initialize(const std::string& pipeline, const bool execute)
{
    m_initOnce.ensure([this, &pipeline, execute]() {
        std::istringstream ssPipeline(pipeline);
        pdal::PipelineReader pipelineReader(m_pipelineManager);
        pipelineReader.readPipeline(ssPipeline);

        // This segment could take a substantial amount of time.  The
        // PdalBindings wrapper ensures that it will run in a non-blocking
        // manner in the uv_work_queue.
        if (execute)
        {
            pdal::Options options;
            options.add("do_sample", false);
            m_pipelineManager.addFilter(
                "filters.stats",
                m_pipelineManager.getStage());

            m_pipelineManager.execute();

            m_pointContext = m_pipelineManager.context();
            const pdal::PointBufferSet& pbSet(m_pipelineManager.buffers());
            m_pointBuffer = *pbSet.begin();

            if (!m_pointBuffer->hasDim(pdal::Dimension::Id::X) ||
                !m_pointBuffer->hasDim(pdal::Dimension::Id::Y) ||
                !m_pointBuffer->hasDim(pdal::Dimension::Id::Z))
            {
                throw std::runtime_error(
                    "Pipeline output should contain X, Y and Z dimensions");
            }
        }
    });
}

std::size_t PdalSession::getNumPoints() const
{
    return m_pointBuffer->size();
}

std::string PdalSession::getSchema() const
{
    std::ostringstream oss;
    boost::property_tree::ptree tree(pdal::utils::toPTree(m_pointContext));
    boost::property_tree::write_json(oss, tree);
    return oss.str();
}

std::string PdalSession::getStats() const
{
    return m_pipelineManager.getMetadata().toJSON();
}

std::string PdalSession::getSrs() const
{
    return m_pointContext.spatialRef().getRawWKT();
}

std::size_t PdalSession::readDim(
        unsigned char* buffer,
        const DimInfo& dim,
        const std::size_t index) const
{
    if (dim.type == "floating")
    {
        if (dim.size == 4)
        {
            float val(m_pointBuffer->getFieldAs<float>(dim.id, index));
            std::memcpy(buffer, &val, dim.size);
        }
        else if (dim.size == 8)
        {
            double val(m_pointBuffer->getFieldAs<double>(dim.id, index));
            std::memcpy(buffer, &val, dim.size);
        }
        else
        {
            throw std::runtime_error("Invalid floating size requested");
        }
    }
    else
    {
        if (dim.size == 1)
        {
            uint8_t val(m_pointBuffer->getFieldAs<uint8_t>(dim.id, index));
            std::memcpy(buffer, &val, dim.size);
        }
        else if (dim.size == 2)
        {
            uint16_t val(m_pointBuffer->getFieldAs<uint16_t>(dim.id, index));
            std::memcpy(buffer, &val, dim.size);
        }
        else if (dim.size == 4)
        {
            uint32_t val(m_pointBuffer->getFieldAs<uint32_t>(dim.id, index));
            std::memcpy(buffer, &val, dim.size);
        }
        else if (dim.size == 8)
        {
            uint64_t val(m_pointBuffer->getFieldAs<uint64_t>(dim.id, index));
            std::memcpy(buffer, &val, dim.size);
        }
        else
        {
            throw std::runtime_error("Invalid integer size requested");
        }
    }

    return dim.size;
}

std::size_t PdalSession::readUnindexed(
        std::vector<unsigned char>& buffer,
        const Schema& schema,
        const std::size_t start,
        const std::size_t count) const
{
    if (start >= getNumPoints())
        throw std::runtime_error("Invalid starting offset in 'read'");

    // If zero points specified, read all points after 'start'.
    const std::size_t pointsToRead(
            count > 0 ?
                std::min<std::size_t>(count, getNumPoints() - start) :
                getNumPoints() - start);

    try
    {
        buffer.resize(pointsToRead * schema.stride());

        unsigned char* pos(buffer.data());

        for (boost::uint32_t i(start); i < start + pointsToRead; ++i)
        {
            for (const auto& dim : schema.dims)
            {
                pos += readDim(pos, dim, i);
            }
        }
    }
    catch (...)
    {
        throw std::runtime_error("Failed to read points from PDAL");
    }

    return pointsToRead;
}

std::size_t PdalSession::read(
        std::vector<unsigned char>& buffer,
        const Schema& schema,
        const double xMin,
        const double yMin,
        const double xMax,
        const double yMax,
        std::size_t depthBegin,
        std::size_t depthEnd)
{
    m_pdalIndex->ensureIndex(PdalIndex::QuadIndex, m_pointBuffer);
    const pdal::QuadIndex& quadIndex(m_pdalIndex->quadIndex());

    const std::vector<std::size_t> results(quadIndex.getPoints(
            xMin,
            yMin,
            xMax,
            yMax,
            depthBegin,
            depthEnd));

    return readIndexList(buffer, schema, results);
}

std::size_t PdalSession::read(
        std::vector<unsigned char>& buffer,
        const Schema& schema,
        const std::size_t depthBegin,
        const std::size_t depthEnd)
{
    m_pdalIndex->ensureIndex(PdalIndex::QuadIndex, m_pointBuffer);
    const pdal::QuadIndex& quadIndex(m_pdalIndex->quadIndex());

    const std::vector<std::size_t> results(quadIndex.getPoints(
            depthBegin,
            depthEnd));

    return readIndexList(buffer, schema, results);
}

std::size_t PdalSession::read(
        std::vector<unsigned char>& buffer,
        const Schema& schema,
        const std::size_t rasterize,
        RasterMeta& rasterMeta)
{
    m_pdalIndex->ensureIndex(PdalIndex::QuadIndex, m_pointBuffer);
    const pdal::QuadIndex& quadIndex(m_pdalIndex->quadIndex());

    const std::vector<std::size_t> results(quadIndex.getPoints(
            rasterize,
            rasterMeta.xBegin,
            rasterMeta.xEnd,
            rasterMeta.xStep,
            rasterMeta.yBegin,
            rasterMeta.yEnd,
            rasterMeta.yStep));

    return readIndexList(buffer, schema, results, true);
}

std::size_t PdalSession::read(
        std::vector<unsigned char>& buffer,
        const Schema& schema,
        const RasterMeta& rasterMeta)
{
    m_pdalIndex->ensureIndex(PdalIndex::QuadIndex, m_pointBuffer);
    const pdal::QuadIndex& quadIndex(m_pdalIndex->quadIndex());

    const std::vector<std::size_t> results(quadIndex.getPoints(
            rasterMeta.xBegin,
            rasterMeta.xEnd,
            rasterMeta.xStep,
            rasterMeta.yBegin,
            rasterMeta.yEnd,
            rasterMeta.yStep));

    return readIndexList(buffer, schema, results, true);
}

std::size_t PdalSession::read(
        std::vector<unsigned char>& buffer,
        const Schema& schema,
        const bool is3d,
        const double radius,
        const double x,
        const double y,
        const double z)
{
    m_pdalIndex->ensureIndex(
            is3d ? PdalIndex::KdIndex3d : PdalIndex::KdIndex2d,
            m_pointBuffer);

    const pdal::KDIndex& kdIndex(
            is3d ? m_pdalIndex->kdIndex3d() : m_pdalIndex->kdIndex2d());

    // KDIndex::radius() takes r^2.
    const std::vector<std::size_t> results(
            kdIndex.radius(x, y, z, radius * radius));

    return readIndexList(buffer, schema, results);
}

std::size_t PdalSession::readIndexList(
        std::vector<unsigned char>& buffer,
        const Schema& schema,
        const std::vector<std::size_t>& indexList,
        const bool rasterize) const
{
    const std::size_t pointsToRead(indexList.size());

    // Rasterization
    std::size_t stride(schema.stride());

    if (rasterize)
    {
        // Clientward rasterization schemas always contain a byte to specify
        // whether a point at this location in the raster exists.
        ++stride;

        for (auto dim : schema.dims)
        {
            if (rasterOmit(dim.id))
            {
                stride -= dim.size;
            }
        }
    }

    try
    {
        buffer.resize(pointsToRead * stride, 0);

        unsigned char* pos(buffer.data());

        for (std::size_t i : indexList)
        {
            if (i != std::numeric_limits<std::size_t>::max())
            {
                if (rasterize)
                {
                    // Mark this point as a valid point.
                    std::fill(pos, pos + 1, 1);
                    ++pos;
                }

                for (const auto& dim : schema.dims)
                {
                    if (!rasterize || !rasterOmit(dim.id))
                    {
                        pos += readDim(pos, dim, i);
                    }
                }
            }
            else
            {
                if (rasterize)
                {
                    // Mark this point as a hole.
                    std::fill(pos, pos + 1, 0);
                }

                pos += stride;
            }
        }
    }
    catch (...)
    {
        throw std::runtime_error("Failed to read points from PDAL");
    }

    return pointsToRead;
}

void PdalIndex::ensureIndex(
        const IndexType indexType,
        const pdal::PointBufferPtr pointBufferPtr)
{
    const pdal::PointBuffer& pointBuffer(*pointBufferPtr.get());

    switch (indexType)
    {
        case KdIndex2d:
            m_kd2dOnce.ensure([this, &pointBuffer]() {
                m_kdIndex2d.reset(new pdal::KDIndex(pointBuffer));
                m_kdIndex2d->build(false);
            });
            break;
        case KdIndex3d:
            m_kd3dOnce.ensure([this, &pointBuffer]() {
                m_kdIndex3d.reset(new pdal::KDIndex(pointBuffer));
                m_kdIndex3d->build(true);
            });
            break;
        case QuadIndex:
            m_quadOnce.ensure([this, &pointBuffer]() {
                m_quadIndex.reset(new pdal::QuadIndex(pointBuffer));
                m_quadIndex->build();
            });
            break;
        default:
            throw std::runtime_error("Invalid PDAL index type");
    }
}

//////////////////////////////////////////////////////////////////////////////

BufferTransmitter::BufferTransmitter(
        const std::string& host,
        const int port,
        const unsigned char* data,
        const std::size_t size)
    : m_socket()
    , m_data(data)
    , m_size(size)
{
    namespace asio = boost::asio;
    using boost::asio::ip::tcp;

    std::stringstream portStream;
    portStream << port;

    asio::io_service service;
    tcp::resolver resolver(service);

    tcp::resolver::query q(host, portStream.str());
    tcp::resolver::iterator iter = resolver.resolve(q), end;

    m_socket.reset(new tcp::socket(service));

    int retryCount = 0;
    boost::system::error_code ignored_error;

    // Don't fail yet, the setup service may be setting up the receiver.
    tcp::resolver::iterator connectIter;

    while (
        (connectIter = asio::connect(*m_socket, iter, ignored_error)) == end &&
            retryCount++ < 500)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    if (connectIter == end)
    {
        std::stringstream errStream;
        errStream << "Could not connect to " << host << ":" << port;
        throw std::runtime_error(errStream.str());
    }
}

void BufferTransmitter::transmit(
        const std::size_t offset,
        const std::size_t bytes)
{
    boost::system::error_code ignored_error;

    boost::asio::write(
            *m_socket,
            boost::asio::buffer(
                m_data + offset,
                bytes ?
                    std::min(bytes, m_size - offset) :
                    m_size - offset),
            ignored_error);
}

<|endoftext|>