<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- vim:set ts=4 sw=4 sts=4 noet: */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "exec/task-runner.h"

#include <cassert>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <future>
#include <numeric>
#include <vector>

#define BOOST_FILESYSTEM_NO_DEPRECATED
#include <boost/filesystem/fstream.hpp>
#define BOOST_DATE_TIME_NO_LIB
#include <boost/interprocess/file_mapping.hpp>
#include <boost/interprocess/mapped_region.hpp>

#include "bc/index.h"
#include "cas.h"
#include "cas/dimension.h"
#include "compiler.h"
#include "db/driver.h"
#include "db/read-only-driver.h"
#include "db/statement-driver.h"
#include "exec.h"
#include "exec/job-runner.h"
#include "exec/parameter.h"
#include "filter.h"
#include "filter/cutter.h"
#include "flint/ls.h"
#include "flint/workspace.h"
#include "job.h"
#include "layout.h"
#include "lo/layout.h"
#include "lo/layout_loader.h"
#include "load.h"
#include "task.h"
#include "task/config-reader.h"

namespace flint {
namespace exec {

namespace {

int CountParameterSamples(sqlite3 *db)
{
	db::StatementDriver sd(db, "SELECT COUNT(*) FROM parameter_samples");
	int e = sqlite3_step(sd.stmt());
	if (e != SQLITE_ROW) {
		std::cerr << "failed to step statement: " << e << std::endl;
		return -1;
	}
	return sqlite3_column_int(sd.stmt(), 0);
}

const unsigned int kUnitInterval = 200;
const unsigned int kMaxInterval = kUnitInterval << 5;

}

TaskRunner::TaskRunner(int id, char *path, const boost::filesystem::path &dir,
					   ctrl::Argument *arg)
	: id_(id)
	, path_(path)
	, arg_(arg)
	, dir_(dir)
	, layout_(dir)
	, generated_layout_(dir)
{
	char buf[64];
	std::sprintf(buf, "%d", id);
	dir_ /= buf;
	std::sprintf(buf, "%d/layout", id);
	layout_ /= buf;
	std::sprintf(buf, "%d/generated-layout", id);
	generated_layout_ /= buf;
}

TaskRunner::~TaskRunner() = default;

task::Task *TaskRunner::GetTask()
{
	return task_.get();
}

sqlite3 *TaskRunner::GetDatabase()
{
	return db_driver_->db();
}

sqlite3 *TaskRunner::GetModelDatabase()
{
	return modeldb_driver_->db();
}

const cas::DimensionAnalyzer *TaskRunner::GetDimensionAnalyzer() const
{
	return dimension_analyzer_.get();
}

bool TaskRunner::CreateSpec(int id, sqlite3 *db)
{
	auto spec_file = dir_ / "spec.txt";
	boost::filesystem::ofstream ofs(spec_file, std::ios::out|std::ios::binary);
	if (!ofs) {
		std::cerr << "failed to open " << spec_file << std::endl;
		return false;
	}
	bool r = task::Spec(id, db, ofs);
	ofs.close();
	return r;
}

bool TaskRunner::CreateControlFile(int num_samples)
{
	assert(task_);

	auto control_file = dir_ / "control";
	size_t size = num_samples + 1;
	if (!workspace::CreateSparseFileAtomically(control_file, size))
		return false;
	try {
		boost::interprocess::file_mapping fm(control_file.string().c_str(), boost::interprocess::read_write);
		boost::interprocess::mapped_region mr(fm, boost::interprocess::read_write);
		task_->control_mr = std::move(mr);
	} catch (const boost::interprocess::interprocess_exception &e) {
		std::cerr << "failed to map file: " << e.what() << std::endl;
		return false;
	}
	return true;
}

bool TaskRunner::CreateProgressFile(int num_samples)
{
	auto progress_file = dir_ / "progress";
	size_t size = num_samples + 1;
	if (!workspace::CreateSparseFileAtomically(progress_file, size))
		return false;
	try {
		boost::interprocess::file_mapping fm(progress_file.string().c_str(), boost::interprocess::read_write);
		boost::interprocess::mapped_region mr(fm, boost::interprocess::read_write);
		task_->progress_mr = std::move(mr);
	} catch (const boost::interprocess::interprocess_exception &e) {
		std::cerr << "failed to map file: " << e.what() << std::endl;
		return false;
	}
	return true;
}

bool TaskRunner::CreateRssFile(int num_samples)
{
	auto rss_file = dir_ / "rss";
	size_t size = (num_samples + 1) * sizeof(double);
	if (!workspace::CreateSparseFileAtomically(rss_file, size))
		return false;
	try {
		boost::interprocess::file_mapping fm(rss_file.string().c_str(), boost::interprocess::read_write);
		boost::interprocess::mapped_region mr(fm, boost::interprocess::read_write);
		task_->rss_mr = std::move(mr);
	} catch (const boost::interprocess::interprocess_exception &e) {
		std::cerr << "failed to map file: " << e.what() << std::endl;
		return false;
	}
	return true;
}

bool TaskRunner::Run()
{
	task_.reset(load::Load(path_.get(), load::kExec, dir_, &data_));
	if (!task_)
		return false;
	{
		auto driver = db::Driver::Create(dir_.parent_path() / "x.db");
		auto db = driver->db();
		if (!db)
			return false;
		if (!task::Config(id_, db, dir_))
			return false;
	}
	{
		auto driver = db::ReadOnlyDriver::Create(dir_.parent_path() / "x.db");
		auto db = driver->db();
		if (!db)
			return false;
		if (!CreateSpec(id_, db))
			return false;
	}

	modeldb_driver_ = db::ReadOnlyDriver::Create(dir_ / "model.db");
	auto spec_file = dir_ / "spec.txt";
	auto filter_file = dir_ / "filter";
	if (!filter::Create(modeldb_driver_->db(), spec_file, layout_, filter_file))
		return false;
	auto track_file = dir_ / "track";
	if (!filter::Track(filter_file, track_file))
		return false;
	auto isdh_file = dir_ / "isdh";
	if (!filter::Isdh(filter_file, isdh_file))
		return false;
	{
		task::ConfigReader reader(modeldb_driver_->db());
		if (!reader.Read())
			return false;
		// fill task's rest of fields
		task_->method = reader.GetMethod();
		task_->length = reader.length();
		task_->step = reader.step();
		task_->granularity = reader.granularity();
		task_->output_start_time = reader.output_start_time();
		{
			std::unique_ptr<Layout> layout(new Layout);
			LayoutLoader loader(layout_);
			if (!loader.Load(layout.get()))
				return false;
			size_t layer_size = layout->Calculate();
			assert(layer_size > kOffsetBase);
			task_->layout.swap(layout);
			task_->layer_size = layer_size;

			{
				filter::Cutter cutter;
				if (!cutter.Load(filter_file, layer_size))
					return false;
				task_->writer.reset(cutter.CreateWriter());
			}

			if (reader.GetDpsPath()) {
				auto ls_config = ls::CreateConfiguration(reader.GetDpsPath(), *task_->layout);
				if (!ls_config)
					return false;
				task_->ls_config.swap(ls_config);
			}
		}
	}
	if (task_->method == compiler::Method::kArk) {
		std::unique_ptr<cas::System> system(new cas::System);
		if (!system->Load(modeldb_driver_->db()))
			return false;
		if (!cas::AnnotateEquations(modeldb_driver_->db(), "input_eqs", system.get()))
			return false;
		task_->system = std::move(system);
	} else {
		cas::DimensionAnalyzer da;
		if (!da.Load(modeldb_driver_->db()))
			return false;
		compiler::Compiler c(&da);
		task_->reinit_bc.reset(c.Compile(modeldb_driver_->db(), "dependent_ivs", compiler::Method::kAssign));
		if (!task_->reinit_bc)
			return false;
		task_->bc.reset(c.Compile(modeldb_driver_->db(), "input_eqs", task_->method));
		if (!task_->bc)
			return false;
	}

	db_driver_ = db::Driver::Create(dir_ / "task.db");
	if (!exec::SaveParameters(dir_, db_driver_->db()))
		return false;
	int n = CountParameterSamples(db_driver_->db());
	if (n <= 0)
		return false;
	if (!CreateControlFile(n))
		return false;
	if (!CreateProgressFile(n))
		return false;
	if (task_->ls_config && !CreateRssFile(n))
		return false;
	if (!task::Form(db_driver_->db()))
		return false;
	dimension_analyzer_.reset(new cas::DimensionAnalyzer);
	if (!dimension_analyzer_->Load(db_driver_->db()))
		return false;
	if (!layout::Generate(db_driver_->db(), generated_layout_))
		return false;
	std::vector<std::future<bool> > v;
	size_t c = static_cast<size_t>((arg_ && arg_->concurrency > 0) ? arg_->concurrency : 1);
	char *addr = static_cast<char *>(task_->progress_mr.get_address());
	auto reflect = [addr, n]{
		// addr is 1-based
		auto a = std::accumulate<char *, int64_t>(addr+1, addr+1+n, 0)/n;
		assert(0 <= a && a <= 100);
		*addr = static_cast<char>(a);
	};
	bool generated_all = false;
	unsigned int interval = kUnitInterval;
	bool result = true;
	do {
		while (!generated_all && v.size() < c) {
			int job_id;
			if (!job::Generate(db_driver_->db(), dir_, &job_id))
				return false;
			if (job_id == 0) { // all jobs has been generated
				generated_all = true;
				break;
			}

			auto lmbd = [](TaskRunner *tr, int id){
				JobRunner runner(tr, id);
				return runner.Run();
			};
			v.emplace_back(std::async(std::launch::async, lmbd, this, job_id));
		}

		auto it = v.begin();
		while (it != v.end()) {
			auto &f = *it;
			std::future_status s = f.wait_for(std::chrono::milliseconds(0));
			switch (s) {
			case std::future_status::deferred:
				++it; // come back later
				break;
			case std::future_status::timeout:
				++it;
				break;
			case std::future_status::ready:
				if (!f.get())
					result = false;
				interval = 0;
				it = v.erase(it);
				break;
			}
		}

		reflect();

		if (interval == 0) {
			interval = kUnitInterval;
			if (generated_all && v.empty())
				goto done;
		} else {
			// wait for a job finished
			std::this_thread::sleep_for(std::chrono::milliseconds(interval));
			if (interval < kMaxInterval)
				interval <<= 1;
		}
	} while (!task_->IsCanceled());
	reflect();
 done:
	return result;
}

}
}
<commit_msg>Add a TODO<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- vim:set ts=4 sw=4 sts=4 noet: */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "exec/task-runner.h"

#include <cassert>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <future>
#include <numeric>
#include <vector>

#define BOOST_FILESYSTEM_NO_DEPRECATED
#include <boost/filesystem/fstream.hpp>
#define BOOST_DATE_TIME_NO_LIB
#include <boost/interprocess/file_mapping.hpp>
#include <boost/interprocess/mapped_region.hpp>

#include "bc/index.h"
#include "cas.h"
#include "cas/dimension.h"
#include "compiler.h"
#include "db/driver.h"
#include "db/read-only-driver.h"
#include "db/statement-driver.h"
#include "exec.h"
#include "exec/job-runner.h"
#include "exec/parameter.h"
#include "filter.h"
#include "filter/cutter.h"
#include "flint/ls.h"
#include "flint/workspace.h"
#include "job.h"
#include "layout.h"
#include "lo/layout.h"
#include "lo/layout_loader.h"
#include "load.h"
#include "task.h"
#include "task/config-reader.h"

