<commit_before>#ifndef TCL_BUFFER_HPP
#define TCL_BUFFER_HPP

#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL\cl.h>
#endif

#include <vector>
#include <array>
#include <mutex>
#include "CLInformation.hpp"

namespace tcl
{
	// CLExecuteŏzQƂĂ܂
	class CLExecute;

	/**
	* foCẌ̃bp[NX
	*/
	class CLBuffer
	{
	private:
		static CLExecute* exec;			// zQƂĂ܂̂Ń|C^ɂĂ
		static std::mutex execMutex;	// }`Xbh΍
		cl_mem memory;
		size_t size;

	public:
		/**
		* mۂeʂ擾
		* \return mۂe
		*/
		inline const size_t Size() const {
			return size;
		}

		/**
		* mۂIuWFNg擾
		* \return mۂIuWFNg
		*/
		inline cl_mem& Memory() {
			return memory;
		}

		cl_mem& operator() () {
			return memory;
		}

	private:
		/**
		* Rs[֎~
		*/
		CLBuffer(const CLBuffer& copy) { }

		template <typename T>
		void SizeTest(const size_t& size) const
		{
			auto argSize = size * sizeof(T);
			if (this->size < argSize)
			{
				throw CLFailedAllacException("obt@̃TCYzXg̃TCY̕傫");
			}
		}

		void ResultTest(const cl_int result) const
		{
			if (result != CL_SUCCESS)
			{
				throw CLException("WriteReadɎs܂", result);
			}
		}

		void ReadTest(const cl_uint result) const
		{
			if (result != CL_SUCCESS)
			{
				switch (result)
				{
				case CL_INVALID_COMMAND_QUEUE:
					throw CLException("R}hL[ł");
				case CL_INVALID_CONTEXT:
					throw CLException("ReNXgł");
				case CL_INVALID_MEM_OBJECT:
					throw CLException("obt@IuWFNgł");
				case CL_INVALID_VALUE:
					throw CLException("w肵ǂݍݗ̈悪͈͊Oł");
				case CL_INVALID_EVENT_WAIT_LIST:
					throw CLException("Cxg҂Xgł");
				case CL_MISALIGNED_SUB_BUFFER_OFFSET:
					throw CLException("Tuobt@̃ItZbgACgĂ܂");
				case CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST:
					throw CLException("ǂݍ݃R}hubLOǂ");
				case CL_MEM_OBJECT_ALLOCATION_FAILURE:
					throw CLException("obt@Ɗ֘Atꂽf[^ۑ̈ւ̃mۂɎs");
				case CL_OUT_OF_RESOURCES:
					throw CLException("foCX̃\[X̊mۂɎs");
				case CL_OUT_OF_HOST_MEMORY:
					throw CLException("zXg̃\[X̊mۂɎs");
				}
			}
		}

		template <typename T>
		void SafeEnqueueRead(size_t size, T* data)
		{
			auto result = clEnqueueReadBuffer(
				exec->CommandQueue(), memory, CL_TRUE,
				0, size, data,
				0, NULL, NULL);
			ReadTest(result);
		}

		template <typename T>
		void SafeEnqueueWrite(size_t size, T* data)
		{
			auto result = clEnqueueWriteBuffer(
				exec->CommandQueue(), memory, CL_TRUE,
				0, size, data,
				0, NULL, NULL);
			ResultTest(result);
		}

	protected:
		/**
		* ň̂͊댯Ȃ̂ŃftHgRXgN^͋֎~
		*/
		CLBuffer()
			: size(0) {}

		CLBuffer(const cl_mem_flags flag, const size_t size, void* hostPtr)
			: size(size)
		{
			memory = clCreateBuffer(information.context, flag, size, hostPtr, &information.result);
		}

	public:
		virtual ~CLBuffer()
		{
			clReleaseMemObject(memory);
		}

		/**
		* zXgfoCXɓ]
		*/
		template <typename T>
		CLBuffer& Write(const std::vector<T>& enqueueData)
		{
			SizeTest<T>(enqueueData.size());
			SafeEnqueueWrite(sizeof(T) * enqueueData.size(), &enqueueData[0]);
			return *this;
		}

		/**
		* zXgfoCXɓ]
		*/
		template <typename T, size_t NUM>
		CLBuffer& Write(const std::array<T, NUM>& enqueueData)
		{
			SizeTest<T>(enqueueData.size());
			SafeEnqueueWrite(sizeof(T) * enqueueData.size(), &enqueueData[0]);
			return *this;
		}

		/**
		* zXgfoCXɓ]
		* \attention z񓊂Ɨ܂
		*/
		template <typename T>
		CLBuffer& Write(const T& data)
		{
			SafeEnqueueWrite(sizeof(T), &data);
			return *this;
		}

		/**
		* zXgfoCXɓ]
		* \attention |C^zꍇ
		*/
		template <typename T>
		CLBuffer& Write(T* data, const size_t num)
		{
			SafeEnqueueWrite(sizeof(T) * num, data);
			return *this;
		}

		/**
		* foCXzXgɓ]
		*/
		template <typename T>
		CLBuffer& Read(std::vector<T>& dequeueData)
		{
			SizeTest<T>(dequeueData.size());
			SafeEnqueueRead(sizeof(T) * dequeueData.size(), &dequeueData[0]);
			return *this;
		}

		/**
		* foCXzXgɓ]
		*/
		template <typename T, size_t NUM>
		CLBuffer& Read(std::array<T, NUM>& dequeueData)
		{
			SizeTest<T>(dequeueData.size());
			SafeEnqueueRead(sizeof(T) * dequeueData.size(), &dequeueData[0]);
			return *this;
		}

		/**
		* foCXzXgɓ]
		* \attention z񓊂Ɨ܂
		*/
		template <typename T>
		CLBuffer& Read(T& data)
		{
			SafeEnqueueRead(sizeof(T), &data);
			return *this;
		}

		/**
		* foCXzXgɓ]
		* \attention |C^zꍇ
		*/
		template <typename T>
		CLBuffer& Read(T* data, const size_t num)
		{
			SafeEnqueueRead(sizeof(T) * num, data);
			return *this;
		}
	};
}

#endif<commit_msg>仕様変更でごちゃごちゃしてる<commit_after>#ifndef TCL_BUFFER_HPP
#define TCL_BUFFER_HPP

#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL\cl.h>
#endif

#include <vector>
#include <array>
#include <mutex>
#include "CLInformation.hpp"

namespace tcl
{
	// CLExecuteŏzQƂĂ܂
	class CLExecute;

	/**
	* foCẌ̃bp[NX
	*/
	template <typename TYPE>
	class CLBuffer
	{
	private:
		cl_mem memory;
		size_t size;
		TYPE* hostDataPtr;

	public:
		/**
		* mۂeʂ擾
		* \return mۂe
		*/
		inline const size_t Size() const {
			return size;
		}

		/**
		* mۂIuWFNg擾
		* \return mۂIuWFNg
		*/
		inline cl_mem& Memory() {
			return memory;
		}

		cl_mem& operator() () {
			return memory;
		}

	private:
		/**
		* Rs[֎~
		*/
		CLBuffer(const CLBuffer& copy) { }

		template <typename T>
		void SizeTest(const size_t& size) const
		{
			auto argSize = size * sizeof(T);
			if (this->size < argSize)
			{
				throw CLFailedAllacException("obt@̃TCYzXg̃TCY̕傫");
			}
		}

		void ResultTest(const cl_int result) const
		{
			if (result != CL_SUCCESS)
			{
				throw CLException("WriteReadɎs܂", result);
			}
		}

		void ReadTest(const cl_uint result) const
		{
			if (result != CL_SUCCESS)
			{
				switch (result)
				{
				case CL_INVALID_COMMAND_QUEUE:
					throw CLException("R}hL[ł");
				case CL_INVALID_CONTEXT:
					throw CLException("ReNXgł");
				case CL_INVALID_MEM_OBJECT:
					throw CLException("obt@IuWFNgł");
				case CL_INVALID_VALUE:
					throw CLException("w肵ǂݍݗ̈悪͈͊Oł");
				case CL_INVALID_EVENT_WAIT_LIST:
					throw CLException("Cxg҂Xgł");
				case CL_MISALIGNED_SUB_BUFFER_OFFSET:
					throw CLException("Tuobt@̃ItZbgACgĂ܂");
				case CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST:
					throw CLException("ǂݍ݃R}hubLOǂ");
				case CL_MEM_OBJECT_ALLOCATION_FAILURE:
					throw CLException("obt@Ɗ֘Atꂽf[^ۑ̈ւ̃mۂɎs");
				case CL_OUT_OF_RESOURCES:
					throw CLException("foCX̃\[X̊mۂɎs");
				case CL_OUT_OF_HOST_MEMORY:
					throw CLException("zXg̃\[X̊mۂɎs");
				}
			}
		}

		template <typename T>
		void SafeEnqueueRead(size_t size, T* data)
		{
			auto result = clEnqueueReadBuffer(
				exec->CommandQueue(), memory, CL_TRUE,
				0, size, data,
				0, NULL, NULL);
			ReadTest(result);
		}

		template <typename T>
		void SafeEnqueueWrite(size_t size, T* data)
		{
			auto result = clEnqueueWriteBuffer(
				exec->CommandQueue(), memory, CL_TRUE,
				0, size, data,
				0, NULL, NULL);
			ResultTest(result);
		}

	protected:
		/**
		* ň̂͊댯Ȃ̂ŃftHgRXgN^͋֎~
		*/
		CLBuffer()
			: size(0) {}

		CLBuffer(const cl_mem_flags flag, const size_t size, void* hostPtr)
			: size(size)
		{
			memory = clCreateBuffer(information.context, flag, size, hostPtr, &information.result);
		}

	public:
		virtual ~CLBuffer()
		{
			clReleaseMemObject(memory);
		}

		/**
		* zXgfoCXɓ]
		*/
		template <typename T>
		CLBuffer& Write(std::vector<T>& enqueueData)
		{
			SizeTest<T>(enqueueData.size());
			//SafeEnqueueWrite(sizeof(T) * enqueueData.size(), &enqueueData[0]);
			hostDataPtr = &enqueueData[0];
			size = sizeof(T) * enqueueData.size();
			return *this;
		}

		/**
		* zXgfoCXɓ]
		*/
		template <typename T, size_t NUM>
		CLBuffer& Write(std::array<T, NUM>& enqueueData)
		{
			SizeTest<T>(enqueueData.size());
			//SafeEnqueueWrite(sizeof(T) * enqueueData.size(), &enqueueData[0]);
			hostDataPtr = &enqueueData[0];
			size = sizeof(T) * enqueueData.size();
			return *this;
		}

		/**
		* zXgfoCXɓ]
		* \attention z񓊂Ɨ܂
		*/
		template <typename TYPE>
		CLBuffer& Write(TYPE& data)
		{
			//SafeEnqueueWrite(sizeof(TYPE), &data);
			hostDataPtr = &data;
			size = sizeof(TYPE);
			return *this;
		}

		/**
		* zXgfoCXɓ]
		* \attention |C^zꍇ
		*/
		template <typename T>
		CLBuffer& Write(TYPE* data, const size_t num)
		{
			//SafeEnqueueWrite(sizeof(TYPE) * num, data);
			hostDataPtr = &data;
			size = sizeof(T);
			return *this;
		}

		/**
		* foCXzXgɓ]
		*/
		template <typename T>
		CLBuffer& Read(std::vector<T>& dequeueData)
		{
			SizeTest<T>(dequeueData.size());
			SafeEnqueueRead(sizeof(T) * dequeueData.size(), &dequeueData[0]);
			return *this;
		}

		/**
		* foCXzXgɓ]
		*/
		template <typename T, size_t NUM>
		CLBuffer& Read(std::array<T, NUM>& dequeueData)
		{
			SizeTest<T>(dequeueData.size());
			SafeEnqueueRead(sizeof(T) * dequeueData.size(), &dequeueData[0]);
			return *this;
		}

		/**
		* foCXzXgɓ]
		* \attention z񓊂Ɨ܂
		*/
		template <typename TYPE>
		CLBuffer& Read(TYPE& data)
		{
			SafeEnqueueRead(sizeof(TYPE), &data);
			return *this;
		}

		/**
		* foCXzXgɓ]
		* \attention |C^zꍇ
		*/
		template <typename TYPE>
		CLBuffer& Read(TYPE* data, const size_t num)
		{
			SafeEnqueueRead(sizeof(TYPE) * num, data);
			return *this;
		}
	};
}

#endif<|endoftext|>


