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

#include "update_engine/download_action.h"
#include <errno.h>
#include <algorithm>
#include <string>
#include <vector>
#include <glib.h>
#include "update_engine/action_pipe.h"
#include "update_engine/subprocess.h"

using std::min;
using std::string;
using std::vector;

namespace chromeos_update_engine {

// Use a buffer to reduce the number of IOPS on SSD devices.
const size_t kFileWriterBufferSize = 128 * 1024;  // 128 KiB

DownloadAction::DownloadAction(PrefsInterface* prefs,
                               HttpFetcher* http_fetcher)
    : prefs_(prefs),
      writer_(NULL),
      http_fetcher_(http_fetcher),
      code_(kActionCodeSuccess),
      delegate_(NULL),
      bytes_received_(0) {}

DownloadAction::~DownloadAction() {}

void DownloadAction::PerformAction() {
  http_fetcher_->set_delegate(this);

  // Get the InstallPlan and read it
  CHECK(HasInputObject());
  install_plan_ = GetInputObject();
  bytes_received_ = 0;

  install_plan_.Dump();

  if (writer_) {
    LOG(INFO) << "Using writer for test.";
  } else {
    delta_performer_.reset(new DeltaPerformer(prefs_));
    delta_performer_->set_current_kernel_hash(install_plan_.kernel_hash);
    delta_performer_->set_current_rootfs_hash(install_plan_.rootfs_hash);
    writer_ = delta_performer_.get();
  }
  int rc = writer_->Open(install_plan_.install_path.c_str(),
                         O_TRUNC | O_WRONLY | O_CREAT | O_LARGEFILE,
                         0644);
  if (rc < 0) {
    LOG(ERROR) << "Unable to open output file " << install_plan_.install_path;
    // report error to processor
    processor_->ActionComplete(this, kActionCodeInstallDeviceOpenError);
    return;
  }
  if (delta_performer_.get() &&
      !delta_performer_->OpenKernel(
          install_plan_.kernel_install_path.c_str())) {
    LOG(ERROR) << "Unable to open kernel file "
               << install_plan_.kernel_install_path.c_str();
    writer_->Close();
    processor_->ActionComplete(this, kActionCodeKernelDeviceOpenError);
    return;
  }
  if (delegate_) {
    delegate_->SetDownloadStatus(true);  // Set to active.
  }
  http_fetcher_->BeginTransfer(install_plan_.download_url);
}

void DownloadAction::TerminateProcessing() {
  if (writer_) {
    LOG_IF(WARNING, writer_->Close() != 0) << "Error closing the writer.";
    writer_ = NULL;
  }
  if (delegate_) {
    delegate_->SetDownloadStatus(false);  // Set to inactive.
  }
  // Terminates the transfer. The action is terminated, if necessary, when the
  // TransferTerminated callback is received.
  http_fetcher_->TerminateTransfer();
}

void DownloadAction::SeekToOffset(off_t offset) {
  bytes_received_ = offset;
}

void DownloadAction::ReceivedBytes(HttpFetcher *fetcher,
                                   const char* bytes,
                                   int length) {
  bytes_received_ += length;
  if (delegate_)
    delegate_->BytesReceived(bytes_received_, install_plan_.size);
  if (writer_ && !writer_->Write(bytes, length)) {
    LOG(ERROR) << "Write error -- terminating processing.";
    // Don't tell the action processor that the action is complete until we get
    // the TransferTerminated callback. Otherwise, this and the HTTP fetcher
    // objects may get destroyed before all callbacks are complete.
    code_ = kActionCodeDownloadWriteError;
    TerminateProcessing();
    return;
  }
}

namespace {
void FlushLinuxCaches() {
  vector<string> command;
  command.push_back("/bin/sync");
  int rc;
  LOG(INFO) << "FlushLinuxCaches-sync...";
  Subprocess::SynchronousExec(command, &rc, NULL);
  LOG(INFO) << "FlushLinuxCaches-drop_caches...";

  const char* const drop_cmd = "3\n";
  utils::WriteFile("/proc/sys/vm/drop_caches", drop_cmd, strlen(drop_cmd));

  LOG(INFO) << "FlushLinuxCaches done.";
}
}

void DownloadAction::TransferComplete(HttpFetcher *fetcher, bool successful) {
  if (writer_) {
    LOG_IF(WARNING, writer_->Close() != 0) << "Error closing the writer.";
    writer_ = NULL;
  }
  if (delegate_) {
    delegate_->SetDownloadStatus(false);  // Set to inactive.
  }
  ActionExitCode code =
      successful ? kActionCodeSuccess : kActionCodeDownloadTransferError;
  if (code == kActionCodeSuccess && delta_performer_.get()) {
    code = delta_performer_->VerifyPayload("",
                                           install_plan_.download_hash,
                                           install_plan_.size);
    if (code != kActionCodeSuccess) {
      LOG(ERROR) << "Download of " << install_plan_.download_url
                 << " failed due to payload verification error.";
    } else if (!delta_performer_->GetNewPartitionInfo(
        &install_plan_.kernel_size,
        &install_plan_.kernel_hash,
        &install_plan_.rootfs_size,
        &install_plan_.rootfs_hash)) {
      LOG(ERROR) << "Unable to get new partition hash info.";
      code = kActionCodeDownloadNewPartitionInfoError;
    }
  }

  FlushLinuxCaches();

  // Write the path to the output pipe if we're successful.
  if (code == kActionCodeSuccess && HasOutputPipe())
    SetOutputObject(install_plan_);
  processor_->ActionComplete(this, code);
}

void DownloadAction::TransferTerminated(HttpFetcher *fetcher) {
  if (code_ != kActionCodeSuccess) {
    processor_->ActionComplete(this, code_);
  }
}

};  // namespace {}
<commit_msg>Don't drop cache.<commit_after>// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "update_engine/download_action.h"
#include <errno.h>
#include <algorithm>
#include <string>
#include <vector>
#include <glib.h>
#include "update_engine/action_pipe.h"
#include "update_engine/subprocess.h"

using std::min;
using std::string;
using std::vector;

namespace chromeos_update_engine {

// Use a buffer to reduce the number of IOPS on SSD devices.
const size_t kFileWriterBufferSize = 128 * 1024;  // 128 KiB

DownloadAction::DownloadAction(PrefsInterface* prefs,
                               HttpFetcher* http_fetcher)
    : prefs_(prefs),
      writer_(NULL),
      http_fetcher_(http_fetcher),
      code_(kActionCodeSuccess),
      delegate_(NULL),
      bytes_received_(0) {}

DownloadAction::~DownloadAction() {}

void DownloadAction::PerformAction() {
  http_fetcher_->set_delegate(this);

  // Get the InstallPlan and read it
  CHECK(HasInputObject());
  install_plan_ = GetInputObject();
  bytes_received_ = 0;

  install_plan_.Dump();

  if (writer_) {
    LOG(INFO) << "Using writer for test.";
  } else {
    delta_performer_.reset(new DeltaPerformer(prefs_));
    delta_performer_->set_current_kernel_hash(install_plan_.kernel_hash);
    delta_performer_->set_current_rootfs_hash(install_plan_.rootfs_hash);
    writer_ = delta_performer_.get();
  }
  int rc = writer_->Open(install_plan_.install_path.c_str(),
                         O_TRUNC | O_WRONLY | O_CREAT | O_LARGEFILE,
                         0644);
  if (rc < 0) {
    LOG(ERROR) << "Unable to open output file " << install_plan_.install_path;
    // report error to processor
    processor_->ActionComplete(this, kActionCodeInstallDeviceOpenError);
    return;
  }
  if (delta_performer_.get() &&
      !delta_performer_->OpenKernel(
          install_plan_.kernel_install_path.c_str())) {
    LOG(ERROR) << "Unable to open kernel file "
               << install_plan_.kernel_install_path.c_str();
    writer_->Close();
    processor_->ActionComplete(this, kActionCodeKernelDeviceOpenError);
    return;
  }
  if (delegate_) {
    delegate_->SetDownloadStatus(true);  // Set to active.
  }
  http_fetcher_->BeginTransfer(install_plan_.download_url);
}

void DownloadAction::TerminateProcessing() {
  if (writer_) {
    LOG_IF(WARNING, writer_->Close() != 0) << "Error closing the writer.";
    writer_ = NULL;
  }
  if (delegate_) {
    delegate_->SetDownloadStatus(false);  // Set to inactive.
  }
  // Terminates the transfer. The action is terminated, if necessary, when the
  // TransferTerminated callback is received.
  http_fetcher_->TerminateTransfer();
}

void DownloadAction::SeekToOffset(off_t offset) {
  bytes_received_ = offset;
}

void DownloadAction::ReceivedBytes(HttpFetcher *fetcher,
                                   const char* bytes,
                                   int length) {
  bytes_received_ += length;
  if (delegate_)
    delegate_->BytesReceived(bytes_received_, install_plan_.size);
  if (writer_ && !writer_->Write(bytes, length)) {
    LOG(ERROR) << "Write error -- terminating processing.";
    // Don't tell the action processor that the action is complete until we get
    // the TransferTerminated callback. Otherwise, this and the HTTP fetcher
    // objects may get destroyed before all callbacks are complete.
    code_ = kActionCodeDownloadWriteError;
    TerminateProcessing();
    return;
  }
}

void DownloadAction::TransferComplete(HttpFetcher *fetcher, bool successful) {
  if (writer_) {
    LOG_IF(WARNING, writer_->Close() != 0) << "Error closing the writer.";
    writer_ = NULL;
  }
  if (delegate_) {
    delegate_->SetDownloadStatus(false);  // Set to inactive.
  }
  ActionExitCode code =
      successful ? kActionCodeSuccess : kActionCodeDownloadTransferError;
  if (code == kActionCodeSuccess && delta_performer_.get()) {
    code = delta_performer_->VerifyPayload("",
                                           install_plan_.download_hash,
                                           install_plan_.size);
    if (code != kActionCodeSuccess) {
      LOG(ERROR) << "Download of " << install_plan_.download_url
                 << " failed due to payload verification error.";
    } else if (!delta_performer_->GetNewPartitionInfo(
        &install_plan_.kernel_size,
        &install_plan_.kernel_hash,
        &install_plan_.rootfs_size,
        &install_plan_.rootfs_hash)) {
      LOG(ERROR) << "Unable to get new partition hash info.";
      code = kActionCodeDownloadNewPartitionInfoError;
    }
  }

  // Write the path to the output pipe if we're successful.
  if (code == kActionCodeSuccess && HasOutputPipe())
    SetOutputObject(install_plan_);
  processor_->ActionComplete(this, code);
}

void DownloadAction::TransferTerminated(HttpFetcher *fetcher) {
  if (code_ != kActionCodeSuccess) {
    processor_->ActionComplete(this, code_);
  }
}

};  // namespace {}
<|endoftext|>


<commit_before>#include <Siv3D.hpp>
#include "Main.h"
#include "Loader.hpp"

#ifdef DEPLOY
String currentDocument(L"./doc/");
String configFile(L"./speedreader.ini");
String sampleDocument(L"./sample/");
#else
String currentDocument(L"../Speedreader/speedreader/doc/");
String configFile(L"../Speedreader/speedreader.ini");
String sampleDocument(L"../Speedreader/speedreader/sample/");
#endif

std::wstring displayOrder(L"LTR"); // Right to left(RTL): 0 LTR: 1
double joystickPointerSpeed = 1.0;
int drawingXOffset = 100;
double viewingPage = 0;
int displayMode = 1;
int autoplaySpeed = 0;
int debugTexureLoadingBenchmark;
int numPages;

void loadPDFConfig() {
	String filename = Format(currentDocument, L"config.ini");
	INIReader ini(filename);
	if (!ini)
	{
		INIWriter default_ini(filename);
		default_ini.write(L"displayOrder", L"LTR");
		ini = INIReader(filename);
	}
	displayOrder = ini.getOr<std::wstring>(L"displayOrder", L"LTR");
}

void updateConfig(INIReader	config) {
	config.reload();
	joystickPointerSpeed = config.getOr<double>(L"Controller.PointerSpeed", 1.0);
	drawingXOffset = config.getOr<int>(L"Drawing.XOffset", 100);
	debugTexureLoadingBenchmark = config.getOr<int>(L"Debug.TextureLoadingBenchmark", 0);
}

void loadNewDocument(String path) {
	currentDocument = path;
	Profiler::EnableWarning(false); // 再読み込み時のテクスチャ破棄で警告されるので読み終わるまでdisable
	loadPDFConfig();
	viewingPage = 0;
	displayMode = 1;
	loader::loadPDF(currentDocument);
	numPages = loader::numPages;
}