namespace flint {
namespace exec {

namespace {

int CountParameterSamples(sqlite3 *db)
{
	db::StatementDriver sd(db, "SELECT COUNT(*) FROM parameter_samples");
	int e = sqlite3_step(sd.stmt());
	if (e != SQLITE_ROW) {
		std::cerr << "failed to step statement: " << e << std::endl;
		return -1;
	}
	return sqlite3_column_int(sd.stmt(), 0);
}

const unsigned int kUnitInterval = 200;
const unsigned int kMaxInterval = kUnitInterval << 5;

}

TaskRunner::TaskRunner(int id, char *path, const boost::filesystem::path &dir,
					   ctrl::Argument *arg)
	: id_(id)
	, path_(path)
	, arg_(arg)
	, dir_(dir)
	, layout_(dir)
	, generated_layout_(dir)
{
	char buf[64];
	std::sprintf(buf, "%d", id);
	dir_ /= buf;
	std::sprintf(buf, "%d/layout", id);
	layout_ /= buf;
	std::sprintf(buf, "%d/generated-layout", id);
	generated_layout_ /= buf;
}

TaskRunner::~TaskRunner() = default;

task::Task *TaskRunner::GetTask()
{
	return task_.get();
}

sqlite3 *TaskRunner::GetDatabase()
{
	return db_driver_->db();
}

sqlite3 *TaskRunner::GetModelDatabase()
{
	return modeldb_driver_->db();
}

const cas::DimensionAnalyzer *TaskRunner::GetDimensionAnalyzer() const
{
	return dimension_analyzer_.get();
}

bool TaskRunner::CreateSpec(int id, sqlite3 *db)
{
	auto spec_file = dir_ / "spec.txt";
	boost::filesystem::ofstream ofs(spec_file, std::ios::out|std::ios::binary);
	if (!ofs) {
		std::cerr << "failed to open " << spec_file << std::endl;
		return false;
	}
	bool r = task::Spec(id, db, ofs);
	ofs.close();
	return r;
}

bool TaskRunner::CreateControlFile(int num_samples)
{
	assert(task_);

	auto control_file = dir_ / "control";
	size_t size = num_samples + 1;
	if (!workspace::CreateSparseFileAtomically(control_file, size))
		return false;
	try {
		boost::interprocess::file_mapping fm(control_file.string().c_str(), boost::interprocess::read_write);
		boost::interprocess::mapped_region mr(fm, boost::interprocess::read_write);
		task_->control_mr = std::move(mr);
	} catch (const boost::interprocess::interprocess_exception &e) {
		std::cerr << "failed to map file: " << e.what() << std::endl;
		return false;
	}
	return true;
}

bool TaskRunner::CreateProgressFile(int num_samples)
{
	auto progress_file = dir_ / "progress";
	size_t size = num_samples + 1;
	if (!workspace::CreateSparseFileAtomically(progress_file, size))
		return false;
	try {
		boost::interprocess::file_mapping fm(progress_file.string().c_str(), boost::interprocess::read_write);
		boost::interprocess::mapped_region mr(fm, boost::interprocess::read_write);
		task_->progress_mr = std::move(mr);
	} catch (const boost::interprocess::interprocess_exception &e) {
		std::cerr << "failed to map file: " << e.what() << std::endl;
		return false;
	}
	return true;
}

bool TaskRunner::CreateRssFile(int num_samples)
{
	auto rss_file = dir_ / "rss";
	size_t size = (num_samples + 1) * sizeof(double);
	if (!workspace::CreateSparseFileAtomically(rss_file, size))
		return false;
	try {
		boost::interprocess::file_mapping fm(rss_file.string().c_str(), boost::interprocess::read_write);
		boost::interprocess::mapped_region mr(fm, boost::interprocess::read_write);
		task_->rss_mr = std::move(mr);
	} catch (const boost::interprocess::interprocess_exception &e) {
		std::cerr << "failed to map file: " << e.what() << std::endl;
		return false;
	}
	return true;
}

bool TaskRunner::Run()
{
	task_.reset(load::Load(path_.get(), load::kExec, dir_, &data_));
	if (!task_)
		return false;
	{
		auto driver = db::Driver::Create(dir_.parent_path() / "x.db");
		auto db = driver->db();
		if (!db)
			return false;
		if (!task::Config(id_, db, dir_))
			return false;
	}
	{
		auto driver = db::ReadOnlyDriver::Create(dir_.parent_path() / "x.db");
		auto db = driver->db();
		if (!db)
			return false;
		if (!CreateSpec(id_, db))
			return false;
	}

	modeldb_driver_ = db::ReadOnlyDriver::Create(dir_ / "model.db");
	auto spec_file = dir_ / "spec.txt";
	auto filter_file = dir_ / "filter";
	if (!filter::Create(modeldb_driver_->db(), spec_file, layout_, filter_file))
		return false;
	auto track_file = dir_ / "track";
	if (!filter::Track(filter_file, track_file))
		return false;
	auto isdh_file = dir_ / "isdh";
	if (!filter::Isdh(filter_file, isdh_file))
		return false;
	{
		task::ConfigReader reader(modeldb_driver_->db());
		if (!reader.Read())
			return false;
		// fill task's rest of fields
		task_->method = reader.GetMethod();
		task_->length = reader.length();
		task_->step = reader.step();
		task_->granularity = reader.granularity();
		task_->output_start_time = reader.output_start_time();
		{
			std::unique_ptr<Layout> layout(new Layout);
			LayoutLoader loader(layout_);
			if (!loader.Load(layout.get()))
				return false;
			size_t layer_size = layout->Calculate();
			assert(layer_size > kOffsetBase);
			task_->layout.swap(layout);
			task_->layer_size = layer_size;

			{
				filter::Cutter cutter;
				if (!cutter.Load(filter_file, layer_size))
					return false;
				task_->writer.reset(cutter.CreateWriter());
			}

			if (reader.GetDpsPath()) {
				auto ls_config = ls::CreateConfiguration(reader.GetDpsPath(), *task_->layout);
				if (!ls_config)
					return false;
				task_->ls_config.swap(ls_config);
			}
		}
	}
	if (task_->method == compiler::Method::kArk) {
		std::unique_ptr<cas::System> system(new cas::System);
		if (!system->Load(modeldb_driver_->db()))
			return false;
		if (!cas::AnnotateEquations(modeldb_driver_->db(), "input_eqs", system.get()))
			return false;
		task_->system = std::move(system);
	} else {
		cas::DimensionAnalyzer da;
		if (!da.Load(modeldb_driver_->db()))
			return false;
		compiler::Compiler c(&da);
		task_->reinit_bc.reset(c.Compile(modeldb_driver_->db(), "dependent_ivs", compiler::Method::kAssign));
		if (!task_->reinit_bc)
			return false;
		task_->bc.reset(c.Compile(modeldb_driver_->db(), "input_eqs", task_->method));
		if (!task_->bc)
			return false;
	}

	db_driver_ = db::Driver::Create(dir_ / "task.db");
	if (!exec::SaveParameters(dir_, db_driver_->db()))
		return false;
	int n = CountParameterSamples(db_driver_->db());
	if (n <= 0)
		return false;
	if (!CreateControlFile(n))
		return false;
	if (!CreateProgressFile(n))
		return false;
	if (task_->ls_config && !CreateRssFile(n))
		return false;
	if (!task::Form(db_driver_->db()))
		return false;
	dimension_analyzer_.reset(new cas::DimensionAnalyzer);
	if (!dimension_analyzer_->Load(db_driver_->db()))
		return false;
	if (!layout::Generate(db_driver_->db(), generated_layout_))
		return false;
	std::vector<std::future<bool> > v;
	size_t c = static_cast<size_t>((arg_ && arg_->concurrency > 0) ? arg_->concurrency : 1);
	char *addr = static_cast<char *>(task_->progress_mr.get_address());
	auto reflect = [addr, n]{
		// addr is 1-based
		auto a = std::accumulate<char *, int64_t>(addr+1, addr+1+n, 0)/n; // TODO: replace with C++17's std::reduce
		assert(0 <= a && a <= 100);
		*addr = static_cast<char>(a);
	};
	bool generated_all = false;
	unsigned int interval = kUnitInterval;
	bool result = true;
	do {
		while (!generated_all && v.size() < c) {
			int job_id;
			if (!job::Generate(db_driver_->db(), dir_, &job_id))
				return false;
			if (job_id == 0) { // all jobs has been generated
				generated_all = true;
				break;
			}

			auto lmbd = [](TaskRunner *tr, int id){
				JobRunner runner(tr, id);
				return runner.Run();
			};
			v.emplace_back(std::async(std::launch::async, lmbd, this, job_id));
		}

		auto it = v.begin();
		while (it != v.end()) {
			auto &f = *it;
			std::future_status s = f.wait_for(std::chrono::milliseconds(0));
			switch (s) {
			case std::future_status::deferred:
				++it; // come back later
				break;
			case std::future_status::timeout:
				++it;
				break;
			case std::future_status::ready:
				if (!f.get())
					result = false;
				interval = 0;
				it = v.erase(it);
				break;
			}
		}

		reflect();

		if (interval == 0) {
			interval = kUnitInterval;
			if (generated_all && v.empty())
				goto done;
		} else {
			// wait for a job finished
			std::this_thread::sleep_for(std::chrono::milliseconds(interval));
			if (interval < kMaxInterval)
				interval <<= 1;
		}
	} while (!task_->IsCanceled());
	reflect();
 done:
	return result;
}

}
}
<|endoftext|>


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

#include <grpc/support/port_platform.h>

#ifdef GPR_POSIX_SYNC

#include <errno.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
#include <time.h>
#include "src/core/lib/profiling/timers.h"

#ifdef GPR_LOW_LEVEL_COUNTERS
gpr_atm gpr_mu_locks = 0;
gpr_atm gpr_counter_atm_cas = 0;
gpr_atm gpr_counter_atm_add = 0;
#endif

void gpr_mu_init(gpr_mu* mu) {
  GPR_ASSERT(pthread_mutex_init(mu, nullptr) == 0);
}

void gpr_mu_destroy(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_destroy(mu) == 0); }

void gpr_mu_lock(gpr_mu* mu) {
#ifdef GPR_LOW_LEVEL_COUNTERS
  GPR_ATM_INC_COUNTER(gpr_mu_locks);
#endif
  GPR_TIMER_BEGIN("gpr_mu_lock", 0);
  GPR_ASSERT(pthread_mutex_lock(mu) == 0);
  GPR_TIMER_END("gpr_mu_lock", 0);
}

void gpr_mu_unlock(gpr_mu* mu) {
  GPR_TIMER_BEGIN("gpr_mu_unlock", 0);
  GPR_ASSERT(pthread_mutex_unlock(mu) == 0);
  GPR_TIMER_END("gpr_mu_unlock", 0);
}

int gpr_mu_trylock(gpr_mu* mu) {
  int err;
  GPR_TIMER_BEGIN("gpr_mu_trylock", 0);
  err = pthread_mutex_trylock(mu);
  GPR_ASSERT(err == 0 || err == EBUSY);
  GPR_TIMER_END("gpr_mu_trylock", 0);
  return err == 0;
}

/*----------------------------------------*/

void gpr_cv_init(gpr_cv* cv) {
  GPR_ASSERT(pthread_cond_init(cv, nullptr) == 0);
}

void gpr_cv_destroy(gpr_cv* cv) { GPR_ASSERT(pthread_cond_destroy(cv) == 0); }

int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) {
  int err = 0;
  if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) ==
      0) {
    err = pthread_cond_wait(cv, mu);
  } else {
    struct timespec abs_deadline_ts;
    abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME);
    abs_deadline_ts.tv_sec = (time_t)abs_deadline.tv_sec;
    abs_deadline_ts.tv_nsec = abs_deadline.tv_nsec;
    err = pthread_cond_timedwait(cv, mu, &abs_deadline_ts);
  }
  GPR_ASSERT(err == 0 || err == ETIMEDOUT || err == EAGAIN);
  return err == ETIMEDOUT;
}

void gpr_cv_signal(gpr_cv* cv) { GPR_ASSERT(pthread_cond_signal(cv) == 0); }

void gpr_cv_broadcast(gpr_cv* cv) {
  GPR_ASSERT(pthread_cond_broadcast(cv) == 0);
}

/*----------------------------------------*/

void gpr_once_init(gpr_once* once, void (*init_function)(void)) {
  GPR_ASSERT(pthread_once(once, init_function) == 0);
}

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

#include <grpc/support/port_platform.h>

#ifdef GPR_POSIX_SYNC

#include <errno.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
#include <time.h>
#include "src/core/lib/profiling/timers.h"

#ifdef GPR_LOW_LEVEL_COUNTERS
gpr_atm gpr_mu_locks = 0;
gpr_atm gpr_counter_atm_cas = 0;
gpr_atm gpr_counter_atm_add = 0;
#endif

void gpr_mu_init(gpr_mu* mu) {
  GPR_ASSERT(pthread_mutex_init(mu, nullptr) == 0);
}

void gpr_mu_destroy(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_destroy(mu) == 0); }

void gpr_mu_lock(gpr_mu* mu) {
#ifdef GPR_LOW_LEVEL_COUNTERS
  GPR_ATM_INC_COUNTER(gpr_mu_locks);
#endif
  GPR_TIMER_BEGIN("gpr_mu_lock", 0);
  GPR_ASSERT(pthread_mutex_lock(mu) == 0);
  GPR_TIMER_END("gpr_mu_lock", 0);
}

