<commit_before>#include <sys/errno.h>
#include <sys/uio.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>

#include <common/buffer.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

#include <io/io_system.h>

#define	IO_READ_BUFFER_SIZE	65536

IOSystem::Handle::Handle(int fd, Channel *owner)
: log_("/io/system/handle"),
  fd_(fd),
  owner_(owner),
  close_callback_(NULL),
  close_action_(NULL),
  read_amount_(0),
  read_buffer_(),
  read_callback_(NULL),
  read_action_(NULL),
  write_buffer_(),
  write_callback_(NULL),
  write_action_(NULL)
{ }

IOSystem::Handle::~Handle()
{
	ASSERT(fd_ == -1);

	ASSERT(close_action_ == NULL);
	ASSERT(close_callback_ == NULL);

	ASSERT(read_action_ == NULL);
	ASSERT(read_callback_ == NULL);

	ASSERT(write_action_ == NULL);
	ASSERT(write_callback_ == NULL);
}

void
IOSystem::Handle::close_callback(void)
{
	close_action_->cancel();
	close_action_ = NULL;

	ASSERT(fd_ != -1);
	int rv = ::close(fd_);
	if (rv == -1) {
		switch (errno) {
		case EAGAIN:
			close_action_ = close_schedule();
			break;
		default:
			close_callback_->event(Event(Event::Error, errno));
			Action *a = EventSystem::instance()->schedule(close_callback_);
			close_action_ = a;
			close_callback_ = NULL;
			break;
		}
		return;
	}
	fd_ = -1;
	close_callback_->event(Event(Event::Done, 0));
	Action *a = EventSystem::instance()->schedule(close_callback_);
	close_action_ = a;
	close_callback_ = NULL;
}

void
IOSystem::Handle::close_cancel(void)
{
	ASSERT(close_action_ != NULL);
	close_action_->cancel();
	close_action_ = NULL;

	if (close_callback_ != NULL) {
		delete close_callback_;
		close_callback_ = NULL;
	}
}

Action *
IOSystem::Handle::close_schedule(void)
{
	ASSERT(close_action_ == NULL);
	Callback *cb = callback(this, &IOSystem::Handle::close_callback);
	Action *a = EventSystem::instance()->schedule(cb);
	return (a);
}

void
IOSystem::Handle::read_callback(Event e)
{
	read_action_->cancel();
	read_action_ = NULL;

	switch (e.type_) {
	case Event::EOS:
	case Event::Done:
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}

	size_t rlen;

	if (read_amount_ == 0)
		rlen = IO_READ_BUFFER_SIZE;
	else {
		rlen = read_amount_ - read_buffer_.length();
		ASSERT(rlen != 0);
		if (rlen > IO_READ_BUFFER_SIZE)
			rlen = IO_READ_BUFFER_SIZE;
	}

	uint8_t data[IO_READ_BUFFER_SIZE];
	ssize_t len = ::read(fd_, data, sizeof data);
	if (len == -1) {
		switch (errno) {
		case EAGAIN:
			read_action_ = read_schedule();
			break;
		default:
			read_callback_->event(Event(Event::Error, errno, read_buffer_));
			Action *a = EventSystem::instance()->schedule(read_callback_);
			read_action_ = a;
			read_callback_ = NULL;
			read_buffer_.clear();
			read_amount_ = 0;
			break;
		}
		return;
	}

	/*
	 * XXX
	 * If we get an EOS from EventPoll, should we just terminate after that
	 * one read?  How can we tell how much data is still available to be
	 * read?  Will we get it all in one read?  Eventually, one would expect
	 * to get a read with a length of 0, or an error, but will kevent even
	 * continue to fire off read events?
	 */
	if (len == 0) {
		read_callback_->event(Event(Event::EOS, 0, read_buffer_));
		Action *a = EventSystem::instance()->schedule(read_callback_);
		read_action_ = a;
		read_callback_ = NULL;
		read_buffer_.clear();
		read_amount_ = 0;
		return;
	}

	read_buffer_.append(data, len);
	read_action_ = read_schedule();
}

void
IOSystem::Handle::read_cancel(void)
{
	ASSERT(read_action_ != NULL);
	read_action_->cancel();
	read_action_ = NULL;

	if (read_callback_ != NULL) {
		delete read_callback_;
		read_callback_ = NULL;
	}
}

Action *
IOSystem::Handle::read_schedule(void)
{
	ASSERT(read_action_ == NULL);

	if (!read_buffer_.empty() && read_buffer_.length() >= read_amount_) {
		if (read_amount_ == 0)
			read_amount_ = read_buffer_.length();
		read_callback_->event(Event(Event::Done, 0, Buffer(read_buffer_, read_amount_)));
		Action *a = EventSystem::instance()->schedule(read_callback_);
		read_callback_ = NULL;
		read_buffer_.skip(read_amount_);
		read_amount_ = 0;
		return (a);
	}

	EventCallback *cb = callback(this, &IOSystem::Handle::read_callback);
	Action *a = EventSystem::instance()->poll(EventPoll::Readable, fd_, cb);
	return (a);
}

void
IOSystem::Handle::write_callback(Event e)
{
	write_action_->cancel();
	write_action_ = NULL;

	switch (e.type_) {
	case Event::EOS:
	case Event::Done:
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}

	/* XXX This doesn't handle UDP nicely.  Right?  */
	struct iovec iov[IOV_MAX];
	size_t iovcnt = write_buffer_.fill_iovec(iov, IOV_MAX);

	ssize_t len = ::writev(fd_, iov, iovcnt);
	if (len == -1) {
		switch (errno) {
		case EAGAIN:
			write_action_ = write_schedule();
			break;
		default:
			write_callback_->event(Event(Event::Error, errno));
			Action *a = EventSystem::instance()->schedule(write_callback_);
			write_action_ = a;
			write_callback_ = NULL;
			break;
		}
		return;
	}

	write_buffer_.skip(len);

	if (write_buffer_.empty()) {
		write_callback_->event(Event(Event::Done, 0));
		Action *a = EventSystem::instance()->schedule(write_callback_);
		write_action_ = a;
		write_callback_ = NULL;
		return;
	}
	write_action_ = write_schedule();
}

void
IOSystem::Handle::write_cancel(void)
{
	ASSERT(write_action_ != NULL);
	write_action_->cancel();
	write_action_ = NULL;

	if (write_callback_ != NULL) {
		delete write_callback_;
		write_callback_ = NULL;
	}
}

Action *
IOSystem::Handle::write_schedule(void)
{
	ASSERT(write_action_ == NULL);
	EventCallback *cb = callback(this, &IOSystem::Handle::write_callback);
	Action *a = EventSystem::instance()->poll(EventPoll::Writable, fd_, cb);
	return (a);
}

IOSystem::IOSystem(void)
: log_("/io/system"),
  handle_map_()
{ }

IOSystem::~IOSystem()
{
	ASSERT(handle_map_.empty());
}

void
IOSystem::attach(int fd, Channel *owner)
{
	ASSERT(handle_map_.find(handle_key_t(fd, owner)) == handle_map_.end());
	handle_map_[handle_key_t(fd, owner)] = new IOSystem::Handle(fd, owner);
}

void
IOSystem::detach(int fd, Channel *owner)
{
	handle_map_t::iterator it;
	IOSystem::Handle *h;

	it = handle_map_.find(handle_key_t(fd, owner));
	ASSERT(it != handle_map_.end());

	h = it->second;
	ASSERT(h != NULL);
	ASSERT(h->owner_ == owner);

	handle_map_.erase(it);
	delete h;
}

Action *
IOSystem::close(int fd, Channel *owner, EventCallback *cb)
{
	IOSystem::Handle *h;

	h = handle_map_[handle_key_t(fd, owner)];
	ASSERT(h != NULL);

	ASSERT(h->close_callback_ == NULL);
	ASSERT(h->close_action_ == NULL);

	ASSERT(h->read_callback_ == NULL);
	ASSERT(h->read_action_ == NULL);

	ASSERT(h->write_callback_ == NULL);
	ASSERT(h->write_action_ == NULL);

	ASSERT(h->fd_ != -1);

	h->close_callback_ = cb;
	h->close_action_ = h->close_schedule();
	return (cancellation(h, &IOSystem::Handle::close_cancel));
}

Action *
IOSystem::read(int fd, Channel *owner, size_t amount, EventCallback *cb)
{
	IOSystem::Handle *h;

	h = handle_map_[handle_key_t(fd, owner)];
	ASSERT(h != NULL);

	ASSERT(h->read_callback_ == NULL);
	ASSERT(h->read_action_ == NULL);

	h->read_amount_ = amount;
	h->read_callback_ = cb;
	h->read_action_ = h->read_schedule();
	return (cancellation(h, &IOSystem::Handle::read_cancel));
}

Action *
IOSystem::write(int fd, Channel *owner, Buffer *buffer, EventCallback *cb)
{
	IOSystem::Handle *h;

	h = handle_map_[handle_key_t(fd, owner)];
	ASSERT(h != NULL);

	ASSERT(h->write_callback_ == NULL);
	ASSERT(h->write_action_ == NULL);
	ASSERT(h->write_buffer_.empty());

	h->write_buffer_.append(buffer);
	buffer->clear();

	h->write_callback_ = cb;
	h->write_action_ = h->write_schedule();
	return (cancellation(h, &IOSystem::Handle::write_cancel));
}
<commit_msg>Blow up nicely if the Buffer * passed to write() is empty, instead of blowing up in Buffer::skip() later on.<commit_after>#include <sys/errno.h>
#include <sys/uio.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>

#include <common/buffer.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

#include <io/io_system.h>

#define	IO_READ_BUFFER_SIZE	65536

IOSystem::Handle::Handle(int fd, Channel *owner)
: log_("/io/system/handle"),
  fd_(fd),
  owner_(owner),
  close_callback_(NULL),
  close_action_(NULL),
  read_amount_(0),
  read_buffer_(),
  read_callback_(NULL),
  read_action_(NULL),
  write_buffer_(),
  write_callback_(NULL),
  write_action_(NULL)
{ }

IOSystem::Handle::~Handle()
{
	ASSERT(fd_ == -1);

	ASSERT(close_action_ == NULL);
	ASSERT(close_callback_ == NULL);

	ASSERT(read_action_ == NULL);
	ASSERT(read_callback_ == NULL);

	ASSERT(write_action_ == NULL);
	ASSERT(write_callback_ == NULL);
}

void
IOSystem::Handle::close_callback(void)
{
	close_action_->cancel();
	close_action_ = NULL;

	ASSERT(fd_ != -1);
	int rv = ::close(fd_);
	if (rv == -1) {
		switch (errno) {
		case EAGAIN:
			close_action_ = close_schedule();
			break;
		default:
			close_callback_->event(Event(Event::Error, errno));
			Action *a = EventSystem::instance()->schedule(close_callback_);
			close_action_ = a;
			close_callback_ = NULL;
			break;
		}
		return;
	}
	fd_ = -1;
	close_callback_->event(Event(Event::Done, 0));
	Action *a = EventSystem::instance()->schedule(close_callback_);
	close_action_ = a;
	close_callback_ = NULL;
}

void
IOSystem::Handle::close_cancel(void)
{
	ASSERT(close_action_ != NULL);
	close_action_->cancel();
	close_action_ = NULL;

	if (close_callback_ != NULL) {
		delete close_callback_;
		close_callback_ = NULL;
	}
}