void convertToDDS() {
	// TODO: make menu to call this
	for (auto i : step(100)) {
		Image(
			Format(L"C:/Users/nishio/Desktop/images/pages_{:04d}.png"_fmt, i + 1)
		).save(
			Format(L"C:/Users/nishio/Desktop/images/pages_{:04d}.dds"_fmt, i + 1)
		);
	}
}

void Main()
{
	INIReader config(configFile);
	updateConfig(config);

	const Font font(30);
	const Font font10(10);

	loadPDFConfig();

	Window::SetTitle(L"Speedreader");
	Window::Resize(1300, 700);
	Window::ToUpperLeft();
	Window::SetStyle(WindowStyle::Sizeable);

	Cursor::SetPos(0, 0);
	Vec2 pos = Mouse::Pos();

	Stopwatch stopwatch(true);
	loader::loadPDF(currentDocument);
	numPages = loader::numPages;

	while (System::Update())
	{
		double invFPS = stopwatch.ms();
		stopwatch.restart();
		if (config.hasChanged()) updateConfig(config);

		if (Dragdrop::HasItems())
		{
			const Array<FilePath> items = Dragdrop::GetFilePaths();
			loadNewDocument(items[0]);
		}

		// まだ読み終わってなければ順次ロード
		loader::keepLoading();

		auto controller = XInput(0);

		controller.setLeftTriggerDeadZone();
		controller.setRightTriggerDeadZone();
		controller.setLeftThumbDeadZone();
		controller.setRightThumbDeadZone();

		pos += Vec2(
			controller.leftThumbX * joystickPointerSpeed * invFPS,
			-controller.leftThumbY * joystickPointerSpeed * invFPS);
		//pos += Mouse::Delta();  // マウスも併用する場合はジョイスティックでの移動差分をマウスの入力と勘違いするので用修正
		if (pos.x < 0) pos.x = 0;
		if (pos.y < 0) pos.y = 0;
		if (pos.x > Window::Width()) pos.x = Window::Width();
		if (pos.y > Window::Height()) pos.y = Window::Height();

		viewingPage -= pow(controller.leftTrigger, 2);
		viewingPage += pow(controller.rightTrigger, 2);

		viewingPage += controller.rightThumbY / 5;  // slow

		// キーでのパラパラめくり// 早送り巻き戻しメタファー
		if (Input::KeyRight.clicked) {
			if (autoplaySpeed > 0) {
				autoplaySpeed *= 2;
			}
			else if (autoplaySpeed == 0) {
				autoplaySpeed = 1;
			}
			else {
				autoplaySpeed = 0;
			}
		}
		if (Input::KeyLeft.clicked) {
			if (autoplaySpeed < 0) {
				autoplaySpeed *= 2;
			}
			else if (autoplaySpeed == 0) {
				autoplaySpeed = -1;
			}
			else {
				autoplaySpeed = 0;
			}
		}
		if (autoplaySpeed) {
			viewingPage += autoplaySpeed * invFPS / 1000;
			font10(L"自動再生: ", autoplaySpeed).draw(0, 0);
		}

		if (viewingPage < 0) viewingPage = 0;
		if (viewingPage > numPages - 1) viewingPage = numPages - 1;
		if (displayMode == 0) {
			if (controller.buttonA.clicked || Input::KeyDown.clicked) viewingPage += 0.5;
			if (controller.buttonB.clicked || Input::KeyUp.clicked) viewingPage -= 0.5;
		}
		else {
			if (controller.buttonA.clicked || Input::KeyDown.clicked) {
				viewingPage++;
				autoplaySpeed = 0;
			}
			if (controller.buttonB.clicked || Input::KeyUp.clicked) {
				viewingPage--;
				autoplaySpeed = 0;
			}
		}
		// 最初・最後のページで前後に移動した時に反対側に飛ぶべきかどうか、今disabled
		//if (page < 0) page += numPages;
		//if (page > numPages - 1) page = 0;
		if (viewingPage < 0) viewingPage = 0;
		if (viewingPage > numPages - 1) viewingPage = numPages - 1;

		int ipage = static_cast<int>(viewingPage) % numPages;

		if (controller.buttonLB.clicked || Input::KeyZ.clicked) {
			displayMode = (displayMode - 1);
			if (displayMode < 0) displayMode = 0;
		}
		if (controller.buttonRB.clicked || Input::KeyC.clicked) {
			displayMode = (displayMode + 1);
		}

		Texture t = loader::getPage(ipage);
		double h = static_cast<double>(t.height);
		double w = static_cast<double>(t.width);
		const int screenHeight = 640;
		double pageHeight = screenHeight, pageWidth = w / h * pageHeight;

		int horizontalMultiplier = 2; // 見開きにするなら2、しないなら1
		if (h < w) horizontalMultiplier = 1;

		// draw progress bar
		int progressBarWidth = static_cast<int>(pageWidth * horizontalMultiplier);
		Rect(drawingXOffset, screenHeight + 10,
			progressBarWidth, 20).draw(Color(200));
		Rect(drawingXOffset, screenHeight + 12,
			progressBarWidth * (ipage + 1) / numPages, 16).draw(Color(100));
		font10(ipage + 1).draw(drawingXOffset, screenHeight + 12);

		const int32 w2 = font10(numPages).region().w;
		font10(numPages).draw(drawingXOffset + progressBarWidth - w2, screenHeight + 12);

		if (displayMode == 0) {
			// Zoom-in mode
			int scale = 2;
			if (static_cast<int>(viewingPage * 2) % 2 == 0) {
				t.resize(pageWidth * scale, pageHeight * scale).draw(drawingXOffset, 0);
			}
			else {
				t(0, h / 2, w, h / 2).resize(pageWidth * scale, pageHeight).draw(drawingXOffset, 0);
			}
		}
		else if(displayMode > 0) {
			int numPageHorizontal = displayMode * horizontalMultiplier;
			int numPageVertical = displayMode;
			// Tile mode
			if (displayOrder == L"LTR") {
				pageHeight /= numPageVertical;
				pageWidth /= numPageVertical;
				for (int y = 0; y < numPageVertical; y++) {
					for (int x = 0; x < numPageHorizontal; x++) {
						int i = ipage + y * numPageHorizontal + x;
						loader::getPage(i)
							.resize(pageWidth, pageHeight)
							.draw(drawingXOffset + pageWidth * x, pageHeight * y);

					}
				}
			}
			else {
				pageHeight /= numPageVertical;
				pageWidth /= numPageVertical;
				for (int y = 0; y < numPageVertical; y++) {
					for (int x = 0; x < numPageHorizontal; x++) {
						int i = ipage + y * numPageHorizontal + x;
						loader::getPage(i)
							.resize(pageWidth, pageHeight)
							.draw(drawingXOffset + pageWidth * (numPageHorizontal - x - 1), pageHeight * y);

					}
				}
			}

			// Xボタンでそのページを通常表示
			if (controller.buttonX.clicked || Input::MouseL.clicked) {
				if (Input::MouseL.clicked) {
					pos = Mouse::Pos();
				}
				int x = static_cast<int>((pos.x - drawingXOffset) / pageWidth);
				if (displayOrder != L"LTR") {
					x = numPageHorizontal - x - 1;
				}
				int y = static_cast<int>(pos.y / pageHeight);
				viewingPage = ipage + x + y * numPageHorizontal;
				displayMode = 1;
				Cursor::SetPos(0, 0);
				pos = { 0, 0 };
			}
		}

		// デモ用
		if (controller.buttonY.clicked || Input::KeyY.clicked) {
			loadNewDocument(sampleDocument);
		}

		// カーソル表示
		Circle(pos, 10).draw({ 255, 255, 0, 127 });
	}
}
<commit_msg>ignore ESC<commit_after>#include <Siv3D.hpp>
#include "Main.h"
#include "Loader.hpp"

#ifdef DEPLOY
String currentDocument(L"./doc/");
String configFile(L"./speedreader.ini");
String sampleDocument(L"./sample/");
#else
String currentDocument(L"../Speedreader/speedreader/doc/");
String configFile(L"../Speedreader/speedreader.ini");
String sampleDocument(L"../Speedreader/speedreader/sample/");
#endif

std::wstring displayOrder(L"LTR"); // Right to left(RTL): 0 LTR: 1
double joystickPointerSpeed = 1.0;
int drawingXOffset = 100;
double viewingPage = 0;
int displayMode = 1;
int autoplaySpeed = 0;
int debugTexureLoadingBenchmark;
int numPages;

void loadPDFConfig() {
	String filename = Format(currentDocument, L"config.ini");
	INIReader ini(filename);
	if (!ini)
	{
		INIWriter default_ini(filename);
		default_ini.write(L"displayOrder", L"LTR");
		ini = INIReader(filename);
	}
	displayOrder = ini.getOr<std::wstring>(L"displayOrder", L"LTR");
}

void updateConfig(INIReader	config) {
	config.reload();
	joystickPointerSpeed = config.getOr<double>(L"Controller.PointerSpeed", 1.0);
	drawingXOffset = config.getOr<int>(L"Drawing.XOffset", 100);
	debugTexureLoadingBenchmark = config.getOr<int>(L"Debug.TextureLoadingBenchmark", 0);
}

void loadNewDocument(String path) {
	currentDocument = path;
	Profiler::EnableWarning(false); // 再読み込み時のテクスチャ破棄で警告されるので読み終わるまでdisable
	loadPDFConfig();
	viewingPage = 0;
	displayMode = 1;
	loader::loadPDF(currentDocument);
	numPages = loader::numPages;
}

void convertToDDS() {
	// TODO: make menu to call this
	for (auto i : step(100)) {
		Image(
			Format(L"C:/Users/nishio/Desktop/images/pages_{:04d}.png"_fmt, i + 1)
		).save(
			Format(L"C:/Users/nishio/Desktop/images/pages_{:04d}.dds"_fmt, i + 1)
		);
	}
}

