<commit_before>//
//  ofxAvAudioPlayer.cpp
//  emptyExample
//
//  Created by Hansi on 13.07.15.
//
// a huge chunk of this file is based on the
// blog entry https://blinkingblip.wordpress.com/2011/10/08/decoding-and-playing-an-audio-stream-using-libavcodec-libavformat-and-libao/
// (had to make some adjustments for changes in ffmpeg
// and libavcodecs examples
// https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/decoding_encoding.c

#include "ofxAvAudioPlayer.h"
#include "ofMain.h"

using namespace std;

#define die(msg) cerr << msg << endl; return false;

ofxAvAudioPlayer::ofxAvAudioPlayer(){
	// default audio settings
	output_channel_layout = av_get_default_channel_layout(2);
	output_sample_rate = 44100;
	output_num_channels = 2;
	volume = 1;

	f = NULL;
	isLooping = false;
	decoded_frame = NULL;
	codec_context = NULL;
	buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
	swr_context = NULL;
	packet = NULL;
	av_register_all();

	unloadSound();
}

bool ofxAvAudioPlayer::loadSound(string fileName, bool stream){
	unloadSound();

	string fileNameAbs = ofToDataPath(fileName,true);
	const char * input_filename = fileNameAbs.c_str();
	// the first finds the right codec, following  https://blinkingblip.wordpress.com/2011/10/08/decoding-and-playing-an-audio-stream-using-libavcodec-libavformat-and-libao/
	container = 0;
	if (avformat_open_input(&container, input_filename, NULL, NULL) < 0) {
		die("Could not open file");
	}

	if (avformat_find_stream_info(container,NULL) < 0) {
		die("Could not find file info");
	}

	audio_stream_id = -1;

	// To find the first audio stream. This process may not be necessary
	// if you can gurarantee that the container contains only the desired
	// audio stream
	int i;
	for (i = 0; i < container->nb_streams; i++) {
		if (container->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
			audio_stream_id = i;
			break;
		}
	}

	if (audio_stream_id == -1) {
		die("Could not find an audio stream");
	}

	// Find the apropriate codec and open it
	codec_context = container->streams[audio_stream_id]->codec;

	AVCodec* codec = avcodec_find_decoder(codec_context->codec_id);
	if (avcodec_open2(codec_context, codec,NULL)) {
		die("Could not find open the needed codec");
	}

	// from here on it's mostly following
	// https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/decoding_encoding.c
	f = fopen(input_filename, "rb");
	if (!f) {
		fprintf(stderr, "Could not open %s\n", input_filename);
		return false;
	}

	//packet.data = inbuf;
	//packet.size = fread(inbuf, 1, AVCODEC_AUDIO_INBUF_SIZE, f);
	packet = new AVPacket();
	av_init_packet(packet);
	packet->data = NULL;
	packet->size = 0;

	// we continue here:
	decode_next_frame();
	duration = av_time_to_millis(container->streams[audio_stream_id]->duration);

	swr_context = NULL;
	isLoaded = true;
	isPlaying = true;

	return true;
}

bool ofxAvAudioPlayer::setupAudioOut( int numChannels, int sampleRate ){
	output_channel_layout = av_get_default_channel_layout(numChannels);
	output_sample_rate = sampleRate;
	output_num_channels = numChannels;

	return true;
}

void ofxAvAudioPlayer::unloadSound(){
	len = 0;
	isLoaded = false;
	isPlaying = false;
	packet_data_size = 0;
	decoded_buffer_pos = 0;
	decoded_buffer_len = 0;
	next_seekTarget = -1;

	if( f ){
		fclose(f);
		f = NULL;
	}
	if( codec_context ){
		avcodec_close(codec_context);
		av_free(codec_context);
		codec_context = NULL;
	}
	if( decoded_frame ){
		av_frame_free(&decoded_frame);
		decoded_frame = NULL;
	}

	if( swr_context ){
		swr_free(&swr_context);
		swr_context = NULL;
	}

	if( packet ){
		av_free_packet(packet);
		packet = NULL;
	}
}

void ofxAvAudioPlayer::audioOut(float *output, int bufferSize, int nChannels){
	if( !isLoaded ){ return; }

	if( next_seekTarget >= 0 ){
		//av_seek_frame(container,-1,next_seekTarget,AVSEEK_FLAG_ANY);
		avformat_seek_file(container,audio_stream_id,0,next_seekTarget,next_seekTarget,AVSEEK_FLAG_ANY);
		next_seekTarget = -1;
		avcodec_flush_buffers(codec_context);
		decode_next_frame();
	}

	if( !isPlaying ){ return; }

	int max_read_packets = 2;
	if( decoded_frame && decoded_frame);
	// number of samples read per channel (up to bufferSize)
	int num_samples_read = 0;

	if( decoded_frame == NULL ){
		decode_next_frame();
	}

	while( decoded_frame != NULL && max_read_packets > 0 ){
		max_read_packets --;

		int missing_samples = bufferSize*nChannels - num_samples_read;
		int available_samples = decoded_buffer_len - decoded_buffer_pos;
		if( missing_samples > 0 && available_samples > 0 ){
			int samples = min( missing_samples, available_samples );

			if( volume != 0 ){
				memcpy(output+num_samples_read, decoded_buffer+decoded_buffer_pos, samples*sizeof(float) );
			}

			if( volume != 1 && volume != 0 ){
				for( int i = 0; i < samples; i++ ){
					output[i+num_samples_read] *= volume;
				}
			}

			decoded_buffer_pos += samples;
			num_samples_read += samples;
		}

		if( num_samples_read >= bufferSize*nChannels ){
			return;
		}
		else{
			decode_next_frame();
		}
	}
}

/*void ofxAvAudioPlayer::readData(){
	// this was quite helpful: http://ffmpeg.org/doxygen/trunk/demuxing_decoding_8c-example.html

	// do we still have data to decode?
	if( decode_next_frame() ){
		return true;
	}
	else{
		// nope, grab next frame!
		if(av_read_frame(container, packet) >= 0){
			AVPacket orig_pkt = pkt;
			do {
				ret = decode_packet(&got_frame, 0);
				if (ret < 0)
					break;
				pkt.data += ret;
				pkt.size -= ret;
			} while (pkt.size > 0);
			av_free_packet(&orig_pkt);
		}
	}

}*/

bool ofxAvAudioPlayer::decode_next_frame(){
	int res = av_read_frame(container, packet);
	bool didRead = res >= 0;

	if( didRead ){
		int got_frame = 0;
		if (!decoded_frame) {
			if (!(decoded_frame = av_frame_alloc())) {
				fprintf(stderr, "Could not allocate audio frame\n");
				//exit(1);
				return false;
			}
		}
		else{
			av_frame_unref(decoded_frame);
		}

		len = avcodec_decode_audio4(codec_context, decoded_frame, &got_frame, packet);
		if (len < 0) {
			// no data
			return false;
		}

		if (got_frame) {

			if( swr_context == NULL ){
				int input_channel_layout = decoded_frame->channel_layout;
				if( input_channel_layout == 0 ){
					input_channel_layout = av_get_default_channel_layout( codec_context->channels );
				}
				swr_context = swr_alloc_set_opts(NULL,
												 output_channel_layout, AV_SAMPLE_FMT_FLT, output_sample_rate,
												 input_channel_layout, (AVSampleFormat)decoded_frame->format, decoded_frame->sample_rate,
												 0, NULL);
				swr_init(swr_context);

				if (!swr_context){
					fprintf(stderr, "Could not allocate resampler context\n");
					return false;
				}

			}

			/* if a frame has been decoded, resample to desired rate */
			int samples_per_channel = AVCODEC_MAX_AUDIO_FRAME_SIZE/output_num_channels;
			//samples_per_channel = 512;
			uint8_t * out = (uint8_t*)decoded_buffer;
			int samples_converted = swr_convert(swr_context,
												(uint8_t**)&out, samples_per_channel,
												(const uint8_t**)decoded_frame->extended_data, decoded_frame->nb_samples);
			decoded_buffer_len = samples_converted*output_num_channels;
			decoded_buffer_pos = 0;
		}

		packet->size -= len;
		packet->data += len;
//		packet->dts =
//		packet->pts = AV_NOPTS_VALUE;

		return true;
	}
	else{
		// no data read...
		packet_data_size = 0;
		decoded_buffer_len = 0;
		decoded_buffer_pos = 0;
		if( isLooping ){
			avformat_seek_file(container,audio_stream_id,0,0,0,AVSEEK_FLAG_ANY);
			avcodec_flush_buffers(codec_context);
			decode_next_frame();
		}
		else{
			isPlaying = false;
		}

		return false;
	}
}

unsigned long long ofxAvAudioPlayer::av_time_to_millis( int64_t av_time ){
	return av_rescale(1000*av_time,(uint64_t)container->streams[audio_stream_id]->time_base.num,container->streams[audio_stream_id]->time_base.den);
	//alternative:
	//return av_time*1000*av_q2d(container->streams[audio_stream_id]->time_base);
}

int64_t ofxAvAudioPlayer::millis_to_av_time( unsigned long long ms ){
	//TODO: fix conversion
/*	int64_t timeBase = (int64_t(codec_context->time_base.num) * AV_TIME_BASE) / int64_t(codec_context->time_base.den);
	int64_t seekTarget = int64_t(ms) / timeBase;*/
	return av_rescale(ms,container->streams[audio_stream_id]->time_base.den,(uint64_t)container->streams[audio_stream_id]->time_base.num)/1000;
}

void ofxAvAudioPlayer::setPositionMS(int ms){
	next_seekTarget = millis_to_av_time(ms);
}

int ofxAvAudioPlayer::getPositionMS(){
	int64_t ts = packet->pts;
	return av_time_to_millis( ts );
}

float ofxAvAudioPlayer::getPosition(){
	return duration == 0? 0 : (getPositionMS()/(float)duration);
}

void ofxAvAudioPlayer::setPosition(float percent){
	if(duration>0) setPositionMS(percent*duration);
}

void ofxAvAudioPlayer::stop(){
	isPlaying =false;
}

void ofxAvAudioPlayer::play(){
	if( isLoaded ){
		isPlaying = true;
	}
}

void ofxAvAudioPlayer::setLoop(bool loop){
	isLooping = loop;
}

void ofxAvAudioPlayer::setVolume(float vol){
	this->volume = vol;
}<commit_msg>fixed crash when file is invalid<commit_after>//
//  ofxAvAudioPlayer.cpp
//  emptyExample
//
//  Created by Hansi on 13.07.15.
//
// a huge chunk of this file is based on the
// blog entry https://blinkingblip.wordpress.com/2011/10/08/decoding-and-playing-an-audio-stream-using-libavcodec-libavformat-and-libao/
// (had to make some adjustments for changes in ffmpeg
// and libavcodecs examples
// https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/decoding_encoding.c

#include "ofxAvAudioPlayer.h"
#include "ofMain.h"

using namespace std;

#define die(msg) { unloadSound(); cerr << msg << endl; return false; }

ofxAvAudioPlayer::ofxAvAudioPlayer(){
	// default audio settings
	output_channel_layout = av_get_default_channel_layout(2);
	output_sample_rate = 44100;
	output_num_channels = 2;
	volume = 1;

	f = NULL;
	isLooping = false;
	decoded_frame = NULL;
	codec_context = NULL;
	buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
	swr_context = NULL;
	packet = NULL;
	av_register_all();

	unloadSound();
}

