<commit_before>/*

   nsjail - logging
   -----------------------------------------

   Copyright 2014 Google Inc. All Rights Reserved.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/

#include "logs.h"

#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

#include "macros.h"
#include "util.h"

namespace logs {

static int _log_fd = STDERR_FILENO;
static bool _log_fd_isatty = true;
static enum llevel_t _log_level = INFO;
static bool _log_set = false;

static void setDupLogFdOr(int fd, int orfd) {
	int saved_errno = errno;
	_log_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
	if (_log_fd == -1) {
		_log_fd = fcntl(orfd, F_DUPFD_CLOEXEC, 0);
	}
	if (_log_fd == -1) {
		_log_fd = orfd;
	}
	_log_fd_isatty = (isatty(_log_fd) == 1);
	errno = saved_errno;
}

/*
 * Log to stderr by default. Use a dup()d fd, because in the future we'll associate the
 * connection socket with fd (0, 1, 2).
 */
__attribute__((constructor)) static void log_init(void) {
	setDupLogFdOr(STDERR_FILENO, STDERR_FILENO);
}

bool logSet() {
	return _log_set;
}

void logLevel(enum llevel_t ll) {
	_log_level = ll;
}

void logFile(const std::string& logfile) {
	_log_set = true;
	/* Close previous log_fd */
	if (_log_fd > STDERR_FILENO) {
		close(_log_fd);
	}
	int newlogfd = TEMP_FAILURE_RETRY(
	    open(logfile.c_str(), O_CREAT | O_RDWR | O_APPEND | O_CLOEXEC, 0640));
	setDupLogFdOr(newlogfd, STDERR_FILENO);
	if (newlogfd == -1) {
		PLOG_W("Couldn't open logfile open('%s')", logfile.c_str());
	} else {
		close(newlogfd);
	}
}

void logMsg(enum llevel_t ll, const char* fn, int ln, bool perr, const char* fmt, ...) {
	if (ll < _log_level) {
		return;
	}

	char strerr[512];
	if (perr) {
		snprintf(strerr, sizeof(strerr), "%s", strerror(errno));
	}
	struct {
		const char* const descr;
		const char* const prefix;
		const bool print_funcline;
		const bool print_time;
	} static const logLevels[] = {
	    {"D", "\033[0;4m", true, true},
	    {"I", "\033[1m", false, true},
	    {"W", "\033[0;33m", true, true},
	    {"E", "\033[1;31m", true, true},
	    {"F", "\033[7;35m", true, true},
	    {"HR", "\033[0m", false, false},
	    {"HB", "\033[1m", false, false},
	};

	/* Start printing logs */
	std::string msg;
	if (_log_fd_isatty) {
		msg.append(logLevels[ll].prefix);
	}
	if (ll != HELP && ll != HELP_BOLD) {
		msg.append("[").append(logLevels[ll].descr).append("]");
	}
	if (logLevels[ll].print_time) {
		msg.append("[").append(util::timeToStr(time(NULL))).append("]");
	}
	if (logLevels[ll].print_funcline) {
		msg.append("[")
		    .append(std::to_string(getpid()))
		    .append("] ")
		    .append(fn)
		    .append("():")
		    .append(std::to_string(ln));
	}

	char* strp;
	va_list args;
	va_start(args, fmt);
	int ret = vasprintf(&strp, fmt, args);
	va_end(args);
	if (ret == -1) {
		msg.append(" [logs internal]: MEMORY ALLOCATION ERROR");
	} else {
		msg.append(" ").append(strp);
		free(strp);
	}
	if (perr) {
		msg.append(": ").append(strerr);
	}
	if (_log_fd_isatty) {
		msg.append("\033[0m");
	}
	msg.append("\n");
	/* End printing logs */

	if (write(_log_fd, msg.c_str(), msg.size()) == -1) {
		dprintf(_log_fd, "%s", msg.c_str());
	}

	if (ll == FATAL) {
		exit(0xff);
	}
}

void logStop(int sig) {
	LOG_I("Server stops due to fatal signal (%d) caught. Exiting", sig);
}

}  // namespace logs
<commit_msg>log: close previous log descriptor a bit later:<commit_after>/*

   nsjail - logging
   -----------------------------------------

   Copyright 2014 Google Inc. All Rights Reserved.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/

#include "logs.h"

#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

#include "macros.h"
#include "util.h"

namespace logs {

static int _log_fd = STDERR_FILENO;
static bool _log_fd_isatty = true;
static enum llevel_t _log_level = INFO;
static bool _log_set = false;

static void setDupLogFdOr(int fd, int orfd) {
	int saved_errno = errno;
	_log_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
	if (_log_fd == -1) {
		_log_fd = fcntl(orfd, F_DUPFD_CLOEXEC, 0);
	}
	if (_log_fd == -1) {
		_log_fd = orfd;
	}
	_log_fd_isatty = (isatty(_log_fd) == 1);
	errno = saved_errno;
}

/*
 * Log to stderr by default. Use a dup()d fd, because in the future we'll associate the
 * connection socket with fd (0, 1, 2).
 */
__attribute__((constructor)) static void log_init(void) {
	setDupLogFdOr(STDERR_FILENO, STDERR_FILENO);
}

bool logSet() {
	return _log_set;
}

void logLevel(enum llevel_t ll) {
	_log_level = ll;
}

void logFile(const std::string& logfile) {
	_log_set = true;
	int newlogfd = TEMP_FAILURE_RETRY(
	    open(logfile.c_str(), O_CREAT | O_RDWR | O_APPEND | O_CLOEXEC, 0640));
	if (newlogfd == -1) {
		PLOG_W("Couldn't open logfile open('%s')", logfile.c_str());
		return;
	}
	/* Close previous log_fd */
	if (_log_fd > STDERR_FILENO) {
		close(_log_fd);
	}
	setDupLogFdOr(newlogfd, STDERR_FILENO);
	close(newlogfd);
}

void logMsg(enum llevel_t ll, const char* fn, int ln, bool perr, const char* fmt, ...) {
	if (ll < _log_level) {
		return;
	}

	char strerr[512];
	if (perr) {
		snprintf(strerr, sizeof(strerr), "%s", strerror(errno));
	}
	struct {
		const char* const descr;
		const char* const prefix;
		const bool print_funcline;
		const bool print_time;
	} static const logLevels[] = {
	    {"D", "\033[0;4m", true, true},
	    {"I", "\033[1m", false, true},
	    {"W", "\033[0;33m", true, true},
	    {"E", "\033[1;31m", true, true},
	    {"F", "\033[7;35m", true, true},
	    {"HR", "\033[0m", false, false},
	    {"HB", "\033[1m", false, false},
	};

	/* Start printing logs */
	std::string msg;
	if (_log_fd_isatty) {
		msg.append(logLevels[ll].prefix);
	}
	if (ll != HELP && ll != HELP_BOLD) {
		msg.append("[").append(logLevels[ll].descr).append("]");
	}
	if (logLevels[ll].print_time) {
		msg.append("[").append(util::timeToStr(time(NULL))).append("]");
	}
	if (logLevels[ll].print_funcline) {
		msg.append("[")
		    .append(std::to_string(getpid()))
		    .append("] ")
		    .append(fn)
		    .append("():")
		    .append(std::to_string(ln));
	}

	char* strp;
	va_list args;
	va_start(args, fmt);
	int ret = vasprintf(&strp, fmt, args);
	va_end(args);
	if (ret == -1) {
		msg.append(" [logs internal]: MEMORY ALLOCATION ERROR");
	} else {
		msg.append(" ").append(strp);
		free(strp);
	}
	if (perr) {
		msg.append(": ").append(strerr);
	}
	if (_log_fd_isatty) {
		msg.append("\033[0m");
	}
	msg.append("\n");
	/* End printing logs */

	if (write(_log_fd, msg.c_str(), msg.size()) == -1) {
		dprintf(_log_fd, "%s", msg.c_str());
	}

	if (ll == FATAL) {
		exit(0xff);
	}
}

void logStop(int sig) {
	LOG_I("Server stops due to fatal signal (%d) caught. Exiting", sig);
}

}  // namespace logs
<|endoftext|>


<commit_before>// Implementation of a linear time algorithm that find the longest palindromic
// substring of a given string.
//
// Author: Mikhail Andrenkov
// Date: October 22, 2017
//
// Credit: This code is a modification of a Manacher's Algorithm implementation
//         from https://algs4.cs.princeton.edu/53substring/Manacher.java.html
////////////////////////////////////////////////////////////////////////////////

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

std::string expand(const std::string&);
std::string solve(const std::string&);

// Returns the longest palindromic substring of |given|.
std::string solve(const std::string &given) {
	// Expand |given| to represent all palindrome indices.
	std::string pad = expand(given);
	// Declare an array to store the size of the longest palindromic substring
	// at each index of |pad|.
	std::vector<int> lps(pad.size(), 1);

	// The center of the active palindrome.
	int c = 0;
	// The rightmost index of the active palindrome.
	int r = 0;
	for (int i = 0; i < pad.size(); ++i) {
		// If |i| is past |r|, no previous LPS entries can be reused.
		if (i < r) {
			// Calculate the center index of the mirror palindrome.
			int j = 2*c - i;
			// Calculate the remaining distance in the active palindrome.
			int remaining = r - i + 1;
			lps[i] = std::min(remaining, lps[j]);
		}

		// Check if the current palindrome extends beyond the active palindrome.
		int length = lps[i];
		while (i - length >= 0 && i + length < pad.size() && pad[i - length] == pad[i + length]) {
			++lps[i];
			++length;
		}

		// Update the active palindrome if the current palindrome reaches further to the right.
		int i_r = i + lps[i] - 1;
		if (i_r > r) {
			c = i;
			r = i_r;
		}
	}

	// Extract the index and size of the longest palindromic substring.
	auto it = std::max_element(lps.begin(), lps.end());
	int index = std::distance(lps.begin(), it);
	int size = lps[index];

	// Convert the expanded index and size to match the original string.
	int start = (index + 1)/2 - size/2
	int length = std::max(1, size - 1);
	return given.substr(start, length);
}

// Returns |given| with a "|" inserted before and after character.
std::string expand(const std::string &given) {
	std::string buffer = "|";
	for (const auto &c : given) {
		buffer += c;
		buffer += "|";
	}
	return buffer;
}

// Execution entry point.
int main() {
	// Declare some sanity-check tests.
	std::vector<std::pair<const std::string, const std::string>> tests = {
		{"", ""},
		{"a", "a"},
		{"aba", "aba"},
		{"xabbab", "abba"},
		{"xababay", "ababa"}
	};

	for (const auto &p : tests) {
		std::string given = p.first;
		std::string want = p.second;
		std::string lps = solve(given);

		std::string result = want == lps ? "PASS" : "FAIL";
		std::cout << result << ": ";
		std::cout << "solve(\"" << given << "\") = \"" << lps << "\"";
		std::cout << ", want \"" << want << "\".\n";
	}

	return 0;
}
<commit_msg>Replaced missing semicolon.<commit_after>// Implementation of a linear time algorithm that find the longest palindromic
// substring of a given string.
//
// Author: Mikhail Andrenkov
// Date: October 22, 2017
//
// Credit: This code is a modification of a Manacher's Algorithm implementation
//         from https://algs4.cs.princeton.edu/53substring/Manacher.java.html
////////////////////////////////////////////////////////////////////////////////

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

std::string expand(const std::string&);
std::string solve(const std::string&);

