<commit_before>// FeatureExtractionCpp.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"

#include "HaemoragingImage.hpp"
#include "HistogramNormalize.hpp"

const char* keys =
{
    "{1||| must specify reference image name}"
    "{2||| must specify image name}"

};

Mat src, src_gray, reference;
RNG rng(12345);
string sourceWindow("Source");

ParamBag params;
unique_ptr<HaemoragingImage> haemorage(new HaemoragingImage);

vector<vector<Point>> * FindHaemorages(unique_ptr<HaemoragingImage>&, Mat&, ParamBag&);

void thresh_callback(int, void *)
{
    unique_ptr<vector<vector<Point>>> contours(FindHaemorages(haemorage, src, params));

    Mat img;
    src.copyTo(img);
    TransformImage::DrawContours(*contours, vector<Vec4i>(), img);

    /// Draw contours
    /// Show in a window
    imshow(sourceWindow, img);
}

int main(int argc, char** argv)
{
    CommandLineParser parser(argc, argv, keys);
    string ref_file_name = parser.get<string>("1");
    string file_name = parser.get<string>("2");

    gpu::printCudaDeviceInfo(0);

    Mat rgb;
    rgb = imread(file_name, IMREAD_COLOR);

    auto hi = HaemoragingImage(rgb);
    hi.PyramidDown();
    Mat src = hi.getEnhanced();
    rgb = imread(ref_file_name, IMREAD_COLOR);

    auto ref_image = HaemoragingImage(rgb);
    ref_image.PyramidDown();
    reference = ref_image.getEnhanced();

    Channels _channels[3] = { Channels::RED, Channels::GREEN, Channels::BLUE};
    vector<Channels> channels(_channels, _channels + 3);

    auto histSpec = HistogramNormalize(reference, channels);

    Mat dest;
    histSpec.HistogramSpecification(src, dest);

    namedWindow(sourceWindow, WINDOW_NORMAL);
    imshow(sourceWindow, dest);

    //params.cannyThresh = 30;

    //createTrackbar("Track", sourceWindow, &(params.cannyThresh), 100, thresh_callback);
    //thresh_callback(0, &(params.cannyThresh));
    //ref_image.DisplayEnhanced(true);
    waitKey(0);
    return(0);
}

<commit_msg>cleanup<commit_after>// FeatureExtractionCpp.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"

#include "HaemoragingImage.hpp"
#include "HistogramNormalize.hpp"

const char* keys =
{
    "{1||| must specify reference image name}"
    "{2||| must specify image name}"

};

Mat src, src_gray, reference;
RNG rng(12345);
string sourceWindow("Source");
string targetWindow("Target");
string transformedWindow("Transformed");

ParamBag params;
unique_ptr<HaemoragingImage> haemorage(new HaemoragingImage);

vector<vector<Point>> * FindHaemorages(unique_ptr<HaemoragingImage>&, Mat&, ParamBag&);

void thresh_callback(int, void *)
{
    unique_ptr<vector<vector<Point>>> contours(FindHaemorages(haemorage, src, params));

    Mat img;
    src.copyTo(img);
    TransformImage::DrawContours(*contours, vector<Vec4i>(), img);

    /// Draw contours
    /// Show in a window
    imshow(sourceWindow, img);
}

int main(int argc, char** argv)
{
    CommandLineParser parser(argc, argv, keys);
    string ref_file_name = parser.get<string>("1");
    string file_name = parser.get<string>("2");

    gpu::printCudaDeviceInfo(0);

    Mat rgb;
    rgb = imread(file_name, IMREAD_COLOR);

    auto hi = HaemoragingImage(rgb);
    hi.PyramidDown();
    src = hi.getEnhanced();

    rgb = imread(ref_file_name, IMREAD_COLOR);

    auto ref_image = HaemoragingImage(rgb);
    ref_image.PyramidDown();
    reference = ref_image.getEnhanced();

    Channels _channels[3] = { Channels::RED, Channels::GREEN, Channels::BLUE};
    vector<Channels> channels(_channels, _channels + 3);

    auto histSpec = HistogramNormalize(reference, channels);

    Mat dest;
    histSpec.HistogramSpecification(src, dest);

    namedWindow(sourceWindow, WINDOW_NORMAL);
    namedWindow(targetWindow, WINDOW_NORMAL);
    namedWindow(transformedWindow, WINDOW_NORMAL);

    imshow(sourceWindow, reference);
    imshow(targetWindow, src);
    imshow(transformedWindow, dest);

    //params.cannyThresh = 30;
    //createTrackbar("Track", sourceWindow, &(params.cannyThresh), 100, thresh_callback);
    //thresh_callback(0, &(params.cannyThresh));
    //ref_image.DisplayEnhanced(true);
    waitKey(0);
    return(0);
}

<|endoftext|>


<commit_before>/*
 * Check the bulldog-tyke status directory.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "bulldog.hxx"
#include "net/SocketAddress.hxx"

#include <daemon/log.h>
#include <socket/address.h>

#include <glib.h>

#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

#define WORKERS "/workers/"

static struct {
    char path[4096];

    size_t path_length;
} bulldog;

void
bulldog_init(const char *path)
{
    if (path == nullptr)
        return;

    if (strlen(path) + sizeof(WORKERS) + 16 >= sizeof(bulldog.path)) {
        daemon_log(1, "bulldog path is too long\n");
        return;
    }

    strcpy(bulldog.path, path);
    strcat(bulldog.path, WORKERS);
    bulldog.path_length = strlen(bulldog.path);
}

void
bulldog_deinit()
{
}

gcc_pure
static const char *
bulldog_node_path(SocketAddress address,
                  const char *attribute_name)
{
    assert(!address.IsNull());
    assert(attribute_name != nullptr);
    assert(*attribute_name != 0);

    if (bulldog.path[0] == 0)
        /* disabled */
        return nullptr;

    if (!socket_address_to_string(bulldog.path + bulldog.path_length,
                                  sizeof(bulldog.path) - bulldog.path_length,
                                  address.GetAddress(), address.GetSize()))
        return nullptr;

    g_strlcat(bulldog.path, "/", sizeof(bulldog.path));
    g_strlcat(bulldog.path, attribute_name, sizeof(bulldog.path));
    return bulldog.path;
}

gcc_pure
static const char *
read_first_line(const char *path, char *buffer, size_t buffer_size)
{
    assert(path != nullptr);
    assert(buffer != nullptr);
    assert(buffer_size > 0);

    int fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
    if (fd < 0)
        return nullptr;

    ssize_t nbytes = read(fd, buffer, buffer_size - 1);
    if (nbytes < 0)
        return nullptr;

    close(fd);

    /* use only the first line */
    char *p = (char *)memchr(buffer, '\n', nbytes);
    if (p == nullptr)
        p = buffer + nbytes;

    *p = 0;

    return buffer;
}

bool
bulldog_check(SocketAddress address)
{
    const char *path = bulldog_node_path(address, "status");
    if (path == nullptr)
        /* disabled */
        return true;

    char buffer[32];
    const char *value = read_first_line(path, buffer, sizeof(buffer));
    if (value == nullptr) {
        if (errno != ENOENT)
            daemon_log(2, "Failed to read %s: %s\n",
                       path, strerror(errno));
        else
            daemon_log(4, "No such bulldog-tyke status file: %s\n",
                       path);
        return true;
    }

    daemon_log(5, "bulldog: %s='%s'\n", path, value);

    return strcmp(value, "alive") == 0;
}

bool
bulldog_is_fading(SocketAddress address)
{
    const char *path = bulldog_node_path(address, "graceful");
    if (path == nullptr)
        /* disabled */
        return false;

    char buffer[32];
    const char *value = read_first_line(path, buffer, sizeof(buffer));
    if (value == nullptr)
        return false;

    daemon_log(5, "bulldog: %s='%s'\n", path, value);

    return strcmp(value, "1") == 0;
}
<commit_msg>bulldog: use class StringBuilder<commit_after>/*
 * Check the bulldog-tyke status directory.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "bulldog.hxx"
#include "net/SocketAddress.hxx"
#include "util/StringBuilder.hxx"

#include <daemon/log.h>
#include <socket/address.h>

#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

#define WORKERS "/workers/"

static struct {
    char path[4096];

    size_t path_length;
} bulldog;

void
bulldog_init(const char *path)
try {
    if (path == nullptr)
        return;

    StringBuilder<> b(bulldog.path, sizeof(bulldog.path));
    b.Append(path);
    b.Append(WORKERS);

    bulldog.path_length = strlen(bulldog.path);
} catch (StringBuilder<>::Overflow) {
    bulldog.path[0] = 0;
    daemon_log(1, "bulldog path is too long\n");
}

void
bulldog_deinit()
{
}

gcc_pure
static const char *
bulldog_node_path(SocketAddress address,
                  const char *attribute_name)
try {
    assert(!address.IsNull());
    assert(attribute_name != nullptr);
    assert(*attribute_name != 0);

    if (bulldog.path[0] == 0)
        /* disabled */
        return nullptr;

    if (!socket_address_to_string(bulldog.path + bulldog.path_length,
                                  sizeof(bulldog.path) - bulldog.path_length,
                                  address.GetAddress(), address.GetSize()))
        return nullptr;

    StringBuilder<> b(bulldog.path + strlen(bulldog.path),
                      bulldog.path + sizeof(bulldog.path));
    b.Append('/');
    b.Append(attribute_name);
    return bulldog.path;
} catch (StringBuilder<>::Overflow) {
    return nullptr;
}

gcc_pure
static const char *
read_first_line(const char *path, char *buffer, size_t buffer_size)
{
    assert(path != nullptr);
    assert(buffer != nullptr);
    assert(buffer_size > 0);

    int fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
    if (fd < 0)
        return nullptr;

    ssize_t nbytes = read(fd, buffer, buffer_size - 1);
    if (nbytes < 0)
        return nullptr;

    close(fd);

    /* use only the first line */
    char *p = (char *)memchr(buffer, '\n', nbytes);
    if (p == nullptr)
        p = buffer + nbytes;

    *p = 0;

    return buffer;
}

bool
bulldog_check(SocketAddress address)
{
    const char *path = bulldog_node_path(address, "status");
    if (path == nullptr)
        /* disabled */
        return true;

    char buffer[32];
    const char *value = read_first_line(path, buffer, sizeof(buffer));
    if (value == nullptr) {
        if (errno != ENOENT)
            daemon_log(2, "Failed to read %s: %s\n",
                       path, strerror(errno));
        else
            daemon_log(4, "No such bulldog-tyke status file: %s\n",
                       path);
        return true;
    }

    daemon_log(5, "bulldog: %s='%s'\n", path, value);

    return strcmp(value, "alive") == 0;
}

