<commit_before>//=====================================================================//
/*!	@file
	@brief	R8C USB チェッカー・メイン @n
			for ST7567 SPI (128 x 32) @n
			LCD: Aitendo M-G0812P7567
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstring>
#include "common/vect.h"
#include "system.hpp"
#include "clock.hpp"
#include "intr.hpp"
#include "port.hpp"
#include "common/intr_utils.hpp"
#include "common/delay.hpp"
#include "common/port_map.hpp"
#include "common/fifo.hpp"
#include "common/uart_io.hpp"
#include "common/format.hpp"
#include "common/trb_io.hpp"
#include "common/trj_io.hpp"
#include "common/spi_io.hpp"
#include "chip/ST7565.hpp"
#include "common/monograph.hpp"
#include "common/font6x12.hpp"

// #include "bitmap/font32.h"

namespace {

// ポートの配置
// P4_2(1):   LCD_SCK(SCL)
// P3_7(2):   LCD_/CS
// /RES(3):  (System reset)
// P4_7(4):   LCD_/RES
// VSS:(5)   (Power GND)
// P4_6(6):
// VCC(7):   (Power +3.3V)
// MODE(8):  (System mode)
// P3_5(9):
// P3_4(10):
// P3_3(11):  LCD_A0
// P4_5(12):  LCD_SDA
// P1_7(13):
// P1_6(14):  ---
// P1_5(15):  RXD0
// P1_4(16):  TXD0
// P1_3(17):  AN3
// P1_2(18):  AN2
// P1_1(19):  AN1
// P1_0(20):  AN0

#if 0
	const uint8_t* nmbs_[] = {
		nmb_0, nmb_1, nmb_2, nmb_3, nmb_4,
		nmb_5, nmb_6, nmb_7, nmb_8, nmb_9,
		txt_hz, txt_k
	};
#endif

	device::trb_io<utils::null_task> timer_b_;

	typedef utils::fifo<uint8_t, 16> buffer;
	typedef device::uart_io<device::UART0, buffer, buffer> uart;
	uart uart_;

	// LCD SCL: P4_2(1)
	typedef device::PORT<device::PORT4, device::bitpos::B2> SPI_SCL;
	// LCD SDA: P4_5(12)
	typedef device::PORT<device::PORT4, device::bitpos::B5> SPI_SDA;

	typedef device::spi_io<SPI_SCL, SPI_SDA, device::NULL_PORT> SPI;
	SPI		spi_;

	// LCD /CS:  P3_7(2)
	typedef device::PORT<device::PORT3, device::bitpos::B7> LCD_SEL;
	// LCD A0:   P3_3(11)
	typedef device::PORT<device::PORT3, device::bitpos::B3> LCD_A0;
	// LCD /RES: P4_7(4)
	typedef device::PORT<device::PORT4, device::bitpos::B7> LCD_RES;

	typedef chip::ST7565<SPI, LCD_SEL, LCD_A0, LCD_RES> LCD;
	LCD 	lcd_(spi_);

	typedef graphics::font6x12 afont;
	graphics::kfont_null kfont_;
	graphics::monograph<128, 32, afont> bitmap_(kfont_);

	uint8_t v_ = 91;
	uint8_t m_ = 123;
	uint8_t rand_()
	{
		v_ += v_ << 2;
		++v_;
		uint8_t n = 0;
		if(m_ & 0x02) n = 1;
		if(m_ & 0x40) n ^= 1;
		m_ += m_;
		if(n == 0) ++m_;
		return v_ ^ m_;
	}
}

extern "C" {
	void sci_putch(char ch) {
		uart_.putch(ch);
	}

	char sci_getch(void) {
		return uart_.getch();
	}

	uint16_t sci_length() {
		return uart_.length();
	}

	void sci_puts(const char* str) {
		uart_.puts(str);
	}
}

extern "C" {
	const void* variable_vectors_[] __attribute__ ((section (".vvec"))) = {
		reinterpret_cast<void*>(brk_inst_),		nullptr,	// (0)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (1) flash_ready
		reinterpret_cast<void*>(null_task_),	nullptr,	// (2)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (3)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (4) コンパレーターB1
		reinterpret_cast<void*>(null_task_),	nullptr,	// (5) コンパレーターB3
		reinterpret_cast<void*>(null_task_),	nullptr,	// (6)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (7) タイマＲＣ

		reinterpret_cast<void*>(null_task_),	nullptr,	// (8)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (9)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (10)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (11)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (12)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (13) キー入力
		reinterpret_cast<void*>(null_task_),	nullptr,	// (14) A/D 変換
		reinterpret_cast<void*>(null_task_),	nullptr,	// (15)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (16)
		reinterpret_cast<void*>(uart_.isend),	nullptr,	// (17) UART0 送信
		reinterpret_cast<void*>(uart_.irecv),	nullptr,	// (18) UART0 受信
		reinterpret_cast<void*>(null_task_),	nullptr,	// (19)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (20)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (21) /INT2
		reinterpret_cast<void*>(null_task_),	nullptr,	// (22) タイマＲＪ２
		reinterpret_cast<void*>(null_task_),	nullptr,	// (23) 周期タイマ

		reinterpret_cast<void*>(timer_b_.itask),nullptr,	// (24) タイマＲＢ２
		reinterpret_cast<void*>(null_task_),	nullptr,	// (25) /INT1
		reinterpret_cast<void*>(null_task_),	nullptr,	// (26) /INT3
		reinterpret_cast<void*>(null_task_),	nullptr,	// (27)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (28)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (29) /INT0
		reinterpret_cast<void*>(null_task_),	nullptr,	// (30)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (31)
	};
}

// __attribute__ ((section (".exttext")))
int main(int argc, char *argv[])
{
	using namespace device;

// クロック関係レジスタ・プロテクト解除
	PRCR.PRC0 = 1;

// 高速オンチップオシレーターへ切り替え(20MHz)
// ※ F_CLK を設定する事（Makefile内）
	OCOCR.HOCOE = 1;
	utils::delay::micro_second(1);	// >=30uS(125KHz)
	SCKCR.HSCKSEL = 1;
	CKSTPR.SCKSEL = 1;

	PRCR.PRC0 = 0;

	// タイマーＢ初期化
	{
		uint8_t ir_level = 2;
		timer_b_.start_timer(60, ir_level);
	}

	// UART の設定 (P1_4: TXD0[out], P1_5: RXD0[in])
	// ※シリアルライターでは、RXD 端子は、P1_6 となっているので注意！
	{
		utils::PORT_MAP(utils::port_map::P14::TXD0);
		utils::PORT_MAP(utils::port_map::P15::RXD0);
		uint8_t ir_level = 1;
		uart_.start(57600, ir_level);
	}

	// SPI を開始
	{
		spi_.start(0);
	}

	// LCD を開始
	{
		lcd_.start(0x00, true, true);  // contrast, reverse=yes, BIAS9
		bitmap_.clear(0);
	}

	utils::format("Start USB Checker\n");
	utils::format("# ");

	uint16_t x = rand_() & 127;
	uint16_t y = rand_() & 31;
	uint16_t xx;
	uint16_t yy;
	uint8_t loop = 50;
	while(1) {
		timer_b_.sync();
		lcd_.copy(bitmap_.fb(), bitmap_.page_num());

		if(loop >= 50) {
			loop = 0;
			bitmap_.clear(0);
			bitmap_.frame(0, 0, 128, 32, 1);
			bitmap_.frame(10, 10, 128-20, 32-20, 1);
			bitmap_.draw_text(0, 0, "ABCDEFG");
			bitmap_.line(0, 0, 127, 31, 1);
			bitmap_.line(0, 31, 127,  0, 1);
		}
		xx = rand_() & 127;
		yy = rand_() & 31;
		bitmap_.line(x, y, xx, yy, 1);
		x = xx;
		y = yy;
		++loop;
	}
}
<commit_msg>update<commit_after>//=====================================================================//
/*!	@file
	@brief	R8C USB チェッカー・メイン @n
			for ST7567 SPI (128 x 32) @n
			LCD: Aitendo M-G0812P7567
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstring>
#include "common/vect.h"
#include "system.hpp"
#include "clock.hpp"
#include "intr.hpp"
#include "port.hpp"
#include "common/intr_utils.hpp"
#include "common/delay.hpp"
#include "common/port_map.hpp"
#include "common/fifo.hpp"
#include "common/uart_io.hpp"
#include "common/format.hpp"
#include "common/trb_io.hpp"
#include "common/adc_io.hpp"
#include "common/spi_io.hpp"
#include "chip/ST7565.hpp"
#include "common/monograph.hpp"
#include "common/font6x12.hpp"
#include "common/fixed_string.hpp"

// #include "bitmap/font32.h"

namespace {

// ポートの配置
// P4_2(1):   LCD_SCK(SCL)
// P3_7(2):   LCD_/CS
// /RES(3):  (System reset)
// P4_7(4):   LCD_/RES
// VSS:(5)   (Power GND)
// P4_6(6):
// VCC(7):   (Power +3.3V)
// MODE(8):  (System mode)
// P3_5(9):
// P3_4(10):
// P3_3(11):  LCD_A0
// P4_5(12):  LCD_SDA
// P1_7(13):
// P1_6(14):  ---
// P1_5(15):  RXD0
// P1_4(16):  TXD0
// P1_3(17):  AN3
// P1_2(18):  AN2
// P1_1(19):  AN1
// P1_0(20):  AN0

	device::trb_io<utils::null_task> timer_b_;

	typedef utils::fifo<uint8_t, 16> buffer;
	typedef device::uart_io<device::UART0, buffer, buffer> uart;
	uart uart_;

	typedef device::adc_io<utils::null_task> adc;
	adc adc_;

	// LCD SCL: P4_2(1)
	typedef device::PORT<device::PORT4, device::bitpos::B2> SPI_SCL;
	// LCD SDA: P4_5(12)
	typedef device::PORT<device::PORT4, device::bitpos::B5> SPI_SDA;

	typedef device::spi_io<SPI_SCL, SPI_SDA, device::NULL_PORT> SPI;
	SPI		spi_;

	// LCD /CS:  P3_7(2)
	typedef device::PORT<device::PORT3, device::bitpos::B7> LCD_SEL;
	// LCD A0:   P3_3(11)
	typedef device::PORT<device::PORT3, device::bitpos::B3> LCD_A0;
	// LCD /RES: P4_7(4)
	typedef device::PORT<device::PORT4, device::bitpos::B7> LCD_RES;

	typedef chip::ST7565<SPI, LCD_SEL, LCD_A0, LCD_RES> LCD;
	LCD 	lcd_(spi_);

	typedef graphics::font6x12 afont;
	graphics::kfont_null kfont_;
	graphics::monograph<128, 32, afont> bitmap_(kfont_);

	typedef utils::fixed_string<32> string32;
	string32	string32_;

	class string_out {
	public:
		string_out() { string32_.clear(); }
		void operator () (char ch) {
			string32_ += ch;
		}
	};

	typedef utils::basic_format<string_out> sformat;
}

extern "C" {
	void sci_putch(char ch) {
		uart_.putch(ch);
	}

	char sci_getch(void) {
		return uart_.getch();
	}

	uint16_t sci_length() {
		return uart_.length();
	}

	void sci_puts(const char* str) {
		uart_.puts(str);
	}
}

extern "C" {
	const void* variable_vectors_[] __attribute__ ((section (".vvec"))) = {
		reinterpret_cast<void*>(brk_inst_),		nullptr,	// (0)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (1) flash_ready
		reinterpret_cast<void*>(null_task_),	nullptr,	// (2)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (3)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (4) コンパレーターB1
		reinterpret_cast<void*>(null_task_),	nullptr,	// (5) コンパレーターB3
		reinterpret_cast<void*>(null_task_),	nullptr,	// (6)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (7) タイマＲＣ

		reinterpret_cast<void*>(null_task_),	nullptr,	// (8)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (9)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (10)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (11)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (12)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (13) キー入力
		reinterpret_cast<void*>(null_task_),	nullptr,	// (14) A/D 変換
		reinterpret_cast<void*>(null_task_),	nullptr,	// (15)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (16)
		reinterpret_cast<void*>(uart_.isend),	nullptr,	// (17) UART0 送信
		reinterpret_cast<void*>(uart_.irecv),	nullptr,	// (18) UART0 受信
		reinterpret_cast<void*>(null_task_),	nullptr,	// (19)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (20)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (21) /INT2
		reinterpret_cast<void*>(null_task_),	nullptr,	// (22) タイマＲＪ２
		reinterpret_cast<void*>(null_task_),	nullptr,	// (23) 周期タイマ

		reinterpret_cast<void*>(timer_b_.itask),nullptr,	// (24) タイマＲＢ２
		reinterpret_cast<void*>(null_task_),	nullptr,	// (25) /INT1
		reinterpret_cast<void*>(null_task_),	nullptr,	// (26) /INT3
		reinterpret_cast<void*>(null_task_),	nullptr,	// (27)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (28)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (29) /INT0
		reinterpret_cast<void*>(null_task_),	nullptr,	// (30)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (31)
	};
}

// __attribute__ ((section (".exttext")))
int main(int argc, char *argv[])
{
	using namespace device;

// クロック関係レジスタ・プロテクト解除
	PRCR.PRC0 = 1;

// 高速オンチップオシレーターへ切り替え(20MHz)
// ※ F_CLK を設定する事（Makefile内）
	OCOCR.HOCOE = 1;
	utils::delay::micro_second(1);	// >=30uS(125KHz)
	SCKCR.HSCKSEL = 1;
	CKSTPR.SCKSEL = 1;

	PRCR.PRC0 = 0;

	// タイマーＢ初期化
	{
		uint8_t ir_level = 2;
		timer_b_.start_timer(50, ir_level);
	}

	// UART の設定 (P1_4: TXD0[out], P1_5: RXD0[in])
	// ※シリアルライターでは、RXD 端子は、P1_6 となっているので注意！
	{
		utils::PORT_MAP(utils::port_map::P14::TXD0);
		utils::PORT_MAP(utils::port_map::P15::RXD0);
		uint8_t ir_level = 1;
		uart_.start(57600, ir_level);
	}

	// ADC の設定
	{
		utils::PORT_MAP(utils::port_map::P10::AN0);
		utils::PORT_MAP(utils::port_map::P11::AN1);
		adc_.start(adc::cnv_type::CH0_CH1, adc::ch_grp::AN0_AN1, true);
	}

	// SPI を開始
	{
		spi_.start(0);
	}

	// LCD を開始
	{
		lcd_.start(0x00, true, true);  // contrast, reverse=yes, BIAS9
		bitmap_.clear(0);
	}

	utils::format("Start USB Checker\n");

	uint8_t loop = 0;
	while(1) {
		timer_b_.sync();

		adc_.scan();  // A/D scan start

		lcd_.copy(bitmap_.fb(), bitmap_.page_num());

		adc_.sync(); // A/D scan sync

		if(loop >= 25) {
			loop = 0;
			bitmap_.clear(0);
			auto v = adc_.get_value(0);
			sformat("%d") % v;
			bitmap_.draw_text(0, 0, string32_.c_str());

			auto s = timer_b_.get_count() / 50;
			auto h = s / 60;
			sformat("%02d:%02d") % (h % 100) % (s % 60);
			bitmap_.draw_text(0, 12, string32_.c_str());
		}
		++loop;
	}
}
<|endoftext|>


<commit_before>//===-- Function.cpp - Implement the Global object classes ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Function class for the VMCore library.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
#include "llvm/ParameterAttributes.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Support/LeakDetector.h"
#include "SymbolTableListTraitsImpl.h"
#include "llvm/ADT/StringExtras.h"
using namespace llvm;

BasicBlock *ilist_traits<BasicBlock>::createSentinel() {
  BasicBlock *Ret = new BasicBlock();
  // This should not be garbage monitored.
  LeakDetector::removeGarbageObject(Ret);
  return Ret;
}

iplist<BasicBlock> &ilist_traits<BasicBlock>::getList(Function *F) {
  return F->getBasicBlockList();
}

Argument *ilist_traits<Argument>::createSentinel() {
  Argument *Ret = new Argument(Type::Int32Ty);
  // This should not be garbage monitored.
  LeakDetector::removeGarbageObject(Ret);
  return Ret;
}

iplist<Argument> &ilist_traits<Argument>::getList(Function *F) {
  return F->getArgumentList();
}

// Explicit instantiations of SymbolTableListTraits since some of the methods
// are not in the public header file...
template class SymbolTableListTraits<Argument, Function, Function>;
template class SymbolTableListTraits<BasicBlock, Function, Function>;

//===----------------------------------------------------------------------===//
// Argument Implementation
//===----------------------------------------------------------------------===//

Argument::Argument(const Type *Ty, const std::string &Name, Function *Par)
  : Value(Ty, Value::ArgumentVal) {
  Parent = 0;

  // Make sure that we get added to a function
  LeakDetector::addGarbageObject(this);

  if (Par)
    Par->getArgumentList().push_back(this);
  setName(Name);
}

void Argument::setParent(Function *parent) {
  if (getParent())
    LeakDetector::addGarbageObject(this);
  Parent = parent;
  if (getParent())
    LeakDetector::removeGarbageObject(this);
}

//===----------------------------------------------------------------------===//
// ParamAttrsList Implementation
//===----------------------------------------------------------------------===//

uint16_t
ParamAttrsList::getParamAttrs(uint16_t Index) const {
  unsigned limit = attrs.size();
  for (unsigned i = 0; i < limit; ++i)
    if (attrs[i].index == Index)
      return attrs[i].attrs;
  return ParamAttr::None;
}

std::string
ParamAttrsList::getParamAttrsText(uint16_t Attrs) {
  std::string Result;
  if (Attrs & ParamAttr::ZExt)
    Result += "zext ";
  if (Attrs & ParamAttr::SExt)
    Result += "sext ";
  if (Attrs & ParamAttr::NoReturn)
    Result += "noreturn ";
  if (Attrs & ParamAttr::NoUnwind)
    Result += "nounwind ";
  if (Attrs & ParamAttr::InReg)
    Result += "inreg ";
  if (Attrs & ParamAttr::StructRet)
    Result += "sret ";
  return Result;
}

void
ParamAttrsList::addAttributes(uint16_t Index, uint16_t Attrs) {
  // First, try to replace an existing one
  for (unsigned i = 0; i < attrs.size(); ++i)
    if (attrs[i].index == Index) {
      attrs[i].attrs |= Attrs;
      return;
    }

  // If not found, add a new one
  ParamAttrsWithIndex Val;
  Val.attrs = Attrs;
  Val.index = Index;
  attrs.push_back(Val);
}

void
ParamAttrsList::removeAttributes(uint16_t Index, uint16_t Attrs) {
  // Find the index from which to remove the attributes
  for (unsigned i = 0; i < attrs.size(); ++i)
    if (attrs[i].index == Index) {
      attrs[i].attrs &= ~Attrs;
      if (attrs[i].attrs == ParamAttr::None)
        attrs.erase(&attrs[i]);
      return;
    }

  // The index wasn't found above
  assert(0 && "Index not found for removeAttributes");
}

//===----------------------------------------------------------------------===//
// Function Implementation
//===----------------------------------------------------------------------===//

Function::Function(const FunctionType *Ty, LinkageTypes Linkage,
                   const std::string &name, Module *ParentModule)
  : GlobalValue(PointerType::get(Ty), Value::FunctionVal, 0, 0, Linkage, name) {
  ParamAttrs = 0;
  CallingConvention = 0;
  BasicBlocks.setItemParent(this);
  BasicBlocks.setParent(this);
  ArgumentList.setItemParent(this);
  ArgumentList.setParent(this);
  SymTab = new ValueSymbolTable();

  assert((getReturnType()->isFirstClassType() ||getReturnType() == Type::VoidTy)
         && "LLVM functions cannot return aggregate values!");

  // Create the arguments vector, all arguments start out unnamed.
  for (unsigned i = 0, e = Ty->getNumParams(); i != e; ++i) {
    assert(Ty->getParamType(i) != Type::VoidTy &&
           "Cannot have void typed arguments!");
    ArgumentList.push_back(new Argument(Ty->getParamType(i)));
  }

  // Make sure that we get added to a function
  LeakDetector::addGarbageObject(this);

  if (ParentModule)
    ParentModule->getFunctionList().push_back(this);
}

Function::~Function() {
  dropAllReferences();    // After this it is safe to delete instructions.

  // Delete all of the method arguments and unlink from symbol table...
  ArgumentList.clear();
  ArgumentList.setParent(0);
  delete SymTab;
}

void Function::setParent(Module *parent) {
  if (getParent())
    LeakDetector::addGarbageObject(this);
  Parent = parent;
  if (getParent())
    LeakDetector::removeGarbageObject(this);
}

const FunctionType *Function::getFunctionType() const {
  return cast<FunctionType>(getType()->getElementType());
}

bool Function::isVarArg() const {
  return getFunctionType()->isVarArg();
}

const Type *Function::getReturnType() const {
  return getFunctionType()->getReturnType();
}

void Function::removeFromParent() {
  getParent()->getFunctionList().remove(this);
}

void Function::eraseFromParent() {
  getParent()->getFunctionList().erase(this);
}

// dropAllReferences() - This function causes all the subinstructions to "let
// go" of all references that they are maintaining.  This allows one to
// 'delete' a whole class at a time, even though there may be circular
// references... first all references are dropped, and all use counts go to
// zero.  Then everything is deleted for real.  Note that no operations are
// valid on an object that has "dropped all references", except operator
// delete.
//
void Function::dropAllReferences() {
  for (iterator I = begin(), E = end(); I != E; ++I)
    I->dropAllReferences();
  BasicBlocks.clear();    // Delete all basic blocks...
}

/// getIntrinsicID - This method returns the ID number of the specified
/// function, or Intrinsic::not_intrinsic if the function is not an
/// intrinsic, or if the pointer is null.  This value is always defined to be
/// zero to allow easy checking for whether a function is intrinsic or not.  The
/// particular intrinsic functions which correspond to this value are defined in
/// llvm/Intrinsics.h.
///
unsigned Function::getIntrinsicID(bool noAssert) const {
  const ValueName *ValName = this->getValueName();
  if (!ValName)
    return 0;
  unsigned Len = ValName->getKeyLength();
  const char *Name = ValName->getKeyData();

  if (Len <= 5 || Name[4] != '.' || Name[0] != 'l' || Name[1] != 'l'
      || Name[2] != 'v' || Name[3] != 'm')
    return 0;  // All intrinsics start with 'llvm.'

  assert((Len != 5 || noAssert) && "'llvm.' is an invalid intrinsic name!");

#define GET_FUNCTION_RECOGNIZER
#include "llvm/Intrinsics.gen"
#undef GET_FUNCTION_RECOGNIZER
  assert(noAssert && "Invalid LLVM intrinsic name");
  return 0;
}

std::string Intrinsic::getName(ID id, const Type **Tys, unsigned numTys) {
  assert(id < num_intrinsics && "Invalid intrinsic ID!");
  const char * const Table[] = {
    "not_intrinsic",
#define GET_INTRINSIC_NAME_TABLE
#include "llvm/Intrinsics.gen"
#undef GET_INTRINSIC_NAME_TABLE
  };
  if (numTys == 0)
    return Table[id];
  std::string Result(Table[id]);
  for (unsigned i = 0; i < numTys; ++i)
    if (Tys[i])
      Result += "." + Tys[i]->getDescription();
  return Result;
}

const FunctionType *Intrinsic::getType(ID id, const Type **Tys,
                                       uint32_t numTys) {
  const Type *ResultTy = NULL;
  std::vector<const Type*> ArgTys;
  bool IsVarArg = false;

#define GET_INTRINSIC_GENERATOR
#include "llvm/Intrinsics.gen"
#undef GET_INTRINSIC_GENERATOR

  return FunctionType::get(ResultTy, ArgTys, IsVarArg);
}

Function *Intrinsic::getDeclaration(Module *M, ID id, const Type **Tys,
                                    unsigned numTys) {
// There can never be multiple globals with the same name of different types,
// because intrinsics must be a specific type.
  return cast<Function>(M->getOrInsertFunction(getName(id, Tys, numTys),
                                               getType(id, Tys, numTys)));
}

Value *IntrinsicInst::StripPointerCasts(Value *Ptr) {
  if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Ptr)) {
    if (CE->getOpcode() == Instruction::BitCast) {
      if (isa<PointerType>(CE->getOperand(0)->getType()))
        return StripPointerCasts(CE->getOperand(0));
    } else if (CE->getOpcode() == Instruction::GetElementPtr) {
      for (unsigned i = 1, e = CE->getNumOperands(); i != e; ++i)
        if (!CE->getOperand(i)->isNullValue())
          return Ptr;
      return StripPointerCasts(CE->getOperand(0));
    }
    return Ptr;
  }

  if (BitCastInst *CI = dyn_cast<BitCastInst>(Ptr)) {
    if (isa<PointerType>(CI->getOperand(0)->getType()))
      return StripPointerCasts(CI->getOperand(0));
  } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Ptr)) {
    for (unsigned i = 1, e = GEP->getNumOperands(); i != e; ++i)
      if (!isa<Constant>(GEP->getOperand(i)) ||
          !cast<Constant>(GEP->getOperand(i))->isNullValue())
        return Ptr;
    return StripPointerCasts(GEP->getOperand(0));
  }
  return Ptr;
}

// vim: sw=2 ai
<commit_msg>Don't return 0 if the len == 5, let the assert handle that case. Thanks, Chris.<commit_after>//===-- Function.cpp - Implement the Global object classes ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Function class for the VMCore library.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
#include "llvm/ParameterAttributes.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Support/LeakDetector.h"
#include "SymbolTableListTraitsImpl.h"
#include "llvm/ADT/StringExtras.h"
using namespace llvm;

BasicBlock *ilist_traits<BasicBlock>::createSentinel() {
  BasicBlock *Ret = new BasicBlock();
  // This should not be garbage monitored.
  LeakDetector::removeGarbageObject(Ret);
  return Ret;
}

iplist<BasicBlock> &ilist_traits<BasicBlock>::getList(Function *F) {
  return F->getBasicBlockList();
}

Argument *ilist_traits<Argument>::createSentinel() {
  Argument *Ret = new Argument(Type::Int32Ty);
  // This should not be garbage monitored.
  LeakDetector::removeGarbageObject(Ret);
  return Ret;
}

iplist<Argument> &ilist_traits<Argument>::getList(Function *F) {
  return F->getArgumentList();
}

// Explicit instantiations of SymbolTableListTraits since some of the methods
// are not in the public header file...
template class SymbolTableListTraits<Argument, Function, Function>;
template class SymbolTableListTraits<BasicBlock, Function, Function>;

//===----------------------------------------------------------------------===//
// Argument Implementation
//===----------------------------------------------------------------------===//

Argument::Argument(const Type *Ty, const std::string &Name, Function *Par)
  : Value(Ty, Value::ArgumentVal) {
  Parent = 0;

  // Make sure that we get added to a function
  LeakDetector::addGarbageObject(this);

  if (Par)
    Par->getArgumentList().push_back(this);
  setName(Name);
}

void Argument::setParent(Function *parent) {
  if (getParent())
    LeakDetector::addGarbageObject(this);
  Parent = parent;
  if (getParent())
    LeakDetector::removeGarbageObject(this);
}

//===----------------------------------------------------------------------===//
// ParamAttrsList Implementation
//===----------------------------------------------------------------------===//

uint16_t
ParamAttrsList::getParamAttrs(uint16_t Index) const {
  unsigned limit = attrs.size();
  for (unsigned i = 0; i < limit; ++i)
    if (attrs[i].index == Index)
      return attrs[i].attrs;
  return ParamAttr::None;
}

std::string
ParamAttrsList::getParamAttrsText(uint16_t Attrs) {
  std::string Result;
  if (Attrs & ParamAttr::ZExt)
    Result += "zext ";
  if (Attrs & ParamAttr::SExt)
    Result += "sext ";
  if (Attrs & ParamAttr::NoReturn)
    Result += "noreturn ";
  if (Attrs & ParamAttr::NoUnwind)
    Result += "nounwind ";
  if (Attrs & ParamAttr::InReg)
    Result += "inreg ";
  if (Attrs & ParamAttr::StructRet)
    Result += "sret ";
  return Result;
}

void
ParamAttrsList::addAttributes(uint16_t Index, uint16_t Attrs) {
  // First, try to replace an existing one
  for (unsigned i = 0; i < attrs.size(); ++i)
    if (attrs[i].index == Index) {
      attrs[i].attrs |= Attrs;
      return;
    }

  // If not found, add a new one
  ParamAttrsWithIndex Val;
  Val.attrs = Attrs;
  Val.index = Index;
  attrs.push_back(Val);
}

void
ParamAttrsList::removeAttributes(uint16_t Index, uint16_t Attrs) {
  // Find the index from which to remove the attributes
  for (unsigned i = 0; i < attrs.size(); ++i)
    if (attrs[i].index == Index) {
      attrs[i].attrs &= ~Attrs;
      if (attrs[i].attrs == ParamAttr::None)
        attrs.erase(&attrs[i]);
      return;
    }

  // The index wasn't found above
  assert(0 && "Index not found for removeAttributes");
}

//===----------------------------------------------------------------------===//
// Function Implementation
//===----------------------------------------------------------------------===//

Function::Function(const FunctionType *Ty, LinkageTypes Linkage,
                   const std::string &name, Module *ParentModule)
  : GlobalValue(PointerType::get(Ty), Value::FunctionVal, 0, 0, Linkage, name) {
  ParamAttrs = 0;
  CallingConvention = 0;
  BasicBlocks.setItemParent(this);
  BasicBlocks.setParent(this);
  ArgumentList.setItemParent(this);
  ArgumentList.setParent(this);
  SymTab = new ValueSymbolTable();

  assert((getReturnType()->isFirstClassType() ||getReturnType() == Type::VoidTy)
         && "LLVM functions cannot return aggregate values!");

  // Create the arguments vector, all arguments start out unnamed.
  for (unsigned i = 0, e = Ty->getNumParams(); i != e; ++i) {
    assert(Ty->getParamType(i) != Type::VoidTy &&
           "Cannot have void typed arguments!");
    ArgumentList.push_back(new Argument(Ty->getParamType(i)));
  }

  // Make sure that we get added to a function
  LeakDetector::addGarbageObject(this);

  if (ParentModule)
    ParentModule->getFunctionList().push_back(this);
}

Function::~Function() {
  dropAllReferences();    // After this it is safe to delete instructions.

  // Delete all of the method arguments and unlink from symbol table...
  ArgumentList.clear();
  ArgumentList.setParent(0);
  delete SymTab;
}

void Function::setParent(Module *parent) {
  if (getParent())
    LeakDetector::addGarbageObject(this);
  Parent = parent;
  if (getParent())
    LeakDetector::removeGarbageObject(this);
}

const FunctionType *Function::getFunctionType() const {
  return cast<FunctionType>(getType()->getElementType());
}

bool Function::isVarArg() const {
  return getFunctionType()->isVarArg();
}

const Type *Function::getReturnType() const {
  return getFunctionType()->getReturnType();
}

void Function::removeFromParent() {
  getParent()->getFunctionList().remove(this);
}

void Function::eraseFromParent() {
  getParent()->getFunctionList().erase(this);
}

// dropAllReferences() - This function causes all the subinstructions to "let
// go" of all references that they are maintaining.  This allows one to
// 'delete' a whole class at a time, even though there may be circular
// references... first all references are dropped, and all use counts go to
// zero.  Then everything is deleted for real.  Note that no operations are
// valid on an object that has "dropped all references", except operator
// delete.
//
void Function::dropAllReferences() {
  for (iterator I = begin(), E = end(); I != E; ++I)
    I->dropAllReferences();
  BasicBlocks.clear();    // Delete all basic blocks...
}

/// getIntrinsicID - This method returns the ID number of the specified
/// function, or Intrinsic::not_intrinsic if the function is not an
/// intrinsic, or if the pointer is null.  This value is always defined to be
/// zero to allow easy checking for whether a function is intrinsic or not.  The
/// particular intrinsic functions which correspond to this value are defined in
/// llvm/Intrinsics.h.
///
unsigned Function::getIntrinsicID(bool noAssert) const {
  const ValueName *ValName = this->getValueName();
  if (!ValName)
    return 0;
  unsigned Len = ValName->getKeyLength();
  const char *Name = ValName->getKeyData();

  if (Len < 5 || Name[4] != '.' || Name[0] != 'l' || Name[1] != 'l'
      || Name[2] != 'v' || Name[3] != 'm')
    return 0;  // All intrinsics start with 'llvm.'

  assert((Len != 5 || noAssert) && "'llvm.' is an invalid intrinsic name!");

#define GET_FUNCTION_RECOGNIZER
#include "llvm/Intrinsics.gen"
#undef GET_FUNCTION_RECOGNIZER
  assert(noAssert && "Invalid LLVM intrinsic name");
  return 0;
}

std::string Intrinsic::getName(ID id, const Type **Tys, unsigned numTys) {
  assert(id < num_intrinsics && "Invalid intrinsic ID!");
  const char * const Table[] = {
    "not_intrinsic",
#define GET_INTRINSIC_NAME_TABLE
#include "llvm/Intrinsics.gen"
#undef GET_INTRINSIC_NAME_TABLE
  };
  if (numTys == 0)
    return Table[id];
  std::string Result(Table[id]);
  for (unsigned i = 0; i < numTys; ++i)
    if (Tys[i])
      Result += "." + Tys[i]->getDescription();
  return Result;
}

const FunctionType *Intrinsic::getType(ID id, const Type **Tys,
                                       uint32_t numTys) {
  const Type *ResultTy = NULL;
  std::vector<const Type*> ArgTys;
  bool IsVarArg = false;

#define GET_INTRINSIC_GENERATOR
#include "llvm/Intrinsics.gen"
#undef GET_INTRINSIC_GENERATOR

  return FunctionType::get(ResultTy, ArgTys, IsVarArg);
}

Function *Intrinsic::getDeclaration(Module *M, ID id, const Type **Tys,
                                    unsigned numTys) {
// There can never be multiple globals with the same name of different types,
// because intrinsics must be a specific type.
  return cast<Function>(M->getOrInsertFunction(getName(id, Tys, numTys),
                                               getType(id, Tys, numTys)));
}

Value *IntrinsicInst::StripPointerCasts(Value *Ptr) {
  if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Ptr)) {
    if (CE->getOpcode() == Instruction::BitCast) {
      if (isa<PointerType>(CE->getOperand(0)->getType()))
        return StripPointerCasts(CE->getOperand(0));
    } else if (CE->getOpcode() == Instruction::GetElementPtr) {
      for (unsigned i = 1, e = CE->getNumOperands(); i != e; ++i)
        if (!CE->getOperand(i)->isNullValue())
          return Ptr;
      return StripPointerCasts(CE->getOperand(0));
    }
    return Ptr;
  }

  if (BitCastInst *CI = dyn_cast<BitCastInst>(Ptr)) {
    if (isa<PointerType>(CI->getOperand(0)->getType()))
      return StripPointerCasts(CI->getOperand(0));
  } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Ptr)) {
    for (unsigned i = 1, e = GEP->getNumOperands(); i != e; ++i)
      if (!isa<Constant>(GEP->getOperand(i)) ||
          !cast<Constant>(GEP->getOperand(i))->isNullValue())
        return Ptr;
    return StripPointerCasts(GEP->getOperand(0));
  }
  return Ptr;
}

// vim: sw=2 ai
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "WebURLRequest.h"

#include "WebHTTPHeaderVisitor.h"
#include "WebURL.h"
#include "WebURLRequestPrivate.h"

#include "ResourceRequest.h"

using namespace WebCore;

namespace WebKit {

// The standard implementation of WebURLRequestPrivate, which maintains
// ownership of a ResourceRequest instance.
class WebURLRequestPrivateImpl : public WebURLRequestPrivate {
public:
    WebURLRequestPrivateImpl()
    {
        m_resourceRequest = &m_resourceRequestAllocation;
    }

    WebURLRequestPrivateImpl(const WebURLRequestPrivate* p)
        : m_resourceRequestAllocation(*p->m_resourceRequest)
    {
        m_resourceRequest = &m_resourceRequestAllocation;
    }

    virtual void dispose() { delete this; }

    ResourceRequest m_resourceRequestAllocation;
};

void WebURLRequest::initialize()
{
    assign(new WebURLRequestPrivateImpl());
}

void WebURLRequest::reset()
{
    assign(0);
}

void WebURLRequest::assign(const WebURLRequest& r)
{
    assign(r.m_private ? new WebURLRequestPrivateImpl(r.m_private) : 0);
}

WebURL WebURLRequest::url() const
{
    return m_private->m_resourceRequest->url();
}

void WebURLRequest::setURL(const WebURL& url)
{
    m_private->m_resourceRequest->setURL(url);
}

WebURL WebURLRequest::firstPartyForCookies() const
{
    return m_private->m_resourceRequest->firstPartyForCookies();
}

void WebURLRequest::setFirstPartyForCookies(const WebURL& firstPartyForCookies)
{
    m_private->m_resourceRequest->setFirstPartyForCookies(firstPartyForCookies);
}

WebURLRequest::CachePolicy WebURLRequest::cachePolicy() const
{
    return static_cast<WebURLRequest::CachePolicy>(
        m_private->m_resourceRequest->cachePolicy());
}

void WebURLRequest::setCachePolicy(CachePolicy cachePolicy)
{
    m_private->m_resourceRequest->setCachePolicy(
        static_cast<ResourceRequestCachePolicy>(cachePolicy));
}

WebString WebURLRequest::httpMethod() const
{
    return m_private->m_resourceRequest->httpMethod();
}

void WebURLRequest::setHTTPMethod(const WebString& httpMethod)
{
    m_private->m_resourceRequest->setHTTPMethod(httpMethod);
}

WebString WebURLRequest::httpHeaderField(const WebString& name) const
{
    return m_private->m_resourceRequest->httpHeaderField(String(name));
}

void WebURLRequest::setHTTPHeaderField(const WebString& name, const WebString& value)
{
    m_private->m_resourceRequest->setHTTPHeaderField(String(name), value);
}

void WebURLRequest::addHTTPHeaderField(const WebString& name, const WebString& value)
{
    m_private->m_resourceRequest->addHTTPHeaderField(String(name), value);
}

void WebURLRequest::clearHTTPHeaderField(const WebString& name)
{
    // FIXME: Add a clearHTTPHeaderField method to ResourceRequest.
    const HTTPHeaderMap& map = m_private->m_resourceRequest->httpHeaderFields();
    const_cast<HTTPHeaderMap*>(&map)->remove(String(name));
}

void WebURLRequest::visitHTTPHeaderFields(WebHTTPHeaderVisitor* visitor) const
{
    const HTTPHeaderMap& map = m_private->m_resourceRequest->httpHeaderFields();
    for (HTTPHeaderMap::const_iterator it = map.begin(); it != map.end(); ++it)
        visitor->visitHeader(String(it->first), it->second);
}

WebHTTPBody WebURLRequest::httpBody() const
{
    return m_private->m_resourceRequest->httpBody();
}

void WebURLRequest::setHTTPBody(const WebHTTPBody& httpBody)
{
    m_private->m_resourceRequest->setHTTPBody(httpBody);
}

bool WebURLRequest::reportUploadProgress() const
{
    return m_private->m_resourceRequest->reportUploadProgress();
}

void WebURLRequest::setReportUploadProgress(bool reportUploadProgress)
{
    m_private->m_resourceRequest->setReportUploadProgress(reportUploadProgress);
}

WebURLRequest::TargetType WebURLRequest::targetType() const
{
    return static_cast<TargetType>(m_private->m_resourceRequest->targetType());
}

void WebURLRequest::setTargetType(TargetType targetType)
{
    m_private->m_resourceRequest->setTargetType(
        static_cast<ResourceRequest::TargetType>(targetType));
}

int WebURLRequest::requestorID() const
{
    return m_private->m_resourceRequest->requestorID();
}

void WebURLRequest::setRequestorID(int requestorID)
{
    m_private->m_resourceRequest->setRequestorID(requestorID);
}

int WebURLRequest::requestorProcessID() const
{
    return m_private->m_resourceRequest->requestorProcessID();
}

void WebURLRequest::setRequestorProcessID(int requestorProcessID)
{
    m_private->m_resourceRequest->setRequestorProcessID(requestorProcessID);
}

int WebURLRequest::appCacheContextID() const
{
    return m_private->m_resourceRequest->appCacheContextID();
}

void WebURLRequest::setAppCacheContextID(int appCacheContextID)
{
    m_private->m_resourceRequest->setAppCacheContextID(appCacheContextID);
}

WebCString WebURLRequest::securityInfo() const
{
    return m_private->m_resourceRequest->securityInfo();
}

void WebURLRequest::setSecurityInfo(const WebCString& securityInfo)
{
    m_private->m_resourceRequest->setSecurityInfo(securityInfo);
}

ResourceRequest& WebURLRequest::toMutableResourceRequest()
{
    ASSERT(m_private);
    ASSERT(m_private->m_resourceRequest);

    return *m_private->m_resourceRequest;
}

const ResourceRequest& WebURLRequest::toResourceRequest() const
{
    ASSERT(m_private);
    ASSERT(m_private->m_resourceRequest);

    return *m_private->m_resourceRequest;
}

void WebURLRequest::assign(WebURLRequestPrivate* p)
{
    if (m_private == p)
        return;
    if (m_private)
        m_private->dispose();
    m_private = p;
}

} // namespace WebKit
<commit_msg>Fix GCC build bustage.<commit_after>/*
 * Copyright (C) 2009 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "WebURLRequest.h"

#include "WebHTTPBody.h"
#include "WebHTTPHeaderVisitor.h"
#include "WebURL.h"
#include "WebURLRequestPrivate.h"

#include "ResourceRequest.h"

using namespace WebCore;

namespace WebKit {

// The standard implementation of WebURLRequestPrivate, which maintains
// ownership of a ResourceRequest instance.
class WebURLRequestPrivateImpl : public WebURLRequestPrivate {
public:
    WebURLRequestPrivateImpl()
    {
        m_resourceRequest = &m_resourceRequestAllocation;
    }

    WebURLRequestPrivateImpl(const WebURLRequestPrivate* p)
        : m_resourceRequestAllocation(*p->m_resourceRequest)
    {
        m_resourceRequest = &m_resourceRequestAllocation;
    }

    virtual void dispose() { delete this; }

    ResourceRequest m_resourceRequestAllocation;
};

void WebURLRequest::initialize()
{
    assign(new WebURLRequestPrivateImpl());
}

void WebURLRequest::reset()
{
    assign(0);
}

void WebURLRequest::assign(const WebURLRequest& r)
{
    assign(r.m_private ? new WebURLRequestPrivateImpl(r.m_private) : 0);
}

WebURL WebURLRequest::url() const
{
    return m_private->m_resourceRequest->url();
}

void WebURLRequest::setURL(const WebURL& url)
{
    m_private->m_resourceRequest->setURL(url);
}

WebURL WebURLRequest::firstPartyForCookies() const
{
    return m_private->m_resourceRequest->firstPartyForCookies();
}

void WebURLRequest::setFirstPartyForCookies(const WebURL& firstPartyForCookies)
{
    m_private->m_resourceRequest->setFirstPartyForCookies(firstPartyForCookies);
}

WebURLRequest::CachePolicy WebURLRequest::cachePolicy() const
{
    return static_cast<WebURLRequest::CachePolicy>(
        m_private->m_resourceRequest->cachePolicy());
}

void WebURLRequest::setCachePolicy(CachePolicy cachePolicy)
{
    m_private->m_resourceRequest->setCachePolicy(
        static_cast<ResourceRequestCachePolicy>(cachePolicy));
}

WebString WebURLRequest::httpMethod() const
{
    return m_private->m_resourceRequest->httpMethod();
}

void WebURLRequest::setHTTPMethod(const WebString& httpMethod)
{
    m_private->m_resourceRequest->setHTTPMethod(httpMethod);
}

WebString WebURLRequest::httpHeaderField(const WebString& name) const
{
    return m_private->m_resourceRequest->httpHeaderField(String(name));
}

void WebURLRequest::setHTTPHeaderField(const WebString& name, const WebString& value)
{
    m_private->m_resourceRequest->setHTTPHeaderField(String(name), value);
}

void WebURLRequest::addHTTPHeaderField(const WebString& name, const WebString& value)
{
    m_private->m_resourceRequest->addHTTPHeaderField(String(name), value);
}

void WebURLRequest::clearHTTPHeaderField(const WebString& name)
{
    // FIXME: Add a clearHTTPHeaderField method to ResourceRequest.
    const HTTPHeaderMap& map = m_private->m_resourceRequest->httpHeaderFields();
    const_cast<HTTPHeaderMap*>(&map)->remove(String(name));
}

void WebURLRequest::visitHTTPHeaderFields(WebHTTPHeaderVisitor* visitor) const
{
    const HTTPHeaderMap& map = m_private->m_resourceRequest->httpHeaderFields();
    for (HTTPHeaderMap::const_iterator it = map.begin(); it != map.end(); ++it)
        visitor->visitHeader(String(it->first), it->second);
}

WebHTTPBody WebURLRequest::httpBody() const
{
    return m_private->m_resourceRequest->httpBody();
}

void WebURLRequest::setHTTPBody(const WebHTTPBody& httpBody)
{
    m_private->m_resourceRequest->setHTTPBody(httpBody);
}

bool WebURLRequest::reportUploadProgress() const
{
    return m_private->m_resourceRequest->reportUploadProgress();
}

void WebURLRequest::setReportUploadProgress(bool reportUploadProgress)
{
    m_private->m_resourceRequest->setReportUploadProgress(reportUploadProgress);
}

WebURLRequest::TargetType WebURLRequest::targetType() const
{
    return static_cast<TargetType>(m_private->m_resourceRequest->targetType());
}

void WebURLRequest::setTargetType(TargetType targetType)
{
    m_private->m_resourceRequest->setTargetType(
        static_cast<ResourceRequest::TargetType>(targetType));
}

int WebURLRequest::requestorID() const
{
    return m_private->m_resourceRequest->requestorID();
}

void WebURLRequest::setRequestorID(int requestorID)
{
    m_private->m_resourceRequest->setRequestorID(requestorID);
}

int WebURLRequest::requestorProcessID() const
{
    return m_private->m_resourceRequest->requestorProcessID();
}

void WebURLRequest::setRequestorProcessID(int requestorProcessID)
{
    m_private->m_resourceRequest->setRequestorProcessID(requestorProcessID);
}

int WebURLRequest::appCacheContextID() const
{
    return m_private->m_resourceRequest->appCacheContextID();
}

void WebURLRequest::setAppCacheContextID(int appCacheContextID)
{
    m_private->m_resourceRequest->setAppCacheContextID(appCacheContextID);
}

WebCString WebURLRequest::securityInfo() const
{
    return m_private->m_resourceRequest->securityInfo();
}

void WebURLRequest::setSecurityInfo(const WebCString& securityInfo)
{
    m_private->m_resourceRequest->setSecurityInfo(securityInfo);
}

ResourceRequest& WebURLRequest::toMutableResourceRequest()
{
    ASSERT(m_private);
    ASSERT(m_private->m_resourceRequest);

    return *m_private->m_resourceRequest;
}

const ResourceRequest& WebURLRequest::toResourceRequest() const
{
    ASSERT(m_private);
    ASSERT(m_private->m_resourceRequest);

    return *m_private->m_resourceRequest;
}

void WebURLRequest::assign(WebURLRequestPrivate* p)
{
    if (m_private == p)
        return;
    if (m_private)
        m_private->dispose();
    m_private = p;
}

} // namespace WebKit
<|endoftext|>


<commit_before>/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2013, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

/** @file
    Random Number Generator implementation
*/