Action *
IOSystem::Handle::close_schedule(void)
{
	ASSERT(close_action_ == NULL);
	Callback *cb = callback(this, &IOSystem::Handle::close_callback);
	Action *a = EventSystem::instance()->schedule(cb);
	return (a);
}

void
IOSystem::Handle::read_callback(Event e)
{
	read_action_->cancel();
	read_action_ = NULL;

	switch (e.type_) {
	case Event::EOS:
	case Event::Done:
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}

	size_t rlen;

	if (read_amount_ == 0)
		rlen = IO_READ_BUFFER_SIZE;
	else {
		rlen = read_amount_ - read_buffer_.length();
		ASSERT(rlen != 0);
		if (rlen > IO_READ_BUFFER_SIZE)
			rlen = IO_READ_BUFFER_SIZE;
	}

	uint8_t data[IO_READ_BUFFER_SIZE];
	ssize_t len = ::read(fd_, data, sizeof data);
	if (len == -1) {
		switch (errno) {
		case EAGAIN:
			read_action_ = read_schedule();
			break;
		default:
			read_callback_->event(Event(Event::Error, errno, read_buffer_));
			Action *a = EventSystem::instance()->schedule(read_callback_);
			read_action_ = a;
			read_callback_ = NULL;
			read_buffer_.clear();
			read_amount_ = 0;
			break;
		}
		return;
	}

	/*
	 * XXX
	 * If we get an EOS from EventPoll, should we just terminate after that
	 * one read?  How can we tell how much data is still available to be
	 * read?  Will we get it all in one read?  Eventually, one would expect
	 * to get a read with a length of 0, or an error, but will kevent even
	 * continue to fire off read events?
	 */
	if (len == 0) {
		read_callback_->event(Event(Event::EOS, 0, read_buffer_));
		Action *a = EventSystem::instance()->schedule(read_callback_);
		read_action_ = a;
		read_callback_ = NULL;
		read_buffer_.clear();
		read_amount_ = 0;
		return;
	}

	read_buffer_.append(data, len);
	read_action_ = read_schedule();
}

void
IOSystem::Handle::read_cancel(void)
{
	ASSERT(read_action_ != NULL);
	read_action_->cancel();
	read_action_ = NULL;

	if (read_callback_ != NULL) {
		delete read_callback_;
		read_callback_ = NULL;
	}
}

Action *
IOSystem::Handle::read_schedule(void)
{
	ASSERT(read_action_ == NULL);

	if (!read_buffer_.empty() && read_buffer_.length() >= read_amount_) {
		if (read_amount_ == 0)
			read_amount_ = read_buffer_.length();
		read_callback_->event(Event(Event::Done, 0, Buffer(read_buffer_, read_amount_)));
		Action *a = EventSystem::instance()->schedule(read_callback_);
		read_callback_ = NULL;
		read_buffer_.skip(read_amount_);
		read_amount_ = 0;
		return (a);
	}

	EventCallback *cb = callback(this, &IOSystem::Handle::read_callback);
	Action *a = EventSystem::instance()->poll(EventPoll::Readable, fd_, cb);
	return (a);
}

void
IOSystem::Handle::write_callback(Event e)
{
	write_action_->cancel();
	write_action_ = NULL;

	switch (e.type_) {
	case Event::EOS:
	case Event::Done:
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}

	/* XXX This doesn't handle UDP nicely.  Right?  */
	struct iovec iov[IOV_MAX];
	size_t iovcnt = write_buffer_.fill_iovec(iov, IOV_MAX);

	ssize_t len = ::writev(fd_, iov, iovcnt);
	if (len == -1) {
		switch (errno) {
		case EAGAIN:
			write_action_ = write_schedule();
			break;
		default:
			write_callback_->event(Event(Event::Error, errno));
			Action *a = EventSystem::instance()->schedule(write_callback_);
			write_action_ = a;
			write_callback_ = NULL;
			break;
		}
		return;
	}

	write_buffer_.skip(len);

	if (write_buffer_.empty()) {
		write_callback_->event(Event(Event::Done, 0));
		Action *a = EventSystem::instance()->schedule(write_callback_);
		write_action_ = a;
		write_callback_ = NULL;
		return;
	}
	write_action_ = write_schedule();
}

void
IOSystem::Handle::write_cancel(void)
{
	ASSERT(write_action_ != NULL);
	write_action_->cancel();
	write_action_ = NULL;

	if (write_callback_ != NULL) {
		delete write_callback_;
		write_callback_ = NULL;
	}
}

Action *
IOSystem::Handle::write_schedule(void)
{
	ASSERT(write_action_ == NULL);
	EventCallback *cb = callback(this, &IOSystem::Handle::write_callback);
	Action *a = EventSystem::instance()->poll(EventPoll::Writable, fd_, cb);
	return (a);
}

IOSystem::IOSystem(void)
: log_("/io/system"),
  handle_map_()
{ }

IOSystem::~IOSystem()
{
	ASSERT(handle_map_.empty());
}

void
IOSystem::attach(int fd, Channel *owner)
{
	ASSERT(handle_map_.find(handle_key_t(fd, owner)) == handle_map_.end());
	handle_map_[handle_key_t(fd, owner)] = new IOSystem::Handle(fd, owner);
}

void
IOSystem::detach(int fd, Channel *owner)
{
	handle_map_t::iterator it;
	IOSystem::Handle *h;

	it = handle_map_.find(handle_key_t(fd, owner));
	ASSERT(it != handle_map_.end());

	h = it->second;
	ASSERT(h != NULL);
	ASSERT(h->owner_ == owner);

	handle_map_.erase(it);
	delete h;
}

Action *
IOSystem::close(int fd, Channel *owner, EventCallback *cb)
{
	IOSystem::Handle *h;

	h = handle_map_[handle_key_t(fd, owner)];
	ASSERT(h != NULL);

	ASSERT(h->close_callback_ == NULL);
	ASSERT(h->close_action_ == NULL);

	ASSERT(h->read_callback_ == NULL);
	ASSERT(h->read_action_ == NULL);

	ASSERT(h->write_callback_ == NULL);
	ASSERT(h->write_action_ == NULL);

	ASSERT(h->fd_ != -1);

	h->close_callback_ = cb;
	h->close_action_ = h->close_schedule();
	return (cancellation(h, &IOSystem::Handle::close_cancel));
}

Action *
IOSystem::read(int fd, Channel *owner, size_t amount, EventCallback *cb)
{
	IOSystem::Handle *h;

	h = handle_map_[handle_key_t(fd, owner)];
	ASSERT(h != NULL);

	ASSERT(h->read_callback_ == NULL);
	ASSERT(h->read_action_ == NULL);

	h->read_amount_ = amount;
	h->read_callback_ = cb;
	h->read_action_ = h->read_schedule();
	return (cancellation(h, &IOSystem::Handle::read_cancel));
}

Action *
IOSystem::write(int fd, Channel *owner, Buffer *buffer, EventCallback *cb)
{
	IOSystem::Handle *h;

	h = handle_map_[handle_key_t(fd, owner)];
	ASSERT(h != NULL);

	ASSERT(h->write_callback_ == NULL);
	ASSERT(h->write_action_ == NULL);
	ASSERT(h->write_buffer_.empty());

	ASSERT(!buffer->empty());
	h->write_buffer_.append(buffer);
	buffer->clear();

	h->write_callback_ = cb;
	h->write_action_ = h->write_schedule();
	return (cancellation(h, &IOSystem::Handle::write_cancel));
}
<|endoftext|>


<commit_before>

#include "base/Window.h"
#include "base/Scene.h"
#include "base/Mesh.h"
#include "base/PerspectiveCamera.h"
#include "base/OrthographicCamera.h"
#include "material/DefaultMaterials.h"
#include "base/Texture.h"
#include "loader/ImageUtils.h"
#include "base/CubeGeometry.h"
#include "base/PlaneGeometry.h"
#include "opengl/GLRenderer.h"
#include "base/Code.h"
#include "loader/CTMLoader.h"
#include "base/MathUtils.h"
#include "loader/FontLoader.h"
#include "base/UIPanel.h"

#include <iostream>
#include <cassert>

using namespace three;

class CamaroDemo : public Window
{
  public:
    CamaroDemo()
      : Window(1024, 768)
    {
      const char * sky[6] = {
        "assets/sky/teide_posx.jpg",
        "assets/sky/teide_negx.jpg",
        "assets/sky/teide_posy.jpg",
        "assets/sky/teide_negy.jpg",
        "assets/sky/teide_posz.jpg",
        "assets/sky/teide_negz.jpg",
      };

      setTitle("Camaro Example");

      scene = new Scene();

      camera = new PerspectiveCamera(70, 1024.0 / 768.0, 1, 1000);
      camera->position.z = -18;
      camera->position.x = 0;
      camera->position.y = 9;
      camera->lookAt(Vector3(0, 1, 0));

      pivot = new Object();
      pivot->add(camera);

      scene->add(pivot);

      skyMap = ImageUtils::loadCubeTexture(sky, RGBFormat);

      camaro = createCar();
      scene->add(camaro);

      MeshBasicMaterial * groundMaterial = new MeshBasicMaterial();
      groundMaterial->diffuse = Color("#636363");
      groundMaterial->useEnvMap = true;
      groundMaterial->envMap = skyMap;
      groundMaterial->reflectivity = 0.2;

      Mesh * ground = new Mesh(new PlaneGeometry(30, 30, 4, 4), groundMaterial);
      scene->add(ground);

      // UI

      uiScene = new Scene();

      uiCamera = new OrthographicCamera(0, 1024, 0, 768, 1, 1000);
      uiScene->add(uiCamera);

      panel = new UIPanel(FontLoader::loadFont("assets/fonts/UbuntuLight.ttf", 16, 256, 256));
      panel->position = Vector3(5, 5, -1);
      uiScene->add(panel);

      renderer = new GLRenderer();
      renderer->setClearColor(Color("#587CEC"));
      renderer->autoClear = false;

      drag = false;
      mouseX = 0;
      mouseY = 0;
      angle = 0.0f;
      angleSpeed = 0.0f;
    }

    void resize(int width, int height)
    {
      renderer->setSize(width, height);
      camera->aspect = width / (float)height;
      camera->updateProjectionMatrix();

      uiCamera->right = width;
      uiCamera->bottom = height;
      uiCamera->updateProjectionMatrix();
    }

    void mousePressed(int button)
    {
      drag = true;
    }

    void mouseReleased(int button)
    {
      drag = false;
    }

    void mouseMoved(int x, int y)
    {
      int diffX = x - mouseX;
      int diffY = y - mouseY;
      mouseX = x;
      mouseY = y;

      if (drag)
        angle -= diffX * 0.003f;
    }

    bool update(double dt)
    {
      //camaro->rotation.y = angle;
      //camaro->matrixWorldNeedsUpdate = true;
      pivot->rotation.y = angle;
      pivot->matrixWorldNeedsUpdate = true;

      if (drag)
      {
        angleSpeed = max(0.0f, angleSpeed - (float)dt * 1.0f);
      }
      else
      {
        angleSpeed = min(0.2f, angleSpeed + (float)dt * 0.2f);
      }

      angle += angleSpeed * dt;

      // Build ui
      panel->begin(Vector2(mouseX, mouseY), false, 0);
      panel->label("Hello World!");
      panel->indent();
      panel->label("This is Daniel speaking!");
      panel->unindent();
      panel->label("Another label!");
      panel->separatorLine();
      panel->label("This is cool!");
      panel->end();

      return !isKeyDown(Key::Esc);
    }