bool
bulldog_is_fading(SocketAddress address)
{
    const char *path = bulldog_node_path(address, "graceful");
    if (path == nullptr)
        /* disabled */
        return false;

    char buffer[32];
    const char *value = read_first_line(path, buffer, sizeof(buffer));
    if (value == nullptr)
        return false;

    daemon_log(5, "bulldog: %s='%s'\n", path, value);

    return strcmp(value, "1") == 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>

#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/program_options.hpp>

#include <mettle/driver/cmd_line.hpp>
#include <mettle/driver/log/child.hpp>
#include <mettle/driver/log/summary.hpp>
#include <mettle/driver/log/term.hpp>

#include "run_test_files.hpp"

namespace caliber {

namespace {
  struct all_options : mettle::generic_options, mettle::output_options,
                       mettle::child_options {
    METTLE_OPTIONAL_NS::optional<int> child_fd;
    std::vector<std::string> files;
  };
}

} // namespace caliber

int main(int argc, const char *argv[]) {
  using namespace mettle;
  namespace opts = boost::program_options;

  caliber::all_options args;
  auto generic = make_generic_options(args);
  auto output = make_output_options(args);
  auto child = make_child_options(args);

  opts::options_description hidden("Hidden options");
  hidden.add_options()
    ("child", opts::value(&args.child_fd), "run this file as a child process")
    ("file", opts::value(&args.files), "input file")
  ;
  opts::positional_options_description pos;
  pos.add("file", -1);

  opts::variables_map vm;
  std::vector<std::string> child_args;
  try {
    opts::options_description all;
    all.add(generic).add(output).add(child).add(hidden);
    auto parsed = opts::command_line_parser(argc, argv)
      .options(all).positional(pos).run();

    opts::store(parsed, vm);
    opts::notify(vm);
  } catch(const std::exception &e) {
    std::cerr << e.what() << std::endl;
    return 1;
  }

  if(args.show_help) {
    opts::options_description displayed;
    displayed.add(generic).add(output).add(child);
    std::cout << displayed << std::endl;
    return 1;
  }

  if(args.files.empty()) {
    std::cerr << "no inputs specified" << std::endl;
    return 1;
  }

  if(args.child_fd) {
    if(auto output_opt = has_option(output, vm)) {
      using namespace opts::command_line_style;
      std::cerr << output_opt->canonical_display_name(allow_long)
                << " can't be used with --child" << std::endl;
      return 1;
    }

    namespace io = boost::iostreams;
    io::stream<io::file_descriptor_sink> fds(
      *args.child_fd, io::never_close_handle
    );
    log::child logger(fds);
    caliber::run_test_files(args.files, logger, args.filters);
    return 0;
  }

  if(args.no_fork && args.show_terminal) {
    std::cerr << "--show-terminal requires forking tests" << std::endl;
    return 1;
  }

  term::enable(std::cout, args.color);
  indenting_ostream out(std::cout);

  auto progress_log = make_progress_logger(out, args);
  log::summary logger(out, progress_log.get(), args.show_time,
                      args.show_terminal);

  caliber::run_test_files(args.files, logger, args.filters);

  logger.summarize();
  return !logger.good();
}
<commit_msg>Remove unused variable<commit_after>#include <iostream>
#include <vector>

#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/program_options.hpp>

#include <mettle/driver/cmd_line.hpp>
#include <mettle/driver/log/child.hpp>
#include <mettle/driver/log/summary.hpp>
#include <mettle/driver/log/term.hpp>

#include "run_test_files.hpp"

namespace caliber {

namespace {
  struct all_options : mettle::generic_options, mettle::output_options,
                       mettle::child_options {
    METTLE_OPTIONAL_NS::optional<int> child_fd;
    std::vector<std::string> files;
  };
}

} // namespace caliber

int main(int argc, const char *argv[]) {
  using namespace mettle;
  namespace opts = boost::program_options;

  caliber::all_options args;
  auto generic = make_generic_options(args);
  auto output = make_output_options(args);
  auto child = make_child_options(args);

  opts::options_description hidden("Hidden options");
  hidden.add_options()
    ("child", opts::value(&args.child_fd), "run this file as a child process")
    ("file", opts::value(&args.files), "input file")
  ;
  opts::positional_options_description pos;
  pos.add("file", -1);

  opts::variables_map vm;
  try {
    opts::options_description all;
    all.add(generic).add(output).add(child).add(hidden);
    auto parsed = opts::command_line_parser(argc, argv)
      .options(all).positional(pos).run();

    opts::store(parsed, vm);
    opts::notify(vm);
  } catch(const std::exception &e) {
    std::cerr << e.what() << std::endl;
    return 1;
  }

  if(args.show_help) {
    opts::options_description displayed;
    displayed.add(generic).add(output).add(child);
    std::cout << displayed << std::endl;
    return 1;
  }

  if(args.files.empty()) {
    std::cerr << "no inputs specified" << std::endl;
    return 1;
  }

  if(args.child_fd) {
    if(auto output_opt = has_option(output, vm)) {
      using namespace opts::command_line_style;
      std::cerr << output_opt->canonical_display_name(allow_long)
                << " can't be used with --child" << std::endl;
      return 1;
    }

    namespace io = boost::iostreams;
    io::stream<io::file_descriptor_sink> fds(
      *args.child_fd, io::never_close_handle
    );
    log::child logger(fds);
    caliber::run_test_files(args.files, logger, args.filters);
    return 0;
  }

  if(args.no_fork && args.show_terminal) {
    std::cerr << "--show-terminal requires forking tests" << std::endl;
    return 1;
  }

  term::enable(std::cout, args.color);
  indenting_ostream out(std::cout);

  auto progress_log = make_progress_logger(out, args);
  log::summary logger(out, progress_log.get(), args.show_time,
                      args.show_terminal);

  caliber::run_test_files(args.files, logger, args.filters);

  logger.summarize();
  return !logger.good();
}
<|endoftext|>


<commit_before>#include <SFML/Network.hpp>
#include <iostream>
#include <fstream>
#include <cstring>
#define NB_BYTE_PER_PACKET 8192

enum SCommand : signed char {
	NotAuthorized = -127,
	TooBig,
	AlreadyExist,
	ServerFailure,
	UnknownIssue,

	ServerReady = 0,

	Upload = 1,
	Download,
	Ls
};

unsigned int getFileLength( std::string const& filename ) {

	std::ifstream file( filename.c_str(), std::ios::binary | std::ios::in );
	if( !file.fail() )
	{
		file.seekg( 0, std::ios::end );
		return file.tellg();
	}
	return 0;
}

bool startUpload( std::ifstream& infile, unsigned int& file_size, sf::TcpSocket& server ) {		//Starts an upload by opening the file and telling the server about its name and size
													//Also retrieves server's answer (upload accepted or denied)
	std::string filename;

	std::cout << "File name : ";
	std::cin >> filename;

	file_size = getFileLength( filename ) ;
	infile.open(filename.c_str(), std::ios::binary | std::ios::in);

	if( file_size == 0 || infile.fail() ) {
		std::cout << "There was a problem reading the file" << std::endl;
		return false;
	}

	sf::Packet packet;

	packet << Upload << filename << file_size << NB_BYTE_PER_PACKET;
	server.send(packet);
	packet.clear();

	int server_state;

	server.receive(packet);
	if( packet.getDataSize() > sizeof( int ) || !(packet >> server_state) ){
		std::cout << "There was an error retrieving server state" << std::endl;
		return false;
	}

	switch( static_cast<char>(server_state) ){
		case ServerReady :
			return true;

		default:
			std::cout << "The server is busy" << std::endl;
			return false;
	}
	std::cout << "Unknown error" << std::endl;
	return false;
}

bool sconnect( sf::TcpSocket& socket ) {

	unsigned short remote_port;
	std::string remote_address;

	std::cout << "Remote address : ";
	std::cin >> remote_address;
	std::cout << "Remote port : ";
	std::cin >> remote_port;
	std::cout << "Connecting to the remote @ " << remote_address << ":" << remote_port << std::endl;

	if( socket.connect( remote_address, remote_port ) != sf::Socket::Done ){
		std::cout << "Connection wasn't successful" << std::endl;
		return false;
	}

	std::cout << "Successfully connected" << std::endl;
	return true;
}

bool sendData( sf::TcpSocket& server ){

	std::ifstream input_file;
	unsigned int file_size;

	if( !startUpload( input_file, file_size, server) ){
		std::cout << "Could not send the file" << std::endl;			//Preparing to upload
		return false;
	}

	unsigned int loop_number=file_size/NB_BYTE_PER_PACKET;
	char input_data_array[NB_BYTE_PER_PACKET];
	sf::Packet spacket;
	spacket.clear();
	unsigned char percentage_count(0);

	std::cout << "Upload is starting" << std::endl;
	for( unsigned int i(0) ; i<loop_number ; ++i ){					//Reading an sending the file

		input_file.read( input_data_array, NB_BYTE_PER_PACKET);
		for( unsigned int j(0) ; j<NB_BYTE_PER_PACKET ; ++j)
			spacket << static_cast<sf::Int8>(input_data_array[j]);

		if( server.send(spacket) == sf::Socket::Disconnected ){

			std::cout << "Lost connection with server !" << std::endl;
			return false;
		}
		spacket.clear();

		server.receive(spacket);						//Sync with server
		spacket.clear();

		if( static_cast<unsigned char>(100*i/loop_number) > percentage_count ){
			percentage_count = static_cast<unsigned char>(100*i/loop_number);
			std::cout << "[" << static_cast<short>(percentage_count) << "%] - File being transfered" << std::endl;	//Displaying upload percentage
		}

	}

	file_size -= loop_number * NB_BYTE_PER_PACKET;
	if( file_size > 0){								//There is some more to be transferred

		char* file_tail = new char[file_size];
		input_file.read( file_tail, file_size);
		for( unsigned int j(0) ; j< file_size ; ++j)
			spacket << file_tail[j];

		if( server.send(spacket) == sf::Socket::Disconnected ){
			std::cout << "Too bad. You almost done it but you were disconnected by server :(" << std::endl;
			delete file_tail;
			return false;
		}

		delete file_tail;

	}

	std::cout << "Transfer terminated successfully" << std::endl;

	return true;
}

bool retrieveData( sf::TcpSocket& server ) {
	return false;
}

int main(int argc, char* argv[]) {

	sf::TcpSocket socket;
	std::string user_input;

	if( !sconnect( socket ) )
			return 1;

	do{
		std::cout << "Do you wish to upload a file ? [y/n/q] ";
		std::cin >> user_input;

		if( user_input == "" || user_input == "y" || user_input == "Y" ) {

			if( !sendData( socket ) ){
				std::cout << "Failed to upload data to server" << std::endl;
			}

		}

		if( user_input == "q"){
			std::cout << "Closing connection and exiting" << std::endl;
			socket.disconnect();
			return 0;
		}

		std::cout << "Do you wish to download a file ? [y/n/q] ";
		std::cin >> user_input;

		if( user_input == "" || user_input == "y" || user_input == "Y" ) {

			if( !retrieveData( socket ) ){
				std::cout << "Failed to retrieve data from server" << std::endl;
			}

		}

		if( user_input == "q" ){
			std::cout << "Closing Connection and exiting" << std::endl;
			socket.disconnect();
			return 0;
		}

	}while(true);
}
<commit_msg>Adding server answer interpretation<commit_after>#include <SFML/Network.hpp>
#include <iostream>
#include <fstream>
#include <cstring>
#define NB_BYTE_PER_PACKET 8192

enum SCommand : signed char {
	NotAuthorized = -127,
	TooBig,
	AlreadyExist,
	ServerFailure,
	UnknownIssue,

	ServerReady = 0,

	Upload = 1,
	Download,
	Ls
};

bool interpretServerAns( signed char sanswer){								//Sends message to console telling the problem // success

	std::cout << "Server :";

	switch( sanswer ){

	case NotAuthorized :
		std::cout << "action unauthorized" << std::endl;
		return false;

	case TooBig:
		std::cout << "file too heavy" << std::endl;
		return false;

	case AlreadyExist:
		std::cout << "this file already exists" << std::endl;
		return false;

	case ServerFailure:
		std::cout << "an error has occured" << std::endl;
		return false;

	case UnknownIssue:
		std::cout << "dafuq has happened ?!?" << std::endl;
		return false;

	case ServerReady:
		std::cout << "ready" << std::endl;
		return true;

	default:
		std::cout << "unexpected answer from server" << std::endl;
		return false;
	}
}

unsigned int getFileLength( std::string const& filename ) {						//Retrieving file size in bytes

	std::ifstream file( filename.c_str(), std::ios::binary | std::ios::in );
	if( !file.fail() )
	{
		file.seekg( 0, std::ios::end );
		return file.tellg();
	}
	return 0;
}

bool startUpload( std::ifstream& infile, unsigned int& file_size, sf::TcpSocket& server ) {		//Starts an upload by opening the file and telling the server about its name and size
													//Also retrieves server's answer (upload accepted or denied)
	std::string filename;

	std::cout << "File name : ";
	std::cin >> filename;

	file_size = getFileLength( filename ) ;
	infile.open(filename.c_str(), std::ios::binary | std::ios::in);

	if( file_size == 0 || infile.fail() ) {
		std::cout << "There was a problem reading the file" << std::endl;
		return false;
	}

	sf::Packet packet;

	packet << Upload << filename << file_size << NB_BYTE_PER_PACKET;
	server.send(packet);
	packet.clear();

	int server_state;

	server.receive(packet);
	if( packet.getDataSize() > sizeof( int ) || !(packet >> server_state) ){
		std::cout << "There was an error retrieving server state" << std::endl;
		return false;
	}
	return interpretServerAns( static_cast<char>(server_state) );
}

bool sconnect( sf::TcpSocket& socket ) {								//Connect the client to the server

	unsigned short remote_port;
	std::string remote_address;

	std::cout << "Remote address : ";
	std::cin >> remote_address;
	std::cout << "Remote port : ";
	std::cin >> remote_port;
	std::cout << "Connecting to the remote @ " << remote_address << ":" << remote_port << std::endl;

	if( socket.connect( remote_address, remote_port ) != sf::Socket::Done ){
		std::cout << "Connection wasn't successful" << std::endl;
		return false;
	}

	std::cout << "Successfully connected" << std::endl;
	return true;
}

bool sendData( sf::TcpSocket& server ){									// Sends a file to the server

	std::ifstream input_file;
	unsigned int file_size;

	if( !startUpload( input_file, file_size, server) ){
		std::cout << "Could not send the file" << std::endl;			//Preparing to upload
		return false;
	}

	unsigned int loop_number=file_size/NB_BYTE_PER_PACKET;
	char input_data_array[NB_BYTE_PER_PACKET];
	sf::Packet spacket;
	spacket.clear();
	unsigned char percentage_count(0);

	std::cout << "Upload is starting" << std::endl;
	for( unsigned int i(0) ; i<loop_number ; ++i ){					//Reading an sending the file

		input_file.read( input_data_array, NB_BYTE_PER_PACKET);
		for( unsigned int j(0) ; j<NB_BYTE_PER_PACKET ; ++j)
			spacket << static_cast<sf::Int8>(input_data_array[j]);

		if( server.send(spacket) == sf::Socket::Disconnected ){

			std::cout << "Lost connection with server !" << std::endl;
			return false;
		}
		spacket.clear();

		server.receive(spacket);						//Sync with server
		spacket.clear();

		if( static_cast<unsigned char>(100*i/loop_number) > percentage_count ){
			percentage_count = static_cast<unsigned char>(100*i/loop_number);
			std::cout << "[" << static_cast<short>(percentage_count) << "%] - File being transfered" << std::endl;	//Displaying upload percentage
		}

	}

	file_size -= loop_number * NB_BYTE_PER_PACKET;
	if( file_size > 0){								//There is some more to be transferred

		char* file_tail = new char[file_size];
		input_file.read( file_tail, file_size);
		for( unsigned int j(0) ; j< file_size ; ++j)
			spacket << file_tail[j];

		if( server.send(spacket) == sf::Socket::Disconnected ){
			std::cout << "Too bad. You almost done it but you were disconnected by server :(" << std::endl;
			delete file_tail;
			return false;
		}

		delete file_tail;

	}

	std::cout << "Transfer terminated successfully" << std::endl;

	return true;
}

bool retrieveData( sf::TcpSocket& server ) {								//Retrieves a file from the server
	return false;
}

int main(int argc, char* argv[]) {

	sf::TcpSocket socket;
	std::string user_input;

	if( !sconnect( socket ) )
			return 1;

	do{
		std::cout << "Do you wish to upload a file ? [y/n/q] ";
		std::cin >> user_input;

		if( user_input == "" || user_input == "y" || user_input == "Y" ) {

			if( !sendData( socket ) ){
				std::cout << "Failed to upload data to server" << std::endl;
			}

		}

		if( user_input == "q"){
			std::cout << "Closing connection and exiting" << std::endl;
			socket.disconnect();
			return 0;
		}

		std::cout << "Do you wish to download a file ? [y/n/q] ";
		std::cin >> user_input;

		if( user_input == "" || user_input == "y" || user_input == "Y" ) {

			if( !retrieveData( socket ) ){
				std::cout << "Failed to retrieve data from server" << std::endl;
			}

		}

		if( user_input == "q" ){
			std::cout << "Closing Connection and exiting" << std::endl;
			socket.disconnect();
			return 0;
		}

	}while(true);
}
<|endoftext|>


<commit_before>/*
    Implementation of the Compiler class.

*/

#include <cctype>       //character comparison functions
#include <stdexcept>
#include <assert.h>
#include "compiler.hh"

namespace ds_compiler {

const size_t Compiler::NUM_REGISTERS = 8;
const char Compiler::ERR_CHAR = '\0';
const std::unordered_set<char> Compiler::ADD_OPS({'+', '-'});
const std::unordered_set<char> Compiler::MULT_OPS({'*', '/'});

//constructors
Compiler::Compiler (std::ostream& output)
    : m_input_stream (std::ios::in|std::ios::out), m_output_stream(output)
{

}

void Compiler::compile_intermediate (const std::string input_line) {

    //clear contents and error flags on m_input_stream
    m_input_stream.str("");
    m_input_stream.clear();

    m_input_stream << input_line;

    try {
        start_symbol();
    } catch (std::exception &ex) {
        std::cerr << ex.what() << '\n';
        throw std::runtime_error("Compilation failed.\n");
    }
}

void Compiler::compile_full (const std::vector<std::string> source, const std::string class_name) {

    compile_start(class_name);
    for (auto line : source) {
        compile_intermediate(line);
    }
    compile_end();

}

void Compiler::compile_start (const std::string class_name) const {
    add_includes();

    //begin class declaration, qualify everything as public
    emit_line("class "+ class_name + "{");
    emit_line("public:");

    define_member_variables();
    define_constructor(class_name);
    define_cpu_pop();
    define_getters();
    define_is_stack_empty();

    emit_line("void run() {");  //begin definition of run()
}

void Compiler::compile_end () const {
    //TODO - should I assert that cpu_stack is empty?

    emit_line("}");     //end definition of run()
    define_dump();
    emit_line("};");    //close class definition
}

void Compiler::add_includes() const {
    emit_line("#include <stack>");
    emit_line("#include <vector>");
    emit_line("#include <iostream>");
    emit_line("#include <string>");
    emit_line("#include <unordered_map>");
}

void Compiler::define_member_variables() const {
    emit_line("std::stack<int> cpu_stack;");
    emit_line("std::vector<int> cpu_registers;");
    emit_line("std::unordered_map<char, int> cpu_variables;");
}

void Compiler::define_constructor(const std::string class_name) const {
    emit_line(class_name + "() ");
    emit_line(": cpu_stack()");
    emit_line(", cpu_registers(" + std::to_string(NUM_REGISTERS) + ", 0)");
    emit_line(", cpu_variables()");
    emit_line("{}");
}

//emit definition of a function for easier stack handling
void Compiler::define_cpu_pop() const {
    emit_line("int cpu_pop() {");
    emit_line("int val = cpu_stack.top();");
    emit_line("cpu_stack.pop();");
    emit_line("return val; }");
}

void Compiler::define_getters() const {
    emit_line("int get_register(int index) {");
    emit_line("return cpu_registers.at(index);}");

    emit_line("int get_variable(char var_name) {");
    emit_line("return cpu_variables.at(var_name);}");

    //no getter for stack; stack should always be empty
}

void Compiler::define_is_stack_empty() const {
    emit_line("bool is_stack_empty() {");
    emit_line("return cpu_stack.empty();}");
}

void Compiler::define_dump() const {
    //TODO - are these dumps necessary?

    emit_line("void dump () {");

    emit_line("std::cout << \"Register contents\\n\";");
    emit_line("for (int i = 0; i < " + std::to_string(NUM_REGISTERS) + "; ++i)");
    emit_line("std::cout << std::string(\"Register \") << i << \": \" << cpu_registers.at(i) << '\\n';");

    emit_line("std::cout << \"Stack contents (top to bottom)\\n\";");
    emit_line("while (!cpu_stack.empty()) {");
    emit_line("std::cout << cpu_stack.top() << '\\n';");
    emit_line("cpu_stack.pop();}");

    emit_line("std::cout << \"Variable contents\\n\";");
    emit_line("for (auto i = cpu_variables.begin(); i != cpu_variables.end(); ++i)");
    emit_line("std::cout << \"cpu_variables[\" << i->first << \"] = \" << i->second << '\\n';");

    emit_line("}");
}

void Compiler::start_symbol () {

}

//cradle methods

void Compiler::report_error(const std::string err) const {

    m_output_stream << '\n';
    m_output_stream << "Error: " << err << '\n';

}

void Compiler::abort(const std::string err) const {

    report_error(err);
    throw std::runtime_error("Compilation failed.\n");
}

void Compiler::expected(const std::string expect) const {

    abort(expect + " expected.\n");
}

//overload to handle single characters;
//prevents having to construct a string whenever calling expected()
void Compiler::expected(const char c) const {
    expected(std::string(1, c));
}

//checks if next character matches; if so, consume that character
void Compiler::match(const char c) {

    if (m_input_stream.peek() == c) {
        m_input_stream.get();
    } else {
        expected(c);
    }
}

// gets a valid identifier from input stream
char Compiler::get_name () {
    if (!std::isalpha(m_input_stream.peek())) {
        expected("Name");
        return ERR_CHAR;
    } else {
        return std::toupper(m_input_stream.get());
    }

}

//gets a number
char Compiler::get_num () {
    if (!std::isdigit(m_input_stream.peek())) {
        expected("Integer");
        return ERR_CHAR;
    } else {
        return m_input_stream.get();
    }
}

//output a string
void Compiler::emit (std::string s) const {
    m_output_stream << s;
}

//output a string with newline
void Compiler::emit_line (std::string s) const {
    emit(s);
    emit("\n");
}

bool Compiler::is_in(const char elem, const std::unordered_set<char> us) {
    return us.find(elem) != us.end();
}

} //end namespace<commit_msg>Remove TODO note in define_dump(); dump functions are useful for debugging<commit_after>/*
    Implementation of the Compiler class.

*/

#include <cctype>       //character comparison functions
#include <stdexcept>
#include <assert.h>
#include "compiler.hh"

namespace ds_compiler {

const size_t Compiler::NUM_REGISTERS = 8;
const char Compiler::ERR_CHAR = '\0';
const std::unordered_set<char> Compiler::ADD_OPS({'+', '-'});
const std::unordered_set<char> Compiler::MULT_OPS({'*', '/'});

//constructors
Compiler::Compiler (std::ostream& output)
    : m_input_stream (std::ios::in|std::ios::out), m_output_stream(output)
{

}

void Compiler::compile_intermediate (const std::string input_line) {

    //clear contents and error flags on m_input_stream
    m_input_stream.str("");
    m_input_stream.clear();

    m_input_stream << input_line;

    try {
        start_symbol();
    } catch (std::exception &ex) {
        std::cerr << ex.what() << '\n';
        throw std::runtime_error("Compilation failed.\n");
    }
}

void Compiler::compile_full (const std::vector<std::string> source, const std::string class_name) {

    compile_start(class_name);
    for (auto line : source) {
        compile_intermediate(line);
    }
    compile_end();

}

void Compiler::compile_start (const std::string class_name) const {
    add_includes();

    //begin class declaration, qualify everything as public
    emit_line("class "+ class_name + "{");
    emit_line("public:");

    define_member_variables();
    define_constructor(class_name);
    define_cpu_pop();
    define_getters();
    define_is_stack_empty();

    emit_line("void run() {");  //begin definition of run()
}

void Compiler::compile_end () const {
    //TODO - should I assert that cpu_stack is empty?

    emit_line("}");     //end definition of run()
    define_dump();
    emit_line("};");    //close class definition
}

void Compiler::add_includes() const {
    emit_line("#include <stack>");
    emit_line("#include <vector>");
    emit_line("#include <iostream>");
    emit_line("#include <string>");
    emit_line("#include <unordered_map>");
}

void Compiler::define_member_variables() const {
    emit_line("std::stack<int> cpu_stack;");
    emit_line("std::vector<int> cpu_registers;");
    emit_line("std::unordered_map<char, int> cpu_variables;");
}

void Compiler::define_constructor(const std::string class_name) const {
    emit_line(class_name + "() ");
    emit_line(": cpu_stack()");
    emit_line(", cpu_registers(" + std::to_string(NUM_REGISTERS) + ", 0)");
    emit_line(", cpu_variables()");
    emit_line("{}");
}

//emit definition of a function for easier stack handling
void Compiler::define_cpu_pop() const {
    emit_line("int cpu_pop() {");
    emit_line("int val = cpu_stack.top();");
    emit_line("cpu_stack.pop();");
    emit_line("return val; }");
}

void Compiler::define_getters() const {
    emit_line("int get_register(int index) {");
    emit_line("return cpu_registers.at(index);}");

    emit_line("int get_variable(char var_name) {");
    emit_line("return cpu_variables.at(var_name);}");

    //no getter for stack; stack should always be empty
}

void Compiler::define_is_stack_empty() const {
    emit_line("bool is_stack_empty() {");
    emit_line("return cpu_stack.empty();}");
}

void Compiler::define_dump() const {
    emit_line("void dump () {");

    emit_line("std::cout << \"Register contents\\n\";");
    emit_line("for (int i = 0; i < " + std::to_string(NUM_REGISTERS) + "; ++i)");
    emit_line("std::cout << std::string(\"Register \") << i << \": \" << cpu_registers.at(i) << '\\n';");

    emit_line("std::cout << \"Stack contents (top to bottom)\\n\";");
    emit_line("while (!cpu_stack.empty()) {");
    emit_line("std::cout << cpu_stack.top() << '\\n';");
    emit_line("cpu_stack.pop();}");

    emit_line("std::cout << \"Variable contents\\n\";");
    emit_line("for (auto i = cpu_variables.begin(); i != cpu_variables.end(); ++i)");
    emit_line("std::cout << \"cpu_variables[\" << i->first << \"] = \" << i->second << '\\n';");

    emit_line("}");
}

void Compiler::start_symbol () {

}

//cradle methods

void Compiler::report_error(const std::string err) const {

    m_output_stream << '\n';
    m_output_stream << "Error: " << err << '\n';

}

void Compiler::abort(const std::string err) const {

    report_error(err);
    throw std::runtime_error("Compilation failed.\n");
}

void Compiler::expected(const std::string expect) const {

    abort(expect + " expected.\n");
}

//overload to handle single characters;
//prevents having to construct a string whenever calling expected()
void Compiler::expected(const char c) const {
    expected(std::string(1, c));
}

//checks if next character matches; if so, consume that character
void Compiler::match(const char c) {

    if (m_input_stream.peek() == c) {
        m_input_stream.get();
    } else {
        expected(c);
    }
}

// gets a valid identifier from input stream
char Compiler::get_name () {
    if (!std::isalpha(m_input_stream.peek())) {
        expected("Name");
        return ERR_CHAR;
    } else {
        return std::toupper(m_input_stream.get());
    }

}

//gets a number
char Compiler::get_num () {
    if (!std::isdigit(m_input_stream.peek())) {
        expected("Integer");
        return ERR_CHAR;
    } else {
        return m_input_stream.get();
    }
}

//output a string
void Compiler::emit (std::string s) const {
    m_output_stream << s;
}

//output a string with newline
void Compiler::emit_line (std::string s) const {
    emit(s);
    emit("\n");
}

bool Compiler::is_in(const char elem, const std::unordered_set<char> us) {
    return us.find(elem) != us.end();
}

} //end namespace<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef HEADER_GUARD_CLASS_CONTENTS_H
#define HEADER_GUARD_CLASS_CONTENTS_H

#include <memory>
#include <mutex>
#include <string>
#include <type_traits>
#include <vector>
#include <cstddef>

#include "change.hh"
#include "mode.hh"

namespace vick {

/*!
 * \file contents.hh
 *
 * \brief Defines the class contents, which contains all the
 * information about the buffer.
 */

/*!
 * \brief Define `move_t` so that code can be more descriptive and
 * can change it from one place.
 */
using move_t = std::size_t;

/*!
 * \brief Define `move_ts` to be a signed version of `move_t`
 *
 * \see move_t
 */
using move_ts = typename std::make_signed<move_t>::type;

/*!
 * \brief Define `move_tu` to be an unsigned version of `move_t`
 *
 * \see move_t
 */
using move_tu = typename std::make_unsigned<move_t>::type;

/*!
 * \class contents contents.hh "contents.hh"
 *
 * \brief Defines all the information about the buffer.
 */
class contents {
public:
    std::map<char, std::function<boost::optional<std::shared_ptr<
                       change> >(contents &, boost::optional<int>)> >
        normal_map /*!< \brief The contents buffer (file) specfic
                    * normal mode character mappings. */,
        insert_map /*!< \brief The contents buffer (file) specfic
                    * insert mode character mappings. */;

    /*!
     * \brief The type of file the buffer is.
     *
     * Default mode is fundamental;
     */
    mode* buffer_mode;

    /*!
     * \brief The literal contents of the buffer
     */
    std::vector<std::string> cont;

    /*!
     * \brief The list of changes to the buffer.  This is public so
     * that treed-undo (a la Emacs) can be implemented the same as
     * linear is.
     */
    std::vector<std::shared_ptr<change> > changes;

    /*!
     * \brief For use to lock access to `cont` when it is being
     * updated in one thread and displayed in another.
     */
    std::mutex print_mutex;

    /*!
     * \brief The current change the buffer is in
     */
    size_t changes_i = 0;

    move_t
        y = 0 /*!< \brief The y (vertical) position in the buffer. */,
        x = 0 /*!< \brief The x (horizontal) position in the buffer. */,
        desired_x = 0 /*!< \brief This will be set to the x value we
                       * want when you move to a different line but
                       * the line you move to is too short
                       *
                       * \see waiting_for_desired */,
        y_offset = 0 /*!< \brief The number of lines that are not
                      * displayed (off the top) */,
        max_y /*!< \brief The vertical height the buffer has been
               * allocated on the screen - [0, max_y) */,
        max_x /*!< \brief The horizontal width the buffer has been
               * allocated on the screen - [0, max_x) */;

    bool waiting_for_desired = false /*!< \brief Controls if the x
                                      * value will try to adjust to
                                      * desired_x
                                      *
                                      * \see desired_x */,
         refresh = true /*!< \brief Controls if the screen should
                         * refresh everytime something happens */,
         delete_mode = false /*!< \brief Controls if the private mode
                              * pointer variable will be deleted in the
                              * destructor */,
         is_inserting = false /*!< \brief Will be true if the user is
                               * currently inserting text into the
                               * buffer.  This will cause the
                               * print_contents method to not have
                               * undefined behavior if x is too
                               * large. */,
         windows_file_endings = false /*!< \brief If true, then when
                                       * saving, appends the byte 13 to
                                       * each line.  We use this to
                                       * maintain plugin consistency
                                       * across platforms.  (The buffer
                                       * is in no way affected by this
                                       * variable)
                                       */;

    explicit contents(
        std::vector<std::string> cont = std::vector<std::string>(),
        mode* buffer_mode = &fundamental_mode);
    explicit contents(mode* buffer_mode);
    contents(move_t y, move_t x,
             mode* buffer_mode = &fundamental_mode);

    /*!
     * \brief Constructs this contents object as a copy of the other
     * contents object.
     *
     * This forces the private mode member to make a deep copy.
     */
    contents(const contents&);
    contents(contents&&) = default;

    /*!
     * \brief If delete_mode is true, then it will delete the private
     * mode pointer member.
     *
     * \see delete_mode
     */
    ~contents();

    /*!
     * \brief Constructs this contents object as a copy of the other
     * contents object.
     *
     * This forces the private mode member to make a deep copy.
     */
    contents& operator=(const contents&);
    contents& operator=(contents&&);

    /*!
     * \brief Calls the private mode member's `operator()` with
     * `*this` and the character given to this function.
     */
    bool operator()(char);

    /*!
     * \brief Updates the values of ``max_y`` and ``max_x``
     *
     * \see max_y
     * \see max_x
     */
    void refreshmaxyx();

    /*!
     * \brief Calls ``cont.push_back(str)``
     *
     * \see cont
     *
     * \param str The string to be put at the end of the vector of
     * strings, `cont`
     */
    void push_back(const std::string& str);
};
}

#endif
<commit_msg>Add a `file_name` field to `contents`<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef HEADER_GUARD_CLASS_CONTENTS_H
#define HEADER_GUARD_CLASS_CONTENTS_H

#include <memory>
#include <mutex>
#include <string>
#include <type_traits>
#include <vector>
#include <cstddef>

#include "change.hh"
#include "mode.hh"

namespace vick {

/*!
 * \file contents.hh
 *
 * \brief Defines the class contents, which contains all the
 * information about the buffer.
 */

/*!
 * \brief Define `move_t` so that code can be more descriptive and
 * can change it from one place.
 */
using move_t = std::size_t;

/*!
 * \brief Define `move_ts` to be a signed version of `move_t`
 *
 * \see move_t
 */
using move_ts = typename std::make_signed<move_t>::type;

/*!
 * \brief Define `move_tu` to be an unsigned version of `move_t`
 *
 * \see move_t
 */
using move_tu = typename std::make_unsigned<move_t>::type;

/*!
 * \class contents contents.hh "contents.hh"
 *
 * \brief Defines all the information about the buffer.
 */
class contents {
public:
    std::map<char, std::function<boost::optional<std::shared_ptr<
                       change> >(contents &, boost::optional<int>)> >
        normal_map /*!< \brief The contents buffer (file) specfic
                    * normal mode character mappings. */,
        insert_map /*!< \brief The contents buffer (file) specfic
                    * insert mode character mappings. */;

    /*!
     * \brief The type of file the buffer is.
     *
     * Default mode is fundamental;
     */
    mode* buffer_mode;

    /*!
     * \brief The literal contents of the buffer
     */
    std::vector<std::string> cont;

    /*!
     * \brief The list of changes to the buffer.  This is public so
     * that treed-undo (a la Emacs) can be implemented the same as
     * linear is.
     */
    std::vector<std::shared_ptr<change> > changes;

    /*!
     * \brief For use to lock access to `cont` when it is being
     * updated in one thread and displayed in another.
     */
    std::mutex print_mutex;

    /*!
     * \brief The file that the contents was read from.
     */
    std::string file_name;

    /*!
     * \brief The current change the buffer is in
     */
    size_t changes_i = 0;

    move_t
        y = 0 /*!< \brief The y (vertical) position in the buffer. */,
        x = 0 /*!< \brief The x (horizontal) position in the buffer. */,
        desired_x = 0 /*!< \brief This will be set to the x value we
                       * want when you move to a different line but
                       * the line you move to is too short
                       *
                       * \see waiting_for_desired */,
        y_offset = 0 /*!< \brief The number of lines that are not
                      * displayed (off the top) */,
        max_y /*!< \brief The vertical height the buffer has been
               * allocated on the screen - [0, max_y) */,
        max_x /*!< \brief The horizontal width the buffer has been
               * allocated on the screen - [0, max_x) */;

    bool waiting_for_desired = false /*!< \brief Controls if the x
                                      * value will try to adjust to
                                      * desired_x
                                      *
                                      * \see desired_x */,
         refresh = true /*!< \brief Controls if the screen should
                         * refresh everytime something happens */,
         delete_mode = false /*!< \brief Controls if the private mode
                              * pointer variable will be deleted in the
                              * destructor */,
         is_inserting = false /*!< \brief Will be true if the user is
                               * currently inserting text into the
                               * buffer.  This will cause the
                               * print_contents method to not have
                               * undefined behavior if x is too
                               * large. */,
         windows_file_endings = false /*!< \brief If true, then when
                                       * saving, appends the byte 13 to
                                       * each line.  We use this to
                                       * maintain plugin consistency
                                       * across platforms.  (The buffer
                                       * is in no way affected by this
                                       * variable)
                                       */;

    explicit contents(
        std::vector<std::string> cont = std::vector<std::string>(),
        mode* buffer_mode = &fundamental_mode);
    explicit contents(mode* buffer_mode);
    contents(move_t y, move_t x,
             mode* buffer_mode = &fundamental_mode);

    /*!
     * \brief Constructs this contents object as a copy of the other
     * contents object.
     *
     * This forces the private mode member to make a deep copy.
     */
    contents(const contents&);
    contents(contents&&) = default;

    /*!
     * \brief If delete_mode is true, then it will delete the private
     * mode pointer member.
     *
     * \see delete_mode
     */
    ~contents();

    /*!
     * \brief Constructs this contents object as a copy of the other
     * contents object.
     *
     * This forces the private mode member to make a deep copy.
     */
    contents& operator=(const contents&);
    contents& operator=(contents&&);

    /*!
     * \brief Calls the private mode member's `operator()` with
     * `*this` and the character given to this function.
     */
    bool operator()(char);

    /*!
     * \brief Updates the values of ``max_y`` and ``max_x``
     *
     * \see max_y
     * \see max_x
     */
    void refreshmaxyx();

    /*!
     * \brief Calls ``cont.push_back(str)``
     *
     * \see cont
     *
     * \param str The string to be put at the end of the vector of
     * strings, `cont`
     */
    void push_back(const std::string& str);
};
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Luke San Antonio
 * All rights reserved.
 *
 * This file provides the implementation for the engine's C interface,
 * specifically tailored for LuaJIT's FFI facilities.
 *
 * Scene stuff
 */

#include "redcrane.hpp"

#define CHECK_ID(id) \
        REDC_ASSERT_MSG(id != 0, "No more room for any more objects"); \
        if(id == 0) return id;

using namespace redc;

extern "C"
{
  // See scene.lua
  void *redc_make_scene(void *eng)
  {
    auto engine= (Engine*) eng;

    auto sc = new Peer_Ptr<Scene>(new Scene);
    sc->get()->engine = engine;

    engine->scenes.push_back(sc->peer());
    return sc;
  }
  void redc_unmake_scene(void *scene)
  {
    auto sc = (Peer_Ptr<Scene> *) scene;
    delete sc;
  }

  uint16_t redc_scene_add_camera(void *sc, const char *tp)
  {
    // For the moment, this is the only kind of camera we support

    std::function <gfx::Camera(gfx::IDriver const&)> cam_func;

    if(strcmp(tp, "fps") == 0)
    {
      // Ayy we got a camera
      cam_func = redc::gfx::make_fps_camera;
    }
    else
    {
      log_w("Invalid camera type '%' so making an fps camera", tp);
    }

    // The first camera will be set as active automatically by Active_Map from
    // id_map.hpp.
    auto scene = lock_resource<redc::Scene>(sc);

    auto id = scene->index_gen.get();
    CHECK_ID(id);

    auto &obj = scene->objs[id - 1];
    obj.obj = Cam_Object{cam_func(*scene->engine->driver)};

    // We can be sure at this point the id is non-zero (because of CHECK_ID).

    // If this is our first camera
    if(!scene->active_camera) scene->active_camera = id;

    // Return the id
    return id;
  }

  uint16_t redc_scene_get_active_camera(void *sc)
  {
    auto scene = lock_resource<redc::Scene>(sc);

    // This will be zero when there isn't an active camera.
    return scene->active_camera;
  }
  void redc_scene_activate_camera(void *sc, uint16_t cam)
  {
    if(!cam)
    {
      log_w("Cannot make an invalid object the active camera, "
                    "ignoring request");
      return;
    }

    // We have a camera
    auto scene = lock_resource<redc::Scene>(sc);

    if(scene->objs[cam-1].obj.which() == Object::Cam)
    {
      scene->active_camera = cam;
    }
    else
    {
      log_w("Cannot make non-camera the active camera, ignoring request");
    }
  }

  uint16_t redc_scene_attach(void *sc, void *ms, uint16_t parent)
  {
    auto scene = lock_resource<redc::Scene>(sc);

    auto id = scene->index_gen.get();
    CHECK_ID(id);

    auto mesh = lock_resource<gfx::Mesh_Chunk>(ms);
    scene->objs[id - 1].obj = Mesh_Object{std::move(mesh), glm::mat4(1.0f)};

    if(parent)
    {
      scene->objs[id - 1].parent = &scene->objs[parent-1];
    }

    return id;
  }

  bool redc_running(void *eng)
  {
    return ((redc::Engine *) eng)->running;
  }

  void redc_scene_step(void *sc)
  {
    auto scene = lock_resource<redc::Scene>(sc);

    Cam_Object* active_camera;
    if(scene->active_camera)
    {
      active_camera =
              &boost::get<Cam_Object>(scene->objs[scene->active_camera-1].obj);
    }

    SDL_Event event;
    while(SDL_PollEvent(&event))
    {
      // If we already used the event, bail.
      //if(collect_input(input, event, input_cfg)) continue;

      // Otherwise
      switch(event.type)
      {
        case SDL_QUIT:
          scene->engine->running = false;
          break;
        case SDL_MOUSEMOTION:
          if(active_camera)
          {
            active_camera->control.apply_delta_yaw(active_camera->cam,
                    event.motion.xrel / 1000.0f);

            active_camera->control.apply_delta_pitch(active_camera->cam,
                    event.motion.yrel / 1000.0f);
          }
          break;
        case SDL_KEYDOWN:
          //if(event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) running = false;
          break;
        default:
          break;
      }
    }
  }

  void redc_scene_render(void *sc)
  {
    auto scene = lock_resource<redc::Scene>(sc);

#ifdef REDC_LOG_FRAMES
    ++scene->frame_count;
    if(scene->frame_timer.has_been(std::chrono::seconds(1)))
    {
      log_d("fps: %", scene->frame_count);
      scene->frame_count = 0;
      scene->frame_timer.reset();
    }
#endif

    // Make sure we have an active camera
    if(!scene->active_camera)
    {
      log_e("No active camera; cannot render scene");
      return;
    }

    // Load the active camera
    auto active_camera =
            boost::get<Cam_Object>(scene->objs[scene->active_camera - 1].obj);
    gfx::use_camera(*scene->engine->driver, active_camera.cam);

    // Clear the screen
    scene->engine->driver->clear();

    // Find active shader.
    auto active_shader = scene->engine->driver->active_shader();

    // i is the loop counter, id is our current id.
    // Loop however many times as we have ids.
    int cur_id = 0;
    for(int i = 0; i < scene->index_gen.reserved(); ++i)
    {
      // Check to make sure the current id hasn't been removed.
      // Remember to add one

      // Increment the current id until we find one that is valid. Technically
      // we could just check if it hasn't been removed because we shouldn't
      // get far enough to exceed count but whatever this makes more semantic
      // sense. Then again if we exceed count_ we could enter a loop where we
      // exit only at overflow.

      // Put the increment in the expression because we always want to be
      // incrementing the counter, otherwise we risk rendering the same object
      // many times
      while(!scene->index_gen.is_valid((++cur_id)));

      // If the above scenario becomes an issue, replace !is_valid with
      // is_removed and check if it's valid here. If it hasn't been removed
      // but isn't valid we went to far, so exit early. I'm not doing that here
      // because I don't think it will be an issue.

      auto &obj = scene->objs[cur_id-1];
      if(obj.obj.which() == Object::Cam)
      {
        // Debugging enabled? Render cameras in some way?
      }
      else if(obj.obj.which() == Object::Mesh)
      {
        auto mesh_obj = boost::get<Mesh_Object>(obj.obj);

        // Find out the model
        auto model = object_model(obj);

        gfx::render_chunk(*mesh_obj.chunk);
      }
    }
  }
}
<commit_msg>Use object model when rendering<commit_after>/*
 * Copyright (c) 2016 Luke San Antonio
 * All rights reserved.
 *
 * This file provides the implementation for the engine's C interface,
 * specifically tailored for LuaJIT's FFI facilities.
 *
 * Scene stuff
 */

#include "redcrane.hpp"

#define CHECK_ID(id) \
        REDC_ASSERT_MSG(id != 0, "No more room for any more objects"); \
        if(id == 0) return id;

using namespace redc;

extern "C"
{
  // See scene.lua
  void *redc_make_scene(void *eng)
  {
    auto engine= (Engine*) eng;

    auto sc = new Peer_Ptr<Scene>(new Scene);
    sc->get()->engine = engine;

    engine->scenes.push_back(sc->peer());
    return sc;
  }
  void redc_unmake_scene(void *scene)
  {
    auto sc = (Peer_Ptr<Scene> *) scene;
    delete sc;
  }

  uint16_t redc_scene_add_camera(void *sc, const char *tp)
  {
    // For the moment, this is the only kind of camera we support

    std::function <gfx::Camera(gfx::IDriver const&)> cam_func;

    if(strcmp(tp, "fps") == 0)
    {
      // Ayy we got a camera
      cam_func = redc::gfx::make_fps_camera;
    }
    else
    {
      log_w("Invalid camera type '%' so making an fps camera", tp);
    }

    // The first camera will be set as active automatically by Active_Map from
    // id_map.hpp.
    auto scene = lock_resource<redc::Scene>(sc);

    auto id = scene->index_gen.get();
    CHECK_ID(id);

    auto &obj = scene->objs[id - 1];
    obj.obj = Cam_Object{cam_func(*scene->engine->driver)};

    // We can be sure at this point the id is non-zero (because of CHECK_ID).

    // If this is our first camera
    if(!scene->active_camera) scene->active_camera = id;

    // Return the id
    return id;
  }

  uint16_t redc_scene_get_active_camera(void *sc)
  {
    auto scene = lock_resource<redc::Scene>(sc);

    // This will be zero when there isn't an active camera.
    return scene->active_camera;
  }
  void redc_scene_activate_camera(void *sc, uint16_t cam)
  {
    if(!cam)
    {
      log_w("Cannot make an invalid object the active camera, "
                    "ignoring request");
      return;
    }

    // We have a camera
    auto scene = lock_resource<redc::Scene>(sc);

    if(scene->objs[cam-1].obj.which() == Object::Cam)
    {
      scene->active_camera = cam;
    }
    else
    {
      log_w("Cannot make non-camera the active camera, ignoring request");
    }
  }

  uint16_t redc_scene_attach(void *sc, void *ms, uint16_t parent)
  {
    auto scene = lock_resource<redc::Scene>(sc);

    auto id = scene->index_gen.get();
    CHECK_ID(id);

    auto mesh = lock_resource<gfx::Mesh_Chunk>(ms);
    scene->objs[id - 1].obj = Mesh_Object{std::move(mesh), glm::mat4(1.0f)};

    if(parent)
    {
      scene->objs[id - 1].parent = &scene->objs[parent-1];
    }

    return id;
  }

  bool redc_running(void *eng)
  {
    return ((redc::Engine *) eng)->running;
  }

  void redc_scene_step(void *sc)
  {
    auto scene = lock_resource<redc::Scene>(sc);

    Cam_Object* active_camera;
    if(scene->active_camera)
    {
      active_camera =
              &boost::get<Cam_Object>(scene->objs[scene->active_camera-1].obj);
    }

    SDL_Event event;
    while(SDL_PollEvent(&event))
    {
      // If we already used the event, bail.
      //if(collect_input(input, event, input_cfg)) continue;

      // Otherwise
      switch(event.type)
      {
        case SDL_QUIT:
          scene->engine->running = false;
          break;
        case SDL_MOUSEMOTION:
          if(active_camera)
          {
            active_camera->control.apply_delta_yaw(active_camera->cam,
                    event.motion.xrel / 1000.0f);

            active_camera->control.apply_delta_pitch(active_camera->cam,
                    event.motion.yrel / 1000.0f);
          }
          break;
        case SDL_KEYDOWN:
          //if(event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) running = false;
          break;
        default:
          break;
      }
    }
  }

  void redc_scene_render(void *sc)
  {
    auto scene = lock_resource<redc::Scene>(sc);

#ifdef REDC_LOG_FRAMES
    ++scene->frame_count;
    if(scene->frame_timer.has_been(std::chrono::seconds(1)))
    {
      log_d("fps: %", scene->frame_count);
      scene->frame_count = 0;
      scene->frame_timer.reset();
    }
#endif

    // Make sure we have an active camera
    if(!scene->active_camera)
    {
      log_e("No active camera; cannot render scene");
      return;
    }

    // Load the active camera
    auto active_camera =
            boost::get<Cam_Object>(scene->objs[scene->active_camera - 1].obj);
    gfx::use_camera(*scene->engine->driver, active_camera.cam);

    // Clear the screen
    scene->engine->driver->clear();

    // Find active shader.
    auto active_shader = scene->engine->driver->active_shader();

    // i is the loop counter, id is our current id.
    // Loop however many times as we have ids.
    int cur_id = 0;
    for(int i = 0; i < scene->index_gen.reserved(); ++i)
    {
      // Check to make sure the current id hasn't been removed.
      // Remember to add one

      // Increment the current id until we find one that is valid. Technically
      // we could just check if it hasn't been removed because we shouldn't
      // get far enough to exceed count but whatever this makes more semantic
      // sense. Then again if we exceed count_ we could enter a loop where we
      // exit only at overflow.

      // Put the increment in the expression because we always want to be
      // incrementing the counter, otherwise we risk rendering the same object
      // many times
      while(!scene->index_gen.is_valid((++cur_id)));

      // If the above scenario becomes an issue, replace !is_valid with
      // is_removed and check if it's valid here. If it hasn't been removed
      // but isn't valid we went to far, so exit early. I'm not doing that here
      // because I don't think it will be an issue.

      auto &obj = scene->objs[cur_id-1];
      if(obj.obj.which() == Object::Cam)
      {
        // Debugging enabled? Render cameras in some way?
      }
      else if(obj.obj.which() == Object::Mesh)
      {
        auto mesh_obj = boost::get<Mesh_Object>(obj.obj);

        // Find out the model
        auto model = object_model(obj);
        scene->engine->driver->active_shader()->set_model(model);

        gfx::render_chunk(*mesh_obj.chunk);
      }
    }
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Luke San Antonio
 * All rights reserved.
 *
 * This file provides the implementation for the engine's C interface,
 * specifically tailored for LuaJIT's FFI facilities.
 *
 * Scene stuff
 */

#include "redcrane.hpp"

#define CHECK_ID(id) \
        REDC_ASSERT_MSG(id != 0, "No more room for any more objects"); \
        if(id == 0) return id;

using namespace redc;

extern "C"
{
  // See scene.lua
  void *redc_make_scene(void *engine)
  {
    auto sc = new redc::Scene;
    sc->engine = (redc::Engine *) engine;
    return sc;
  }
  void redc_unmake_scene(void *scene)
  {
    auto sc = (redc::Scene *) scene;
    delete sc;
  }

  uint16_t redc_scene_add_camera(void *sc, const char *tp)
  {
    // For the moment, this is the only kind of camera we support

    std::function <gfx::Camera(gfx::IDriver const&)> cam_func;

    if(strcmp(tp, "fps") == 0)
    {
      // Ayy we got a camera
      cam_func = redc::gfx::make_fps_camera;
    }
    else
    {
      log_w("Invalid camera type '%' so making an fps camera", tp);
    }

    // The first camera will be set as active automatically by Active_Map from
    // id_map.hpp.
    auto scene = (redc::Scene *) sc;

    auto id = scene->index_gen.get();
    CHECK_ID(id);
    auto &obj = scene->objs[id - 1];
    obj.obj = Cam_Object{cam_func(*scene->engine->driver)};

    // We can be sure at this point the id is non-zero (because of CHECK_ID).

    // If this is our first camera
    if(!scene->active_camera) scene->active_camera = id;

    // Return the id
    return id;
  }

  uint16_t redc_scene_get_active_camera(void *sc)
  {
    auto scene = (redc::Scene *) sc;

    // This will be zero when there isn't an active camera.
    return scene->active_camera;
  }
  void redc_scene_activate_camera(void *sc, uint16_t cam)
  {
    if(!cam)
    {
      log_w("Cannot make an invalid object the active camera, "
                    "ignoring request");
      return;
    }

    // We have a camera
    auto scene = (redc::Scene *) sc;

    if(scene->objs[cam].obj.which() == Object::Cam)
    {
      scene->active_camera = cam;
    }
    else
    {
      log_w("Cannot make non-camera the active camera, ignoring request");
    }
  }

  uint16_t redc_scene_attach(void *sc, void *ms, uint16_t parent)
  {
    auto scene = (redc::Scene *) sc;
    auto mesh = (redc::gfx::Mesh_Chunk *) ms;

    auto id = scene->index_gen.get();
    CHECK_ID(id);
    scene->objs[id - 1].obj = Mesh_Object{gfx::copy_mesh_chunk_share_mesh(*mesh),
                                          glm::mat4(1.0f)};
    if(parent)
    {
      scene->objs[id - 1].parent = &scene->objs[parent];
    }
  }

  bool redc_running(void *eng)
  {
    return ((redc::Engine *) eng)->running;
  }

  void redc_scene_step(void *sc)
  {
    auto scene = (redc::Scene *) sc;

    Cam_Object* active_camera;
    if(scene->active_camera)
    {
      active_camera =
              &boost::get<Cam_Object>(scene->objs[scene->active_camera-1].obj);
    }

    SDL_Event event;
    while(SDL_PollEvent(&event))
    {
      // If we already used the event, bail.
      //if(collect_input(input, event, input_cfg)) continue;

      // Otherwise
      switch(event.type)
      {
        case SDL_QUIT:
          scene->engine->running = false;
          break;
        case SDL_MOUSEMOTION:
          if(active_camera)
          {
            active_camera->control.apply_delta_yaw(active_camera->cam,
                    event.motion.xrel / 1000.0f);

            active_camera->control.apply_delta_pitch(active_camera->cam,
                    event.motion.yrel / 1000.0f);
          }
          break;
        case SDL_KEYDOWN:
          //if(event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) running = false;
          break;
        default:
          break;
      }
    }
  }

  void redc_scene_render(void *sc)
  {
    auto scene = (redc::Scene *) sc;

    // Make sure we have an active camera
    if(!scene->active_camera)
    {
      log_e("No active camera; cannot render scene");
      return;
    }

    // Load the active camera
    auto active_camera =
            boost::get<Cam_Object>(scene->objs[scene->active_camera - 1].obj);
    gfx::use_camera(*scene->engine->driver, active_camera.cam);

    // Clear the screen
    scene->engine->driver->clear();

    // Find active shader.
    auto active_shader = scene->engine->driver->active_shader();

    // i is the loop counter, id is our current id.
    // Loop however many times as we have ids.
    int cur_id = 0;
    for(int i = 0; i < scene->index_gen.reserved(); ++i);
    {
      // Check to make sure the current id hasn't been removed.
      // Remember to add one

      // Increment the current id until we find one that is valid. Technically
      // we could just check if it hasn't been removed because we shouldn't
      // get far enough to exceed count but whatever this makes more semantic
      // sense. Then again if we exceed count_ we could enter a loop where we
      // exit only at overflow.
      while(!scene->index_gen.is_valid((cur_id + 1))) { ++cur_id; }

      // If the above scenario becomes an issue, replace !is_valid with
      // is_removed and check if it's valid here. If it hasn't been removed
      // but isn't valid we went to far, so exit early. I'm not doing that here
      // because I don't think it will be an issue.

      auto &obj = scene->objs[cur_id];
      if(obj.obj.which() == Object::Cam)
      {
        // Debugging enabled? Render cameras in some way?
      }
      else if(obj.obj.which() == Object::Mesh)
      {
        auto mesh_obj = boost::get<Mesh_Object>(obj.obj);

        // Find out the model
        auto model = object_model(obj);

        gfx::render_chunk(mesh_obj.chunk);
      }
    }
  }
}
<commit_msg>Active camera should be set to the id not the index<commit_after>/*
 * Copyright (c) 2016 Luke San Antonio
 * All rights reserved.
 *
 * This file provides the implementation for the engine's C interface,
 * specifically tailored for LuaJIT's FFI facilities.
 *
 * Scene stuff
 */

#include "redcrane.hpp"

#define CHECK_ID(id) \
        REDC_ASSERT_MSG(id != 0, "No more room for any more objects"); \
        if(id == 0) return id;

using namespace redc;

extern "C"
{
  // See scene.lua
  void *redc_make_scene(void *engine)
  {
    auto sc = new redc::Scene;
    sc->engine = (redc::Engine *) engine;
    return sc;
  }
  void redc_unmake_scene(void *scene)
  {
    auto sc = (redc::Scene *) scene;
    delete sc;
  }

  uint16_t redc_scene_add_camera(void *sc, const char *tp)
  {
    // For the moment, this is the only kind of camera we support

    std::function <gfx::Camera(gfx::IDriver const&)> cam_func;

    if(strcmp(tp, "fps") == 0)
    {
      // Ayy we got a camera
      cam_func = redc::gfx::make_fps_camera;
    }
    else
    {
      log_w("Invalid camera type '%' so making an fps camera", tp);
    }

    // The first camera will be set as active automatically by Active_Map from
    // id_map.hpp.
    auto scene = (redc::Scene *) sc;

    auto id = scene->index_gen.get();
    CHECK_ID(id);
    auto &obj = scene->objs[id - 1];
    obj.obj = Cam_Object{cam_func(*scene->engine->driver)};

    // We can be sure at this point the id is non-zero (because of CHECK_ID).

    // If this is our first camera
    if(!scene->active_camera) scene->active_camera = id;

    // Return the id
    return id;
  }

  uint16_t redc_scene_get_active_camera(void *sc)
  {
    auto scene = (redc::Scene *) sc;

    // This will be zero when there isn't an active camera.
    return scene->active_camera;
  }
  void redc_scene_activate_camera(void *sc, uint16_t cam)
  {
    if(!cam)
    {
      log_w("Cannot make an invalid object the active camera, "
                    "ignoring request");
      return;
    }

    // We have a camera
    auto scene = (redc::Scene *) sc;

    if(scene->objs[cam].obj.which() == Object::Cam)
    {
      scene->active_camera = cam+1;
    }
    else
    {
      log_w("Cannot make non-camera the active camera, ignoring request");
    }
  }

  uint16_t redc_scene_attach(void *sc, void *ms, uint16_t parent)
  {
    auto scene = (redc::Scene *) sc;
    auto mesh = (redc::gfx::Mesh_Chunk *) ms;

    auto id = scene->index_gen.get();
    CHECK_ID(id);
    scene->objs[id - 1].obj = Mesh_Object{gfx::copy_mesh_chunk_share_mesh(*mesh),
                                          glm::mat4(1.0f)};
    if(parent)
    {
      scene->objs[id - 1].parent = &scene->objs[parent];
    }
  }

  bool redc_running(void *eng)
  {
    return ((redc::Engine *) eng)->running;
  }

  void redc_scene_step(void *sc)
  {
    auto scene = (redc::Scene *) sc;

    Cam_Object* active_camera;
    if(scene->active_camera)
    {
      active_camera =
              &boost::get<Cam_Object>(scene->objs[scene->active_camera-1].obj);
    }

    SDL_Event event;
    while(SDL_PollEvent(&event))
    {
      // If we already used the event, bail.
      //if(collect_input(input, event, input_cfg)) continue;

      // Otherwise
      switch(event.type)
      {
        case SDL_QUIT:
          scene->engine->running = false;
          break;
        case SDL_MOUSEMOTION:
          if(active_camera)
          {
            active_camera->control.apply_delta_yaw(active_camera->cam,
                    event.motion.xrel / 1000.0f);

            active_camera->control.apply_delta_pitch(active_camera->cam,
                    event.motion.yrel / 1000.0f);
          }
          break;
        case SDL_KEYDOWN:
          //if(event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) running = false;
          break;
        default:
          break;
      }
    }
  }

  void redc_scene_render(void *sc)
  {
    auto scene = (redc::Scene *) sc;

    // Make sure we have an active camera
    if(!scene->active_camera)
    {
      log_e("No active camera; cannot render scene");
      return;
    }

    // Load the active camera
    auto active_camera =
            boost::get<Cam_Object>(scene->objs[scene->active_camera - 1].obj);
    gfx::use_camera(*scene->engine->driver, active_camera.cam);

    // Clear the screen
    scene->engine->driver->clear();

    // Find active shader.
    auto active_shader = scene->engine->driver->active_shader();

    // i is the loop counter, id is our current id.
    // Loop however many times as we have ids.
    int cur_id = 0;
    for(int i = 0; i < scene->index_gen.reserved(); ++i);
    {
      // Check to make sure the current id hasn't been removed.
      // Remember to add one

      // Increment the current id until we find one that is valid. Technically
      // we could just check if it hasn't been removed because we shouldn't
      // get far enough to exceed count but whatever this makes more semantic
      // sense. Then again if we exceed count_ we could enter a loop where we
      // exit only at overflow.
      while(!scene->index_gen.is_valid((cur_id + 1))) { ++cur_id; }

      // If the above scenario becomes an issue, replace !is_valid with
      // is_removed and check if it's valid here. If it hasn't been removed
      // but isn't valid we went to far, so exit early. I'm not doing that here
      // because I don't think it will be an issue.

      auto &obj = scene->objs[cur_id];
      if(obj.obj.which() == Object::Cam)
      {
        // Debugging enabled? Render cameras in some way?
      }
      else if(obj.obj.which() == Object::Mesh)
      {
        auto mesh_obj = boost::get<Mesh_Object>(obj.obj);

        // Find out the model
        auto model = object_model(obj);

        gfx::render_chunk(mesh_obj.chunk);
      }
    }
  }
}
<|endoftext|>


<commit_before>//===-- SIFixSGPRCopies.cpp - Remove potential VGPR => SGPR copies --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file
/// Copies from VGPR to SGPR registers are illegal and the register coalescer
/// will sometimes generate these illegal copies in situations like this:
///
///  Register Class <vsrc> is the union of <vgpr> and <sgpr>
///
/// BB0:
///   %vreg0 <sgpr> = SCALAR_INST
///   %vreg1 <vsrc> = COPY %vreg0 <sgpr>
///    ...
///    BRANCH %cond BB1, BB2
///  BB1:
///    %vreg2 <vgpr> = VECTOR_INST
///    %vreg3 <vsrc> = COPY %vreg2 <vgpr>
///  BB2:
///    %vreg4 <vsrc> = PHI %vreg1 <vsrc>, <BB#0>, %vreg3 <vrsc>, <BB#1>
///    %vreg5 <vgpr> = VECTOR_INST %vreg4 <vsrc>
///
///
/// The coalescer will begin at BB0 and eliminate its copy, then the resulting
/// code will look like this:
///
/// BB0:
///   %vreg0 <sgpr> = SCALAR_INST
///    ...
///    BRANCH %cond BB1, BB2
/// BB1:
///   %vreg2 <vgpr> = VECTOR_INST
///   %vreg3 <vsrc> = COPY %vreg2 <vgpr>
/// BB2:
///   %vreg4 <sgpr> = PHI %vreg0 <sgpr>, <BB#0>, %vreg3 <vsrc>, <BB#1>
///   %vreg5 <vgpr> = VECTOR_INST %vreg4 <sgpr>
///
/// Now that the result of the PHI instruction is an SGPR, the register
/// allocator is now forced to constrain the register class of %vreg3 to
/// <sgpr> so we end up with final code like this:
///
/// BB0:
///   %vreg0 <sgpr> = SCALAR_INST
///    ...
///    BRANCH %cond BB1, BB2
/// BB1:
///   %vreg2 <vgpr> = VECTOR_INST
///   %vreg3 <sgpr> = COPY %vreg2 <vgpr>
/// BB2:
///   %vreg4 <sgpr> = PHI %vreg0 <sgpr>, <BB#0>, %vreg3 <sgpr>, <BB#1>
///   %vreg5 <vgpr> = VECTOR_INST %vreg4 <sgpr>
///
/// Now this code contains an illegal copy from a VGPR to an SGPR.
///
/// In order to avoid this problem, this pass searches for PHI instructions
/// which define a <vsrc> register and constrains its definition class to
/// <vgpr> if the user of the PHI's definition register is a vector instruction.
/// If the PHI's definition class is constrained to <vgpr> then the coalescer
/// will be unable to perform the COPY removal from the above example  which
/// ultimately led to the creation of an illegal COPY.
//===----------------------------------------------------------------------===//

#include "AMDGPU.h"
#include "AMDGPUSubtarget.h"
#include "SIInstrInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"

using namespace llvm;

#define DEBUG_TYPE "sgpr-copies"

namespace {

class SIFixSGPRCopies : public MachineFunctionPass {
public:
  static char ID;

  SIFixSGPRCopies() : MachineFunctionPass(ID) { }

  bool runOnMachineFunction(MachineFunction &MF) override;

  const char *getPassName() const override {
    return "SI Fix SGPR copies";
  }

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.setPreservesCFG();
    MachineFunctionPass::getAnalysisUsage(AU);
  }
};

} // End anonymous namespace

INITIALIZE_PASS(SIFixSGPRCopies, DEBUG_TYPE,
                "SI Fix SGPR copies", false, false)

char SIFixSGPRCopies::ID = 0;

char &llvm::SIFixSGPRCopiesID = SIFixSGPRCopies::ID;

FunctionPass *llvm::createSIFixSGPRCopiesPass() {
  return new SIFixSGPRCopies();
}

static bool hasVGPROperands(const MachineInstr &MI, const SIRegisterInfo *TRI) {
  const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
  for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
    if (!MI.getOperand(i).isReg() ||
        !TargetRegisterInfo::isVirtualRegister(MI.getOperand(i).getReg()))
      continue;

    if (TRI->hasVGPRs(MRI.getRegClass(MI.getOperand(i).getReg())))
      return true;
  }
  return false;
}

static std::pair<const TargetRegisterClass *, const TargetRegisterClass *>
getCopyRegClasses(const MachineInstr &Copy,
                  const SIRegisterInfo &TRI,
                  const MachineRegisterInfo &MRI) {
  unsigned DstReg = Copy.getOperand(0).getReg();
  unsigned SrcReg = Copy.getOperand(1).getReg();

  const TargetRegisterClass *SrcRC =
    TargetRegisterInfo::isVirtualRegister(SrcReg) ?
    MRI.getRegClass(SrcReg) :
    TRI.getPhysRegClass(SrcReg);

  // We don't really care about the subregister here.
  // SrcRC = TRI.getSubRegClass(SrcRC, Copy.getOperand(1).getSubReg());

  const TargetRegisterClass *DstRC =
    TargetRegisterInfo::isVirtualRegister(DstReg) ?
    MRI.getRegClass(DstReg) :
    TRI.getPhysRegClass(DstReg);

  return std::make_pair(SrcRC, DstRC);
}

static bool isVGPRToSGPRCopy(const TargetRegisterClass *SrcRC,
                             const TargetRegisterClass *DstRC,
                             const SIRegisterInfo &TRI) {
  return TRI.isSGPRClass(DstRC) && TRI.hasVGPRs(SrcRC);
}

static bool isSGPRToVGPRCopy(const TargetRegisterClass *SrcRC,
                             const TargetRegisterClass *DstRC,
                             const SIRegisterInfo &TRI) {
  return TRI.isSGPRClass(SrcRC) && TRI.hasVGPRs(DstRC);
}

// Distribute an SGPR->VGPR copy of a REG_SEQUENCE into a VGPR REG_SEQUENCE.
//
// SGPRx = ...
// SGPRy = REG_SEQUENCE SGPRx, sub0 ...
// VGPRz = COPY SGPRy
//
// ==>
//
// VGPRx = COPY SGPRx
// VGPRz = REG_SEQUENCE VGPRx, sub0
//
// This exposes immediate folding opportunities when materializing 64-bit
// immediates.
static bool foldVGPRCopyIntoRegSequence(MachineInstr &MI,
                                        const SIRegisterInfo *TRI,
                                        const SIInstrInfo *TII,
                                        MachineRegisterInfo &MRI) {
  assert(MI.isRegSequence());

  unsigned DstReg = MI.getOperand(0).getReg();
  if (!TRI->isSGPRClass(MRI.getRegClass(DstReg)))
    return false;

  if (!MRI.hasOneUse(DstReg))
    return false;

  MachineInstr &CopyUse = *MRI.use_instr_begin(DstReg);
  if (!CopyUse.isCopy())
    return false;

  const TargetRegisterClass *SrcRC, *DstRC;
  std::tie(SrcRC, DstRC) = getCopyRegClasses(CopyUse, *TRI, MRI);

  if (!isSGPRToVGPRCopy(SrcRC, DstRC, *TRI))
    return false;

  // TODO: Could have multiple extracts?
  unsigned SubReg = CopyUse.getOperand(1).getSubReg();
  if (SubReg != AMDGPU::NoSubRegister)
    return false;

  MRI.setRegClass(DstReg, DstRC);

  // SGPRx = ...
  // SGPRy = REG_SEQUENCE SGPRx, sub0 ...
  // VGPRz = COPY SGPRy

  // =>
  // VGPRx = COPY SGPRx
  // VGPRz = REG_SEQUENCE VGPRx, sub0

  MI.getOperand(0).setReg(CopyUse.getOperand(0).getReg());

  for (unsigned I = 1, N = MI.getNumOperands(); I != N; I += 2) {
    unsigned SrcReg = MI.getOperand(I).getReg();
    unsigned SrcSubReg = MI.getOperand(I).getSubReg();

    const TargetRegisterClass *SrcRC = MRI.getRegClass(SrcReg);
    assert(TRI->isSGPRClass(SrcRC) &&
           "Expected SGPR REG_SEQUENCE to only have SGPR inputs");

    SrcRC = TRI->getSubRegClass(SrcRC, SrcSubReg);
    const TargetRegisterClass *NewSrcRC = TRI->getEquivalentVGPRClass(SrcRC);

    unsigned TmpReg = MRI.createVirtualRegister(NewSrcRC);

    BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(), TII->get(AMDGPU::COPY), TmpReg)
      .addOperand(MI.getOperand(I));

    MI.getOperand(I).setReg(TmpReg);
  }

  CopyUse.eraseFromParent();
  return true;
}

bool SIFixSGPRCopies::runOnMachineFunction(MachineFunction &MF) {
  MachineRegisterInfo &MRI = MF.getRegInfo();
  const SIRegisterInfo *TRI =
      static_cast<const SIRegisterInfo *>(MF.getSubtarget().getRegisterInfo());
  const SIInstrInfo *TII =
      static_cast<const SIInstrInfo *>(MF.getSubtarget().getInstrInfo());

  SmallVector<MachineInstr *, 16> Worklist;

  for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
                                                  BI != BE; ++BI) {

    MachineBasicBlock &MBB = *BI;
    for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
         I != E; ++I) {
      MachineInstr &MI = *I;

      switch (MI.getOpcode()) {
      default:
        continue;
      case AMDGPU::COPY: {
        // If the destination register is a physical register there isn't really
        // much we can do to fix this.
        if (!TargetRegisterInfo::isVirtualRegister(MI.getOperand(0).getReg()))
          continue;

        const TargetRegisterClass *SrcRC, *DstRC;
        std::tie(SrcRC, DstRC) = getCopyRegClasses(MI, *TRI, MRI);
        if (isVGPRToSGPRCopy(SrcRC, DstRC, *TRI)) {
          DEBUG(dbgs() << "Fixing VGPR -> SGPR copy: " << MI);
          TII->moveToVALU(MI);
        }

        break;
      }
      case AMDGPU::PHI: {
        DEBUG(dbgs() << "Fixing PHI: " << MI);
        unsigned Reg = MI.getOperand(0).getReg();
        if (!TRI->isSGPRClass(MRI.getRegClass(Reg)))
          break;

        // If a PHI node defines an SGPR and any of its operands are VGPRs,
        // then we need to move it to the VALU.
        //
        // Also, if a PHI node defines an SGPR and has all SGPR operands
        // we must move it to the VALU, because the SGPR operands will
        // all end up being assigned the same register, which means
        // there is a potential for a conflict if different threads take
        // different control flow paths.
        //
        // For Example:
        //
        // sgpr0 = def;
        // ...
        // sgpr1 = def;
        // ...
        // sgpr2 = PHI sgpr0, sgpr1
        // use sgpr2;
        //
        // Will Become:
        //
        // sgpr2 = def;
        // ...
        // sgpr2 = def;
        // ...
        // use sgpr2
        //
        // FIXME: This is OK if the branching decision is made based on an
        // SGPR value.
        bool SGPRBranch = false;

        // The one exception to this rule is when one of the operands
        // is defined by a SI_BREAK, SI_IF_BREAK, or SI_ELSE_BREAK
        // instruction.  In this case, there we know the program will
        // never enter the second block (the loop) without entering
        // the first block (where the condition is computed), so there
        // is no chance for values to be over-written.

        bool HasBreakDef = false;
        for (unsigned i = 1; i < MI.getNumOperands(); i+=2) {
          unsigned Reg = MI.getOperand(i).getReg();
          if (TRI->hasVGPRs(MRI.getRegClass(Reg))) {
            TII->moveToVALU(MI);
            break;
          }
          MachineInstr *DefInstr = MRI.getUniqueVRegDef(Reg);
          assert(DefInstr);
          switch(DefInstr->getOpcode()) {

          case AMDGPU::SI_BREAK:
          case AMDGPU::SI_IF_BREAK:
          case AMDGPU::SI_ELSE_BREAK:
          // If we see a PHI instruction that defines an SGPR, then that PHI
          // instruction has already been considered and should have
          // a *_BREAK as an operand.
          case AMDGPU::PHI:
            HasBreakDef = true;
            break;
          }
        }

        if (!SGPRBranch && !HasBreakDef)
          TII->moveToVALU(MI);
        break;
      }
      case AMDGPU::REG_SEQUENCE: {
        if (TRI->hasVGPRs(TII->getOpRegClass(MI, 0)) ||
            !hasVGPROperands(MI, TRI)) {
          foldVGPRCopyIntoRegSequence(MI, TRI, TII, MRI);
          continue;
        }

        DEBUG(dbgs() << "Fixing REG_SEQUENCE: " << MI);

        TII->moveToVALU(MI);
        break;
      }
      case AMDGPU::INSERT_SUBREG: {
        const TargetRegisterClass *DstRC, *Src0RC, *Src1RC;
        DstRC = MRI.getRegClass(MI.getOperand(0).getReg());
        Src0RC = MRI.getRegClass(MI.getOperand(1).getReg());
        Src1RC = MRI.getRegClass(MI.getOperand(2).getReg());
        if (TRI->isSGPRClass(DstRC) &&
            (TRI->hasVGPRs(Src0RC) || TRI->hasVGPRs(Src1RC))) {
          DEBUG(dbgs() << " Fixing INSERT_SUBREG: " << MI);
          TII->moveToVALU(MI);
        }
        break;
      }
      }
    }
  }

  return true;
}
<commit_msg>AMDGPU: Fix debug name of pass to better match<commit_after>//===-- SIFixSGPRCopies.cpp - Remove potential VGPR => SGPR copies --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file
/// Copies from VGPR to SGPR registers are illegal and the register coalescer
/// will sometimes generate these illegal copies in situations like this:
///
///  Register Class <vsrc> is the union of <vgpr> and <sgpr>
///
/// BB0:
///   %vreg0 <sgpr> = SCALAR_INST
///   %vreg1 <vsrc> = COPY %vreg0 <sgpr>
///    ...
///    BRANCH %cond BB1, BB2
///  BB1:
///    %vreg2 <vgpr> = VECTOR_INST
///    %vreg3 <vsrc> = COPY %vreg2 <vgpr>
///  BB2:
///    %vreg4 <vsrc> = PHI %vreg1 <vsrc>, <BB#0>, %vreg3 <vrsc>, <BB#1>
///    %vreg5 <vgpr> = VECTOR_INST %vreg4 <vsrc>
///
///
/// The coalescer will begin at BB0 and eliminate its copy, then the resulting
/// code will look like this:
///
/// BB0:
///   %vreg0 <sgpr> = SCALAR_INST
///    ...
///    BRANCH %cond BB1, BB2
/// BB1:
///   %vreg2 <vgpr> = VECTOR_INST
///   %vreg3 <vsrc> = COPY %vreg2 <vgpr>
/// BB2:
///   %vreg4 <sgpr> = PHI %vreg0 <sgpr>, <BB#0>, %vreg3 <vsrc>, <BB#1>
///   %vreg5 <vgpr> = VECTOR_INST %vreg4 <sgpr>
///
/// Now that the result of the PHI instruction is an SGPR, the register
/// allocator is now forced to constrain the register class of %vreg3 to
/// <sgpr> so we end up with final code like this:
///
/// BB0:
///   %vreg0 <sgpr> = SCALAR_INST
///    ...
///    BRANCH %cond BB1, BB2
/// BB1:
///   %vreg2 <vgpr> = VECTOR_INST
///   %vreg3 <sgpr> = COPY %vreg2 <vgpr>
/// BB2:
///   %vreg4 <sgpr> = PHI %vreg0 <sgpr>, <BB#0>, %vreg3 <sgpr>, <BB#1>
///   %vreg5 <vgpr> = VECTOR_INST %vreg4 <sgpr>
///
/// Now this code contains an illegal copy from a VGPR to an SGPR.
///
/// In order to avoid this problem, this pass searches for PHI instructions
/// which define a <vsrc> register and constrains its definition class to
/// <vgpr> if the user of the PHI's definition register is a vector instruction.
/// If the PHI's definition class is constrained to <vgpr> then the coalescer
/// will be unable to perform the COPY removal from the above example  which
/// ultimately led to the creation of an illegal COPY.
//===----------------------------------------------------------------------===//