#include <cstdlib>
#include <ctime>
#include <cmath> // For ldexp.
#include <iostream> // for istream, ostream

#include <capnp/message.h>
#include <capnp/serialize.h>
#include <kj/std/iostream.h>

#include <nupic/proto/RandomProto.capnp.h>
#include <nupic/utils/Log.hpp>
#include <nupic/utils/Random.hpp>
#include <nupic/utils/StringUtils.hpp>

using namespace nupic;
Random* Random::theInstanceP_ = nullptr;
RandomSeedFuncPtr Random::seeder_ = nullptr;

const UInt32 Random::MAX32 = (UInt32)((Int32)(-1));
const UInt64 Random::MAX64 = (UInt64)((Int64)(-1));

static NTA_UInt64 badSeeder()
{
  NTA_THROW << "Logic error in initialization of Random subsystem.";
  return 0;
}

/**
 * Using an Impl provides two things:
 * 1) ability to specify different algorithms (not yet implemented)
 * 2) constructors Random(long) and Random(string) without code duplication.
 */

// Algorithm-level implementation of the random number generator.
// When we have different algorithms RandomImpl will become an interface
// class and subclasses will implement specific algorithms

namespace nupic
{
  class RandomImpl
  {
  public:
    RandomImpl(UInt64 seed);
    ~RandomImpl() {};
    void write(RandomImplProto::Builder& proto) const;
    void read(RandomImplProto::Reader& proto);
    UInt32 getUInt32();
    // Note: copy constructor and operator= are needed
    // The default is ok.
  private:
    friend std::ostream& operator<<(std::ostream& outStream, const RandomImpl& r);
    friend std::istream& operator>>(std::istream& inStream, RandomImpl& r);
    // internal state
    static const int stateSize_ = 31;
    static const int sep_ = 3;
    int state_[stateSize_];
    int rptr_;
    int fptr_;

  };
};