bool ofxAvAudioPlayer::loadSound(string fileName, bool stream){
	unloadSound();

	string fileNameAbs = ofToDataPath(fileName,true);
	const char * input_filename = fileNameAbs.c_str();
	// the first finds the right codec, following  https://blinkingblip.wordpress.com/2011/10/08/decoding-and-playing-an-audio-stream-using-libavcodec-libavformat-and-libao/
	container = 0;
	if (avformat_open_input(&container, input_filename, NULL, NULL) < 0) {
		die("Could not open file");
	}

	if (avformat_find_stream_info(container,NULL) < 0) {
		die("Could not find file info");
	}

	audio_stream_id = -1;

	// To find the first audio stream. This process may not be necessary
	// if you can gurarantee that the container contains only the desired
	// audio stream
	int i;
	for (i = 0; i < container->nb_streams; i++) {
		if (container->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
			audio_stream_id = i;
			break;
		}
	}

	if (audio_stream_id == -1) {
		die("Could not find an audio stream");
	}

	// Find the apropriate codec and open it
	codec_context = container->streams[audio_stream_id]->codec;

	AVCodec* codec = avcodec_find_decoder(codec_context->codec_id);
	if (avcodec_open2(codec_context, codec,NULL)) {
		die("Could not find open the needed codec");
	}

	// from here on it's mostly following
	// https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/decoding_encoding.c
	f = fopen(input_filename, "rb");
	if (!f) {
		fprintf(stderr, "Could not open %s\n", input_filename);
		return false;
	}

	//packet.data = inbuf;
	//packet.size = fread(inbuf, 1, AVCODEC_AUDIO_INBUF_SIZE, f);
	packet = new AVPacket();
	av_init_packet(packet);
	packet->data = NULL;
	packet->size = 0;

	// we continue here:
	decode_next_frame();
	duration = av_time_to_millis(container->streams[audio_stream_id]->duration);

	swr_context = NULL;
	isLoaded = true;
	isPlaying = true;

	return true;
}

bool ofxAvAudioPlayer::setupAudioOut( int numChannels, int sampleRate ){
	output_channel_layout = av_get_default_channel_layout(numChannels);
	output_sample_rate = sampleRate;
	output_num_channels = numChannels;

	return true;
}

void ofxAvAudioPlayer::unloadSound(){
	len = 0;
	isLoaded = false;
	isPlaying = false;
	packet_data_size = 0;
	decoded_buffer_pos = 0;
	decoded_buffer_len = 0;
	next_seekTarget = -1;

	if( f ){
		fclose(f);
		f = NULL;
	}
	if( codec_context ){
		avcodec_close(codec_context);
		av_free(codec_context);
		codec_context = NULL;
	}
	if( decoded_frame ){
		av_frame_free(&decoded_frame);
		decoded_frame = NULL;
	}

	if( swr_context ){
		swr_free(&swr_context);
		swr_context = NULL;
	}

	if( packet ){
		av_free_packet(packet);
		packet = NULL;
	}
}

void ofxAvAudioPlayer::audioOut(float *output, int bufferSize, int nChannels){
	if( !isLoaded ){ return; }

	if( next_seekTarget >= 0 ){
		//av_seek_frame(container,-1,next_seekTarget,AVSEEK_FLAG_ANY);
		avformat_seek_file(container,audio_stream_id,0,next_seekTarget,next_seekTarget,AVSEEK_FLAG_ANY);
		next_seekTarget = -1;
		avcodec_flush_buffers(codec_context);
		decode_next_frame();
	}

	if( !isPlaying ){ return; }

	int max_read_packets = 2;
	if( decoded_frame && decoded_frame);
	// number of samples read per channel (up to bufferSize)
	int num_samples_read = 0;

	if( decoded_frame == NULL ){
		decode_next_frame();
	}

	while( decoded_frame != NULL && max_read_packets > 0 ){
		max_read_packets --;

		int missing_samples = bufferSize*nChannels - num_samples_read;
		int available_samples = decoded_buffer_len - decoded_buffer_pos;
		if( missing_samples > 0 && available_samples > 0 ){
			int samples = min( missing_samples, available_samples );

			if( volume != 0 ){
				memcpy(output+num_samples_read, decoded_buffer+decoded_buffer_pos, samples*sizeof(float) );
			}

			if( volume != 1 && volume != 0 ){
				for( int i = 0; i < samples; i++ ){
					output[i+num_samples_read] *= volume;
				}
			}

			decoded_buffer_pos += samples;
			num_samples_read += samples;
		}

		if( num_samples_read >= bufferSize*nChannels ){
			return;
		}
		else{
			decode_next_frame();
		}
	}
}

/*void ofxAvAudioPlayer::readData(){
	// this was quite helpful: http://ffmpeg.org/doxygen/trunk/demuxing_decoding_8c-example.html

	// do we still have data to decode?
	if( decode_next_frame() ){
		return true;
	}
	else{
		// nope, grab next frame!
		if(av_read_frame(container, packet) >= 0){
			AVPacket orig_pkt = pkt;
			do {
				ret = decode_packet(&got_frame, 0);
				if (ret < 0)
					break;
				pkt.data += ret;
				pkt.size -= ret;
			} while (pkt.size > 0);
			av_free_packet(&orig_pkt);
		}
	}

}*/

bool ofxAvAudioPlayer::decode_next_frame(){
	int res = av_read_frame(container, packet);
	bool didRead = res >= 0;

	if( didRead ){
		int got_frame = 0;
		if (!decoded_frame) {
			if (!(decoded_frame = av_frame_alloc())) {
				fprintf(stderr, "Could not allocate audio frame\n");
				//exit(1);
				return false;
			}
		}
		else{
			av_frame_unref(decoded_frame);
		}

		len = avcodec_decode_audio4(codec_context, decoded_frame, &got_frame, packet);
		if (len < 0) {
			// no data
			return false;
		}

		if (got_frame) {

			if( swr_context == NULL ){
				int input_channel_layout = decoded_frame->channel_layout;
				if( input_channel_layout == 0 ){
					input_channel_layout = av_get_default_channel_layout( codec_context->channels );
				}
				swr_context = swr_alloc_set_opts(NULL,
												 output_channel_layout, AV_SAMPLE_FMT_FLT, output_sample_rate,
												 input_channel_layout, (AVSampleFormat)decoded_frame->format, decoded_frame->sample_rate,
												 0, NULL);
				swr_init(swr_context);

				if (!swr_context){
					fprintf(stderr, "Could not allocate resampler context\n");
					return false;
				}

			}

			/* if a frame has been decoded, resample to desired rate */
			int samples_per_channel = AVCODEC_MAX_AUDIO_FRAME_SIZE/output_num_channels;
			//samples_per_channel = 512;
			uint8_t * out = (uint8_t*)decoded_buffer;
			int samples_converted = swr_convert(swr_context,
												(uint8_t**)&out, samples_per_channel,
												(const uint8_t**)decoded_frame->extended_data, decoded_frame->nb_samples);
			decoded_buffer_len = samples_converted*output_num_channels;
			decoded_buffer_pos = 0;
		}

		packet->size -= len;
		packet->data += len;
//		packet->dts =
//		packet->pts = AV_NOPTS_VALUE;

		return true;
	}
	else{
		// no data read...
		packet_data_size = 0;
		decoded_buffer_len = 0;
		decoded_buffer_pos = 0;
		if( isLooping ){
			avformat_seek_file(container,audio_stream_id,0,0,0,AVSEEK_FLAG_ANY);
			avcodec_flush_buffers(codec_context);
			decode_next_frame();
		}
		else{
			isPlaying = false;
		}

		return false;
	}
}

unsigned long long ofxAvAudioPlayer::av_time_to_millis( int64_t av_time ){
	return av_rescale(1000*av_time,(uint64_t)container->streams[audio_stream_id]->time_base.num,container->streams[audio_stream_id]->time_base.den);
	//alternative:
	//return av_time*1000*av_q2d(container->streams[audio_stream_id]->time_base);
}

int64_t ofxAvAudioPlayer::millis_to_av_time( unsigned long long ms ){
	//TODO: fix conversion
/*	int64_t timeBase = (int64_t(codec_context->time_base.num) * AV_TIME_BASE) / int64_t(codec_context->time_base.den);
	int64_t seekTarget = int64_t(ms) / timeBase;*/
	return av_rescale(ms,container->streams[audio_stream_id]->time_base.den,(uint64_t)container->streams[audio_stream_id]->time_base.num)/1000;
}

void ofxAvAudioPlayer::setPositionMS(int ms){
	next_seekTarget = millis_to_av_time(ms);
}

int ofxAvAudioPlayer::getPositionMS(){
	if( !isLoaded ) return 0;
	int64_t ts = packet->pts;
	return av_time_to_millis( ts );
}

float ofxAvAudioPlayer::getPosition(){
	return duration == 0? 0 : (getPositionMS()/(float)duration);
}

void ofxAvAudioPlayer::setPosition(float percent){
	if(duration>0) setPositionMS(percent*duration);
}

void ofxAvAudioPlayer::stop(){
	isPlaying =false;
}

void ofxAvAudioPlayer::play(){
	if( isLoaded ){
		isPlaying = true;
	}
}

void ofxAvAudioPlayer::setLoop(bool loop){
	isLooping = loop;
}

void ofxAvAudioPlayer::setVolume(float vol){
	this->volume = vol;
}<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <OpenNI.h>
#include "onimeshfunctions.h"

namespace onimesh
{
	const int FRAME_DATA_MOD = 100;

	/// <summary>
	/// Creates a name for an output file
	/// </summary>
	std::string getOutputFileName(const char* outputDirectory, const char* inputFile, const char* fileExtension)
	{
		// If the input file does not contain a path
		if (std::string(inputFile).find_last_of('\\') == std::string::npos)
			return std::string(std::string(outputDirectory) + std::string(inputFile) + std::string(fileExtension));

		return std::string(outputDirectory + std::string(inputFile).substr(std::string(inputFile).find_last_of('\\') + 1) + std::string(".csv"));
	}