#include "AMDGPU.h"
#include "AMDGPUSubtarget.h"
#include "SIInstrInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"

using namespace llvm;

#define DEBUG_TYPE "si-fix-sgpr-copies"

namespace {

class SIFixSGPRCopies : public MachineFunctionPass {
public:
  static char ID;

  SIFixSGPRCopies() : MachineFunctionPass(ID) { }

  bool runOnMachineFunction(MachineFunction &MF) override;

  const char *getPassName() const override {
    return "SI Fix SGPR copies";
  }

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.setPreservesCFG();
    MachineFunctionPass::getAnalysisUsage(AU);
  }
};

} // End anonymous namespace

INITIALIZE_PASS(SIFixSGPRCopies, DEBUG_TYPE,
                "SI Fix SGPR copies", false, false)

char SIFixSGPRCopies::ID = 0;

char &llvm::SIFixSGPRCopiesID = SIFixSGPRCopies::ID;

FunctionPass *llvm::createSIFixSGPRCopiesPass() {
  return new SIFixSGPRCopies();
}

static bool hasVGPROperands(const MachineInstr &MI, const SIRegisterInfo *TRI) {
  const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
  for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
    if (!MI.getOperand(i).isReg() ||
        !TargetRegisterInfo::isVirtualRegister(MI.getOperand(i).getReg()))
      continue;

    if (TRI->hasVGPRs(MRI.getRegClass(MI.getOperand(i).getReg())))
      return true;
  }
  return false;
}