Random::Random(const Random& r)
{
  NTA_CHECK(r.impl_ != nullptr);
  seed_ = r.seed_;
  impl_ = new RandomImpl(*r.impl_);
}

void Random::write(std::ostream& stream) const
{
  capnp::MallocMessageBuilder message;
  auto proto = message.initRoot<RandomProto>();
  write(proto);

  kj::std::StdOutputStream out(stream);
  capnp::writeMessage(out, message);
}

void Random::write(RandomProto::Builder& proto) const
{
  // save Random state
  proto.setSeed(seed_);

  // save RandomImpl state
  auto implProto = proto.initImpl();
  impl_->write(implProto);
}

void Random::read(std::istream& stream)
{
  kj::std::StdInputStream in(stream);
  capnp::InputStreamMessageReader message(in);
  RandomProto::Reader proto = message.getRoot<RandomProto>();
  read(proto);
}

void Random::read(RandomProto::Reader& proto)
{
  // load Random state
  seed_ = proto.getSeed();

  // load RandomImpl state
  auto implProto = proto.getImpl();
  impl_->read(implProto);
}

void Random::reseed(UInt64 seed)
{
  seed_ = seed;
  if (impl_)
    delete impl_;
  impl_ = new RandomImpl(seed);
}

Random& Random::operator=(const Random& other)
{
  if (this != &other)
  {
    seed_ = other.seed_;
    if (impl_)
      delete impl_;
    NTA_CHECK(other.impl_ != nullptr);
    impl_ = new RandomImpl(*other.impl_);
  }
  return *this;
}