<commit_before>#include<bits/stdc++.h>
using namespace std;
int main(void)
{
	for(int x=1;x<=1;x++)
	{
		char name1[10] = {0}, name2[10] = {0}, c = 'a';
		int k = x, y = 0, div = 0, tmpint1 = 0, tmpint2 = 0, basetime = 0, endtime = 0;
		string num, tmpstr;
		vector<vector<string>> v, f;
		vector<int> Note[200];
		vector<char> Time[80000];
		string on = "Note_on_c", off = "Note_off_c", head = "Header";
		bool Tr[200] = {0};
		while(k!=0)
		{
			num.push_back(k%10+48);
			k = (k-k%10)/10;
		}
		while(num.size())
		{
			name1[y++] = num.back();
			name2[y-1] = num.back();
			num.pop_back();
		}
		name1[y] = name2[y] = '.';
		name1[y+1] = 'c';
		name1[y+2] = 's';
		name1[y+3] = 'v';
		name2[y+1] = name2[y+3] = 't';
		name2[y+2] = 'x';
		FILE *fp1 = fopen(name1, "r"), *fp2 = fopen("input.txt", "a+");
		if(!fp1||!fp2)
		{
			printf("ERROR!\n");
			continue;
		}
		c = fgetc(fp1);
		while(c!=EOF)
		{
			vector<string> tmp;
			while(c!='\n'&&c!=EOF)
			{
				string temp;
				while(c!='\n'&&c!=','&&c!=EOF)
				{
					if(c == ' ') c = fgetc(fp1);
					if(c == '\n'||c == ',') break;
					temp.push_back(c);
					c = fgetc(fp1);
				}
				tmp.push_back(temp);
				if(c == '\n') break;
				c = fgetc(fp1);
			}
			v.push_back(tmp);
			c = fgetc(fp1);
		}
		for(int i=0;i<v.size();i++)
			if(v[i][2]!=head&&v[i][2]!=on&&v[i][2]!=off)
				v.erase(v.begin()+i--);
			else if(v[i][2] == head) v[i][2] = "h";
			else if(v[i][2] == on) v[i][2] = "n";
			else if(v[i][2] == off) v[i][2] = "f";
		for(int i=1;i<v.size();i++)
		{
			v[i].erase(v[i].begin());
			v[i].erase(v[i].begin()+2);
			v[i].erase(v[i].end());
		}
		tmpstr = v[0][5];
		for(auto i:v[0][5])
			div = 10*div+i-48;
		v.erase(v.begin());
		v.pop_back();
		for(auto i:v)
		{
			basetime = min(basetime, stoi(i[0]));
			endtime = max(endtime, stoi(i[0]));
		}
		endtime = 8*(endtime-basetime)/div;
		printf("%d: %d %d %d\n", x, div, basetime, endtime);
		for(auto i:v)
			Note[stoi(i.back())].push_back(8*(stoi(i.front())-basetime)/div);
		for(int i=0;i<200;i++)
			if(Note[i].size()>0)
				for(auto j:Note[i])
					Time[j].push_back(i+12);
		fprintf(fp2, "\n\n%d\n\n", x);
		for(int i=0;i<endtime+100;i++)
		{
			for(auto j:Time[i])
				Tr[j] = 1-Tr[j];
			for(int j=0;j<200;j++)
				if(Tr[j])
					fprintf(fp2, "%c", j);
			fprintf(fp2, " ");
		}
		for(int i=0;i<100;i++)
			fprintf(fp2, " ");
		fclose(fp1);
		fclose(fp2);
	}
}
<commit_msg>Shorter Codes<commit_after>#include<bits/stdc++.h>
using namespace std;
int main(void)
{
	for(int x=1;x<=1;x++)
	{
		char name1[10] = {0}, name2[10] = {0}, c = 'a';
		int k = x, y = 0, div = 0, tmpint1 = 0, tmpint2 = 0, basetime = 0, endtime = 0;
		string num, tmpstr;
		vector<vector<string>> v, f;
		vector<int> Note[200];
		vector<char> Time[80000];
		string on = "Note_on_c", off = "Note_off_c", head = "Header";
		bool Tr[88] = {0};
		num = to_string(x);
		while(num.size())
		{
			name1[y++] = num.back();
			name2[y-1] = num.back();
			num.pop_back();
		}
		name1[y] = name2[y] = '.';
		name1[y+1] = 'c';
		name1[y+2] = 's';
		name1[y+3] = 'v';
		name2[y+1] = name2[y+3] = 't';
		name2[y+2] = 'x';
		FILE *fp1 = fopen(name1, "r"), *fp2 = fopen("input.txt", "a+");
		if(!fp1||!fp2)
		{
			printf("ERROR!\n");
			continue;
		}
		c = fgetc(fp1);
		while(c!=EOF)
		{
			vector<string> tmp;
			while(c!='\n'&&c!=EOF)
			{
				string temp;
				while(c!='\n'&&c!=','&&c!=EOF)
				{
					if(c == ' ') c = fgetc(fp1);
					if(c == '\n'||c == ',') break;
					temp.push_back(c);
					c = fgetc(fp1);
				}
				tmp.push_back(temp);
				if(c == '\n') break;
				c = fgetc(fp1);
			}
			v.push_back(tmp);
			c = fgetc(fp1);
		}
		for(int i=0;i<v.size();i++)
			if(v[i][2]!=head&&v[i][2]!=on&&v[i][2]!=off)
				v.erase(v.begin()+i--);
			else if(v[i][2] == head) v[i][2] = "h";
			else if(v[i][2] == on) v[i][2] = "n";
			else if(v[i][2] == off) v[i][2] = "f";
		for(int i=1;i<v.size();i++)
		{
			v[i].erase(v[i].begin());
			v[i].erase(v[i].begin()+2);
			v[i].erase(v[i].end());
		}
		div = stoi(v[0][5]);
		v.erase(v.begin());
		v.pop_back();
		for(auto i:v)
		{
			basetime = min(basetime, stoi(i[0]));
			endtime = max(endtime, stoi(i[0]));
		}
		endtime = 8*(endtime-basetime)/div;
		printf("%d: %d %d %d\n", x, div, basetime, endtime);
		for(auto i:v)
			Note[stoi(i.back())].push_back(8*(stoi(i.front())-basetime)/div);
		for(int i=0;i<200;i++)
			if(Note[i].size()>0)
				for(auto j:Note[i])
					Time[j].push_back(i+12);
		fprintf(fp2, "\n\n%d\n\n", x);
		for(int i=0;i<endtime+100;i++)
		{
			for(auto j:Time[i])
				Tr[j] = 1-Tr[j];
			for(int j=0;j<200;j++)
				if(Tr[j])
					fprintf(fp2, "%c", j);
			fprintf(fp2, " ");
		}
		for(int i=0;i<100;i++)
			fprintf(fp2, " ");
		fclose(fp1);
		fclose(fp2);
	}
}
<|endoftext|>


<commit_before>#include "Carduino.h"
#include "LiquidCrystal.h"
#include "DHT.h"
#include "Time.h"
#include "Wire.h"
#include "DS1307RTC.h"
#include "OneWire.h"
#include "DallasTemperature.h"
#include "Arduino.h"

LiquidCrystal Carduino::LCD = LiquidCrystal(PIN_LCD_RS, PIN_LCD_ENABLE, PIN_LCD_D4, PIN_LCD_D5, PIN_LCD_D6, PIN_LCD_D7);
DHT Carduino::TEMP = DHT(PIN_DHT, DHTTYPE);
tmElements_t Carduino::TIME;
OneWire Carduino::ONEWIRE(PIN_ONE_WIRE_BUS);
DallasTemperature Carduino::SENSORS(&Carduino::ONEWIRE);
DeviceAddress Carduino::PROBE01 = { 0x28, 0xFF, 0x8F, 0x34, 0x63, 0x14, 0x02, 0x80 };

byte cBar0[8]    = { 0b11011, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11011, 0b00000 };
byte cBar50[8]   = { 0b11011, 0b11000, 0b11000, 0b11000, 0b11000, 0b11000, 0b11011, 0b00000 };
byte cBar100[8]  = { 0b11011, 0b11011, 0b11011, 0b11011, 0b11011, 0b11011, 0b11011, 0b00000 };
byte cCelcius[8] = { 0b01000, 0b10100, 0b01000, 0b00011, 0b00100, 0b00100, 0b00011, 0b00000 };
byte cEmpty[8]   = { 0b11111, 0b10001, 0b10111, 0b10011, 0b10111, 0b10001, 0b11111, 0b00000 };
byte cFull[8]    = { 0b11111, 0b10001, 0b10111, 0b10011, 0b10111, 0b10111, 0b11111, 0b00000 };
byte cLeisure[8] = { 0b11111, 0b10111, 0b10111, 0b10111, 0b10111, 0b10001, 0b11111, 0b00000 };
byte cStarter[8] = { 0b11111, 0b10001, 0b10111, 0b10001, 0b11101, 0b10001, 0b11111, 0b00000 };

float intTemp;
float extTemp;
int dist;
float distPerc;
float vStarter;
float vLeisure;
String tm;

void Carduino::begin(void) {
  Serial.println("Carduino::begin");

  setupLCD();
  setupDHT();
  setupDist();
  setupSensors();
}

void Carduino::loop(void) {
  intTemp = readIntTemp();
  extTemp = readExtTemp();
  dist = readDist();
  tm = readTime();
  vStarter = readStarterVoltage();
  vLeisure = readLeisureVoltage();

  distPerc = dist / 200.0;

  Carduino::LCD.clear();
  Carduino::LCD.setCursor(0, 0);
  Carduino::LCD.print("Int ");
  Carduino::LCD.print(intTemp, 1);
  Carduino::LCD.print((char)CHAR_CELCIUS);

  Carduino::LCD.setCursor(0, 1);
  Carduino::LCD.print("Ext ");
  Carduino::LCD.print(extTemp, 1);
  Carduino::LCD.print((char)CHAR_CELCIUS);

  Carduino::LCD.setCursor(15, 0);
  Carduino::LCD.print(tm);

  Carduino::LCD.setCursor(0, 2);
  Carduino::LCD.write(CHAR_STARTER);
  Carduino::LCD.print(vStarter, 2);
  Carduino::LCD.print("v");

  Carduino::LCD.setCursor(10, 1);
  Carduino::generateProgressBar(distPerc, LCD_COLUMNS/2);

  Carduino::LCD.setCursor(10, 2);
  Carduino::generateProgressBar(0.75, LCD_COLUMNS/2);

  Carduino::LCD.setCursor(0, 3);
  Carduino::LCD.write(CHAR_LEISURE);
  Carduino::LCD.print(vLeisure, 2);
  Carduino::LCD.print("v");

  Carduino::LCD.setCursor(10, 3);
  Carduino::generateProgressBar(0.92, LCD_COLUMNS/2);
}

void Carduino::setupLCD() {
  Serial.println("Carduino::setupLCD");
  Carduino::LCD.begin(LCD_COLUMNS, LCD_ROWS);
  Carduino::LCD.createChar(CHAR_BAR_0, cBar0);
  Carduino::LCD.createChar(CHAR_BAR_50, cBar50);
  Carduino::LCD.createChar(CHAR_BAR_100, cBar100);
  Carduino::LCD.createChar(CHAR_CELCIUS, cCelcius);
  Carduino::LCD.createChar(CHAR_EMPTY, cEmpty);
  Carduino::LCD.createChar(CHAR_FULL, cFull);
  Carduino::LCD.createChar(CHAR_LEISURE, cLeisure);
  Carduino::LCD.createChar(CHAR_STARTER, cStarter);
  Carduino::LCD.clear();
  Carduino::LCD.setCursor(6, 1);
  Carduino::LCD.print("CARDUINO");
}

void Carduino::setupDHT() {
  Serial.println("Carduino::setupDHT");
  Carduino::TEMP.begin();
}

void Carduino::setupDist() {
  Serial.println("Carduino::setupDist");
  pinMode(PIN_DIST1_TRIG, OUTPUT);
  pinMode(PIN_DIST1_ECHO, INPUT);
}

void Carduino::setupSensors() {
  Serial.println("Carduino::setupSensors");
  Carduino::SENSORS.begin();
  Carduino::SENSORS.setResolution(Carduino::PROBE01, 10);
}

void Carduino::generateProgressBar(float perc, int cols) {
  cols -= 2;
  float value = cols * perc;
  int numSolids = cols * perc;
  int numPartials = (value - numSolids) * 10;

  Carduino::LCD.write(char(CHAR_EMPTY));

  for (int i=0; i< numSolids; i++) {
    Carduino::LCD.write(char(CHAR_BAR_100));
  }
  if (numPartials >= 5) {
    Carduino::LCD.write(char(CHAR_BAR_50));
    numSolids++;
  }
  for (int i=numSolids; i< cols; i++) {
    Carduino::LCD.write(char(CHAR_BAR_0));
  }
  Carduino::LCD.write(char(CHAR_FULL));

}

float Carduino::readLeisureVoltage() {
  return 12.63;
}

float Carduino::readStarterVoltage() {
  return 12.33;
}

float Carduino::readIntTemp() {
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  // Read temperature as Celsius
  return Carduino::TEMP.readTemperature();
}

float Carduino::readExtTemp() {
  Carduino::SENSORS.requestTemperatures();
  return Carduino::SENSORS.getTempC(Carduino::PROBE01);
}

int Carduino::readDist() {
  long distance;
  int duration;

  digitalWrite(PIN_DIST1_TRIG, LOW);
  delayMicroseconds(2);

  digitalWrite(PIN_DIST1_TRIG, HIGH);
  delayMicroseconds(10);

  digitalWrite(PIN_DIST1_TRIG, LOW);

  duration = pulseIn(PIN_DIST1_ECHO, HIGH);

  // Calculate the distance (in cm) based on the speed of sound.
  distance =  duration / 58.2;

  if (distance >= 200 || distance <= 0) {
    distance = -1;
  }

  return distance;
}

String Carduino::readTime() {
  String timeToShow;
  String h, m, s, d, M, y;

  RTC.read(Carduino::TIME);

  h = print2digits(Carduino::TIME.Hour);
  m = print2digits(Carduino::TIME.Minute);
  d = print2digits(Carduino::TIME.Day);
  M = print2digits(Carduino::TIME.Month);
  y = print2digits(tmYearToCalendar(Carduino::TIME.Year));
  timeToShow = h + ':' + m;

  return timeToShow;
}

String Carduino::print2digits(int number) {
  String s;
  if (number >= 0 && number < 10) {
    s = '0' + String(number);
  } else {
    s = String(number);
  }
  return s;
}