	/// <summary>
	/// Reads oni input and exports data as excel docs
	/// </summary>
	void outputExcel(const int argc, const char** argv)
	{
		std::cout << "Start excel data output...\n";
		const char* outputDirectory = argv[1];
		char* inputFile;
		const int numberInputFiles = argc - 2;
		openni::Device device;
		openni::VideoStream ir;
		openni::VideoFrameRef irf;
		OniDepthPixel* pDepth;
		int frameHeight, frameWidth;
		long frameIndex, numberOfFrames;
		std::ofstream out;
		openni::OpenNI::initialize();

		// Output excel doc for each input file
		for (int w = 0; w < numberInputFiles; ++w)
		{
			inputFile = (char*)argv[w + 2];
			std::cout << "Working on file " << inputFile << "...\n";

			// Open the .oni file
			device.open(inputFile);
			ir.create(device, openni::SENSOR_DEPTH);

			// Device Check
			if (!device.isValid())
			{
				std::cerr << "\nError opening oni file.\n";
				exit(2);
			}

			// Verify the device is a file
			if (!device.isFile())
			{
				std::cerr << "\nThe device is not a file.\n";
				exit(3);
			}
			std::cout << "File open success...\n";

			// Set playback controls
			openni::PlaybackControl* pbc = device.getPlaybackControl();
			pbc->setSpeed(-1);
			pbc->setRepeatEnabled(false);

			// Open output file
			std::string outputFile = getOutputFileName(outputDirectory, inputFile, ".csv");
			out.open(outputFile);

			// Read all frames
			numberOfFrames = pbc->getNumberOfFrames(ir);
			std::cout << "Start reading frame data...\n";
			ir.start();
			while (true)
			{
				// Read a frame
				ir.readFrame(&irf);

				// Verify frame data is valid
				if (!irf.isValid())
				{
					std::cerr << "Error reading video stream frame\n";
					break;
				}

				// Gather frame data
				pDepth = (OniDepthPixel*)irf.getData();
				frameIndex = irf.getFrameIndex();

				// Skip unneeded frames
				if (frameIndex % FRAME_DATA_MOD == 0)
				{
					frameHeight = irf.getHeight();
					frameWidth = irf.getWidth();
					std::cout << "Processing " << frameWidth << "x" << frameHeight << " frame number " << frameIndex << "...\n";
					out << "FrameNumber=" << frameIndex << ",FrameWidth=" << frameWidth << ",FrameHeight=" << frameHeight << ",\n";
					for (int y = 0; y < frameHeight; ++y)  // All heights
					{
						for (int x = 0; x < frameWidth; ++x, ++pDepth)  // All witdths
						{
							out << *pDepth << ",";
						}
						out << "\n";
					}
					out << ",\n";
				}
				else
				{
					std::cout << "Skipping frame " << frameIndex << "\n";
				}

				// Break if reading the last frame
				if (numberOfFrames == frameIndex)
				{
					std::cout << "Last frame has been read...\n";
					break;
				}
			}

			// Cleanup
			out.clear();
			out.close();
			ir.stop();
			ir.destroy();
			device.close();
		}

		// OpenNI cleanup
		openni::OpenNI::shutdown();
		std::cout << "Excel data output complete.\n";
	}

	/// <summary>
	/// Reads oni input and exports data as point clouds
	/// </summary>
	void outputPointCloud(const int argc, const char** argv)
	{

	}
}<commit_msg>Windows GUI launcher compatibility update<commit_after>#include <iostream>
#include <fstream>
#include <OpenNI.h>
#include "onimeshfunctions.h"

namespace onimesh
{
	const int FRAME_DATA_MOD = 100;

	/// <summary>
	/// Creates a name for an output file
	/// </summary>
	std::string getOutputFileName(const char* outputDirectory, const char* inputFile, const char* fileExtension)
	{
		// If the path contains '/' characters
		if (std::string(inputFile).find_last_of('/') != std::string::npos)
			return std::string(outputDirectory + std::string(inputFile).substr(std::string(inputFile).find_last_of('/') + 1) + std::string(fileExtension));
		// If the path contains '\' characters
		else if(std::string(inputFile).find_last_of('\\') == std::string::npos)
			return std::string(outputDirectory + std::string(inputFile).substr(std::string(inputFile).find_last_of('\\') + 1) + std::string(fileExtension));

		// Otherwise the input file does not contain a path
		return std::string(std::string(outputDirectory) + std::string(inputFile) + std::string(fileExtension));
	}

	/// <summary>
	/// Reads oni input and exports data as excel docs
	/// </summary>
	void outputExcel(const int argc, const char** argv)
	{
		std::cout << "Start excel data output...\n";
		const char* outputDirectory = argv[1];
		char* inputFile;
		const int numberInputFiles = argc - 2;
		openni::Device device;
		openni::VideoStream ir;
		openni::VideoFrameRef irf;
		OniDepthPixel* pDepth;
		int frameHeight, frameWidth;
		long frameIndex, numberOfFrames;
		std::ofstream out;
		openni::OpenNI::initialize();

		// Output excel doc for each input file
		for (int w = 0; w < numberInputFiles; ++w)
		{
			inputFile = (char*)argv[w + 2];
			std::cout << "Working on file " << inputFile << "...\n";

			// Open the .oni file
			device.open(inputFile);
			ir.create(device, openni::SENSOR_DEPTH);

			// Device Check
			if (!device.isValid())
			{
				std::cerr << "\nError opening oni file.\n";
				exit(2);
			}

			// Verify the device is a file
			if (!device.isFile())
			{
				std::cerr << "\nThe device is not a file.\n";
				exit(3);
			}
			std::cout << "File open success...\n";

			// Set playback controls
			openni::PlaybackControl* pbc = device.getPlaybackControl();
			pbc->setSpeed(-1);
			pbc->setRepeatEnabled(false);

			// Open output file
			std::string outputFile = getOutputFileName(outputDirectory, inputFile, ".csv");
			out.open(outputFile);

			// Read all frames
			numberOfFrames = pbc->getNumberOfFrames(ir);
			std::cout << "Start reading frame data...\n";
			ir.start();
			while (true)
			{
				// Read a frame
				ir.readFrame(&irf);

				// Verify frame data is valid
				if (!irf.isValid())
				{
					std::cerr << "Error reading video stream frame\n";
					break;
				}

				// Gather frame data
				pDepth = (OniDepthPixel*)irf.getData();
				frameIndex = irf.getFrameIndex();

				// Skip unneeded frames
				if (frameIndex % FRAME_DATA_MOD == 0)
				{
					frameHeight = irf.getHeight();
					frameWidth = irf.getWidth();
					std::cout << "Processing " << frameWidth << "x" << frameHeight << " frame number " << frameIndex << "...\n";
					out << "FrameNumber=" << frameIndex << ",FrameWidth=" << frameWidth << ",FrameHeight=" << frameHeight << ",\n";
					for (int y = 0; y < frameHeight; ++y)  // All heights
					{
						for (int x = 0; x < frameWidth; ++x, ++pDepth)  // All witdths
						{
							out << *pDepth << ",";
						}
						out << "\n";
					}
					out << ",\n";
				}
				else
				{
					//std::cout << "Skipping frame " << frameIndex << "\n";
				}

				// Break if reading the last frame
				if (numberOfFrames == frameIndex)
				{
					std::cout << "Last frame has been read...\n";
					break;
				}
			}

			// Cleanup
			out.clear();
			out.close();
			ir.stop();
			ir.destroy();
			device.close();
		}

		// OpenNI cleanup
		openni::OpenNI::shutdown();
		std::cout << "Excel data output complete.\n";
	}

	/// <summary>
	/// Reads oni input and exports data as point clouds
	/// </summary>
	void outputPointCloud(const int argc, const char** argv)
	{

	}
}<|endoftext|>


<commit_before>#include "parameters_parser.hh"

namespace Kakoune
{

String generate_switches_doc(const SwitchMap& switches)
{
    String res;
    for (auto& sw : switches)
        res += format(" -{} {}: {}\n", sw.key,
                      sw.value.takes_arg ? "<arg>" : "",
                      sw.value.description);
    return res;
}

ParametersParser::ParametersParser(ParameterList params,
                                   const ParameterDesc& desc)
    : m_params(params),
      m_desc(desc)
{
    bool only_pos = desc.flags & ParameterDesc::Flags::SwitchesAsPositional;
    for (size_t i = 0; i < params.size(); ++i)
    {
        if (not only_pos and params[i] == "--")
            only_pos = true;
        else if (not only_pos and params[i].length() > 0 and params[i][0_byte] == '-')
        {
            auto it = m_desc.switches.find(params[i].substr(1_byte));
            if (it == m_desc.switches.end())
                throw unknown_option(params[i]);

            if (it->value.takes_arg)
            {
                ++i;
                if (i == params.size() or params[i][0_byte] == '-')
                   throw missing_option_value(it->key);
            }
        }
        else // positional
        {
            if (desc.flags & ParameterDesc::Flags::SwitchesOnlyAtStart)
                only_pos = true;
            m_positional_indices.push_back(i);
        }
    }
    size_t count = m_positional_indices.size();
    if (count > desc.max_positionals or count < desc.min_positionals)
        throw wrong_argument_count();
}

Optional<StringView> ParametersParser::get_switch(StringView name) const
{
    auto it = m_desc.switches.find(name);
    kak_assert(it != m_desc.switches.end());
    for (size_t i = 0; i < m_params.size(); ++i)
    {
        const auto& param = m_params[i];
        if (param[0_byte] == '-' and param.substr(1_byte) == name)
            return it->value.takes_arg ? m_params[i+1] : StringView{};

        if (param == "--")
            break;
    }
    return {};
}

}
<commit_msg>Use 'not empty' in place of 'length > 0'<commit_after>#include "parameters_parser.hh"

namespace Kakoune
{

String generate_switches_doc(const SwitchMap& switches)
{
    String res;
    for (auto& sw : switches)
        res += format(" -{} {}: {}\n", sw.key,
                      sw.value.takes_arg ? "<arg>" : "",
                      sw.value.description);
    return res;
}

ParametersParser::ParametersParser(ParameterList params,
                                   const ParameterDesc& desc)
    : m_params(params),
      m_desc(desc)
{
    bool only_pos = desc.flags & ParameterDesc::Flags::SwitchesAsPositional;
    for (size_t i = 0; i < params.size(); ++i)
    {
        if (not only_pos and params[i] == "--")
            only_pos = true;
        else if (not only_pos and not params[i].empty() and params[i][0_byte] == '-')
        {
            auto it = m_desc.switches.find(params[i].substr(1_byte));
            if (it == m_desc.switches.end())
                throw unknown_option(params[i]);

            if (it->value.takes_arg)
            {
                ++i;
                if (i == params.size() or params[i][0_byte] == '-')
                   throw missing_option_value(it->key);
            }
        }
        else // positional
        {
            if (desc.flags & ParameterDesc::Flags::SwitchesOnlyAtStart)
                only_pos = true;
            m_positional_indices.push_back(i);
        }
    }
    size_t count = m_positional_indices.size();
    if (count > desc.max_positionals or count < desc.min_positionals)
        throw wrong_argument_count();
}

Optional<StringView> ParametersParser::get_switch(StringView name) const
{
    auto it = m_desc.switches.find(name);
    kak_assert(it != m_desc.switches.end());
    for (size_t i = 0; i < m_params.size(); ++i)
    {
        const auto& param = m_params[i];
        if (param[0_byte] == '-' and param.substr(1_byte) == name)
            return it->value.takes_arg ? m_params[i+1] : StringView{};

        if (param == "--")
            break;
    }
    return {};
}

}
<|endoftext|>


<commit_before>//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
//
// spdlog usage example
//
//

#define SPDLOG_TRACE_ON
#define SPDLOG_DEBUG_ON

#include "spdlog/spdlog.h"

#include <iostream>
#include <memory>

void async_example();
void syslog_example();
void android_example();
void user_defined_example();
void err_handler_example();