    void paint()
    {
      renderer->render(scene, camera, 0, true);
      renderer->render(uiScene, uiCamera);
    }

    Object * createCar()
    {
      Mesh * body = CTMLoader::loadMesh("assets/models/camaro/body.ctm");
      Mesh * black = CTMLoader::loadMesh("assets/models/camaro/black.ctm");
      Mesh * black2 = CTMLoader::loadMesh("assets/models/camaro/black2.ctm");
      Mesh * crome = CTMLoader::loadMesh("assets/models/camaro/crome.ctm");
      Mesh * intake = CTMLoader::loadMesh("assets/models/camaro/intake.ctm");
      Mesh * interior = CTMLoader::loadMesh("assets/models/camaro/interior.ctm");
      Mesh * tire = CTMLoader::loadMesh("assets/models/camaro/tire.ctm");
      Mesh * tireRim = CTMLoader::loadMesh("assets/models/camaro/tire_rim.ctm");
      Mesh * window = CTMLoader::loadMesh("assets/models/camaro/window.ctm");
      assert(body && black && black2 && crome && intake && interior && tire && tireRim && window && "Could not Camaro model");

      MeshBasicMaterial * bodyMaterial = new MeshBasicMaterial();
      bodyMaterial->name = "body";
      bodyMaterial->useEnvMap = true;
      bodyMaterial->diffuse = Color("#CE6618");
      bodyMaterial->envMap = skyMap;
      bodyMaterial->reflectivity = 0.2;
      bodyMaterial->needsUpdate = true;

      MeshBasicMaterial * cromeMaterial = new MeshBasicMaterial();
      cromeMaterial->useEnvMap = true;
      cromeMaterial->envMap = skyMap;
      cromeMaterial->reflectivity = 0.9;

      MeshBasicMaterial * windowMaterial = new MeshBasicMaterial();
      windowMaterial->gammaCorrection = true;
      windowMaterial->transparent = true;
      windowMaterial->opacity = 0.5;
      windowMaterial->diffuse = Color(0.3, 0.3, 0.4);
      windowMaterial->useEnvMap = true;
      windowMaterial->useEnvMap = skyMap;
      windowMaterial->reflectivity = 0.8;

      MeshBasicMaterial * tireMaterial = new MeshBasicMaterial();
      tireMaterial->diffuse = Color("#1A1A1A");

      MeshBasicMaterial * blackMaterial = new MeshBasicMaterial();
      blackMaterial->diffuse = Color("#000");

      body->material = bodyMaterial;
      black->material = blackMaterial;
      black2->material = blackMaterial;
      crome->material = cromeMaterial;
      intake->material = bodyMaterial;
      interior->material = blackMaterial;
      tire->material = tireMaterial;
      tireRim->material = cromeMaterial;
      window->material = windowMaterial;

      Object * car = new Object();
      car->add(body);
      car->add(black);
      car->add(black2);
      car->add(crome);
      car->add(intake);
      car->add(interior);
      car->add(tire);
      car->add(tireRim);
      car->add(window);

      return car;
    }

  private:
    Renderer * renderer;
    Scene * scene;
    Scene * uiScene;
    UIPanel * panel;
    PerspectiveCamera * camera;
    OrthographicCamera * uiCamera;
    Object * camaro;
    Object * pivot;
    Texture * skyMap;

    bool drag;
    int mouseX, mouseY;
    float angle, angleSpeed;
};

int main(int argc, char * argv[])
{
  CamaroDemo demo;
  demo.run();
  return 0;
}
<commit_msg>Changed the text<commit_after>

#include "base/Window.h"
#include "base/Scene.h"
#include "base/Mesh.h"
#include "base/PerspectiveCamera.h"
#include "base/OrthographicCamera.h"
#include "material/DefaultMaterials.h"
#include "base/Texture.h"
#include "loader/ImageUtils.h"
#include "base/CubeGeometry.h"
#include "base/PlaneGeometry.h"
#include "opengl/GLRenderer.h"
#include "base/Code.h"
#include "loader/CTMLoader.h"
#include "base/MathUtils.h"
#include "loader/FontLoader.h"
#include "base/UIPanel.h"

#include <iostream>
#include <cassert>

using namespace three;

class CamaroDemo : public Window
{
  public:
    CamaroDemo()
      : Window(1024, 768)
    {
      const char * sky[6] = {
        "assets/sky/teide_posx.jpg",
        "assets/sky/teide_negx.jpg",
        "assets/sky/teide_posy.jpg",
        "assets/sky/teide_negy.jpg",
        "assets/sky/teide_posz.jpg",
        "assets/sky/teide_negz.jpg",
      };

      setTitle("Camaro Example");

      scene = new Scene();

      camera = new PerspectiveCamera(70, 1024.0 / 768.0, 1, 1000);
      camera->position.z = -18;
      camera->position.x = 0;
      camera->position.y = 9;
      camera->lookAt(Vector3(0, 1, 0));

      pivot = new Object();
      pivot->add(camera);

      scene->add(pivot);

      skyMap = ImageUtils::loadCubeTexture(sky, RGBFormat);

      camaro = createCar();
      scene->add(camaro);

      MeshBasicMaterial * groundMaterial = new MeshBasicMaterial();
      groundMaterial->diffuse = Color("#636363");
      groundMaterial->useEnvMap = true;
      groundMaterial->envMap = skyMap;
      groundMaterial->reflectivity = 0.2;

      Mesh * ground = new Mesh(new PlaneGeometry(30, 30, 4, 4), groundMaterial);
      scene->add(ground);

      // UI

      uiScene = new Scene();

      uiCamera = new OrthographicCamera(0, 1024, 0, 768, 1, 1000);
      uiScene->add(uiCamera);

      panel = new UIPanel(FontLoader::loadFont("assets/fonts/UbuntuLight.ttf", 16, 256, 256));
      panel->position = Vector3(5, 5, -1);
      uiScene->add(panel);

      renderer = new GLRenderer();
      renderer->setClearColor(Color("#587CEC"));
      renderer->autoClear = false;

      drag = false;
      mouseX = 0;
      mouseY = 0;
      angle = 0.0f;
      angleSpeed = 0.0f;
    }

    void resize(int width, int height)
    {
      renderer->setSize(width, height);
      camera->aspect = width / (float)height;
      camera->updateProjectionMatrix();

      uiCamera->right = width;
      uiCamera->bottom = height;
      uiCamera->updateProjectionMatrix();
    }

    void mousePressed(int button)
    {
      drag = true;
    }

    void mouseReleased(int button)
    {
      drag = false;
    }

    void mouseMoved(int x, int y)
    {
      int diffX = x - mouseX;
      int diffY = y - mouseY;
      mouseX = x;
      mouseY = y;

      if (drag)
        angle -= diffX * 0.003f;
    }

    bool update(double dt)
    {
      //camaro->rotation.y = angle;
      //camaro->matrixWorldNeedsUpdate = true;
      pivot->rotation.y = angle;
      pivot->matrixWorldNeedsUpdate = true;

      if (drag)
      {
        angleSpeed = max(0.0f, angleSpeed - (float)dt * 1.0f);
      }
      else
      {
        angleSpeed = min(0.2f, angleSpeed + (float)dt * 0.2f);
      }

      angle += angleSpeed * dt;

      // Build ui
      panel->begin(Vector2(mouseX, mouseY), false, 0);
      panel->label("Camaro Demo");
      panel->indent();
      panel->label("Indented label");
      panel->unindent();
      panel->label("Another label");
      panel->separatorLine();
      panel->label("This is cool!");
      panel->end();

      return !isKeyDown(Key::Esc);
    }

    void paint()
    {
      renderer->render(scene, camera, 0, true);
      renderer->render(uiScene, uiCamera);
    }

    Object * createCar()
    {
      Mesh * body = CTMLoader::loadMesh("assets/models/camaro/body.ctm");
      Mesh * black = CTMLoader::loadMesh("assets/models/camaro/black.ctm");
      Mesh * black2 = CTMLoader::loadMesh("assets/models/camaro/black2.ctm");
      Mesh * crome = CTMLoader::loadMesh("assets/models/camaro/crome.ctm");
      Mesh * intake = CTMLoader::loadMesh("assets/models/camaro/intake.ctm");
      Mesh * interior = CTMLoader::loadMesh("assets/models/camaro/interior.ctm");
      Mesh * tire = CTMLoader::loadMesh("assets/models/camaro/tire.ctm");
      Mesh * tireRim = CTMLoader::loadMesh("assets/models/camaro/tire_rim.ctm");
      Mesh * window = CTMLoader::loadMesh("assets/models/camaro/window.ctm");
      assert(body && black && black2 && crome && intake && interior && tire && tireRim && window && "Could not Camaro model");

      MeshBasicMaterial * bodyMaterial = new MeshBasicMaterial();
      bodyMaterial->name = "body";
      bodyMaterial->useEnvMap = true;
      bodyMaterial->diffuse = Color("#CE6618");
      bodyMaterial->envMap = skyMap;
      bodyMaterial->reflectivity = 0.2;
      bodyMaterial->needsUpdate = true;

      MeshBasicMaterial * cromeMaterial = new MeshBasicMaterial();
      cromeMaterial->useEnvMap = true;
      cromeMaterial->envMap = skyMap;
      cromeMaterial->reflectivity = 0.9;

      MeshBasicMaterial * windowMaterial = new MeshBasicMaterial();
      windowMaterial->gammaCorrection = true;
      windowMaterial->transparent = true;
      windowMaterial->opacity = 0.5;
      windowMaterial->diffuse = Color(0.3, 0.3, 0.4);
      windowMaterial->useEnvMap = true;
      windowMaterial->useEnvMap = skyMap;
      windowMaterial->reflectivity = 0.8;

      MeshBasicMaterial * tireMaterial = new MeshBasicMaterial();
      tireMaterial->diffuse = Color("#1A1A1A");

      MeshBasicMaterial * blackMaterial = new MeshBasicMaterial();
      blackMaterial->diffuse = Color("#000");

      body->material = bodyMaterial;
      black->material = blackMaterial;
      black2->material = blackMaterial;
      crome->material = cromeMaterial;
      intake->material = bodyMaterial;
      interior->material = blackMaterial;
      tire->material = tireMaterial;
      tireRim->material = cromeMaterial;
      window->material = windowMaterial;

      Object * car = new Object();
      car->add(body);
      car->add(black);
      car->add(black2);
      car->add(crome);
      car->add(intake);
      car->add(interior);
      car->add(tire);
      car->add(tireRim);
      car->add(window);

      return car;
    }

  private:
    Renderer * renderer;
    Scene * scene;
    Scene * uiScene;
    UIPanel * panel;
    PerspectiveCamera * camera;
    OrthographicCamera * uiCamera;
    Object * camaro;
    Object * pivot;
    Texture * skyMap;

    bool drag;
    int mouseX, mouseY;
    float angle, angleSpeed;
};

int main(int argc, char * argv[])
{
  CamaroDemo demo;
  demo.run();
  return 0;
}
<|endoftext|>