void gpr_mu_unlock(gpr_mu* mu) {
  GPR_TIMER_BEGIN("gpr_mu_unlock", 0);
  GPR_ASSERT(pthread_mutex_unlock(mu) == 0);
  GPR_TIMER_END("gpr_mu_unlock", 0);
}

int gpr_mu_trylock(gpr_mu* mu) {
  int err;
  GPR_TIMER_BEGIN("gpr_mu_trylock", 0);
  err = pthread_mutex_trylock(mu);
  GPR_ASSERT(err == 0 || err == EBUSY);
  GPR_TIMER_END("gpr_mu_trylock", 0);
  return err == 0;
}

/*----------------------------------------*/

void gpr_cv_init(gpr_cv* cv) {
  pthread_condattr_t attr;
  GPR_ASSERT(pthread_condattr_init(&attr) == 0);
#if GPR_LINUX
  GPR_ASSERT(pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) == 0);
#endif  // GPR_LINUX
  GPR_ASSERT(pthread_cond_init(cv, &attr) == 0);
}

void gpr_cv_destroy(gpr_cv* cv) { GPR_ASSERT(pthread_cond_destroy(cv) == 0); }

int gpr_cv_wait(gpr_cv* cv, gpr_mu* mu, gpr_timespec abs_deadline) {
  int err = 0;
  if (gpr_time_cmp(abs_deadline, gpr_inf_future(abs_deadline.clock_type)) ==
      0) {
    err = pthread_cond_wait(cv, mu);
  } else {
    struct timespec abs_deadline_ts;
#if GPR_LINUX
    abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_MONOTONIC);
#else
    abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME);
#endif  // GPR_LINUX
    abs_deadline_ts.tv_sec = (time_t)abs_deadline.tv_sec;
    abs_deadline_ts.tv_nsec = abs_deadline.tv_nsec;
    err = pthread_cond_timedwait(cv, mu, &abs_deadline_ts);
  }
  GPR_ASSERT(err == 0 || err == ETIMEDOUT || err == EAGAIN);
  return err == ETIMEDOUT;
}

void gpr_cv_signal(gpr_cv* cv) { GPR_ASSERT(pthread_cond_signal(cv) == 0); }

void gpr_cv_broadcast(gpr_cv* cv) {
  GPR_ASSERT(pthread_cond_broadcast(cv) == 0);
}

/*----------------------------------------*/

void gpr_once_init(gpr_once* once, void (*init_function)(void)) {
  GPR_ASSERT(pthread_once(once, init_function) == 0);
}

#endif /* GRP_POSIX_SYNC */
<|endoftext|>


<commit_before>//
// Created by dar on 2/29/16.
//

#include "EntityDoor.h"

EntityDoor::EntityDoor(Map *map, unsigned char type) : EntityMoving(map, 1.0, 0.25), type(type) {
    b2PolygonShape shape;
    shape.SetAsBox(0.5 - 0.05, 0.125);
    b2FixtureDef fixDef;
    fixDef.shape = &shape;
    fixDef.density = 0.01f;
    fixDef.friction = 0.1f;

    this->body->CreateFixture(&fixDef);

    this->hinge = this->map->getWorld()->CreateBody(&bodyDef);
    b2CircleShape circleShape;
    circleShape.m_radius = 0.001;
    fixDef.shape = &circleShape;
    this->hinge->CreateFixture(&fixDef);
    this->hinge->SetUserData(this);
    this->hinge->SetAngularDamping(30.0);
    this->hinge->SetLinearDamping(30.0);
    this->hinge->CreateFixture(&fixDef);

    b2RevoluteJointDef revoluteJointDef;

    revoluteJointDef.localAnchorA.Set(this->getHingeOffsetX(), this->getHingeOffsetY()); //-0.125 for hinge on top, 0.125 on bottom
    revoluteJointDef.localAnchorB.Set(0, 0);

    //inside the loop, only need to change the bodies to be joined
    revoluteJointDef.bodyA = this->body;
    revoluteJointDef.bodyB = this->hinge;
    this->map->getWorld()->CreateJoint(&revoluteJointDef);
}

void EntityDoor::setX(double x) {
    Entity::setX(x);
    this->hinge->SetTransform(b2Vec2((float32) (x - this->width * 0.5 + this->getHingeOffsetX()), this->hinge->GetPosition().y), this->hinge->GetAngle());
}

void EntityDoor::setY(double y) {
    Entity::setY(y);
    this->hinge->SetTransform(b2Vec2(this->hinge->GetPosition().x, (float32) (y - this->height * 0.5 + this->getHingeOffsetY())), this->hinge->GetAngle());
}<commit_msg>Adjusted doors density<commit_after>//
// Created by dar on 2/29/16.
//

#include "EntityDoor.h"

EntityDoor::EntityDoor(Map *map, unsigned char type) : EntityMoving(map, 1.0, 0.25), type(type) {
    b2PolygonShape shape;
    shape.SetAsBox(0.5 - 0.05, 0.125);
    b2FixtureDef fixDef;
    fixDef.shape = &shape;
    fixDef.density = 0.06f;
    fixDef.friction = 0.1f;

    this->body->CreateFixture(&fixDef);

    this->hinge = this->map->getWorld()->CreateBody(&bodyDef);
    b2CircleShape circleShape;
    circleShape.m_radius = 0.001;
    fixDef.shape = &circleShape;
    this->hinge->CreateFixture(&fixDef);
    this->hinge->SetUserData(this);
    this->hinge->SetAngularDamping(30.0);
    this->hinge->SetLinearDamping(30.0);
    this->hinge->CreateFixture(&fixDef);

    b2RevoluteJointDef revoluteJointDef;

    revoluteJointDef.localAnchorA.Set(this->getHingeOffsetX(), this->getHingeOffsetY()); //-0.125 for hinge on top, 0.125 on bottom
    revoluteJointDef.localAnchorB.Set(0, 0);

    //inside the loop, only need to change the bodies to be joined
    revoluteJointDef.bodyA = this->body;
    revoluteJointDef.bodyB = this->hinge;
    this->map->getWorld()->CreateJoint(&revoluteJointDef);
}

void EntityDoor::setX(double x) {
    Entity::setX(x);
    this->hinge->SetTransform(b2Vec2((float32) (x - this->width * 0.5 + this->getHingeOffsetX()), this->hinge->GetPosition().y), this->hinge->GetAngle());
}

void EntityDoor::setY(double y) {
    Entity::setY(y);
    this->hinge->SetTransform(b2Vec2(this->hinge->GetPosition().x, (float32) (y - this->height * 0.5 + this->getHingeOffsetY())), this->hinge->GetAngle());
}<|endoftext|>