namespace spd = spdlog;
int main(int, char *[])
{
    try
    {
         spdlog::set_async_mode(1024);
        // Console logger with color
        auto console = spd::stdout_color_mt("console");

        for (int i = 0; i < 2000; i++)
        {
            console->info("{} Hello thread pool!", i);
        }

        return 0;

        console->info("Welcome to spdlog!");
        console->error("Some error message with arg{}..", 1);

        // Formatting examples
        console->warn("Easy padding in numbers like {:08d}", 12);
        console->critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
        console->info("Support for floats {:03.2f}", 1.23456);
        console->info("Positional args are {1} {0}..", "too", "supported");
        console->info("{:<30}", "left aligned");

        spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");
        return 0;

        // Create basic file logger (not rotated)
        auto my_logger = spd::basic_logger_mt("basic_logger", "logs/basic-log.txt");
        my_logger->info("Some log message");

        // Create a file rotating logger with 5mb size max and 3 rotated files
        auto rotating_logger = spd::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
        for (int i = 0; i < 10; ++i)
        {
            rotating_logger->info("{} * {} equals {:>10}", i, i, i * i);
        }

        // Create a daily logger - a new file is created every day on 2:30am
        auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
        // trigger flush if the log severity is error or higher
        daily_logger->flush_on(spd::level::err);
        daily_logger->info(123.44);

        // Customize msg format for all messages
        spd::set_pattern("[%^+++%$] [%H:%M:%S %z] [thread %t] %v");
        console->info("This an info message with custom format (and custom color range between the '%^' and '%$')");
        console->error("This an error message with custom format (and custom color range between the '%^' and '%$')");

        // Runtime log levels
        spd::set_level(spd::level::info); // Set global log level to info
        console->debug("This message should not be displayed!");
        console->set_level(spd::level::debug); // Set specific logger's log level
        console->debug("This message should be displayed..");

        // Compile time log levels
        // define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON
        SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
        SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);

        // Asynchronous logging is very fast..
        // Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
        async_example();

        // syslog example. linux/osx only
        syslog_example();

        // android example. compile with NDK
        android_example();

        // Log user-defined types example
        user_defined_example();

        // Change default log error handler
        err_handler_example();

        // Apply a function on all registered loggers
        spd::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example."); });

        // Release and close all loggers
        spdlog::drop_all();
    }
    // Exceptions will only be thrown upon failed logger or sink construction (not during logging)
    catch (const spd::spdlog_ex &ex)
    {
        std::cout << "Log init failed: " << ex.what() << std::endl;
        return 1;
    }
}

void async_example()
{
    size_t q_size = 4096; // queue size must be power of 2
    spdlog::set_async_mode(q_size);
    auto async_file = spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
    for (int i = 0; i < 100; ++i)
    {
        async_file->info("Async message #{}", i);
    }
}

// syslog example (linux/osx/freebsd)
void syslog_example()
{
#ifdef SPDLOG_ENABLE_SYSLOG
    std::string ident = "spdlog-example";
    auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
    syslog_logger->warn("This is warning that will end up in syslog.");
#endif
}

// Android example
void android_example()
{
#if defined(__ANDROID__)
    std::string tag = "spdlog-android";
    auto android_logger = spd::android_logger("android", tag);
    android_logger->critical("Use \"adb shell logcat\" to view this message.");
#endif
}

// user defined types logging by implementing operator<<
struct my_type
{
    int i;
    template<typename OStream>
    friend OStream &operator<<(OStream &os, const my_type &c)
    {
        return os << "[my_type i=" << c.i << "]";
    }
};

#include "spdlog/fmt/ostr.h" // must be included
void user_defined_example()
{
    spd::get("console")->info("user defined type: {}", my_type{14});
}

//
// custom error handler
//
void err_handler_example()
{
    // can be set globaly or per logger(logger->set_error_handler(..))
    spdlog::set_error_handler([](const std::string &msg) { std::cerr << "my err handler: " << msg << std::endl; });
    spd::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
}
<commit_msg>Fixed example<commit_after>//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
//
// spdlog usage example
//
//

#define SPDLOG_TRACE_ON
#define SPDLOG_DEBUG_ON

#include "spdlog/spdlog.h"

#include <iostream>
#include <memory>

void async_example();
void syslog_example();
void android_example();
void user_defined_example();
void err_handler_example();

namespace spd = spdlog;
int main(int, char *[])
{
    try
    {
        // Console logger with color
        auto console = spd::stdout_color_mt("console");
        console->info("Welcome to spdlog!");
        console->error("Some error message with arg{}..", 1);

        // Formatting examples
        console->warn("Easy padding in numbers like {:08d}", 12);
        console->critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
        console->info("Support for floats {:03.2f}", 1.23456);
        console->info("Positional args are {1} {0}..", "too", "supported");
        console->info("{:<30}", "left aligned");

        spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");

        // Create basic file logger (not rotated)
        auto my_logger = spd::basic_logger_mt("basic_logger", "logs/basic-log.txt");
        my_logger->info("Some log message");

        // Create a file rotating logger with 5mb size max and 3 rotated files
        auto rotating_logger = spd::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
        for (int i = 0; i < 10; ++i)
        {
            rotating_logger->info("{} * {} equals {:>10}", i, i, i * i);
        }

        // Create a daily logger - a new file is created every day on 2:30am
        auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
        // trigger flush if the log severity is error or higher
        daily_logger->flush_on(spd::level::err);
        daily_logger->info(123.44);

        // Customize msg format for all messages
        spd::set_pattern("[%^+++%$] [%H:%M:%S %z] [thread %t] %v");
        console->info("This an info message with custom format (and custom color range between the '%^' and '%$')");
        console->error("This an error message with custom format (and custom color range between the '%^' and '%$')");

        // Runtime log levels
        spd::set_level(spd::level::info); // Set global log level to info
        console->debug("This message should not be displayed!");
        console->set_level(spd::level::debug); // Set specific logger's log level
        console->debug("This message should be displayed..");

        // Compile time log levels
        // define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON
        SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
        SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);

        // Asynchronous logging is very fast..
        // Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
        async_example();

        // syslog example. linux/osx only
        syslog_example();

        // android example. compile with NDK
        android_example();

        // Log user-defined types example
        user_defined_example();

        // Change default log error handler
        err_handler_example();

        // Apply a function on all registered loggers
        spd::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example."); });

        // Release and close all loggers
        spdlog::drop_all();
    }
    // Exceptions will only be thrown upon failed logger or sink construction (not during logging)
    catch (const spd::spdlog_ex &ex)
    {
        std::cout << "Log init failed: " << ex.what() << std::endl;
        return 1;
    }
}

void async_example()
{
    size_t q_size = 4096; // queue size must be power of 2
    spdlog::set_async_mode(q_size);
    auto async_file = spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
    for (int i = 0; i < 100; ++i)
    {
        async_file->info("Async message #{}", i);
    }
}

// syslog example (linux/osx/freebsd)
void syslog_example()
{
#ifdef SPDLOG_ENABLE_SYSLOG
    std::string ident = "spdlog-example";
    auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
    syslog_logger->warn("This is warning that will end up in syslog.");
#endif
}

// Android example
void android_example()
{
#if defined(__ANDROID__)
    std::string tag = "spdlog-android";
    auto android_logger = spd::android_logger("android", tag);
    android_logger->critical("Use \"adb shell logcat\" to view this message.");
#endif
}

// user defined types logging by implementing operator<<
struct my_type
{
    int i;
    template<typename OStream>
    friend OStream &operator<<(OStream &os, const my_type &c)
    {
        return os << "[my_type i=" << c.i << "]";
    }
};

#include "spdlog/fmt/ostr.h" // must be included
void user_defined_example()
{
    spd::get("console")->info("user defined type: {}", my_type{14});
}

//
// custom error handler
//
void err_handler_example()
{
    // can be set globaly or per logger(logger->set_error_handler(..))
    spdlog::set_error_handler([](const std::string &msg) { std::cerr << "my err handler: " << msg << std::endl; });
    spd::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3);
}
<|endoftext|>


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

//
// spdlog usage example
//
#include <iostream>
#include "spdlog/spdlog.h"

int main(int, char* [])
{

    namespace spd = spdlog;

    try
    {
        std::string filename = "logs/spdlog_example";
        // Set log level to all loggers to DEBUG and above
        spd::set_level(spd::level::DEBUG);

        //Create console, multithreaded logger
        auto console = spd::stdout_logger_mt("console");
        console->info("Welcome to spdlog!") ;
        console->info("An info message example {}..", 1);
        console->info() << "Streams are supported too  " << 1;

        console->info("Easy padding in numbers like {:08d}", 12);
        console->info("Support for int: {0:d};  hex: {0:08x};  oct: {0:o}; bin: {0:b}", 42);
        console->info("Support for floats {:03.2f}", 1.23456);
        console->info("Positional args are {1} {0}..", "too", "supported");

        console->info("{:<30}", "left aligned");
        console->info("{:>30}", "right aligned");
        console->info("{:^30}", "centered");

        //Create a file rotating logger with 5mb size max and 3 rotated files
        auto file_logger = spd::rotating_logger_mt("file_logger", filename, 1024 * 1024 * 5, 3);

        file_logger->info("Log file message number", 1);
        for(int i = 0; i < 10; ++i)
            file_logger->info("{} * {} equals {:>10}", i, i, i*i);

        spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
        file_logger->info("This is another message with custom format");

        spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");

		// Debug and trace macros to be turned on/off at compile time.
		// Evaluates to empty statements if not turned on
		// Define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON - before including spdlog.h
        SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
        SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);

#ifdef __linux__
		// syslog example
		std::string ident = "spdlog_example"; // empty ident can be used to use current program name
        auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
        syslog_logger->set_pattern("[%l] %v"); //syslog already put timestamps so set the pattern to minimum (log level and the message)
        syslog_logger->warn("This message that will end up in syslog. This is Linux only..");
#endif

        // Asynchronous logging is easy..
        // Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
        // Note: queue size must be power of 2!
        size_t q_size = 1048576;
        spdlog::set_async_mode(q_size);
        auto async_file= spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
        async_file->info() << "This is async log.." << "Should be very fast!";

    }
    catch (const spd::spdlog_ex& ex)
    {
        std::cout << "Log failed: " << ex.what() << std::endl;
    }
    return 0;
}

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

//
// spdlog usage example
//
#include <iostream>
#include "spdlog/spdlog.h"

int main(int, char* [])
{

    namespace spd = spdlog;

    try
    {
        std::string filename = "logs/spdlog_example";
        // Set log level to all loggers to DEBUG and above
        spd::set_level(spd::level::DEBUG);

        //Create console, multithreaded logger
        auto console = spd::stdout_logger_mt("console");
        console->info("Welcome to spdlog!") ;
        console->info("An info message example {}..", 1);
        console->info() << "Streams are supported too  " << 1;

        console->info("Easy padding in numbers like {:08d}", 12);
        console->info("Support for int: {0:d};  hex: {0:08x};  oct: {0:o}; bin: {0:b}", 42);
        console->info("Support for floats {:03.2f}", 1.23456);
        console->info("Positional args are {1} {0}..", "too", "supported");

        console->info("{:<30}", "left aligned");
        console->info("{:>30}", "right aligned");
        console->info("{:^30}", "centered");

        //Create a file rotating logger with 5mb size max and 3 rotated files
        auto file_logger = spd::rotating_logger_mt("file_logger", filename, 1024 * 1024 * 5, 3);

        file_logger->info("Log file message number", 1);
        for(int i = 0; i < 10; ++i)
            file_logger->info("{} * {} equals {:>10}", i, i, i*i);

        spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
        file_logger->info("This is another message with custom format");

        spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");

		// Debug and trace macros to be turned on/off at compile time.
		// Evaluates to empty statements if not turned on
		// Define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON - before including spdlog.h
        SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
        SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);

#ifdef __linux__
		// syslog example
		std::string ident = "spdlog_example"; // empty ident can be used to use current program name
        auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
        syslog_logger->set_pattern("[%l] %v"); //syslog already put timestamps so set the pattern to minimum (log level and the message)
        syslog_logger->warn("This message that will end up in syslog. This is Linux only..");
#endif

        // Asynchronous logging is easy..
        // Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
        // Note: queue size must be power of 2!
        size_t q_size = 1048576;
        spdlog::set_async_mode(q_size);
        auto async_file= spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
        for(int i = 0; i < 100; i++)
	        async_file->info("This is async log message #{}.. Should be very fast.. ", i);

    }
    catch (const spd::spdlog_ex& ex)
    {
        std::cout << "Log failed: " << ex.what() << std::endl;
    }
    return 0;
}