// Returns the longest palindromic substring of |given|.
std::string solve(const std::string &given) {
	// Expand |given| to represent all palindrome indices.
	std::string pad = expand(given);
	// Declare an array to store the size of the longest palindromic substring
	// at each index of |pad|.
	std::vector<int> lps(pad.size(), 1);

	// The center of the active palindrome.
	int c = 0;
	// The rightmost index of the active palindrome.
	int r = 0;
	for (int i = 0; i < pad.size(); ++i) {
		// If |i| is past |r|, no previous LPS entries can be reused.
		if (i < r) {
			// Calculate the center index of the mirror palindrome.
			int j = 2*c - i;
			// Calculate the remaining distance in the active palindrome.
			int remaining = r - i + 1;
			lps[i] = std::min(remaining, lps[j]);
		}

		// Check if the current palindrome extends beyond the active palindrome.
		int length = lps[i];
		while (i - length >= 0 && i + length < pad.size() && pad[i - length] == pad[i + length]) {
			++lps[i];
			++length;
		}

		// Update the active palindrome if the current palindrome reaches further to the right.
		int i_r = i + lps[i] - 1;
		if (i_r > r) {
			c = i;
			r = i_r;
		}
	}

	// Extract the index and size of the longest palindromic substring.
	auto it = std::max_element(lps.begin(), lps.end());
	int index = std::distance(lps.begin(), it);
	int size = lps[index];

	// Convert the expanded index and size to match the original string.
	int start = (index + 1)/2 - size/2;
	int length = std::max(1, size - 1);
	return given.substr(start, length);
}

// Returns |given| with a "|" inserted before and after character.
std::string expand(const std::string &given) {
	std::string buffer = "|";
	for (const auto &c : given) {
		buffer += c;
		buffer += "|";
	}
	return buffer;
}

// Execution entry point.
int main() {
	// Declare some sanity-check tests.
	std::vector<std::pair<const std::string, const std::string>> tests = {
		{"", ""},
		{"a", "a"},
		{"aba", "aba"},
		{"xabbab", "abba"},
		{"xababay", "ababa"}
	};

	for (const auto &p : tests) {
		std::string given = p.first;
		std::string want = p.second;
		std::string lps = solve(given);

		std::string result = want == lps ? "PASS" : "FAIL";
		std::cout << result << ": ";
		std::cout << "solve(\"" << given << "\") = \"" << lps << "\"";
		std::cout << ", want \"" << want << "\".\n";
	}

	return 0;
}
<|endoftext|>


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

#include <os>
#include <net/inet4>
#include <statman>
#include <profile>
#include <cstdio>
#include <timers>

#define CLIENT_PORT 1337
#define SERVER_PORT 1338
#define NCAT_RECEIVE_PORT 9000

#define SEND_BUF_LEN 1300
#define SERVER_TEST_LEN 10
#define PACKETS_PER_INTERVAL 50000

using namespace net::ip4;

uint64_t  packets_rx{0};
uint64_t  packets_tx{0};
uint64_t  initial_packets_rx{0};
uint64_t  initial_packets_tx{0};
uint64_t  prev_packets_rx{0};
uint64_t  prev_packets_tx{0};
uint64_t  total_packets_rx{0};
uint64_t  total_packets_tx{0};
uint64_t  data_len{0};
bool      timestamps{true};
bool      first_time{true};
bool      data_received{false};
std::chrono::milliseconds dack{40};
uint64_t  first_ts = 0;
uint64_t  sample_ts = 0;
uint64_t  last_ts = 0;

struct activity {
  void reset() {
  }
  void print(activity& other) {
    auto tdiff = total - other.total;
    auto sdiff = asleep - other.asleep;
    if (tdiff > 0) {
      double idle = sdiff / (float) tdiff;
      printf("* CPU was %.2f%% idle\n", idle * 100.0);
    }
  }
  uint64_t total;
  uint64_t asleep;
};
activity activity_before;
activity activity_after;

void init_sample_stats()
{
    data_len = 0;
    initial_packets_rx = Statman::get().get_by_name("eth0.ethernet.packets_rx").get_uint64();
    initial_packets_tx = Statman::get().get_by_name("eth0.ethernet.packets_tx").get_uint64();
    prev_packets_rx  = initial_packets_rx;
    prev_packets_tx = initial_packets_tx;
    first_ts = OS::nanos_since_boot();
    sample_ts = last_ts = first_ts;
    activity_before.reset();
}

void measure_sample_stats()
{
    static uint64_t diff;
    auto prev_diff = diff;

    diff = last_ts - first_ts;
    activity_after.reset();

    activity_after.print(activity_before);

    uint64_t now_rx = Statman::get().get_by_name("eth0.ethernet.packets_rx").get_uint64();
    uint64_t now_tx = Statman::get().get_by_name("eth0.ethernet.packets_tx").get_uint64();

    packets_rx  = now_rx - prev_packets_rx;
    packets_tx  = now_tx - prev_packets_tx;
    prev_packets_rx = now_rx;
    prev_packets_tx = now_tx;
    total_packets_rx = now_rx - initial_packets_rx;
    total_packets_tx = now_tx - initial_packets_tx;

    printf("-------------------Start-----------------\n");
    printf("Packets RX [%llu] TX [%llu]\n", packets_rx, packets_tx);
    printf("Total Packets RX [%llu] TX [%llu]\n", total_packets_rx, total_packets_tx);

    double prev_durs = ((double) (diff - prev_diff) / 1000000000L);
    double total_durs   = ((double)diff) / 1000000000L;
    double mbits  = (data_len/(1024*1024)*8) / total_durs;
    printf("Duration: %.2fs, Total Duration: %.2fs, "
          " Payload: %lld MB %.2f MBit/s\n\n",
          prev_durs, total_durs, data_len /(1024*1024), mbits);
    printf("-------------------End-------------------\n");
}

void send_cb() {
    data_len += SEND_BUF_LEN;
}