Random::~Random()
{
  delete impl_;
}

Random::Random(UInt64 seed)
{
  // Get the seeder even if we don't need it, because
  // this will have the side effect of allocating the
  // singleton if necessary. The singleton will actuallly
  // be allocated in a recursive call to the Random
  // constructor, with seed = 0 and
  RandomSeedFuncPtr seeder = getSeeder();
  NTA_CHECK(seeder != nullptr);
  if (seed == 0) {
    if (seeder == badSeeder) {
      // we are constructing the singleton
      seed_ = (UInt64)time(nullptr);
    } else {
      seed_ = seeder();
    }
  } else {
    seed_ = seed;
  }
  // if seed is zero at this point, there is a logic error.
  NTA_CHECK(seed_ != 0);
  impl_ = new RandomImpl(seed_);
}

RandomSeedFuncPtr Random::getSeeder()
{
  if (seeder_ == nullptr)
  {
    NTA_CHECK(theInstanceP_ == nullptr);
    // set the seeder to something not NULL
    // so the constructor below will not
    // see a NULL pointer and call us recursively.
    seeder_ = badSeeder;
    theInstanceP_ = new Random(0);
    seeder_ = GetRandomSeed;
  }
  return seeder_;
}

void Random::initSeeder(const RandomSeedFuncPtr r)
{
  NTA_CHECK(r != nullptr);
  seeder_ = r;
}