<commit_msg>If the distance is out of max, don't display a bar<commit_after>#include "Carduino.h"
#include "LiquidCrystal.h"
#include "DHT.h"
#include "Time.h"
#include "Wire.h"
#include "DS1307RTC.h"
#include "OneWire.h"
#include "DallasTemperature.h"
#include "Arduino.h"

LiquidCrystal Carduino::LCD = LiquidCrystal(PIN_LCD_RS, PIN_LCD_ENABLE, PIN_LCD_D4, PIN_LCD_D5, PIN_LCD_D6, PIN_LCD_D7);
DHT Carduino::TEMP = DHT(PIN_DHT, DHTTYPE);
tmElements_t Carduino::TIME;
OneWire Carduino::ONEWIRE(PIN_ONE_WIRE_BUS);
DallasTemperature Carduino::SENSORS(&Carduino::ONEWIRE);
DeviceAddress Carduino::PROBE01 = { 0x28, 0xFF, 0x8F, 0x34, 0x63, 0x14, 0x02, 0x80 };

byte cBar0[8]    = { 0b11011, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11011, 0b00000 };
byte cBar50[8]   = { 0b11011, 0b11000, 0b11000, 0b11000, 0b11000, 0b11000, 0b11011, 0b00000 };
byte cBar100[8]  = { 0b11011, 0b11011, 0b11011, 0b11011, 0b11011, 0b11011, 0b11011, 0b00000 };
byte cCelcius[8] = { 0b01000, 0b10100, 0b01000, 0b00011, 0b00100, 0b00100, 0b00011, 0b00000 };
byte cEmpty[8]   = { 0b11111, 0b10001, 0b10111, 0b10011, 0b10111, 0b10001, 0b11111, 0b00000 };
byte cFull[8]    = { 0b11111, 0b10001, 0b10111, 0b10011, 0b10111, 0b10111, 0b11111, 0b00000 };
byte cLeisure[8] = { 0b11111, 0b10111, 0b10111, 0b10111, 0b10111, 0b10001, 0b11111, 0b00000 };
byte cStarter[8] = { 0b11111, 0b10001, 0b10111, 0b10001, 0b11101, 0b10001, 0b11111, 0b00000 };

float intTemp;
float extTemp;
int dist;
float distPerc;
float vStarter;
float vLeisure;
String tm;

void Carduino::begin(void) {
  Serial.println("Carduino::begin");

  setupLCD();
  setupDHT();
  setupDist();
  setupSensors();
}

void Carduino::loop(void) {
  intTemp = readIntTemp();
  extTemp = readExtTemp();
  dist = readDist();
  tm = readTime();
  vStarter = readStarterVoltage();
  vLeisure = readLeisureVoltage();

  distPerc = dist / 200.0;

  Carduino::LCD.clear();
  Carduino::LCD.setCursor(0, 0);
  Carduino::LCD.print("Int ");
  Carduino::LCD.print(intTemp, 1);
  Carduino::LCD.print((char)CHAR_CELCIUS);

  Carduino::LCD.setCursor(0, 1);
  Carduino::LCD.print("Ext ");
  Carduino::LCD.print(extTemp, 1);
  Carduino::LCD.print((char)CHAR_CELCIUS);

  Carduino::LCD.setCursor(15, 0);
  Carduino::LCD.print(tm);

  Carduino::LCD.setCursor(0, 2);
  Carduino::LCD.write(CHAR_STARTER);
  Carduino::LCD.print(vStarter, 2);
  Carduino::LCD.print("v");

  if (dist != -1) {
    Carduino::LCD.setCursor(10, 1);
    Carduino::generateProgressBar(distPerc, LCD_COLUMNS/2);
  }

  Carduino::LCD.setCursor(10, 2);
  Carduino::generateProgressBar(0.75, LCD_COLUMNS/2);

  Carduino::LCD.setCursor(0, 3);
  Carduino::LCD.write(CHAR_LEISURE);
  Carduino::LCD.print(vLeisure, 2);
  Carduino::LCD.print("v");

  Carduino::LCD.setCursor(10, 3);
  Carduino::generateProgressBar(0.92, LCD_COLUMNS/2);
}

void Carduino::setupLCD() {
  Serial.println("Carduino::setupLCD");
  Carduino::LCD.begin(LCD_COLUMNS, LCD_ROWS);
  Carduino::LCD.createChar(CHAR_BAR_0, cBar0);
  Carduino::LCD.createChar(CHAR_BAR_50, cBar50);
  Carduino::LCD.createChar(CHAR_BAR_100, cBar100);
  Carduino::LCD.createChar(CHAR_CELCIUS, cCelcius);
  Carduino::LCD.createChar(CHAR_EMPTY, cEmpty);
  Carduino::LCD.createChar(CHAR_FULL, cFull);
  Carduino::LCD.createChar(CHAR_LEISURE, cLeisure);
  Carduino::LCD.createChar(CHAR_STARTER, cStarter);
  Carduino::LCD.clear();
  Carduino::LCD.setCursor(6, 1);
  Carduino::LCD.print("CARDUINO");
}

void Carduino::setupDHT() {
  Serial.println("Carduino::setupDHT");
  Carduino::TEMP.begin();
}

void Carduino::setupDist() {
  Serial.println("Carduino::setupDist");
  pinMode(PIN_DIST1_TRIG, OUTPUT);
  pinMode(PIN_DIST1_ECHO, INPUT);
}

void Carduino::setupSensors() {
  Serial.println("Carduino::setupSensors");
  Carduino::SENSORS.begin();
  Carduino::SENSORS.setResolution(Carduino::PROBE01, 10);
}

void Carduino::generateProgressBar(float perc, int cols) {
  cols -= 2;
  float value = cols * perc;
  int numSolids = cols * perc;
  int numPartials = (value - numSolids) * 10;

  Carduino::LCD.write(char(CHAR_EMPTY));

  for (int i=0; i< numSolids; i++) {
    Carduino::LCD.write(char(CHAR_BAR_100));
  }
  if (numPartials >= 5) {
    Carduino::LCD.write(char(CHAR_BAR_50));
    numSolids++;
  }
  for (int i=numSolids; i< cols; i++) {
    Carduino::LCD.write(char(CHAR_BAR_0));
  }
  Carduino::LCD.write(char(CHAR_FULL));

}

float Carduino::readLeisureVoltage() {
  return 12.63;
}

float Carduino::readStarterVoltage() {
  return 12.33;
}

float Carduino::readIntTemp() {
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  // Read temperature as Celsius
  return Carduino::TEMP.readTemperature();
}

float Carduino::readExtTemp() {
  Carduino::SENSORS.requestTemperatures();
  return Carduino::SENSORS.getTempC(Carduino::PROBE01);
}

int Carduino::readDist() {
  long distance;
  int duration;

  digitalWrite(PIN_DIST1_TRIG, LOW);
  delayMicroseconds(2);

  digitalWrite(PIN_DIST1_TRIG, HIGH);
  delayMicroseconds(10);

  digitalWrite(PIN_DIST1_TRIG, LOW);

  duration = pulseIn(PIN_DIST1_ECHO, HIGH);

  // Calculate the distance (in cm) based on the speed of sound.
  distance =  duration / 58.2;

  if (distance >= 200 || distance <= 0) {
    distance = -1;
  }

  return distance;
}

String Carduino::readTime() {
  String timeToShow;
  String h, m, s, d, M, y;

  RTC.read(Carduino::TIME);

  h = print2digits(Carduino::TIME.Hour);
  m = print2digits(Carduino::TIME.Minute);
  d = print2digits(Carduino::TIME.Day);
  M = print2digits(Carduino::TIME.Month);
  y = print2digits(tmYearToCalendar(Carduino::TIME.Year));
  timeToShow = h + ':' + m;

  return timeToShow;
}

String Carduino::print2digits(int number) {
  String s;
  if (number >= 0 && number < 10) {
    s = '0' + String(number);
  } else {
    s = String(number);
  }
  return s;
}

<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Solidity AST to EVM bytecode compiler.
 */

#include <cassert>
#include <utility>
#include <libsolidity/AST.h>
#include <libsolidity/Compiler.h>

namespace dev {
namespace solidity {

void CompilerContext::setLabelPosition(uint32_t _label, uint32_t _position)
{
	assert(m_labelPositions.find(_label) == m_labelPositions.end());
	m_labelPositions[_label] = _position;
}

uint32_t CompilerContext::getLabelPosition(uint32_t _label) const
{
	auto iter = m_labelPositions.find(_label);
	assert(iter != m_labelPositions.end());
	return iter->second;
}

void ExpressionCompiler::compile(Expression& _expression)
{
	m_assemblyItems.clear();
	_expression.accept(*this);
}

bytes ExpressionCompiler::getAssembledBytecode() const
{
	bytes assembled;
	assembled.reserve(m_assemblyItems.size());

	// resolve label references
	for (uint32_t pos = 0; pos < m_assemblyItems.size(); ++pos)
	{
		AssemblyItem const& item = m_assemblyItems[pos];
		if (item.getType() == AssemblyItem::Type::LABEL)
			m_context.setLabelPosition(item.getLabel(), pos + 1);
	}

	for (AssemblyItem const& item: m_assemblyItems)
		if (item.getType() == AssemblyItem::Type::LABELREF)
			assembled.push_back(m_context.getLabelPosition(item.getLabel()));
		else
			assembled.push_back(item.getData());

	return assembled;
}

AssemblyItems ExpressionCompiler::compileExpression(CompilerContext& _context,
													Expression& _expression)
{
	ExpressionCompiler compiler(_context);
	compiler.compile(_expression);
	return compiler.getAssemblyItems();
}

void ExpressionCompiler::endVisit(Assignment& _assignment)
{
	Expression& rightHandSide = _assignment.getRightHandSide();
	Token::Value op = _assignment.getAssignmentOperator();
	if (op != Token::ASSIGN)
	{
		// compound assignment
		// @todo retrieve lvalue value
		rightHandSide.accept(*this);
		Type const& resultType = *_assignment.getType();
		cleanHigherOrderBitsIfNeeded(*rightHandSide.getType(), resultType);
		appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), resultType);
	}
	else
		rightHandSide.accept(*this);
	// @todo store value
}

void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation)
{
	//@todo type checking and creating code for an operator should be in the same place:
	// the operator should know how to convert itself and to which types it applies, so
	// put this code together with "Type::acceptsBinary/UnaryOperator" into a class that
	// represents the operator
	switch (_unaryOperation.getOperator())
	{
	case Token::NOT: // !
		append(eth::Instruction::NOT);
		break;
	case Token::BIT_NOT: // ~
		// ~a modeled as "a xor (0 - 1)" for now
		append(eth::Instruction::PUSH1);
		append(1);
		append(eth::Instruction::PUSH1);
		append(0);
		append(eth::Instruction::SUB);
		append(eth::Instruction::XOR);
		break;
	case Token::DELETE: // delete
		// a -> a xor a (= 0).
		// @todo this should also be an assignment
		// @todo semantics change for complex types
		append(eth::Instruction::DUP1);
		append(eth::Instruction::XOR);
		break;
	case Token::INC: // ++ (pre- or postfix)
		// @todo this should also be an assignment
		if (_unaryOperation.isPrefixOperation())
		{
			append(eth::Instruction::PUSH1);
			append(1);
			append(eth::Instruction::ADD);
		}
		break;
	case Token::DEC: // -- (pre- or postfix)
		// @todo this should also be an assignment
		if (_unaryOperation.isPrefixOperation())
		{
			append(eth::Instruction::PUSH1);
			append(1);
			append(eth::Instruction::SWAP1); //@todo avoid this
			append(eth::Instruction::SUB);
		}
		break;
	case Token::ADD: // +
		// unary add, so basically no-op
		break;
	case Token::SUB: // -
		append(eth::Instruction::NEG);
		break;
	default:
		assert(false); // invalid operation
	}
}

bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation)
{
	Expression& leftExpression = _binaryOperation.getLeftExpression();
	Expression& rightExpression = _binaryOperation.getRightExpression();
	Type const& resultType = *_binaryOperation.getType();
	Token::Value const op = _binaryOperation.getOperator();

	if (op == Token::AND || op == Token::OR)
	{
		// special case: short-circuiting
		appendAndOrOperatorCode(_binaryOperation);
	}
	else if (Token::isCompareOp(op))
	{
		leftExpression.accept(*this);
		rightExpression.accept(*this);

		// the types to compare have to be the same, but the resulting type is always bool
		assert(*leftExpression.getType() == *rightExpression.getType());
		appendCompareOperatorCode(op, *leftExpression.getType());
	}
	else
	{
		leftExpression.accept(*this);
		cleanHigherOrderBitsIfNeeded(*leftExpression.getType(), resultType);
		rightExpression.accept(*this);
		cleanHigherOrderBitsIfNeeded(*rightExpression.getType(), resultType);
		appendOrdinaryBinaryOperatorCode(op, resultType);
	}

	// do not visit the child nodes, we already did that explicitly
	return false;
}

void ExpressionCompiler::endVisit(FunctionCall& _functionCall)
{
	if (_functionCall.isTypeConversion())
	{
		//@todo binary representation for all supported types (bool and int) is the same, so no-op
		// here for now.
	}
	else
	{
		//@todo
	}
}

void ExpressionCompiler::endVisit(MemberAccess&)
{

}

void ExpressionCompiler::endVisit(IndexAccess&)
{

}

void ExpressionCompiler::endVisit(Identifier&)
{

}