void send_data(auto &client, auto &inet) {
    for (size_t i = 0; i < PACKETS_PER_INTERVAL; i++) {
        const char c = 'A' + (i % 26);
        std::string buff(SEND_BUF_LEN, c);
        client.sendto(inet.gateway(), NCAT_RECEIVE_PORT, buff.data(), buff.size(), send_cb);
    }
    sample_ts = last_ts;
    last_ts = OS::nanos_since_boot();
    printf("Done sending data\n");
}
void Service::start(const std::string& input) {
#ifdef USERSPACE_LINUX
    extern void create_network_device(int N, const char* route, const char* ip);
    create_network_device(0, "10.0.0.0/24", "10.0.0.1");

    // Get the first IP stack configured from config.json
    auto& inet = net::Super_stack::get<net::IP4>(0);
    inet.network_config({10,0,0,42}, {255,255,255,0}, {10,0,0,1});
#else
    auto& inet = net::Super_stack::get<net::IP4>(0);
#endif
    auto& udp = inet.udp();

    if (input.find("client") != std::string::npos) {
        auto& client = udp.bind(CLIENT_PORT);
        printf("Running as Client\n");

        init_sample_stats();
        printf("Sending to %s!\n", inet.gateway().str().c_str());
        send_data(client, inet);
        int timer = Timers::periodic(1s, 2s,
          [&timer, &inet, &client] (uint32_t) {
            static int secs = 0;
            measure_sample_stats();
            send_data(client, inet);
              /* Run the test for 10 seconds */
              if (secs++ == 10) {
                  Timers::stop(timer);
                  printf("Stopping test\n");
              }
          });
    } else {
        auto& server = udp.bind(SERVER_PORT);
        printf("Running as Server. Waiting for data...\n");
        server.on_read(
            [&server](auto addr, auto port, const char* buf, int len) {
            auto data = std::string(buf, len);
            using namespace std::chrono;
            if (first_time) {
                printf("Received data..\n");
                init_sample_stats();
                first_time = false;
            }
            //CHECK(1, "Getting UDP data from %s:  %d -> %s",
            //    addr.str().c_str(), port, data.c_str());
            data_len += data.size();
            data_received = true;
            sample_ts = last_ts;
            last_ts = OS::nanos_since_boot();
      });

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

#include <os>
#include <net/inet4>
#include <statman>
#include <profile>
#include <cstdio>
#include <timers>

#define CLIENT_PORT 1337
#define SERVER_PORT 1338
#define NCAT_RECEIVE_PORT 9000

#define SEND_BUF_LEN 1300
#define SERVER_TEST_LEN 10
#define PACKETS_PER_INTERVAL 50000

using namespace net::ip4;

uint64_t  packets_rx{0};
uint64_t  packets_tx{0};
uint64_t  initial_packets_rx{0};
uint64_t  initial_packets_tx{0};
uint64_t  prev_packets_rx{0};
uint64_t  prev_packets_tx{0};
uint64_t  total_packets_rx{0};
uint64_t  total_packets_tx{0};
uint64_t  data_len{0};
bool      timestamps{true};
bool      first_time{true};
bool      data_received{false};
std::chrono::milliseconds dack{40};
uint64_t  first_ts = 0;
uint64_t  sample_ts = 0;
uint64_t  last_ts = 0;

struct activity {
  void reset() {
  }
  void print(activity& other) {
    auto tdiff = total - other.total;
    auto sdiff = asleep - other.asleep;
    if (tdiff > 0) {
      double idle = sdiff / (float) tdiff;
      printf("* CPU was %.2f%% idle\n", idle * 100.0);
    }
  }
  uint64_t total;
  uint64_t asleep;
};
activity activity_before;
activity activity_after;

void init_sample_stats()
{
    data_len = 0;
    initial_packets_rx = Statman::get().get_by_name("eth0.ethernet.packets_rx").get_uint64();
    initial_packets_tx = Statman::get().get_by_name("eth0.ethernet.packets_tx").get_uint64();
    prev_packets_rx  = initial_packets_rx;
    prev_packets_tx = initial_packets_tx;
    first_ts = OS::nanos_since_boot();
    sample_ts = last_ts = first_ts;
    activity_before.reset();
}

void measure_sample_stats()
{
    static uint64_t diff;
    auto prev_diff = diff;

    diff = last_ts - first_ts;
    activity_after.reset();

    activity_after.print(activity_before);

    uint64_t now_rx = Statman::get().get_by_name("eth0.ethernet.packets_rx").get_uint64();
    uint64_t now_tx = Statman::get().get_by_name("eth0.ethernet.packets_tx").get_uint64();

    packets_rx  = now_rx - prev_packets_rx;
    packets_tx  = now_tx - prev_packets_tx;
    prev_packets_rx = now_rx;
    prev_packets_tx = now_tx;
    total_packets_rx = now_rx - initial_packets_rx;
    total_packets_tx = now_tx - initial_packets_tx;

    printf("-------------------Start-----------------\n");
    printf("Packets RX [%llu] TX [%llu]\n", packets_rx, packets_tx);
    printf("Total Packets RX [%llu] TX [%llu]\n", total_packets_rx, total_packets_tx);

    double prev_durs = ((double) (diff - prev_diff) / 1000000000L);
    double total_durs   = ((double)diff) / 1000000000L;
    double mbits  = (data_len/(1024*1024)*8) / total_durs;
    printf("Duration: %.2fs, Total Duration: %.2fs, "
          " Payload: %lld MB %.2f MBit/s\n\n",
          prev_durs, total_durs, data_len /(1024*1024), mbits);
    printf("-------------------End-------------------\n");
}

void send_cb() {
    data_len += SEND_BUF_LEN;
}

void send_data(net::UDPSocket& client, net::Inet<net::IP4>& inet) {
    for (size_t i = 0; i < PACKETS_PER_INTERVAL; i++) {
        const char c = 'A' + (i % 26);
        std::string buff(SEND_BUF_LEN, c);
        client.sendto(inet.gateway(), NCAT_RECEIVE_PORT, buff.data(), buff.size(), send_cb);
    }
    sample_ts = last_ts;
    last_ts = OS::nanos_since_boot();
    printf("Done sending data\n");
}
void Service::start(const std::string& input) {
#ifdef USERSPACE_LINUX
    extern void create_network_device(int N, const char* route, const char* ip);
    create_network_device(0, "10.0.0.0/24", "10.0.0.1");

    // Get the first IP stack configured from config.json
    auto& inet = net::Super_stack::get<net::IP4>(0);
    inet.network_config({10,0,0,42}, {255,255,255,0}, {10,0,0,1});
#else
    auto& inet = net::Super_stack::get<net::IP4>(0);
#endif
    auto& udp = inet.udp();

    if (input.find("client") != std::string::npos) {
        auto& client = udp.bind(CLIENT_PORT);
        printf("Running as Client\n");

        init_sample_stats();
        printf("Sending to %s!\n", inet.gateway().str().c_str());
        send_data(client, inet);
        int timer = Timers::periodic(1s, 2s,
          [&timer, &inet, &client] (uint32_t) {
            static int secs = 0;
            measure_sample_stats();
            send_data(client, inet);
              /* Run the test for 10 seconds */
              if (secs++ == 10) {
                  Timers::stop(timer);
                  printf("Stopping test\n");
              }
          });
    } else {
        auto& server = udp.bind(SERVER_PORT);
        printf("Running as Server. Waiting for data...\n");
        server.on_read(
            []([[maybe_unused]]auto addr,
                      [[maybe_unused]]auto port,
                      const char* buf, int len)
        {
            auto data = std::string(buf, len);
            using namespace std::chrono;
            if (first_time) {
                printf("Received data..\n");
                init_sample_stats();
                first_time = false;
            }
            //CHECK(1, "Getting UDP data from %s:  %d -> %s",
            //    addr.str().c_str(), port, data.c_str());
            data_len += data.size();
            data_received = true;
            sample_ts = last_ts;
            last_ts = OS::nanos_since_boot();
      });

      Timers::periodic(5s, 5s,
      [] (uint32_t) {
        if (data_received) {
            measure_sample_stats();
            data_received = false;
        }
      });
    }
}
<|endoftext|>


<commit_before>//===- AsmMatcherEmitter.cpp - Generate an assembly matcher ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tablegen backend emits a target specifier matcher for converting parsed
// assembly operands in the MCInst structures.
//
//===----------------------------------------------------------------------===//

#include "AsmMatcherEmitter.h"
#include "CodeGenTarget.h"
#include "Record.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Debug.h"
#include <set>
#include <list>
using namespace llvm;

/// FlattenVariants - Flatten an .td file assembly string by selecting the
/// variant at index \arg N.
static std::string FlattenVariants(const std::string &AsmString,
                                   unsigned N) {
  StringRef Cur = AsmString;
  std::string Res = "";

  for (;;) {
    // Add the prefix until the next '{', and split out the contents in the
    // braces.
    std::pair<StringRef, StringRef> Inner, Split = Cur.split('{');

    Res += Split.first;
    if (Split.second.empty())
      break;

    Inner = Split.second.split('}');

    // Select the Nth variant (or empty).
    StringRef Selection = Inner.first;
    for (unsigned i = 0; i != N; ++i)
      Selection = Selection.split('|').second;
    Res += Selection.split('|').first;

    Cur = Inner.second;
  }

  return Res;
}

/// TokenizeAsmString - Tokenize a simplified assembly string.
static void TokenizeAsmString(const std::string &AsmString,
                              SmallVectorImpl<StringRef> &Tokens) {
  unsigned Prev = 0;
  bool InTok = true;
  for (unsigned i = 0, e = AsmString.size(); i != e; ++i) {
    switch (AsmString[i]) {
    case '*':
    case '!':
    case ' ':
    case '\t':
    case ',':
      if (InTok) {
        Tokens.push_back(StringRef(&AsmString[Prev], i - Prev));
        InTok = false;
      }
      if (AsmString[i] == '*' || AsmString[i] == '!')
        Tokens.push_back(StringRef(&AsmString[i], 1));
      Prev = i + 1;
      break;

    default:
      InTok = true;
    }
  }
  if (InTok && Prev != AsmString.size())
    Tokens.push_back(StringRef(&AsmString[Prev], AsmString.size() - Prev));
}

void AsmMatcherEmitter::run(raw_ostream &OS) {
  CodeGenTarget Target;
  const std::vector<CodeGenRegister> &Registers = Target.getRegisters();
  Record *AsmParser = Target.getAsmParser();
  std::string ClassName = AsmParser->getValueAsString("AsmParserClassName");

  std::string Namespace = Registers[0].TheDef->getValueAsString("Namespace");

  EmitSourceFileHeader("Assembly Matcher Source Fragment", OS);

  // Emit the function to match a register name to number.

  OS << "bool " << Target.getName() << ClassName
     << "::MatchRegisterName(const StringRef &Name, unsigned &RegNo) {\n";

  // FIXME: TableGen should have a fast string matcher generator.
  for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
    const CodeGenRegister &Reg = Registers[i];
    if (Reg.TheDef->getValueAsString("AsmName").empty())
      continue;

    OS << "  if (Name == \""
       << Reg.TheDef->getValueAsString("AsmName") << "\")\n"
       << "    return RegNo=" << i + 1 << ", false;\n";
  }
  OS << "  return true;\n";
  OS << "}\n";

  // Emit the function to match instructions.
  std::vector<const CodeGenInstruction*> NumberedInstructions;
  Target.getInstructionsByEnumValue(NumberedInstructions);

  std::list<std::string> MatchFns;

  OS << "\n";
  const std::map<std::string, CodeGenInstruction> &Instructions =
    Target.getInstructions();
  for (std::map<std::string, CodeGenInstruction>::const_iterator
         it = Instructions.begin(), ie = Instructions.end(); it != ie; ++it) {
    const CodeGenInstruction &CGI = it->second;

    // Ignore psuedo ops.
    //
    // FIXME: This is a hack.
    if (const RecordVal *Form = CGI.TheDef->getValue("Form"))
      if (Form->getValue()->getAsString() == "Pseudo")
        continue;

    // Ignore instructions with no .s string.
    //
    // FIXME: What are these?
    if (CGI.AsmString.empty())
      continue;

    // FIXME: Hack; ignore "lock".
    if (StringRef(CGI.AsmString).startswith("lock"))
      continue;

    // FIXME: Hack.
#if 0
    if (1 && it->first != "SUB8mr")
      continue;
#endif

    std::string Flattened = FlattenVariants(CGI.AsmString, 0);
    SmallVector<StringRef, 8> Tokens;

    TokenizeAsmString(Flattened, Tokens);

    DEBUG({
        outs() << it->first << " -- flattened:\""
               << Flattened << "\", tokens:[";
        for (unsigned i = 0, e = Tokens.size(); i != e; ++i) {
          outs() << Tokens[i];
          if (i + 1 != e)
            outs() << ", ";
        }
        outs() << "]\n";

        for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) {
          const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[i];
          outs() << "  op[" << i << "] = " << OI.Name
                 << " " << OI.Rec->getName()
                 << " (" << OI.MIOperandNo << ", " << OI.MINumOperands << ")\n";
        }
      });

    // FIXME: Ignore non-literal tokens.
    if (std::find(Tokens[0].begin(), Tokens[0].end(), '$') != Tokens[0].end())
      continue;

    std::string FnName = "Match_" + Target.getName() + "_Inst_" + it->first;
    MatchFns.push_back(FnName);

    OS << "static bool " << FnName
       << "(const StringRef &Name,"
       << " SmallVectorImpl<X86Operand> &Operands,"
       << " MCInst &Inst) {\n\n";

    OS << "  // Match name.\n";
    OS << "  if (Name != \"" << Tokens[0] << "\")\n";
    OS << "    return true;\n\n";

    OS << "  // Match number of operands.\n";
    OS << "  if (Operands.size() != " << Tokens.size() - 1 << ")\n";
    OS << "    return true;\n\n";

    // Compute the total number of MCOperands.
    //
    // FIXME: Isn't this somewhere else?
    unsigned NumMIOperands = 0;
    for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) {
      const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[i];
      NumMIOperands = std::max(NumMIOperands,
                               OI.MIOperandNo + OI.MINumOperands);
    }

    std::set<unsigned> MatchedOperands;
    // This the list of operands we need to fill in.
    if (NumMIOperands)
      OS << "  MCOperand Ops[" << NumMIOperands << "];\n\n";

    unsigned ParsedOpIdx = 0;
    for (unsigned i = 1, e = Tokens.size(); i < e; ++i) {
      // FIXME: Can only match simple operands.
      if (Tokens[i][0] != '$') {
        OS << "  // FIXME: unable to match token: '" << Tokens[i] << "'!\n";
        OS << "  return true;\n\n";
        continue;
      }

      // Map this token to an operand. FIXME: Move elsewhere.

      unsigned Idx;
      try {
        Idx = CGI.getOperandNamed(Tokens[i].substr(1));
      } catch(...) {
        OS << "  // FIXME: unable to find operand: '" << Tokens[i] << "'!\n";
        OS << "  return true;\n\n";
        continue;
      }

      // FIXME: Each match routine should always end up filling the same number
      // of operands, we should just check that the number matches what the
      // match routine expects here instead of passing it. We can do this once
      // we start generating the class match functions.
      const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[Idx];

      // Track that we have matched these operands.
      //
      // FIXME: Verify that we don't parse something to the same operand twice.
      for (unsigned j = 0; j != OI.MINumOperands; ++j)
        MatchedOperands.insert(OI.MIOperandNo + j);

      OS << "  // Match '" << Tokens[i] << "' (parsed operand " << ParsedOpIdx
         << ") to machine operands [" << OI.MIOperandNo << ", "
         << OI.MIOperandNo + OI.MINumOperands << ").\n";
      OS << "  if (Match_" << Target.getName()
         << "_Op_" << OI.Rec->getName()  << "("
         << "Operands[" << ParsedOpIdx << "], "
         << "&Ops[" << OI.MIOperandNo << "], "
         << OI.MINumOperands << "))\n";
      OS << "    return true;\n\n";

      ++ParsedOpIdx;
    }

    // Generate code to construct the MCInst.

    OS << "  // Construct MCInst.\n";
    OS << "  Inst.setOpcode(" << Target.getName() << "::"
       << it->first << ");\n";
    for (unsigned i = 0, e = NumMIOperands; i != e; ++i) {
      // FIXME: Oops! Ignore this for now, the instruction should print ok. If
      // we need to evaluate the constraints.
      if (!MatchedOperands.count(i)) {
        OS << "\n";
        OS << "  // FIXME: Nothing matched Ops[" << i << "]!\n";
        OS << "  Ops[" << i << "] = MCOperand::CreateReg(0);\n";
        OS << "\n";
      }

      OS << "  Inst.addOperand(Ops[" << i << "]);\n";
    }
    OS << "\n";
    OS << "  return false;\n";
    OS << "}\n\n";
  }

  // Generate the top level match function.

  OS << "bool " << Target.getName() << ClassName
     << "::MatchInstruction(const StringRef &Name, "
     << "SmallVectorImpl<" << Target.getName() << "Operand> &Operands, "
     << "MCInst &Inst) {\n";
  for (std::list<std::string>::iterator it = MatchFns.begin(),
         ie = MatchFns.end(); it != ie; ++it) {
    OS << "  if (!" << *it << "(Name, Operands, Inst))\n";
    OS << "    return false;\n\n";
  }

  OS << "  return true;\n";
  OS << "}\n\n";
}
<commit_msg>TableGen / AsmMatcher: Tweaks to avoid generating completely bogus match functions.  - Fix variant flattening when the variant embeds an operand reference.<commit_after>//===- AsmMatcherEmitter.cpp - Generate an assembly matcher ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tablegen backend emits a target specifier matcher for converting parsed
// assembly operands in the MCInst structures.
//
//===----------------------------------------------------------------------===//

#include "AsmMatcherEmitter.h"
#include "CodeGenTarget.h"
#include "Record.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Debug.h"
#include <set>
#include <list>
using namespace llvm;