<|endoftext|>


<commit_before>#include "Script.hpp"

#include <fstream>
#include <cassert>

#include "../ResourceManager/AssetManager.hpp"
#include "../GUI/Window.hpp"
#include "../GUI/Widgets/Button.hpp"
#include "../GUI/Widgets/Label.hpp"
#include "../GUI/Widgets/TextBox.hpp"
#include "../GUI/Widgets/Toggle.hpp"

namespace swift
{
	sf::RenderWindow* Script::window = nullptr;
	AssetManager* Script::assets = nullptr;
	sf::Clock* Script::clock = nullptr;
	Settings* Script::settings = nullptr;

	Script::Script()
			:	gui(nullptr),
				stateReturn(nullptr)
	{
		deleteMe = false;

		// We don't want to give the scripts access to os commands or file writing abilities
		luaState.OpenLib("base", luaopen_base);
		luaState.OpenLib("math", luaopen_math);
		luaState.OpenLib("string", luaopen_string);
		luaState.OpenLib("table", luaopen_table);

		addVariables();
		addClasses();
		addFunctions();
	}

	Script::~Script()
	{
	}

	bool Script::loadFromFile(const std::string& file)
	{
		bool r = luaState.Load(file);	// r will be false if errors, true otherwise

		return r;
	}

	void Script::start()
	{
		luaState["Start"]();

		if(static_cast<bool>(luaState["Done"]) == true)
		{
			deleteMe = true;
		}
	}

	void Script::run()
	{
		luaState["Update"]();

		if(static_cast<bool>(luaState["Done"]) == true)
		{
			deleteMe = true;
		}
	}

	bool Script::toDelete()
	{
		return deleteMe;
	}

	void Script::setWindow(sf::RenderWindow& win)
	{
		window = &win;
	}

	void Script::setAssetManager(AssetManager& am)
	{
		assets = &am;
	}

	void Script::setSettings(Settings& s)
	{
		settings = &s;
	}

	void Script::setGUI(cstr::Window& ui)
	{
		gui = &ui;
	}

	void Script::setKeyboard(KeyboardManager& k)
	{
		keyboard = &k;
	}

	void Script::setStateReturn(State::Type& t)
	{
		stateReturn = &t;
	}

	void Script::setClock(sf::Clock& c)
	{
		clock = &c;
	}

	void Script::addVariables()
	{
		luaState["states"]["MainMenu"] = 0;
		luaState["states"]["Settings"] = 1;
		luaState["states"]["Play"] = 2;
		luaState["states"]["Exit"] = 3;
	}

	void Script::addClasses()
	{
		luaState["Label"].SetClass<cstr::Label>("setTextSize", &cstr::Label::setCharacterSize);
		luaState["Button"].SetClass<cstr::Button>("setText", &cstr::Button::setText);
		luaState["Toggle"].SetClass<cstr::Toggle>("getState", &cstr::Toggle::getState);
		luaState["TextBox"].SetClass<cstr::TextBox>("getString", &cstr::TextBox::getString);
	}

	void Script::addFunctions()
	{
		// utility functions
		luaState["getWindowSize"] = [&]()
		{
			if(window)
				return std::make_tuple(window->getSize().x, window->getSize().y);
			else
				return std::make_tuple(0u, 0u);
		};

		luaState["getTime"] = [&]()
		{
			if(clock)
				return clock->getElapsedTime().asSeconds();
			else
				return 0.f;
		};

		luaState["doKeypress"] = [&](std::string k) -> void
		{
			if(keyboard)
				keyboard->call(k);
		};

		// gui functions
		luaState["setFont"] = [&](std::string f) -> void
		{
			if(gui)
				gui->setFont(assets->getFont(f));
		};

		luaState["addLabel"] = [&](int x, int y, std::string l) -> cstr::Label*
		{
			return &gui->addLabel({x, y}, l);
		};

		luaState["addButton"] = [&](int x, int y, int w, int h, std::string t, sel::function<void()> f) -> cstr::Button*
		{
			return &gui->addButton({x, y, w, h}, assets->getTexture(t), static_cast<std::function<void()>>(f));
		};

		luaState["addToggle"] = [&](int x, int y, int w, int h, std::string texOff, std::string texOn, bool s) -> cstr::Toggle*
		{
			return &gui->addToggle({x, y, w, h}, assets->getTexture(texOff), assets->getTexture(texOn), s);
		};

		luaState["addTextBox"] = [&](int x, int y, int w, int h, int inR, int inG, int inB, int outR, int outG, int outB) -> cstr::TextBox*
		{
			return &gui->addTextBox({x, y, w, h}, {static_cast<sf::Uint8>(inR), static_cast<sf::Uint8>(inG), static_cast<sf::Uint8>(inB)},
												{static_cast<sf::Uint8>(outR), static_cast<sf::Uint8>(outG), static_cast<sf::Uint8>(outB)});
		};

		// State functions
		luaState["setStateReturn"] = [&](unsigned s)
		{
			*stateReturn = static_cast<State::Type>(s);
		};

		// Settings functions
		luaState["getSettingStr"] = [&](std::string n)
		{
			std::string v;
			return std::make_tuple(settings->get(n, v), v);
		};

		luaState["setSettingStr"] = [&](std::string n, std::string v)
		{
			settings->set(n, v);
		};

		luaState["getSettingBool"] = [&](std::string n)
		{
			bool v;
			return std::make_tuple(settings->get(n, v), v);
		};

		luaState["setSettingBool"] = [&](std::string n, bool v)
		{
			settings->set(n, v);
		};

		luaState["getSettingNum"] = [&](std::string n)
		{
			int v;
			return std::make_tuple(settings->get(n, v), v);
		};

		luaState["setSettingNum"] = [&](std::string n, int v)
		{
			settings->set(n, v);
		};
	}
}<commit_msg>Cleaned out Script functions in prep for new GUI.<commit_after>#include "Script.hpp"

#include <fstream>
#include <cassert>

#include "../ResourceManager/AssetManager.hpp"
//#include "../GUI/Window.hpp"
//#include "../GUI/Widgets/Button.hpp"
//#include "../GUI/Widgets/Label.hpp"
//#include "../GUI/Widgets/TextBox.hpp"
//#include "../GUI/Widgets/Toggle.hpp"

namespace swift
{
	sf::RenderWindow* Script::window = nullptr;
	AssetManager* Script::assets = nullptr;
	sf::Clock* Script::clock = nullptr;
	Settings* Script::settings = nullptr;

	Script::Script()
			:	gui(nullptr),
				stateReturn(nullptr)
	{
		deleteMe = false;

		// We don't want to give the scripts access to os commands or file writing abilities
		luaState.OpenLib("base", luaopen_base);
		luaState.OpenLib("math", luaopen_math);
		luaState.OpenLib("string", luaopen_string);
		luaState.OpenLib("table", luaopen_table);

		addVariables();
		addClasses();
		addFunctions();
	}

	Script::~Script()
	{
	}

	bool Script::loadFromFile(const std::string& file)
	{
		bool r = luaState.Load(file);	// r will be false if errors, true otherwise

		return r;
	}

	void Script::start()
	{
		luaState["Start"]();

		if(static_cast<bool>(luaState["Done"]) == true)
		{
			deleteMe = true;
		}
	}

	void Script::run()
	{
		luaState["Update"]();

		if(static_cast<bool>(luaState["Done"]) == true)
		{
			deleteMe = true;
		}
	}

	bool Script::toDelete()
	{
		return deleteMe;
	}

	void Script::setWindow(sf::RenderWindow& win)
	{
		window = &win;
	}

	void Script::setAssetManager(AssetManager& am)
	{
		assets = &am;
	}

	void Script::setSettings(Settings& s)
	{
		settings = &s;
	}

	void Script::setGUI(cstr::Window& ui)
	{
		gui = &ui;
	}

	void Script::setKeyboard(KeyboardManager& k)
	{
		keyboard = &k;
	}

	void Script::setStateReturn(State::Type& t)
	{
		stateReturn = &t;
	}

	void Script::setClock(sf::Clock& c)
	{
		clock = &c;
	}

	void Script::addVariables()
	{
		luaState["states"]["MainMenu"] = 0;
		luaState["states"]["Settings"] = 1;
		luaState["states"]["Play"] = 2;
		luaState["states"]["Exit"] = 3;
	}

	void Script::addClasses()
	{

	}

	void Script::addFunctions()
	{
		// utility functions
		luaState["getWindowSize"] = [&]()
		{
			if(window)
				return std::make_tuple(window->getSize().x, window->getSize().y);
			else
				return std::make_tuple(0u, 0u);
		};

		luaState["getTime"] = [&]()
		{
			if(clock)
				return clock->getElapsedTime().asSeconds();
			else
				return 0.f;
		};

		luaState["doKeypress"] = [&](std::string k) -> void
		{
			if(keyboard)
				keyboard->call(k);
		};

		// gui functions
		luaState["setFont"] = [&](std::string f) -> void
		{
			if(gui)
				gui->setFont(assets->getFont(f));
		};

		// State functions
		luaState["setStateReturn"] = [&](unsigned s)
		{
			*stateReturn = static_cast<State::Type>(s);
		};

		// Settings functions
		luaState["getSettingStr"] = [&](std::string n)
		{
			std::string v;
			return std::make_tuple(settings->get(n, v), v);
		};

		luaState["setSettingStr"] = [&](std::string n, std::string v)
		{
			return settings->set(n, v);
		};

		luaState["getSettingBool"] = [&](std::string n)
		{
			bool v;
			return std::make_tuple(settings->get(n, v), v);
		};

		luaState["setSettingBool"] = [&](std::string n, bool v)
		{
			return settings->set(n, v);
		};

		luaState["getSettingNum"] = [&](std::string n)
		{
			int v;
			return std::make_tuple(settings->get(n, v), v);
		};

		luaState["setSettingNum"] = [&](std::string n, int v)
		{
			return settings->set(n, v);
		};
	}
}<|endoftext|>