void ExpressionCompiler::endVisit(Literal& _literal)
{
	switch (_literal.getType()->getCategory())
	{
	case Type::Category::INTEGER:
	case Type::Category::BOOL:
	{
		bytes value = _literal.getType()->literalToBigEndian(_literal);
		assert(value.size() <= 32);
		assert(!value.empty());
		append(static_cast<byte>(eth::Instruction::PUSH1) + static_cast<byte>(value.size() - 1));
		append(value);
		break;
	}
	default:
		assert(false); // @todo
	}
}

void ExpressionCompiler::cleanHigherOrderBitsIfNeeded(const Type& _typeOnStack, const Type& _targetType)
{
	// If the type of one of the operands is extended, we need to remove all
	// higher-order bits that we might have ignored in previous operations.
	// @todo: store in the AST whether the operand might have "dirty" higher
	// order bits

	if (_typeOnStack == _targetType)
		return;
	if (_typeOnStack.getCategory() == Type::Category::INTEGER &&
			_targetType.getCategory() == Type::Category::INTEGER)
	{
		//@todo
	}
	else
	{
		// If we get here, there is either an implementation missing to clean higher oder bits
		// for non-integer types that are explicitly convertible or we got here in error.
		assert(!_typeOnStack.isExplicitlyConvertibleTo(_targetType));
		assert(false); // these types should not be convertible.
	}
}

void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation)
{
	Token::Value const op = _binaryOperation.getOperator();
	assert(op == Token::OR || op == Token::AND);

	_binaryOperation.getLeftExpression().accept(*this);
	append(eth::Instruction::DUP1);
	if (op == Token::AND)
		append(eth::Instruction::NOT);
	uint32_t endLabel = appendConditionalJump();
	_binaryOperation.getRightExpression().accept(*this);
	appendLabel(endLabel);
}

void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type const& _type)
{
	if (_operator == Token::EQ || _operator == Token::NE)
	{
		append(eth::Instruction::EQ);
		if (_operator == Token::NE)
			append(eth::Instruction::NOT);
	}
	else
	{
		IntegerType const* type = dynamic_cast<IntegerType const*>(&_type);
		assert(type);
		bool const isSigned = type->isSigned();

		// note that EVM opcodes compare like "stack[0] < stack[1]",
		// but our left value is at stack[1], so everyhing is reversed.
		switch (_operator)
		{
		case Token::GTE:
			append(isSigned ? eth::Instruction::SGT : eth::Instruction::GT);
			append(eth::Instruction::NOT);
			break;
		case Token::LTE:
			append(isSigned ? eth::Instruction::SLT : eth::Instruction::LT);
			append(eth::Instruction::NOT);
			break;
		case Token::GT:
			append(isSigned ? eth::Instruction::SLT : eth::Instruction::LT);
			break;
		case Token::LT:
			append(isSigned ? eth::Instruction::SGT : eth::Instruction::GT);
			break;
		default:
			assert(false);
		}
	}
}

void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type)
{
	if (Token::isArithmeticOp(_operator))
		appendArithmeticOperatorCode(_operator, _type);
	else if (Token::isBitOp(_operator))
		appendBitOperatorCode(_operator);
	else if (Token::isShiftOp(_operator))
		appendShiftOperatorCode(_operator);
	else
		assert(false); // unknown binary operator
}

void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type)
{
	IntegerType const* type = dynamic_cast<IntegerType const*>(&_type);
	assert(type);
	bool const isSigned = type->isSigned();

	switch (_operator)
	{
	case Token::ADD:
		append(eth::Instruction::ADD);
		break;
	case Token::SUB:
		append(eth::Instruction::SWAP1);
		append(eth::Instruction::SUB);
		break;
	case Token::MUL:
		append(eth::Instruction::MUL);
		break;
	case Token::DIV:
		append(isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV);
		break;
	case Token::MOD:
		append(isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD);
		break;
	default:
		assert(false);
	}
}

void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator)
{
	switch (_operator)
	{
	case Token::BIT_OR:
		append(eth::Instruction::OR);
		break;
	case Token::BIT_AND:
		append(eth::Instruction::AND);
		break;
	case Token::BIT_XOR:
		append(eth::Instruction::XOR);
		break;
	default:
		assert(false);
	}
}

void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator)
{
	switch (_operator)
	{
	case Token::SHL:
		assert(false); //@todo
		break;
	case Token::SAR:
		assert(false); //@todo
		break;
	default:
		assert(false);
	}
}

uint32_t ExpressionCompiler::appendConditionalJump()
{
	uint32_t label = m_context.dispenseNewLabel();
	append(eth::Instruction::PUSH1);
	appendLabelref(label);
	append(eth::Instruction::JUMPI);
	return label;
}

void ExpressionCompiler::append(bytes const& _data)
{
	m_assemblyItems.reserve(m_assemblyItems.size() + _data.size());
	for (byte b: _data)
		append(b);
}

}
}
<commit_msg>Adjustments for the NEG->BNOT change.<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Solidity AST to EVM bytecode compiler.
 */

#include <cassert>
#include <utility>
#include <libsolidity/AST.h>
#include <libsolidity/Compiler.h>

namespace dev {
namespace solidity {

void CompilerContext::setLabelPosition(uint32_t _label, uint32_t _position)
{
	assert(m_labelPositions.find(_label) == m_labelPositions.end());
	m_labelPositions[_label] = _position;
}

uint32_t CompilerContext::getLabelPosition(uint32_t _label) const
{
	auto iter = m_labelPositions.find(_label);
	assert(iter != m_labelPositions.end());
	return iter->second;
}

void ExpressionCompiler::compile(Expression& _expression)
{
	m_assemblyItems.clear();
	_expression.accept(*this);
}

bytes ExpressionCompiler::getAssembledBytecode() const
{
	bytes assembled;
	assembled.reserve(m_assemblyItems.size());

	// resolve label references
	for (uint32_t pos = 0; pos < m_assemblyItems.size(); ++pos)
	{
		AssemblyItem const& item = m_assemblyItems[pos];
		if (item.getType() == AssemblyItem::Type::LABEL)
			m_context.setLabelPosition(item.getLabel(), pos + 1);
	}

	for (AssemblyItem const& item: m_assemblyItems)
		if (item.getType() == AssemblyItem::Type::LABELREF)
			assembled.push_back(m_context.getLabelPosition(item.getLabel()));
		else
			assembled.push_back(item.getData());

	return assembled;
}

AssemblyItems ExpressionCompiler::compileExpression(CompilerContext& _context,
													Expression& _expression)
{
	ExpressionCompiler compiler(_context);
	compiler.compile(_expression);
	return compiler.getAssemblyItems();
}

void ExpressionCompiler::endVisit(Assignment& _assignment)
{
	Expression& rightHandSide = _assignment.getRightHandSide();
	Token::Value op = _assignment.getAssignmentOperator();
	if (op != Token::ASSIGN)
	{
		// compound assignment
		// @todo retrieve lvalue value
		rightHandSide.accept(*this);
		Type const& resultType = *_assignment.getType();
		cleanHigherOrderBitsIfNeeded(*rightHandSide.getType(), resultType);
		appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), resultType);
	}
	else
		rightHandSide.accept(*this);
	// @todo store value
}

void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation)
{
	//@todo type checking and creating code for an operator should be in the same place:
	// the operator should know how to convert itself and to which types it applies, so
	// put this code together with "Type::acceptsBinary/UnaryOperator" into a class that
	// represents the operator
	switch (_unaryOperation.getOperator())
	{
	case Token::NOT: // !
		append(eth::Instruction::NOT);
		break;
	case Token::BIT_NOT: // ~
		append(eth::Instruction::BNOT);
		break;
	case Token::DELETE: // delete
		// a -> a xor a (= 0).
		// @todo this should also be an assignment
		// @todo semantics change for complex types
		append(eth::Instruction::DUP1);
		append(eth::Instruction::XOR);
		break;
	case Token::INC: // ++ (pre- or postfix)
		// @todo this should also be an assignment
		if (_unaryOperation.isPrefixOperation())
		{
			append(eth::Instruction::PUSH1);
			append(1);
			append(eth::Instruction::ADD);
		}
		break;
	case Token::DEC: // -- (pre- or postfix)
		// @todo this should also be an assignment
		if (_unaryOperation.isPrefixOperation())
		{
			append(eth::Instruction::PUSH1);
			append(1);
			append(eth::Instruction::SWAP1); //@todo avoid this
			append(eth::Instruction::SUB);
		}
		break;
	case Token::ADD: // +
		// unary add, so basically no-op
		break;
	case Token::SUB: // -
		// unary -x translates into "0-x"
		append(eth::Instruction::PUSH1);
		append(0);
		append(eth::Instruction::SUB);
		break;
	default:
		assert(false); // invalid operation
	}
}

bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation)
{
	Expression& leftExpression = _binaryOperation.getLeftExpression();
	Expression& rightExpression = _binaryOperation.getRightExpression();
	Type const& resultType = *_binaryOperation.getType();
	Token::Value const op = _binaryOperation.getOperator();

	if (op == Token::AND || op == Token::OR)
	{
		// special case: short-circuiting
		appendAndOrOperatorCode(_binaryOperation);
	}
	else if (Token::isCompareOp(op))
	{
		leftExpression.accept(*this);
		rightExpression.accept(*this);

		// the types to compare have to be the same, but the resulting type is always bool
		assert(*leftExpression.getType() == *rightExpression.getType());
		appendCompareOperatorCode(op, *leftExpression.getType());
	}
	else
	{
		leftExpression.accept(*this);
		cleanHigherOrderBitsIfNeeded(*leftExpression.getType(), resultType);
		rightExpression.accept(*this);
		cleanHigherOrderBitsIfNeeded(*rightExpression.getType(), resultType);
		appendOrdinaryBinaryOperatorCode(op, resultType);
	}

	// do not visit the child nodes, we already did that explicitly
	return false;
}

void ExpressionCompiler::endVisit(FunctionCall& _functionCall)
{
	if (_functionCall.isTypeConversion())
	{
		//@todo binary representation for all supported types (bool and int) is the same, so no-op
		// here for now.
	}
	else
	{
		//@todo
	}
}

void ExpressionCompiler::endVisit(MemberAccess&)
{

}

void ExpressionCompiler::endVisit(IndexAccess&)
{

}

void ExpressionCompiler::endVisit(Identifier&)
{

}

void ExpressionCompiler::endVisit(Literal& _literal)
{
	switch (_literal.getType()->getCategory())
	{
	case Type::Category::INTEGER:
	case Type::Category::BOOL:
	{
		bytes value = _literal.getType()->literalToBigEndian(_literal);
		assert(value.size() <= 32);
		assert(!value.empty());
		append(static_cast<byte>(eth::Instruction::PUSH1) + static_cast<byte>(value.size() - 1));
		append(value);
		break;
	}
	default:
		assert(false); // @todo
	}
}

void ExpressionCompiler::cleanHigherOrderBitsIfNeeded(const Type& _typeOnStack, const Type& _targetType)
{
	// If the type of one of the operands is extended, we need to remove all
	// higher-order bits that we might have ignored in previous operations.
	// @todo: store in the AST whether the operand might have "dirty" higher
	// order bits

	if (_typeOnStack == _targetType)
		return;
	if (_typeOnStack.getCategory() == Type::Category::INTEGER &&
			_targetType.getCategory() == Type::Category::INTEGER)
	{
		//@todo
	}
	else
	{
		// If we get here, there is either an implementation missing to clean higher oder bits
		// for non-integer types that are explicitly convertible or we got here in error.
		assert(!_typeOnStack.isExplicitlyConvertibleTo(_targetType));
		assert(false); // these types should not be convertible.
	}
}

void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation)
{
	Token::Value const op = _binaryOperation.getOperator();
	assert(op == Token::OR || op == Token::AND);

	_binaryOperation.getLeftExpression().accept(*this);
	append(eth::Instruction::DUP1);
	if (op == Token::AND)
		append(eth::Instruction::NOT);
	uint32_t endLabel = appendConditionalJump();
	_binaryOperation.getRightExpression().accept(*this);
	appendLabel(endLabel);
}

void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type const& _type)
{
	if (_operator == Token::EQ || _operator == Token::NE)
	{
		append(eth::Instruction::EQ);
		if (_operator == Token::NE)
			append(eth::Instruction::NOT);
	}
	else
	{
		IntegerType const* type = dynamic_cast<IntegerType const*>(&_type);
		assert(type);
		bool const isSigned = type->isSigned();

		// note that EVM opcodes compare like "stack[0] < stack[1]",
		// but our left value is at stack[1], so everyhing is reversed.
		switch (_operator)
		{
		case Token::GTE:
			append(isSigned ? eth::Instruction::SGT : eth::Instruction::GT);
			append(eth::Instruction::NOT);
			break;
		case Token::LTE:
			append(isSigned ? eth::Instruction::SLT : eth::Instruction::LT);
			append(eth::Instruction::NOT);
			break;
		case Token::GT:
			append(isSigned ? eth::Instruction::SLT : eth::Instruction::LT);
			break;
		case Token::LT:
			append(isSigned ? eth::Instruction::SGT : eth::Instruction::GT);
			break;
		default:
			assert(false);
		}
	}
}

void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type)
{
	if (Token::isArithmeticOp(_operator))
		appendArithmeticOperatorCode(_operator, _type);
	else if (Token::isBitOp(_operator))
		appendBitOperatorCode(_operator);
	else if (Token::isShiftOp(_operator))
		appendShiftOperatorCode(_operator);
	else
		assert(false); // unknown binary operator
}