void Random::shutdown()
{
  if (theInstanceP_ != nullptr)
  {
    delete theInstanceP_;
    theInstanceP_ = nullptr;
  }
}

UInt32 Random::getUInt32(const UInt32 max)
{
  NTA_ASSERT(max > 0);
  UInt32 smax = Random::MAX32 - (Random::MAX32 % max);
  UInt32 sample;
  do {
    sample = impl_->getUInt32();
  } while (sample > smax);

  // NTA_WARN << "Random32(" << max << ") -> " << sample % max << " smax = " << smax;
  return sample % max;
}

UInt64 Random::getUInt64(const UInt64 max)
{
  NTA_ASSERT(max > 0);
  UInt64 smax = Random::MAX64 - (Random::MAX64 % max);
  UInt64 sample, lo, hi;
  do {
    lo = impl_->getUInt32();
    hi = impl_->getUInt32();
    sample = lo | (hi << 32);
  } while(sample > smax);
  // NTA_WARN << "Random64(" << max << ") -> " << sample % max << " smax = " << smax;

  return sample % max;
}

double Random::getReal64()
{
  const int mantissaBits = 48;
  const UInt64 max = (UInt64)0x1U << mantissaBits;
  UInt64 value = getUInt64(max);
  Real64 dvalue = (Real64) value; // No loss because we only need the 48 mantissa bits.
  Real64 returnval = ::ldexp(dvalue, -mantissaBits);
  // NTA_WARN << "RandomReal -> " << returnval;
  return returnval;
}

// ---- RandomImpl follows ----

UInt32 RandomImpl::getUInt32(void)
{
  long i;
#ifdef RANDOM_SUPERDEBUG
  printf("Random::get *fptr = %ld; *rptr = %ld fptr = %ld rptr = %ld\n", state_[fptr_], state_[rptr_], fptr_, rptr_);
#endif
  state_[fptr_] += state_[rptr_];
  i = state_[fptr_];
  i = (i >> 1) & 0x7fffffff;	/* chucking least random bit */
  if (++fptr_ >= stateSize_) {
    fptr_ = 0;
    ++rptr_;
  } else if (++rptr_ >= stateSize_)
    rptr_ = 0;
#ifdef RANDOM_SUPERDEBUG
  printf("Random::get returning %ld\n", i);
  for (int j = 0; j < stateSize_; j++) {
    printf("Random:get: %d  %ld\n", j, state_[j]);
  }
#endif

  return((UInt32)i);
}

RandomImpl::RandomImpl(UInt64 seed)
{

  /**
   * Initialize our state. Taken from BSD source for random()
   */
  state_[0] = (int)seed;
  for (long i = 1; i < stateSize_; i++) {
    /*
     * Implement the following, without overflowing 31 bits:
     *
     *	state[i] = (16807 * state[i - 1]) % 2147483647;
     *
     *	2^31-1 (prime) = 2147483647 = 127773*16807+2836
     */
    ldiv_t val = ldiv(state_[i-1], 127773);
    long test = 16807 * val.rem - 2836 * val.quot;
    state_[i] = test + (test < 0 ? 2147483647 : 0);
  }
  fptr_ = sep_;
  rptr_ = 0;
#ifdef RANDOM_SUPERDEBUG
  printf("Random: init for seed = %lu\n", seed);
  for (int i = 0; i < stateSize_; i++) {
    printf("Random: %d  %ld\n", i, state_[i]);
  }
#endif

  for (long i = 0; i < 10 * stateSize_; i++)
    (void)getUInt32();
#ifdef RANDOM_SUPERDEBUG
  printf("Random: after init for seed = %lu\n", seed);
  printf("Random: *fptr = %ld; *rptr = %ld fptr = %ld rptr = %ld\n", state_[fptr_], state_[rptr_], fptr_, rptr_);
  for (long i = 0; i < stateSize_; i++) {
    printf("Random: %d  %ld\n", i, state_[i]);
  }
#endif
}

void RandomImpl::write(RandomImplProto::Builder& proto) const
{
  auto state = proto.initState(stateSize_);
  for (UInt i = 0; i < stateSize_; ++i)
  {
    state.set(i, state_[i]);
  }
  proto.setRptr(rptr_);
  proto.setFptr(fptr_);
}

void RandomImpl::read(RandomImplProto::Reader& proto)
{
  auto state = proto.getState();
  for (UInt i = 0; i < state.size(); ++i)
  {
    state_[i] = state[i];
  }
  rptr_ = proto.getRptr();
  fptr_ = proto.getFptr();
}

namespace nupic
{
  std::ostream& operator<<(std::ostream& outStream, const Random& r)
  {
    outStream << "random-v1 ";
    outStream << r.seed_ << " ";
    NTA_CHECK(r.impl_ != nullptr);
    outStream << *r.impl_;
    outStream << " endrandom-v1";
    return outStream;
  }

  std::istream& operator>>(std::istream& inStream, Random& r)
  {
    std::string version;

    inStream >> version;
    if (version != "random-v1")
    {
      NTA_THROW << "Random() deserializer -- found unexpected version string '"
                << version << "'";
    }
    inStream >> r.seed_;
    if (! r.impl_)
      r.impl_ = new RandomImpl(0);

    inStream >> *r.impl_;

    std::string endtag;
    inStream >> endtag;
    if (endtag != "endrandom-v1")
    {
      NTA_THROW << "Random() deserializer -- found unexpected end tag '"
                << endtag << "'";
    }

    return inStream;
  }

  std::ostream& operator<<(std::ostream& outStream, const RandomImpl& r)
  {
    outStream << "randomimpl-v1 ";
    outStream << RandomImpl::stateSize_ << " ";
    for (auto & elem : r.state_)
      outStream << elem << " ";
    outStream << r.rptr_ << " ";
    outStream << r.fptr_;
    return outStream;
  }

  std::istream& operator>>(std::istream& inStream, RandomImpl& r)
  {
    std::string version;
    inStream >> version;
    if (version != "randomimpl-v1")
    {
      NTA_THROW << "RandomImpl() deserializer -- found unexpected version string '"
                << version << "'";
    }
    UInt32 ss = 0;
    inStream >> ss;
    NTA_CHECK(ss == (UInt32)RandomImpl::stateSize_) << " ss = " << ss;

    for (auto & elem : r.state_)
      inStream >> elem;
    inStream >> r.rptr_;
    inStream >> r.fptr_;
    return inStream;
  }

  // helper function for seeding RNGs across the plugin barrier
  // Unless there is a logic error, should not be called if
  // the Random singleton has not been initialized.
  NTA_UInt64 GetRandomSeed()
  {
    Random* r = nupic::Random::theInstanceP_;
    NTA_CHECK(r != nullptr);
    NTA_UInt64 result = r->getUInt64();
    return result;
  }

} // namespace nupic

<commit_msg>preventing integer overflow<commit_after>/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2013, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

/** @file
    Random Number Generator implementation
*/

#include <cstdlib>
#include <ctime>
#include <cmath> // For ldexp.
#include <iostream> // for istream, ostream

#include <capnp/message.h>
#include <capnp/serialize.h>
#include <kj/std/iostream.h>

#include <nupic/proto/RandomProto.capnp.h>
#include <nupic/utils/Log.hpp>
#include <nupic/utils/Random.hpp>
#include <nupic/utils/StringUtils.hpp>

using namespace nupic;
Random* Random::theInstanceP_ = nullptr;
RandomSeedFuncPtr Random::seeder_ = nullptr;

const UInt32 Random::MAX32 = (UInt32)((Int32)(-1));
const UInt64 Random::MAX64 = (UInt64)((Int64)(-1));

static NTA_UInt64 badSeeder()
{
  NTA_THROW << "Logic error in initialization of Random subsystem.";
  return 0;
}

/**
 * Using an Impl provides two things:
 * 1) ability to specify different algorithms (not yet implemented)
 * 2) constructors Random(long) and Random(string) without code duplication.
 */