<commit_before>/*
 * RTokenizer.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/r_util/RTokenizer.hpp>

#include <boost/regex.hpp>

#include <core/Error.hpp>
#include <core/Log.hpp>

namespace core {
namespace r_util {

namespace {

class TokenPatterns
{
private:
   friend TokenPatterns& tokenPatterns();
   TokenPatterns()
      : NUMBER(L"[0-9]*(\\.[0-9]*)?([eE][+-]?[0-9]*)?[Li]?"),
        HEX_NUMBER(L"0x[0-9a-fA-F]*L?"),
        USER_OPERATOR(L"%[^%]*%"),
        REST_OF_IDENTIFIER(L"[\\w.]*"),
        QUOTED_IDENTIFIER(L"`[^`]*`"),
        UNTIL_END_QUOTE(L"[\\\\\'\"]"),
        WHITESPACE(L"[\\s\\u00A0\u3000]+"),
        COMMENT(L"#.*?$")
   {
   }

public:
   const boost::wregex NUMBER;
   const boost::wregex HEX_NUMBER;
   const boost::wregex USER_OPERATOR;
   const boost::wregex REST_OF_IDENTIFIER;
   const boost::wregex QUOTED_IDENTIFIER;
   const boost::wregex UNTIL_END_QUOTE;
   const boost::wregex WHITESPACE;
   const boost::wregex COMMENT;
};

TokenPatterns& tokenPatterns()
{
   static TokenPatterns instance;
   return instance;
}

} // anonymous namespace

const wchar_t RToken::LPAREN         = L'(';
const wchar_t RToken::RPAREN         = L')';
const wchar_t RToken::LBRACKET       = L'[';
const wchar_t RToken::RBRACKET       = L']';
const wchar_t RToken::LBRACE         = L'{';
const wchar_t RToken::RBRACE         = L'}';
const wchar_t RToken::COMMA          = L',';
const wchar_t RToken::SEMI           = L';';
const wchar_t RToken::WHITESPACE     = 0x1001;
const wchar_t RToken::STRING         = 0x1002;
const wchar_t RToken::NUMBER         = 0x1003;
const wchar_t RToken::ID             = 0x1004;
const wchar_t RToken::OPER           = 0x1005;
const wchar_t RToken::UOPER          = 0x1006;
const wchar_t RToken::ERROR          = 0x1007;
const wchar_t RToken::LDBRACKET      = 0x1008;
const wchar_t RToken::RDBRACKET      = 0x1009;
const wchar_t RToken::COMMENT        = 0x100A;

struct RToken::Impl
{
   Impl(wchar_t type,
        std::wstring::const_iterator begin,
        std::wstring::const_iterator end,
        std::size_t offset,
        std::size_t length)
      : type(type), begin(begin), end(end), offset(offset), length(length)
   {
   }
   wchar_t type;
   std::wstring::const_iterator begin;
   std::wstring::const_iterator end;
   std::size_t offset;
   std::size_t length;
};

RToken::RToken()
   : pImpl_()
{
}

RToken::RToken(wchar_t type,
               std::wstring::const_iterator begin,
               std::wstring::const_iterator end,
               std::size_t offset,
               std::size_t length)
   : pImpl_(new Impl(type, begin, end, offset, length))
{
}

RToken::~RToken()
{
}

wchar_t RToken::type() const
{
   return pImpl_->type;
}

std::wstring RToken::content() const
{
   return std::wstring(pImpl_->begin, pImpl_->end);
}

std::size_t RToken::offset() const
{
   return pImpl_->offset;
}

std::size_t RToken::length() const
{
   return pImpl_->length;
}

bool operator==(const RToken& lhs, const RToken& rhs)
{
   if (!lhs && !rhs)
   {
      return true;
   }
   else if (!lhs || !rhs)
   {
      return false;
   }
   else
   {
      return lhs.type() == rhs.type() &&
             lhs.content() == rhs.content() &&
             lhs.offset() == rhs.offset() &&
             lhs.length() == rhs.length();
   }
}

const std::size_t RTokenRange::NPOS = -1;

RTokenRange::RTokenRange(const std::wstring& code)
   : tokenizer_(code), pos_(NPOS)
{
   // make a copy of the tokens so we can access them randomly
   RToken token;
   while (token = tokenizer_.nextToken())
      tokens_.push_back(token);
}

bool RTokenRange::isBOD() const
{
   return pos_ == NPOS;
}

bool RTokenRange::isEOD() const
{
   return pos_ > tokens_.size();
}

RToken RTokenRange::currentToken()
{
   if (pos_ != NPOS && (tokens_.size() > pos_))
      return tokens_.at(pos_) ;
   else
      return RToken();
}

RToken RTokenRange::next()
{
   pos_++ ;
   ensureValidIndex() ;
   return currentToken() ;
}

RToken RTokenRange::prev()
{
   pos_-- ;
   ensureValidIndex() ;
   return currentToken() ;
}

Error RTokenRange::moveTo(std::size_t index)
{
   if (index > tokens_.size())
      return systemError(boost::system::errc::invalid_seek, ERROR_LOCATION);

   pos_ = index ;

   return Success();
}

void RTokenRange::moveToBOD()
{
   pos_ = NPOS;
}

void RTokenRange::moveToEOD()
{
   pos_ = tokens_.size();
}

void RTokenRange::ensureValidIndex()
{
   pos_ = std::min(std::max(NPOS, pos_), tokens_.size()) ;
}

RToken RTokenizer::nextToken()
{
  if (eol())
     return RToken() ;

  wchar_t c = peek() ;

  switch (c)
  {
  case L'(': case L')':
  case L'{': case L'}':
  case L';': case L',':
     return consumeToken(c, 1) ;
  case L'[':
     if (peek(1) == L'[')
        return consumeToken(RToken::LDBRACKET, 2) ;
     else
        return consumeToken(c, 1) ;
  case L']':
     if (peek(1) == L']')
        return consumeToken(RToken::RDBRACKET, 2) ;
     else
        return consumeToken(c, 1) ;
  case L'"':
  case L'\'':
     return matchStringLiteral() ;
  case L'`':
     return matchQuotedIdentifier();
  case L'#':
     return matchComment();
  case L'%':
     return matchUserOperator();
  case L' ': case L'\t': case L'\r': case L'\n':
  case L'\u00A0': case L'\u3000':
     return matchWhitespace() ;
  }

  wchar_t cNext = peek(1) ;

  if ((c >= L'0' && c <= L'9')
        || (c == L'.' && cNext >= L'0' && cNext <= L'9'))
  {
     RToken numberToken = matchNumber() ;
     if (numberToken.length() > 0)
        return numberToken ;
  }

  if (std::iswalpha(c) || c == L'.')
  {
     // From Section 10.3.2, identifiers must not start with
     // a period followed by a digit.
     //
     // Since we're not checking that the second character is
     // not a digit, we must match on identifiers AFTER we have
     // already tried to match on number.
     return matchIdentifier() ;
  }

  RToken oper = matchOperator() ;
  if (oper)
     return oper ;

  // Error!!
  return consumeToken(RToken::ERROR, 1) ;
}

RToken RTokenizer::matchWhitespace()
{
   std::wstring whitespace = peek(tokenPatterns().WHITESPACE) ;
   return consumeToken(RToken::WHITESPACE, whitespace.length()) ;
}

RToken RTokenizer::matchStringLiteral()
{
   std::wstring::const_iterator start = pos_ ;
   wchar_t quot = eat() ;

   bool wellFormed = false ;

   while (!eol())
   {
      eatUntil(tokenPatterns().UNTIL_END_QUOTE);

      if (eol())
         break ;

      wchar_t c = eat() ;
      if (c == quot)
      {
         wellFormed = true ;
         break ;
      }

      if (c == L'\\')
      {
         if (!eol())
            eat() ;

         // Actually the escape expression can be longer than
         // just the backslash plus one character--but we don't
         // need to distinguish escape expressions from other
         // literal text other than for the purposes of breaking
         // out of the string
      }
   }

   return RStringToken(RToken::STRING,
                       start,
                       pos_,
                       start - data_.begin(),
                       pos_ - start,
                       wellFormed) ;
}

RToken RTokenizer::matchNumber()
{
   std::wstring num = peek(tokenPatterns().HEX_NUMBER) ;
   if (num.empty())
      num = peek(tokenPatterns().NUMBER) ;

   return consumeToken(RToken::NUMBER, num.length());
}

RToken RTokenizer::matchIdentifier()
{
   std::wstring::const_iterator start = pos_ ;
   eat();
   std::wstring rest = peek(tokenPatterns().REST_OF_IDENTIFIER) ;
   pos_ += rest.length() ;
   return RToken(RToken::ID,
                 start,
                 pos_,
                 start - data_.begin(),
                 pos_ - start) ;
}

RToken RTokenizer::matchQuotedIdentifier()
{
   std::wstring iden = peek(tokenPatterns().QUOTED_IDENTIFIER) ;
   if (iden.empty())
      return consumeToken(RToken::ERROR, 1);
   else
      return consumeToken(RToken::ID, iden.length());
}

RToken RTokenizer::matchComment()
{
   std::wstring comment = peek(tokenPatterns().COMMENT);
   return consumeToken(RToken::COMMENT, comment.length());
}

RToken RTokenizer::matchUserOperator()
{
   std::wstring oper = peek(tokenPatterns().USER_OPERATOR) ;
   if (oper.empty())
      return consumeToken(RToken::ERROR, 1) ;
   else
      return consumeToken(RToken::UOPER, oper.length()) ;
}

RToken RTokenizer::matchOperator()
{
   wchar_t cNext = peek(1) ;

   switch (peek())
   {
   case L'+': case L'*': case L'/':
   case L'^': case L'&': case L'|':
   case L'~': case L'$': case L':':
      // single-character operators
      return consumeToken(RToken::OPER, 1) ;
   case L'-': // also ->
      return consumeToken(RToken::OPER, cNext == L'>' ? 2 : 1) ;
   case L'>': // also >=
      return consumeToken(RToken::OPER, cNext == L'=' ? 2 : 1) ;
   case L'<': // also <- and <=
      return consumeToken(RToken::OPER, cNext == L'=' ? 2 :
                                       cNext == L'-' ? 2 :
                                       1) ;
   case L'=': // also ==
      return consumeToken(RToken::OPER, cNext == L'=' ? 2 : 1) ;
   case L'!': // also !=
      return consumeToken(RToken::OPER, cNext == L'=' ? 2 : 1) ;
   default:
      return RToken() ;
   }
}

bool RTokenizer::eol()
{
   return pos_ >= data_.end();
}

wchar_t RTokenizer::peek()
{
   return peek(0) ;
}

wchar_t RTokenizer::peek(std::size_t lookahead)
{
   if ((pos_ + lookahead) >= data_.end())
      return 0 ;
   else
      return *(pos_ + lookahead) ;
}

wchar_t RTokenizer::eat()
{
   wchar_t result = *pos_;
   pos_++ ;
   return result ;
}

std::wstring RTokenizer::peek(const boost::wregex& regex)
{
   boost::wsmatch match;
   std::wstring::const_iterator end = data_.end();
   boost::match_flag_type flg = boost::match_default | boost::match_continuous;
   if (boost::regex_search(pos_, end, match, regex, flg))
   {
      return match[0];
   }
   else
   {
      return std::wstring();
   }
}

void RTokenizer::eatUntil(const boost::wregex& regex)
{
   boost::wsmatch match;
   std::wstring::const_iterator end = data_.end();
   if (boost::regex_search(pos_, end, match, regex))
   {
      pos_ = match[0].first;
   }
   else
   {
      // eat all on failure to match
      pos_ = data_.end();
   }
}

RToken RTokenizer::consumeToken(wchar_t tokenType, std::size_t length)
{
   if (length == 0)
   {
      LOG_WARNING_MESSAGE("Can't create zero-length token");
      return RToken();
   }
   else if (pos_ + length > data_.end())
   {
      LOG_WARNING_MESSAGE("Premature EOF");
      return RToken();
   }

   std::wstring::const_iterator start = pos_ ;
   pos_ += length ;
   return RToken(tokenType,
                 start,
                 pos_,
                 start - data_.begin(),
                 length) ;
}

} // namespace r_util
} // namespace core

<commit_msg>add todo comments for tokenizer<commit_after>/*
 * RTokenizer.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

// TODO: Eliminate length field (can be calculated)
// TODO: Eliminate shared_ptr for no allocations at all
// TODO: Operator == shouldn't call contents()
// TODO: Slicing of RStringToken (may need to merge w/ RToken)
// TODO: RTokenRange is broken (NPOS=-1)

#include <core/r_util/RTokenizer.hpp>

#include <boost/regex.hpp>

#include <core/Error.hpp>
#include <core/Log.hpp>

namespace core {
namespace r_util {

namespace {

class TokenPatterns
{
private:
   friend TokenPatterns& tokenPatterns();
   TokenPatterns()
      : NUMBER(L"[0-9]*(\\.[0-9]*)?([eE][+-]?[0-9]*)?[Li]?"),
        HEX_NUMBER(L"0x[0-9a-fA-F]*L?"),
        USER_OPERATOR(L"%[^%]*%"),
        REST_OF_IDENTIFIER(L"[\\w.]*"),
        QUOTED_IDENTIFIER(L"`[^`]*`"),
        UNTIL_END_QUOTE(L"[\\\\\'\"]"),
        WHITESPACE(L"[\\s\\u00A0\u3000]+"),
        COMMENT(L"#.*?$")
   {
   }

public:
   const boost::wregex NUMBER;
   const boost::wregex HEX_NUMBER;
   const boost::wregex USER_OPERATOR;
   const boost::wregex REST_OF_IDENTIFIER;
   const boost::wregex QUOTED_IDENTIFIER;
   const boost::wregex UNTIL_END_QUOTE;
   const boost::wregex WHITESPACE;
   const boost::wregex COMMENT;
};

TokenPatterns& tokenPatterns()
{
   static TokenPatterns instance;
   return instance;
}

} // anonymous namespace

const wchar_t RToken::LPAREN         = L'(';
const wchar_t RToken::RPAREN         = L')';
const wchar_t RToken::LBRACKET       = L'[';
const wchar_t RToken::RBRACKET       = L']';
const wchar_t RToken::LBRACE         = L'{';
const wchar_t RToken::RBRACE         = L'}';
const wchar_t RToken::COMMA          = L',';
const wchar_t RToken::SEMI           = L';';
const wchar_t RToken::WHITESPACE     = 0x1001;
const wchar_t RToken::STRING         = 0x1002;
const wchar_t RToken::NUMBER         = 0x1003;
const wchar_t RToken::ID             = 0x1004;
const wchar_t RToken::OPER           = 0x1005;
const wchar_t RToken::UOPER          = 0x1006;
const wchar_t RToken::ERROR          = 0x1007;
const wchar_t RToken::LDBRACKET      = 0x1008;
const wchar_t RToken::RDBRACKET      = 0x1009;
const wchar_t RToken::COMMENT        = 0x100A;

struct RToken::Impl
{
   Impl(wchar_t type,
        std::wstring::const_iterator begin,
        std::wstring::const_iterator end,
        std::size_t offset,
        std::size_t length)
      : type(type), begin(begin), end(end), offset(offset), length(length)
   {
   }
   wchar_t type;
   std::wstring::const_iterator begin;
   std::wstring::const_iterator end;
   std::size_t offset;
   std::size_t length;
};

RToken::RToken()
   : pImpl_()
{
}

RToken::RToken(wchar_t type,
               std::wstring::const_iterator begin,
               std::wstring::const_iterator end,
               std::size_t offset,
               std::size_t length)
   : pImpl_(new Impl(type, begin, end, offset, length))
{
}

RToken::~RToken()
{
}

wchar_t RToken::type() const
{
   return pImpl_->type;
}

std::wstring RToken::content() const
{
   return std::wstring(pImpl_->begin, pImpl_->end);
}

std::size_t RToken::offset() const
{
   return pImpl_->offset;
}

std::size_t RToken::length() const
{
   return pImpl_->length;
}

bool operator==(const RToken& lhs, const RToken& rhs)
{
   if (!lhs && !rhs)
   {
      return true;
   }
   else if (!lhs || !rhs)
   {
      return false;
   }
   else
   {
      return lhs.type() == rhs.type() &&
             lhs.content() == rhs.content() &&
             lhs.offset() == rhs.offset() &&
             lhs.length() == rhs.length();
   }
}

const std::size_t RTokenRange::NPOS = -1;

RTokenRange::RTokenRange(const std::wstring& code)
   : tokenizer_(code), pos_(NPOS)
{
   // make a copy of the tokens so we can access them randomly
   RToken token;
   while (token = tokenizer_.nextToken())
      tokens_.push_back(token);
}

bool RTokenRange::isBOD() const
{
   return pos_ == NPOS;
}

bool RTokenRange::isEOD() const
{
   return pos_ > tokens_.size();
}

RToken RTokenRange::currentToken()
{
   if (pos_ != NPOS && (tokens_.size() > pos_))
      return tokens_.at(pos_) ;
   else
      return RToken();
}

RToken RTokenRange::next()
{
   pos_++ ;
   ensureValidIndex() ;
   return currentToken() ;
}

RToken RTokenRange::prev()
{
   pos_-- ;
   ensureValidIndex() ;
   return currentToken() ;
}

Error RTokenRange::moveTo(std::size_t index)
{
   if (index > tokens_.size())
      return systemError(boost::system::errc::invalid_seek, ERROR_LOCATION);

   pos_ = index ;

   return Success();
}

void RTokenRange::moveToBOD()
{
   pos_ = NPOS;
}

void RTokenRange::moveToEOD()
{
   pos_ = tokens_.size();
}

void RTokenRange::ensureValidIndex()
{
   pos_ = std::min(std::max(NPOS, pos_), tokens_.size()) ;
}

RToken RTokenizer::nextToken()
{
  if (eol())
     return RToken() ;

  wchar_t c = peek() ;

  switch (c)
  {
  case L'(': case L')':
  case L'{': case L'}':
  case L';': case L',':
     return consumeToken(c, 1) ;
  case L'[':
     if (peek(1) == L'[')
        return consumeToken(RToken::LDBRACKET, 2) ;
     else
        return consumeToken(c, 1) ;
  case L']':
     if (peek(1) == L']')
        return consumeToken(RToken::RDBRACKET, 2) ;
     else
        return consumeToken(c, 1) ;
  case L'"':
  case L'\'':
     return matchStringLiteral() ;
  case L'`':
     return matchQuotedIdentifier();
  case L'#':
     return matchComment();
  case L'%':
     return matchUserOperator();
  case L' ': case L'\t': case L'\r': case L'\n':
  case L'\u00A0': case L'\u3000':
     return matchWhitespace() ;
  }

  wchar_t cNext = peek(1) ;

  if ((c >= L'0' && c <= L'9')
        || (c == L'.' && cNext >= L'0' && cNext <= L'9'))
  {
     RToken numberToken = matchNumber() ;
     if (numberToken.length() > 0)
        return numberToken ;
  }

  if (std::iswalpha(c) || c == L'.')
  {
     // From Section 10.3.2, identifiers must not start with
     // a period followed by a digit.
     //
     // Since we're not checking that the second character is
     // not a digit, we must match on identifiers AFTER we have
     // already tried to match on number.
     return matchIdentifier() ;
  }

  RToken oper = matchOperator() ;
  if (oper)
     return oper ;

  // Error!!
  return consumeToken(RToken::ERROR, 1) ;
}

RToken RTokenizer::matchWhitespace()
{
   std::wstring whitespace = peek(tokenPatterns().WHITESPACE) ;
   return consumeToken(RToken::WHITESPACE, whitespace.length()) ;
}

RToken RTokenizer::matchStringLiteral()
{
   std::wstring::const_iterator start = pos_ ;
   wchar_t quot = eat() ;

   bool wellFormed = false ;

   while (!eol())
   {
      eatUntil(tokenPatterns().UNTIL_END_QUOTE);

      if (eol())
         break ;

      wchar_t c = eat() ;
      if (c == quot)
      {
         wellFormed = true ;
         break ;
      }

      if (c == L'\\')
      {
         if (!eol())
            eat() ;

         // Actually the escape expression can be longer than
         // just the backslash plus one character--but we don't
         // need to distinguish escape expressions from other
         // literal text other than for the purposes of breaking
         // out of the string
      }
   }

   return RStringToken(RToken::STRING,
                       start,
                       pos_,
                       start - data_.begin(),
                       pos_ - start,
                       wellFormed) ;
}

RToken RTokenizer::matchNumber()
{
   std::wstring num = peek(tokenPatterns().HEX_NUMBER) ;
   if (num.empty())
      num = peek(tokenPatterns().NUMBER) ;

   return consumeToken(RToken::NUMBER, num.length());
}

RToken RTokenizer::matchIdentifier()
{
   std::wstring::const_iterator start = pos_ ;
   eat();
   std::wstring rest = peek(tokenPatterns().REST_OF_IDENTIFIER) ;
   pos_ += rest.length() ;
   return RToken(RToken::ID,
                 start,
                 pos_,
                 start - data_.begin(),
                 pos_ - start) ;
}

RToken RTokenizer::matchQuotedIdentifier()
{
   std::wstring iden = peek(tokenPatterns().QUOTED_IDENTIFIER) ;
   if (iden.empty())
      return consumeToken(RToken::ERROR, 1);
   else
      return consumeToken(RToken::ID, iden.length());
}

RToken RTokenizer::matchComment()
{
   std::wstring comment = peek(tokenPatterns().COMMENT);
   return consumeToken(RToken::COMMENT, comment.length());
}

RToken RTokenizer::matchUserOperator()
{
   std::wstring oper = peek(tokenPatterns().USER_OPERATOR) ;
   if (oper.empty())
      return consumeToken(RToken::ERROR, 1) ;
   else
      return consumeToken(RToken::UOPER, oper.length()) ;
}

RToken RTokenizer::matchOperator()
{
   wchar_t cNext = peek(1) ;

   switch (peek())
   {
   case L'+': case L'*': case L'/':
   case L'^': case L'&': case L'|':
   case L'~': case L'$': case L':':
      // single-character operators
      return consumeToken(RToken::OPER, 1) ;
   case L'-': // also ->
      return consumeToken(RToken::OPER, cNext == L'>' ? 2 : 1) ;
   case L'>': // also >=
      return consumeToken(RToken::OPER, cNext == L'=' ? 2 : 1) ;
   case L'<': // also <- and <=
      return consumeToken(RToken::OPER, cNext == L'=' ? 2 :
                                       cNext == L'-' ? 2 :
                                       1) ;
   case L'=': // also ==
      return consumeToken(RToken::OPER, cNext == L'=' ? 2 : 1) ;
   case L'!': // also !=
      return consumeToken(RToken::OPER, cNext == L'=' ? 2 : 1) ;
   default:
      return RToken() ;
   }
}

bool RTokenizer::eol()
{
   return pos_ >= data_.end();
}

wchar_t RTokenizer::peek()
{
   return peek(0) ;
}

wchar_t RTokenizer::peek(std::size_t lookahead)
{
   if ((pos_ + lookahead) >= data_.end())
      return 0 ;
   else
      return *(pos_ + lookahead) ;
}

wchar_t RTokenizer::eat()
{
   wchar_t result = *pos_;
   pos_++ ;
   return result ;
}

std::wstring RTokenizer::peek(const boost::wregex& regex)
{
   boost::wsmatch match;
   std::wstring::const_iterator end = data_.end();
   boost::match_flag_type flg = boost::match_default | boost::match_continuous;
   if (boost::regex_search(pos_, end, match, regex, flg))
   {
      return match[0];
   }
   else
   {
      return std::wstring();
   }
}

void RTokenizer::eatUntil(const boost::wregex& regex)
{
   boost::wsmatch match;
   std::wstring::const_iterator end = data_.end();
   if (boost::regex_search(pos_, end, match, regex))
   {
      pos_ = match[0].first;
   }
   else
   {
      // eat all on failure to match
      pos_ = data_.end();
   }
}

RToken RTokenizer::consumeToken(wchar_t tokenType, std::size_t length)
{
   if (length == 0)
   {
      LOG_WARNING_MESSAGE("Can't create zero-length token");
      return RToken();
   }
   else if (pos_ + length > data_.end())
   {
      LOG_WARNING_MESSAGE("Premature EOF");
      return RToken();
   }

   std::wstring::const_iterator start = pos_ ;
   pos_ += length ;
   return RToken(tokenType,
                 start,
                 pos_,
                 start - data_.begin(),
                 length) ;
}

} // namespace r_util
} // namespace core

<|endoftext|>


<commit_before>#include <iostream>
#include "monte_carlo/util.h"
#include "linalg/util.h"
#include "linalg/ray.h"
#include "linalg/vector.h"
#include "geometry/sphere.h"

Sphere::Sphere(float radius) : radius(radius){}
bool Sphere::intersect(Ray &ray, DifferentialGeometry &diff_geom) const {
	//Compute quadratic sphere coefficients
	Vector ray_orig{ray.o};
	float a = ray.d.length_sqr();
	float b = 2 * ray.d.dot(ray_orig);
	float c = ray_orig.length_sqr() - radius * radius;
	//Solve quadratic equation for t values
	//If no solutions exist the ray doesn't intersect the sphere
	float t[2];
	if (!solve_quadratic(a, b, c, t[0], t[1])){
		return false;
	}
	//Early out, if t[0] (min) is > max or t[1] (max) is < min then both
	//our hits are outside of the region we're testing
	if (t[0] > ray.max_t || t[1] < ray.min_t){
		return false;
	}
	//Find the t value that is within the region we care about, or return if neither is
	float t_hit = t[0];
	if (t_hit < ray.min_t){
		t_hit = t[1];
		if (t_hit > ray.max_t){
			return false;
		}
	}
	ray.max_t = t_hit;
	diff_geom.point = ray(t_hit);
	//For a unit sphere the normal is the same as the point hit
	diff_geom.normal = Normal{diff_geom.point};
	diff_geom.geom_normal = diff_geom.normal;
	if (ray.d.dot(diff_geom.normal) < 0){
		diff_geom.hit_side = HITSIDE::FRONT;
	}
	else {
		diff_geom.hit_side = HITSIDE::BACK;
	}

	//Compute parameterization of surface and various derivatives for texturing
	//Sphere is parameterized by phi and theta coords
	float phi = std::atan2(diff_geom.point.x, diff_geom.point.y);
	if (phi < 0){
		phi += TAU;
	}
	float theta = std::acos(clamp(diff_geom.point.z / radius, -1.f, 1.f));
	diff_geom.u = phi / TAU;
	diff_geom.v = theta / PI;

	//Compute derivatives for point vs. parameterization, using trig shortcuts to
	//skip cos/sin calls
	float inv_z = 1 / std::sqrt(diff_geom.point.x * diff_geom.point.x
		+ diff_geom.point.y * diff_geom.point.y);
	float cos_phi = diff_geom.point.x * inv_z;
	float sin_phi = diff_geom.point.y * inv_z;
	diff_geom.dp_du = Vector{-TAU * diff_geom.point.y, TAU * diff_geom.point.x, 0};
	diff_geom.dp_dv = PI * Vector{diff_geom.point.z * cos_phi, diff_geom.point.z * sin_phi,
		-radius * std::sin(theta)};

	//Compute derivatives of normals using Weingarten eqns
	Vector ddp_duu = -TAU * TAU * Vector{diff_geom.point.x, diff_geom.point.y, 0};
	Vector ddp_duv = PI * TAU * diff_geom.point.z * Vector{-sin_phi, cos_phi, 0};
	Vector ddp_dvv = -PI * PI * Vector{diff_geom.point.x, diff_geom.point.y, diff_geom.point.z};

	float E = diff_geom.dp_du.dot(diff_geom.dp_du);
	float F = diff_geom.dp_du.dot(diff_geom.dp_dv);
	float G = diff_geom.dp_dv.dot(diff_geom.dp_dv);
	float e = diff_geom.normal.dot(ddp_duu);
	float f = diff_geom.normal.dot(ddp_duv);
	float g = diff_geom.normal.dot(ddp_dvv);
	float divisor = 1 / (E * G - F * F);
	diff_geom.dn_du = Normal{(f * F - e * G) * divisor * diff_geom.dp_du
		+ (e * F - f * E) * divisor * diff_geom.dp_dv};
	diff_geom.dn_dv = Normal{(g * F - f * G) * divisor * diff_geom.dp_du
		+ (f * F - g * E) * divisor * diff_geom.dp_dv};
	return true;
}
BBox Sphere::bound() const {
	return BBox{Point{-radius, -radius, -radius},
		Point{radius, radius, radius}};
}
void Sphere::refine(std::vector<Geometry*> &prims){
	prims.push_back(this);
}
float Sphere::surface_area() const {
	return 2 * TAU * radius;
}
Point Sphere::sample(const std::array<float, 2> &u, Normal &normal) const {
	Point p = Point{0, 0, 0} + radius * uniform_sample_sphere(u);
	normal = Normal{p.x, p.y, p.z}.normalized();
	return p;
}
Point Sphere::sample(const Point &p, const std::array<float, 2> &u, Normal &normal) const {
	//Compute coordinate system for sampling the sphere where z is the vector from the center to the point
	Vector w_z = Vector{-p}.normalized();
	Vector w_x, w_y;
	coordinate_system(w_z, w_x, w_y);
	//If we're inside the sphere we can just sample it uniformly
	if (p.distance_sqr(Point{0, 0, 0}) - radius * radius < 1e-4){
		return sample(u, normal);
	}
	//Compute angle of cone that we see of the sphere
	float cos_theta = std::sqrt(std::max(0.f, 1 - radius * radius / p.distance_sqr(Point{0, 0, 0})));
	DifferentialGeometry dg;
	Ray ray{p, uniform_sample_cone(u, cos_theta, w_x, w_y, w_z), 0.001};
	//We might not hit the sphere due to some numerical errors, so make sure it does hit
	if (!intersect(ray, dg)){
		ray.max_t = ray.d.normalized().dot(Point{0, 0, 0} - p);
	}
	Point ps = ray(ray.max_t);
	normal = Normal{ps}.normalized();
	return ps;
}
float Sphere::pdf(const Point&) const {
	return 1 / surface_area();
}
float Sphere::pdf(const Point &p, const Vector&) const {
	//If we're in the sphere the PDF is uniform
	if (p.distance_sqr(Point{0, 0, 0}) - radius * radius < 1e-4){
		return 1 / surface_area();
	}
	float cos_theta = std::sqrt(std::max(0.f, 1 - radius * radius / p.distance_sqr(Point{0, 0, 0})));
	return uniform_cone_pdf(cos_theta);
}

<commit_msg>Fix sampling for when inside sphere<commit_after>#include <iostream>
#include "monte_carlo/util.h"
#include "linalg/util.h"
#include "linalg/ray.h"
#include "linalg/vector.h"
#include "geometry/sphere.h"

Sphere::Sphere(float radius) : radius(radius){}
bool Sphere::intersect(Ray &ray, DifferentialGeometry &diff_geom) const {
	//Compute quadratic sphere coefficients
	Vector ray_orig{ray.o};
	float a = ray.d.length_sqr();
	float b = 2 * ray.d.dot(ray_orig);
	float c = ray_orig.length_sqr() - radius * radius;
	//Solve quadratic equation for t values
	//If no solutions exist the ray doesn't intersect the sphere
	float t[2];
	if (!solve_quadratic(a, b, c, t[0], t[1])){
		return false;
	}
	//Early out, if t[0] (min) is > max or t[1] (max) is < min then both
	//our hits are outside of the region we're testing
	if (t[0] > ray.max_t || t[1] < ray.min_t){
		return false;
	}
	//Find the t value that is within the region we care about, or return if neither is
	float t_hit = t[0];
	if (t_hit < ray.min_t){
		t_hit = t[1];
		if (t_hit > ray.max_t){
			return false;
		}
	}
	ray.max_t = t_hit;
	diff_geom.point = ray(t_hit);
	//For a unit sphere the normal is the same as the point hit
	diff_geom.normal = Normal{diff_geom.point};
	diff_geom.geom_normal = diff_geom.normal;
	if (ray.d.dot(diff_geom.normal) < 0){
		diff_geom.hit_side = HITSIDE::FRONT;
	}
	else {
		diff_geom.hit_side = HITSIDE::BACK;
	}

	//Compute parameterization of surface and various derivatives for texturing
	//Sphere is parameterized by phi and theta coords
	float phi = std::atan2(diff_geom.point.x, diff_geom.point.y);
	if (phi < 0){
		phi += TAU;
	}
	float theta = std::acos(clamp(diff_geom.point.z / radius, -1.f, 1.f));
	diff_geom.u = phi / TAU;
	diff_geom.v = theta / PI;

	//Compute derivatives for point vs. parameterization, using trig shortcuts to
	//skip cos/sin calls
	float inv_z = 1 / std::sqrt(diff_geom.point.x * diff_geom.point.x
		+ diff_geom.point.y * diff_geom.point.y);
	float cos_phi = diff_geom.point.x * inv_z;
	float sin_phi = diff_geom.point.y * inv_z;
	diff_geom.dp_du = Vector{-TAU * diff_geom.point.y, TAU * diff_geom.point.x, 0};
	diff_geom.dp_dv = PI * Vector{diff_geom.point.z * cos_phi, diff_geom.point.z * sin_phi,
		-radius * std::sin(theta)};

	//Compute derivatives of normals using Weingarten eqns
	Vector ddp_duu = -TAU * TAU * Vector{diff_geom.point.x, diff_geom.point.y, 0};
	Vector ddp_duv = PI * TAU * diff_geom.point.z * Vector{-sin_phi, cos_phi, 0};
	Vector ddp_dvv = -PI * PI * Vector{diff_geom.point.x, diff_geom.point.y, diff_geom.point.z};

	float E = diff_geom.dp_du.dot(diff_geom.dp_du);
	float F = diff_geom.dp_du.dot(diff_geom.dp_dv);
	float G = diff_geom.dp_dv.dot(diff_geom.dp_dv);
	float e = diff_geom.normal.dot(ddp_duu);
	float f = diff_geom.normal.dot(ddp_duv);
	float g = diff_geom.normal.dot(ddp_dvv);
	float divisor = 1 / (E * G - F * F);
	diff_geom.dn_du = Normal{(f * F - e * G) * divisor * diff_geom.dp_du
		+ (e * F - f * E) * divisor * diff_geom.dp_dv};
	diff_geom.dn_dv = Normal{(g * F - f * G) * divisor * diff_geom.dp_du
		+ (f * F - g * E) * divisor * diff_geom.dp_dv};
	return true;
}
BBox Sphere::bound() const {
	return BBox{Point{-radius, -radius, -radius},
		Point{radius, radius, radius}};
}
void Sphere::refine(std::vector<Geometry*> &prims){
	prims.push_back(this);
}
float Sphere::surface_area() const {
	return 2 * TAU * radius;
}
Point Sphere::sample(const std::array<float, 2> &u, Normal &normal) const {
	Point p = Point{0, 0, 0} + radius * uniform_sample_sphere(u);
	normal = Normal{p.x, p.y, p.z}.normalized();
	return p;
}
Point Sphere::sample(const Point &p, const std::array<float, 2> &u, Normal &normal) const {
	//Compute coordinate system for sampling the sphere where z is the vector from the center to the point
	Vector w_z = Vector{-p}.normalized();
	Vector w_x, w_y;
	coordinate_system(w_z, w_x, w_y);
	//If we're inside the sphere we can just sample it uniformly
	if (p.distance_sqr(Point{0, 0, 0}) - radius * radius < 1e-4){
		return sample(u, normal);
	}
	//Compute angle of cone that we see of the sphere
	float cos_theta = std::sqrt(std::max(0.f, 1 - radius * radius / p.distance_sqr(Point{0, 0, 0})));
	DifferentialGeometry dg;
	Ray ray{p, uniform_sample_cone(u, cos_theta, w_x, w_y, w_z), 0.001};
	//We might not hit the sphere due to some numerical errors, so make sure it does hit
	if (!intersect(ray, dg)){
		ray.max_t = ray.d.normalized().dot(Point{0, 0, 0} - p);
	}
	Point ps = ray(ray.max_t);
	normal = Normal{ps}.normalized();
	return ps;
}
float Sphere::pdf(const Point&) const {
	return 1 / surface_area();
}
float Sphere::pdf(const Point &p, const Vector &w_i) const {
	//If we're in the sphere compute the weight inside but defined over the solid angle
	if (p.distance_sqr(Point{0, 0, 0}) - radius * radius < 1e-4){
		DifferentialGeometry dg;
		Ray ray{p, w_i, 0.001};
		if (!intersect(ray, dg)){
			return 0;
		}
		//Convert PDF over area to be over solid angle
		float pdf_val = p.distance_sqr(ray(ray.max_t)) / (std::abs(dg.normal.dot(-w_i)) * surface_area());
		return std::isinf(pdf_val) ? 0 : pdf_val;
	}
	float cos_theta = std::sqrt(std::max(0.f, 1 - radius * radius / p.distance_sqr(Point{0, 0, 0})));
	return uniform_cone_pdf(cos_theta);
}

<|endoftext|>


<commit_before>#ifndef TOPAZ_GL2_API_RENDERER_HPP
#define TOPAZ_GL2_API_RENDERER_HPP

#include "gl/api/output.hpp"
#include "gl/api/resource.hpp"
#include "gl/api/component.hpp"
#include "gl/api/shader.hpp"
#include "core/containers/basic_list.hpp"
#include "core/containers/enum_field.hpp"
#include "core/vector.hpp"
#include <concepts>
#include <variant>

namespace tz::gl
{
	/**
	 * @ingroup tz_gl2_renderer
	 * Specifies options to enable extra functionality within Renderers.
	 */
	enum class RendererOption
	{
		/// - Disables depth-testing, with a small gain in performance.
		NoDepthTesting,
		/// - Enables alpha-blending. Causes pixels with alpha value <1.0 to blend with the previous colour in the framebuffer, at a small cost to performance.
		AlphaBlending,
		/// - When a compute renderer's `render()` is invoked, the thread will block until the compute-shader has finished processing.
		BlockingCompute
	};

	/**
	 * @ingroup tz_gl2_renderer
	 * Represents a collection of renderer options.
	 */
	using RendererOptions = tz::EnumField<RendererOption>;

	template<typename T>
	concept RendererInfoType = requires(T t, ResourceHandle r, IResource& resource, IOutput& output, RendererOptions options, tz::Vec4 vec4, tz::Vec3ui vec3ui)
	{
		{t.resource_count()} -> std::convertible_to<unsigned int>;
		{t.get_resource(r)} -> std::convertible_to<const IResource*>;
		{t.get_resources()} -> std::same_as<std::span<const IResource* const>>;

		{t.add_resource(resource)} -> std::same_as<ResourceHandle>;
		{t.set_output(output)} -> std::same_as<void>;
		{t.get_output()} -> std::convertible_to<const IOutput*>;

		{t.set_options(options)} -> std::same_as<void>;
		{t.get_options()} -> std::convertible_to<RendererOptions>;

		{t.set_clear_colour(vec4)} -> std::same_as<void>;
		{t.get_clear_colour()} -> std::convertible_to<tz::Vec4>;

		{t.set_compute_kernel(vec3ui)} -> std::same_as<void>;
		{t.get_compute_kernel()} -> std::convertible_to<tz::Vec3ui>;

		{t.shader()} -> ShaderInfoType;
	};

	/**
	 * Represents an edit to an existing buffer component owned by an existing renderer.
	 */
	struct RendererBufferComponentEditRequest
	{
		/// Handle corresponding to the buffer to edit.
		ResourceHandle buffer_handle;
		/// New size of the buffer, in bytes.
		std::size_t size;
	};

	/**
	 * Represents an edit to an existing image component owned by an existing renderer.
	 */
	struct RendererImageComponentEditRequest
	{
		/// Handle corresponding to the image to edit.
		ResourceHandle image_handle;
		/// New dimensions of the image, in pixels.
		tz::Vec2ui dimensions;
	};

	/**
	 * Represents an edit, setting a new value for the compute kernel for a renderer.
	 */
	struct RendererComputeEditRequest
	{
		/// New compute kernel workgroup dimensions.
		tz::Vec3ui kernel;
	};

	/**
	 * Type-safe union of @ref RendererBufferComponentEditRequest and @ref RendererImageComponentEditRequest
	 */
	using RendererComponentEditRequest = std::variant<RendererBufferComponentEditRequest, RendererImageComponentEditRequest>;

	/**
	 * @ingroup tz_gl2_renderer
	 * Represents an edit to an existing renderer.
	 */
	struct RendererEditRequest
	{
		/**
		 * List of edits to components owned by the renderer.
		 */
		std::vector<RendererComponentEditRequest> component_edits;
		std::optional<RendererComputeEditRequest> compute_edit = std::nullopt;
	};

	/**
	 * @ingroup tz_gl2_renderer
	 * Named requirement for a Renderer.
	 */
	template<typename T>
	concept RendererType = requires(T t, ResourceHandle r, std::size_t tri_count, const RendererEditRequest& edit_request)
	{
		/**
		 * Retrieves the number of resources used by the renderer.
		 * @return Number of resources of any type.
		 */
		{t.resource_count()} -> std::convertible_to<unsigned int>;
		/**
		 * Retrieve an existing renderer resource via an existing handle.
		 * @param r Handle corresponding to an existing resource. If the handle is not associated with this renderer, the behaviour is undefined.
		 * @return Pointer to the resource corresponding to the provided handle.
		 */
		{t.get_resource(r)} -> std::convertible_to<const IResource*>;
		/**
		 * Retrieve an existing renderer component via an existing handle.
		 * @param r Handle corresponding to an existing resource. If the handle is not associated with this renderer, the behaviour is undefined.
		 * @return Pointer to the component based upon the resource corresponding to the provided handle.
		 */
		{t.get_component(r)} -> std::convertible_to<const IComponent*>;
		/**
		 * Retrieve the options with which the renderer was constructed.
		 * @return Options containing additional features used by the renderer.
		 */
		{t.get_options()} -> std::convertible_to<RendererOptions>;
		/**
		 * Invoke the renderer, emitting a single draw call of a set number of triangles. The number of triangles renderered is equal to the number of triangles rendered in the previous draw-call. If this is the first draw, zero triangles are rendered.
		 */
		{t.render()} -> std::same_as<void>;
		/**
		 * Invoke the renderer, emitting a single draw call of a set number of triangles.
		 * @param tri_count Number of triangles to render.
		 */
		{t.render(tri_count)} -> std::same_as<void>;
		/**
		 * Confirm changes to a renderer.
		 *
		 * Editing renderers is expensive, so it should only be done if absolutely necessary. If you are editing renderers on a per-frame basis, consider creating multiple different renderers upfront for each hot-path and switching between them as necessary instead.
		 * @param edit_request Structure specifying which edits to make.
		 */
		{t.edit(edit_request)} -> std::same_as<void>;
	};
}