<commit_before>// -*- mode: C++ -*-
//
// Copyright (c) 2007, 2008, 2009, 2010, 2011 The University of Utah
// All rights reserved.
//
// This file is part of `csmith', a random generator of C programs.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistributions in binary form must reproduce the above copyright
//     notice, this list of conditions and the following disclaimer in the
//     documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include "StatementArrayOp.h"
#include <cassert>
#include "Common.h"
#include "Block.h"
#include "CGContext.h"
#include "CGOptions.h"
#include "Constant.h"
#include "ExpressionFuncall.h"
#include "ExpressionVariable.h"
#include "Function.h"
#include "FunctionInvocation.h"
#include "FunctionInvocationBinary.h"
#include "VariableSelector.h"
#include "FactMgr.h"
#include "Lhs.h"
#include "SafeOpFlags.h"
#include "Error.h"
#include "PartialExpander.h"
#include "Bookkeeper.h"
#include "DepthSpec.h"
#include "StatementBreak.h"
#include "StatementFor.h"
#include "CFGEdge.h"
#include "ArrayVariable.h"
#include "random.h"

using namespace std;

///////////////////////////////////////////////////////////////////////////////

/*
 * Randomly determine the iteration over an array: initial value,
 * increment value (negative means going backwards), given the size
 * of array
 */
void
StatementArrayOp::make_random_iter_ctrl(int size, int &init, int &incr)
{
	// We don't have to put error guards here because we are trying
	// to get pure random numbers, and in this case, we cannot get
	// errors
	init = pure_rnd_flipcoin(50) ? 0 : pure_rnd_upto(size);
	incr = pure_rnd_flipcoin(50) ? 1 : pure_rnd_upto(size) + 1;
}

/*
 *
 */
Statement*
StatementArrayOp::make_random(CGContext &cg_context)
{
	bool ary_init = rnd_flipcoin(5);
	ERROR_GUARD(NULL);
	if (ary_init) {
		return make_random_array_init(cg_context);
	}
	StatementFor* sf = StatementFor::make_random_array_loop(cg_context);
	return sf;
}

StatementArrayOp *
StatementArrayOp::make_random_array_init(CGContext &cg_context)
{
	// select the array to initialize
	//static int g = 0;
	//int h = g++;
	ArrayVariable* av =  VariableSelector::select_array(cg_context);
	ERROR_GUARD(NULL);
	cg_context.get_effect_stm().clear();
	// Select the loop control variable.
	vector<const Variable*> invalid_vars;
	vector<const Variable*> cvs;
	ERROR_GUARD(NULL);
	// the iteration settings are simple: start from index 0, step through all members
	vector<int> inits, incrs;
	size_t i;
	cg_context.get_effect_stm().clear();
	FactMgr* fm = get_fact_mgr(&cg_context);
	for (i=0; i<av->get_dimension(); i++) {
		inits.push_back(0);
		incrs.push_back(1);
		Variable *cv = VariableSelector::SelectLoopCtrlVar(cg_context, invalid_vars);
		invalid_vars.push_back(cv);
		cvs.push_back(cv);
		assert(cg_context.read_indices(cv, fm->global_facts));
		cg_context.write_var(cv);
	}
	cg_context.write_var(av);

	// JYTODO: initialize only field(s) of array members if they are of type struct
	Block* b = cg_context.get_current_block()->random_parent_block();
	Expression* init = VariableSelector::make_init_value(Effect::READ, cg_context, av->type, &av->qfer, b);
	assert(init->visit_facts(fm->global_facts, cg_context));
	StatementArrayOp* sa = new StatementArrayOp(cg_context.get_current_block(), av, cvs, inits, incrs, init);
	Lhs lhs(*av);
	if (update_fact_for_assign(&lhs, init, fm->global_facts)) {
		cg_context.get_current_func()->fact_changed = true;
	}
	fm->map_stm_effect[sa] = cg_context.get_effect_stm();
	return sa;
}

/*
 *
 */
StatementArrayOp::StatementArrayOp(Block* b, const ArrayVariable* av,
				   const std::vector<const Variable*>& cvs,
				   const std::vector<int>& inits,
				   const std::vector<int>& incrs,
				   const Block *body)
	: Statement(eArrayOp, b),
	  array_var(av),
	  ctrl_vars(cvs),
	  inits(inits),
	  incrs(incrs),
	  body(body),
	  init_value(0)
{
	// Nothing else to do.
}

/*
 *
 */
StatementArrayOp::StatementArrayOp(Block* b, const ArrayVariable* av,
				   const std::vector<const Variable*>& cvs,
				   const std::vector<int>& inits,
				   const std::vector<int>& incrs,
				   const Expression *e)
	: Statement(eArrayOp, b),
	  array_var(av),
	  ctrl_vars(cvs),
	  inits(inits),
	  incrs(incrs),
	  body(0),
	  init_value(e)
{
	// Nothing else to do.
}

/*
 *
 */
StatementArrayOp::~StatementArrayOp(void)
{
	delete init_value;
	delete body;
}

void
StatementArrayOp::output_header(std::ostream& out, int& indent) const
{
	size_t i;
	for (i=0; i<array_var->get_dimension(); i++) {
		if (i > 0) {
			output_tab(out, indent);
			out << "{";
			outputln(out);
			indent++;
		}
		output_tab(out, indent);
		out << "for (";
		ctrl_vars[i]->Output(out);
		out << " = " << inits[i] << "; ";
		ctrl_vars[i]->Output(out);
		(incrs[i] > 0) ? out << " < " << array_var->get_sizes()[i] : out << " >= 0";
		out << "; ";
		ctrl_vars[i]->Output(out);
		if (CGOptions::ccomp()) {
			// ccomp disable something like g += 1, where g is volatile
			out << " = ";
			ctrl_vars[i]->Output(out);
			out << " + " << incrs[i] << ")";
		}
		else {
			out << " += " << incrs[i] << ")";
		}
		outputln(out);
	}
}

/*
 *
 */
void
StatementArrayOp::Output(std::ostream &out, FactMgr* fm, int indent) const
{
	size_t i;
	output_header(out, indent);

	if (body) {
		body->Output(out, fm, indent);
	}
	else if (init_value) {
		output_tab(out, indent);
		out << "{";
		outputln(out);
		// cannot assign array members to a struct/union constant directly, has to create a "fake" struct var first
		if (init_value->term_type == eConstant && array_var->is_aggregate()) {
			output_tab(out, indent+1);
			array_var->type->Output(out);
			out << " tmp = ";
			init_value->Output(out);
			out << ";";
			outputln(out);
			output_tab(out, indent+1);
			array_var->output_with_indices(out, ctrl_vars);
			out << " = tmp;";
			outputln(out);
		}
		else {
			output_tab(out, indent+1);
			array_var->output_with_indices(out, ctrl_vars);
			out << " = ";
			init_value->Output(out);
			out << ";";
			outputln(out);
		}
		output_tab(out, indent);
		out << "}";
		outputln(out);
	}
	// output the closing bracelets
	for (i=1; i<array_var->get_dimension(); i++) {
		indent--;
		output_tab(out, indent);
		out << "}";
		outputln(out);
	}
}

bool
StatementArrayOp::visit_facts(vector<const Fact*>& inputs, CGContext& cg_context) const
{
	// walk the iterations
	size_t i;
	for (i=0; i<array_var->get_dimension(); i++) {
		const Variable *cv = ctrl_vars[i];
		if (!cg_context.check_write_var(cv, inputs)) {
			return false;
		}
	}
	FactMgr* fm = get_fact_mgr(&cg_context);
	// walk the body (if there is one)
	if (body) {
		FactVec facts_copy = inputs;
		Effect eff = cg_context.get_effect_stm();
		if (!body->visit_facts(inputs, cg_context)) {
			return false;
		}
		// if body must return, means the control reached end of for-loop with pre-loop env
		if (body->must_return()) {
			inputs = facts_copy;
		} else {
			inputs = fm->map_facts_in[body];
		}
		// include the facts from "break" statements
		// find edges leading to the end of this statement, and merge
		vector<const CFGEdge*> edges;
		find_edges_in(edges, true, false);
		for (i=0; i<edges.size(); i++) {
			const Statement* src = edges[i]->src;
			merge_jump_facts(inputs, fm->map_facts_out[src]);
		}
		// compute accumulated effect
		set_accumulated_effect_after_block(eff, body, cg_context);
	}
	// walk the initializing value, if this is an array initialization
	else if (init_value) {
		Lhs lhs(*array_var);
		if (!init_value->visit_facts(inputs, cg_context)) {
			return false;
		}
		if (!lhs.visit_facts(inputs, cg_context)) {
			return false;
		}
		update_fact_for_assign(&lhs, init_value, inputs);
		fm->map_stm_effect[this] = cg_context.get_effect_stm();
	}
	return true;
}

///////////////////////////////////////////////////////////////////////////////

// Local Variables:
// c-basic-offset: 4
// tab-width: 4
// End:

// End of file.
<commit_msg>avoid using diff. union fields as IVs of the same loop<commit_after>// -*- mode: C++ -*-
//
// Copyright (c) 2007, 2008, 2009, 2010, 2011 The University of Utah
// All rights reserved.
//
// This file is part of `csmith', a random generator of C programs.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistributions in binary form must reproduce the above copyright
//     notice, this list of conditions and the following disclaimer in the
//     documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include "StatementArrayOp.h"
#include <cassert>
#include "Common.h"
#include "Block.h"
#include "CGContext.h"
#include "CGOptions.h"
#include "Constant.h"
#include "ExpressionFuncall.h"
#include "ExpressionVariable.h"
#include "Function.h"
#include "FunctionInvocation.h"
#include "FunctionInvocationBinary.h"
#include "VariableSelector.h"
#include "FactMgr.h"
#include "Lhs.h"
#include "SafeOpFlags.h"
#include "Error.h"
#include "PartialExpander.h"
#include "Bookkeeper.h"
#include "DepthSpec.h"
#include "StatementBreak.h"
#include "StatementFor.h"
#include "CFGEdge.h"
#include "ArrayVariable.h"
#include "random.h"

using namespace std;

///////////////////////////////////////////////////////////////////////////////

/*
 * Randomly determine the iteration over an array: initial value,
 * increment value (negative means going backwards), given the size
 * of array
 */
void
StatementArrayOp::make_random_iter_ctrl(int size, int &init, int &incr)
{
	// We don't have to put error guards here because we are trying
	// to get pure random numbers, and in this case, we cannot get
	// errors
	init = pure_rnd_flipcoin(50) ? 0 : pure_rnd_upto(size);
	incr = pure_rnd_flipcoin(50) ? 1 : pure_rnd_upto(size) + 1;
}

/*
 *
 */
Statement*
StatementArrayOp::make_random(CGContext &cg_context)
{
	bool ary_init = rnd_flipcoin(5);
	ERROR_GUARD(NULL);
	if (ary_init) {
		return make_random_array_init(cg_context);
	}
	StatementFor* sf = StatementFor::make_random_array_loop(cg_context);
	return sf;
}