void Main()
{
	INIReader config(configFile);
	updateConfig(config);

	const Font font(30);
	const Font font10(10);

	loadPDFConfig();

	Window::SetTitle(L"Speedreader");
	Window::Resize(1300, 700);
	Window::ToUpperLeft();
	Window::SetStyle(WindowStyle::Sizeable);

	Cursor::SetPos(0, 0);
	Vec2 pos = Mouse::Pos();

	Stopwatch stopwatch(true);
	loader::loadPDF(currentDocument);
	numPages = loader::numPages;

	// ESCでWindowを閉じない
	System::SetExitEvent(WindowEvent::CloseButton);

	while (System::Update())
	{
		double invFPS = stopwatch.ms();
		stopwatch.restart();
		if (config.hasChanged()) updateConfig(config);

		if (Dragdrop::HasItems())
		{
			const Array<FilePath> items = Dragdrop::GetFilePaths();
			loadNewDocument(items[0]);
		}

		// まだ読み終わってなければ順次ロード
		loader::keepLoading();

		auto controller = XInput(0);

		controller.setLeftTriggerDeadZone();
		controller.setRightTriggerDeadZone();
		controller.setLeftThumbDeadZone();
		controller.setRightThumbDeadZone();

		pos += Vec2(
			controller.leftThumbX * joystickPointerSpeed * invFPS,
			-controller.leftThumbY * joystickPointerSpeed * invFPS);
		//pos += Mouse::Delta();  // マウスも併用する場合はジョイスティックでの移動差分をマウスの入力と勘違いするので用修正
		if (pos.x < 0) pos.x = 0;
		if (pos.y < 0) pos.y = 0;
		if (pos.x > Window::Width()) pos.x = Window::Width();
		if (pos.y > Window::Height()) pos.y = Window::Height();

		viewingPage -= pow(controller.leftTrigger, 2);
		viewingPage += pow(controller.rightTrigger, 2);

		viewingPage += controller.rightThumbY / 5;  // slow

		// キーでのパラパラめくり// 早送り巻き戻しメタファー
		if (Input::KeyRight.clicked) {
			if (autoplaySpeed > 0) {
				autoplaySpeed *= 2;
			}
			else if (autoplaySpeed == 0) {
				autoplaySpeed = 1;
			}
			else {
				autoplaySpeed = 0;
			}
		}
		if (Input::KeyLeft.clicked) {
			if (autoplaySpeed < 0) {
				autoplaySpeed *= 2;
			}
			else if (autoplaySpeed == 0) {
				autoplaySpeed = -1;
			}
			else {
				autoplaySpeed = 0;
			}
		}
		if (autoplaySpeed) {
			viewingPage += autoplaySpeed * invFPS / 1000;
			font10(L"自動再生: ", autoplaySpeed).draw(0, 0);
		}

		if (viewingPage < 0) viewingPage = 0;
		if (viewingPage > numPages - 1) viewingPage = numPages - 1;
		if (displayMode == 0) {
			if (controller.buttonA.clicked || Input::KeyDown.clicked) viewingPage += 0.5;
			if (controller.buttonB.clicked || Input::KeyUp.clicked) viewingPage -= 0.5;
		}
		else {
			if (controller.buttonA.clicked || Input::KeyDown.clicked) {
				viewingPage++;
				autoplaySpeed = 0;
			}
			if (controller.buttonB.clicked || Input::KeyUp.clicked) {
				viewingPage--;
				autoplaySpeed = 0;
			}
		}
		// 最初・最後のページで前後に移動した時に反対側に飛ぶべきかどうか、今disabled
		//if (page < 0) page += numPages;
		//if (page > numPages - 1) page = 0;
		if (viewingPage < 0) viewingPage = 0;
		if (viewingPage > numPages - 1) viewingPage = numPages - 1;

		int ipage = static_cast<int>(viewingPage) % numPages;

		if (controller.buttonLB.clicked || Input::KeyZ.clicked) {
			displayMode = (displayMode - 1);
			if (displayMode < 0) displayMode = 0;
		}
		if (controller.buttonRB.clicked || Input::KeyC.clicked) {
			displayMode = (displayMode + 1);
		}

		Texture t = loader::getPage(ipage);
		double h = static_cast<double>(t.height);
		double w = static_cast<double>(t.width);
		const int screenHeight = 640;
		double pageHeight = screenHeight, pageWidth = w / h * pageHeight;

		int horizontalMultiplier = 2; // 見開きにするなら2、しないなら1
		if (h < w) horizontalMultiplier = 1;

		// draw progress bar
		int progressBarWidth = static_cast<int>(pageWidth * horizontalMultiplier);
		Rect(drawingXOffset, screenHeight + 10,
			progressBarWidth, 20).draw(Color(200));
		Rect(drawingXOffset, screenHeight + 12,
			progressBarWidth * (ipage + 1) / numPages, 16).draw(Color(100));
		font10(ipage + 1).draw(drawingXOffset, screenHeight + 12);

		const int32 w2 = font10(numPages).region().w;
		font10(numPages).draw(drawingXOffset + progressBarWidth - w2, screenHeight + 12);

		if (displayMode == 0) {
			// Zoom-in mode
			int scale = 2;
			if (static_cast<int>(viewingPage * 2) % 2 == 0) {
				t.resize(pageWidth * scale, pageHeight * scale).draw(drawingXOffset, 0);
			}
			else {
				t(0, h / 2, w, h / 2).resize(pageWidth * scale, pageHeight).draw(drawingXOffset, 0);
			}
		}
		else if(displayMode > 0) {
			int numPageHorizontal = displayMode * horizontalMultiplier;
			int numPageVertical = displayMode;
			// Tile mode
			if (displayOrder == L"LTR") {
				pageHeight /= numPageVertical;
				pageWidth /= numPageVertical;
				for (int y = 0; y < numPageVertical; y++) {
					for (int x = 0; x < numPageHorizontal; x++) {
						int i = ipage + y * numPageHorizontal + x;
						loader::getPage(i)
							.resize(pageWidth, pageHeight)
							.draw(drawingXOffset + pageWidth * x, pageHeight * y);

					}
				}
			}
			else {
				pageHeight /= numPageVertical;
				pageWidth /= numPageVertical;
				for (int y = 0; y < numPageVertical; y++) {
					for (int x = 0; x < numPageHorizontal; x++) {
						int i = ipage + y * numPageHorizontal + x;
						loader::getPage(i)
							.resize(pageWidth, pageHeight)
							.draw(drawingXOffset + pageWidth * (numPageHorizontal - x - 1), pageHeight * y);

					}
				}
			}

			// Xボタンでそのページを通常表示
			if (controller.buttonX.clicked || Input::MouseL.clicked) {
				if (Input::MouseL.clicked) {
					pos = Mouse::Pos();
				}
				int x = static_cast<int>((pos.x - drawingXOffset) / pageWidth);
				if (displayOrder != L"LTR") {
					x = numPageHorizontal - x - 1;
				}
				int y = static_cast<int>(pos.y / pageHeight);
				viewingPage = ipage + x + y * numPageHorizontal;
				displayMode = 1;
				Cursor::SetPos(0, 0);
				pos = { 0, 0 };
			}
		}

		// デモ用
		if (controller.buttonY.clicked || Input::KeyY.clicked) {
			loadNewDocument(sampleDocument);
		}

		// カーソル表示
		Circle(pos, 10).draw({ 255, 255, 0, 127 });
	}
}
<|endoftext|>


<commit_before>/*******************************
Copyright (c) 2016-2022 Grégoire Angerand

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 "memory.h"

#include <y/utils/memory.h>

#include <atomic>
#include <cstdlib>

namespace editor {
namespace memory {

std::atomic<usize> live_allocs = 0;
std::atomic<u64> total_allocs= 0;

usize live_allocations() {
    return live_allocs;
}

u64 total_allocations() {
    return total_allocs;
}

static void* alloc_internal(usize size, usize alignment = max_alignment) {
    size = size ? size : 1;

    auto try_alloc = [=] {
        #ifdef Y_OS_WIN
            return _aligned_malloc(size, alignment);
        #else
            return std::aligned_alloc(alignment, size);
        #endif
    };

    void* ptr = nullptr;
    while((ptr = try_alloc()) == nullptr) {
        std::new_handler nh = std::get_new_handler();
        if(!nh) {
            throw std::bad_alloc{};
        }
        nh();
    }

    ++total_allocs;
    ++live_allocs;

    y_profile_alloc(ptr, size);

    return ptr;

}

static void free_internal(void* ptr) {
    if(ptr) {
        --live_allocs;
    }

    y_profile_free(ptr);

#ifdef Y_OS_WIN
    _aligned_free(ptr);
#else
    std::free(ptr);
#endif
}
}
}

void* operator new(std::size_t size) {
    return editor::memory::alloc_internal(size);
}

void* operator new(std::size_t size, std::align_val_t al) {
    return editor::memory::alloc_internal(size, std::size_t(al));
}

void operator delete(void* ptr) noexcept {
    editor::memory::free_internal(ptr);
}

void operator delete(void* ptr, std::align_val_t) noexcept {
    editor::memory::free_internal(ptr);
}

<commit_msg>debug allocator fix<commit_after>/*******************************
Copyright (c) 2016-2022 Grégoire Angerand

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 "memory.h"

#include <y/utils/memory.h>

#include <atomic>
#include <cstdlib>

namespace editor {
namespace memory {

std::atomic<usize> live_allocs = 0;
std::atomic<u64> total_allocs= 0;

usize live_allocations() {
    return live_allocs;
}

u64 total_allocations() {
    return total_allocs;
}

static void* alloc_internal(usize size, usize alignment = max_alignment) {
    if(!size) {
        return nullptr;
    }

    auto try_alloc = [=] {
        #ifdef Y_OS_WIN
            return _aligned_malloc(size, alignment);
        #else
            return std::aligned_alloc(alignment, size);
        #endif
    };

    void* ptr = nullptr;
    while((ptr = try_alloc()) == nullptr) {
        std::new_handler nh = std::get_new_handler();
        if(!nh) {
            throw std::bad_alloc{};
        }
        nh();
    }

    ++total_allocs;
    ++live_allocs;

    y_profile_alloc(ptr, size);

    return ptr;

}

static void free_internal(void* ptr) {
    if(ptr) {
        --live_allocs;
    }

    y_profile_free(ptr);

#ifdef Y_OS_WIN
    _aligned_free(ptr);
#else
    std::free(ptr);
#endif
}
}
}

void* operator new(std::size_t size) {
    return editor::memory::alloc_internal(size);
}

void* operator new(std::size_t size, std::align_val_t al) {
    return editor::memory::alloc_internal(size, std::size_t(al));
}

void operator delete(void* ptr) noexcept {
    editor::memory::free_internal(ptr);
}

void operator delete(void* ptr, std::align_val_t) noexcept {
    editor::memory::free_internal(ptr);
}

<|endoftext|>


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

#ifndef _SIRIKATA_CORE_UTIL_INSTANCE_METHOD_NOT_REENTRANT_HPP_
#define _SIRIKATA_CORE_UTIL_INSTANCE_METHOD_NOT_REENTRANT_HPP_

#include <sirikata/core/util/Platform.hpp>

namespace Sirikata {

/** A utility class that lets you specify that a method isn't reentrant and
 *  validate in debug mode that you're not calling it recursively. It checks
 *  reentrancy per instance, i.e. it is expected that it is reentrant for
 *  different instances (e.g. you might have class A and have instance A1::foo
 *  call instance A2::foo and be fine, but A1::foo eventually hitting A1::foo
 *  again on the same stack is not ok).
 *
 *  This might seem simple, but in cases where you are using listeners or
 *  generic callbacks it might be hard to verify statically that you don't
 *  accidentally have recursion. This lets you just annotate a bit of code to
 *  make sure it remains true. In release mode all checks are disabled and the
 *  class uses no space.
 *
 *  Note that you should use one of these *per non-reentrant method*. If you
 *  have A::foo and A::bar, you need one of these for each one.
 *
 *  To use the class, you want a declaraction like
 *    InstanceMethodNotReentrant mFooNotRentrant;
 *  in your class and then create a token in the method, e.g.
 *    void A::foo() {
 *      InstanceMethodNotReentrant::Token not_reentrant(mFooNotRentrant);
 *    }
 *
 */
class SIRIKATA_EXPORT InstanceMethodNotReentrant {
public:
    InstanceMethodNotReentrant()
        : count(0)
    {}

    class Token {
    public:
        Token(InstanceMethodNotReentrant& par)
#if SIRIKATA_DEBUG
         : parent(par)
#endif
        {
#if SIRIKATA_DEBUG
            assert(parent.count == 0);
            parent.count++;
#endif
        }
        ~Token() {
#if SIRIKATA_DEBUG
            parent.count--;
#endif
        }

    private:
#if SIRIKATA_DEBUG
        InstanceMethodNotReentrant& parent;
#endif
    };

#if SIRIKATA_DEBUG
    char count;
#endif
}; // class InstanceMethodNotReentrant

} // namespace Sirikata

#endif //_SIRIKATA_CORE_UTIL_INSTANCE_METHOD_NOT_REENTRANT_HPP_
<commit_msg>Fix missing ifdef in InstanceMethodNotReentrant.<commit_after>// Copyright (c) 2012 Sirikata Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.

#ifndef _SIRIKATA_CORE_UTIL_INSTANCE_METHOD_NOT_REENTRANT_HPP_
#define _SIRIKATA_CORE_UTIL_INSTANCE_METHOD_NOT_REENTRANT_HPP_

#include <sirikata/core/util/Platform.hpp>

namespace Sirikata {

/** A utility class that lets you specify that a method isn't reentrant and
 *  validate in debug mode that you're not calling it recursively. It checks
 *  reentrancy per instance, i.e. it is expected that it is reentrant for
 *  different instances (e.g. you might have class A and have instance A1::foo
 *  call instance A2::foo and be fine, but A1::foo eventually hitting A1::foo
 *  again on the same stack is not ok).
 *
 *  This might seem simple, but in cases where you are using listeners or
 *  generic callbacks it might be hard to verify statically that you don't
 *  accidentally have recursion. This lets you just annotate a bit of code to
 *  make sure it remains true. In release mode all checks are disabled and the
 *  class uses no space.
 *
 *  Note that you should use one of these *per non-reentrant method*. If you
 *  have A::foo and A::bar, you need one of these for each one.
 *
 *  To use the class, you want a declaraction like
 *    InstanceMethodNotReentrant mFooNotRentrant;
 *  in your class and then create a token in the method, e.g.
 *    void A::foo() {
 *      InstanceMethodNotReentrant::Token not_reentrant(mFooNotRentrant);
 *    }
 *
 */
class SIRIKATA_EXPORT InstanceMethodNotReentrant {
public:
    InstanceMethodNotReentrant()
#if SIRIKATA_DEBUG
        : count(0)
#endif
    {}

    class Token {
    public:
        Token(InstanceMethodNotReentrant& par)
#if SIRIKATA_DEBUG
         : parent(par)
#endif
        {
#if SIRIKATA_DEBUG
            assert(parent.count == 0);
            parent.count++;
#endif
        }
        ~Token() {
#if SIRIKATA_DEBUG
            parent.count--;
#endif
        }