<commit_before>/***********************************************************************
 dbinfo.cpp - Example showing how to request information about the
	database schema, such as table names, column types, etc.

 Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by
 MySQL AB, and (c) 2004-2007 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the CREDITS
 file in the top directory of the distribution for details.

 This file is part of MySQL++.

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

 MySQL++ is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#include "util.h"

#include <mysql++.h>

#include <iomanip>
#include <iostream>
#include <string>
#include <vector>

using namespace std;
using namespace mysqlpp;

vector<string> yy;

static ostream&
separator(ostream& os)
{
	os << endl << "---------------------------" << endl << endl;
	return os;
}

int
main(int argc, char* argv[])
{
	Connection con(use_exceptions);
	try {
		connect_to_db(argc, argv, con, "");

		// Show MySQL version
		cout << "MySQL version: " << con.client_info() << separator;
		Query query = con.query();

		// Show all the databases we can see
		query << "show databases";
		cout << "Query: " << query.preview() << endl;

		Result res = query.store();
		cout << "Databases found: " << res.size();

		Row row;
		cout.setf(ios::left);
		Result::iterator i;
		for (i = res.begin(); i != res.end(); ++i) {
			row = *i;
			cout << endl << '\t' << setw(17) << row[0];
		}
		cout << separator;

		// Show the tables in the mysql database
		con.select_db("mysql");

		query.reset();
		query << "show tables";
		cout << "Query: " << query.preview() << endl;

		res = query.store();
		cout << "Tables found: " << res.size();

		cout.setf(ios::left);
		for (i = res.begin(); i != res.end(); ++i) {
			row = *i;
			string xx(row[0]);
			cout << endl << '\t' << setw(17) << row[0];
			yy.push_back(xx);
		}
		cout << separator;

		// Show information about each of the tables we found
		for (unsigned int j = 0; j < yy.size(); ++j) {
			query.reset();
			query << "describe " << yy[j] << "";
			cout << "Query: " << query.preview() << endl;
			res = query.store();
			unsigned int columns = res.num_fields(), counter;
			vector<int> widths;
			for (counter = 0; counter < columns; counter++) {
				string s = res.names(counter);
				if (s.compare("field") == 0) {
					widths.push_back(22);
				}
				else if (s.compare("type") == 0) {
					widths.push_back(20);
				}
				else if (s.compare("null") == 0) {
					widths.push_back(4);
				}
				else if (s.compare("key") == 0) {
					widths.push_back(3);
				}
				else if (s.compare("extra") == 0) {
					widths.push_back(0);
				}
				else {
					widths.push_back(15);
				}

				if (widths[counter]) {
					cout << '|' << setw(widths[counter]) <<
							res.names(counter) << '|';
				}
			}
			cout << endl;

			for (i = res.begin(); i != res.end(); ++i) {
				row = *i;
				for (counter = 0; counter < columns; counter++) {
					if (widths[counter]) {
						cout << ' ' << setw(widths[counter]) <<
								row.at(counter) << ' ';
					}
				}
				cout << endl;
			}

			cout << separator;
		}

		// Show the user table contents
		query.reset();
	 	query << "select * from user";
		cout << "Query: " << query.preview() << endl << endl;

		res = query.store();
		int columns = res.num_fields();
		cout << "fields = " << res.num_fields() << ", rows = " <<
				res.size() << endl;
		volatile MYSQL_RES* ress = res.raw_result();
		if (!ress)
			return -1;
		for (i = res.begin(); i != res.end(); ++i) {
			row = *i;
			for (int counter = 0; counter < columns; counter++) {
				cout << row.at(counter) << "  ";
			}
			cout << endl;
		}
	}
	catch (const BadQuery& er) {
		// Handle any query errors
		cerr << "Query error: " << er.what() << endl;
		return -1;
	}
	catch (const BadConversion& er) {
		// Handle bad conversions
		cerr << "Conversion error: " << er.what() << endl <<
				"\tretrieved data size: " << er.retrieved <<
				", actual size: " << er.actual_size << endl;
		return -1;
	}
	catch (const Exception& er) {
		// Catch-all for any other MySQL++ exceptions
		cerr << "Error: " << er.what() << endl;
		return -1;
	}

	return 0;
}
<commit_msg>Cleaned up dbinfo example style<commit_after>/***********************************************************************
 dbinfo.cpp - Example showing how to request information about the
	database schema, such as table names, column types, etc.

 Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by
 MySQL AB, and (c) 2004-2007 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the CREDITS
 file in the top directory of the distribution for details.

 This file is part of MySQL++.

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

 MySQL++ is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#include "util.h"

#include <mysql++.h>

#include <iomanip>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

static ostream&
separator(ostream& os)
{
	os << endl << "---------------------------" << endl << endl;
	return os;
}

int
main(int argc, char* argv[])
{
	mysqlpp::Connection con(mysqlpp::use_exceptions);
	try {
		connect_to_db(argc, argv, con, "");

		// Show MySQL version
		cout << "MySQL version: " << con.client_info() << separator;
		mysqlpp::Query query = con.query();

		// Show all the databases we can see
		query << "show databases";
		cout << "Query: " << query.preview() << endl;

		mysqlpp::Result res = query.store();
		cout << "Databases found: " << res.size();

		cout.setf(ios::left);
		mysqlpp::Result::iterator rit;
		for (rit = res.begin(); rit != res.end(); ++rit) {
			cout << endl << '\t' << setw(17) << (*rit)[0];
		}
		cout << separator;

		// Show the tables in the mysql database
		con.select_db("mysql");

		query.reset();
		query << "show tables";
		cout << "Query: " << query.preview() << endl;

		res = query.store();
		cout << "Tables found: " << res.size();

		vector<string> tables;
		cout.setf(ios::left);
		for (rit = res.begin(); rit != res.end(); ++rit) {
			string tbl((*rit)[0]);
			cout << endl << '\t' << setw(17) << tbl;
			tables.push_back(tbl);
		}
		cout << separator;

		// Show information about each of the tables we found
		vector<string>::iterator vit;
		for (vit = tables.begin(); vit != tables.end(); ++vit) {
			query.reset();
			query << "describe " << *vit;
			cout << "Query: " << query.preview() << endl;
			res = query.store();
			unsigned int columns = res.num_fields();
			vector<int> widths;
			for (int i = 0; i < columns; ++i) {
				string s = res.names(i);
				if (s.compare("field") == 0) {
					widths.push_back(22);
				}
				else if (s.compare("type") == 0) {
					widths.push_back(20);
				}
				else if (s.compare("null") == 0) {
					widths.push_back(4);
				}
				else if (s.compare("key") == 0) {
					widths.push_back(3);
				}
				else if (s.compare("extra") == 0) {
					widths.push_back(0);
				}
				else {
					widths.push_back(15);
				}

				if (widths[i]) {
					cout << '|' << setw(widths[i]) <<
							res.names(i) << '|';
				}
			}
			cout << endl;

			for (rit = res.begin(); rit != res.end(); ++rit) {
				for (int i = 0; i < columns; ++i) {
					if (widths[i]) {
						cout << ' ' << setw(widths[i]) << (*rit)[i] << ' ';
					}
				}
				cout << endl;
			}

			cout << separator;
		}

		// Show the user table contents
		query.reset();
	 	query << "select * from user";
		cout << "Query: " << query.preview() << endl << endl;

		res = query.store();
		int columns = res.num_fields();
		cout << "fields = " << res.num_fields() << ", rows = " <<
				res.size() << endl;
		volatile MYSQL_RES* ress = res.raw_result();
		if (!ress)
			return -1;
		for (rit = res.begin(); rit != res.end(); ++rit) {
			for (int i = 0; i < columns; ++i) {
				cout << (*rit)[i] << "  ";
			}
			cout << endl;
		}
	}
	catch (const mysqlpp::BadQuery& er) {
		// Handle any query errors
		cerr << "Query error: " << er.what() << endl;
		return -1;
	}
	catch (const mysqlpp::BadConversion& er) {
		// Handle bad conversions
		cerr << "Conversion error: " << er.what() << endl <<
				"\tretrieved data size: " << er.retrieved <<
				", actual size: " << er.actual_size << endl;
		return -1;
	}
	catch (const mysqlpp::Exception& er) {
		// Catch-all for any other MySQL++ exceptions
		cerr << "Error: " << er.what() << endl;
		return -1;
	}

	return 0;
}
<|endoftext|>


<commit_before>#include <map>
#include <unordered_map>
#include <string>
#include <iostream>
#include <chrono>
#include <vector>
#include <parallel_hashmap/phmap.h>

#include <sstream>

namespace patch
{
    template <typename T> std::string to_string(const T& n)
    {
        std::ostringstream stm;
        stm << n;
        return stm.str();
    }
}

template <typename T>
using milliseconds = std::chrono::duration<T, std::milli>;

class custom_type
{
    std::string one = "one";
    std::string two = "two";
    std::uint32_t three = 3;
    std::uint64_t four = 4;
    std::uint64_t five = 5;
public:
    custom_type() = default;
    // Make object movable and non-copyable
    custom_type(custom_type &&) = default;
    custom_type& operator=(custom_type &&) = default;
    // should be automatically deleted per http://www.slideshare.net/ripplelabs/howard-hinnant-accu2014
    //custom_type(custom_type const&) = delete;
    //custom_type& operator=(custom_type const&) = delete;
};

void test(std::size_t iterations, std::size_t container_size)
{
    std::clog << "bench: iterations: " << iterations <<  " / container_size: "  << container_size << "\n";
    {
        std::size_t count = 0;
        auto t1 = std::chrono::high_resolution_clock::now();
        for (std::size_t i=0; i<iterations; ++i)
        {
            std::unordered_map<std::string,custom_type> m;
            m.reserve(container_size);
            for (std::size_t j=0; j<container_size; ++j)
                m.emplace(patch::to_string(j),custom_type());
            count += m.size();
        }
        auto t2 = std::chrono::high_resolution_clock::now();
        auto elapsed = milliseconds<double>(t2 - t1).count();
        if (count != iterations*container_size)
            std::clog << "  invalid count: " << count << "\n";
        std::clog << "  std::unordered_map:     " << std::fixed << int(elapsed) << " ms\n";
    }

    {
        std::size_t count = 0;
        auto t1 = std::chrono::high_resolution_clock::now();
        for (std::size_t i=0; i<iterations; ++i)
        {
            std::map<std::string,custom_type> m;
            for (std::size_t j=0; j<container_size; ++j)
                m.emplace(patch::to_string(j),custom_type());
            count += m.size();
        }
        auto t2 = std::chrono::high_resolution_clock::now();
        auto elapsed = milliseconds<double>(t2 - t1).count();
        if (count != iterations*container_size)
            std::clog << "  invalid count: " << count << "\n";
        std::clog << "  std::map:               " << std::fixed << int(elapsed) << " ms\n";
    }

    {
        std::size_t count = 0;
        auto t1 = std::chrono::high_resolution_clock::now();
        for (std::size_t i=0; i<iterations; ++i)
        {
            std::vector<std::pair<std::string,custom_type>> m;
            m.reserve(container_size);
            for (std::size_t j=0; j<container_size; ++j)
                m.emplace_back(patch::to_string(j),custom_type());
            count += m.size();
        }
        auto t2 = std::chrono::high_resolution_clock::now();
        auto elapsed = milliseconds<double>(t2 - t1).count();
        if (count != iterations*container_size)
            std::clog << "  invalid count: " << count << "\n";
        std::clog << "  std::vector<std::pair>: " << std::fixed << int(elapsed) << " ms\n";
    }

    {
        std::size_t count = 0;
        auto t1 = std::chrono::high_resolution_clock::now();
        for (std::size_t i=0; i<iterations; ++i)
        {
            phmap::flat_hash_map<std::string,custom_type> m;
            m.reserve(container_size);
            for (std::size_t j=0; j<container_size; ++j)
                m.emplace(patch::to_string(j),custom_type());
            count += m.size();
        }
        auto t2 = std::chrono::high_resolution_clock::now();
        auto elapsed = milliseconds<double>(t2 - t1).count();
        if (count != iterations*container_size)
            std::clog << "  invalid count: " << count << "\n";
        std::clog << "  phmap::flat_hash_map:   " << std::fixed << int(elapsed) << " ms\n";
    }

}

int main()
{
    std::size_t iterations = 100000;

    test(iterations,1);
    test(iterations,10);
    test(iterations,50);
}
<commit_msg>cleanup the emplace example and add more enlightening testcase.<commit_after>#include <map>
#include <unordered_map>
#include <string>
#include <iostream>
#include <chrono>
#include <vector>
#include <parallel_hashmap/phmap.h>

#include <sstream>

namespace patch
{
    template <typename T> std::string to_string(const T& n)
    {
        std::ostringstream stm;
        stm << n;
        return stm.str();
    }
}

template <typename T>
using milliseconds = std::chrono::duration<T, std::milli>;

class custom_type
{
    std::string one = "one";
    std::string two = "two";
    std::uint32_t three = 3;
    std::uint64_t four = 4;
    std::uint64_t five = 5;
public:
    custom_type() = default;

    // Make object movable and non-copyable
    custom_type(custom_type &&) = default;
    custom_type& operator=(custom_type &&) = default;

    // should be automatically deleted per http://www.slideshare.net/ripplelabs/howard-hinnant-accu2014
    //custom_type(custom_type const&) = delete;
    //custom_type& operator=(custom_type const&) = delete;
};

class custom_type_2
{
    std::uint32_t three = 3;
    std::uint64_t four  = 4;
    std::uint64_t five  = 5;
    std::uint64_t six   = 6;
public:
    custom_type_2() = default;

    // Make object movable and non-copyable
    custom_type_2(custom_type_2 &&) = default;
    custom_type_2& operator=(custom_type_2 &&) = default;

    // should be automatically deleted per http://www.slideshare.net/ripplelabs/howard-hinnant-accu2014
    //custom_type_2(custom_type_2 const&) = delete;
    //custom_type_2& operator=(custom_type_2 const&) = delete;
};

// emplace string + large struct
// -----------------------------
template <class Map, class V, class T> struct _emplace
{
    void operator()(Map &m, std::size_t j);
};

// "void" template parameter -> use emplace
template <class Map, class V> struct _emplace<Map, V, void>
{
    void operator()(Map &m, std::size_t j)
    {
        m.emplace(patch::to_string(j), V());
    }
};

// "int" template parameter -> use emplace_back for std::vector
template <class Map, class V> struct _emplace<Map, V, int>
{
    void operator()(Map &m, std::size_t j)
    {
        m.emplace_back(patch::to_string(j), V());
    }
};

// insert <int, custom_type_2>
// ---------------------------
template <class Map, class V, class T> struct emplace_2_ints
{
    void operator()(Map &m, std::size_t j);
};

// "void" template parameter -> use emplace
template <class Map, class V> struct emplace_2_ints<Map, V, void>
{
    void operator()(Map &m, std::size_t j)
    {
        m.emplace(j, V());
    }
};

// "int" template parameter -> use emplace_back for std::vector
template <class Map, class V> struct emplace_2_ints<Map, V, int>
{
    void operator()(Map &m, std::size_t j)
    {
        m.emplace_back(j, V());
    }
};

// The test itself
// ---------------
template <class Map, class V, class T, template <class, class, class> class INSERT>
void _test(std::size_t iterations, std::size_t container_size, const char *map_name)
{
    std::size_t count = 0;
    auto t1 = std::chrono::high_resolution_clock::now();
    INSERT<Map, V, T> insert;
    for (std::size_t i=0; i<iterations; ++i)
    {
        Map m;
        for (std::size_t j=0; j<container_size; ++j)
            insert(m, j);
        count += m.size();
    }
    auto t2 = std::chrono::high_resolution_clock::now();
    auto elapsed = milliseconds<double>(t2 - t1).count();
    if (count != iterations*container_size)
        std::clog << "  invalid count: " << count << "\n";
    std::clog << map_name << std::fixed << int(elapsed) << " ms\n";
}

template <class K, class V, template <class, class, class> class INSERT>
void test(std::size_t iterations, std::size_t container_size)
{
    std::clog << "bench: iterations: " << iterations <<  " / container_size: "  << container_size << "\n";

    _test<std::map<K, V>,               V, void, INSERT>(iterations, container_size, "  std::map:               ");
    _test<std::unordered_map<K, V>,     V, void, INSERT>(iterations, container_size, "  std::unordered_map:     ");
    _test<phmap::flat_hash_map<K, V>,   V, void, INSERT>(iterations, container_size, "  phmap::flat_hash_map:   ");
    _test<std::vector<std::pair<K, V>>, V, int, INSERT> (iterations, container_size, "  std::vector<std::pair>: ");
    std::clog << "\n";

}

int main()
{
    std::size_t iterations = 100000;

    // test with custom_type_2 (int key + 32 byte value). This is representative
    // of the hash table insertion speed.
    // -------------------------------------------------------------------------
    std::clog << "\n\n" << "testing with <int, custom_type_2>"   "\n";
    std::clog << "---------------------------------"   "\n";
    test<int, custom_type_2, emplace_2_ints>(iterations,10);
    test<int, custom_type_2, emplace_2_ints>(iterations,100);
    test<int, custom_type_2, emplace_2_ints>(iterations,500);

    // test with custom_type, which contains two std::string values, and use
    // a generated string key. This is not very indicative of the speed of the
    // hash itself, as a good chunk of the time is spent creating the keys and
    // values (as shown by the long times even for std::vector).
    // -----------------------------------------------------------------------
    std::clog << "\n" << "testing with <string, custom_type>"   "\n";
    std::clog << "---------------------------------"   "\n";
    test<std::string, custom_type, _emplace>(iterations,1);
    test<std::string, custom_type, _emplace>(iterations,10);
    test<std::string, custom_type, _emplace>(iterations,50);

}
<|endoftext|>


<commit_before>// @(#)root/tree:$Id$
// Author: Rene Brun   17/03/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// A TLeaf for a variable length string.                                //
//////////////////////////////////////////////////////////////////////////

#include "TLeafC.h"
#include "TBranch.h"
#include "TBasket.h"
#include "TClonesArray.h"
#include "Riostream.h"
#include <string>

ClassImp(TLeafC)

//______________________________________________________________________________
TLeafC::TLeafC(): TLeaf()
{
//*-*-*-*-*-*Default constructor for LeafC*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*        ============================

   fLenType = 1;
   fMinimum = 0;
   fMaximum = 0;
   fValue   = 0;
   fPointer = 0;
}

//______________________________________________________________________________
TLeafC::TLeafC(TBranch *parent, const char *name, const char *type)
   :TLeaf(parent, name,type)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create a LeafC*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                      ==============
//*-*

   fLenType = 1;
   fMinimum = 0;
   fMaximum = 0;
   fValue   = 0;
   fPointer = 0;
}

//______________________________________________________________________________
TLeafC::~TLeafC()
{
//*-*-*-*-*-*Default destructor for a LeafC*-*-*-*-*-*-*-*-*-*-*-*
//*-*        ===============================

   if (ResetAddress(0,kTRUE)) delete [] fValue;
}

//______________________________________________________________________________
void TLeafC::Export(TClonesArray *list, Int_t n)
{
//*-*-*-*-*-*Export element from local leaf buffer to ClonesArray*-*-*-*-*
//*-*        ====================================================

   Int_t j = 0;
   for (Int_t i=0;i<n;i++) {
      memcpy((char*)list->UncheckedAt(i) + fOffset,&fValue[j], 1);
      j += fLen;
   }
}

//______________________________________________________________________________
void TLeafC::FillBasket(TBuffer &b)
{
//*-*-*-*-*-*-*-*-*-*-*Pack leaf elements in Basket output buffer*-*-*-*-*-*-*
//*-*                  ==========================================

   if (fPointer) fValue = *fPointer;
   Int_t len = strlen(fValue);
   if (len >= fMaximum) fMaximum = len+1;
   if (len >= fLen)     fLen = len+1;
   b.WriteFastArrayString(fValue,len);
}

//______________________________________________________________________________
const char *TLeafC::GetTypeName() const
{
//*-*-*-*-*-*-*-*Returns name of leaf type*-*-*-*-*-*-*-*-*-*-*-*
//*-*            =========================

   if (fIsUnsigned) return "UChar_t";
   return "Char_t";
}

//______________________________________________________________________________
void TLeafC::Import(TClonesArray *list, Int_t n)
{
//*-*-*-*-*-*Import element from ClonesArray into local leaf buffer*-*-*-*-*
//*-*        ======================================================

   Int_t j = 0;
   for (Int_t i=0;i<n;i++) {
      memcpy(&fValue[j],(char*)list->UncheckedAt(i) + fOffset, 1);
      j += fLen;
   }
}

//______________________________________________________________________________
void TLeafC::PrintValue(Int_t) const
{
   // Prints leaf value.

   char *value = (char*)GetValuePointer();
   printf("%s",value);
}

//______________________________________________________________________________
void TLeafC::ReadBasket(TBuffer &b)
{
   // Read leaf elements from Basket input buffer.

   // Try to deal with the file written during the time where len was not
   // written to disk when len was == 0.
   Int_t readbasket = GetBranch()->GetReadBasket();
   TBasket *basket = GetBranch()->GetBasket(readbasket);
   Int_t* entryOffset = basket->GetEntryOffset();
   if (entryOffset) {
      Long64_t first = GetBranch()->GetBasketEntry()[readbasket];
      Long64_t entry = GetBranch()->GetReadEntry();
      if ( ( ( (readbasket == GetBranch()->GetWriteBasket() && (entry+1) == GetBranch()->GetEntries()) /* Very last entry */
               ||
               (readbasket <  GetBranch()->GetWriteBasket() && (entry+1) == GetBranch()->GetBasketEntry()[readbasket+1] ) /* Last entry of the basket */
             )
             &&
             ( entryOffset[entry-first] == basket->GetLast() ) /* The 'read' point is at the end of the basket */
           )
           ||
           ( entryOffset[entry-first] == entryOffset[entry-first+1] ) /* This string did not use up any space in the buffer */
         )
      {
         // Empty string
         fValue[0] = '\0';
         return;
      }
   }
   b.ReadFastArrayString(fValue,fLen);
}