#endif // TOPAZ_GL2_API_RENDERER_HPP
<commit_msg>* Fixed missing include causing MSVC breakages<commit_after>#ifndef TOPAZ_GL2_API_RENDERER_HPP
#define TOPAZ_GL2_API_RENDERER_HPP

#include "gl/api/output.hpp"
#include "gl/api/resource.hpp"
#include "gl/api/component.hpp"
#include "gl/api/shader.hpp"
#include "core/containers/basic_list.hpp"
#include "core/containers/enum_field.hpp"
#include "core/vector.hpp"
#include <concepts>
#include <variant>
#include <optional>

namespace tz::gl
{
	/**
	 * @ingroup tz_gl2_renderer
	 * Specifies options to enable extra functionality within Renderers.
	 */
	enum class RendererOption
	{
		/// - Disables depth-testing, with a small gain in performance.
		NoDepthTesting,
		/// - Enables alpha-blending. Causes pixels with alpha value <1.0 to blend with the previous colour in the framebuffer, at a small cost to performance.
		AlphaBlending,
		/// - When a compute renderer's `render()` is invoked, the thread will block until the compute-shader has finished processing.
		BlockingCompute
	};

	/**
	 * @ingroup tz_gl2_renderer
	 * Represents a collection of renderer options.
	 */
	using RendererOptions = tz::EnumField<RendererOption>;