    private:
#if SIRIKATA_DEBUG
        InstanceMethodNotReentrant& parent;
#endif
    };

#if SIRIKATA_DEBUG
    char count;
#endif
}; // class InstanceMethodNotReentrant

} // namespace Sirikata

#endif //_SIRIKATA_CORE_UTIL_INSTANCE_METHOD_NOT_REENTRANT_HPP_
<|endoftext|>


<commit_before>#include "TFile.h"
#include "TH1F.h"
#include "TTreeReader.h"
#include "TTreeReaderValue.h"

#ifdef __CINT__
#pragma link C++ class TTreeReaderValue<Float_t>+;
#endif

void TreeReaderSimple() {
	TH1F *myHistogram = new TH1F ("h1","ntuple",100,-4,4);

	TFile::Open("hsimple.root");
	TTreeReader myHSimpleReader ("ntuple");

	TTreeReaderValue<Float_t> myPx (myHSimpleReader, "px");
	TTreeReaderValue<Float_t> myPy (myHSimpleReader, "py");

	for (int i = 0; myHSimpleReader.SetNextEntry(); ++i){
		myHistogram->Fill(*myPx + *myPy);
	}

	myHistogram->Draw();
}
<commit_msg>Changed for loop to while loop, as the counter was not used<commit_after>#include "TFile.h"
#include "TH1F.h"
#include "TTreeReader.h"
#include "TTreeReaderValue.h"

#ifdef __CINT__
#pragma link C++ class TTreeReaderValue<Float_t>+;
#endif

void TreeReaderSimple() {
	TH1F *myHistogram = new TH1F ("h1","ntuple",100,-4,4);

	TFile::Open("hsimple.root");
	TTreeReader myHSimpleReader ("ntuple");

	TTreeReaderValue<Float_t> myPx (myHSimpleReader, "px");
	TTreeReaderValue<Float_t> myPy (myHSimpleReader, "py");

	while (myHSimpleReader.SetNextEntry()){
		myHistogram->Fill(*myPx + *myPy);
	}

	myHistogram->Draw();
}
<|endoftext|>


<commit_before>//===-- BrainF.cpp - BrainF compiler example ----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===--------------------------------------------------------------------===//
//
// This class compiles the BrainF language into LLVM assembly.
//
// The BrainF language has 8 commands:
// Command   Equivalent C    Action
// -------   ------------    ------
// ,         *h=getchar();   Read a character from stdin, 255 on EOF
// .         putchar(*h);    Write a character to stdout
// -         --*h;           Decrement tape
// +         ++*h;           Increment tape
// <         --h;            Move head left
// >         ++h;            Move head right
// [         while(*h) {     Start loop
// ]         }               End loop
//
//===--------------------------------------------------------------------===//

#include "BrainF.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/ADT/STLExtras.h"
#include <iostream>
using namespace llvm;

//Set the constants for naming
const char *BrainF::tapereg = "tape";
const char *BrainF::headreg = "head";
const char *BrainF::label   = "brainf";
const char *BrainF::testreg = "test";

Module *BrainF::parse(std::istream *in1, int mem, CompileFlags cf,
                      LLVMContext& Context) {
  in       = in1;
  memtotal = mem;
  comflag  = cf;

  header(Context);
  readloop(0, 0, 0, Context);
  delete builder;
  return module;
}

void BrainF::header(LLVMContext& C) {
  module = new Module("BrainF", C);

  //Function prototypes

  //declare void @llvm.memset.p0i8.i32(i8 *, i8, i32, i32, i1)
  const Type *Tys[] = { Type::getInt8PtrTy(C), Type::getInt32Ty(C) };
  Function *memset_func = Intrinsic::getDeclaration(module, Intrinsic::memset,
                                                    Tys, 2);

  //declare i32 @getchar()
  getchar_func = cast<Function>(module->
    getOrInsertFunction("getchar", IntegerType::getInt32Ty(C), NULL));

  //declare i32 @putchar(i32)
  putchar_func = cast<Function>(module->
    getOrInsertFunction("putchar", IntegerType::getInt32Ty(C),
                        IntegerType::getInt32Ty(C), NULL));

  //Function header

  //define void @brainf()
  brainf_func = cast<Function>(module->
    getOrInsertFunction("brainf", Type::getVoidTy(C), NULL));

  builder = new IRBuilder<>(BasicBlock::Create(C, label, brainf_func));

  //%arr = malloc i8, i32 %d
  ConstantInt *val_mem = ConstantInt::get(C, APInt(32, memtotal));
  BasicBlock* BB = builder->GetInsertBlock();
  const Type* IntPtrTy = IntegerType::getInt32Ty(C);
  const Type* Int8Ty = IntegerType::getInt8Ty(C);
  Constant* allocsize = ConstantExpr::getSizeOf(Int8Ty);
  allocsize = ConstantExpr::getTruncOrBitCast(allocsize, IntPtrTy);
  ptr_arr = CallInst::CreateMalloc(BB, IntPtrTy, Int8Ty, allocsize, val_mem,
                                   NULL, "arr");
  BB->getInstList().push_back(cast<Instruction>(ptr_arr));

  //call void @llvm.memset.p0i8.i32(i8 *%arr, i8 0, i32 %d, i32 1, i1 0)
  {
    Value *memset_params[] = {
      ptr_arr,
      ConstantInt::get(C, APInt(8, 0)),
      val_mem,
      ConstantInt::get(C, APInt(32, 1)),
      ConstantInt::get(C, APInt(1, 0))
    };

    CallInst *memset_call = builder->
      CreateCall(memset_func, memset_params, array_endof(memset_params));
    memset_call->setTailCall(false);
  }

  //%arrmax = getelementptr i8 *%arr, i32 %d
  if (comflag & flag_arraybounds) {
    ptr_arrmax = builder->
      CreateGEP(ptr_arr, ConstantInt::get(C, APInt(32, memtotal)), "arrmax");
  }

  //%head.%d = getelementptr i8 *%arr, i32 %d
  curhead = builder->CreateGEP(ptr_arr,
                               ConstantInt::get(C, APInt(32, memtotal/2)),
                               headreg);

  //Function footer

  //brainf.end:
  endbb = BasicBlock::Create(C, label, brainf_func);

  //call free(i8 *%arr)
  endbb->getInstList().push_back(CallInst::CreateFree(ptr_arr, endbb));

  //ret void
  ReturnInst::Create(C, endbb);

  //Error block for array out of bounds
  if (comflag & flag_arraybounds)
  {
    //@aberrormsg = internal constant [%d x i8] c"\00"
    Constant *msg_0 =
      ConstantArray::get(C, "Error: The head has left the tape.", true);

    GlobalVariable *aberrormsg = new GlobalVariable(
      *module,
      msg_0->getType(),
      true,
      GlobalValue::InternalLinkage,
      msg_0,
      "aberrormsg");

    //declare i32 @puts(i8 *)
    Function *puts_func = cast<Function>(module->
      getOrInsertFunction("puts", IntegerType::getInt32Ty(C),
                      PointerType::getUnqual(IntegerType::getInt8Ty(C)), NULL));

    //brainf.aberror:
    aberrorbb = BasicBlock::Create(C, label, brainf_func);

    //call i32 @puts(i8 *getelementptr([%d x i8] *@aberrormsg, i32 0, i32 0))
    {
      Constant *zero_32 = Constant::getNullValue(IntegerType::getInt32Ty(C));

      Constant *gep_params[] = {
        zero_32,
        zero_32
      };

      Constant *msgptr = ConstantExpr::
        getGetElementPtr(aberrormsg, gep_params,
                         array_lengthof(gep_params));

      Value *puts_params[] = {
        msgptr
      };

      CallInst *puts_call =
        CallInst::Create(puts_func,
                         puts_params, array_endof(puts_params),
                         "", aberrorbb);
      puts_call->setTailCall(false);
    }

    //br label %brainf.end
    BranchInst::Create(endbb, aberrorbb);
  }
}

void BrainF::readloop(PHINode *phi, BasicBlock *oldbb, BasicBlock *testbb,
                      LLVMContext &C) {
  Symbol cursym = SYM_NONE;
  int curvalue = 0;
  Symbol nextsym = SYM_NONE;
  int nextvalue = 0;
  char c;
  int loop;
  int direction;

  while(cursym != SYM_EOF && cursym != SYM_ENDLOOP) {
    // Write out commands
    switch(cursym) {
      case SYM_NONE:
        // Do nothing
        break;

      case SYM_READ:
        {
          //%tape.%d = call i32 @getchar()
          CallInst *getchar_call = builder->CreateCall(getchar_func, tapereg);
          getchar_call->setTailCall(false);
          Value *tape_0 = getchar_call;

          //%tape.%d = trunc i32 %tape.%d to i8
          Value *tape_1 = builder->
            CreateTrunc(tape_0, IntegerType::getInt8Ty(C), tapereg);

          //store i8 %tape.%d, i8 *%head.%d
          builder->CreateStore(tape_1, curhead);
        }
        break;

      case SYM_WRITE:
        {
          //%tape.%d = load i8 *%head.%d
          LoadInst *tape_0 = builder->CreateLoad(curhead, tapereg);

          //%tape.%d = sext i8 %tape.%d to i32
          Value *tape_1 = builder->
            CreateSExt(tape_0, IntegerType::getInt32Ty(C), tapereg);

          //call i32 @putchar(i32 %tape.%d)
          Value *putchar_params[] = {
            tape_1
          };
          CallInst *putchar_call = builder->
            CreateCall(putchar_func,
                       putchar_params, array_endof(putchar_params));
          putchar_call->setTailCall(false);
        }
        break;

      case SYM_MOVE:
        {
          //%head.%d = getelementptr i8 *%head.%d, i32 %d
          curhead = builder->
            CreateGEP(curhead, ConstantInt::get(C, APInt(32, curvalue)),
                      headreg);

          //Error block for array out of bounds
          if (comflag & flag_arraybounds)
          {
            //%test.%d = icmp uge i8 *%head.%d, %arrmax
            Value *test_0 = builder->
              CreateICmpUGE(curhead, ptr_arrmax, testreg);

            //%test.%d = icmp ult i8 *%head.%d, %arr
            Value *test_1 = builder->
              CreateICmpULT(curhead, ptr_arr, testreg);

            //%test.%d = or i1 %test.%d, %test.%d
            Value *test_2 = builder->
              CreateOr(test_0, test_1, testreg);

            //br i1 %test.%d, label %main.%d, label %main.%d
            BasicBlock *nextbb = BasicBlock::Create(C, label, brainf_func);
            builder->CreateCondBr(test_2, aberrorbb, nextbb);

            //main.%d:
            builder->SetInsertPoint(nextbb);
          }
        }
        break;

      case SYM_CHANGE:
        {
          //%tape.%d = load i8 *%head.%d
          LoadInst *tape_0 = builder->CreateLoad(curhead, tapereg);

          //%tape.%d = add i8 %tape.%d, %d
          Value *tape_1 = builder->
            CreateAdd(tape_0, ConstantInt::get(C, APInt(8, curvalue)), tapereg);

          //store i8 %tape.%d, i8 *%head.%d\n"
          builder->CreateStore(tape_1, curhead);
        }
        break;

      case SYM_LOOP:
        {
          //br label %main.%d
          BasicBlock *testbb = BasicBlock::Create(C, label, brainf_func);
          builder->CreateBr(testbb);

          //main.%d:
          BasicBlock *bb_0 = builder->GetInsertBlock();
          BasicBlock *bb_1 = BasicBlock::Create(C, label, brainf_func);
          builder->SetInsertPoint(bb_1);

          // Make part of PHI instruction now, wait until end of loop to finish
          PHINode *phi_0 =
            PHINode::Create(PointerType::getUnqual(IntegerType::getInt8Ty(C)),
                            2, headreg, testbb);
          phi_0->addIncoming(curhead, bb_0);
          curhead = phi_0;

          readloop(phi_0, bb_1, testbb, C);
        }
        break;

      default:
        std::cerr << "Error: Unknown symbol.\n";
        abort();
        break;
    }

    cursym = nextsym;
    curvalue = nextvalue;
    nextsym = SYM_NONE;

    // Reading stdin loop
    loop = (cursym == SYM_NONE)
        || (cursym == SYM_MOVE)
        || (cursym == SYM_CHANGE);
    while(loop) {
      *in>>c;
      if (in->eof()) {
        if (cursym == SYM_NONE) {
          cursym = SYM_EOF;
        } else {
          nextsym = SYM_EOF;
        }
        loop = 0;
      } else {
        direction = 1;
        switch(c) {
          case '-':
            direction = -1;
            // Fall through

          case '+':
            if (cursym == SYM_CHANGE) {
              curvalue += direction;
              // loop = 1
            } else {
              if (cursym == SYM_NONE) {
                cursym = SYM_CHANGE;
                curvalue = direction;
                // loop = 1
              } else {
                nextsym = SYM_CHANGE;
                nextvalue = direction;
                loop = 0;
              }
            }
            break;

          case '<':
            direction = -1;
            // Fall through

          case '>':
            if (cursym == SYM_MOVE) {
              curvalue += direction;
              // loop = 1
            } else {
              if (cursym == SYM_NONE) {
                cursym = SYM_MOVE;
                curvalue = direction;
                // loop = 1
              } else {
                nextsym = SYM_MOVE;
                nextvalue = direction;
                loop = 0;
              }
            }
            break;

          case ',':
            if (cursym == SYM_NONE) {
              cursym = SYM_READ;
            } else {
              nextsym = SYM_READ;
            }
            loop = 0;
            break;

          case '.':
            if (cursym == SYM_NONE) {
              cursym = SYM_WRITE;
            } else {
              nextsym = SYM_WRITE;
            }
            loop = 0;
            break;

          case '[':
            if (cursym == SYM_NONE) {
              cursym = SYM_LOOP;
            } else {
              nextsym = SYM_LOOP;
            }
            loop = 0;
            break;

          case ']':
            if (cursym == SYM_NONE) {
              cursym = SYM_ENDLOOP;
            } else {
              nextsym = SYM_ENDLOOP;
            }
            loop = 0;
            break;

          // Ignore other characters
          default:
            break;
        }
      }
    }
  }

  if (cursym == SYM_ENDLOOP) {
    if (!phi) {
      std::cerr << "Error: Extra ']'\n";
      abort();
    }

    // Write loop test
    {
      //br label %main.%d
      builder->CreateBr(testbb);

      //main.%d:

      //%head.%d = phi i8 *[%head.%d, %main.%d], [%head.%d, %main.%d]
      //Finish phi made at beginning of loop
      phi->addIncoming(curhead, builder->GetInsertBlock());
      Value *head_0 = phi;

      //%tape.%d = load i8 *%head.%d
      LoadInst *tape_0 = new LoadInst(head_0, tapereg, testbb);

      //%test.%d = icmp eq i8 %tape.%d, 0
      ICmpInst *test_0 = new ICmpInst(*testbb, ICmpInst::ICMP_EQ, tape_0,
                                    ConstantInt::get(C, APInt(8, 0)), testreg);

      //br i1 %test.%d, label %main.%d, label %main.%d
      BasicBlock *bb_0 = BasicBlock::Create(C, label, brainf_func);
      BranchInst::Create(bb_0, oldbb, test_0, testbb);

      //main.%d:
      builder->SetInsertPoint(bb_0);

      //%head.%d = phi i8 *[%head.%d, %main.%d]
      PHINode *phi_1 = builder->
        CreatePHI(PointerType::getUnqual(IntegerType::getInt8Ty(C)), 1,
                  headreg);
      phi_1->addIncoming(head_0, testbb);
      curhead = phi_1;
    }

    return;
  }

  //End of the program, so go to return block
  builder->CreateBr(endbb);

  if (phi) {
    std::cerr << "Error: Missing ']'\n";
    abort();
  }
}
<commit_msg>Remove the const from Type after of Jay deconstify work.<commit_after>//===-- BrainF.cpp - BrainF compiler example ----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===--------------------------------------------------------------------===//
//
// This class compiles the BrainF language into LLVM assembly.
//
// The BrainF language has 8 commands:
// Command   Equivalent C    Action
// -------   ------------    ------
// ,         *h=getchar();   Read a character from stdin, 255 on EOF
// .         putchar(*h);    Write a character to stdout
// -         --*h;           Decrement tape
// +         ++*h;           Increment tape
// <         --h;            Move head left
// >         ++h;            Move head right
// [         while(*h) {     Start loop
// ]         }               End loop
//
//===--------------------------------------------------------------------===//