//______________________________________________________________________________
void TLeafC::ReadBasketExport(TBuffer &b, TClonesArray *list, Int_t n)
{
   // Read leaf elements from Basket input buffer
   // and export buffer to TClonesArray objects.

   UChar_t len;
   b >> len;
   if (len) {
      if (len >= fLen) len = fLen-1;
      b.ReadFastArray(fValue,len);
      fValue[len] = 0;
   } else {
      fValue[0] = 0;
   }

   Int_t j = 0;
   for (Int_t i=0;i<n;i++) {
      memcpy((char*)list->UncheckedAt(i) + fOffset,&fValue[j], 1);
      j += fLen;
   }
}

//______________________________________________________________________________
void TLeafC::ReadValue(istream &s)
{
   // Read a string from istream s and store it into the branch buffer.

   string temp;
   s >> temp;
   if ( TestBit(kNewValue) &&
        (temp.size()+1 > ((UInt_t)fNdata))) {
      // Grow buffer if needed and we created the buffer.
      fNdata = temp.size() + 1;
      if (TestBit(kIndirectAddress) && fPointer) {
         delete [] *fPointer;
         *fPointer = new char[fNdata];
      } else {
         fValue = new char[fNdata];
      }
   }
   strcpy(fValue,temp.c_str());
}