/// FlattenVariants - Flatten an .td file assembly string by selecting the
/// variant at index \arg N.
static std::string FlattenVariants(const std::string &AsmString,
                                   unsigned N) {
  StringRef Cur = AsmString;
  std::string Res = "";

  for (;;) {
    // Find the start of the next variant string.
    size_t VariantsStart = 0;
    for (size_t e = Cur.size(); VariantsStart != e; ++VariantsStart)
      if (Cur[VariantsStart] == '{' &&
          (VariantsStart == 0 || Cur[VariantsStart-1] != '$'))
        break;

    // Add the prefix to the result.
    Res += Cur.slice(0, VariantsStart);
    if (VariantsStart == Cur.size())
      break;

    ++VariantsStart; // Skip the '{'.

    // Scan to the end of the variants string.
    size_t VariantsEnd = VariantsStart;
    unsigned NestedBraces = 1;
    for (size_t e = Cur.size(); VariantsEnd != e; ++VariantsEnd) {
      if (Cur[VariantsEnd] == '}') {
        if (--NestedBraces == 0)
          break;
      } else if (Cur[VariantsEnd] == '{')
        ++NestedBraces;
    }

    // Select the Nth variant (or empty).
    StringRef Selection = Cur.slice(VariantsStart, VariantsEnd);
    for (unsigned i = 0; i != N; ++i)
      Selection = Selection.split('|').second;
    Res += Selection.split('|').first;

    assert(VariantsEnd != Cur.size() &&
           "Unterminated variants in assembly string!");
    Cur = Cur.substr(VariantsEnd + 1);
  }

  return Res;
}

/// TokenizeAsmString - Tokenize a simplified assembly string.
static void TokenizeAsmString(const std::string &AsmString,
                              SmallVectorImpl<StringRef> &Tokens) {
  unsigned Prev = 0;
  bool InTok = true;
  for (unsigned i = 0, e = AsmString.size(); i != e; ++i) {
    switch (AsmString[i]) {
    case '*':
    case '!':
    case ' ':
    case '\t':
    case ',':
      if (InTok) {
        Tokens.push_back(StringRef(&AsmString[Prev], i - Prev));
        InTok = false;
      }
      if (AsmString[i] == '*' || AsmString[i] == '!')
        Tokens.push_back(StringRef(&AsmString[i], 1));
      Prev = i + 1;
      break;

    default:
      InTok = true;
    }
  }
  if (InTok && Prev != AsmString.size())
    Tokens.push_back(StringRef(&AsmString[Prev], AsmString.size() - Prev));
}

void AsmMatcherEmitter::run(raw_ostream &OS) {
  CodeGenTarget Target;
  const std::vector<CodeGenRegister> &Registers = Target.getRegisters();
  Record *AsmParser = Target.getAsmParser();
  std::string ClassName = AsmParser->getValueAsString("AsmParserClassName");

  std::string Namespace = Registers[0].TheDef->getValueAsString("Namespace");

  EmitSourceFileHeader("Assembly Matcher Source Fragment", OS);

  // Emit the function to match a register name to number.

  OS << "bool " << Target.getName() << ClassName
     << "::MatchRegisterName(const StringRef &Name, unsigned &RegNo) {\n";

  // FIXME: TableGen should have a fast string matcher generator.
  for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
    const CodeGenRegister &Reg = Registers[i];
    if (Reg.TheDef->getValueAsString("AsmName").empty())
      continue;

    OS << "  if (Name == \""
       << Reg.TheDef->getValueAsString("AsmName") << "\")\n"
       << "    return RegNo=" << i + 1 << ", false;\n";
  }
  OS << "  return true;\n";
  OS << "}\n";

  // Emit the function to match instructions.
  std::vector<const CodeGenInstruction*> NumberedInstructions;
  Target.getInstructionsByEnumValue(NumberedInstructions);

  std::list<std::string> MatchFns;

  OS << "\n";
  const std::map<std::string, CodeGenInstruction> &Instructions =
    Target.getInstructions();
  for (std::map<std::string, CodeGenInstruction>::const_iterator
         it = Instructions.begin(), ie = Instructions.end(); it != ie; ++it) {
    const CodeGenInstruction &CGI = it->second;

    // Ignore psuedo ops.
    //
    // FIXME: This is a hack.
    if (const RecordVal *Form = CGI.TheDef->getValue("Form"))
      if (Form->getValue()->getAsString() == "Pseudo")
        continue;

    // Ignore "PHI" node.
    //
    // FIXME: This is also a hack.
    if (it->first == "PHI")
      continue;

    // Ignore instructions with no .s string.
    //
    // FIXME: What are these?
    if (CGI.AsmString.empty())
      continue;

    // FIXME: Hack; ignore "lock".
    if (StringRef(CGI.AsmString).startswith("lock"))
      continue;

    std::string Flattened = FlattenVariants(CGI.AsmString, 0);
    SmallVector<StringRef, 8> Tokens;

    TokenizeAsmString(Flattened, Tokens);

    DEBUG({
        outs() << it->first << " -- flattened:\""
               << Flattened << "\", tokens:[";
        for (unsigned i = 0, e = Tokens.size(); i != e; ++i) {
          outs() << Tokens[i];
          if (i + 1 != e)
            outs() << ", ";
        }
        outs() << "]\n";

        for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) {
          const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[i];
          outs() << "  op[" << i << "] = " << OI.Name
                 << " " << OI.Rec->getName()
                 << " (" << OI.MIOperandNo << ", " << OI.MINumOperands << ")\n";
        }
      });

    // FIXME: Ignore prefixes with non-literal tokens.
    if (std::find(Tokens[0].begin(), Tokens[0].end(), '$') != Tokens[0].end()) {
      DEBUG({
          errs() << "warning: '" << it->first << "': "
                 << "ignoring non-literal token '" << Tokens[0] << "', \n";
        });
      continue;
    }

    // Ignore instructions with subreg specifiers, these are always fake
    // instructions for simplifying codegen.
    //
    // FIXME: Is this true?
    //
    // Also, we ignore instructions which reference the operand multiple times;
    // this implies a constraint we would not currently honor. These are
    // currently always fake instructions for simplifying codegen.
    //
    // FIXME: Encode this assumption in the .td, so we can error out here.
    std::set<std::string> OperandNames;
    unsigned HasSubreg = 0, HasDuplicate = 0;
    for (unsigned i = 1, e = Tokens.size(); i < e; ++i) {
      if (Tokens[i][0] == '$' &&
          std::find(Tokens[i].begin(),
                    Tokens[i].end(), ':') != Tokens[i].end())
        HasSubreg = i;
      if (Tokens[i][0] == '$' && !OperandNames.insert(Tokens[i]).second)
        HasDuplicate = i;
    }
    if (HasSubreg) {
      DEBUG({
          errs() << "warning: '" << it->first << "': "
                 << "ignoring instruction; operand with subreg attribute '"
                 << Tokens[HasSubreg] << "', \n";
        });
      continue;
    } else if (HasDuplicate) {
      DEBUG({
          errs() << "warning: '" << it->first << "': "
                 << "ignoring instruction; tied operand '"
                 << Tokens[HasSubreg] << "', \n";
        });
      continue;
    }

    std::string FnName = "Match_" + Target.getName() + "_Inst_" + it->first;
    MatchFns.push_back(FnName);

    OS << "static bool " << FnName
       << "(const StringRef &Name,"
       << " SmallVectorImpl<X86Operand> &Operands,"
       << " MCInst &Inst) {\n\n";

    OS << "  // Match name.\n";
    OS << "  if (Name != \"" << Tokens[0] << "\")\n";
    OS << "    return true;\n\n";

    OS << "  // Match number of operands.\n";
    OS << "  if (Operands.size() != " << Tokens.size() - 1 << ")\n";
    OS << "    return true;\n\n";

    // Compute the total number of MCOperands.
    //
    // FIXME: Isn't this somewhere else?
    unsigned NumMIOperands = 0;
    for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) {
      const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[i];
      NumMIOperands = std::max(NumMIOperands,
                               OI.MIOperandNo + OI.MINumOperands);
    }

    std::set<unsigned> MatchedOperands;
    // This the list of operands we need to fill in.
    if (NumMIOperands)
      OS << "  MCOperand Ops[" << NumMIOperands << "];\n\n";

    unsigned ParsedOpIdx = 0;
    for (unsigned i = 1, e = Tokens.size(); i < e; ++i) {
      // FIXME: Can only match simple operands.
      if (Tokens[i][0] != '$') {
        OS << "  // FIXME: unable to match token: '" << Tokens[i] << "'!\n";
        OS << "  return true;\n\n";
        continue;
      }

      // Map this token to an operand. FIXME: Move elsewhere.

      unsigned Idx;
      try {
        Idx = CGI.getOperandNamed(Tokens[i].substr(1));
      } catch(...) {
        OS << "  // FIXME: unable to find operand: '" << Tokens[i] << "'!\n";
        OS << "  return true;\n\n";
        continue;
      }

      // FIXME: Each match routine should always end up filling the same number
      // of operands, we should just check that the number matches what the
      // match routine expects here instead of passing it. We can do this once
      // we start generating the class match functions.
      const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[Idx];

      // Track that we have matched these operands.
      //
      // FIXME: Verify that we don't parse something to the same operand twice.
      for (unsigned j = 0; j != OI.MINumOperands; ++j)
        MatchedOperands.insert(OI.MIOperandNo + j);

      OS << "  // Match '" << Tokens[i] << "' (parsed operand " << ParsedOpIdx
         << ") to machine operands [" << OI.MIOperandNo << ", "
         << OI.MIOperandNo + OI.MINumOperands << ").\n";
      OS << "  if (Match_" << Target.getName()
         << "_Op_" << OI.Rec->getName()  << "("
         << "Operands[" << ParsedOpIdx << "], "
         << "&Ops[" << OI.MIOperandNo << "], "
         << OI.MINumOperands << "))\n";
      OS << "    return true;\n\n";

      ++ParsedOpIdx;
    }

    // Generate code to construct the MCInst.

    OS << "  // Construct MCInst.\n";
    OS << "  Inst.setOpcode(" << Target.getName() << "::"
       << it->first << ");\n";
    for (unsigned i = 0, e = NumMIOperands; i != e; ++i) {
      // FIXME: Oops! Ignore this for now, the instruction should print ok. If
      // we need to evaluate the constraints.
      if (!MatchedOperands.count(i)) {
        OS << "\n";
        OS << "  // FIXME: Nothing matched Ops[" << i << "]!\n";
        OS << "  Ops[" << i << "] = MCOperand::CreateReg(0);\n";
        OS << "\n";
      }

      OS << "  Inst.addOperand(Ops[" << i << "]);\n";
    }
    OS << "\n";
    OS << "  return false;\n";
    OS << "}\n\n";
  }

  // Generate the top level match function.

  OS << "bool " << Target.getName() << ClassName
     << "::MatchInstruction(const StringRef &Name, "
     << "SmallVectorImpl<" << Target.getName() << "Operand> &Operands, "
     << "MCInst &Inst) {\n";
  for (std::list<std::string>::iterator it = MatchFns.begin(),
         ie = MatchFns.end(); it != ie; ++it) {
    OS << "  if (!" << *it << "(Name, Operands, Inst))\n";
    OS << "    return false;\n\n";
  }

  OS << "  return true;\n";
  OS << "}\n\n";
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

  Some parts of this code are derived from ITK. See ITKCopyright.txt
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include <iostream>
#include <sstream>

#include "itkRescaleIntensityImageFilter.h"
#include "itkVectorIndexSelectionCastImageFilter.h"

#include "otbImageToVectorImageCastFilter.h"
#include "otbImageList.h"
#include "otbImage.h"
#include "otbVectorImage.h"
#include "otbImageFileReader.h"
#include "otbStreamingHistogramVectorImageFilter.h"
#include "otbStreamingMinMaxVectorImageFilter.h"
#include "otbGlobalHistogramEqualizationFilter.h"
#include "otbVectorImageColorSpaceTransformFilter.h"
#include "otbImageFileWriter.h"
#include "otbImageListToVectorImageFilter.h"
#include "otbRGBToYUVFunctor.h"
#include "otbYUVToRGBFunctor.h"

#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"