void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type)
{
	IntegerType const* type = dynamic_cast<IntegerType const*>(&_type);
	assert(type);
	bool const isSigned = type->isSigned();

	switch (_operator)
	{
	case Token::ADD:
		append(eth::Instruction::ADD);
		break;
	case Token::SUB:
		append(eth::Instruction::SWAP1);
		append(eth::Instruction::SUB);
		break;
	case Token::MUL:
		append(eth::Instruction::MUL);
		break;
	case Token::DIV:
		append(isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV);
		break;
	case Token::MOD:
		append(isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD);
		break;
	default:
		assert(false);
	}
}

void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator)
{
	switch (_operator)
	{
	case Token::BIT_OR:
		append(eth::Instruction::OR);
		break;
	case Token::BIT_AND:
		append(eth::Instruction::AND);
		break;
	case Token::BIT_XOR:
		append(eth::Instruction::XOR);
		break;
	default:
		assert(false);
	}
}

void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator)
{
	switch (_operator)
	{
	case Token::SHL:
		assert(false); //@todo
		break;
	case Token::SAR:
		assert(false); //@todo
		break;
	default:
		assert(false);
	}
}

uint32_t ExpressionCompiler::appendConditionalJump()
{
	uint32_t label = m_context.dispenseNewLabel();
	append(eth::Instruction::PUSH1);
	appendLabelref(label);
	append(eth::Instruction::JUMPI);
	return label;
}

void ExpressionCompiler::append(bytes const& _data)
{
	m_assemblyItems.reserve(m_assemblyItems.size() + _data.size());
	for (byte b: _data)
		append(b);
}

}
}
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Solidity compiler.
 */

#include <algorithm>
#include <libevmcore/Instruction.h>
#include <libevmcore/Assembly.h>
#include <libsolidity/AST.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/ExpressionCompiler.h>
#include <libsolidity/CompilerUtils.h>

using namespace std;

namespace dev {
namespace solidity {

void Compiler::compileContract(ContractDefinition const& _contract, vector<MagicVariableDeclaration const*> const& _magicGlobals)
{
	m_context = CompilerContext(); // clear it just in case

	for (MagicVariableDeclaration const* variable: _magicGlobals)
		m_context.addMagicGlobal(*variable);

	for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
		if (function->getName() != _contract.getName()) // don't add the constructor here
			m_context.addFunction(*function);
	registerStateVariables(_contract);

	appendFunctionSelector(_contract);
	for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
		if (function->getName() != _contract.getName()) // don't add the constructor here
			function->accept(*this);

	packIntoContractCreator(_contract);
}

void Compiler::packIntoContractCreator(ContractDefinition const& _contract)
{
	CompilerContext runtimeContext;
	swap(m_context, runtimeContext);

	registerStateVariables(_contract);

	FunctionDefinition* constructor = nullptr;
	for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
		if (function->getName() == _contract.getName())
		{
			constructor = function.get();
			break;
		}
	if (constructor)
	{
		eth::AssemblyItem returnTag = m_context.pushNewTag();
		m_context.addFunction(*constructor); // note that it cannot be called due to syntactic reasons
		//@todo copy constructor arguments from calldata to memory prior to this
		//@todo calling other functions inside the constructor should either trigger a parse error
		//or we should copy them here (register them above and call "accept") - detecting which
		// functions are referenced / called needs to be done in a recursive way.
		appendCalldataUnpacker(*constructor, true);
		m_context.appendJumpTo(m_context.getFunctionEntryLabel(*constructor));
		constructor->accept(*this);
		m_context << returnTag;
	}

	eth::AssemblyItem sub = m_context.addSubroutine(runtimeContext.getAssembly());
	// stack contains sub size
	m_context << eth::Instruction::DUP1 << sub << u256(0) << eth::Instruction::CODECOPY;
	m_context << u256(0) << eth::Instruction::RETURN;
}

void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
{
	vector<FunctionDefinition const*> interfaceFunctions = _contract.getInterfaceFunctions();
	vector<eth::AssemblyItem> callDataUnpackerEntryPoints;

	if (interfaceFunctions.size() > 255)
		BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("More than 255 public functions for contract."));

	// retrieve the first byte of the call data, which determines the called function
	// @todo This code had a jump table in a previous version which was more efficient but also
	// error prone (due to the optimizer and variable length tag addresses)
	m_context << u256(1) << u256(0) // some constants
			  << eth::dupInstruction(1) << eth::Instruction::CALLDATALOAD
			  << eth::dupInstruction(2) << eth::Instruction::BYTE
			  << eth::dupInstruction(2);

	// stack here: 1 0 <funid> 0, stack top will be counted up until it matches funid
	for (unsigned funid = 0; funid < interfaceFunctions.size(); ++funid)
	{
		callDataUnpackerEntryPoints.push_back(m_context.newTag());
		m_context << eth::dupInstruction(2) << eth::dupInstruction(2) << eth::Instruction::EQ;
		m_context.appendConditionalJumpTo(callDataUnpackerEntryPoints.back());
		m_context << eth::dupInstruction(4) << eth::Instruction::ADD;
		//@todo avoid the last ADD (or remove it in the optimizer)
	}
	m_context << eth::Instruction::STOP; // function not found

	for (unsigned funid = 0; funid < interfaceFunctions.size(); ++funid)
	{
		FunctionDefinition const& function = *interfaceFunctions[funid];
		m_context << callDataUnpackerEntryPoints[funid];
		eth::AssemblyItem returnTag = m_context.pushNewTag();
		appendCalldataUnpacker(function);
		m_context.appendJumpTo(m_context.getFunctionEntryLabel(function));
		m_context << returnTag;
		appendReturnValuePacker(function);
	}
}

unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, bool _fromMemory)
{
	// We do not check the calldata size, everything is zero-padded.
	unsigned dataOffset = 1;
	eth::Instruction load = _fromMemory ? eth::Instruction::MLOAD : eth::Instruction::CALLDATALOAD;

	//@todo this can be done more efficiently, saving some CALLDATALOAD calls
	for (ASTPointer<VariableDeclaration> const& var: _function.getParameters())
	{
		unsigned const numBytes = var->getType()->getCalldataEncodedSize();
		if (numBytes == 0 || numBytes > 32)
			BOOST_THROW_EXCEPTION(CompilerError()
								  << errinfo_sourceLocation(var->getLocation())
								  << errinfo_comment("Type " + var->getType()->toString() + " not yet supported."));
		if (numBytes == 32)
			m_context << u256(dataOffset) << load;
		else
			m_context << (u256(1) << ((32 - numBytes) * 8)) << u256(dataOffset)
					  << load << eth::Instruction::DIV;
		dataOffset += numBytes;
	}
	return dataOffset;
}

void Compiler::appendReturnValuePacker(FunctionDefinition const& _function)
{
	//@todo this can be also done more efficiently
	unsigned dataOffset = 0;
	vector<ASTPointer<VariableDeclaration>> const& parameters = _function.getReturnParameters();
	unsigned stackDepth = CompilerUtils(m_context).getSizeOnStack(parameters);
	for (unsigned i = 0; i < parameters.size(); ++i)
	{
		Type const& paramType = *parameters[i]->getType();
		unsigned numBytes = paramType.getCalldataEncodedSize();
		if (numBytes == 0 || numBytes > 32)
			BOOST_THROW_EXCEPTION(CompilerError()
								  << errinfo_sourceLocation(parameters[i]->getLocation())
								  << errinfo_comment("Type " + paramType.toString() + " not yet supported."));
		CompilerUtils(m_context).copyToStackTop(stackDepth, paramType);
		if (numBytes != 32)
			m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL;
		m_context << u256(dataOffset) << eth::Instruction::MSTORE;
		stackDepth -= paramType.getSizeOnStack();
		dataOffset += numBytes;
	}
	// note that the stack is not cleaned up here
	m_context << u256(dataOffset) << u256(0) << eth::Instruction::RETURN;
}

void Compiler::registerStateVariables(ContractDefinition const& _contract)
{
	//@todo sort them?
	for (ASTPointer<VariableDeclaration> const& variable: _contract.getStateVariables())
		m_context.addStateVariable(*variable);
}

bool Compiler::visit(FunctionDefinition const& _function)
{
	//@todo to simplify this, the calling convention could by changed such that
	// caller puts: [retarg0] ... [retargm] [return address] [arg0] ... [argn]
	// although note that this reduces the size of the visible stack

	m_context.startNewFunction();
	m_returnTag = m_context.newTag();
	m_breakTags.clear();
	m_continueTags.clear();

	m_context << m_context.getFunctionEntryLabel(_function);

	// stack upon entry: [return address] [arg0] [arg1] ... [argn]
	// reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp]

	for (ASTPointer<VariableDeclaration const> const& variable: _function.getParameters())
		m_context.addVariable(*variable);
	for (ASTPointer<VariableDeclaration const> const& variable: _function.getReturnParameters())
		m_context.addAndInitializeVariable(*variable);
	for (VariableDeclaration const* localVariable: _function.getLocalVariables())
		m_context.addAndInitializeVariable(*localVariable);

	_function.getBody().accept(*this);

	m_context << m_returnTag;

	// Now we need to re-shuffle the stack. For this we keep a record of the stack layout
	// that shows the target positions of the elements, where "-1" denotes that this element needs
	// to be removed from the stack.
	// Note that the fact that the return arguments are of increasing index is vital for this
	// algorithm to work.

	unsigned const argumentsSize = CompilerUtils::getSizeOnStack(_function.getParameters());
	unsigned const returnValuesSize = CompilerUtils::getSizeOnStack(_function.getReturnParameters());
	unsigned const localVariablesSize = CompilerUtils::getSizeOnStack(_function.getLocalVariables());

	vector<int> stackLayout;
	stackLayout.push_back(returnValuesSize); // target of return address
	stackLayout += vector<int>(argumentsSize, -1); // discard all arguments
	for (unsigned i = 0; i < returnValuesSize; ++i)
		stackLayout.push_back(i);
	stackLayout += vector<int>(localVariablesSize, -1);

	while (stackLayout.back() != int(stackLayout.size() - 1))
		if (stackLayout.back() < 0)
		{
			m_context << eth::Instruction::POP;
			stackLayout.pop_back();
		}
		else
		{
			m_context << eth::swapInstruction(stackLayout.size() - stackLayout.back() - 1);
			swap(stackLayout[stackLayout.back()], stackLayout.back());
		}
	//@todo assert that everything is in place now

	m_context << eth::Instruction::JUMP;

	return false;
}

bool Compiler::visit(IfStatement const& _ifStatement)
{
	compileExpression(_ifStatement.getCondition());
	eth::AssemblyItem trueTag = m_context.appendConditionalJump();
	if (_ifStatement.getFalseStatement())
		_ifStatement.getFalseStatement()->accept(*this);
	eth::AssemblyItem endTag = m_context.appendJumpToNew();
	m_context << trueTag;
	_ifStatement.getTrueStatement().accept(*this);
	m_context << endTag;
	return false;
}

bool Compiler::visit(WhileStatement const& _whileStatement)
{
	eth::AssemblyItem loopStart = m_context.newTag();
	eth::AssemblyItem loopEnd = m_context.newTag();
	m_continueTags.push_back(loopStart);
	m_breakTags.push_back(loopEnd);

	m_context << loopStart;
	compileExpression(_whileStatement.getCondition());
	m_context << eth::Instruction::ISZERO;
	m_context.appendConditionalJumpTo(loopEnd);

	_whileStatement.getBody().accept(*this);

	m_context.appendJumpTo(loopStart);
	m_context << loopEnd;

	m_continueTags.pop_back();
	m_breakTags.pop_back();
	return false;
}

bool Compiler::visit(Continue const&)
{
	if (!m_continueTags.empty())
		m_context.appendJumpTo(m_continueTags.back());
	return false;
}

bool Compiler::visit(Break const&)
{
	if (!m_breakTags.empty())
		m_context.appendJumpTo(m_breakTags.back());
	return false;
}

bool Compiler::visit(Return const& _return)
{
	//@todo modifications are needed to make this work with functions returning multiple values
	if (Expression const* expression = _return.getExpression())
	{
		compileExpression(*expression);
		VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front();
		ExpressionCompiler::appendTypeConversion(m_context, *expression->getType(), *firstVariable.getType());

		CompilerUtils(m_context).moveToStackVariable(firstVariable);
	}
	m_context.appendJumpTo(m_returnTag);
	return false;
}

bool Compiler::visit(VariableDefinition const& _variableDefinition)
{
	if (Expression const* expression = _variableDefinition.getExpression())
	{
		compileExpression(*expression);
		ExpressionCompiler::appendTypeConversion(m_context,
												 *expression->getType(),
												 *_variableDefinition.getDeclaration().getType());
		CompilerUtils(m_context).moveToStackVariable(_variableDefinition.getDeclaration());
	}
	return false;
}

bool Compiler::visit(ExpressionStatement const& _expressionStatement)
{
	Expression const& expression = _expressionStatement.getExpression();
	compileExpression(expression);
	CompilerUtils(m_context).popStackElement(*expression.getType());
	return false;
}

void Compiler::compileExpression(Expression const& _expression)
{
	ExpressionCompiler::compileExpression(m_context, _expression, m_optimize);
}

}
}
<commit_msg>Do not add at the end of the function selector "loop".<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Solidity compiler.
 */

#include <algorithm>
#include <libevmcore/Instruction.h>
#include <libevmcore/Assembly.h>
#include <libsolidity/AST.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/ExpressionCompiler.h>
#include <libsolidity/CompilerUtils.h>

using namespace std;