//______________________________________________________________________________
void TLeafC::SetAddress(void *add)
{
//*-*-*-*-*-*-*-*-*-*-*Set leaf buffer data address*-*-*-*-*-*
//*-*                  ============================

   if (ResetAddress(add)) {
      delete [] fValue;
   }
   if (add) {
      if (TestBit(kIndirectAddress)) {
         fPointer = (char**)add;
         Int_t ncountmax = fLen;
         if (fLeafCount) ncountmax = fLen*(fLeafCount->GetMaximum() + 1);
         if ((fLeafCount && ncountmax > Int_t(fLeafCount->GetValue())) ||
             ncountmax > fNdata || *fPointer == 0) {
            if (*fPointer) delete [] *fPointer;
            if (ncountmax > fNdata) fNdata = ncountmax;
            *fPointer = new char[fNdata];
         }
         fValue = *fPointer;
      } else {
         fValue = (char*)add;
      }
   }
   else {
      fValue = new char[fNdata];
      fValue[0] = 0;
   }
}
<commit_msg>use strlcpy<commit_after>// @(#)root/tree:$Id$
// Author: Rene Brun   17/03/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// A TLeaf for a variable length string.                                //
//////////////////////////////////////////////////////////////////////////

#include "TLeafC.h"
#include "TBranch.h"
#include "TBasket.h"
#include "TClonesArray.h"
#include "Riostream.h"
#include <string>

ClassImp(TLeafC)

//______________________________________________________________________________
TLeafC::TLeafC(): TLeaf()
{
//*-*-*-*-*-*Default constructor for LeafC*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*        ============================

   fLenType = 1;
   fMinimum = 0;
   fMaximum = 0;
   fValue   = 0;
   fPointer = 0;
}

//______________________________________________________________________________
TLeafC::TLeafC(TBranch *parent, const char *name, const char *type)
   :TLeaf(parent, name,type)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create a LeafC*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                      ==============
//*-*

   fLenType = 1;
   fMinimum = 0;
   fMaximum = 0;
   fValue   = 0;
   fPointer = 0;
}

//______________________________________________________________________________
TLeafC::~TLeafC()
{
//*-*-*-*-*-*Default destructor for a LeafC*-*-*-*-*-*-*-*-*-*-*-*
//*-*        ===============================

   if (ResetAddress(0,kTRUE)) delete [] fValue;
}

//______________________________________________________________________________
void TLeafC::Export(TClonesArray *list, Int_t n)
{
//*-*-*-*-*-*Export element from local leaf buffer to ClonesArray*-*-*-*-*
//*-*        ====================================================

   Int_t j = 0;
   for (Int_t i=0;i<n;i++) {
      memcpy((char*)list->UncheckedAt(i) + fOffset,&fValue[j], 1);
      j += fLen;
   }
}

//______________________________________________________________________________
void TLeafC::FillBasket(TBuffer &b)
{
//*-*-*-*-*-*-*-*-*-*-*Pack leaf elements in Basket output buffer*-*-*-*-*-*-*
//*-*                  ==========================================

   if (fPointer) fValue = *fPointer;
   Int_t len = strlen(fValue);
   if (len >= fMaximum) fMaximum = len+1;
   if (len >= fLen)     fLen = len+1;
   b.WriteFastArrayString(fValue,len);
}

//______________________________________________________________________________
const char *TLeafC::GetTypeName() const
{
//*-*-*-*-*-*-*-*Returns name of leaf type*-*-*-*-*-*-*-*-*-*-*-*
//*-*            =========================

   if (fIsUnsigned) return "UChar_t";
   return "Char_t";
}

//______________________________________________________________________________
void TLeafC::Import(TClonesArray *list, Int_t n)
{
//*-*-*-*-*-*Import element from ClonesArray into local leaf buffer*-*-*-*-*
//*-*        ======================================================

   Int_t j = 0;
   for (Int_t i=0;i<n;i++) {
      memcpy(&fValue[j],(char*)list->UncheckedAt(i) + fOffset, 1);
      j += fLen;
   }
}

//______________________________________________________________________________
void TLeafC::PrintValue(Int_t) const
{
   // Prints leaf value.

   char *value = (char*)GetValuePointer();
   printf("%s",value);
}

//______________________________________________________________________________
void TLeafC::ReadBasket(TBuffer &b)
{
   // Read leaf elements from Basket input buffer.

   // Try to deal with the file written during the time where len was not
   // written to disk when len was == 0.
   Int_t readbasket = GetBranch()->GetReadBasket();
   TBasket *basket = GetBranch()->GetBasket(readbasket);
   Int_t* entryOffset = basket->GetEntryOffset();
   if (entryOffset) {
      Long64_t first = GetBranch()->GetBasketEntry()[readbasket];
      Long64_t entry = GetBranch()->GetReadEntry();
      if ( ( ( (readbasket == GetBranch()->GetWriteBasket() && (entry+1) == GetBranch()->GetEntries()) /* Very last entry */
               ||
               (readbasket <  GetBranch()->GetWriteBasket() && (entry+1) == GetBranch()->GetBasketEntry()[readbasket+1] ) /* Last entry of the basket */
             )
             &&
             ( entryOffset[entry-first] == basket->GetLast() ) /* The 'read' point is at the end of the basket */
           )
           ||
           ( entryOffset[entry-first] == entryOffset[entry-first+1] ) /* This string did not use up any space in the buffer */
         )
      {
         // Empty string
         fValue[0] = '\0';
         return;
      }
   }
   b.ReadFastArrayString(fValue,fLen);
}

//______________________________________________________________________________
void TLeafC::ReadBasketExport(TBuffer &b, TClonesArray *list, Int_t n)
{
   // Read leaf elements from Basket input buffer
   // and export buffer to TClonesArray objects.

   UChar_t len;
   b >> len;
   if (len) {
      if (len >= fLen) len = fLen-1;
      b.ReadFastArray(fValue,len);
      fValue[len] = 0;
   } else {
      fValue[0] = 0;
   }

   Int_t j = 0;
   for (Int_t i=0;i<n;i++) {
      memcpy((char*)list->UncheckedAt(i) + fOffset,&fValue[j], 1);
      j += fLen;
   }
}

//______________________________________________________________________________
void TLeafC::ReadValue(istream &s)
{
   // Read a string from istream s and store it into the branch buffer.

   string temp;
   s >> temp;
   if ( TestBit(kNewValue) &&
        (temp.size()+1 > ((UInt_t)fNdata))) {
      // Grow buffer if needed and we created the buffer.
      fNdata = temp.size() + 1;
      if (TestBit(kIndirectAddress) && fPointer) {
         delete [] *fPointer;
         *fPointer = new char[fNdata];
      } else {
         fValue = new char[fNdata];
      }
   }
   strlcpy(fValue,temp.c_str(),fNdata);
}

//______________________________________________________________________________
void TLeafC::SetAddress(void *add)
{
//*-*-*-*-*-*-*-*-*-*-*Set leaf buffer data address*-*-*-*-*-*
//*-*                  ============================

   if (ResetAddress(add)) {
      delete [] fValue;
   }
   if (add) {
      if (TestBit(kIndirectAddress)) {
         fPointer = (char**)add;
         Int_t ncountmax = fLen;
         if (fLeafCount) ncountmax = fLen*(fLeafCount->GetMaximum() + 1);
         if ((fLeafCount && ncountmax > Int_t(fLeafCount->GetValue())) ||
             ncountmax > fNdata || *fPointer == 0) {
            if (*fPointer) delete [] *fPointer;
            if (ncountmax > fNdata) fNdata = ncountmax;
            *fPointer = new char[fNdata];
         }
         fValue = *fPointer;
      } else {
         fValue = (char*)add;
      }
   }
   else {
      fValue = new char[fNdata];
      fValue[0] = 0;
   }
}
<|endoftext|>


<commit_before>#include "gpu.hpp"

#include <aliceVision/config.hpp>
#include <aliceVision/system/Logger.hpp>

#include <sstream>
#include <memory.h>

#if ALICEVISION_IS_DEFINED(ALICEVISION_HAVE_CUDA)
#include <cuda_runtime.h>
#endif