	template<typename T>
	concept RendererInfoType = requires(T t, ResourceHandle r, IResource& resource, IOutput& output, RendererOptions options, tz::Vec4 vec4, tz::Vec3ui vec3ui)
	{
		{t.resource_count()} -> std::convertible_to<unsigned int>;
		{t.get_resource(r)} -> std::convertible_to<const IResource*>;
		{t.get_resources()} -> std::same_as<std::span<const IResource* const>>;

		{t.add_resource(resource)} -> std::same_as<ResourceHandle>;
		{t.set_output(output)} -> std::same_as<void>;
		{t.get_output()} -> std::convertible_to<const IOutput*>;

		{t.set_options(options)} -> std::same_as<void>;
		{t.get_options()} -> std::convertible_to<RendererOptions>;

		{t.set_clear_colour(vec4)} -> std::same_as<void>;
		{t.get_clear_colour()} -> std::convertible_to<tz::Vec4>;

		{t.set_compute_kernel(vec3ui)} -> std::same_as<void>;
		{t.get_compute_kernel()} -> std::convertible_to<tz::Vec3ui>;

		{t.shader()} -> ShaderInfoType;
	};

	/**
	 * Represents an edit to an existing buffer component owned by an existing renderer.
	 */
	struct RendererBufferComponentEditRequest
	{
		/// Handle corresponding to the buffer to edit.
		ResourceHandle buffer_handle;
		/// New size of the buffer, in bytes.
		std::size_t size;
	};