static std::pair<const TargetRegisterClass *, const TargetRegisterClass *>
getCopyRegClasses(const MachineInstr &Copy,
                  const SIRegisterInfo &TRI,
                  const MachineRegisterInfo &MRI) {
  unsigned DstReg = Copy.getOperand(0).getReg();
  unsigned SrcReg = Copy.getOperand(1).getReg();

  const TargetRegisterClass *SrcRC =
    TargetRegisterInfo::isVirtualRegister(SrcReg) ?
    MRI.getRegClass(SrcReg) :
    TRI.getPhysRegClass(SrcReg);

  // We don't really care about the subregister here.
  // SrcRC = TRI.getSubRegClass(SrcRC, Copy.getOperand(1).getSubReg());

  const TargetRegisterClass *DstRC =
    TargetRegisterInfo::isVirtualRegister(DstReg) ?
    MRI.getRegClass(DstReg) :
    TRI.getPhysRegClass(DstReg);

  return std::make_pair(SrcRC, DstRC);
}

static bool isVGPRToSGPRCopy(const TargetRegisterClass *SrcRC,
                             const TargetRegisterClass *DstRC,
                             const SIRegisterInfo &TRI) {
  return TRI.isSGPRClass(DstRC) && TRI.hasVGPRs(SrcRC);
}