namespace aliceVision {
namespace gpu {

bool gpuSupportCUDA(int minComputeCapabilityMajor,
    int minComputeCapabilityMinor,
    int minTotalDeviceMemory)
{
#if ALICEVISION_IS_DEFINED(ALICEVISION_HAVE_CUDA)
    int nbDevices = 0;
    cudaError_t success;
    success = cudaGetDeviceCount(&nbDevices);
    if( success != cudaSuccess )
    {
        ALICEVISION_LOG_ERROR("cudaGetDeviceCount failed: " << cudaGetErrorString(success));
        nbDevices = 0;
    }

    if(nbDevices > 0)
    {
        for(int i = 0; i < nbDevices; ++i)
        {
            cudaDeviceProp deviceProperties;

            if(cudaGetDeviceProperties(&deviceProperties, i) != cudaSuccess)
            {
                ALICEVISION_LOG_ERROR("Cannot get properties for CUDA gpu device " << i);
                continue;
            }

            if((deviceProperties.major > minComputeCapabilityMajor ||
                (deviceProperties.major == minComputeCapabilityMajor &&
                    deviceProperties.minor >= minComputeCapabilityMinor)) &&
                deviceProperties.totalGlobalMem >= (minTotalDeviceMemory*1024*1024))
            {
                ALICEVISION_LOG_INFO("Supported CUDA-Enabled GPU detected.");
                return true;
            }
            else
            {
                ALICEVISION_LOG_ERROR("CUDA-Enabled GPU detected, but the compute capabilities is not enough.\n"
                    << " - Device " << i << ": " << deviceProperties.major << "." << deviceProperties.minor << ", global memory: " << int(deviceProperties.totalGlobalMem / (1024*1024)) << "MB\n"
                    << " - Requirements: " << minComputeCapabilityMajor << "." << minComputeCapabilityMinor << ", global memory: " << minTotalDeviceMemory << "MB\n"
                );
            }
        }
        ALICEVISION_LOG_INFO("CUDA-Enabled GPU not supported.");
    }
    else
    {
        ALICEVISION_LOG_INFO("Can't find CUDA-Enabled GPU.");
    }
#endif
    return false;
}

std::string gpuInformationCUDA()
{
    std::string information;
#if ALICEVISION_IS_DEFINED(ALICEVISION_HAVE_CUDA)
    int nbDevices = 0;
    if( cudaGetDeviceCount(&nbDevices) != cudaSuccess )
    {
        ALICEVISION_LOG_WARNING( "Could not determine number of CUDA cards in this system" );
        nbDevices = 0;
    }

    if(nbDevices > 0)
    {
        information = "CUDA-Enabled GPU.\n";
        for(int i = 0; i < nbDevices; ++i)
        {
            cudaDeviceProp deviceProperties;
            if(cudaGetDeviceProperties( &deviceProperties, i) != cudaSuccess )
            {
                ALICEVISION_LOG_ERROR("Cannot get properties for CUDA gpu device " << i);
                continue;
            }

            if( cudaSetDevice( i ) != cudaSuccess )
            {
                ALICEVISION_LOG_WARNING( "Device with number " << i << " does not exist" );
                continue;
            }

            std::size_t avail;
            std::size_t total;
            if(cudaMemGetInfo(&avail, &total) != cudaSuccess)
            {
                // if the card does not provide this information.
                avail = 0;
                total = 0;
                ALICEVISION_LOG_WARNING("Cannot get available memory information for CUDA gpu device " << i << ".");
            }
            std::stringstream deviceSS;

            deviceSS << "Device information:" << std::endl
                << "\t- id:                      " << i << std::endl
                << "\t- name:                    " << deviceProperties.name << std::endl
                << "\t- compute capability:      " << deviceProperties.major << "." << deviceProperties.minor << std::endl
                << "\t- total device memory:     " << deviceProperties.totalGlobalMem / (1024 * 1024) << " MB " << std::endl
                << "\t- device memory available: " << avail / (1024 * 1024) << " MB " << std::endl
                << "\t- per-block shared memory: " << deviceProperties.sharedMemPerBlock << std::endl
                << "\t- warp size:               " << deviceProperties.warpSize << std::endl
                << "\t- max threads per block:   " << deviceProperties.maxThreadsPerBlock << std::endl
                << "\t- max threads per SM(X):   " << deviceProperties.maxThreadsPerMultiProcessor << std::endl
                << "\t- max block sizes:         "
                << "{" << deviceProperties.maxThreadsDim[0]
                << "," << deviceProperties.maxThreadsDim[1]
                << "," << deviceProperties.maxThreadsDim[2] << "}" << std::endl
                << "\t- max grid sizes:          "
                << "{" << deviceProperties.maxGridSize[0]
                << "," << deviceProperties.maxGridSize[1]
                << "," << deviceProperties.maxGridSize[2] << "}" << std::endl
                << "\t- max 2D array texture:    "
                << "{" << deviceProperties.maxTexture2D[0]
                << "," << deviceProperties.maxTexture2D[1] << "}" << std::endl
                << "\t- max 3D array texture:    "
                << "{" << deviceProperties.maxTexture3D[0]
                << "," << deviceProperties.maxTexture3D[1]
                << "," << deviceProperties.maxTexture3D[2] << "}" << std::endl
                << "\t- max 2D linear texture:   "
                << "{" << deviceProperties.maxTexture2DLinear[0]
                << "," << deviceProperties.maxTexture2DLinear[1]
                << "," << deviceProperties.maxTexture2DLinear[2] << "}" << std::endl
                << "\t- max 2D layered texture:  "
                << "{" << deviceProperties.maxTexture2DLayered[0]
                << "," << deviceProperties.maxTexture2DLayered[1]
                << "," << deviceProperties.maxTexture2DLayered[2] << "}" << std::endl
                << "\t- number of SM(x)s:        " << deviceProperties.multiProcessorCount << std::endl
                << "\t- registers per SM(x):     " << deviceProperties.regsPerMultiprocessor << std::endl
                << "\t- registers per block:     " << deviceProperties.regsPerBlock << std::endl
                << "\t- concurrent kernels:      " << (deviceProperties.concurrentKernels ? "yes":"no") << std::endl
                << "\t- mapping host memory:     " << (deviceProperties.canMapHostMemory ? "yes":"no") << std::endl
                << "\t- unified addressing:      " << (deviceProperties.unifiedAddressing ? "yes":"no") << std::endl
                << "\t- texture alignment:       " << deviceProperties.textureAlignment << " byte" << std::endl
                << "\t- pitch alignment:         " << deviceProperties.texturePitchAlignment << " byte" << std::endl;

            information += deviceSS.str();
        }
    }
#else
    information = "No CUDA-Enabled GPU.";
#endif
    return information;
}

} // namespace gpu
} // namespace aliceVision<commit_msg>[gpu] fix info messages<commit_after>#include "gpu.hpp"

#include <aliceVision/config.hpp>
#include <aliceVision/system/Logger.hpp>

#include <sstream>
#include <memory.h>

#if ALICEVISION_IS_DEFINED(ALICEVISION_HAVE_CUDA)
#include <cuda_runtime.h>
#endif

namespace aliceVision {
namespace gpu {

bool gpuSupportCUDA(int minComputeCapabilityMajor,
    int minComputeCapabilityMinor,
    int minTotalDeviceMemory)
{
#if ALICEVISION_IS_DEFINED(ALICEVISION_HAVE_CUDA)
    int nbDevices = 0;
    cudaError_t success;
    success = cudaGetDeviceCount(&nbDevices);
    if( success != cudaSuccess )
    {
        ALICEVISION_LOG_ERROR("cudaGetDeviceCount failed: " << cudaGetErrorString(success));
        nbDevices = 0;
    }

    if(nbDevices > 0)
    {
        for(int i = 0; i < nbDevices; ++i)
        {
            cudaDeviceProp deviceProperties;

            if(cudaGetDeviceProperties(&deviceProperties, i) != cudaSuccess)
            {
                ALICEVISION_LOG_ERROR("Cannot get properties for CUDA gpu device " << i);
                continue;
            }

            if((deviceProperties.major > minComputeCapabilityMajor ||
                (deviceProperties.major == minComputeCapabilityMajor &&
                    deviceProperties.minor >= minComputeCapabilityMinor)) &&
                deviceProperties.totalGlobalMem >= (minTotalDeviceMemory*1024*1024))
            {
                ALICEVISION_LOG_INFO("Supported CUDA-Enabled GPU detected.");
                return true;
            }
            else
            {
                ALICEVISION_LOG_ERROR("CUDA-Enabled GPU detected, but the compute capabilities is not enough.\n"
                    << " - Device " << i << ": " << deviceProperties.major << "." << deviceProperties.minor << ", global memory: " << int(deviceProperties.totalGlobalMem / (1024*1024)) << "MB\n"
                    << " - Requirements: " << minComputeCapabilityMajor << "." << minComputeCapabilityMinor << ", global memory: " << minTotalDeviceMemory << "MB\n"
                );
            }
        }
        ALICEVISION_LOG_INFO("CUDA-Enabled GPU not supported.");
    }
    else
    {
        ALICEVISION_LOG_INFO("Can't find CUDA-Enabled GPU.");
    }
#endif
    return false;
}

std::string gpuInformationCUDA()
{
    std::string information;
#if ALICEVISION_IS_DEFINED(ALICEVISION_HAVE_CUDA)
    int nbDevices = 0;
    if( cudaGetDeviceCount(&nbDevices) != cudaSuccess )
    {
        ALICEVISION_LOG_WARNING( "Could not determine number of CUDA cards in this system" );
        nbDevices = 0;
    }

    if(nbDevices > 0)
    {
        information = "CUDA-Enabled GPU.\n";
        for(int i = 0; i < nbDevices; ++i)
        {
            cudaDeviceProp deviceProperties;
            if(cudaGetDeviceProperties( &deviceProperties, i) != cudaSuccess )
            {
                ALICEVISION_LOG_ERROR("Cannot get properties for CUDA gpu device " << i);
                continue;
            }

            if( cudaSetDevice( i ) != cudaSuccess )
            {
                ALICEVISION_LOG_WARNING( "Device with number " << i << " does not exist" );
                continue;
            }

            std::size_t avail;
            std::size_t total;
            if(cudaMemGetInfo(&avail, &total) != cudaSuccess)
            {
                // if the card does not provide this information.
                avail = 0;
                total = 0;
                ALICEVISION_LOG_WARNING("Cannot get available memory information for CUDA gpu device " << i << ".");
            }
            std::stringstream deviceSS;

            deviceSS << "Device information:" << std::endl
                << "\t- id:                      " << i << std::endl
                << "\t- name:                    " << deviceProperties.name << std::endl
                << "\t- compute capability:      " << deviceProperties.major << "." << deviceProperties.minor << std::endl
                << "\t- total device memory:     " << deviceProperties.totalGlobalMem / (1024 * 1024) << " MB " << std::endl
                << "\t- device memory available: " << avail / (1024 * 1024) << " MB " << std::endl
                << "\t- per-block shared memory: " << deviceProperties.sharedMemPerBlock << std::endl
                << "\t- warp size:               " << deviceProperties.warpSize << std::endl
                << "\t- max threads per block:   " << deviceProperties.maxThreadsPerBlock << std::endl
                << "\t- max threads per SM(X):   " << deviceProperties.maxThreadsPerMultiProcessor << std::endl
                << "\t- max block sizes:         "
                << "{" << deviceProperties.maxThreadsDim[0]
                << "," << deviceProperties.maxThreadsDim[1]
                << "," << deviceProperties.maxThreadsDim[2] << "}" << std::endl
                << "\t- max grid sizes:          "
                << "{" << deviceProperties.maxGridSize[0]
                << "," << deviceProperties.maxGridSize[1]
                << "," << deviceProperties.maxGridSize[2] << "}" << std::endl
                << "\t- max 2D array texture:    "
                << "{" << deviceProperties.maxTexture2D[0]
                << "," << deviceProperties.maxTexture2D[1] << "}" << std::endl
                << "\t- max 3D array texture:    "
                << "{" << deviceProperties.maxTexture3D[0]
                << "," << deviceProperties.maxTexture3D[1]
                << "," << deviceProperties.maxTexture3D[2] << "}" << std::endl
                << "\t- max 2D linear texture:   "
                << "{" << deviceProperties.maxTexture2DLinear[0]
                << "," << deviceProperties.maxTexture2DLinear[1]
                << "," << deviceProperties.maxTexture2DLinear[2] << "}" << std::endl
                << "\t- max 2D layered texture:  "
                << "{" << deviceProperties.maxTexture2DLayered[0]
                << "," << deviceProperties.maxTexture2DLayered[1]
                << "," << deviceProperties.maxTexture2DLayered[2] << "}" << std::endl
                << "\t- number of SM(x)s:        " << deviceProperties.multiProcessorCount << std::endl
                << "\t- registers per SM(x):     " << deviceProperties.regsPerMultiprocessor << std::endl
                << "\t- registers per block:     " << deviceProperties.regsPerBlock << std::endl
                << "\t- concurrent kernels:      " << (deviceProperties.concurrentKernels ? "yes":"no") << std::endl
                << "\t- mapping host memory:     " << (deviceProperties.canMapHostMemory ? "yes":"no") << std::endl
                << "\t- unified addressing:      " << (deviceProperties.unifiedAddressing ? "yes":"no") << std::endl
                << "\t- texture alignment:       " << deviceProperties.textureAlignment << " byte" << std::endl
                << "\t- pitch alignment:         " << deviceProperties.texturePitchAlignment << " byte" << std::endl;

            information += deviceSS.str();
        }
    }
    else
    {
        information = "No CUDA-Enabled GPU.";
    }
#else
    information = "AliceVision built without CUDA support.";
#endif
    return information;
}

} // namespace gpu
} // namespace aliceVision<|endoftext|>


<commit_before>#include "http_server.h"

#include "evpp/libevent_headers.h"
#include "evpp/libevent_watcher.h"
#include "evpp/event_loop.h"
#include "evpp/event_loop_thread.h"
#include "evpp/event_loop_thread_pool.h"