#include "BrainF.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/ADT/STLExtras.h"
#include <iostream>
using namespace llvm;

//Set the constants for naming
const char *BrainF::tapereg = "tape";
const char *BrainF::headreg = "head";
const char *BrainF::label   = "brainf";
const char *BrainF::testreg = "test";

Module *BrainF::parse(std::istream *in1, int mem, CompileFlags cf,
                      LLVMContext& Context) {
  in       = in1;
  memtotal = mem;
  comflag  = cf;

  header(Context);
  readloop(0, 0, 0, Context);
  delete builder;
  return module;
}

void BrainF::header(LLVMContext& C) {
  module = new Module("BrainF", C);

  //Function prototypes

  //declare void @llvm.memset.p0i8.i32(i8 *, i8, i32, i32, i1)
  Type *Tys[] = { Type::getInt8PtrTy(C), Type::getInt32Ty(C) };
  Function *memset_func = Intrinsic::getDeclaration(module, Intrinsic::memset,
                                                    Tys, 2);

  //declare i32 @getchar()
  getchar_func = cast<Function>(module->
    getOrInsertFunction("getchar", IntegerType::getInt32Ty(C), NULL));

  //declare i32 @putchar(i32)
  putchar_func = cast<Function>(module->
    getOrInsertFunction("putchar", IntegerType::getInt32Ty(C),
                        IntegerType::getInt32Ty(C), NULL));

  //Function header

  //define void @brainf()
  brainf_func = cast<Function>(module->
    getOrInsertFunction("brainf", Type::getVoidTy(C), NULL));

  builder = new IRBuilder<>(BasicBlock::Create(C, label, brainf_func));

  //%arr = malloc i8, i32 %d
  ConstantInt *val_mem = ConstantInt::get(C, APInt(32, memtotal));
  BasicBlock* BB = builder->GetInsertBlock();
  const Type* IntPtrTy = IntegerType::getInt32Ty(C);
  const Type* Int8Ty = IntegerType::getInt8Ty(C);
  Constant* allocsize = ConstantExpr::getSizeOf(Int8Ty);
  allocsize = ConstantExpr::getTruncOrBitCast(allocsize, IntPtrTy);
  ptr_arr = CallInst::CreateMalloc(BB, IntPtrTy, Int8Ty, allocsize, val_mem,
                                   NULL, "arr");
  BB->getInstList().push_back(cast<Instruction>(ptr_arr));

  //call void @llvm.memset.p0i8.i32(i8 *%arr, i8 0, i32 %d, i32 1, i1 0)
  {
    Value *memset_params[] = {
      ptr_arr,
      ConstantInt::get(C, APInt(8, 0)),
      val_mem,
      ConstantInt::get(C, APInt(32, 1)),
      ConstantInt::get(C, APInt(1, 0))
    };

    CallInst *memset_call = builder->
      CreateCall(memset_func, memset_params, array_endof(memset_params));
    memset_call->setTailCall(false);
  }

  //%arrmax = getelementptr i8 *%arr, i32 %d
  if (comflag & flag_arraybounds) {
    ptr_arrmax = builder->
      CreateGEP(ptr_arr, ConstantInt::get(C, APInt(32, memtotal)), "arrmax");
  }

  //%head.%d = getelementptr i8 *%arr, i32 %d
  curhead = builder->CreateGEP(ptr_arr,
                               ConstantInt::get(C, APInt(32, memtotal/2)),
                               headreg);

  //Function footer

  //brainf.end:
  endbb = BasicBlock::Create(C, label, brainf_func);

  //call free(i8 *%arr)
  endbb->getInstList().push_back(CallInst::CreateFree(ptr_arr, endbb));

  //ret void
  ReturnInst::Create(C, endbb);

  //Error block for array out of bounds
  if (comflag & flag_arraybounds)
  {
    //@aberrormsg = internal constant [%d x i8] c"\00"
    Constant *msg_0 =
      ConstantArray::get(C, "Error: The head has left the tape.", true);

    GlobalVariable *aberrormsg = new GlobalVariable(
      *module,
      msg_0->getType(),
      true,
      GlobalValue::InternalLinkage,
      msg_0,
      "aberrormsg");

    //declare i32 @puts(i8 *)
    Function *puts_func = cast<Function>(module->
      getOrInsertFunction("puts", IntegerType::getInt32Ty(C),
                      PointerType::getUnqual(IntegerType::getInt8Ty(C)), NULL));

    //brainf.aberror:
    aberrorbb = BasicBlock::Create(C, label, brainf_func);

    //call i32 @puts(i8 *getelementptr([%d x i8] *@aberrormsg, i32 0, i32 0))
    {
      Constant *zero_32 = Constant::getNullValue(IntegerType::getInt32Ty(C));

      Constant *gep_params[] = {
        zero_32,
        zero_32
      };

      Constant *msgptr = ConstantExpr::
        getGetElementPtr(aberrormsg, gep_params,
                         array_lengthof(gep_params));

      Value *puts_params[] = {
        msgptr
      };

      CallInst *puts_call =
        CallInst::Create(puts_func,
                         puts_params, array_endof(puts_params),
                         "", aberrorbb);
      puts_call->setTailCall(false);
    }

    //br label %brainf.end
    BranchInst::Create(endbb, aberrorbb);
  }
}