namespace dev {
namespace solidity {

void Compiler::compileContract(ContractDefinition const& _contract, vector<MagicVariableDeclaration const*> const& _magicGlobals)
{
	m_context = CompilerContext(); // clear it just in case

	for (MagicVariableDeclaration const* variable: _magicGlobals)
		m_context.addMagicGlobal(*variable);

	for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
		if (function->getName() != _contract.getName()) // don't add the constructor here
			m_context.addFunction(*function);
	registerStateVariables(_contract);

	appendFunctionSelector(_contract);
	for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
		if (function->getName() != _contract.getName()) // don't add the constructor here
			function->accept(*this);

	packIntoContractCreator(_contract);
}

void Compiler::packIntoContractCreator(ContractDefinition const& _contract)
{
	CompilerContext runtimeContext;
	swap(m_context, runtimeContext);

	registerStateVariables(_contract);

	FunctionDefinition* constructor = nullptr;
	for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
		if (function->getName() == _contract.getName())
		{
			constructor = function.get();
			break;
		}
	if (constructor)
	{
		eth::AssemblyItem returnTag = m_context.pushNewTag();
		m_context.addFunction(*constructor); // note that it cannot be called due to syntactic reasons
		//@todo copy constructor arguments from calldata to memory prior to this
		//@todo calling other functions inside the constructor should either trigger a parse error
		//or we should copy them here (register them above and call "accept") - detecting which
		// functions are referenced / called needs to be done in a recursive way.
		appendCalldataUnpacker(*constructor, true);
		m_context.appendJumpTo(m_context.getFunctionEntryLabel(*constructor));
		constructor->accept(*this);
		m_context << returnTag;
	}

	eth::AssemblyItem sub = m_context.addSubroutine(runtimeContext.getAssembly());
	// stack contains sub size
	m_context << eth::Instruction::DUP1 << sub << u256(0) << eth::Instruction::CODECOPY;
	m_context << u256(0) << eth::Instruction::RETURN;
}

void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
{
	vector<FunctionDefinition const*> interfaceFunctions = _contract.getInterfaceFunctions();
	vector<eth::AssemblyItem> callDataUnpackerEntryPoints;

	if (interfaceFunctions.size() > 255)
		BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("More than 255 public functions for contract."));

	// retrieve the first byte of the call data, which determines the called function
	// @todo This code had a jump table in a previous version which was more efficient but also
	// error prone (due to the optimizer and variable length tag addresses)
	m_context << u256(1) << u256(0) // some constants
			  << eth::dupInstruction(1) << eth::Instruction::CALLDATALOAD
			  << eth::dupInstruction(2) << eth::Instruction::BYTE
			  << eth::dupInstruction(2);

	// stack here: 1 0 <funid> 0, stack top will be counted up until it matches funid
	for (unsigned funid = 0; funid < interfaceFunctions.size(); ++funid)
	{
		callDataUnpackerEntryPoints.push_back(m_context.newTag());
		m_context << eth::dupInstruction(2) << eth::dupInstruction(2) << eth::Instruction::EQ;
		m_context.appendConditionalJumpTo(callDataUnpackerEntryPoints.back());
		if (funid < interfaceFunctions.size() - 1)
			m_context << eth::dupInstruction(4) << eth::Instruction::ADD;
	}
	m_context << eth::Instruction::STOP; // function not found

	for (unsigned funid = 0; funid < interfaceFunctions.size(); ++funid)
	{
		FunctionDefinition const& function = *interfaceFunctions[funid];
		m_context << callDataUnpackerEntryPoints[funid];
		eth::AssemblyItem returnTag = m_context.pushNewTag();
		appendCalldataUnpacker(function);
		m_context.appendJumpTo(m_context.getFunctionEntryLabel(function));
		m_context << returnTag;
		appendReturnValuePacker(function);
	}
}

unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, bool _fromMemory)
{
	// We do not check the calldata size, everything is zero-padded.
	unsigned dataOffset = 1;
	eth::Instruction load = _fromMemory ? eth::Instruction::MLOAD : eth::Instruction::CALLDATALOAD;

	//@todo this can be done more efficiently, saving some CALLDATALOAD calls
	for (ASTPointer<VariableDeclaration> const& var: _function.getParameters())
	{
		unsigned const numBytes = var->getType()->getCalldataEncodedSize();
		if (numBytes == 0 || numBytes > 32)
			BOOST_THROW_EXCEPTION(CompilerError()
								  << errinfo_sourceLocation(var->getLocation())
								  << errinfo_comment("Type " + var->getType()->toString() + " not yet supported."));
		if (numBytes == 32)
			m_context << u256(dataOffset) << load;
		else
			m_context << (u256(1) << ((32 - numBytes) * 8)) << u256(dataOffset)
					  << load << eth::Instruction::DIV;
		dataOffset += numBytes;
	}
	return dataOffset;
}

void Compiler::appendReturnValuePacker(FunctionDefinition const& _function)
{
	//@todo this can be also done more efficiently
	unsigned dataOffset = 0;
	vector<ASTPointer<VariableDeclaration>> const& parameters = _function.getReturnParameters();
	unsigned stackDepth = CompilerUtils(m_context).getSizeOnStack(parameters);
	for (unsigned i = 0; i < parameters.size(); ++i)
	{
		Type const& paramType = *parameters[i]->getType();
		unsigned numBytes = paramType.getCalldataEncodedSize();
		if (numBytes == 0 || numBytes > 32)
			BOOST_THROW_EXCEPTION(CompilerError()
								  << errinfo_sourceLocation(parameters[i]->getLocation())
								  << errinfo_comment("Type " + paramType.toString() + " not yet supported."));
		CompilerUtils(m_context).copyToStackTop(stackDepth, paramType);
		if (numBytes != 32)
			m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL;
		m_context << u256(dataOffset) << eth::Instruction::MSTORE;
		stackDepth -= paramType.getSizeOnStack();
		dataOffset += numBytes;
	}
	// note that the stack is not cleaned up here
	m_context << u256(dataOffset) << u256(0) << eth::Instruction::RETURN;
}

void Compiler::registerStateVariables(ContractDefinition const& _contract)
{
	//@todo sort them?
	for (ASTPointer<VariableDeclaration> const& variable: _contract.getStateVariables())
		m_context.addStateVariable(*variable);
}

bool Compiler::visit(FunctionDefinition const& _function)
{
	//@todo to simplify this, the calling convention could by changed such that
	// caller puts: [retarg0] ... [retargm] [return address] [arg0] ... [argn]
	// although note that this reduces the size of the visible stack

	m_context.startNewFunction();
	m_returnTag = m_context.newTag();
	m_breakTags.clear();
	m_continueTags.clear();

	m_context << m_context.getFunctionEntryLabel(_function);

	// stack upon entry: [return address] [arg0] [arg1] ... [argn]
	// reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp]

	for (ASTPointer<VariableDeclaration const> const& variable: _function.getParameters())
		m_context.addVariable(*variable);
	for (ASTPointer<VariableDeclaration const> const& variable: _function.getReturnParameters())
		m_context.addAndInitializeVariable(*variable);
	for (VariableDeclaration const* localVariable: _function.getLocalVariables())
		m_context.addAndInitializeVariable(*localVariable);

	_function.getBody().accept(*this);

	m_context << m_returnTag;

	// Now we need to re-shuffle the stack. For this we keep a record of the stack layout
	// that shows the target positions of the elements, where "-1" denotes that this element needs
	// to be removed from the stack.
	// Note that the fact that the return arguments are of increasing index is vital for this
	// algorithm to work.

	unsigned const argumentsSize = CompilerUtils::getSizeOnStack(_function.getParameters());
	unsigned const returnValuesSize = CompilerUtils::getSizeOnStack(_function.getReturnParameters());
	unsigned const localVariablesSize = CompilerUtils::getSizeOnStack(_function.getLocalVariables());

	vector<int> stackLayout;
	stackLayout.push_back(returnValuesSize); // target of return address
	stackLayout += vector<int>(argumentsSize, -1); // discard all arguments
	for (unsigned i = 0; i < returnValuesSize; ++i)
		stackLayout.push_back(i);
	stackLayout += vector<int>(localVariablesSize, -1);

	while (stackLayout.back() != int(stackLayout.size() - 1))
		if (stackLayout.back() < 0)
		{
			m_context << eth::Instruction::POP;
			stackLayout.pop_back();
		}
		else
		{
			m_context << eth::swapInstruction(stackLayout.size() - stackLayout.back() - 1);
			swap(stackLayout[stackLayout.back()], stackLayout.back());
		}
	//@todo assert that everything is in place now

	m_context << eth::Instruction::JUMP;

	return false;
}

bool Compiler::visit(IfStatement const& _ifStatement)
{
	compileExpression(_ifStatement.getCondition());
	eth::AssemblyItem trueTag = m_context.appendConditionalJump();
	if (_ifStatement.getFalseStatement())
		_ifStatement.getFalseStatement()->accept(*this);
	eth::AssemblyItem endTag = m_context.appendJumpToNew();
	m_context << trueTag;
	_ifStatement.getTrueStatement().accept(*this);
	m_context << endTag;
	return false;
}

bool Compiler::visit(WhileStatement const& _whileStatement)
{
	eth::AssemblyItem loopStart = m_context.newTag();
	eth::AssemblyItem loopEnd = m_context.newTag();
	m_continueTags.push_back(loopStart);
	m_breakTags.push_back(loopEnd);

	m_context << loopStart;
	compileExpression(_whileStatement.getCondition());
	m_context << eth::Instruction::ISZERO;
	m_context.appendConditionalJumpTo(loopEnd);

	_whileStatement.getBody().accept(*this);

	m_context.appendJumpTo(loopStart);
	m_context << loopEnd;

	m_continueTags.pop_back();
	m_breakTags.pop_back();
	return false;
}

bool Compiler::visit(Continue const&)
{
	if (!m_continueTags.empty())
		m_context.appendJumpTo(m_continueTags.back());
	return false;
}

bool Compiler::visit(Break const&)
{
	if (!m_breakTags.empty())
		m_context.appendJumpTo(m_breakTags.back());
	return false;
}

bool Compiler::visit(Return const& _return)
{
	//@todo modifications are needed to make this work with functions returning multiple values
	if (Expression const* expression = _return.getExpression())
	{
		compileExpression(*expression);
		VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front();
		ExpressionCompiler::appendTypeConversion(m_context, *expression->getType(), *firstVariable.getType());

		CompilerUtils(m_context).moveToStackVariable(firstVariable);
	}
	m_context.appendJumpTo(m_returnTag);
	return false;
}

bool Compiler::visit(VariableDefinition const& _variableDefinition)
{
	if (Expression const* expression = _variableDefinition.getExpression())
	{
		compileExpression(*expression);
		ExpressionCompiler::appendTypeConversion(m_context,
												 *expression->getType(),
												 *_variableDefinition.getDeclaration().getType());
		CompilerUtils(m_context).moveToStackVariable(_variableDefinition.getDeclaration());
	}
	return false;
}

bool Compiler::visit(ExpressionStatement const& _expressionStatement)
{
	Expression const& expression = _expressionStatement.getExpression();
	compileExpression(expression);
	CompilerUtils(m_context).popStackElement(*expression.getType());
	return false;
}

void Compiler::compileExpression(Expression const& _expression)
{
	ExpressionCompiler::compileExpression(m_context, _expression, m_optimize);
}

}
}
<|endoftext|>


<commit_before>/*
 * Dijkstra.hpp
 *
 *  Created on: Nov 5, 2014
 *      Author: Pimenta
 */

#ifndef DIJKSTRA_HPP_
#define DIJKSTRA_HPP_

#include <queue>

#include "Graph.hpp"

struct DijkstraEdge {
  Vertex v;
  Weight dist;
  DijkstraEdge(Vertex v, Weight dist) : v(v), dist(dist) {

  }
  bool operator<(const DijkstraEdge& other) const {
    return dist > other.dist;
  }
};

inline Weight dijkstra(const Graph& G, Vertex s, Vertex d) {
  Weight* dist = new Weight[G.size() + 1];
  for (Vertex v = 1; v <= Vertex(G.size()); v++) {
    dist[v] = INF;
  }
  dist[s] = 0;
  std::priority_queue<DijkstraEdge> Q;
  Q.push(DijkstraEdge(s, 0));

  while (!Q.empty()) {
    DijkstraEdge unode = Q.top();
    Q.pop();

    if (unode.v == d) break;
    if (unode.dist > dist[unode.v]) continue;

    const std::map<Vertex, Weight>& u = G.at(unode.v);
    for (auto& kv : u) {
      Weight alt = unode.dist + kv.second;
      if (alt < dist[kv.first]) {
        dist[kv.first] = alt;
        Q.push(DijkstraEdge(kv.first, alt));
      }
    }
  }

  Weight w = dist[d];
  delete[] dist;
  return w;
}

#endif /* DIJKSTRA_HPP_ */
<commit_msg>Putting auxiliar struct inside Dijkstra's<commit_after>/*
 * Dijkstra.hpp
 *
 *  Created on: Nov 5, 2014
 *      Author: Pimenta
 */

#ifndef DIJKSTRA_HPP_
#define DIJKSTRA_HPP_

#include <queue>

#include "Graph.hpp"