namespace otb
{
namespace Wrapper
{
class ColorHistogramEqualize : public Application
{
public:

  typedef ColorHistogramEqualize Self;
  typedef Application Superclass;
  typedef itk::SmartPointer<Self> Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  itkNewMacro(Self);

  itkTypeMacro(Self, otb::Application);

  typedef unsigned int PixelType;
  // typedef unsigned int OutputPixelType;

  typedef otb::Image<PixelType, 2>  ImageType;
  typedef otb::VectorImage<PixelType, 2>   VectorType;
  typedef otb::VectorImage<float, 2>   FloatVectorType;
  typedef FloatVectorType::PixelType FloatVectorPixelType;
  typedef VectorType::PixelType VectorPixelType;
  typedef otb::Image<float, 2>  FloatImageType;

  typedef otb::StreamingMinMaxVectorImageFilter<VectorType> StreamingMinMaxFilterType;
  typedef itk::VariableLengthVector<PixelType> MinMaxPixelType;

  typedef otb::StreamingHistogramVectorImageFilter<VectorType> HistogramFilterType;
  typedef typename itk::NumericTraits< float >::RealType MeasurementType;
  typedef itk::Statistics::Histogram< MeasurementType, 1 > HistogramType;
  typedef otb::ObjectList< HistogramType > HistogramListType;
  typedef otb::GlobalHistogramEqualizationFilter<ImageType, FloatImageType> HistogramEqualizationFilterType;

  typedef otb::Functor::RGBToYUVFunctor<VectorPixelType,FloatVectorPixelType> YUVFunctorType;
  typedef otb::VectorImageColorSpaceTransformFilter<VectorType, FloatVectorType, YUVFunctorType> YUVFilterType;
  typedef itk::VectorIndexSelectionCastImageFilter<FloatVectorType, FloatImageType> VectorCastFilterType;
  typedef itk::RescaleIntensityImageFilter<FloatImageType, ImageType> FloatRescalerType;
  typedef otb::ImageToVectorImageCastFilter<ImageType,VectorType> ImageToVectorImageCastFilterType;
  typedef otb::ImageList<FloatImageType>  ImageListType;
  typedef otb::ImageListToVectorImageFilter<ImageListType, FloatVectorType > ListConcatenerFilterType;
  typedef otb::Functor::YUVToRGBFunctor<FloatVectorPixelType,VectorPixelType> YUVToRGBFunctorType;
  typedef otb::VectorImageColorSpaceTransformFilter<FloatVectorType, VectorType, YUVToRGBFunctorType> RGBFilterType;

private:

  void DoInit()
  {
    this->SetHaveInXML(false);
    this->SetHaveOutXML(false);
    SetName("ColorHistogramEqualize");
    SetDescription("Perform Histogram Equalization of Multi band raster image");

    SetDocName("ColorHistogramEqualize");
    SetDocLongDescription("Perform Histogram Equalization of Multi band raster image");
    SetDocLimitations("None");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso("ColorSpaceTransform");

    AddDocTag("Contrast Enhancement");
    AddDocTag("color histogram");

    AddParameter(ParameterType_InputImage, "in", "Input Image");
    MandatoryOn("in");

    AddParameter(ParameterType_String, "type", "Pixel type of input image(eg: uint8/uint16)");
    SetParameterString("type", "uint8");

    AddParameter(ParameterType_OutputImage, "out", "Output Image");
    MandatoryOn("out");

    AddParameter(ParameterType_Int, "red", "Red channel");
    SetDefaultParameterInt("red", 0);
    AddParameter(ParameterType_Int, "green", "Green channel");
    SetDefaultParameterInt("green", 1);
    AddParameter(ParameterType_Int, "blue", "Blue channel");
    SetDefaultParameterInt("blue", 2);

    SetDocExampleParameterValue("in", "rgbInput.tif");
    SetDocExampleParameterValue("type", "uint8");
    SetDocExampleParameterValue("out", "yuvOutput.tif");

  }

  void DoUpdateParameters()
  {
  }

  void DoExecute()
  {
    std::string inputFilename = GetParameterAsString("in");
    std::string type = GetParameterString("type");
    itk::Index<3> index;
    index[0] = GetParameterInt("red"); ;
    index[1] = GetParameterInt("green");
    index[2] = GetParameterInt("blue");

    int delta = 128;
    if (type == "uint8")
      delta = 128;
    else if(type == "uint16")
      delta = 32768;
    else if(type == "float")
      delta =  0.5;
    else
      std::cerr << "Unknown pixel type\n";

    typedef otb::ImageFileReader<VectorType> VectorReaderType;
    VectorReaderType::Pointer vectorReader = VectorReaderType::New();
    vectorReader->SetFileName(inputFilename);
    vectorReader->Update();

    StreamingMinMaxFilterType::Pointer filterMinMax = StreamingMinMaxFilterType::New();
    filterMinMax->SetInput( vectorReader->GetOutput() );
    filterMinMax->Update();
    MinMaxPixelType maxPixel = filterMinMax->GetMaximum();
    MinMaxPixelType::ValueType maxPixelValue;
    maxPixelValue = maxPixel[0]; //must get the maximum of all bands
    maxPixelValue = (maxPixelValue < 255) ? 255 : maxPixelValue;  //shouldnt go below 255 in case of uint8

    YUVFilterType::Pointer yuvFilter = YUVFilterType::New();
    yuvFilter->SetInput(vectorReader->GetOutput());
    yuvFilter->SetDelta(delta);
    yuvFilter->SetRGBIndex(index);
    yuvFilter->Update();

    VectorCastFilterType::Pointer vectorCastFilter1 = VectorCastFilterType::New();
    vectorCastFilter1->SetInput(yuvFilter->GetOutput());
    vectorCastFilter1->SetIndex(0);
    vectorCastFilter1->Update();

    FloatRescalerType::Pointer floatRescaler1 = FloatRescalerType::New();
    floatRescaler1->SetOutputMinimum(0);
    floatRescaler1->SetOutputMaximum(maxPixelValue );
    floatRescaler1->SetInput(vectorCastFilter1->GetOutput()); //Y
    floatRescaler1->Update();

    VectorCastFilterType::Pointer vectorCastFilter2 = VectorCastFilterType::New();
    vectorCastFilter2->SetInput(yuvFilter->GetOutput());
    vectorCastFilter2->SetIndex(1);
    vectorCastFilter2->Update();

    VectorCastFilterType::Pointer vectorCastFilter3 = VectorCastFilterType::New();
    vectorCastFilter3->SetInput(yuvFilter->GetOutput());
    vectorCastFilter3->SetIndex(2);
    vectorCastFilter3->Update();

    ImageToVectorImageCastFilterType::Pointer imageToVectorFilter = ImageToVectorImageCastFilterType::New();
    imageToVectorFilter->SetInput(floatRescaler1->GetOutput());
    imageToVectorFilter->Update();

    VectorType::Pointer histInput;
    ImageType::Pointer histEquInput;

    histInput = imageToVectorFilter->GetOutput(); //conversion of indexFilter->out
    histEquInput = floatRescaler1->GetOutput();

    filterMinMax->SetInput( histInput );
    filterMinMax->Update();
    MinMaxPixelType minPixel = filterMinMax->GetMinimum();
    maxPixel = filterMinMax->GetMaximum();

    unsigned int binestimate = maxPixel[0]- minPixel[0] + 1;
    unsigned int bins = (binestimate < 256)? 256: binestimate;

    otbAppLogDEBUG( << "MaxPixelValue = " << maxPixelValue <<std::endl );
    otbAppLogDEBUG( << "Delta = " << delta << std::endl );
    otbAppLogDEBUG( << "Bins = " << bins << std::endl );

    HistogramFilterType::Pointer histogramFilter =  HistogramFilterType::New();
    histogramFilter->SetInput( histInput );
    histogramFilter->GetFilter()->SetHistogramMin( minPixel );
    histogramFilter->GetFilter()->SetHistogramMax( maxPixel );
    histogramFilter->GetFilter()->SetNumberOfBins( bins );
    histogramFilter->GetFilter()->SetSubSamplingRate( 1 );
    histogramFilter->Update();

    HistogramEqualizationFilterType::Pointer histEqualizeFilter = HistogramEqualizationFilterType::New();

    HistogramListType::Pointer histList = histogramFilter->GetHistogramList();
    for( HistogramListType::ConstIterator it( histList->Begin() );   it!=histList->End();  ++it )
      {

      HistogramType::Pointer hist = it.Get();
      histEqualizeFilter->SetInput( histEquInput );

      // histEqualizeFilter->SetMinimumRange(0);
      histEqualizeFilter->SetMinimumRange(minPixel[0]);
      histEqualizeFilter->SetHistogram(hist);
      histEqualizeFilter->Update();

      /*
      typedef  otb::ImageFileWriter< VectorType > FloatImageWriterType;
      typedef  otb::ImageFileWriter< FloatImageType > ImageWriterType;
      ImageWriterType::Pointer outImageWriter = ImageWriterType::New();
      outImageWriter->SetFileName(strm.str());
      outImageWriter->SetInput(histEqualizeFilter->GetOutput());
      outImageWriter->Update();
      std::cerr << strm.str() << "\n";
      */
      }

    ///YCbCr -> rgb
    ImageListType::Pointer  m_ImageList = ImageListType::New();
    m_ImageList->PushBack( histEqualizeFilter->GetOutput() ); //Y band equalized
    m_ImageList->PushBack( vectorCastFilter2->GetOutput() ); //Cb
    m_ImageList->PushBack( vectorCastFilter3->GetOutput() ); //Cr

    ListConcatenerFilterType::Pointer  m_Concatener = ListConcatenerFilterType::New();

    m_Concatener->SetInput( m_ImageList );
    m_Concatener->Update();

    RGBFilterType::Pointer rgbFilter = RGBFilterType::New();
    rgbFilter->SetMaxPixelValue(maxPixelValue);
    rgbFilter->SetDelta(delta);
    rgbFilter->SetInput(m_Concatener->GetOutput());
    rgbFilter->SetRGBIndex(index);
    rgbFilter->Update();

    SetParameterOutputImage("out", rgbFilter->GetOutput());
  }

};
} //end namespace Wrapper
} //end namespace otb

OTB_APPLICATION_EXPORT(otb::Wrapper::ColorHistogramEqualize)
<commit_msg>COMP: do not use typename outside template class<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

  Some parts of this code are derived from ITK. See ITKCopyright.txt
  for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include <iostream>
#include <sstream>

#include "itkRescaleIntensityImageFilter.h"
#include "itkVectorIndexSelectionCastImageFilter.h"

#include "otbImageToVectorImageCastFilter.h"
#include "otbImageList.h"
#include "otbImage.h"
#include "otbVectorImage.h"
#include "otbImageFileReader.h"
#include "otbStreamingHistogramVectorImageFilter.h"
#include "otbStreamingMinMaxVectorImageFilter.h"
#include "otbGlobalHistogramEqualizationFilter.h"
#include "otbVectorImageColorSpaceTransformFilter.h"
#include "otbImageFileWriter.h"
#include "otbImageListToVectorImageFilter.h"
#include "otbRGBToYUVFunctor.h"
#include "otbYUVToRGBFunctor.h"

#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"

namespace otb
{
namespace Wrapper
{
class ColorHistogramEqualize : public Application
{
public:

  typedef ColorHistogramEqualize Self;
  typedef Application Superclass;
  typedef itk::SmartPointer<Self> Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  itkNewMacro(Self);

  itkTypeMacro(Self, otb::Application);

  typedef unsigned int PixelType;
  // typedef unsigned int OutputPixelType;

  typedef otb::Image<PixelType, 2>  ImageType;
  typedef otb::VectorImage<PixelType, 2>   VectorType;
  typedef otb::VectorImage<float, 2>   FloatVectorType;
  typedef FloatVectorType::PixelType FloatVectorPixelType;
  typedef VectorType::PixelType VectorPixelType;
  typedef otb::Image<float, 2>  FloatImageType;