// Algorithm-level implementation of the random number generator.
// When we have different algorithms RandomImpl will become an interface
// class and subclasses will implement specific algorithms

namespace nupic
{
  class RandomImpl
  {
  public:
    RandomImpl(UInt64 seed);
    ~RandomImpl() {};
    void write(RandomImplProto::Builder& proto) const;
    void read(RandomImplProto::Reader& proto);
    UInt32 getUInt32();
    // Note: copy constructor and operator= are needed
    // The default is ok.
  private:
    friend std::ostream& operator<<(std::ostream& outStream, const RandomImpl& r);
    friend std::istream& operator>>(std::istream& inStream, RandomImpl& r);
    // internal state
    static const int stateSize_ = 31;
    static const int sep_ = 3;
    int state_[stateSize_];
    int rptr_;
    int fptr_;

  };
};

Random::Random(const Random& r)
{
  NTA_CHECK(r.impl_ != nullptr);
  seed_ = r.seed_;
  impl_ = new RandomImpl(*r.impl_);
}

void Random::write(std::ostream& stream) const
{
  capnp::MallocMessageBuilder message;
  auto proto = message.initRoot<RandomProto>();
  write(proto);

  kj::std::StdOutputStream out(stream);
  capnp::writeMessage(out, message);
}

void Random::write(RandomProto::Builder& proto) const
{
  // save Random state
  proto.setSeed(seed_);

  // save RandomImpl state
  auto implProto = proto.initImpl();
  impl_->write(implProto);
}

void Random::read(std::istream& stream)
{
  kj::std::StdInputStream in(stream);
  capnp::InputStreamMessageReader message(in);
  RandomProto::Reader proto = message.getRoot<RandomProto>();
  read(proto);
}

void Random::read(RandomProto::Reader& proto)
{
  // load Random state
  seed_ = proto.getSeed();

  // load RandomImpl state
  auto implProto = proto.getImpl();
  impl_->read(implProto);
}

void Random::reseed(UInt64 seed)
{
  seed_ = seed;
  if (impl_)
    delete impl_;
  impl_ = new RandomImpl(seed);
}

Random& Random::operator=(const Random& other)
{
  if (this != &other)
  {
    seed_ = other.seed_;
    if (impl_)
      delete impl_;
    NTA_CHECK(other.impl_ != nullptr);
    impl_ = new RandomImpl(*other.impl_);
  }
  return *this;
}

Random::~Random()
{
  delete impl_;
}

Random::Random(UInt64 seed)
{
  // Get the seeder even if we don't need it, because
  // this will have the side effect of allocating the
  // singleton if necessary. The singleton will actuallly
  // be allocated in a recursive call to the Random
  // constructor, with seed = 0 and
  RandomSeedFuncPtr seeder = getSeeder();
  NTA_CHECK(seeder != nullptr);
  if (seed == 0) {
    if (seeder == badSeeder) {
      // we are constructing the singleton
      seed_ = (UInt64)time(nullptr);
    } else {
      seed_ = seeder();
    }
  } else {
    seed_ = seed;
  }
  // if seed is zero at this point, there is a logic error.
  NTA_CHECK(seed_ != 0);
  impl_ = new RandomImpl(seed_);
}

RandomSeedFuncPtr Random::getSeeder()
{
  if (seeder_ == nullptr)
  {
    NTA_CHECK(theInstanceP_ == nullptr);
    // set the seeder to something not NULL
    // so the constructor below will not
    // see a NULL pointer and call us recursively.
    seeder_ = badSeeder;
    theInstanceP_ = new Random(0);
    seeder_ = GetRandomSeed;
  }
  return seeder_;
}

void Random::initSeeder(const RandomSeedFuncPtr r)
{
  NTA_CHECK(r != nullptr);
  seeder_ = r;
}

void Random::shutdown()
{
  if (theInstanceP_ != nullptr)
  {
    delete theInstanceP_;
    theInstanceP_ = nullptr;
  }
}

UInt32 Random::getUInt32(const UInt32 max)
{
  NTA_ASSERT(max > 0);
  UInt32 smax = Random::MAX32 - (Random::MAX32 % max);
  UInt32 sample;
  do {
    sample = impl_->getUInt32();
  } while (sample > smax);

  // NTA_WARN << "Random32(" << max << ") -> " << sample % max << " smax = " << smax;
  return sample % max;
}

UInt64 Random::getUInt64(const UInt64 max)
{
  NTA_ASSERT(max > 0);
  UInt64 smax = Random::MAX64 - (Random::MAX64 % max);
  UInt64 sample, lo, hi;
  do {
    lo = impl_->getUInt32();
    hi = impl_->getUInt32();
    sample = lo | (hi << 32);
  } while(sample > smax);
  // NTA_WARN << "Random64(" << max << ") -> " << sample % max << " smax = " << smax;

  return sample % max;
}

double Random::getReal64()
{
  const int mantissaBits = 48;
  const UInt64 max = (UInt64)0x1U << mantissaBits;
  UInt64 value = getUInt64(max);
  Real64 dvalue = (Real64) value; // No loss because we only need the 48 mantissa bits.
  Real64 returnval = ::ldexp(dvalue, -mantissaBits);
  // NTA_WARN << "RandomReal -> " << returnval;
  return returnval;
}

// ---- RandomImpl follows ----

UInt32 RandomImpl::getUInt32(void)
{
  int i;
#ifdef RANDOM_SUPERDEBUG
  printf("Random::get *fptr = %ld; *rptr = %ld fptr = %ld rptr = %ld\n", state_[fptr_], state_[rptr_], fptr_, rptr_);
#endif
  state_[fptr_] = (int)(((long)state_[fptr_] + (long)state_[rptr_]) % Random::MAX32);
  i = state_[fptr_];
  i = (i >> 1) & 0x7fffffff;	/* chucking least random bit */
  if (++fptr_ >= stateSize_) {
    fptr_ = 0;
    ++rptr_;
  } else if (++rptr_ >= stateSize_)
    rptr_ = 0;
#ifdef RANDOM_SUPERDEBUG
  printf("Random::get returning %ld\n", i);
  for (int j = 0; j < stateSize_; j++) {
    printf("Random:get: %d  %ld\n", j, state_[j]);
  }
#endif

  return(i);
}

RandomImpl::RandomImpl(UInt64 seed)
{

  /**
   * Initialize our state. Taken from BSD source for random()
   */
  state_[0] = (int)seed;
  for (long i = 1; i < stateSize_; i++) {
    /*
     * Implement the following, without overflowing 31 bits:
     *
     *	state[i] = (16807 * state[i - 1]) % 2147483647;
     *
     *	2^31-1 (prime) = 2147483647 = 127773*16807+2836
     */
    ldiv_t val = ldiv(state_[i-1], 127773);
    long test = 16807 * val.rem - 2836 * val.quot;
    state_[i] = test + (test < 0 ? 2147483647 : 0);
  }
  fptr_ = sep_;
  rptr_ = 0;
#ifdef RANDOM_SUPERDEBUG
  printf("Random: init for seed = %lu\n", seed);
  for (int i = 0; i < stateSize_; i++) {
    printf("Random: %d  %ld\n", i, state_[i]);
  }
#endif

  for (long i = 0; i < 10 * stateSize_; i++)
    (void)getUInt32();
#ifdef RANDOM_SUPERDEBUG
  printf("Random: after init for seed = %lu\n", seed);
  printf("Random: *fptr = %ld; *rptr = %ld fptr = %ld rptr = %ld\n", state_[fptr_], state_[rptr_], fptr_, rptr_);
  for (long i = 0; i < stateSize_; i++) {
    printf("Random: %d  %ld\n", i, state_[i]);
  }
#endif
}

void RandomImpl::write(RandomImplProto::Builder& proto) const
{
  auto state = proto.initState(stateSize_);
  for (UInt i = 0; i < stateSize_; ++i)
  {
    state.set(i, state_[i]);
  }
  proto.setRptr(rptr_);
  proto.setFptr(fptr_);
}

void RandomImpl::read(RandomImplProto::Reader& proto)
{
  auto state = proto.getState();
  for (UInt i = 0; i < state.size(); ++i)
  {
    state_[i] = state[i];
  }
  rptr_ = proto.getRptr();
  fptr_ = proto.getFptr();
}

namespace nupic
{
  std::ostream& operator<<(std::ostream& outStream, const Random& r)
  {
    outStream << "random-v1 ";
    outStream << r.seed_ << " ";
    NTA_CHECK(r.impl_ != nullptr);
    outStream << *r.impl_;
    outStream << " endrandom-v1";
    return outStream;
  }

  std::istream& operator>>(std::istream& inStream, Random& r)
  {
    std::string version;

    inStream >> version;
    if (version != "random-v1")
    {
      NTA_THROW << "Random() deserializer -- found unexpected version string '"
                << version << "'";
    }
    inStream >> r.seed_;
    if (! r.impl_)
      r.impl_ = new RandomImpl(0);

    inStream >> *r.impl_;

    std::string endtag;
    inStream >> endtag;
    if (endtag != "endrandom-v1")
    {
      NTA_THROW << "Random() deserializer -- found unexpected end tag '"
                << endtag << "'";
    }

    return inStream;
  }

  std::ostream& operator<<(std::ostream& outStream, const RandomImpl& r)
  {
    outStream << "randomimpl-v1 ";
    outStream << RandomImpl::stateSize_ << " ";
    for (auto & elem : r.state_)
      outStream << elem << " ";
    outStream << r.rptr_ << " ";
    outStream << r.fptr_;
    return outStream;
  }

  std::istream& operator>>(std::istream& inStream, RandomImpl& r)
  {
    std::string version;
    inStream >> version;
    if (version != "randomimpl-v1")
    {
      NTA_THROW << "RandomImpl() deserializer -- found unexpected version string '"
                << version << "'";
    }
    UInt32 ss = 0;
    inStream >> ss;
    NTA_CHECK(ss == (UInt32)RandomImpl::stateSize_) << " ss = " << ss;

    for (auto & elem : r.state_)
      inStream >> elem;
    inStream >> r.rptr_;
    inStream >> r.fptr_;
    return inStream;
  }

  // helper function for seeding RNGs across the plugin barrier
  // Unless there is a logic error, should not be called if
  // the Random singleton has not been initialized.
  NTA_UInt64 GetRandomSeed()
  {
    Random* r = nupic::Random::theInstanceP_;
    NTA_CHECK(r != nullptr);
    NTA_UInt64 result = r->getUInt64();
    return result;
  }

} // namespace nupic

<|endoftext|>


<commit_before>//===-- MachineCSE.cpp - Machine Common Subexpression Elimination Pass ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass performs global common subexpression elimination on machine
// instructions using a scoped hash table based value numbering scheme. It
// must be run while the machine function is still in SSA form.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "machine-cse"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"

using namespace llvm;

STATISTIC(NumCoalesces, "Number of copies coalesced");
STATISTIC(NumCSEs,      "Number of common subexpression eliminated");

namespace {
  class MachineCSE : public MachineFunctionPass {
    const TargetInstrInfo *TII;
    MachineRegisterInfo  *MRI;
    MachineDominatorTree *DT;
  public:
    static char ID; // Pass identification
    MachineCSE() : MachineFunctionPass(&ID), CurrVN(0) {}

    virtual bool runOnMachineFunction(MachineFunction &MF);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      MachineFunctionPass::getAnalysisUsage(AU);
      AU.addRequired<MachineDominatorTree>();
      AU.addPreserved<MachineDominatorTree>();
    }

  private:
    unsigned CurrVN;
    ScopedHashTable<MachineInstr*, unsigned, MachineInstrExpressionTrait> VNT;
    SmallVector<MachineInstr*, 64> Exps;

    bool PerformTrivialCoalescing(MachineInstr *MI, MachineBasicBlock *MBB);
    bool ProcessBlock(MachineDomTreeNode *Node);
  };
} // end anonymous namespace

char MachineCSE::ID = 0;
static RegisterPass<MachineCSE>
X("machine-cse", "Machine Common Subexpression Elimination");

FunctionPass *llvm::createMachineCSEPass() { return new MachineCSE(); }