inline Weight dijkstra(const Graph& G, Vertex s, Vertex d) {
  struct DijkstraEdge {
    Vertex v;
    Weight dist;
    DijkstraEdge(Vertex v, Weight dist) : v(v), dist(dist) {

    }
    bool operator<(const DijkstraEdge& other) const {
      return dist > other.dist;
    }
  };

  Weight* dist = new Weight[G.size() + 1];
  for (Vertex v = 1; v <= Vertex(G.size()); v++) {
    dist[v] = INF;
  }
  dist[s] = 0;
  std::priority_queue<DijkstraEdge> Q;
  Q.push(DijkstraEdge(s, 0));

  while (!Q.empty()) {
    DijkstraEdge unode = Q.top();
    Q.pop();

    if (unode.v == d) break;
    if (unode.dist > dist[unode.v]) continue;

    const std::map<Vertex, Weight>& u = G.at(unode.v);
    for (auto& kv : u) {
      Weight alt = unode.dist + kv.second;
      if (alt < dist[kv.first]) {
        dist[kv.first] = alt;
        Q.push(DijkstraEdge(kv.first, alt));
      }
    }
  }

  Weight w = dist[d];
  delete[] dist;
  return w;
}

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


<commit_before>/*//////////////////////////////////////////////////////////////////////////////
// Name:        dlgabout.cpp
// Purpose:     Implementation of CDlgAbout
// Author:      Ruediger Herrmann
// Copyright:   (c) Ruediger Herrmann
//////////////////////////////////////////////////////////////////////////////*/

#include "stdafx.h"
#include "ECTImportX.h"
#include "ECTImportX.h"
#include "DlgAbout.h"
#include "Module.h"
#include "helpcontextmap.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CDlgAbout::CDlgAbout(CWnd* pParent)
	: CDialog(CDlgAbout::IDD, pParent) {
	//{{AFX_DATA_INIT(CDlgAbout)
	//}}AFX_DATA_INIT
}

void CDlgAbout::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CDlgAbout)
	DDX_Control(pDX, IDC_EMAIL, m_EMail);
	DDX_Control(pDX, IDC_ABOUTICON, m_AboutIcon);
	DDX_Control(pDX, IDC_VERSION, m_Version);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CDlgAbout, CDialog)
	//{{AFX_MSG_MAP(CDlgAbout)
	ON_WM_HELPINFO()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL CDlgAbout::OnInitDialog()
{

	CDialog::OnInitDialog();

  // load and display logo icon
  HICON IconHandle = LoadIcon ( theApp.m_hInstance, MAKEINTRESOURCE ( IDI_ABOUTDLL ) );
  if ( IconHandle != NULL )
    m_AboutIcon.SetIcon ( IconHandle );

  // set mail address
  CString eMail = _T("");
  eMail.LoadString( IDS_EMAIL );
  m_EMail.SetWindowText( eMail );

  // get filename
  CString ModuleFilename;
  if ( GetModuleFileName ( theApp.m_hInstance, ModuleFilename.GetBufferSetLength ( MAX_PATH + 1 ), MAX_PATH ) == 0 )
    return TRUE;
  ModuleFilename.ReleaseBuffer();

  // determine version info size
  DWORD VersionInfoSize;
  DWORD NonsenseHandle;
  VersionInfoSize = GetFileVersionInfoSize ( ModuleFilename.GetBuffer ( 0 ), &NonsenseHandle );
  if ( VersionInfoSize == 0 )
    return TRUE;

	// allocate memory for and then get version info data block
  LPVOID VersionData;
  VersionData = malloc ( VersionInfoSize );
  if ( !GetFileVersionInfo ( ModuleFilename.GetBuffer ( 0 ), NonsenseHandle, VersionInfoSize, VersionData ) )
    return TRUE;

  // get fixed version info
  VS_FIXEDFILEINFO* FixedFileInfo = NULL;
  UINT FixedFileInfoSize;
  if ( !VerQueryValue ( VersionData, _T("\\"), (void**) &FixedFileInfo, &FixedFileInfoSize ) )
  {
    free ( VersionData );
    return TRUE;
  }

  CString Version;
  Version.Format ( IDS_VERSION, HIWORD ( FixedFileInfo->dwProductVersionMS ), LOWORD ( FixedFileInfo->dwProductVersionMS ), HIWORD ( FixedFileInfo->dwProductVersionLS ), LOWORD ( FixedFileInfo->dwProductVersionLS ) );
  m_Version.SetWindowText ( Version );

  // free version info block
  free ( VersionData );

  return TRUE;
}

BOOL CDlgAbout::OnHelpInfo(HELPINFO* pHelpInfo)
{
	char exefilename[MAX_PATH];
	char *cp;
	if (::GetModuleFileName(theApp.m_hInstance, exefilename, MAX_PATH) && (cp = strrchr(exefilename, '\\')))
	{
		strcpy(cp, "\\ECTEImport.htm");
		::ShellExecute(NULL, "open", exefilename, NULL, NULL, SW_SHOWNORMAL);
	}
	return CDialog::OnHelpInfo ( pHelpInfo );
}
<commit_msg>doppelter #include<commit_after>/*//////////////////////////////////////////////////////////////////////////////
// Name:        dlgabout.cpp
// Purpose:     Implementation of CDlgAbout
// Author:      Ruediger Herrmann
// Copyright:   (c) Ruediger Herrmann
//////////////////////////////////////////////////////////////////////////////*/

#include "stdafx.h"
#include "ECTImportX.h"
#include "DlgAbout.h"
#include "Module.h"
#include "helpcontextmap.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CDlgAbout::CDlgAbout(CWnd* pParent)
	: CDialog(CDlgAbout::IDD, pParent) {
	//{{AFX_DATA_INIT(CDlgAbout)
	//}}AFX_DATA_INIT
}

void CDlgAbout::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CDlgAbout)
	DDX_Control(pDX, IDC_EMAIL, m_EMail);
	DDX_Control(pDX, IDC_ABOUTICON, m_AboutIcon);
	DDX_Control(pDX, IDC_VERSION, m_Version);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CDlgAbout, CDialog)
	//{{AFX_MSG_MAP(CDlgAbout)
	ON_WM_HELPINFO()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL CDlgAbout::OnInitDialog()
{

	CDialog::OnInitDialog();

  // load and display logo icon
  HICON IconHandle = LoadIcon ( theApp.m_hInstance, MAKEINTRESOURCE ( IDI_ABOUTDLL ) );
  if ( IconHandle != NULL )
    m_AboutIcon.SetIcon ( IconHandle );

  // set mail address
  CString eMail = _T("");
  eMail.LoadString( IDS_EMAIL );
  m_EMail.SetWindowText( eMail );

  // get filename
  CString ModuleFilename;
  if ( GetModuleFileName ( theApp.m_hInstance, ModuleFilename.GetBufferSetLength ( MAX_PATH + 1 ), MAX_PATH ) == 0 )
    return TRUE;
  ModuleFilename.ReleaseBuffer();

  // determine version info size
  DWORD VersionInfoSize;
  DWORD NonsenseHandle;
  VersionInfoSize = GetFileVersionInfoSize ( ModuleFilename.GetBuffer ( 0 ), &NonsenseHandle );
  if ( VersionInfoSize == 0 )
    return TRUE;

	// allocate memory for and then get version info data block
  LPVOID VersionData;
  VersionData = malloc ( VersionInfoSize );
  if ( !GetFileVersionInfo ( ModuleFilename.GetBuffer ( 0 ), NonsenseHandle, VersionInfoSize, VersionData ) )
    return TRUE;

  // get fixed version info
  VS_FIXEDFILEINFO* FixedFileInfo = NULL;
  UINT FixedFileInfoSize;
  if ( !VerQueryValue ( VersionData, _T("\\"), (void**) &FixedFileInfo, &FixedFileInfoSize ) )
  {
    free ( VersionData );
    return TRUE;
  }

  CString Version;
  Version.Format ( IDS_VERSION, HIWORD ( FixedFileInfo->dwProductVersionMS ), LOWORD ( FixedFileInfo->dwProductVersionMS ), HIWORD ( FixedFileInfo->dwProductVersionLS ), LOWORD ( FixedFileInfo->dwProductVersionLS ) );
  m_Version.SetWindowText ( Version );

  // free version info block
  free ( VersionData );

  return TRUE;
}

BOOL CDlgAbout::OnHelpInfo(HELPINFO* pHelpInfo)
{
	char exefilename[MAX_PATH];
	char *cp;
	if (::GetModuleFileName(theApp.m_hInstance, exefilename, MAX_PATH) && (cp = strrchr(exefilename, '\\')))
	{
		strcpy(cp, "\\ECTEImport.htm");
		::ShellExecute(NULL, "open", exefilename, NULL, NULL, SW_SHOWNORMAL);
	}
	return CDialog::OnHelpInfo ( pHelpInfo );
}
<|endoftext|>


<commit_before>#ifndef _FFITYPES_H_
#define _FFITYPES_H_

#if defined(_MSCVER) && _MSC_VER < 1600
// HACK: stdint.h is not available in VC9. try to define uintptr_t based
// on the size of a void pointer. I don't know the correct compiler macros
// for this, but the trait also looks way more portable than an "#ifdef".

template <unsigned int Size> struct GetUIntPtrType;
template <> struct GetUIntPtrType<4> { typedef unsigned int Type; };
template <> struct GetUIntPtrType<8> { typedef unsigned long long Type; };

typedef GetUIntPtrType<sizeof(void *)>::Type uintptr_t;

#else
#include <stdint.h>
#endif // _WIN32

/// Integral types supported by CtrlFFI
enum IntegralType
{
  // FIRST_VALUE_TYPE and LAST_VALUE_TYPE enclose the non-pointer, non-special
  // types to allow easy checking and easy mapping.

  // non-fixed size types
  CTRLFFI_FIRST_VALUE_TYPE = 0,
  CTRLFFI_UCHAR = 1,
  CTRLFFI_CHAR,
  CTRLFFI_USHORT,
  CTRLFFI_SHORT,
  CTRLFFI_UINT,
  CTRLFFI_INT,
  CTRLFFI_ULONG,
  CTRLFFI_LONG,
  CTRLFFI_FLOAT,
  CTRLFFI_DOUBLE,
  // fixed size types
  CTRLFFI_UINT8,
  CTRLFFI_INT8,
  CTRLFFI_UINT16,
  CTRLFFI_INT16,
  CTRLFFI_UINT32,
  CTRLFFI_INT32,
  CTRLFFI_UINT64,
  CTRLFFI_INT64,
  CTRLFFI_LAST_VALUE_TYPE,
  // pointer types. i rely on these being in the same order as the integral
  // types, so that mapping to them is easier.
  // FIRST_PTR and LAST_PTR enclose the pointer types to allow easy checking
  // for pointer types and easy mapping. they are not valid types.
  CTRLFFI_FIRST_PTR,
  CTRLFFI_UCHAR_PTR,
  CTRLFFI_CHAR_PTR,
  CTRLFFI_USHORT_PTR,
  CTRLFFI_SHORT_PTR,
  CTRLFFI_UINT_PTR,
  CTRLFFI_INT_PTR,
  CTRLFFI_ULONG_PTR,
  CTRLFFI_LONG_PTR,
  CTRLFFI_FLOAT_PTR,
  CTRLFFI_DOUBLE_PTR,
  CTRLFFI_UINT8_PTR,
  CTRLFFI_INT8_PTR,
  CTRLFFI_UINT16_PTR,
  CTRLFFI_INT16_PTR,
  CTRLFFI_UINT32_PTR,
  CTRLFFI_INT32_PTR,
  CTRLFFI_UINT64_PTR,
  CTRLFFI_INT64_PTR,
  CTRLFFI_LAST_PTR,
  // special types
  CTRLFFI_POINTER,
  CTRLFFI_VOID,
  CTRLFFI_STRING,

  // this value terminates the enum. it must always be the last one.
  CTRLFFI_MAX_VALUE
};

#endif // _FFITYPES_H_
<commit_msg>fix compile error on msvc, Types.hxx and stdint.h don't fit together<commit_after>#ifndef _FFITYPES_H_
#define _FFITYPES_H_

// HACK: cannot include stdint.h, since it conflicts with Types.hxx.
// try to define uintptr_t based on the size of a void pointer.

template <unsigned int Size> struct GetUIntPtrType;
template <> struct GetUIntPtrType<4> { typedef unsigned int Type; };
template <> struct GetUIntPtrType<8> { typedef unsigned long long Type; };

typedef GetUIntPtrType<sizeof(void *)>::Type uintptr_t;

/// Integral types supported by CtrlFFI
enum IntegralType
{
  // FIRST_VALUE_TYPE and LAST_VALUE_TYPE enclose the non-pointer, non-special
  // types to allow easy checking and easy mapping.

  // non-fixed size types
  CTRLFFI_FIRST_VALUE_TYPE = 0,
  CTRLFFI_UCHAR = 1,
  CTRLFFI_CHAR,
  CTRLFFI_USHORT,
  CTRLFFI_SHORT,
  CTRLFFI_UINT,
  CTRLFFI_INT,
  CTRLFFI_ULONG,
  CTRLFFI_LONG,
  CTRLFFI_FLOAT,
  CTRLFFI_DOUBLE,
  // fixed size types
  CTRLFFI_UINT8,
  CTRLFFI_INT8,
  CTRLFFI_UINT16,
  CTRLFFI_INT16,
  CTRLFFI_UINT32,
  CTRLFFI_INT32,
  CTRLFFI_UINT64,
  CTRLFFI_INT64,
  CTRLFFI_LAST_VALUE_TYPE,
  // pointer types. i rely on these being in the same order as the integral
  // types, so that mapping to them is easier.
  // FIRST_PTR and LAST_PTR enclose the pointer types to allow easy checking
  // for pointer types and easy mapping. they are not valid types.
  CTRLFFI_FIRST_PTR,
  CTRLFFI_UCHAR_PTR,
  CTRLFFI_CHAR_PTR,
  CTRLFFI_USHORT_PTR,
  CTRLFFI_SHORT_PTR,
  CTRLFFI_UINT_PTR,
  CTRLFFI_INT_PTR,
  CTRLFFI_ULONG_PTR,
  CTRLFFI_LONG_PTR,
  CTRLFFI_FLOAT_PTR,
  CTRLFFI_DOUBLE_PTR,
  CTRLFFI_UINT8_PTR,
  CTRLFFI_INT8_PTR,
  CTRLFFI_UINT16_PTR,
  CTRLFFI_INT16_PTR,
  CTRLFFI_UINT32_PTR,
  CTRLFFI_INT32_PTR,
  CTRLFFI_UINT64_PTR,
  CTRLFFI_INT64_PTR,
  CTRLFFI_LAST_PTR,
  // special types
  CTRLFFI_POINTER,
  CTRLFFI_VOID,
  CTRLFFI_STRING,