void BrainF::readloop(PHINode *phi, BasicBlock *oldbb, BasicBlock *testbb,
                      LLVMContext &C) {
  Symbol cursym = SYM_NONE;
  int curvalue = 0;
  Symbol nextsym = SYM_NONE;
  int nextvalue = 0;
  char c;
  int loop;
  int direction;

  while(cursym != SYM_EOF && cursym != SYM_ENDLOOP) {
    // Write out commands
    switch(cursym) {
      case SYM_NONE:
        // Do nothing
        break;

      case SYM_READ:
        {
          //%tape.%d = call i32 @getchar()
          CallInst *getchar_call = builder->CreateCall(getchar_func, tapereg);
          getchar_call->setTailCall(false);
          Value *tape_0 = getchar_call;

          //%tape.%d = trunc i32 %tape.%d to i8
          Value *tape_1 = builder->
            CreateTrunc(tape_0, IntegerType::getInt8Ty(C), tapereg);

          //store i8 %tape.%d, i8 *%head.%d
          builder->CreateStore(tape_1, curhead);
        }
        break;

      case SYM_WRITE:
        {
          //%tape.%d = load i8 *%head.%d
          LoadInst *tape_0 = builder->CreateLoad(curhead, tapereg);

          //%tape.%d = sext i8 %tape.%d to i32
          Value *tape_1 = builder->
            CreateSExt(tape_0, IntegerType::getInt32Ty(C), tapereg);

          //call i32 @putchar(i32 %tape.%d)
          Value *putchar_params[] = {
            tape_1
          };
          CallInst *putchar_call = builder->
            CreateCall(putchar_func,
                       putchar_params, array_endof(putchar_params));
          putchar_call->setTailCall(false);
        }
        break;

      case SYM_MOVE:
        {
          //%head.%d = getelementptr i8 *%head.%d, i32 %d
          curhead = builder->
            CreateGEP(curhead, ConstantInt::get(C, APInt(32, curvalue)),
                      headreg);

          //Error block for array out of bounds
          if (comflag & flag_arraybounds)
          {
            //%test.%d = icmp uge i8 *%head.%d, %arrmax
            Value *test_0 = builder->
              CreateICmpUGE(curhead, ptr_arrmax, testreg);

            //%test.%d = icmp ult i8 *%head.%d, %arr
            Value *test_1 = builder->
              CreateICmpULT(curhead, ptr_arr, testreg);

            //%test.%d = or i1 %test.%d, %test.%d
            Value *test_2 = builder->
              CreateOr(test_0, test_1, testreg);

            //br i1 %test.%d, label %main.%d, label %main.%d
            BasicBlock *nextbb = BasicBlock::Create(C, label, brainf_func);
            builder->CreateCondBr(test_2, aberrorbb, nextbb);

            //main.%d:
            builder->SetInsertPoint(nextbb);
          }
        }
        break;

      case SYM_CHANGE:
        {
          //%tape.%d = load i8 *%head.%d
          LoadInst *tape_0 = builder->CreateLoad(curhead, tapereg);

          //%tape.%d = add i8 %tape.%d, %d
          Value *tape_1 = builder->
            CreateAdd(tape_0, ConstantInt::get(C, APInt(8, curvalue)), tapereg);

          //store i8 %tape.%d, i8 *%head.%d\n"
          builder->CreateStore(tape_1, curhead);
        }
        break;

      case SYM_LOOP:
        {
          //br label %main.%d
          BasicBlock *testbb = BasicBlock::Create(C, label, brainf_func);
          builder->CreateBr(testbb);

          //main.%d:
          BasicBlock *bb_0 = builder->GetInsertBlock();
          BasicBlock *bb_1 = BasicBlock::Create(C, label, brainf_func);
          builder->SetInsertPoint(bb_1);

          // Make part of PHI instruction now, wait until end of loop to finish
          PHINode *phi_0 =
            PHINode::Create(PointerType::getUnqual(IntegerType::getInt8Ty(C)),
                            2, headreg, testbb);
          phi_0->addIncoming(curhead, bb_0);
          curhead = phi_0;

          readloop(phi_0, bb_1, testbb, C);
        }
        break;

      default:
        std::cerr << "Error: Unknown symbol.\n";
        abort();
        break;
    }

    cursym = nextsym;
    curvalue = nextvalue;
    nextsym = SYM_NONE;

    // Reading stdin loop
    loop = (cursym == SYM_NONE)
        || (cursym == SYM_MOVE)
        || (cursym == SYM_CHANGE);
    while(loop) {
      *in>>c;
      if (in->eof()) {
        if (cursym == SYM_NONE) {
          cursym = SYM_EOF;
        } else {
          nextsym = SYM_EOF;
        }
        loop = 0;
      } else {
        direction = 1;
        switch(c) {
          case '-':
            direction = -1;
            // Fall through

          case '+':
            if (cursym == SYM_CHANGE) {
              curvalue += direction;
              // loop = 1
            } else {
              if (cursym == SYM_NONE) {
                cursym = SYM_CHANGE;
                curvalue = direction;
                // loop = 1
              } else {
                nextsym = SYM_CHANGE;
                nextvalue = direction;
                loop = 0;
              }
            }
            break;

          case '<':
            direction = -1;
            // Fall through

          case '>':
            if (cursym == SYM_MOVE) {
              curvalue += direction;
              // loop = 1
            } else {
              if (cursym == SYM_NONE) {
                cursym = SYM_MOVE;
                curvalue = direction;
                // loop = 1
              } else {
                nextsym = SYM_MOVE;
                nextvalue = direction;
                loop = 0;
              }
            }
            break;

          case ',':
            if (cursym == SYM_NONE) {
              cursym = SYM_READ;
            } else {
              nextsym = SYM_READ;
            }
            loop = 0;
            break;

          case '.':
            if (cursym == SYM_NONE) {
              cursym = SYM_WRITE;
            } else {
              nextsym = SYM_WRITE;
            }
            loop = 0;
            break;

          case '[':
            if (cursym == SYM_NONE) {
              cursym = SYM_LOOP;
            } else {
              nextsym = SYM_LOOP;
            }
            loop = 0;
            break;

          case ']':
            if (cursym == SYM_NONE) {
              cursym = SYM_ENDLOOP;
            } else {
              nextsym = SYM_ENDLOOP;
            }
            loop = 0;
            break;

          // Ignore other characters
          default:
            break;
        }
      }
    }
  }

  if (cursym == SYM_ENDLOOP) {
    if (!phi) {
      std::cerr << "Error: Extra ']'\n";
      abort();
    }

    // Write loop test
    {
      //br label %main.%d
      builder->CreateBr(testbb);

      //main.%d:

      //%head.%d = phi i8 *[%head.%d, %main.%d], [%head.%d, %main.%d]
      //Finish phi made at beginning of loop
      phi->addIncoming(curhead, builder->GetInsertBlock());
      Value *head_0 = phi;

      //%tape.%d = load i8 *%head.%d
      LoadInst *tape_0 = new LoadInst(head_0, tapereg, testbb);

      //%test.%d = icmp eq i8 %tape.%d, 0
      ICmpInst *test_0 = new ICmpInst(*testbb, ICmpInst::ICMP_EQ, tape_0,
                                    ConstantInt::get(C, APInt(8, 0)), testreg);

      //br i1 %test.%d, label %main.%d, label %main.%d
      BasicBlock *bb_0 = BasicBlock::Create(C, label, brainf_func);
      BranchInst::Create(bb_0, oldbb, test_0, testbb);

      //main.%d:
      builder->SetInsertPoint(bb_0);

      //%head.%d = phi i8 *[%head.%d, %main.%d]
      PHINode *phi_1 = builder->
        CreatePHI(PointerType::getUnqual(IntegerType::getInt8Ty(C)), 1,
                  headreg);
      phi_1->addIncoming(head_0, testbb);
      curhead = phi_1;
    }

    return;
  }

  //End of the program, so go to return block
  builder->CreateBr(endbb);

  if (phi) {
    std::cerr << "Error: Missing ']'\n";
    abort();
  }
}
<|endoftext|>


<commit_before>// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o %t
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-1
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-2
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-3
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-4

struct Foo {
  int x;
  float y;
  ~Foo() {}
};

struct TestClass {
  int x;

  TestClass() : x(0) {};
  void MemberFunc() {
    Foo f;
    #pragma clang __debug captured
    {
      f.y = x;
    }
  }
};

void test1() {
  TestClass c;
  c.MemberFunc();
  // CHECK-1: %[[Capture:struct\.anon[\.0-9]*]] = type { %struct.Foo*, %struct.TestClass* }

  // CHECK-1: define {{.*}} void @_ZN9TestClass10MemberFuncEv
  // CHECK-1:   alloca %struct.anon
  // CHECK-1:   getelementptr inbounds %[[Capture]]* %{{[^,]*}}, i32 0, i32 0
  // CHECK-1:   store %struct.Foo* %f, %struct.Foo**
  // CHECK-1:   getelementptr inbounds %[[Capture]]* %{{[^,]*}}, i32 0, i32 1
  // CHECK-1:   call void @[[HelperName:[A-Za-z0-9_]+]](%[[Capture]]*
  // CHECK-1:   call void @_ZN3FooD1Ev
  // CHECK-1:   ret
}

// CHECK-1: define internal void @[[HelperName]]
// CHECK-1:   getelementptr inbounds %[[Capture]]* {{[^,]*}}, i32 0, i32 1
// CHECK-1:   getelementptr inbounds %struct.TestClass* {{[^,]*}}, i32 0, i32 0
// CHECK-1:   getelementptr inbounds %[[Capture]]* {{[^,]*}}, i32 0, i32 0

void test2(int x) {
  int y = [&]() {
    #pragma clang __debug captured
    {
      x++;
    }
    return x;
  }();

  // CHECK-2: define void @_Z5test2i
  // CHECK-2:   call i32 @[[Lambda:["$\w]+]]
  //
  // CHECK-2: define internal i32 @[[Lambda]]
  // CHECK-2:   call void @[[HelperName:["$_A-Za-z0-9]+]](%[[Capture:.*]]*
  //
  // CHECK-2: define internal void @[[HelperName]]
  // CHECK-2:   getelementptr inbounds %[[Capture]]*
  // CHECK-2:   load i32**
  // CHECK-2:   load i32*
}

void test3(int x) {
  #pragma clang __debug captured
  {
    x = [=]() { return x + 1; } ();
  }

  // CHECK-3: %[[Capture:struct\.anon[\.0-9]*]] = type { i32* }

  // CHECK-3: define void @_Z5test3i(i32 %x)
  // CHECK-3:   store i32*
  // CHECK-3:   call void @{{.*}}__captured_stmt
  // CHECK-3:   ret void
}

void test4() {
  #pragma clang __debug captured
  {
    Foo f;
    f.x = 5;
  }
  // CHECK-4: %[[Capture:struct\.anon[\.0-9]*]] = type { i32* }

  // CHECK-4: define void @_Z5test3i(i32 %x)
  // CHECK-4:   store i32*
  // CHECK-4:   call void @[[HelperName:["$_A-Za-z0-9]+]](%[[Capture:.*]]*
  // CHECK-4:   ret void
  //
  // CHECK-4: define internal void @[[HelperName]]
  // CHECK-4:   store i32 5, i32*
  // CHECK-4:   call void @{{.*}}FooD1Ev(%struct.Foo*
}
<commit_msg>Fix captured statements codegen test on ARM<commit_after>// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o %t
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-1
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-2
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-3
// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-4

struct Foo {
  int x;
  float y;
  ~Foo() {}
};

struct TestClass {
  int x;

  TestClass() : x(0) {};
  void MemberFunc() {
    Foo f;
    #pragma clang __debug captured
    {
      f.y = x;
    }
  }
};

void test1() {
  TestClass c;
  c.MemberFunc();
  // CHECK-1: %[[Capture:struct\.anon[\.0-9]*]] = type { %struct.Foo*, %struct.TestClass* }

  // CHECK-1: define {{.*}} void @_ZN9TestClass10MemberFuncEv
  // CHECK-1:   alloca %struct.anon
  // CHECK-1:   getelementptr inbounds %[[Capture]]* %{{[^,]*}}, i32 0, i32 0
  // CHECK-1:   store %struct.Foo* %f, %struct.Foo**
  // CHECK-1:   getelementptr inbounds %[[Capture]]* %{{[^,]*}}, i32 0, i32 1
  // CHECK-1:   call void @[[HelperName:[A-Za-z0-9_]+]](%[[Capture]]*
  // CHECK-1:   call {{.*}}FooD1Ev
  // CHECK-1:   ret
}

// CHECK-1: define internal void @[[HelperName]]
// CHECK-1:   getelementptr inbounds %[[Capture]]* {{[^,]*}}, i32 0, i32 1
// CHECK-1:   getelementptr inbounds %struct.TestClass* {{[^,]*}}, i32 0, i32 0
// CHECK-1:   getelementptr inbounds %[[Capture]]* {{[^,]*}}, i32 0, i32 0

void test2(int x) {
  int y = [&]() {
    #pragma clang __debug captured
    {
      x++;
    }
    return x;
  }();

  // CHECK-2: define void @_Z5test2i
  // CHECK-2:   call i32 @[[Lambda:["$\w]+]]
  //
  // CHECK-2: define internal i32 @[[Lambda]]
  // CHECK-2:   call void @[[HelperName:["$_A-Za-z0-9]+]](%[[Capture:.*]]*
  //
  // CHECK-2: define internal void @[[HelperName]]
  // CHECK-2:   getelementptr inbounds %[[Capture]]*
  // CHECK-2:   load i32**
  // CHECK-2:   load i32*
}

void test3(int x) {
  #pragma clang __debug captured
  {
    x = [=]() { return x + 1; } ();
  }

  // CHECK-3: %[[Capture:struct\.anon[\.0-9]*]] = type { i32* }

  // CHECK-3: define void @_Z5test3i(i32 %x)
  // CHECK-3:   store i32*
  // CHECK-3:   call void @{{.*}}__captured_stmt
  // CHECK-3:   ret void
}

void test4() {
  #pragma clang __debug captured
  {
    Foo f;
    f.x = 5;
  }
  // CHECK-4: %[[Capture:struct\.anon[\.0-9]*]] = type { i32* }

  // CHECK-4: define void @_Z5test3i(i32 %x)
  // CHECK-4:   store i32*
  // CHECK-4:   call void @[[HelperName:["$_A-Za-z0-9]+]](%[[Capture:.*]]*
  // CHECK-4:   ret void
  //
  // CHECK-4: define internal void @[[HelperName]]
  // CHECK-4:   store i32 5, i32*
  // CHECK-4:   call {{.*}}FooD1Ev
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

/* Video related snippets */
#include "qvideorenderercontrol.h"
#include "qmediaservice.h"
#include "qmediaplayer.h"
#include "qabstractvideosurface.h"
#include "qvideowidgetcontrol.h"
#include "qvideowindowcontrol.h"
#include "qgraphicsvideoitem.h"
#include "qmediaplaylist.h"
#include "qvideosurfaceformat.h"

#include <QFormLayout>
#include <QGraphicsView>

//! [Derived Surface]
class MyVideoSurface : public QAbstractVideoSurface
{
    QList<QVideoFrame::PixelFormat> supportedPixelFormats(
            QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const
    {
        Q_UNUSED(handleType);

        // Return the formats you will support
        return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_RGB565;
    }

    bool present(const QVideoFrame &frame)
    {
        Q_UNUSED(frame);
        // Handle the frame and do your processing

        return true;
    }
};
//! [Derived Surface]

//! [Video producer]
class MyVideoProducer : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QAbstractVideoSurface *videoSurface WRITE setVideoSurface)

public:
    void setVideoSurface(QAbstractVideoSurface *surface)
    {
        m_surface = surface;
        m_surface->start(m_format);
    }

    // ...

public slots:
    void onNewVideoContentReceived(const QVideoFrame &frame)
    {
        if (m_surface)
            m_surface->present(frame);
    }

private:
    QAbstractVideoSurface *m_surface;
    QVideoSurfaceFormat m_format;
};