static bool isSGPRToVGPRCopy(const TargetRegisterClass *SrcRC,
                             const TargetRegisterClass *DstRC,
                             const SIRegisterInfo &TRI) {
  return TRI.isSGPRClass(SrcRC) && TRI.hasVGPRs(DstRC);
}

// Distribute an SGPR->VGPR copy of a REG_SEQUENCE into a VGPR REG_SEQUENCE.
//
// SGPRx = ...
// SGPRy = REG_SEQUENCE SGPRx, sub0 ...
// VGPRz = COPY SGPRy
//
// ==>
//
// VGPRx = COPY SGPRx
// VGPRz = REG_SEQUENCE VGPRx, sub0
//
// This exposes immediate folding opportunities when materializing 64-bit
// immediates.
static bool foldVGPRCopyIntoRegSequence(MachineInstr &MI,
                                        const SIRegisterInfo *TRI,
                                        const SIInstrInfo *TII,
                                        MachineRegisterInfo &MRI) {
  assert(MI.isRegSequence());

  unsigned DstReg = MI.getOperand(0).getReg();
  if (!TRI->isSGPRClass(MRI.getRegClass(DstReg)))
    return false;

  if (!MRI.hasOneUse(DstReg))
    return false;

  MachineInstr &CopyUse = *MRI.use_instr_begin(DstReg);
  if (!CopyUse.isCopy())
    return false;

  const TargetRegisterClass *SrcRC, *DstRC;
  std::tie(SrcRC, DstRC) = getCopyRegClasses(CopyUse, *TRI, MRI);

  if (!isSGPRToVGPRCopy(SrcRC, DstRC, *TRI))
    return false;

  // TODO: Could have multiple extracts?
  unsigned SubReg = CopyUse.getOperand(1).getSubReg();
  if (SubReg != AMDGPU::NoSubRegister)
    return false;

  MRI.setRegClass(DstReg, DstRC);

  // SGPRx = ...
  // SGPRy = REG_SEQUENCE SGPRx, sub0 ...
  // VGPRz = COPY SGPRy

  // =>
  // VGPRx = COPY SGPRx
  // VGPRz = REG_SEQUENCE VGPRx, sub0

  MI.getOperand(0).setReg(CopyUse.getOperand(0).getReg());

  for (unsigned I = 1, N = MI.getNumOperands(); I != N; I += 2) {
    unsigned SrcReg = MI.getOperand(I).getReg();
    unsigned SrcSubReg = MI.getOperand(I).getSubReg();

    const TargetRegisterClass *SrcRC = MRI.getRegClass(SrcReg);
    assert(TRI->isSGPRClass(SrcRC) &&
           "Expected SGPR REG_SEQUENCE to only have SGPR inputs");

    SrcRC = TRI->getSubRegClass(SrcRC, SrcSubReg);
    const TargetRegisterClass *NewSrcRC = TRI->getEquivalentVGPRClass(SrcRC);

    unsigned TmpReg = MRI.createVirtualRegister(NewSrcRC);

    BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(), TII->get(AMDGPU::COPY), TmpReg)
      .addOperand(MI.getOperand(I));

    MI.getOperand(I).setReg(TmpReg);
  }

  CopyUse.eraseFromParent();
  return true;
}