namespace evpp {
namespace http {
HTTPServer::HTTPServer(uint32_t thread_num) {
    tpool_.reset(new EventLoopThreadPool(NULL, thread_num));
}

HTTPServer::~HTTPServer() {
    tpool_.reset();
}

bool HTTPServer::Start(int port) {
    bool rc = tpool_->Start(true);
    if (!rc) {
        return rc;
    }

    rc = rc && StartListenThread(port);

    while (!IsRunning()) {
        usleep(1);
    }

    return rc;
}

bool HTTPServer::Start(std::vector<int> listen_ports) {
    bool rc = tpool_->Start(true);
    if (!rc) {
        return rc;
    }

    for (size_t i = 0; i < listen_ports.size(); ++i) {
        if (!StartListenThread(listen_ports[i])) {
            return false;
        }
    }
    return true;
}

bool HTTPServer::StartListenThread(int port) {
    ListenThread lt;
    lt.t = std::make_shared<EventLoopThread>();
    lt.t->SetName(std::string("StandaloneHTTPServer-Main-") + std::to_string(port));

    lt.h = std::make_shared<Service>(lt.t->event_loop());
    if (!lt.h->Listen(port)) {
        LOG_ERROR << "http server listen at port " << port << " failed.";
        return false;
    }

    //  ListenThread ˳ʱøúֹͣ Service
    auto http_close_fn = std::bind(&Service::Stop, lt.h);
    bool rc = lt.t->Start(true,
                          EventLoopThread::Functor(),
                          http_close_fn);
    assert(lt.t->IsRunning());
    for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
        lt.h->RegisterHandler(it->first, it->second);
    }
    lt.h->RegisterDefaultHandler(default_callback_);
    listen_threads_.push_back(lt);
    return rc;
}

void HTTPServer::Stop(bool wait_thread_exit /*= false*/) {
    for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
        it->t->Stop();
    }
    tpool_->Stop();

    if (wait_thread_exit) {
        for (;;) {
            bool stopped = true;
            for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
                // 1. Service Stop listen_thread_ ˳ʱԶִ Service::Stop
                // 2. EventLoopThread  Stop
                if (!it->t->IsStopped()) {
                    stopped = false;
                    break;
                }
            }

            if (!tpool_->IsStopped()) {
                stopped = false;
            }

            if (stopped) {
                break;
            }

            usleep(1);
        }

        assert(tpool_->IsStopped());
        for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
            assert(it->t->IsStopped());
        }
        assert(IsStopped());
    }
}

void HTTPServer::Pause() {
    for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
        EventLoop* loop = it->t->event_loop();
        loop->RunInLoop(std::bind(&Service::Pause, it->h));
    }
}

void HTTPServer::Continue() {
    for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
        EventLoop* loop = it->t->event_loop();
        loop->RunInLoop(std::bind(&Service::Continue, it->h));
    }
}

bool HTTPServer::IsRunning() const {
    if (listen_threads_.empty()) {
        return false;
    }

    if (!tpool_->IsRunning()) {
        return false;
    }

    for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
        if (!it->t->IsRunning()) {
            return false;
        }
    }
    return true;
}

bool HTTPServer::IsStopped() const {
    assert(!listen_threads_.empty());
    assert(tpool_);

    if (!tpool_->IsStopped()) {
        return false;
    }

    for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
        if (!it->t->IsStopped()) {
            return false;
        }
    }
}

void HTTPServer::RegisterHandler(const std::string& uri, HTTPRequestCallback callback) {
    if (IsRunning()) {
        for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
            HTTPRequestCallback cb = std::bind(&HTTPServer::Dispatch, this,
                                               it->h->event_loop(),
                                               std::placeholders::_1,
                                               std::placeholders::_2,
                                               callback);
            it->h->RegisterHandler(uri, cb);
        }
    }
    callbacks_[uri] = callback;
}

void HTTPServer::RegisterDefaultHandler(HTTPRequestCallback callback) {
    if (IsRunning()) {
        for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
            HTTPRequestCallback cb = std::bind(&HTTPServer::Dispatch, this,
                                               it->h->event_loop(),
                                               std::placeholders::_1,
                                               std::placeholders::_2,
                                               callback);
            it->h->RegisterDefaultHandler(cb);
        }
    }
    default_callback_ = callback;
}

void HTTPServer::Dispatch(EventLoop* listening_loop,
                          const ContextPtr& ctx,
                          const HTTPSendResponseCallback& response_callback,
                          const HTTPRequestCallback& user_callback) {
    LOG_TRACE << "dispatch request " << ctx->req << " url=" << ctx->original_uri() << " in main thread";
    EventLoop* loop = NULL;
    loop = GetNextLoop(listening_loop, ctx);

    // HTTPȵ̴߳
    auto f = [](const ContextPtr & context,
                const HTTPSendResponseCallback & response_cb,
                const HTTPRequestCallback & user_cb) {
        LOG_TRACE << "process request " << context->req
            << " url=" << context->original_uri() << " in working thread";

        // ڹִ߳УϲӦõĻصHTTP
        // ϲӦô󣬱Ҫ response_callback Ҳǻص Service::SendReply С
        user_cb(context, response_cb);
    };

    loop->RunInLoop(std::bind(f, ctx, response_callback, user_callback));
}

EventLoop* HTTPServer::GetNextLoop(EventLoop* default_loop, const ContextPtr& ctx) {
    if (tpool_->thread_num() == 0) {
        return default_loop;
    }

    if (IsRoundRobin()) {
        return tpool_->GetNextLoop();
    }
    uint64_t hash = std::hash<std::string>()(ctx->remote_ip);
    return tpool_->GetNextLoopWithHash(hash);
}

Service* HTTPServer::service(int index) const {
    if (index < int(listen_threads_.size())) {
        return listen_threads_[index].h.get();
    }

    return NULL;
}
}
}
<commit_msg>Fix HTTPServer::IsStopped() bug<commit_after>#include "http_server.h"

#include "evpp/libevent_headers.h"
#include "evpp/libevent_watcher.h"
#include "evpp/event_loop.h"
#include "evpp/event_loop_thread.h"
#include "evpp/event_loop_thread_pool.h"

namespace evpp {
namespace http {
HTTPServer::HTTPServer(uint32_t thread_num) {
    tpool_.reset(new EventLoopThreadPool(NULL, thread_num));
}

HTTPServer::~HTTPServer() {
    tpool_.reset();
}

bool HTTPServer::Start(int port) {
    bool rc = tpool_->Start(true);
    if (!rc) {
        return rc;
    }

    rc = rc && StartListenThread(port);

    while (!IsRunning()) {
        usleep(1);
    }

    return rc;
}

bool HTTPServer::Start(std::vector<int> listen_ports) {
    bool rc = tpool_->Start(true);
    if (!rc) {
        return rc;
    }

    for (size_t i = 0; i < listen_ports.size(); ++i) {
        if (!StartListenThread(listen_ports[i])) {
            return false;
        }
    }
    return true;
}

bool HTTPServer::StartListenThread(int port) {
    ListenThread lt;
    lt.t = std::make_shared<EventLoopThread>();
    lt.t->SetName(std::string("StandaloneHTTPServer-Main-") + std::to_string(port));

    lt.h = std::make_shared<Service>(lt.t->event_loop());
    if (!lt.h->Listen(port)) {
        LOG_ERROR << "http server listen at port " << port << " failed.";
        return false;
    }

    //  ListenThread ˳ʱøúֹͣ Service
    auto http_close_fn = std::bind(&Service::Stop, lt.h);
    bool rc = lt.t->Start(true,
                          EventLoopThread::Functor(),
                          http_close_fn);
    assert(lt.t->IsRunning());
    for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
        lt.h->RegisterHandler(it->first, it->second);
    }
    lt.h->RegisterDefaultHandler(default_callback_);
    listen_threads_.push_back(lt);
    return rc;
}

void HTTPServer::Stop(bool wait_thread_exit /*= false*/) {
    for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
        it->t->Stop();
    }
    tpool_->Stop();

    if (wait_thread_exit) {
        for (;;) {
            bool stopped = true;
            for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
                // 1. Service Stop listen_thread_ ˳ʱԶִ Service::Stop
                // 2. EventLoopThread  Stop
                if (!it->t->IsStopped()) {
                    stopped = false;
                    break;
                }
            }

            if (!tpool_->IsStopped()) {
                stopped = false;
            }

            if (stopped) {
                break;
            }

            usleep(1);
        }

        assert(tpool_->IsStopped());
        for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
            assert(it->t->IsStopped());
        }
        assert(IsStopped());
    }
}

void HTTPServer::Pause() {
    for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
        EventLoop* loop = it->t->event_loop();
        loop->RunInLoop(std::bind(&Service::Pause, it->h));
    }
}

void HTTPServer::Continue() {
    for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
        EventLoop* loop = it->t->event_loop();
        loop->RunInLoop(std::bind(&Service::Continue, it->h));
    }
}

bool HTTPServer::IsRunning() const {
    if (listen_threads_.empty()) {
        return false;
    }

    if (!tpool_->IsRunning()) {
        return false;
    }

    for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
        if (!it->t->IsRunning()) {
            return false;
        }
    }
    return true;
}

bool HTTPServer::IsStopped() const {
    assert(!listen_threads_.empty());
    assert(tpool_);

    if (!tpool_->IsStopped()) {
        return false;
    }

    for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
        if (!it->t->IsStopped()) {
            return false;
        }
    }
    return true;
}

void HTTPServer::RegisterHandler(const std::string& uri, HTTPRequestCallback callback) {
    if (IsRunning()) {
        for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
            HTTPRequestCallback cb = std::bind(&HTTPServer::Dispatch, this,
                                               it->h->event_loop(),
                                               std::placeholders::_1,
                                               std::placeholders::_2,
                                               callback);
            it->h->RegisterHandler(uri, cb);
        }
    }
    callbacks_[uri] = callback;
}

void HTTPServer::RegisterDefaultHandler(HTTPRequestCallback callback) {
    if (IsRunning()) {
        for (auto it = listen_threads_.begin(); it != listen_threads_.end(); ++it) {
            HTTPRequestCallback cb = std::bind(&HTTPServer::Dispatch, this,
                                               it->h->event_loop(),
                                               std::placeholders::_1,
                                               std::placeholders::_2,
                                               callback);
            it->h->RegisterDefaultHandler(cb);
        }
    }
    default_callback_ = callback;
}

void HTTPServer::Dispatch(EventLoop* listening_loop,
                          const ContextPtr& ctx,
                          const HTTPSendResponseCallback& response_callback,
                          const HTTPRequestCallback& user_callback) {
    LOG_TRACE << "dispatch request " << ctx->req << " url=" << ctx->original_uri() << " in main thread";
    EventLoop* loop = NULL;
    loop = GetNextLoop(listening_loop, ctx);

    // HTTPȵ̴߳
    auto f = [](const ContextPtr & context,
                const HTTPSendResponseCallback & response_cb,
                const HTTPRequestCallback & user_cb) {
        LOG_TRACE << "process request " << context->req
            << " url=" << context->original_uri() << " in working thread";

        // ڹִ߳УϲӦõĻصHTTP
        // ϲӦô󣬱Ҫ response_callback Ҳǻص Service::SendReply С
        user_cb(context, response_cb);
    };

    loop->RunInLoop(std::bind(f, ctx, response_callback, user_callback));
}

EventLoop* HTTPServer::GetNextLoop(EventLoop* default_loop, const ContextPtr& ctx) {
    if (tpool_->thread_num() == 0) {
        return default_loop;
    }

    if (IsRoundRobin()) {
        return tpool_->GetNextLoop();
    }
    uint64_t hash = std::hash<std::string>()(ctx->remote_ip);
    return tpool_->GetNextLoopWithHash(hash);
}

Service* HTTPServer::service(int index) const {
    if (index < int(listen_threads_.size())) {
        return listen_threads_[index].h.get();
    }

    return NULL;
}
}
}
<|endoftext|>