	/**
	 * Represents an edit to an existing image component owned by an existing renderer.
	 */
	struct RendererImageComponentEditRequest
	{
		/// Handle corresponding to the image to edit.
		ResourceHandle image_handle;
		/// New dimensions of the image, in pixels.
		tz::Vec2ui dimensions;
	};

	/**
	 * Represents an edit, setting a new value for the compute kernel for a renderer.
	 */
	struct RendererComputeEditRequest
	{
		/// New compute kernel workgroup dimensions.
		tz::Vec3ui kernel;
	};

	/**
	 * Type-safe union of @ref RendererBufferComponentEditRequest and @ref RendererImageComponentEditRequest
	 */
	using RendererComponentEditRequest = std::variant<RendererBufferComponentEditRequest, RendererImageComponentEditRequest>;

	/**
	 * @ingroup tz_gl2_renderer
	 * Represents an edit to an existing renderer.
	 */
	struct RendererEditRequest
	{
		/**
		 * List of edits to components owned by the renderer.
		 */
		std::vector<RendererComponentEditRequest> component_edits;
		std::optional<RendererComputeEditRequest> compute_edit = std::nullopt;
	};

	/**
	 * @ingroup tz_gl2_renderer
	 * Named requirement for a Renderer.
	 */
	template<typename T>
	concept RendererType = requires(T t, ResourceHandle r, std::size_t tri_count, const RendererEditRequest& edit_request)
	{
		/**
		 * Retrieves the number of resources used by the renderer.
		 * @return Number of resources of any type.
		 */
		{t.resource_count()} -> std::convertible_to<unsigned int>;
		/**
		 * Retrieve an existing renderer resource via an existing handle.
		 * @param r Handle corresponding to an existing resource. If the handle is not associated with this renderer, the behaviour is undefined.
		 * @return Pointer to the resource corresponding to the provided handle.
		 */
		{t.get_resource(r)} -> std::convertible_to<const IResource*>;
		/**
		 * Retrieve an existing renderer component via an existing handle.
		 * @param r Handle corresponding to an existing resource. If the handle is not associated with this renderer, the behaviour is undefined.
		 * @return Pointer to the component based upon the resource corresponding to the provided handle.
		 */
		{t.get_component(r)} -> std::convertible_to<const IComponent*>;
		/**
		 * Retrieve the options with which the renderer was constructed.
		 * @return Options containing additional features used by the renderer.
		 */
		{t.get_options()} -> std::convertible_to<RendererOptions>;
		/**
		 * Invoke the renderer, emitting a single draw call of a set number of triangles. The number of triangles renderered is equal to the number of triangles rendered in the previous draw-call. If this is the first draw, zero triangles are rendered.
		 */
		{t.render()} -> std::same_as<void>;
		/**
		 * Invoke the renderer, emitting a single draw call of a set number of triangles.
		 * @param tri_count Number of triangles to render.
		 */
		{t.render(tri_count)} -> std::same_as<void>;
		/**
		 * Confirm changes to a renderer.
		 *
		 * Editing renderers is expensive, so it should only be done if absolutely necessary. If you are editing renderers on a per-frame basis, consider creating multiple different renderers upfront for each hot-path and switching between them as necessary instead.
		 * @param edit_request Structure specifying which edits to make.
		 */
		{t.edit(edit_request)} -> std::same_as<void>;
	};
}

#endif // TOPAZ_GL2_API_RENDERER_HPP
<|endoftext|>


<commit_before>// RUN: %check_clang_tidy %s bugprone-infinite-loop %t -- -- -fexceptions

void simple_infinite_loop1() {
  int i = 0;
  int j = 0;
  while (i < 10) {
    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
    j++;
  }

  do {
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
    j++;
  } while (i < 10);

  for (i = 0; i < 10; ++j) {
    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
  }
}

void simple_infinite_loop2() {
  int i = 0;
  int j = 0;
  int Limit = 10;
  while (i < Limit) {
    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
    j++;
  }

  do {
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
    j++;
  } while (i < Limit);

  for (i = 0; i < Limit; ++j) {
    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
  }
}

void simple_not_infinite1() {
  int i = 0;
  int Limit = 100;
  while (i < Limit) {
    // Not an error since 'Limit' is updated.
    Limit--;
  }
  do {
    Limit--;
  } while (i < Limit);

  for (i = 0; i < Limit; Limit--) {
  }
}

void simple_not_infinite2() {
  for (int i = 10; i-- > 0;) {
    // Not an error, since loop variable is modified in its condition part.
  }
}

int unknown_function();

void function_call() {
  int i = 0;
  while (i < unknown_function()) {
    // Not an error, since the function may return different values.
  }

  do {
    // Not an error, since the function may return different values.
  } while (i < unknown_function());

  for (i = 0; i < unknown_function();) {
    // Not an error, since the function may return different values.
  }
}

void escape_before1() {
  int i = 0;
  int Limit = 100;
  int *p = &i;
  while (i < Limit) {
    // Not an error, since *p is alias of i.
    (*p)++;
  }

  do {
    (*p)++;
  } while (i < Limit);

  for (i = 0; i < Limit; ++(*p)) {
  }
}

void escape_before2() {
  int i = 0;
  int Limit = 100;
  int &ii = i;
  while (i < Limit) {
    // Not an error, since ii is alias of i.
    ii++;
  }

  do {
    ii++;
  } while (i < Limit);

  for (i = 0; i < Limit; ++ii) {
  }
}

void escape_inside1() {
  int i = 0;
  int Limit = 100;
  int *p = &i;
  while (i < Limit) {
    // Not an error, since *p is alias of i.
    int *p = &i;
    (*p)++;
  }

  do {
    int *p = &i;
    (*p)++;
  } while (i < Limit);
}

void escape_inside2() {
  int i = 0;
  int Limit = 100;
  while (i < Limit) {
    // Not an error, since ii is alias of i.
    int &ii = i;
    ii++;
  }

  do {
    int &ii = i;
    ii++;
  } while (i < Limit);
}

void escape_after1() {
  int i = 0;
  int j = 0;
  int Limit = 10;

  while (i < Limit) {
    // False negative, but difficult to detect without CFG-based analysis
  }
  int *p = &i;
}

void escape_after2() {
  int i = 0;
  int j = 0;
  int Limit = 10;

  while (i < Limit) {
    // False negative, but difficult to detect without CFG-based analysis
  }
  int &ii = i;
}
-

int glob;

void global1(int &x) {
  int i = 0, Limit = 100;
  while (x < Limit) {
    // Not an error since 'x' can be an alias of 'glob'.
    glob++;
  }
}

void global2() {
  int i = 0, Limit = 100;
  while (glob < Limit) {
    // Since 'glob' is declared out of the function we do not warn.
    i++;
  }
}

struct X {
  int m;

  void change_m();

  void member_expr1(int i) {
    while (i < m) {
      // False negative: No warning, since skipping the case where a struct or
      // class can be found in its condition.
      ;
    }
  }

  void member_expr2(int i) {
    while (i < m) {
      --m;
    }
  }

  void member_expr3(int i) {
    while (i < m) {
      change_m();
    }
  }
};

void array_index() {
  int i = 0;
  int v[10];
  while (i < 10) {
    v[i++] = 0;
  }

  i = 0;
  do {
    v[i++] = 0;
  } while (i < 9);

  for (i = 0; i < 10;) {
    v[i++] = 0;
  }

  for (i = 0; i < 10; v[i++] = 0) {
  }
}

void no_loop_variable() {
  while (0)
    ;
}

void volatile_in_condition() {
  volatile int cond = 0;
  while (!cond) {
  }
}

namespace std {
template<typename T> class atomic {
  T val;
public:
  atomic(T v): val(v) {};
  operator T() { return val; };
};
}

void atomic_in_condition() {
  std::atomic<int> cond = 0;
  while (!cond) {
  }
}

void loop_exit1() {
  int i = 0;
  while (i) {
    if (unknown_function())
      break;
  }
}

void loop_exit2() {
  int i = 0;
  while (i) {
    if (unknown_function())
      return;
  }
}

void loop_exit3() {
  int i = 0;
  while (i) {
    if (unknown_function())
      goto end;
  }
 end:
  ;
}

void loop_exit4() {
  int i = 0;
  while (i) {
    if (unknown_function())
      throw 1;
  }
}

[[noreturn]] void exit(int);

void loop_exit5() {
  int i = 0;
  while (i) {
    if (unknown_function())
      exit(1);
  }
}

void loop_exit_in_lambda() {
  int i = 0;
  while (i) {
    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
    auto l = []() { return 0; };
  }
}

void lambda_capture() {
  int i = 0;
  int Limit = 100;
  int *p = &i;
  while (i < Limit) {
    // Not an error, since i is captured by reference in a lambda.
    auto l = [&i]() { ++i; };
  }

  do {
    int *p = &i;
    (*p)++;
  } while (i < Limit);
}
<commit_msg>[clang-tidy] Fix typo in r373428<commit_after>// RUN: %check_clang_tidy %s bugprone-infinite-loop %t -- -- -fexceptions

void simple_infinite_loop1() {
  int i = 0;
  int j = 0;
  while (i < 10) {
    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
    j++;
  }

  do {
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
    j++;
  } while (i < 10);

  for (i = 0; i < 10; ++j) {
    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
  }
}