//! [Video producer]

class VideoExample : public QObject {
    Q_OBJECT
public:
    void VideoGraphicsItem();
    void VideoRendererControl();
    void VideoWidget();
    void VideoWindowControl();
    void VideoWidgetControl();

private:
    // Common naming
    QMediaService *mediaService;
    QMediaPlaylist *playlist;
    QVideoWidget *videoWidget;
    QWidget *widget;
    QFormLayout *layout;
    QAbstractVideoSurface *myVideoSurface;
    QMediaPlayer *player;
    QMediaContent video;
    QGraphicsView *graphicsView;
};

void VideoExample::VideoRendererControl()
{
    //! [Video renderer control]
    QVideoRendererControl *rendererControl = mediaService->requestControl<QVideoRendererControl *>();
    rendererControl->setSurface(myVideoSurface);
    //! [Video renderer control]
}

void VideoExample::VideoWidget()
{
    //! [Video widget]
    player = new QMediaPlayer;

    playlist = new QMediaPlaylist(player);
    playlist->addMedia(QUrl("http://example.com/myclip1.mp4"));
    playlist->addMedia(QUrl("http://example.com/myclip2.mp4"));

    videoWidget = new QVideoWidget;
    player->setVideoOutput(videoWidget);

    videoWidget->show();
    playlist->setCurrentIndex(1);
    player->play();
    //! [Video widget]

    player->stop();

    //! [Setting surface in player]
    player->setVideoOutput(myVideoSurface);
    //! [Setting surface in player]
}

void VideoExample::VideoWidgetControl()
{
    //! [Video widget control]
    QVideoWidgetControl *widgetControl = mediaService->requestControl<QVideoWidgetControl *>();
    layout->addWidget(widgetControl->videoWidget());
    //! [Video widget control]
}

void VideoExample::VideoWindowControl()
{
    //! [Video window control]
    QVideoWindowControl *windowControl = mediaService->requestControl<QVideoWindowControl *>();
    windowControl->setWinId(widget->winId());
    windowControl->setDisplayRect(widget->rect());
    windowControl->setAspectRatioMode(Qt::KeepAspectRatio);
    //! [Video window control]
}

void VideoExample::VideoGraphicsItem()
{
    //! [Video graphics item]
    player = new QMediaPlayer(this);

    QGraphicsVideoItem *item = new QGraphicsVideoItem;
    player->setVideoOutput(item);
    graphicsView->scene()->addItem(item);
    graphicsView->show();

    player->setMedia(QUrl("http://example.com/myclip4.ogv"));
    player->play();
    //! [Video graphics item]
}
<commit_msg>Add a simple accessor to the video provider snippet<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

/* Video related snippets */
#include "qvideorenderercontrol.h"
#include "qmediaservice.h"
#include "qmediaplayer.h"
#include "qabstractvideosurface.h"
#include "qvideowidgetcontrol.h"
#include "qvideowindowcontrol.h"
#include "qgraphicsvideoitem.h"
#include "qmediaplaylist.h"
#include "qvideosurfaceformat.h"

#include <QFormLayout>
#include <QGraphicsView>

//! [Derived Surface]
class MyVideoSurface : public QAbstractVideoSurface
{
    QList<QVideoFrame::PixelFormat> supportedPixelFormats(
            QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const
    {
        Q_UNUSED(handleType);

        // Return the formats you will support
        return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_RGB565;
    }

    bool present(const QVideoFrame &frame)
    {
        Q_UNUSED(frame);
        // Handle the frame and do your processing

        return true;
    }
};
//! [Derived Surface]

//! [Video producer]
class MyVideoProducer : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QAbstractVideoSurface *videoSurface READ videoSurface WRITE setVideoSurface)

public:
    QAbstractVideoSurface* videoSurface() const { return m_surface; }

    void setVideoSurface(QAbstractVideoSurface *surface)
    {
        m_surface = surface;
        m_surface->start(m_format);
    }

    // ...

public slots:
    void onNewVideoContentReceived(const QVideoFrame &frame)
    {
        if (m_surface)
            m_surface->present(frame);
    }

private:
    QAbstractVideoSurface *m_surface;
    QVideoSurfaceFormat m_format;
};

//! [Video producer]

class VideoExample : public QObject {
    Q_OBJECT
public:
    void VideoGraphicsItem();
    void VideoRendererControl();
    void VideoWidget();
    void VideoWindowControl();
    void VideoWidgetControl();

private:
    // Common naming
    QMediaService *mediaService;
    QMediaPlaylist *playlist;
    QVideoWidget *videoWidget;
    QWidget *widget;
    QFormLayout *layout;
    QAbstractVideoSurface *myVideoSurface;
    QMediaPlayer *player;
    QMediaContent video;
    QGraphicsView *graphicsView;
};

void VideoExample::VideoRendererControl()
{
    //! [Video renderer control]
    QVideoRendererControl *rendererControl = mediaService->requestControl<QVideoRendererControl *>();
    rendererControl->setSurface(myVideoSurface);
    //! [Video renderer control]
}

void VideoExample::VideoWidget()
{
    //! [Video widget]
    player = new QMediaPlayer;

    playlist = new QMediaPlaylist(player);
    playlist->addMedia(QUrl("http://example.com/myclip1.mp4"));
    playlist->addMedia(QUrl("http://example.com/myclip2.mp4"));

    videoWidget = new QVideoWidget;
    player->setVideoOutput(videoWidget);

    videoWidget->show();
    playlist->setCurrentIndex(1);
    player->play();
    //! [Video widget]

    player->stop();

    //! [Setting surface in player]
    player->setVideoOutput(myVideoSurface);
    //! [Setting surface in player]
}

void VideoExample::VideoWidgetControl()
{
    //! [Video widget control]
    QVideoWidgetControl *widgetControl = mediaService->requestControl<QVideoWidgetControl *>();
    layout->addWidget(widgetControl->videoWidget());
    //! [Video widget control]
}

void VideoExample::VideoWindowControl()
{
    //! [Video window control]
    QVideoWindowControl *windowControl = mediaService->requestControl<QVideoWindowControl *>();
    windowControl->setWinId(widget->winId());
    windowControl->setDisplayRect(widget->rect());
    windowControl->setAspectRatioMode(Qt::KeepAspectRatio);
    //! [Video window control]
}

void VideoExample::VideoGraphicsItem()
{
    //! [Video graphics item]
    player = new QMediaPlayer(this);

    QGraphicsVideoItem *item = new QGraphicsVideoItem;
    player->setVideoOutput(item);
    graphicsView->scene()->addItem(item);
    graphicsView->show();

    player->setMedia(QUrl("http://example.com/myclip4.ogv"));
    player->play();
    //! [Video graphics item]
}
<|endoftext|>


<commit_before>e893/*
 * File:   UpdateWorker.cpp
 * Author: uli
 *
 * Created on 23. April 2013, 10:35
 */

#include "ReadWorker.hpp"
#include <czmq.h>
#include <string>
#include <iostream>
#include "TableOpenHelper.hpp"
#include "Tablespace.hpp"
#include "protocol.hpp"
#include "zutil.hpp"
#include "endpoints.hpp"

        using namespace std;
#define DEBUG_READ

/**
 * Read request handler. Shall be called
 *
 * The original message is modified to contain the response.
 *
 * Envelope + Read request Header + Table ID[what zmsg_next() must return] + Payload
 */
static void handleCountRequest(Tablespace& tables, zmsg_t* msg, TableOpenHelper& openHelper) {
#ifdef DEBUG_READ
    printf("Starting to handle count request of size %d\n", (uint32_t) zmsg_size(msg) - 3);
    fflush(stdout);
#endif
    //Parse the table id
    zframe_t* tableIdFrame = zmsg_next(msg);
    assert(zframe_size(tableIdFrame) == sizeof (uint32_t));
    uint32_t tableId = *((uint32_t*) zframe_data(tableIdFrame));
    //Parse the start/end frame
    zframe_t* rangeStartFrame = zmsg_next(msg);
    zframe_t* rangeEndFrame = zmsg_next(msg);
    bool haveRangeStart = !(rangeStartFrame == NULL || zframe_size(rangeStartFrame) == 0);
    bool haveRangeEnd = !(rangeEndFrame == NULL || zframe_size(rangeEndFrame) == 0);
    std::string rangeStart = (haveRangeStart ? string((char*) zframe_data(rangeStartFrame), zframe_size(rangeStartFrame)) : "");
    std::string rangeEnd = (haveRangeEnd ? string((char*) zframe_data(rangeEndFrame), zframe_size(rangeEndFrame)) : "");
    //Remove the range frames (if any), the reply is shorter
    if (rangeStartFrame) {
        removeAndDestroyFrame(msg, rangeStartFrame);
    }
    if (rangeEndFrame) {
        removeAndDestroyFrame(msg, rangeEndFrame);
    }
    //Get the table to read from
    leveldb::DB* db = tables.getTable(tableId, openHelper);
    //Create the response object
    leveldb::ReadOptions readOptions;
    string value; //Where the value will be placed
    leveldb::Status status;
    //Create the iterator
    leveldb::Iterator* it = db->NewIterator(leveldb::ReadOwptions());
    if (haveRangeStart) {
        it->Sekk
    } else {
        it->SeekToFirst();
    }
    uint64_t count = 0;
    //Iterate over all key-values in the range
    for (; it->Valid(); it->Next()) {
        count++;
        string key = it->key().ToString();
        if (haveRangeEnd && key >= rangeEnd) {
            break;
        }
    }
    //TODO handle error
    assert(it->status().ok()); // Check for any errors found during the scan
    //Delete the iterator
    delete it;
    //Build the response message
    zframe_reset(tableIdFrame, &count, sizeof(uint64_t));
}

/**
 * Read request handler. Shall be called for Read requests only!
 *
 * The original message is modified to contain the response.
 *
 * Envelope + Read request Header + Table ID[what zmsg_next() must return] + Payload
 */
static void handleReadRequest(Tablespace& tables, zmsg_t* msg, TableOpenHelper& openHelper) {
#ifdef DEBUG_READ
    printf("Starting to handle read request of size %d\n", (uint32_t) zmsg_size(msg) - 3);
    fflush(stdout);
#endif
    //Parse the table id
    zframe_t* tableIdFrame = zmsg_next(msg);
    assert(zframe_size(tableIdFrame) == sizeof (uint32_t));
    uint32_t tableId = *((uint32_t*) zframe_data(tableIdFrame));
    //Parse the
    //Get the table to read from
    leveldb::DB* db = tables.getTable(tableId, openHelper);
    //Create the response object
    leveldb::ReadOptions readOptions;
    leveldb::Status status;
    //Read each read request
    zframe_t* keyFrame = NULL;
    while ((keyFrame = zmsg_next(msg)) != NULL) {
        //Build a slice of the key (zero-copy)
        string keystr((char*) zframe_data(keyFrame), zframe_size(keyFrame));
        leveldb::Slice key((char*) zframe_data(keyFrame), zframe_size(keyFrame));
#ifdef DEBUG_READ
        printf("Reading key %s from table %d\n", key.ToString().c_str(), tableId);
#endif
        status = db->Get(readOptions, key, &value);
        if (status.IsNotFound()) {
#ifdef DEBUG_READ
            cout << "Could not find value for key " << key.ToString() << "in table " << tableId << endl;
#endif
            //Empty value
            zframe_reset(keyFrame, "", 0);
        } else {
#ifdef DEBUG_READ
            cout << "Read " << value << " (key = " << key.ToString() << ") --> " << value << endl;
#endif
            zframe_reset(keyFrame, value.c_str(), value.length());
        }
    }
    //Now we can remove the table ID frame from the message (doing so before would confuse zmsg_next())
    zmsg_remove(msg, tableIdFrame);
    zframe_destroy(&tableIdFrame);
#ifdef DEBUG_READ
    cout << "Final reply msg size: " << zmsg_size(msg) << endl;
#endif
}

/**
 * The main function for the update worker thread.
 *
 * This function parses the header, calls the appropriate handler function
 * and sends the response for PARTSYNC requests
 */