StatementArrayOp *
StatementArrayOp::make_random_array_init(CGContext &cg_context)
{
	// select the array to initialize
	//static int g = 0;
	//int h = g++;
	ArrayVariable* av =  VariableSelector::select_array(cg_context);
	ERROR_GUARD(NULL);
	cg_context.get_effect_stm().clear();
	// Select the loop control variable.
	vector<const Variable*> invalid_vars;
	vector<const Variable*> cvs;
	ERROR_GUARD(NULL);
	// the iteration settings are simple: start from index 0, step through all members
	vector<int> inits, incrs;
	size_t i;
	cg_context.get_effect_stm().clear();
	FactMgr* fm = get_fact_mgr(&cg_context);
	for (i=0; i<av->get_dimension(); i++) {
		inits.push_back(0);
		incrs.push_back(1);
		Variable *cv = VariableSelector::SelectLoopCtrlVar(cg_context, invalid_vars);
		invalid_vars.push_back(cv);
		cvs.push_back(cv);
		assert(cg_context.read_indices(cv, fm->global_facts));
		cg_context.write_var(cv);
		// put in induction variable list so that later indices have no write-write conflict
		cg_context.iv_bounds[cv] = av->get_sizes()[i];
	}
	cg_context.write_var(av);

	// JYTODO: initialize only field(s) of array members if they are of type struct
	Block* b = cg_context.get_current_block()->random_parent_block();
	Expression* init = VariableSelector::make_init_value(Effect::READ, cg_context, av->type, &av->qfer, b);
	assert(init->visit_facts(fm->global_facts, cg_context));
	StatementArrayOp* sa = new StatementArrayOp(cg_context.get_current_block(), av, cvs, inits, incrs, init);
	Lhs lhs(*av);
	if (update_fact_for_assign(&lhs, init, fm->global_facts)) {
		cg_context.get_current_func()->fact_changed = true;
	}
	fm->map_stm_effect[sa] = cg_context.get_effect_stm();

	// clear IV list from cg_context
	for (i=0; i<cvs.size(); i++) {
		cg_context.iv_bounds.erase(cvs[i]);
	}
	return sa;
}

/*
 *
 */
StatementArrayOp::StatementArrayOp(Block* b, const ArrayVariable* av,
				   const std::vector<const Variable*>& cvs,
				   const std::vector<int>& inits,
				   const std::vector<int>& incrs,
				   const Block *body)
	: Statement(eArrayOp, b),
	  array_var(av),
	  ctrl_vars(cvs),
	  inits(inits),
	  incrs(incrs),
	  body(body),
	  init_value(0)
{
	// Nothing else to do.
}

/*
 *
 */
StatementArrayOp::StatementArrayOp(Block* b, const ArrayVariable* av,
				   const std::vector<const Variable*>& cvs,
				   const std::vector<int>& inits,
				   const std::vector<int>& incrs,
				   const Expression *e)
	: Statement(eArrayOp, b),
	  array_var(av),
	  ctrl_vars(cvs),
	  inits(inits),
	  incrs(incrs),
	  body(0),
	  init_value(e)
{
	// Nothing else to do.
}

/*
 *
 */
StatementArrayOp::~StatementArrayOp(void)
{
	delete init_value;
	delete body;
}

void
StatementArrayOp::output_header(std::ostream& out, int& indent) const
{
	size_t i;
	for (i=0; i<array_var->get_dimension(); i++) {
		if (i > 0) {
			output_tab(out, indent);
			out << "{";
			outputln(out);
			indent++;
		}
		output_tab(out, indent);
		out << "for (";
		ctrl_vars[i]->Output(out);
		out << " = " << inits[i] << "; ";
		ctrl_vars[i]->Output(out);
		(incrs[i] > 0) ? out << " < " << array_var->get_sizes()[i] : out << " >= 0";
		out << "; ";
		ctrl_vars[i]->Output(out);
		if (CGOptions::ccomp()) {
			// ccomp disable something like g += 1, where g is volatile
			out << " = ";
			ctrl_vars[i]->Output(out);
			out << " + " << incrs[i] << ")";
		}
		else {
			out << " += " << incrs[i] << ")";
		}
		outputln(out);
	}
}

/*
 *
 */
void
StatementArrayOp::Output(std::ostream &out, FactMgr* fm, int indent) const
{
	size_t i;
	output_header(out, indent);

	if (body) {
		body->Output(out, fm, indent);
	}
	else if (init_value) {
		output_tab(out, indent);
		out << "{";
		outputln(out);
		// cannot assign array members to a struct/union constant directly, has to create a "fake" struct var first
		if (init_value->term_type == eConstant && array_var->is_aggregate()) {
			output_tab(out, indent+1);
			array_var->type->Output(out);
			out << " tmp = ";
			init_value->Output(out);
			out << ";";
			outputln(out);
			output_tab(out, indent+1);
			array_var->output_with_indices(out, ctrl_vars);
			out << " = tmp;";
			outputln(out);
		}
		else {
			output_tab(out, indent+1);
			array_var->output_with_indices(out, ctrl_vars);
			out << " = ";
			init_value->Output(out);
			out << ";";
			outputln(out);
		}
		output_tab(out, indent);
		out << "}";
		outputln(out);
	}
	// output the closing bracelets
	for (i=1; i<array_var->get_dimension(); i++) {
		indent--;
		output_tab(out, indent);
		out << "}";
		outputln(out);
	}
}

bool
StatementArrayOp::visit_facts(vector<const Fact*>& inputs, CGContext& cg_context) const
{
	// walk the iterations
	size_t i;
	for (i=0; i<array_var->get_dimension(); i++) {
		const Variable *cv = ctrl_vars[i];
		if (!cg_context.check_write_var(cv, inputs)) {
			return false;
		}
	}
	FactMgr* fm = get_fact_mgr(&cg_context);
	// walk the body (if there is one)
	if (body) {
		FactVec facts_copy = inputs;
		Effect eff = cg_context.get_effect_stm();
		if (!body->visit_facts(inputs, cg_context)) {
			return false;
		}
		// if body must return, means the control reached end of for-loop with pre-loop env
		if (body->must_return()) {
			inputs = facts_copy;
		} else {
			inputs = fm->map_facts_in[body];
		}
		// include the facts from "break" statements
		// find edges leading to the end of this statement, and merge
		vector<const CFGEdge*> edges;
		find_edges_in(edges, true, false);
		for (i=0; i<edges.size(); i++) {
			const Statement* src = edges[i]->src;
			merge_jump_facts(inputs, fm->map_facts_out[src]);
		}
		// compute accumulated effect
		set_accumulated_effect_after_block(eff, body, cg_context);
	}
	// walk the initializing value, if this is an array initialization
	else if (init_value) {
		Lhs lhs(*array_var);
		if (!init_value->visit_facts(inputs, cg_context)) {
			return false;
		}
		if (!lhs.visit_facts(inputs, cg_context)) {
			return false;
		}
		update_fact_for_assign(&lhs, init_value, inputs);
		fm->map_stm_effect[this] = cg_context.get_effect_stm();
	}
	return true;
}

///////////////////////////////////////////////////////////////////////////////

// Local Variables:
// c-basic-offset: 4
// tab-width: 4
// End:

// End of file.
<|endoftext|>


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

#ifndef UTIL_RINGBUFFER_HPP
#define UTIL_RINGBUFFER_HPP

#include <cstring>
#include <cassert>
#include <cstdio>

/**
 *  See:
 *  HeapRingBuffer
 *  MemoryRingBuffer
**/

class RingBuffer {
public:
  int write(const void* buffer, int length) noexcept
  {
    const char* data = (const char*) buffer;
    if (length > free_space()) {
      length = free_space();
      if (length == 0) return 0;
    }

    // check if we are going around the buffer ...
    int wrap = (end + length) - this->cap;

    if (wrap > 0) {
      memcpy(at_end() ,    data, length - wrap);
      memcpy(this->buffer, data + length - wrap, wrap);
    }
    else {
      memcpy(at_end(), data, length);
    }
    this->used += length;
    // make sure it wraps properly around
    this->end = (this->end + length) % capacity();
    return length;
  }

  int read(char* dest, int length) noexcept
  {
    if (length > used_space()) {
      length = used_space();
      if (length == 0) return 0;
    }

    // check if we are going around the buffer ...
    int wrap = (start + length) - this->cap;

    if (wrap > 0) {
      memcpy(dest,                 at_start(),   length - wrap);
      memcpy(dest + length - wrap, this->buffer, wrap);
    } else {
      memcpy(dest, at_start(), length);
    }
    this->used -= length;
    // make sure it wraps properly around
    this->start = (this->start + length) % capacity();
    return length;
  }

  int discard(int length) noexcept
  {
    // do nothing if not enough used space to discard anyway
    if (length > used_space()) return 0;
    // commit no-op write and return length
    this->used -= length;
    this->start = (this->start + length) % capacity();
    return length;
  }

  int capacity() const noexcept {
    return this->cap;
  }
  int size() const noexcept {
    return used_space();
  }

  int used_space() const noexcept {
    return this->used;
  }
  int free_space() const noexcept {
    return capacity() - used_space();
  }

  bool full() const noexcept {
    return used_space() == capacity();
  }
  bool empty() const noexcept {
    return used_space() == 0;
  }

  // rotate buffer until it becomes sequential
  const char* sequentialize()
  {
    // not optimized, but if we assume the buffer is always full,
    // then there is no point in doing anything here
    int count = 0;
    int offset = 0;

    while (count < size())
    {
      int index = offset;
      const char tmp  = buffer[index];
      int index2 = (start + index) % capacity();

      while (index2 != offset)
      {
        buffer[index] = buffer[index2];
        count++;

        index = index2;
        index2 = (start + index) % capacity();
      }

      buffer[index] = tmp;
      count++;

      offset++;
    }
    // update internals
    this->start = 0;
    this->end = size();
    return this->buffer;
  }

  const char* data() const noexcept {
    return this->buffer;
  }

protected:
  virtual ~RingBuffer() = 0;
  RingBuffer(char* rbuffer, int size)
    : buffer(rbuffer), cap(size)
  {
    assert(size > 0);
  }

  const char* at_start() const noexcept {
    return &this->buffer[this->start];
  }
  char* at_end() const noexcept {
    return &this->buffer[this->end];
  }
  char* buffer;
  int  cap;
  int  start = 0;
  int  end   = 0;
  int  used  = 0;
};

class HeapRingBuffer : public RingBuffer {
public:
  HeapRingBuffer(int size)
    : RingBuffer(new char[size], size) {}
  virtual ~HeapRingBuffer() {
    delete[] this->buffer;
  }
};

class MemoryRingBuffer : public RingBuffer {
public:
  MemoryRingBuffer(char* location, int size)
    : RingBuffer(location, size) {}
  virtual ~MemoryRingBuffer() {}
};

template <int N>
class FixedRingBuffer : public RingBuffer {
public:
  FixedRingBuffer()
    : RingBuffer(m_buffer, N) {}
  virtual ~FixedRingBuffer() {}

private:
  char m_buffer[N];
};

inline RingBuffer::~RingBuffer() {}

#endif
<commit_msg>util: RingBuffer no longer virtual, moved stuff around<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef UTIL_RINGBUFFER_HPP
#define UTIL_RINGBUFFER_HPP

#include <cstring>
#include <cassert>
#include <cstdio>

/**
 *  See:
 *  HeapRingBuffer
 *  MemoryRingBuffer
**/

class RingBuffer {
public:
  int write(const void* buffer, int length) noexcept
  {
    const char* data = (const char*) buffer;
    if (length > free_space()) {
      length = free_space();
      if (length == 0) return 0;
    }

    // check if we are going around the buffer ...
    int wrap = (end + length) - this->cap;

    if (wrap > 0) {
      memcpy(at_end() ,    data, length - wrap);
      memcpy(this->buffer, data + length - wrap, wrap);
    }
    else {
      memcpy(at_end(), data, length);
    }
    this->used += length;
    // make sure it wraps properly around
    this->end = (this->end + length) % capacity();
    return length;
  }