  typedef otb::StreamingMinMaxVectorImageFilter<VectorType> StreamingMinMaxFilterType;
  typedef itk::VariableLengthVector<PixelType> MinMaxPixelType;

  typedef otb::StreamingHistogramVectorImageFilter<VectorType> HistogramFilterType;
  typedef itk::NumericTraits< float >::RealType MeasurementType;
  typedef itk::Statistics::Histogram< MeasurementType, 1 > HistogramType;
  typedef otb::ObjectList< HistogramType > HistogramListType;
  typedef otb::GlobalHistogramEqualizationFilter<ImageType, FloatImageType> HistogramEqualizationFilterType;

  typedef otb::Functor::RGBToYUVFunctor<VectorPixelType,FloatVectorPixelType> YUVFunctorType;
  typedef otb::VectorImageColorSpaceTransformFilter<VectorType, FloatVectorType, YUVFunctorType> YUVFilterType;
  typedef itk::VectorIndexSelectionCastImageFilter<FloatVectorType, FloatImageType> VectorCastFilterType;
  typedef itk::RescaleIntensityImageFilter<FloatImageType, ImageType> FloatRescalerType;
  typedef otb::ImageToVectorImageCastFilter<ImageType,VectorType> ImageToVectorImageCastFilterType;
  typedef otb::ImageList<FloatImageType>  ImageListType;
  typedef otb::ImageListToVectorImageFilter<ImageListType, FloatVectorType > ListConcatenerFilterType;
  typedef otb::Functor::YUVToRGBFunctor<FloatVectorPixelType,VectorPixelType> YUVToRGBFunctorType;
  typedef otb::VectorImageColorSpaceTransformFilter<FloatVectorType, VectorType, YUVToRGBFunctorType> RGBFilterType;

private:

  void DoInit()
  {
    this->SetHaveInXML(false);
    this->SetHaveOutXML(false);
    SetName("ColorHistogramEqualize");
    SetDescription("Perform Histogram Equalization of Multi band raster image");

    SetDocName("ColorHistogramEqualize");
    SetDocLongDescription("Perform Histogram Equalization of Multi band raster image");
    SetDocLimitations("None");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso("ColorSpaceTransform");

    AddDocTag("Contrast Enhancement");
    AddDocTag("color histogram");

    AddParameter(ParameterType_InputImage, "in", "Input Image");
    MandatoryOn("in");

    AddParameter(ParameterType_String, "type", "Pixel type of input image(eg: uint8/uint16)");
    SetParameterString("type", "uint8");

    AddParameter(ParameterType_OutputImage, "out", "Output Image");
    MandatoryOn("out");

    AddParameter(ParameterType_Int, "red", "Red channel");
    SetDefaultParameterInt("red", 0);
    AddParameter(ParameterType_Int, "green", "Green channel");
    SetDefaultParameterInt("green", 1);
    AddParameter(ParameterType_Int, "blue", "Blue channel");
    SetDefaultParameterInt("blue", 2);

    SetDocExampleParameterValue("in", "rgbInput.tif");
    SetDocExampleParameterValue("type", "uint8");
    SetDocExampleParameterValue("out", "yuvOutput.tif");

  }

  void DoUpdateParameters()
  {
  }

  void DoExecute()
  {
    std::string inputFilename = GetParameterAsString("in");
    std::string type = GetParameterString("type");
    itk::Index<3> index;
    index[0] = GetParameterInt("red"); ;
    index[1] = GetParameterInt("green");
    index[2] = GetParameterInt("blue");

    int delta = 128;
    if (type == "uint8")
      delta = 128;
    else if(type == "uint16")
      delta = 32768;
    else if(type == "float")
      delta =  0.5;
    else
      std::cerr << "Unknown pixel type\n";

    typedef otb::ImageFileReader<VectorType> VectorReaderType;
    VectorReaderType::Pointer vectorReader = VectorReaderType::New();
    vectorReader->SetFileName(inputFilename);
    vectorReader->Update();

    StreamingMinMaxFilterType::Pointer filterMinMax = StreamingMinMaxFilterType::New();
    filterMinMax->SetInput( vectorReader->GetOutput() );
    filterMinMax->Update();
    MinMaxPixelType maxPixel = filterMinMax->GetMaximum();
    MinMaxPixelType::ValueType maxPixelValue;
    maxPixelValue = maxPixel[0]; //must get the maximum of all bands
    maxPixelValue = (maxPixelValue < 255) ? 255 : maxPixelValue;  //shouldnt go below 255 in case of uint8

    YUVFilterType::Pointer yuvFilter = YUVFilterType::New();
    yuvFilter->SetInput(vectorReader->GetOutput());
    yuvFilter->SetDelta(delta);
    yuvFilter->SetRGBIndex(index);
    yuvFilter->Update();

    VectorCastFilterType::Pointer vectorCastFilter1 = VectorCastFilterType::New();
    vectorCastFilter1->SetInput(yuvFilter->GetOutput());
    vectorCastFilter1->SetIndex(0);
    vectorCastFilter1->Update();

    FloatRescalerType::Pointer floatRescaler1 = FloatRescalerType::New();
    floatRescaler1->SetOutputMinimum(0);
    floatRescaler1->SetOutputMaximum(maxPixelValue );
    floatRescaler1->SetInput(vectorCastFilter1->GetOutput()); //Y
    floatRescaler1->Update();

    VectorCastFilterType::Pointer vectorCastFilter2 = VectorCastFilterType::New();
    vectorCastFilter2->SetInput(yuvFilter->GetOutput());
    vectorCastFilter2->SetIndex(1);
    vectorCastFilter2->Update();

    VectorCastFilterType::Pointer vectorCastFilter3 = VectorCastFilterType::New();
    vectorCastFilter3->SetInput(yuvFilter->GetOutput());
    vectorCastFilter3->SetIndex(2);
    vectorCastFilter3->Update();

    ImageToVectorImageCastFilterType::Pointer imageToVectorFilter = ImageToVectorImageCastFilterType::New();
    imageToVectorFilter->SetInput(floatRescaler1->GetOutput());
    imageToVectorFilter->Update();

    VectorType::Pointer histInput;
    ImageType::Pointer histEquInput;

    histInput = imageToVectorFilter->GetOutput(); //conversion of indexFilter->out
    histEquInput = floatRescaler1->GetOutput();

    filterMinMax->SetInput( histInput );
    filterMinMax->Update();
    MinMaxPixelType minPixel = filterMinMax->GetMinimum();
    maxPixel = filterMinMax->GetMaximum();

    unsigned int binestimate = maxPixel[0]- minPixel[0] + 1;
    unsigned int bins = (binestimate < 256)? 256: binestimate;

    otbAppLogDEBUG( << "MaxPixelValue = " << maxPixelValue <<std::endl );
    otbAppLogDEBUG( << "Delta = " << delta << std::endl );
    otbAppLogDEBUG( << "Bins = " << bins << std::endl );

    HistogramFilterType::Pointer histogramFilter =  HistogramFilterType::New();
    histogramFilter->SetInput( histInput );
    histogramFilter->GetFilter()->SetHistogramMin( minPixel );
    histogramFilter->GetFilter()->SetHistogramMax( maxPixel );
    histogramFilter->GetFilter()->SetNumberOfBins( bins );
    histogramFilter->GetFilter()->SetSubSamplingRate( 1 );
    histogramFilter->Update();

    HistogramEqualizationFilterType::Pointer histEqualizeFilter = HistogramEqualizationFilterType::New();

    HistogramListType::Pointer histList = histogramFilter->GetHistogramList();
    for( HistogramListType::ConstIterator it( histList->Begin() );   it!=histList->End();  ++it )
      {

      HistogramType::Pointer hist = it.Get();
      histEqualizeFilter->SetInput( histEquInput );

      // histEqualizeFilter->SetMinimumRange(0);
      histEqualizeFilter->SetMinimumRange(minPixel[0]);
      histEqualizeFilter->SetHistogram(hist);
      histEqualizeFilter->Update();

      /*
      typedef  otb::ImageFileWriter< VectorType > FloatImageWriterType;
      typedef  otb::ImageFileWriter< FloatImageType > ImageWriterType;
      ImageWriterType::Pointer outImageWriter = ImageWriterType::New();
      outImageWriter->SetFileName(strm.str());
      outImageWriter->SetInput(histEqualizeFilter->GetOutput());
      outImageWriter->Update();
      std::cerr << strm.str() << "\n";
      */
      }

    ///YCbCr -> rgb
    ImageListType::Pointer  m_ImageList = ImageListType::New();
    m_ImageList->PushBack( histEqualizeFilter->GetOutput() ); //Y band equalized
    m_ImageList->PushBack( vectorCastFilter2->GetOutput() ); //Cb
    m_ImageList->PushBack( vectorCastFilter3->GetOutput() ); //Cr

    ListConcatenerFilterType::Pointer  m_Concatener = ListConcatenerFilterType::New();

    m_Concatener->SetInput( m_ImageList );
    m_Concatener->Update();

    RGBFilterType::Pointer rgbFilter = RGBFilterType::New();
    rgbFilter->SetMaxPixelValue(maxPixelValue);
    rgbFilter->SetDelta(delta);
    rgbFilter->SetInput(m_Concatener->GetOutput());
    rgbFilter->SetRGBIndex(index);
    rgbFilter->Update();

    SetParameterOutputImage("out", rgbFilter->GetOutput());
  }

};
} //end namespace Wrapper
} //end namespace otb

OTB_APPLICATION_EXPORT(otb::Wrapper::ColorHistogramEqualize)
<|endoftext|>


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

#include <pcl/recognition/hv/hv_papazov.h>