bool MachineCSE::PerformTrivialCoalescing(MachineInstr *MI,
                                          MachineBasicBlock *MBB) {
  bool Changed = false;
  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
    MachineOperand &MO = MI->getOperand(i);
    if (!MO.isReg() || !MO.isUse())
      continue;
    unsigned Reg = MO.getReg();
    if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg))
      continue;
    if (!MRI->hasOneUse(Reg))
      // Only coalesce single use copies. This ensure the copy will be
      // deleted.
      continue;
    MachineInstr *DefMI = MRI->getVRegDef(Reg);
    if (DefMI->getParent() != MBB)
      continue;
    unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx;
    if (TII->isMoveInstr(*DefMI, SrcReg, DstReg, SrcSubIdx, DstSubIdx) &&
        TargetRegisterInfo::isVirtualRegister(SrcReg) &&
        !SrcSubIdx && !DstSubIdx) {
      MO.setReg(SrcReg);
      DefMI->eraseFromParent();
      ++NumCoalesces;
      Changed = true;
    }
  }

  return Changed;
}

static bool hasLivePhysRegDefUse(MachineInstr *MI) {
  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
    MachineOperand &MO = MI->getOperand(i);
    if (!MO.isReg())
      continue;
    unsigned Reg = MO.getReg();
    if (!Reg)
      continue;
    // FIXME: This is obviously overly conservative. On x86 lots of instructions
    // will def EFLAGS and they are not marked dead at this point.
    if (TargetRegisterInfo::isPhysicalRegister(Reg) &&
        !(MO.isDef() && MO.isDead()))
      return true;
  }
  return false;
}

bool MachineCSE::ProcessBlock(MachineDomTreeNode *Node) {
  bool Changed = false;

  ScopedHashTableScope<MachineInstr*, unsigned,
    MachineInstrExpressionTrait> VNTS(VNT);
  MachineBasicBlock *MBB = Node->getBlock();
  for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; ) {
    MachineInstr *MI = &*I;
    ++I;
    bool SawStore = false;
    if (!MI->isSafeToMove(TII, 0, SawStore))
      continue;
    // Ignore copies or instructions that read / write physical registers
    // (except for dead defs of physical registers).
    unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx;
    if (TII->isMoveInstr(*MI, SrcReg, DstReg, SrcSubIdx, DstSubIdx) ||
        MI->isExtractSubreg() || MI->isInsertSubreg() || MI->isSubregToReg())
      continue;

    bool FoundCSE = VNT.count(MI);
    if (!FoundCSE) {
      // Look for trivial copy coalescing opportunities.
      if (PerformTrivialCoalescing(MI, MBB))
        FoundCSE = VNT.count(MI);
    }

    // If the instruction defines a physical register and the value *may* be
    // used, then it's not safe to replace it with a common subexpression.
    if (FoundCSE && hasLivePhysRegDefUse(MI))
      FoundCSE = false;

    if (!FoundCSE) {
      VNT.insert(MI, CurrVN++);
      Exps.push_back(MI);
      continue;
    }

    // Found a common subexpression, eliminate it.
    unsigned CSVN = VNT.lookup(MI);
    MachineInstr *CSMI = Exps[CSVN];
    DEBUG(dbgs() << "Examining: " << *MI);
    DEBUG(dbgs() << "*** Found a common subexpression: " << *CSMI);
    unsigned NumDefs = MI->getDesc().getNumDefs();
    for (unsigned i = 0, e = MI->getNumOperands(); NumDefs && i != e; ++i) {
      MachineOperand &MO = MI->getOperand(i);
      if (!MO.isReg() || !MO.isDef())
        continue;
      unsigned OldReg = MO.getReg();
      unsigned NewReg = CSMI->getOperand(i).getReg();
      assert(OldReg != NewReg &&
             TargetRegisterInfo::isVirtualRegister(OldReg) &&
             TargetRegisterInfo::isVirtualRegister(NewReg) &&
             "Do not CSE physical register defs!");
      MRI->replaceRegWith(OldReg, NewReg);
      --NumDefs;
    }
    MI->eraseFromParent();
    ++NumCSEs;
  }

  // Recursively call ProcessBlock with childred.
  const std::vector<MachineDomTreeNode*> &Children = Node->getChildren();
  for (unsigned i = 0, e = Children.size(); i != e; ++i)
    Changed |= ProcessBlock(Children[i]);

  return Changed;
}

bool MachineCSE::runOnMachineFunction(MachineFunction &MF) {
  TII = MF.getTarget().getInstrInfo();
  MRI = &MF.getRegInfo();
  DT = &getAnalysis<MachineDominatorTree>();
  return ProcessBlock(DT->getRootNode());
}
<commit_msg>Look ahead a bit to determine if a physical register def that is not marked dead is really alive. This is necessary to catch a lot of common cse opportunities for targets like x86.<commit_after>//===-- MachineCSE.cpp - Machine Common Subexpression Elimination Pass ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass performs global common subexpression elimination on machine
// instructions using a scoped hash table based value numbering scheme. It
// must be run while the machine function is still in SSA form.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "machine-cse"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"

using namespace llvm;

STATISTIC(NumCoalesces, "Number of copies coalesced");
STATISTIC(NumCSEs,      "Number of common subexpression eliminated");

namespace {
  class MachineCSE : public MachineFunctionPass {
    const TargetInstrInfo *TII;
    const TargetRegisterInfo *TRI;
    MachineRegisterInfo  *MRI;
    MachineDominatorTree *DT;
  public:
    static char ID; // Pass identification
    MachineCSE() : MachineFunctionPass(&ID), CurrVN(0) {}

    virtual bool runOnMachineFunction(MachineFunction &MF);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      MachineFunctionPass::getAnalysisUsage(AU);
      AU.addRequired<MachineDominatorTree>();
      AU.addPreserved<MachineDominatorTree>();
    }

  private:
    unsigned CurrVN;
    ScopedHashTable<MachineInstr*, unsigned, MachineInstrExpressionTrait> VNT;
    SmallVector<MachineInstr*, 64> Exps;

    bool hasLivePhysRegDefUse(MachineInstr *MI, MachineBasicBlock *MBB);
    bool isPhysDefTriviallyDead(unsigned Reg,
                                MachineBasicBlock::const_iterator I,
                                MachineBasicBlock::const_iterator E);
    bool PerformTrivialCoalescing(MachineInstr *MI, MachineBasicBlock *MBB);
    bool ProcessBlock(MachineDomTreeNode *Node);
  };
} // end anonymous namespace

char MachineCSE::ID = 0;
static RegisterPass<MachineCSE>
X("machine-cse", "Machine Common Subexpression Elimination");

FunctionPass *llvm::createMachineCSEPass() { return new MachineCSE(); }

bool MachineCSE::PerformTrivialCoalescing(MachineInstr *MI,
                                          MachineBasicBlock *MBB) {
  bool Changed = false;
  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
    MachineOperand &MO = MI->getOperand(i);
    if (!MO.isReg() || !MO.isUse())
      continue;
    unsigned Reg = MO.getReg();
    if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg))
      continue;
    if (!MRI->hasOneUse(Reg))
      // Only coalesce single use copies. This ensure the copy will be
      // deleted.
      continue;
    MachineInstr *DefMI = MRI->getVRegDef(Reg);
    if (DefMI->getParent() != MBB)
      continue;
    unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx;
    if (TII->isMoveInstr(*DefMI, SrcReg, DstReg, SrcSubIdx, DstSubIdx) &&
        TargetRegisterInfo::isVirtualRegister(SrcReg) &&
        !SrcSubIdx && !DstSubIdx) {
      MO.setReg(SrcReg);
      DefMI->eraseFromParent();
      ++NumCoalesces;
      Changed = true;
    }
  }

  return Changed;
}

bool MachineCSE::isPhysDefTriviallyDead(unsigned Reg,
                                        MachineBasicBlock::const_iterator I,
                                        MachineBasicBlock::const_iterator E) {
  unsigned LookAheadLeft = 5;
  while (LookAheadLeft--) {
    if (I == E)
      // Reached end of block, register is obviously dead.
      return true;

    if (I->isDebugValue())
      continue;
    bool SeenDef = false;
    for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) {
      const MachineOperand &MO = I->getOperand(i);
      if (!MO.isReg() || !MO.getReg())
        continue;
      if (!TRI->regsOverlap(MO.getReg(), Reg))
        continue;
      if (MO.isUse())
        return false;
      SeenDef = true;
    }
    if (SeenDef)
      // See a def of Reg (or an alias) before encountering any use, it's
      // trivially dead.
      return true;
    ++I;
  }
  return false;
}

bool MachineCSE::hasLivePhysRegDefUse(MachineInstr *MI, MachineBasicBlock *MBB){
  unsigned PhysDef = 0;
  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
    MachineOperand &MO = MI->getOperand(i);
    if (!MO.isReg())
      continue;
    unsigned Reg = MO.getReg();
    if (!Reg)
      continue;
    if (TargetRegisterInfo::isPhysicalRegister(Reg)) {
      if (MO.isUse())
        // Can't touch anything to read a physical register.
        return true;
      if (MO.isDead())
        // If the def is dead, it's ok.
        continue;
      // Ok, this is a physical register def that's not marked "dead". That's
      // common since this pass is run before livevariables. We can scan
      // forward a few instructions and check if it is obviously dead.
      if (PhysDef)
        // Multiple physical register defs. These are rare, forget about it.
        return true;
      PhysDef = Reg;
    }
  }

  if (PhysDef) {
    MachineBasicBlock::iterator I = MI; I = llvm::next(I);
    if (!isPhysDefTriviallyDead(PhysDef, I, MBB->end()))
      return true;
  }
  return false;
}

bool MachineCSE::ProcessBlock(MachineDomTreeNode *Node) {
  bool Changed = false;

  ScopedHashTableScope<MachineInstr*, unsigned,
    MachineInstrExpressionTrait> VNTS(VNT);
  MachineBasicBlock *MBB = Node->getBlock();
  for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; ) {
    MachineInstr *MI = &*I;
    ++I;
    bool SawStore = false;
    if (!MI->isSafeToMove(TII, 0, SawStore))
      continue;
    // Ignore copies or instructions that read / write physical registers
    // (except for dead defs of physical registers).
    unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx;
    if (TII->isMoveInstr(*MI, SrcReg, DstReg, SrcSubIdx, DstSubIdx) ||
        MI->isExtractSubreg() || MI->isInsertSubreg() || MI->isSubregToReg())
      continue;

    bool FoundCSE = VNT.count(MI);
    if (!FoundCSE) {
      // Look for trivial copy coalescing opportunities.
      if (PerformTrivialCoalescing(MI, MBB))
        FoundCSE = VNT.count(MI);
    }
    // FIXME: commute commutable instructions?

    // If the instruction defines a physical register and the value *may* be
    // used, then it's not safe to replace it with a common subexpression.
    if (FoundCSE && hasLivePhysRegDefUse(MI, MBB))
      FoundCSE = false;

    if (!FoundCSE) {
      VNT.insert(MI, CurrVN++);
      Exps.push_back(MI);
      continue;
    }

    // Found a common subexpression, eliminate it.
    unsigned CSVN = VNT.lookup(MI);
    MachineInstr *CSMI = Exps[CSVN];
    DEBUG(dbgs() << "Examining: " << *MI);
    DEBUG(dbgs() << "*** Found a common subexpression: " << *CSMI);
    unsigned NumDefs = MI->getDesc().getNumDefs();
    for (unsigned i = 0, e = MI->getNumOperands(); NumDefs && i != e; ++i) {
      MachineOperand &MO = MI->getOperand(i);
      if (!MO.isReg() || !MO.isDef())
        continue;
      unsigned OldReg = MO.getReg();
      unsigned NewReg = CSMI->getOperand(i).getReg();
      assert(OldReg != NewReg &&
             TargetRegisterInfo::isVirtualRegister(OldReg) &&
             TargetRegisterInfo::isVirtualRegister(NewReg) &&
             "Do not CSE physical register defs!");
      MRI->replaceRegWith(OldReg, NewReg);
      --NumDefs;
    }
    MI->eraseFromParent();
    ++NumCSEs;
  }

  // Recursively call ProcessBlock with childred.
  const std::vector<MachineDomTreeNode*> &Children = Node->getChildren();
  for (unsigned i = 0, e = Children.size(); i != e; ++i)
    Changed |= ProcessBlock(Children[i]);

  return Changed;
}