static void readWorkerThreadFunction(zctx_t* ctx, Tablespace& tablespace) {
    //Create the socket that is used to proxy requests to the external req/rep socket
    void* replyProxySocket = zsocket_new(ctx, ZMQ_PUSH);
    if (zsocket_connect(replyProxySocket, externalRequestProxyEndpoint)) {
        debugZMQError("Connect reply proxy socket", errno);
    }
    assert(replyProxySocket);
    //Create the socket we receive requests from
    void* workPullSocket = zsocket_new(ctx, ZMQ_PULL);
    zsocket_connect(workPullSocket, readWorkerThreadAddr);
    assert(workPullSocket);
    //Create the table open helper (creates a socket that sends table open requests)
    TableOpenHelper tableOpenHelper(ctx);
    //Create the data structure with all info for the poll handler
    while (true) {
        zmsg_t* msg = zmsg_recv(workPullSocket);
        assert(msg);
        assert(zmsg_size(msg) >= 1);
        //Parse the header
        //Contrary to the update message handling, we assume (checked by the request router) that
        // the message contains an envelope. Read requests without envelope (--> without return path)
        // don't really make sense.
        zframe_t* routingFrame = zmsg_first(msg); //Envelope ID
        assert(routingFrame);
        zframe_t* delimiterFrame = zmsg_next(msg); //Envelope delimiter
        assert(delimiterFrame);
        zframe_t* headerFrame = zmsg_next(msg);
        assert(headerFrame);
        assert(isHeaderFrame(headerFrame));
        //Get the request type
        RequestType requestType = getRequestType(headerFrame);
        //Process the rest of the frame
        if (requestType == ReadRequest) {
            handleReadRequest(tablespace, msg, tableOpenHelper);
        } else if (requestType == CountRequest) {
            cerr << "Count request TBD - WIP!" << endl;
        } else {
            cerr << "Internal routing error: request type " << requestType << " routed to update worker thread!" << endl;
        }
        //Send reply (the handler function rewrote the original message to contain the reply)
        assert(msg);
        assert(zmsg_size(msg) >= 3); //2 Envelope + 1 Response header (corner case: Nothing to be read)
        zmsg_send(&msg, replyProxySocket);
    }
    printf("Stopping update processor\n");
    zsocket_destroy(ctx, workPullSocket);
    zsocket_destroy(ctx, replyProxySocket);
}

ReadWorkerController::ReadWorkerController(zctx_t* context, Tablespace& tablespace) : context(context), tablespace(tablespace), numThreads(3) {
    //Initialize the push socket
    workerPushSocket = zsocket_new(context, ZMQ_PUSH);
    zsocket_bind(workerPushSocket, readWorkerThreadAddr);

}

void ReadWorkerController::start() {
    threads = new std::thread*[numThreads];
    for (int i = 0; i < numThreads; i++) {
        threads[i] = new std::thread(readWorkerThreadFunction, context, std::ref(tablespace));
    }
}

ReadWorkerController::~ReadWorkerController() {

    //Send an empty STOP message for each read worker thread (use a temporary socket)
    void* tempSocket = zsocket_new(context, ZMQ_PUSH); //Create a temporary socket
    zsocket_connect(tempSocket, readWorkerThreadAddr);
    for (int i = 0; i < numThreads; i++) {
        //Send an empty msg (signals the table open thread to stop)
        sendEmptyFrameMessage(tempSocket);
    }
    //Cleanup
    zsocket_destroy(context, &tempSocket);
    //Wait for each thread to exit
    for (int i = 0; i < numThreads; i++) {
        threads[i]->join();
        delete threads[i];
    }
    //Free the array
    if (numThreads > 0) {
        delete[] threads;
    }
}

void ReadWorkerController::send(zmsg_t** msg) {
    zmsg_send(msg, workerPushSocket);
}
<commit_msg>Added count request handler<commit_after>e893/*
 * File:   UpdateWorker.cpp
 * Author: uli
 *
 * Created on 23. April 2013, 10:35
 */

#include "ReadWorker.hpp"
#include <czmq.h>
#include <string>
#include <iostream>
#include "TableOpenHelper.hpp"
#include "Tablespace.hpp"
#include "protocol.hpp"
#include "zutil.hpp"
#include "endpoints.hpp"

        using namespace std;
#define DEBUG_READ

/**
 * Read request handler. Shall be called
 *
 * The original message is modified to contain the response.
 *
 * Envelope + Read request Header + Table ID[what zmsg_next() must return] + Payload
 */
static void handleCountRequest(Tablespace& tables, zmsg_t* msg, TableOpenHelper& openHelper) {
#ifdef DEBUG_READ
    printf("Starting to handle count request of size %d\n", (uint32_t) zmsg_size(msg) - 3);
    fflush(stdout);
#endif
    //Parse the table id
    zframe_t* tableIdFrame = zmsg_next(msg);
    assert(zframe_size(tableIdFrame) == sizeof (uint32_t));
    uint32_t tableId = *((uint32_t*) zframe_data(tableIdFrame));
    //Parse the start/end frame
    zframe_t* rangeStartFrame = zmsg_next(msg);
    zframe_t* rangeEndFrame = zmsg_next(msg);
    bool haveRangeStart = !(rangeStartFrame == NULL || zframe_size(rangeStartFrame) == 0);
    bool haveRangeEnd = !(rangeEndFrame == NULL || zframe_size(rangeEndFrame) == 0);
    std::string rangeStart = (haveRangeStart ? string((char*) zframe_data(rangeStartFrame), zframe_size(rangeStartFrame)) : "");
    std::string rangeEnd = (haveRangeEnd ? string((char*) zframe_data(rangeEndFrame), zframe_size(rangeEndFrame)) : "");
    //Remove the range frames (if any), the reply is shorter
    if (rangeStartFrame) {
        removeAndDestroyFrame(msg, rangeStartFrame);
    }
    if (rangeEndFrame) {
        removeAndDestroyFrame(msg, rangeEndFrame);
    }
    //Get the table to read from
    leveldb::DB* db = tables.getTable(tableId, openHelper);
    //Create the response object
    leveldb::ReadOptions readOptions;
    string value; //Where the value will be placed
    leveldb::Status status;
    //Create the iterator
    leveldb::Iterator* it = db->NewIterator(leveldb::ReadOwptions());
    if (haveRangeStart) {
        it->Sekk
    } else {
        it->SeekToFirst();
    }
    uint64_t count = 0;
    //Iterate over all key-values in the range
    for (; it->Valid(); it->Next()) {
        count++;
        string key = it->key().ToString();
        if (haveRangeEnd && key >= rangeEnd) {
            break;
        }
    }
    //TODO handle error
    assert(it->status().ok()); // Check for any errors found during the scan
    //Delete the iterator
    delete it;
    //Build the response message
    zframe_reset(tableIdFrame, &count, sizeof (uint64_t));
}

/**
 * Read request handler. Shall be called for Read requests only!
 *
 * The original message is modified to contain the response.
 *
 * Envelope + Read request Header + Table ID[what zmsg_next() must return] + Payload
 */
static void handleReadRequest(Tablespace& tables, zmsg_t* msg, TableOpenHelper& openHelper) {
#ifdef DEBUG_READ
    printf("Starting to handle read request of size %d\n", (uint32_t) zmsg_size(msg) - 3);
    fflush(stdout);
#endif
    //Parse the table id
    zframe_t* tableIdFrame = zmsg_next(msg);
    assert(zframe_size(tableIdFrame) == sizeof (uint32_t));
    uint32_t tableId = *((uint32_t*) zframe_data(tableIdFrame));
    //Parse the
    //Get the table to read from
    leveldb::DB* db = tables.getTable(tableId, openHelper);
    //Create the response object
    leveldb::ReadOptions readOptions;
    leveldb::Status status;
    //Read each read request
    zframe_t* keyFrame = NULL;
    while ((keyFrame = zmsg_next(msg)) != NULL) {
        //Build a slice of the key (zero-copy)
        string keystr((char*) zframe_data(keyFrame), zframe_size(keyFrame));
        leveldb::Slice key((char*) zframe_data(keyFrame), zframe_size(keyFrame));
#ifdef DEBUG_READ
        printf("Reading key %s from table %d\n", key.ToString().c_str(), tableId);
#endif
        status = db->Get(readOptions, key, &value);
        if (status.IsNotFound()) {
#ifdef DEBUG_READ
            cout << "Could not find value for key " << key.ToString() << "in table " << tableId << endl;
#endif
            //Empty value
            zframe_reset(keyFrame, "", 0);
        } else {
#ifdef DEBUG_READ
            cout << "Read " << value << " (key = " << key.ToString() << ") --> " << value << endl;
#endif
            zframe_reset(keyFrame, value.c_str(), value.length());
        }
    }
    //Now we can remove the table ID frame from the message (doing so before would confuse zmsg_next())
    zmsg_remove(msg, tableIdFrame);
    zframe_destroy(&tableIdFrame);
#ifdef DEBUG_READ
    cout << "Final reply msg size: " << zmsg_size(msg) << endl;
#endif
}

/**
 * The main function for the update worker thread.
 *
 * This function parses the header, calls the appropriate handler function
 * and sends the response for PARTSYNC requests
 */
static void readWorkerThreadFunction(zctx_t* ctx, Tablespace& tablespace) {
    //Create the socket that is used to proxy requests to the external req/rep socket
    void* replyProxySocket = zsocket_new(ctx, ZMQ_PUSH);
    if (zsocket_connect(replyProxySocket, externalRequestProxyEndpoint)) {
        debugZMQError("Connect reply proxy socket", errno);
    }
    assert(replyProxySocket);
    //Create the socket we receive requests from
    void* workPullSocket = zsocket_new(ctx, ZMQ_PULL);
    zsocket_connect(workPullSocket, readWorkerThreadAddr);
    assert(workPullSocket);
    //Create the table open helper (creates a socket that sends table open requests)
    TableOpenHelper tableOpenHelper(ctx);
    //Create the data structure with all info for the poll handler
    while (true) {
        zmsg_t* msg = zmsg_recv(workPullSocket);
        assert(msg);
        assert(zmsg_size(msg) >= 1);
        //Parse the header
        //Contrary to the update message handling, we assume (checked by the request router) that
        // the message contains an envelope. Read requests without envelope (--> without return path)
        // don't really make sense.
        zframe_t* routingFrame = zmsg_first(msg); //Envelope ID
        assert(routingFrame);
        zframe_t* delimiterFrame = zmsg_next(msg); //Envelope delimiter
        assert(delimiterFrame);
        zframe_t* headerFrame = zmsg_next(msg);
        assert(headerFrame);
        assert(isHeaderFrame(headerFrame));
        //Get the request type
        RequestType requestType = getRequestType(headerFrame);
        //Process the rest of the frame
        if (requestType == ReadRequest) {
            handleReadRequest(tablespace, msg, tableOpenHelper);
        } else if (requestType == CountRequest) {
            handleCountRequest(tablespace, msg, tableOpenHelper);
        } else {
            cerr << "Internal routing error: request type " << requestType << " routed to update worker thread!" << endl;
        }
        //Send reply (the handler function rewrote the original message to contain the reply)
        assert(msg);
        assert(zmsg_size(msg) >= 3); //2 Envelope + 1 Response header (corner case: Nothing to be read)
        zmsg_send(&msg, replyProxySocket);
    }
    printf("Stopping update processor\n");
    zsocket_destroy(ctx, workPullSocket);
    zsocket_destroy(ctx, replyProxySocket);
}

ReadWorkerController::ReadWorkerController(zctx_t* context, Tablespace& tablespace) : context(context), tablespace(tablespace), numThreads(3) {
    //Initialize the push socket
    workerPushSocket = zsocket_new(context, ZMQ_PUSH);
    zsocket_bind(workerPushSocket, readWorkerThreadAddr);

}

void ReadWorkerController::start() {
    threads = new std::thread*[numThreads];
    for (int i = 0; i < numThreads; i++) {
        threads[i] = new std::thread(readWorkerThreadFunction, context, std::ref(tablespace));
    }
}

ReadWorkerController::~ReadWorkerController() {

    //Send an empty STOP message for each read worker thread (use a temporary socket)
    void* tempSocket = zsocket_new(context, ZMQ_PUSH); //Create a temporary socket
    zsocket_connect(tempSocket, readWorkerThreadAddr);
    for (int i = 0; i < numThreads; i++) {
        //Send an empty msg (signals the table open thread to stop)
        sendEmptyFrameMessage(tempSocket);
    }
    //Cleanup
    zsocket_destroy(context, &tempSocket);
    //Wait for each thread to exit
    for (int i = 0; i < numThreads; i++) {
        threads[i]->join();
        delete threads[i];
    }
    //Free the array
    if (numThreads > 0) {
        delete[] threads;
    }
}

void ReadWorkerController::send(zmsg_t** msg) {
    zmsg_send(msg, workerPushSocket);
}
<|endoftext|>