bool SIFixSGPRCopies::runOnMachineFunction(MachineFunction &MF) {
  MachineRegisterInfo &MRI = MF.getRegInfo();
  const SIRegisterInfo *TRI =
      static_cast<const SIRegisterInfo *>(MF.getSubtarget().getRegisterInfo());
  const SIInstrInfo *TII =
      static_cast<const SIInstrInfo *>(MF.getSubtarget().getInstrInfo());

  SmallVector<MachineInstr *, 16> Worklist;

  for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
                                                  BI != BE; ++BI) {

    MachineBasicBlock &MBB = *BI;
    for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
         I != E; ++I) {
      MachineInstr &MI = *I;

      switch (MI.getOpcode()) {
      default:
        continue;
      case AMDGPU::COPY: {
        // If the destination register is a physical register there isn't really
        // much we can do to fix this.
        if (!TargetRegisterInfo::isVirtualRegister(MI.getOperand(0).getReg()))
          continue;

        const TargetRegisterClass *SrcRC, *DstRC;
        std::tie(SrcRC, DstRC) = getCopyRegClasses(MI, *TRI, MRI);
        if (isVGPRToSGPRCopy(SrcRC, DstRC, *TRI)) {
          DEBUG(dbgs() << "Fixing VGPR -> SGPR copy: " << MI);
          TII->moveToVALU(MI);
        }

        break;
      }
      case AMDGPU::PHI: {
        DEBUG(dbgs() << "Fixing PHI: " << MI);
        unsigned Reg = MI.getOperand(0).getReg();
        if (!TRI->isSGPRClass(MRI.getRegClass(Reg)))
          break;

        // If a PHI node defines an SGPR and any of its operands are VGPRs,
        // then we need to move it to the VALU.
        //
        // Also, if a PHI node defines an SGPR and has all SGPR operands
        // we must move it to the VALU, because the SGPR operands will
        // all end up being assigned the same register, which means
        // there is a potential for a conflict if different threads take
        // different control flow paths.
        //
        // For Example:
        //
        // sgpr0 = def;
        // ...
        // sgpr1 = def;
        // ...
        // sgpr2 = PHI sgpr0, sgpr1
        // use sgpr2;
        //
        // Will Become:
        //
        // sgpr2 = def;
        // ...
        // sgpr2 = def;
        // ...
        // use sgpr2
        //
        // FIXME: This is OK if the branching decision is made based on an
        // SGPR value.
        bool SGPRBranch = false;

        // The one exception to this rule is when one of the operands
        // is defined by a SI_BREAK, SI_IF_BREAK, or SI_ELSE_BREAK
        // instruction.  In this case, there we know the program will
        // never enter the second block (the loop) without entering
        // the first block (where the condition is computed), so there
        // is no chance for values to be over-written.

        bool HasBreakDef = false;
        for (unsigned i = 1; i < MI.getNumOperands(); i+=2) {
          unsigned Reg = MI.getOperand(i).getReg();
          if (TRI->hasVGPRs(MRI.getRegClass(Reg))) {
            TII->moveToVALU(MI);
            break;
          }
          MachineInstr *DefInstr = MRI.getUniqueVRegDef(Reg);
          assert(DefInstr);
          switch(DefInstr->getOpcode()) {

          case AMDGPU::SI_BREAK:
          case AMDGPU::SI_IF_BREAK:
          case AMDGPU::SI_ELSE_BREAK:
          // If we see a PHI instruction that defines an SGPR, then that PHI
          // instruction has already been considered and should have
          // a *_BREAK as an operand.
          case AMDGPU::PHI:
            HasBreakDef = true;
            break;
          }
        }

        if (!SGPRBranch && !HasBreakDef)
          TII->moveToVALU(MI);
        break;
      }
      case AMDGPU::REG_SEQUENCE: {
        if (TRI->hasVGPRs(TII->getOpRegClass(MI, 0)) ||
            !hasVGPROperands(MI, TRI)) {
          foldVGPRCopyIntoRegSequence(MI, TRI, TII, MRI);
          continue;
        }

        DEBUG(dbgs() << "Fixing REG_SEQUENCE: " << MI);

        TII->moveToVALU(MI);
        break;
      }
      case AMDGPU::INSERT_SUBREG: {
        const TargetRegisterClass *DstRC, *Src0RC, *Src1RC;
        DstRC = MRI.getRegClass(MI.getOperand(0).getReg());
        Src0RC = MRI.getRegClass(MI.getOperand(1).getReg());
        Src1RC = MRI.getRegClass(MI.getOperand(2).getReg());
        if (TRI->isSGPRClass(DstRC) &&
            (TRI->hasVGPRs(Src0RC) || TRI->hasVGPRs(Src1RC))) {
          DEBUG(dbgs() << " Fixing INSERT_SUBREG: " << MI);
          TII->moveToVALU(MI);
        }
        break;
      }
      }
    }
  }

  return true;
}
<|endoftext|>