  int read(char* dest, int length) noexcept
  {
    if (length > used_space()) {
      length = used_space();
      if (length == 0) return 0;
    }

    // check if we are going around the buffer ...
    int wrap = (start + length) - this->cap;

    if (wrap > 0) {
      memcpy(dest,                 at_start(),   length - wrap);
      memcpy(dest + length - wrap, this->buffer, wrap);
    } else {
      memcpy(dest, at_start(), length);
    }
    this->used -= length;
    // make sure it wraps properly around
    this->start = (this->start + length) % capacity();
    return length;
  }

  int discard(int length) noexcept
  {
    // do nothing if not enough used space to discard anyway
    if (length > used_space()) return 0;
    // commit no-op write and return length
    this->used -= length;
    this->start = (this->start + length) % capacity();
    return length;
  }

  int capacity() const noexcept {
    return this->cap;
  }
  int size() const noexcept {
    return used_space();
  }

  int used_space() const noexcept {
    return this->used;
  }
  int free_space() const noexcept {
    return capacity() - used_space();
  }

  bool full() const noexcept {
    return used_space() == capacity();
  }
  bool empty() const noexcept {
    return used_space() == 0;
  }

  bool is_valid() const noexcept {
    return (used <= cap and cap > 0)
      and (start < cap and start >= 0)
      and (end < cap and end >= 0);
  }

  // rotate buffer until it becomes sequential
  const char* sequentialize()
  {
    // not optimized, but if we assume the buffer is always full,
    // then there is no point in doing anything here
    int count = 0;
    int offset = 0;

    while (count < size())
    {
      int index = offset;
      const char tmp  = buffer[index];
      int index2 = (start + index) % capacity();

      while (index2 != offset)
      {
        buffer[index] = buffer[index2];
        count++;

        index = index2;
        index2 = (start + index) % capacity();
      }

      buffer[index] = tmp;
      count++;

      offset++;
    }
    // update internals
    this->start = 0;
    this->end = size();
    return this->buffer;
  }

  const char* data() const noexcept {
    return this->buffer;
  }

protected:
  RingBuffer(char* rbuffer, int size)
    : cap(size), buffer(rbuffer)
  {
    assert(size > 0);
  }

  const char* at_start() const noexcept {
    return &this->buffer[this->start];
  }
  char* at_end() const noexcept {
    return &this->buffer[this->end];
  }

  const int  cap;
  int  start = 0;
  int  end   = 0;
  int  used  = 0;
  char* buffer;
};

class HeapRingBuffer : public RingBuffer {
public:
  HeapRingBuffer(int size)
    : RingBuffer(new char[size], size) {}
  ~HeapRingBuffer() {
    delete[] this->buffer;
  }
};

class MemoryRingBuffer : public RingBuffer {
public:
  MemoryRingBuffer(char* location, int size)
    : RingBuffer(location, size) {}

  MemoryRingBuffer(char* loc, const int cap,
                   int start, int end, int used)
    : RingBuffer(loc, cap)
  {
    this->start = start;
    this->end   = end;
    this->used  = used;
  }

  ~MemoryRingBuffer() {}
};

template <int N>
class FixedRingBuffer : public RingBuffer {
public:
  FixedRingBuffer()
    : RingBuffer(m_buffer, N) {}
  ~FixedRingBuffer() {}

private:
  char m_buffer[N];
};

#endif
<|endoftext|>


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

#ifndef UTIL_RINGBUFFER_HPP
#define UTIL_RINGBUFFER_HPP

#include <cstring>
#include <cassert>
#include <cstdio>

/**
 *  See:
 *  HeapRingBuffer
 *  MemoryRingBuffer
**/

class RingBuffer {
public:
  int write(const void* buffer, int length) noexcept
  {
    const char* data = (const char*) buffer;
    if (length > free_space()) {
      length = free_space();
      if (length == 0) return 0;
    }

    // check if we are going around the buffer ...
    int wrap = (end + length) - this->cap;

    if (wrap > 0) {
      memcpy(at_end() ,    data, length - wrap);
      memcpy(this->buffer, data + length - wrap, wrap);
    }
    else {
      memcpy(at_end(), data, length);
    }
    this->used += length;
    // make sure it wraps properly around
    this->end = (this->end + length) % capacity();
    return length;
  }

  int read(char* dest, int length) noexcept
  {
    if (length > used_space()) {
      length = used_space();
      if (length == 0) return 0;
    }

    // check if we are going around the buffer ...
    int wrap = (start + length) - this->cap;

    if (wrap > 0) {
      memcpy(dest,                 at_start(),   length - wrap);
      memcpy(dest + length - wrap, this->buffer, wrap);
    } else {
      memcpy(dest, at_start(), length);
    }
    this->used -= length;
    // make sure it wraps properly around
    this->start = (this->start + length) % capacity();
    return length;
  }

  int discard(int length) noexcept
  {
    // do nothing if not enough used space to discard anyway
    if (length > used_space()) return 0;
    // commit no-op write and return length
    this->used -= length;
    this->start = (this->start + length) % capacity();
    return length;
  }

  int capacity() const noexcept {
    return this->cap;
  }
  int size() const noexcept {
    return used_space();
  }

  int used_space() const noexcept {
    return this->used;
  }
  int free_space() const noexcept {
    return capacity() - used_space();
  }

  bool full() const noexcept {
    return used_space() == capacity();
  }
  bool empty() const noexcept {
    return used_space() == 0;
  }

  // rotate buffer until it becomes sequential
  const char* sequentialize()
  {
    // not optimized, but if we assume the buffer is always full,
    // then there is no point in doing anything here
    int count = 0;
    int offset = 0;

    while (count < size())
    {
      int index = offset;
      const char tmp  = buffer[index];
      int index2 = (start + index) % capacity();

      while (index2 != offset)
      {
        buffer[index] = buffer[index2];
        count++;

        index = index2;
        index2 = (start + index) % capacity();
      }

      buffer[index] = tmp;
      count++;

      offset++;
    }
    // update internals
    this->start = 0;
    this->end = size();
    return this->buffer;
  }

  const char* data() const noexcept {
    return this->buffer;
  }

protected:
  virtual ~RingBuffer() = 0;
  RingBuffer(char* rbuffer, int size)
    : buffer(rbuffer), cap(size)
  {
    assert(size > 0);
  }

  const char* at_start() const noexcept {
    return &this->buffer[this->start];
  }
  char* at_end() const noexcept {
    return &this->buffer[this->end];
  }
  char* buffer;
  int  cap;
  int  start = 0;
  int  end   = 0;
  int  used  = 0;
};

class HeapRingBuffer : public RingBuffer {
public:
  HeapRingBuffer(int size)
    : RingBuffer(new char[capacity()], size) {}
  virtual ~HeapRingBuffer() {
    delete[] this->buffer;
  }
};

class MemoryRingBuffer : public RingBuffer {
public:
  MemoryRingBuffer(char* location, int size)
    : RingBuffer(location, size) {}
  virtual ~MemoryRingBuffer() {}
};

template <int N>
class FixedRingBuffer : public RingBuffer {
public:
  FixedRingBuffer()
    : RingBuffer(m_buffer, N) {}
  virtual ~FixedRingBuffer() {}

private:
  char m_buffer[N];
};

inline RingBuffer::~RingBuffer() {}

#endif
<commit_msg>util: Fix ringbuffer heap variant constructor<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef UTIL_RINGBUFFER_HPP
#define UTIL_RINGBUFFER_HPP

#include <cstring>
#include <cassert>
#include <cstdio>

/**
 *  See:
 *  HeapRingBuffer
 *  MemoryRingBuffer
**/

class RingBuffer {
public:
  int write(const void* buffer, int length) noexcept
  {
    const char* data = (const char*) buffer;
    if (length > free_space()) {
      length = free_space();
      if (length == 0) return 0;
    }

    // check if we are going around the buffer ...
    int wrap = (end + length) - this->cap;

    if (wrap > 0) {
      memcpy(at_end() ,    data, length - wrap);
      memcpy(this->buffer, data + length - wrap, wrap);
    }
    else {
      memcpy(at_end(), data, length);
    }
    this->used += length;
    // make sure it wraps properly around
    this->end = (this->end + length) % capacity();
    return length;
  }

  int read(char* dest, int length) noexcept
  {
    if (length > used_space()) {
      length = used_space();
      if (length == 0) return 0;
    }

    // check if we are going around the buffer ...
    int wrap = (start + length) - this->cap;

    if (wrap > 0) {
      memcpy(dest,                 at_start(),   length - wrap);
      memcpy(dest + length - wrap, this->buffer, wrap);
    } else {
      memcpy(dest, at_start(), length);
    }
    this->used -= length;
    // make sure it wraps properly around
    this->start = (this->start + length) % capacity();
    return length;
  }

  int discard(int length) noexcept
  {
    // do nothing if not enough used space to discard anyway
    if (length > used_space()) return 0;
    // commit no-op write and return length
    this->used -= length;
    this->start = (this->start + length) % capacity();
    return length;
  }

  int capacity() const noexcept {
    return this->cap;
  }
  int size() const noexcept {
    return used_space();
  }

  int used_space() const noexcept {
    return this->used;
  }
  int free_space() const noexcept {
    return capacity() - used_space();
  }

  bool full() const noexcept {
    return used_space() == capacity();
  }
  bool empty() const noexcept {
    return used_space() == 0;
  }

  // rotate buffer until it becomes sequential
  const char* sequentialize()
  {
    // not optimized, but if we assume the buffer is always full,
    // then there is no point in doing anything here
    int count = 0;
    int offset = 0;

    while (count < size())
    {
      int index = offset;
      const char tmp  = buffer[index];
      int index2 = (start + index) % capacity();

      while (index2 != offset)
      {
        buffer[index] = buffer[index2];
        count++;

        index = index2;
        index2 = (start + index) % capacity();
      }

      buffer[index] = tmp;
      count++;

      offset++;
    }
    // update internals
    this->start = 0;
    this->end = size();
    return this->buffer;
  }

  const char* data() const noexcept {
    return this->buffer;
  }

protected:
  virtual ~RingBuffer() = 0;
  RingBuffer(char* rbuffer, int size)
    : buffer(rbuffer), cap(size)
  {
    assert(size > 0);
  }

  const char* at_start() const noexcept {
    return &this->buffer[this->start];
  }
  char* at_end() const noexcept {
    return &this->buffer[this->end];
  }
  char* buffer;
  int  cap;
  int  start = 0;
  int  end   = 0;
  int  used  = 0;
};

class HeapRingBuffer : public RingBuffer {
public:
  HeapRingBuffer(int size)
    : RingBuffer(new char[size], size) {}
  virtual ~HeapRingBuffer() {
    delete[] this->buffer;
  }
};

class MemoryRingBuffer : public RingBuffer {
public:
  MemoryRingBuffer(char* location, int size)
    : RingBuffer(location, size) {}
  virtual ~MemoryRingBuffer() {}
};

template <int N>
class FixedRingBuffer : public RingBuffer {
public:
  FixedRingBuffer()
    : RingBuffer(m_buffer, N) {}
  virtual ~FixedRingBuffer() {}

private:
  char m_buffer[N];
};

inline RingBuffer::~RingBuffer() {}

#endif
<|endoftext|>