  // this value terminates the enum. it must always be the last one.
  CTRLFFI_MAX_VALUE
};

#endif // _FFITYPES_H_
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <array>
#include <vector>
#include <set>
#include <map>
#include <random>
#include <chrono>
#include <functional>
#include <algorithm>

#include <cmath>

#define NF 16

using Entry = std::array<double, NF>;
using IntPair = std::pair<int, int>;

struct CompareSecond: std::binary_function<IntPair, IntPair, bool>
{
    bool operator()(const IntPair& a, const IntPair& b)
    {
        return a.second < b.second;
    }
};

int main(int argc, char** argv)
{
    // smoothing factor
    const double alpha = 1.0;
    // decision rule
    const int decision = 1;

    if (argc < 2)
        return 1;

    // preparing data
    int total = 0, correct = 0, totalClassified = 0;
    std::map<std::string, std::vector<Entry> > data;
    std::map<std::string, int> n;
    std::map<std::string, double> priors;
    std::map<std::string, std::vector<double> > multinomialLikelihoods;
    std::map<std::string, int> multinomialSums;
    std::map<std::string, Entry > sumX;
    std::map<std::string, std::vector<double> > means;
    std::map<std::string, std::vector<double> > variances;

    auto classify = [&](const std::string& label, const Entry& entry)
    {
        std::string predlabel;
        double maxlikelihood = 0.0;
        double denom = 0.0;
        std::vector<double> probs;
        for (auto it = priors.begin(); it != priors.end(); it++)
        {
            double numer = priors[it->first];
            const auto& firstMultinomialLikelihood = multinomialLikelihoods[it->first];
            const auto& firstMean = means[it->first];
            const auto& firstVariance = variances[it->first];
            for (int j = 0; j < NF; j++)
                switch (decision)
                {
                    case 2:
                        // Multinomial
                        if (entry[j])
                            numer *= pow(firstMultinomialLikelihood[j], entry[j]);
                        break;

                    case 3:
                        // Bernoulli
                        numer *= pow(firstMean[j], entry[j]) * pow(1.0 - firstMean[j], 1.0 - entry[j]);
                        break;

                    default:
                        // Gaussian
                        numer *= 1 / sqrt(2 * M_PI * firstVariance[j]) * exp((-1 * (entry[j] - firstMean[j]) * (entry[j] -firstMean[j])) / (2 * firstVariance[j]));
                        break;
                }

            if (numer > maxlikelihood)
            {
                maxlikelihood = numer;
                predlabel = it->first;
            }
            denom += numer;
            probs.push_back(numer);
        }

        std::cout << predlabel << "\t" << std::setw(1) << std::setprecision(3) << maxlikelihood/denom << "\t";
        if ("" == label)
            std::cout << "<no label>" << std::endl;
        else if (predlabel == label)
        {
            std::cout << "correct" << std::endl;
            correct++;
        }
        else
            std::cout << "incorrect" << std::endl;

        totalClassified++;
    };

    auto readFromFile = [&](const char* filename, bool isClassification)
    {
        std::ifstream file(argv[1]);
        if (!file.is_open())
            return 1;

        while (!file.eof())
        {
            std::string line;
            std::getline(file, line);
            if ("" == line)
                continue;
            std::istringstream linein(std::move(line));
            std::string label;
            std::getline(linein, label, ',');
            Entry entry;
            auto setField = [&entry, &label, &sumX, &multinomialSums, isClassification](int i, const std::string& field)
            {
                switch (field[0])
                {
                    case 'y':
                        entry[i] = 1.0;
                        break;

                    case 'n':
                        entry[i] = 0.0;
                        break;

                    case '?':
                        entry[i] = 0.5;
                        break;
                }
                if (!isClassification)
                {
                    sumX[label][i] += entry[i];
                    multinomialSums[label] += entry[i];
                }
            };
            for (int i = 0; i < NF; i++)
            {
                std::string field;
                std::getline(linein, field, ',');
                setField(i, field);
            }
            std::string field;
            std::getline(linein, field);
            setField(NF - 1, field);
            if (!isClassification)
            {
                data[label].push_back(std::move(entry));
                n[label]++;
                total++;
            }
            else
                classify(label, entry);
        }

        return 0;
    };

    int errcode = readFromFile(argv[1], false);
    if (errcode)
        return errcode;

    for (auto it = sumX.begin(); it != sumX.end(); it++)
    {
        priors[it->first] = (double)n[it->first] / total;

        std::cout << "Class " << it->first << ", prior: " << std::setw(1) << std::setprecision(3) << priors[it->first] << std::endl;
        std::cout << "feature\tmean\tvar\tstddev\tmnl" << std::endl;

        // calculate means
        std::vector<double> featureMeans(NF);
        for (int i = 0; i < NF; i++)
            featureMeans[i] = sumX[it->first][i] / n[it->first];

        // calculate variances
        std::vector<double> featureVariances(NF);
        const auto& firstData = data[it->first];
        for (int i = 0; i < (int)firstData.size(); i++)
            for (int j = 0; j < NF; j++)
                featureVariances[j] += (firstData[i][j] - featureMeans[j]) * (firstData[i][j] - featureMeans[j]);
        for (int i = 0; i < NF; i++)
            featureVariances[i] /= firstData.size();

        const auto& firstSumX = sumX[it->first];
        auto firstMultinomialSum = multinomialSums[it->first];
        auto& firstMultinomialLikelihood = multinomialLikelihoods[it->first];
        // calculate multinomial likelihoods
        for (int i = 0; i < NF; i++)
        {
            double mnl = (firstSumX[i] + alpha) / (firstMultinomialSum + (alpha * featureMeans.size()));
            firstMultinomialLikelihood.push_back(mnl);
        }

        for (unsigned int i = 0; i < NF; i++)
            printf("%i\t%2.3f\t%2.3f\t%2.3f\t%2.3f\n",i+1,featureMeans[i],featureVariances[i],sqrt(featureVariances[i]),firstMultinomialLikelihood[i]);

        means[it->first] = std::move(featureMeans);
        variances[it->first] = std::move(featureVariances);
    }

    // classify
    std::cout << "Classifying:" << std::endl;
    std::cout << "class\tprob\tresult" << std::endl;

    errcode = readFromFile(argv[2], true);
    if (errcode)
        return errcode;
    printf("Accuracy: %3.2f %% (%i/%i)\n", 100.0 * correct / totalClassified, correct, totalClassified);

    return 0;
}
<commit_msg>bayes: renamed macro constant `NF` to `NUM_FIELDS`<commit_after>#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <array>
#include <vector>
#include <set>
#include <map>
#include <random>
#include <chrono>
#include <functional>
#include <algorithm>

#include <cmath>

#define NUM_FIELDS 16

using Entry = std::array<double, NUM_FIELDS>;
using IntPair = std::pair<int, int>;

struct CompareSecond: std::binary_function<IntPair, IntPair, bool>
{
    bool operator()(const IntPair& a, const IntPair& b)
    {
        return a.second < b.second;
    }
};

int main(int argc, char** argv)
{
    // smoothing factor
    const double alpha = 1.0;
    // decision rule
    const int decision = 1;

    if (argc < 2)
        return 1;

    // preparing data
    int total = 0, correct = 0, totalClassified = 0;
    std::map<std::string, std::vector<Entry> > data;
    std::map<std::string, int> n;
    std::map<std::string, double> priors;
    std::map<std::string, std::vector<double> > multinomialLikelihoods;
    std::map<std::string, int> multinomialSums;
    std::map<std::string, Entry > sumX;
    std::map<std::string, std::vector<double> > means;
    std::map<std::string, std::vector<double> > variances;

    auto classify = [&](const std::string& label, const Entry& entry)
    {
        std::string predlabel;
        double maxlikelihood = 0.0;
        double denom = 0.0;
        std::vector<double> probs;
        for (auto it = priors.begin(); it != priors.end(); it++)
        {
            double numer = priors[it->first];
            const auto& firstMultinomialLikelihood = multinomialLikelihoods[it->first];
            const auto& firstMean = means[it->first];
            const auto& firstVariance = variances[it->first];
            for (int j = 0; j < NUM_FIELDS; j++)
                switch (decision)
                {
                    case 2:
                        // Multinomial
                        if (entry[j])
                            numer *= pow(firstMultinomialLikelihood[j], entry[j]);
                        break;

                    case 3:
                        // Bernoulli
                        numer *= pow(firstMean[j], entry[j]) * pow(1.0 - firstMean[j], 1.0 - entry[j]);
                        break;

                    default:
                        // Gaussian
                        numer *= 1 / sqrt(2 * M_PI * firstVariance[j]) * exp((-1 * (entry[j] - firstMean[j]) * (entry[j] -firstMean[j])) / (2 * firstVariance[j]));
                        break;
                }

            if (numer > maxlikelihood)
            {
                maxlikelihood = numer;
                predlabel = it->first;
            }
            denom += numer;
            probs.push_back(numer);
        }

        std::cout << predlabel << "\t" << std::setw(1) << std::setprecision(3) << maxlikelihood/denom << "\t";
        if ("" == label)
            std::cout << "<no label>" << std::endl;
        else if (predlabel == label)
        {
            std::cout << "correct" << std::endl;
            correct++;
        }
        else
            std::cout << "incorrect" << std::endl;

        totalClassified++;
    };

    auto readFromFile = [&](const char* filename, bool isClassification)
    {
        std::ifstream file(argv[1]);
        if (!file.is_open())
            return 1;

        while (!file.eof())
        {
            std::string line;
            std::getline(file, line);
            if ("" == line)
                continue;
            std::istringstream linein(std::move(line));
            std::string label;
            std::getline(linein, label, ',');
            Entry entry;
            auto setField = [&entry, &label, &sumX, &multinomialSums, isClassification](int i, const std::string& field)
            {
                switch (field[0])
                {
                    case 'y':
                        entry[i] = 1.0;
                        break;

                    case 'n':
                        entry[i] = 0.0;
                        break;

                    case '?':
                        entry[i] = 0.5;
                        break;
                }
                if (!isClassification)
                {
                    sumX[label][i] += entry[i];
                    multinomialSums[label] += entry[i];
                }
            };
            for (int i = 0; i < NUM_FIELDS; i++)
            {
                std::string field;
                std::getline(linein, field, ',');
                setField(i, field);
            }
            std::string field;
            std::getline(linein, field);
            setField(NUM_FIELDS - 1, field);
            if (!isClassification)
            {
                data[label].push_back(std::move(entry));
                n[label]++;
                total++;
            }
            else
                classify(label, entry);
        }

        return 0;
    };

    int errcode = readFromFile(argv[1], false);
    if (errcode)
        return errcode;

    for (auto it = sumX.begin(); it != sumX.end(); it++)
    {
        priors[it->first] = (double)n[it->first] / total;

        std::cout << "Class " << it->first << ", prior: " << std::setw(1) << std::setprecision(3) << priors[it->first] << std::endl;
        std::cout << "feature\tmean\tvar\tstddev\tmnl" << std::endl;

        // calculate means
        std::vector<double> featureMeans(NUM_FIELDS);
        for (int i = 0; i < NUM_FIELDS; i++)
            featureMeans[i] = sumX[it->first][i] / n[it->first];

        // calculate variances
        std::vector<double> featureVariances(NUM_FIELDS);
        const auto& firstData = data[it->first];
        for (int i = 0; i < (int)firstData.size(); i++)
            for (int j = 0; j < NUM_FIELDS; j++)
                featureVariances[j] += (firstData[i][j] - featureMeans[j]) * (firstData[i][j] - featureMeans[j]);
        for (int i = 0; i < NUM_FIELDS; i++)
            featureVariances[i] /= firstData.size();

        const auto& firstSumX = sumX[it->first];
        auto firstMultinomialSum = multinomialSums[it->first];
        auto& firstMultinomialLikelihood = multinomialLikelihoods[it->first];
        // calculate multinomial likelihoods
        for (int i = 0; i < NUM_FIELDS; i++)
        {
            double mnl = (firstSumX[i] + alpha) / (firstMultinomialSum + (alpha * featureMeans.size()));
            firstMultinomialLikelihood.push_back(mnl);
        }

        for (unsigned int i = 0; i < NUM_FIELDS; i++)
            printf("%i\t%2.3f\t%2.3f\t%2.3f\t%2.3f\n",i+1,featureMeans[i],featureVariances[i],sqrt(featureVariances[i]),firstMultinomialLikelihood[i]);

        means[it->first] = std::move(featureMeans);
        variances[it->first] = std::move(featureVariances);
    }

    // classify
    std::cout << "Classifying:" << std::endl;
    std::cout << "class\tprob\tresult" << std::endl;

    errcode = readFromFile(argv[2], true);
    if (errcode)
        return errcode;
    printf("Accuracy: %3.2f %% (%i/%i)\n", 100.0 * correct / totalClassified, correct, totalClassified);

    return 0;
}
<|endoftext|>