///////////////////////////////////////////////////////////////////////////////////////////////////
template<typename ModelT, typename SceneT> void
pcl::PapazovHV<ModelT, SceneT>::initialize ()
{
  // initialize mask...
  mask_.resize (complete_models_.size ());
  for (size_t i = 0; i < complete_models_.size (); i++)
    mask_[i] = true;

  // initalize model
  for (size_t m = 0; m < complete_models_.size (); m++)
  {
    boost::shared_ptr <RecognitionModel> recog_model (new RecognitionModel);
    // voxelize model cloud
    recog_model->cloud_.reset (new pcl::PointCloud<ModelT>);
    recog_model->complete_cloud_.reset (new pcl::PointCloud<ModelT>);
    recog_model->id_ = static_cast<int> (m);

    pcl::VoxelGrid<ModelT> voxel_grid;
    voxel_grid.setInputCloud (visible_models_[m]);
    voxel_grid.setLeafSize (resolution_, resolution_, resolution_);
    voxel_grid.filter (*(recog_model->cloud_));

    pcl::VoxelGrid<ModelT> voxel_grid_complete;
    voxel_grid_complete.setInputCloud (complete_models_[m]);
    voxel_grid_complete.setLeafSize (resolution_, resolution_, resolution_);
    voxel_grid_complete.filter (*(recog_model->complete_cloud_));

    std::vector<int> explained_indices;
    std::vector<int> outliers;
    std::vector<int> nn_indices;
    std::vector<float> nn_distances;

    for (size_t i = 0; i < recog_model->cloud_->points.size (); i++)
    {
      if (!scene_downsampled_tree_->radiusSearch (recog_model->cloud_->points[i], inliers_threshold_, nn_indices, nn_distances,
                                                  std::numeric_limits<int>::max ()))
      {
        outliers.push_back (static_cast<int> (i));
      }
      else
      {
        for (size_t k = 0; k < nn_distances.size (); k++)
        {
          explained_indices.push_back (nn_indices[k]); //nn_indices[k] points to the scene
        }
      }
    }

    std::sort (explained_indices.begin (), explained_indices.end ());
    explained_indices.erase (std::unique (explained_indices.begin (), explained_indices.end ()), explained_indices.end ());

    recog_model->bad_information_ = static_cast<int> (outliers.size ());

    if ((static_cast<float> (recog_model->bad_information_) / static_cast<float> (recog_model->complete_cloud_->points.size ()))
        <= penalty_threshold_ && (static_cast<float> (explained_indices.size ())
        / static_cast<float> (recog_model->complete_cloud_->points.size ())) >= support_threshold_)
    {
      recog_model->explained_ = explained_indices;
      recognition_models_.push_back (recog_model);

      // update explained_by_RM_, add 1
      for (size_t i = 0; i < explained_indices.size (); i++)
      {
        explained_by_RM_[explained_indices[i]]++;
        points_explained_by_rm_[explained_indices[i]].push_back (recog_model);
      }
    }
    else
    {
      mask_[m] = false; // the model didnt survive the sequential check...
    }
  }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
template<typename ModelT, typename SceneT> void
pcl::PapazovHV<ModelT, SceneT>::nonMaximaSuppresion ()
{
  // iterate over all vertices of the graph and check if they have a better neighbour, then remove that vertex
  typedef typename boost::graph_traits<Graph>::vertex_iterator VertexIterator;
  VertexIterator vi, vi_end, next;
  boost::tie (vi, vi_end) = boost::vertices (conflict_graph_);

  for (next = vi; next != vi_end; next++)
  {
    const typename Graph::vertex_descriptor v = boost::vertex (*next, conflict_graph_);
    typename boost::graph_traits<Graph>::adjacency_iterator ai;
    typename boost::graph_traits<Graph>::adjacency_iterator ai_end;

    boost::shared_ptr<RecognitionModel> current = static_cast<boost::shared_ptr<RecognitionModel> > (graph_id_model_map_[int (v)]);

    bool a_better_one = false;
    for (tie (ai, ai_end) = boost::adjacent_vertices (v, conflict_graph_); (ai != ai_end) && !a_better_one; ++ai)
    {
      boost::shared_ptr<RecognitionModel> neighbour = static_cast<boost::shared_ptr<RecognitionModel> > (graph_id_model_map_[int (*ai)]);
      if (neighbour->explained_.size () >= current->explained_.size () && mask_[neighbour->id_])
      {
        a_better_one = true;
      }
    }

    if (a_better_one)
    {
      mask_[current->id_] = false;
    }
  }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
template<typename ModelT, typename SceneT> void
pcl::PapazovHV<ModelT, SceneT>::buildConflictGraph ()
{
  // create vertices for the graph
  for (size_t i = 0; i < (recognition_models_.size ()); i++)
  {
    const typename Graph::vertex_descriptor v = boost::add_vertex (recognition_models_[i], conflict_graph_);
    graph_id_model_map_[int (v)] = static_cast<boost::shared_ptr<RecognitionModel> > (recognition_models_[i]);
  }

  // iterate over the remaining models and check for each one if there is a conflict with another one
  for (size_t i = 0; i < recognition_models_.size (); i++)
  {
    for (size_t j = i; j < recognition_models_.size (); j++)
    {
      if (i != j)
      {
        float n_conflicts = 0.f;
        // count scene points explained by both models
        for (size_t k = 0; k < explained_by_RM_.size (); k++)
        {
          if (explained_by_RM_[k] > 1)
          {
            // this point could be a conflict
            bool i_found = false;
            bool j_found = false;
            bool both_found = false;
            for (size_t kk = 0; (kk < points_explained_by_rm_[k].size ()) && !both_found; kk++)
            {
              if (points_explained_by_rm_[k][kk]->id_ == recognition_models_[i]->id_)
                i_found = true;

              if (points_explained_by_rm_[k][kk]->id_ == recognition_models_[j]->id_)
                j_found = true;

              if (i_found && j_found)
                both_found = true;
            }

            if (both_found)
              n_conflicts += 1.f;
          }
        }

        // check if number of points is big enough to create a conflict
        bool add_conflict = false;
        add_conflict = ((n_conflicts / static_cast<float> (recognition_models_[i]->complete_cloud_->points.size ())) > conflict_threshold_size_)
            || ((n_conflicts / static_cast<float> (recognition_models_[j]->complete_cloud_->points.size ())) > conflict_threshold_size_);

        if (add_conflict)
        {
          boost::add_edge (i, j, conflict_graph_);
        }
      }
    }
  }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
template<typename ModelT, typename SceneT> void
pcl::PapazovHV<ModelT, SceneT>::verify ()
{
  initialize();
  buildConflictGraph ();
  nonMaximaSuppresion ();
}

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

#include <pcl/recognition/hv/hv_papazov.h>

///////////////////////////////////////////////////////////////////////////////////////////////////
template<typename ModelT, typename SceneT> void
pcl::PapazovHV<ModelT, SceneT>::initialize ()
{
  // initialize mask...
  mask_.resize (complete_models_.size ());
  for (size_t i = 0; i < complete_models_.size (); i++)
    mask_[i] = true;

  // initalize model
  for (size_t m = 0; m < complete_models_.size (); m++)
  {
    boost::shared_ptr <RecognitionModel> recog_model (new RecognitionModel);
    // voxelize model cloud
    recog_model->cloud_.reset (new pcl::PointCloud<ModelT>);
    recog_model->complete_cloud_.reset (new pcl::PointCloud<ModelT>);
    recog_model->id_ = static_cast<int> (m);

    pcl::VoxelGrid<ModelT> voxel_grid;
    voxel_grid.setInputCloud (visible_models_[m]);
    voxel_grid.setLeafSize (resolution_, resolution_, resolution_);
    voxel_grid.filter (*(recog_model->cloud_));

    pcl::VoxelGrid<ModelT> voxel_grid_complete;
    voxel_grid_complete.setInputCloud (complete_models_[m]);
    voxel_grid_complete.setLeafSize (resolution_, resolution_, resolution_);
    voxel_grid_complete.filter (*(recog_model->complete_cloud_));

    std::vector<int> explained_indices;
    std::vector<int> outliers;
    std::vector<int> nn_indices;
    std::vector<float> nn_distances;

    for (size_t i = 0; i < recog_model->cloud_->points.size (); i++)
    {
      if (!scene_downsampled_tree_->radiusSearch (recog_model->cloud_->points[i], inliers_threshold_, nn_indices, nn_distances,
                                                  std::numeric_limits<int>::max ()))
      {
        outliers.push_back (static_cast<int> (i));
      }
      else
      {
        for (size_t k = 0; k < nn_distances.size (); k++)
        {
          explained_indices.push_back (nn_indices[k]); //nn_indices[k] points to the scene
        }
      }
    }

    std::sort (explained_indices.begin (), explained_indices.end ());
    explained_indices.erase (std::unique (explained_indices.begin (), explained_indices.end ()), explained_indices.end ());

    recog_model->bad_information_ = static_cast<int> (outliers.size ());

    if ((static_cast<float> (recog_model->bad_information_) / static_cast<float> (recog_model->complete_cloud_->points.size ()))
        <= penalty_threshold_ && (static_cast<float> (explained_indices.size ())
        / static_cast<float> (recog_model->complete_cloud_->points.size ())) >= support_threshold_)
    {
      recog_model->explained_ = explained_indices;
      recognition_models_.push_back (recog_model);

      // update explained_by_RM_, add 1
      for (size_t i = 0; i < explained_indices.size (); i++)
      {
        explained_by_RM_[explained_indices[i]]++;
        points_explained_by_rm_[explained_indices[i]].push_back (recog_model);
      }
    }
    else
    {
      mask_[m] = false; // the model didnt survive the sequential check...
    }
  }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
template<typename ModelT, typename SceneT> void
pcl::PapazovHV<ModelT, SceneT>::nonMaximaSuppresion ()
{
  // iterate over all vertices of the graph and check if they have a better neighbour, then remove that vertex
  typedef typename boost::graph_traits<Graph>::vertex_iterator VertexIterator;
  VertexIterator vi, vi_end, next;
  boost::tie (vi, vi_end) = boost::vertices (conflict_graph_);

  for (next = vi; next != vi_end; next++)
  {
    const typename Graph::vertex_descriptor v = boost::vertex (*next, conflict_graph_);
    typename boost::graph_traits<Graph>::adjacency_iterator ai;
    typename boost::graph_traits<Graph>::adjacency_iterator ai_end;

    boost::shared_ptr<RecognitionModel> current = static_cast<boost::shared_ptr<RecognitionModel> > (graph_id_model_map_[int (v)]);

    bool a_better_one = false;
    for (boost::tie (ai, ai_end) = boost::adjacent_vertices (v, conflict_graph_); (ai != ai_end) && !a_better_one; ++ai)
    {
      boost::shared_ptr<RecognitionModel> neighbour = static_cast<boost::shared_ptr<RecognitionModel> > (graph_id_model_map_[int (*ai)]);
      if (neighbour->explained_.size () >= current->explained_.size () && mask_[neighbour->id_])
      {
        a_better_one = true;
      }
    }

    if (a_better_one)
    {
      mask_[current->id_] = false;
    }
  }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
template<typename ModelT, typename SceneT> void
pcl::PapazovHV<ModelT, SceneT>::buildConflictGraph ()
{
  // create vertices for the graph
  for (size_t i = 0; i < (recognition_models_.size ()); i++)
  {
    const typename Graph::vertex_descriptor v = boost::add_vertex (recognition_models_[i], conflict_graph_);
    graph_id_model_map_[int (v)] = static_cast<boost::shared_ptr<RecognitionModel> > (recognition_models_[i]);
  }

  // iterate over the remaining models and check for each one if there is a conflict with another one
  for (size_t i = 0; i < recognition_models_.size (); i++)
  {
    for (size_t j = i; j < recognition_models_.size (); j++)
    {
      if (i != j)
      {
        float n_conflicts = 0.f;
        // count scene points explained by both models
        for (size_t k = 0; k < explained_by_RM_.size (); k++)
        {
          if (explained_by_RM_[k] > 1)
          {
            // this point could be a conflict
            bool i_found = false;
            bool j_found = false;
            bool both_found = false;
            for (size_t kk = 0; (kk < points_explained_by_rm_[k].size ()) && !both_found; kk++)
            {
              if (points_explained_by_rm_[k][kk]->id_ == recognition_models_[i]->id_)
                i_found = true;

              if (points_explained_by_rm_[k][kk]->id_ == recognition_models_[j]->id_)
                j_found = true;

              if (i_found && j_found)
                both_found = true;
            }

            if (both_found)
              n_conflicts += 1.f;
          }
        }

        // check if number of points is big enough to create a conflict
        bool add_conflict = false;
        add_conflict = ((n_conflicts / static_cast<float> (recognition_models_[i]->complete_cloud_->points.size ())) > conflict_threshold_size_)
            || ((n_conflicts / static_cast<float> (recognition_models_[j]->complete_cloud_->points.size ())) > conflict_threshold_size_);

        if (add_conflict)
        {
          boost::add_edge (i, j, conflict_graph_);
        }
      }
    }
  }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
template<typename ModelT, typename SceneT> void
pcl::PapazovHV<ModelT, SceneT>::verify ()
{
  initialize();
  buildConflictGraph ();
  nonMaximaSuppresion ();
}

<|endoftext|>


<commit_before>#include "inputevent.h"
#include <cassert>
#include <iostream>
#include <string>
#include <sstream>

extern "C" {
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <fcntl.h>

#include <sys/socket.h>
#include <netdb.h>
#include <err.h>
}

InputEvent::InputEvent()
    : eventId(SDL_RegisterEvents(1)),
    mutex(SDL_CreateMutex())
{
    assert(eventId >= 0);
    assert(mutex);
}

InputEvent::~InputEvent()
{
}

void InputEvent::pushEvent(const Input &input) {
    //https://wiki.libsdl.org/SDL_UserEvent
    SDL_Event event;
    SDL_zero(event);
    event.type = eventId;
    event.user.code = 0;
    event.user.data1 = new Input(input);
    event.user.data2 = nullptr;
    SDL_PushEvent(&event);
}

void InputEvent::handleEvent(const SDL_Event &event, Radar& radar) {
    if (event.type == eventId) {
        Input* input = (Input*) event.user.data1;
        radar.addDistance(*input);
        delete input;
    }
    if (event.type == SDL_KEYDOWN) {
       SDL_Scancode code = event.key.keysym.scancode;
       //https://wiki.libsdl.org/SDLScancodeLookup
       if (code >= 4 && code <= 39) {
           lock();
           addKey(SDL_GetScancodeName(event.key.keysym.scancode)[0]);
           unlock();
       }
    }
}

void InputEvent::lock() {
   assert(SDL_LockMutex(mutex) == 0);
}

void InputEvent::unlock() {
   assert(SDL_UnlockMutex(mutex) == 0);
}

bool InputEvent::hasKey() {
   lock();
   if (keys.size()) {
       return true;
   }
   else {
      unlock();
      return false;
   }
}

void InputEvent::clear() {
    keys.clear();
}

void InputEvent::addKey(char c) {
    keys.push_back(c);
}

int demoThread(void* data) {
    InputEvent* ie = (InputEvent*) data;

    for (unsigned i = 0; i < 450; ++i) {
        ie->pushEvent(Input(i % 360, 0.8));
        SDL_Delay(30);
    }

    return 0;
}

typedef std::pair<InputEvent*, const char*> fileType;
int fileThread(void* data) {
    fileType* in = (fileType*) data;

    InputEvent* ie = in->first;
    const char* path = in->second;

    int pipe = open(path, O_RDONLY, O_NONBLOCK, 0);

    if (pipe == -1) {
        perror("pipe");
        return 0;
    }

    fd_set fds;
    FD_ZERO(&fds);

    while (true) {
        char input[20];

        //Wait for input
        FD_SET(pipe, &fds);

        int s = select(pipe + 1, &fds, NULL, NULL, NULL);
        if (s < 0) {
            perror("select");
            return 0;
        }

        int r = read(pipe, input, 20);
        if (r > 0) {
            std::string s(input);
            std::stringstream ss(s);
            int angle;
            float distance;

            ss >> angle >> distance;
            if (ss.good()) {
                ie->pushEvent(Input(angle, distance));
            }
        }
        if (r < 0) {
            perror("read");
            return 0;
        }
    }

    return 0;
}

typedef std::pair<InputEvent*, const char**> socketType;
int socketThread(void* data) {
    socketType* in = (socketType*) data;

    InputEvent* ie = in->first;
    const char** argv = in->second;

    //getaddrinfo(3)
    struct addrinfo hints, *res, *res0;
    int error;
    int sock;
    const char *cause = NULL;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    error = getaddrinfo(argv[1], argv[2], &hints, &res0);
    if (error) {
        errx(1, "%s", gai_strerror(error));
        /*NOTREACHED*/
    }
    sock = -1;
    for (res = res0; res; res = res->ai_next) {
        sock = socket(res->ai_family, res->ai_socktype,
                   res->ai_protocol);
        if (sock < 0) {
            cause = "socket";
            continue;
        }

        if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
            cause = "connect";
            close(sock);
            sock = -1;
            continue;
        }

        break;  /* okay we got one */
    }
    if (sock < 0) {
        err(1, "%s", cause);
        /*NOTREACHED*/
    }
    freeaddrinfo(res0);

    std::string str;
    bool lastValid = false;
    unsigned nums = 0;

    while (true) {
        char input[4096] = "";

        fd_set fds;
        timeval tv;
        //Wait for input
        FD_ZERO(&fds);
        FD_SET(sock, &fds);

        //Set waiting time of 10us
        tv.tv_sec = 0;
        tv.tv_usec = 10;

        int s = select(sock + 1, &fds, NULL, NULL, &tv);
        if (s < 0) {
            perror("select");
            return 0;
        }
        if (s == 0) {
            if (ie->hasKey()) {
                std::cout << "SEND: " << ie->keys << std::endl;
                write(sock, ie->keys.c_str(), ie->keys.length());
                ie->clear();
                ie->unlock();
            }
        }

        if (FD_ISSET(sock, &fds)) {
            int r = read(sock, input, 4096);
            if (r > 0) {
                for (unsigned i = 0; i < r; ++i) {
                    char c = input[i];
                    if ( ('0' <= c && c <= '9') || c == '.') {
                        str.push_back(c);
                        lastValid = true;
                    }
                    if (lastValid && (c == ' ' || c == '\r' || c == '\n')) {
                        str.push_back(' ');
                        lastValid = false;
                        nums ++;
                    }
                }

                while (nums >= 2) {
                    int angle;
                    float distance;

                    std::stringstream ss(str);
                    ss >> angle >> distance;
                    if (ss.good()) {
                        //std::cout << "Input: " << angle << " " << distance << std::endl;
                        ie->pushEvent(Input(angle, distance));
                    }
                    std::string::size_type first = str.find(' ') + 1;
                    str = str.substr(str.find(' ', first) + 1);
                    nums -= 2;
                }
            }
            if (r < 0) {
                perror("read");
                return 0;
            }
        }
    }
    close(sock);

    return 0;
}

SDL_Thread* InputEvent::demo() {
    return SDL_CreateThread(demoThread, "DemoThread", this);
}

SDL_Thread* InputEvent::fileInput(const char *path) {
    return SDL_CreateThread(fileThread, "FileThread", new fileType(this, path));
}

SDL_Thread* InputEvent::socketInput(const char **argv) {
   return SDL_CreateThread(socketThread, "SocketThread", new socketType(this, argv));
}
<commit_msg>Functioning version.<commit_after>#include "inputevent.h"
#include <cassert>
#include <iostream>
#include <string>
#include <sstream>

extern "C" {
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <fcntl.h>

#include <sys/socket.h>
#include <netdb.h>
#include <err.h>
}

InputEvent::InputEvent()
    : eventId(SDL_RegisterEvents(1)),
    mutex(SDL_CreateMutex())
{
    assert(eventId >= 0);
    assert(mutex);
}

InputEvent::~InputEvent()
{
}

void InputEvent::pushEvent(const Input &input) {
    //https://wiki.libsdl.org/SDL_UserEvent
    SDL_Event event;
    SDL_zero(event);
    event.type = eventId;
    event.user.code = 0;
    event.user.data1 = new Input(input);
    event.user.data2 = nullptr;
    SDL_PushEvent(&event);
}

void InputEvent::handleEvent(const SDL_Event &event, Radar& radar) {
    if (event.type == eventId) {
        Input* input = (Input*) event.user.data1;
        radar.addDistance(*input);
        delete input;
    }
    if (event.type == SDL_KEYDOWN) {
       SDL_Scancode code = event.key.keysym.scancode;
       //https://wiki.libsdl.org/SDLScancodeLookup
       if (code >= 4 && code <= 39) {
           lock();
           addKey(SDL_GetScancodeName(event.key.keysym.scancode)[0]);
           unlock();
       }
    }
}

void InputEvent::lock() {
   assert(SDL_LockMutex(mutex) == 0);
}

void InputEvent::unlock() {
   assert(SDL_UnlockMutex(mutex) == 0);
}

bool InputEvent::hasKey() {
   lock();
   if (keys.size()) {
       return true;
   }
   else {
      unlock();
      return false;
   }
}

void InputEvent::clear() {
    keys.clear();
}

void InputEvent::addKey(char c) {
    keys.push_back(c);
}

int demoThread(void* data) {
    InputEvent* ie = (InputEvent*) data;

    for (unsigned i = 0; i < 450; ++i) {
        ie->pushEvent(Input(i % 360, 0.8));
        SDL_Delay(30);
    }

    return 0;
}

typedef std::pair<InputEvent*, const char*> fileType;
int fileThread(void* data) {
    fileType* in = (fileType*) data;

    InputEvent* ie = in->first;
    const char* path = in->second;

    int pipe = open(path, O_RDONLY, O_NONBLOCK, 0);

    if (pipe == -1) {
        perror("pipe");
        return 0;
    }

    fd_set fds;
    FD_ZERO(&fds);

    while (true) {
        char input[20];

        //Wait for input
        FD_SET(pipe, &fds);

        int s = select(pipe + 1, &fds, NULL, NULL, NULL);
        if (s < 0) {
            perror("select");
            return 0;
        }

        int r = read(pipe, input, 20);
        if (r > 0) {
            std::string s(input);
            std::stringstream ss(s);
            int angle;
            float distance;

            ss >> angle >> distance;
            if (ss.good()) {
                ie->pushEvent(Input(angle, distance));
            }
        }
        if (r < 0) {
            perror("read");
            return 0;
        }
    }

    return 0;
}

typedef std::pair<InputEvent*, const char**> socketType;
int socketThread(void* data) {
    socketType* in = (socketType*) data;

    InputEvent* ie = in->first;
    const char** argv = in->second;

    //getaddrinfo(3)
    struct addrinfo hints, *res, *res0;
    int error;
    int sock;
    const char *cause = NULL;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 6; //TCP
    error = getaddrinfo(argv[1], argv[2], &hints, &res0);
    if (error) {
        errx(1, "%s", gai_strerror(error));
        /*NOTREACHED*/
    }
    sock = -1;
    for (res = res0; res; res = res->ai_next) {
        sock = socket(res->ai_family, res->ai_socktype,
                   res->ai_protocol);
        if (sock < 0) {
            cause = "socket";
            continue;
        }

        if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
            cause = "connect";
            close(sock);
            sock = -1;
            continue;
        }

        break;  /* okay we got one */
    }
    if (sock < 0) {
        err(1, "%s", cause);
        /*NOTREACHED*/
    }
    freeaddrinfo(res0);

    std::string str;
    bool lastValid = false;
    unsigned nums = 0;

    while (true) {
        char input[4096] = "";

        fd_set fds;
        timeval tv;
        //Wait for input
        FD_ZERO(&fds);
        FD_SET(sock, &fds);

        //Set waiting time of 10us
        tv.tv_sec = 0;
        tv.tv_usec = 10;

        int s = select(sock + 1, &fds, NULL, NULL, &tv);
        if (s < 0) {
            perror("select");
            return 0;
        }
        if (s == 0) {
            if (ie->hasKey()) {
                std::cout << "SEND: " << ie->keys << std::endl;
                ie->keys.push_back('\n');
                s = write(sock, ie->keys.c_str(), ie->keys.length());
                if (s < 0) {
                    perror("write");
                    return 0;
                }
                ie->clear();
                ie->unlock();
            }
        }

        if (FD_ISSET(sock, &fds)) {
            int r = read(sock, input, 4096);
            if (r > 0) {
                for (unsigned i = 0; i < r; ++i) {
                    char c = input[i];
                    if ( ('0' <= c && c <= '9') || c == '.') {
                        str.push_back(c);
                        lastValid = true;
                    }
                    if (lastValid && (c == ' ' || c == '\r' || c == '\n')) {
                        str.push_back(' ');
                        lastValid = false;
                        nums ++;
                    }
                }

                while (nums >= 2) {
                    int angle;
                    float distance;

                    std::stringstream ss(str);
                    ss >> angle >> distance;
                    if (ss.good()) {
                        std::cout << "Input: " << angle << " " << distance << std::endl;
                        ie->pushEvent(Input(angle, distance));
                    }
                    std::string::size_type first = str.find(' ') + 1;
                    str = str.substr(str.find(' ', first) + 1);
                    nums -= 2;
                }
            }
            if (r < 0) {
                perror("read");
                return 0;
            }
        }
    }
    close(sock);

    return 0;
}

SDL_Thread* InputEvent::demo() {
    return SDL_CreateThread(demoThread, "DemoThread", this);
}

SDL_Thread* InputEvent::fileInput(const char *path) {
    return SDL_CreateThread(fileThread, "FileThread", new fileType(this, path));
}

SDL_Thread* InputEvent::socketInput(const char **argv) {
   return SDL_CreateThread(socketThread, "SocketThread", new socketType(this, argv));
}
<|endoftext|>