void simple_infinite_loop2() {
  int i = 0;
  int j = 0;
  int Limit = 10;
  while (i < Limit) {
    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
    j++;
  }

  do {
  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
    j++;
  } while (i < Limit);

  for (i = 0; i < Limit; ++j) {
    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i, Limit) are updated in the loop body [bugprone-infinite-loop]
  }
}

void simple_not_infinite1() {
  int i = 0;
  int Limit = 100;
  while (i < Limit) {
    // Not an error since 'Limit' is updated.
    Limit--;
  }
  do {
    Limit--;
  } while (i < Limit);

  for (i = 0; i < Limit; Limit--) {
  }
}

void simple_not_infinite2() {
  for (int i = 10; i-- > 0;) {
    // Not an error, since loop variable is modified in its condition part.
  }
}

int unknown_function();

void function_call() {
  int i = 0;
  while (i < unknown_function()) {
    // Not an error, since the function may return different values.
  }

  do {
    // Not an error, since the function may return different values.
  } while (i < unknown_function());

  for (i = 0; i < unknown_function();) {
    // Not an error, since the function may return different values.
  }
}

void escape_before1() {
  int i = 0;
  int Limit = 100;
  int *p = &i;
  while (i < Limit) {
    // Not an error, since *p is alias of i.
    (*p)++;
  }

  do {
    (*p)++;
  } while (i < Limit);

  for (i = 0; i < Limit; ++(*p)) {
  }
}

void escape_before2() {
  int i = 0;
  int Limit = 100;
  int &ii = i;
  while (i < Limit) {
    // Not an error, since ii is alias of i.
    ii++;
  }

  do {
    ii++;
  } while (i < Limit);

  for (i = 0; i < Limit; ++ii) {
  }
}

void escape_inside1() {
  int i = 0;
  int Limit = 100;
  int *p = &i;
  while (i < Limit) {
    // Not an error, since *p is alias of i.
    int *p = &i;
    (*p)++;
  }

  do {
    int *p = &i;
    (*p)++;
  } while (i < Limit);
}

void escape_inside2() {
  int i = 0;
  int Limit = 100;
  while (i < Limit) {
    // Not an error, since ii is alias of i.
    int &ii = i;
    ii++;
  }

  do {
    int &ii = i;
    ii++;
  } while (i < Limit);
}

void escape_after1() {
  int i = 0;
  int j = 0;
  int Limit = 10;

  while (i < Limit) {
    // False negative, but difficult to detect without CFG-based analysis
  }
  int *p = &i;
}

void escape_after2() {
  int i = 0;
  int j = 0;
  int Limit = 10;

  while (i < Limit) {
    // False negative, but difficult to detect without CFG-based analysis
  }
  int &ii = i;
}

int glob;

void global1(int &x) {
  int i = 0, Limit = 100;
  while (x < Limit) {
    // Not an error since 'x' can be an alias of 'glob'.
    glob++;
  }
}

void global2() {
  int i = 0, Limit = 100;
  while (glob < Limit) {
    // Since 'glob' is declared out of the function we do not warn.
    i++;
  }
}

struct X {
  int m;

  void change_m();

  void member_expr1(int i) {
    while (i < m) {
      // False negative: No warning, since skipping the case where a struct or
      // class can be found in its condition.
      ;
    }
  }

  void member_expr2(int i) {
    while (i < m) {
      --m;
    }
  }

  void member_expr3(int i) {
    while (i < m) {
      change_m();
    }
  }
};

void array_index() {
  int i = 0;
  int v[10];
  while (i < 10) {
    v[i++] = 0;
  }

  i = 0;
  do {
    v[i++] = 0;
  } while (i < 9);

  for (i = 0; i < 10;) {
    v[i++] = 0;
  }

  for (i = 0; i < 10; v[i++] = 0) {
  }
}

void no_loop_variable() {
  while (0)
    ;
}

void volatile_in_condition() {
  volatile int cond = 0;
  while (!cond) {
  }
}

namespace std {
template<typename T> class atomic {
  T val;
public:
  atomic(T v): val(v) {};
  operator T() { return val; };
};
}

void atomic_in_condition() {
  std::atomic<int> cond = 0;
  while (!cond) {
  }
}

void loop_exit1() {
  int i = 0;
  while (i) {
    if (unknown_function())
      break;
  }
}

void loop_exit2() {
  int i = 0;
  while (i) {
    if (unknown_function())
      return;
  }
}

void loop_exit3() {
  int i = 0;
  while (i) {
    if (unknown_function())
      goto end;
  }
 end:
  ;
}

void loop_exit4() {
  int i = 0;
  while (i) {
    if (unknown_function())
      throw 1;
  }
}

[[noreturn]] void exit(int);

void loop_exit5() {
  int i = 0;
  while (i) {
    if (unknown_function())
      exit(1);
  }
}

void loop_exit_in_lambda() {
  int i = 0;
  while (i) {
    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop]
    auto l = []() { return 0; };
  }
}

void lambda_capture() {
  int i = 0;
  int Limit = 100;
  int *p = &i;
  while (i < Limit) {
    // Not an error, since i is captured by reference in a lambda.
    auto l = [&i]() { ++i; };
  }

  do {
    int *p = &i;
    (*p)++;
  } while (i < Limit);
}
<|endoftext|>


<commit_before>/*
 * Author: Jon Trulson <jtrulson@ics.com>
 * Copyright (c) 2014 Intel Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <unistd.h>
#include <iostream>
#include <string>

#include "grovemd.h"

using namespace upm;
using namespace std;

GroveMD::GroveMD(int bus, uint8_t address)
{
  m_addr = address;

  // setup our i2c link
  if ( !(m_i2c = mraa_i2c_init(bus)) )
    {
      cerr << __FUNCTION__ << ": mraa_i2c_init() failed" << endl;
      return;
    }

  // this board *requires* 100Khz i2c bus only
  mraa_result_t rv;
  //if ( (rv = mraa_i2c_frequency(m_i2c, MRAA_I2C_STD)) != MRAA_SUCCESS )
    //{
      //cerr << "GroveMD: Could not set i2c frequency (MRAA_I2C_STD). " << endl;
      //mraa_result_print(rv);
      //return;
    //}

  if (mraa_i2c_address(m_i2c, m_addr))
    {
      cerr << "GroveMD: Could not initialize i2c bus. " << endl;
      return;
    }
}

GroveMD::~GroveMD()
{
  setMotorSpeeds(0, 0);
  mraa_i2c_stop(m_i2c);
}

bool GroveMD::writePacket(REG_T reg, uint8_t data1, uint8_t data2)
{
  uint8_t buf[3];

  buf[0] = reg;
  buf[1] = data1;
  buf[2] = data2;

  mraa_result_t rv;
  if ( (rv = mraa_i2c_address(m_i2c, m_addr)) != MRAA_SUCCESS )
    {
      cerr << __FUNCTION__ << ": mraa_i2c_address() failed. " << endl;
      mraa_result_print(rv);
      return false;
    }

  // This sleep appears to be required.  Without it, writes randomly
  // fail (no ACK received).  This happens most often on the SET_SPEED
  // packet.  I am guessing that there is a timing problem and/or bug
  // in the motor driver's firmware.

  usleep(100);

  if ( (rv = mraa_i2c_write(m_i2c, buf, 3)) != MRAA_SUCCESS )
    {
      cerr << __FUNCTION__ << ": mraa_i2c_write() failed:" << endl;
      mraa_result_print(rv);
      return false;
    }

  return true;
}

bool GroveMD::setMotorSpeeds(uint8_t speedA, uint8_t speedB)
{
  return writePacket(SET_SPEED, speedA, speedB);
}

bool GroveMD::setPWMFrequencyPrescale(uint8_t freq)
{
  return writePacket(SET_PWM_FREQ, freq, GROVEMD_NOOP);
}

bool GroveMD::setMotorDirections(DC_DIRECTION_T dirA, DC_DIRECTION_T dirB)
{
  uint8_t dir = ((dirB & 0x03) << 2) | (dirA & 0x03);
  return writePacket(SET_DIRECTION, dir, GROVEMD_NOOP);
}

bool GroveMD::enableStepper(STEP_DIRECTION_T dir, uint8_t speed)
{
  return writePacket(STEPPER_ENABLE, dir, speed);
}

bool GroveMD::disableStepper()
{
  return writePacket(STEPPER_DISABLE, GROVEMD_NOOP, GROVEMD_NOOP);
}

bool GroveMD::setStepperSteps(uint8_t steps)
{
  if (steps == 0)
    {
      // invalid
      cerr << __FUNCTION__ << ": invalid number of steps.  "
           << "Valid values are between 1 and 255." << endl;
      return false;
    }

  return writePacket(STEPPER_NUM_STEPS, steps, GROVEMD_NOOP);
}

<commit_msg>grovemd: uncommented mraa_i2c_frequency() call since driver only works at 100kHz<commit_after>/*
 * Author: Jon Trulson <jtrulson@ics.com>
 * Copyright (c) 2014 Intel Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <unistd.h>
#include <iostream>
#include <string>

#include "grovemd.h"

using namespace upm;
using namespace std;

GroveMD::GroveMD(int bus, uint8_t address)
{
  m_addr = address;

  // setup our i2c link
  if ( !(m_i2c = mraa_i2c_init(bus)) )
    {
      cerr << __FUNCTION__ << ": mraa_i2c_init() failed" << endl;
      return;
    }

  // this board *requires* 100Khz i2c bus only
  mraa_result_t rv;
  if ( (rv = mraa_i2c_frequency(m_i2c, MRAA_I2C_STD)) != MRAA_SUCCESS )
    {
      cerr << "GroveMD: Could not set i2c frequency (MRAA_I2C_STD). " << endl;
      mraa_result_print(rv);
      return;
    }

  if (mraa_i2c_address(m_i2c, m_addr))
    {
      cerr << "GroveMD: Could not initialize i2c bus. " << endl;
      return;
    }
}

GroveMD::~GroveMD()
{
  setMotorSpeeds(0, 0);
  mraa_i2c_stop(m_i2c);
}

bool GroveMD::writePacket(REG_T reg, uint8_t data1, uint8_t data2)
{
  uint8_t buf[3];

  buf[0] = reg;
  buf[1] = data1;
  buf[2] = data2;

  mraa_result_t rv;
  if ( (rv = mraa_i2c_address(m_i2c, m_addr)) != MRAA_SUCCESS )
    {
      cerr << __FUNCTION__ << ": mraa_i2c_address() failed. " << endl;
      mraa_result_print(rv);
      return false;
    }

  // This sleep appears to be required.  Without it, writes randomly
  // fail (no ACK received).  This happens most often on the SET_SPEED
  // packet.  I am guessing that there is a timing problem and/or bug
  // in the motor driver's firmware.

  usleep(100);

  if ( (rv = mraa_i2c_write(m_i2c, buf, 3)) != MRAA_SUCCESS )
    {
      cerr << __FUNCTION__ << ": mraa_i2c_write() failed:" << endl;
      mraa_result_print(rv);
      return false;
    }

  return true;
}

bool GroveMD::setMotorSpeeds(uint8_t speedA, uint8_t speedB)
{
  return writePacket(SET_SPEED, speedA, speedB);
}

bool GroveMD::setPWMFrequencyPrescale(uint8_t freq)
{
  return writePacket(SET_PWM_FREQ, freq, GROVEMD_NOOP);
}

bool GroveMD::setMotorDirections(DC_DIRECTION_T dirA, DC_DIRECTION_T dirB)
{
  uint8_t dir = ((dirB & 0x03) << 2) | (dirA & 0x03);
  return writePacket(SET_DIRECTION, dir, GROVEMD_NOOP);
}

bool GroveMD::enableStepper(STEP_DIRECTION_T dir, uint8_t speed)
{
  return writePacket(STEPPER_ENABLE, dir, speed);
}

bool GroveMD::disableStepper()
{
  return writePacket(STEPPER_DISABLE, GROVEMD_NOOP, GROVEMD_NOOP);
}

bool GroveMD::setStepperSteps(uint8_t steps)
{
  if (steps == 0)
    {
      // invalid
      cerr << __FUNCTION__ << ": invalid number of steps.  "
           << "Valid values are between 1 and 255." << endl;
      return false;
    }

  return writePacket(STEPPER_NUM_STEPS, steps, GROVEMD_NOOP);
}

<|endoftext|>