bool MachineCSE::runOnMachineFunction(MachineFunction &MF) {
  TII = MF.getTarget().getInstrInfo();
  TRI = MF.getTarget().getRegisterInfo();
  MRI = &MF.getRegInfo();
  DT = &getAnalysis<MachineDominatorTree>();
  return ProcessBlock(DT->getRootNode());
}
<|endoftext|>


<commit_before>#include "driver.h"

#include <vector>
#include <string>
#include <fstream>
#include <iostream>

namespace ride
{
    vec2 operator+(const vec2& lhs, const vec2& rhs)
    {
        return {lhs.x + rhs.x, lhs.y + rhs.y};
    }

    Font::~Font()
    {
    }

    Driver::~Driver()
    {
    }

    Painter::~Painter()
    {
    }

    App::~App()
    {
    }

    struct Document
    {
        std::vector<std::string> lines;

        vec2 scroll = {0, 0};

        Document()
        {
            LoadFile(__FILE__);
        }

        void LoadFile(const std::string& path)
        {
            std::cout << "Loading " << path << "\n";
            lines.clear();

            std::ifstream file;
            file.open(path.c_str(), std::ios::in | std::ios::binary);
            if(file.is_open() == false)
            {
                return;
            }

            std::string line;
            while(getline(file,line))
            {
                lines.emplace_back(line);
            }
        }
    };

    struct RectScope
    {
        Painter* painter;

        RectScope(Painter* p, const Rect& rect) : painter(p)
        {
            painter->PushClip(rect);
        }

        ~RectScope()
        {
            painter->PopClip();
        }
    };

    void DrawDocument
    (
        std::shared_ptr<Driver> driver,
        std::shared_ptr<Font> font,
        Painter* painter,
        const Rgb& color,
        const Document& d,
        const Rect& rect
    )
    {
        const auto scope = RectScope{painter, rect};
        const auto lower_right = rect.position + rect.size;
        const auto meassure = driver->GetSizeOfString(font, "ABCgdijlk");

        auto draw = rect.position;
        auto scroll = d.scroll;

        for(; draw.y < lower_right.y; draw.y += meassure.height)
        {
            if(scroll.y >= 0 && scroll.y < d.lines.size())
            {
                const auto l = d.lines[scroll.y];
                painter->Text(font, l, draw, color);
            }

            scroll.y = scroll.y + 1;
        }
    }

    const std::string MEASSURE_STRING = "ABCdefjklm";

    struct RideApp : App
    {
        std::shared_ptr<Driver> driver;
        std::shared_ptr<Font> font_ui;
        std::shared_ptr<Font> font_code;
        std::shared_ptr<Font> font_big;
        TextSize text_size;

        Document doc;

        vec2 window_size = vec2{0,0};
        std::optional<vec2> mouse = std::nullopt;
        std::optional<vec2> start = std::nullopt;

        float circle = 25.0f;

        bool on_left = false;

        std::string str = "void main() { return 42; }";

        RideApp(std::shared_ptr<Driver> d)
            : driver(d)
            , font_ui(d->CreateUiFont(12))
            , font_code(d->CreateCodeFont(8))
            , font_big(d->CreateUiFont(100))
            , text_size(d->GetSizeOfString(font_big, MEASSURE_STRING))
        {
            std::cout << text_size.external_leading << "\n";
        }

        void OnSize(const vec2& new_size) override
        {
            window_size = new_size;

            driver->Refresh();
        }

        void OnPaint(Painter* painter) override
        {
            painter->Rect({{0, 0}, window_size}, Rgb{230, 230, 230}, std::nullopt);

            // draw some text
            painter->Text(font_ui, "File | Code | Help", {40, 00}, {0, 0, 0});
            // painter->Text(font_code, str, {40,60}, {0,0,0});

            // draw a circle, green filling, 5-pixels-thick red outline
            if(mouse && !start)
            {
                painter->Circle(*mouse, static_cast<int>(circle), Rgb{0, 255, 0}, Line{{0,0,0}, 1});
            }

            // draw a black line, 3 pixels thick
            if(start && mouse)
            {
                painter->Line( *start, *mouse, {{0,0,0}, 3} ); // draw line across the rectangle
            }

            constexpr auto edit = Rect{{10, 20}, {400, 420}};
            painter->Rect(edit, Rgb{180, 180, 180}, std::nullopt);

            DrawDocument(driver, font_code, painter, {0,0,0}, doc, edit);
        }

        void OnMouseMoved(const vec2& new_position) override
        {
            mouse = new_position;
            driver->Refresh();
        }

        void OnMouseLeftWindow() override
        {
            mouse = std::nullopt;
            driver->Refresh();
        }

        void OnMouseButton(MouseState state, MouseButton button) override
        {
            if(button == MouseButton::Left)
            {
                if(state == MouseState::Up)
                {
                    start = std::nullopt;
                }
                else
                {
                    if(mouse)
                    {
                        start = *mouse;
                    }
                }

            }
            driver->Refresh();
        }

        void OnMouseScroll(float scroll, int lines) override
        {
            circle = std::max(1.0f, circle + scroll * lines);
            driver->Refresh();
        }

        bool ctrl = false;
        bool OnKey(bool down, Key key) override
        {
            if(key == Key::Control)
            {
                ctrl = down;
                driver->Refresh();
                return true;
            }

            if(!down) { return false; }

            bool handled = false;

            switch(key)
            {
            case Key::Left: on_left = true; handled = true; break;
            case Key::Right: on_left = false; handled = true; break;
            case Key::Escape: str = ""; handled = true; break;
            case Key::Up:
                if(ctrl)
                {
                    doc.scroll.y -= 1;
                    handled = true;
                }
                break;
            case Key::Down:
                if(ctrl)
                {
                    doc.scroll.y += 1;
                    handled = true;
                }
                break;

            default: break;
            }

            if(handled)
            {
                driver->Refresh();
            }

            return handled;
        }

        void OnChar(const std::string& ch) override
        {
            str += ch;
            driver->Refresh();
        }
    };

    std::shared_ptr<App>
    CreateApp(std::shared_ptr<Driver> driver)
    {
        return std::make_shared<RideApp>(driver);
    }
}
<commit_msg>added view<commit_after>#include "driver.h"

#include <vector>
#include <string>
#include <fstream>
#include <iostream>

namespace ride
{
    vec2 operator+(const vec2& lhs, const vec2& rhs)
    {
        return {lhs.x + rhs.x, lhs.y + rhs.y};
    }

    Font::~Font()
    {
    }

    Driver::~Driver()
    {
    }

    Painter::~Painter()
    {
    }

    App::~App()
    {
    }

    struct Document
    {
        std::vector<std::string> lines;

        Document()
        {
            LoadFile(__FILE__);
        }

        void LoadFile(const std::string& path)
        {
            std::cout << "Loading " << path << "\n";
            lines.clear();

            std::ifstream file;
            file.open(path.c_str(), std::ios::in | std::ios::binary);
            if(file.is_open() == false)
            {
                return;
            }

            std::string line;
            while(getline(file,line))
            {
                lines.emplace_back(line);
            }
        }
    };

    struct RectScope
    {
        Painter* painter;

        RectScope(Painter* p, const Rect& rect) : painter(p)
        {
            painter->PushClip(rect);
        }

        ~RectScope()
        {
            painter->PopClip();
        }
    };

    struct View
    {
        std::shared_ptr<Font> font;
        std::shared_ptr<Document> document;

        vec2 scroll = {0, 0};
        Rect rect = {{0, 0}, {0, 0}};

        void ScrollY(int y)
        {
            scroll.y += y;
        }

        void Draw
        (
            std::shared_ptr<Driver> driver,
            Painter* painter,
            const Rgb& foreground_color,
            const Rgb& background_color
        )
        {
            painter->Rect(rect, background_color, std::nullopt);

            if(font && document)
            {
                const auto scope = RectScope{painter, rect};
                const auto lower_right = rect.position + rect.size;
                const auto line_height = driver->GetSizeOfString(font, "ABCgdijlk").height;

                auto draw = rect.position;
                auto current_scroll = scroll;

                for(; draw.y < lower_right.y; draw.y += line_height)
                {
                    if(current_scroll.y >= 0 && current_scroll.y < document->lines.size())
                    {
                        const auto l = document->lines[current_scroll.y];
                        painter->Text(font, l, draw, foreground_color);
                    }

                    current_scroll.y = current_scroll.y + 1;
                }
            }
        }
    };

    const std::string MEASSURE_STRING = "ABCdefjklm";

    struct RideApp : App
    {
        std::shared_ptr<Driver> driver;
        std::shared_ptr<Font> font_ui;
        std::shared_ptr<Font> font_code;
        std::shared_ptr<Font> font_big;
        TextSize text_size;

        View view;

        vec2 window_size = vec2{0,0};
        std::optional<vec2> mouse = std::nullopt;
        std::optional<vec2> start = std::nullopt;

        float circle = 25.0f;

        bool on_left = false;

        std::string str = "void main() { return 42; }";

        RideApp(std::shared_ptr<Driver> d)
            : driver(d)
            , font_ui(d->CreateUiFont(12))
            , font_code(d->CreateCodeFont(8))
            , font_big(d->CreateUiFont(100))
            , text_size(d->GetSizeOfString(font_big, MEASSURE_STRING))
        {
            view.font = font_code;
            view.rect = Rect{{10, 20}, {400, 420}};
            view.document = std::make_shared<Document>();
            std::cout << text_size.external_leading << "\n";
        }

        void OnSize(const vec2& new_size) override
        {
            window_size = new_size;

            driver->Refresh();
        }

        void OnPaint(Painter* painter) override
        {
            painter->Rect({{0, 0}, window_size}, Rgb{230, 230, 230}, std::nullopt);

            // draw some text
            painter->Text(font_ui, "File | Code | Help", {40, 00}, {0, 0, 0});
            // painter->Text(font_code, str, {40,60}, {0,0,0});

            // draw a circle, green filling, 5-pixels-thick red outline
            if(mouse && !start)
            {
                painter->Circle(*mouse, static_cast<int>(circle), Rgb{0, 255, 0}, Line{{0,0,0}, 1});
            }

            // draw a black line, 3 pixels thick
            if(start && mouse)
            {
                painter->Line( *start, *mouse, {{0,0,0}, 3} ); // draw line across the rectangle
            }

            view.Draw(driver, painter, {0,0,0}, Rgb{180, 180, 180});
        }

        void OnMouseMoved(const vec2& new_position) override
        {
            mouse = new_position;
            driver->Refresh();
        }

        void OnMouseLeftWindow() override
        {
            mouse = std::nullopt;
            driver->Refresh();
        }

        void OnMouseButton(MouseState state, MouseButton button) override
        {
            if(button == MouseButton::Left)
            {
                if(state == MouseState::Up)
                {
                    start = std::nullopt;
                }
                else
                {
                    if(mouse)
                    {
                        start = *mouse;
                    }
                }

            }
            driver->Refresh();
        }

        void OnMouseScroll(float scroll, int lines) override
        {
            circle = std::max(1.0f, circle + scroll * lines);
            driver->Refresh();
        }

        bool ctrl = false;
        bool OnKey(bool down, Key key) override
        {
            if(key == Key::Control)
            {
                ctrl = down;
                driver->Refresh();
                return true;
            }

            if(!down) { return false; }

            bool handled = false;

            switch(key)
            {
            case Key::Left: on_left = true; handled = true; break;
            case Key::Right: on_left = false; handled = true; break;
            case Key::Escape: str = ""; handled = true; break;
            case Key::Up:
                if(ctrl)
                {
                    view.ScrollY(-1);
                    handled = true;
                }
                break;
            case Key::Down:
                if(ctrl)
                {
                    view.ScrollY(1);
                    handled = true;
                }
                break;

            default: break;
            }

            if(handled)
            {
                driver->Refresh();
            }

            return handled;
        }

        void OnChar(const std::string& ch) override
        {
            str += ch;
            driver->Refresh();
        }
    };

    std::shared_ptr<App>
    CreateApp(std::shared_ptr<Driver> driver)
    {
        return std::make_shared<RideApp>(driver);
    }
}
<|endoftext|>