<commit_before>
#include <limits>
#include <cstdio>
#include <memory>
#include <set>
#include <string>
#include <map>
#include <vector>

#include "table.h"
#include "utfsample.h"

//////////////////////////////////////////////////////////////////////
template <typename IN_T>
struct transition {
	std::string from;
	typename std::make_unsigned<IN_T>::type begin;
	typename std::make_unsigned<IN_T>::type end;
};

//////////////////////////////////////////////////////////////////////
template <typename IN_T>
struct s_and_t {
	std::string s;
	std::initializer_list<transition<IN_T>> t;
};

//////////////////////////////////////////////////////////////////////
template<typename IN_T = char>
class transition_function
{
 public:
	transition_function(std::initializer_list<IN_T> input_classes,
	                    std::vector<size_t> states);

	size_t operator () (const IN_T & in, size_t current_state);

 private:
	std::vector<IN_T> input_classes;
};

//////////////////////////////////////////////////////////////////////
template <typename IN_T = char>
class function_generator
{
 public:
	typedef typename std::make_unsigned<IN_T>::type input_type;
	typedef std::numeric_limits<input_type> input_limits;

 protected:
	const input_type minimum_input_value;
	const input_type maximum_input_value;
	const size_t number_of_inputs;
	std::vector<input_type> range_ends;
	std::map<std::string, size_t> states;
	std::vector<std::string> state_names;
	std::unique_ptr<lookup_table<size_t, 2>> transition_table;

 public:

	function_generator(input_type min = input_limits::min(),
	                   input_type max = input_limits::max())
	  : function_generator({}, min, max) { }

	function_generator(std::initializer_list<s_and_t<IN_T>> everything,
	                   input_type min = input_limits::min(),
	                   input_type max = input_limits::max())
	  : minimum_input_value(min)
	  , maximum_input_value(max)
	  , number_of_inputs(1ul + max - min)
	  , range_ends()
	  , states()
	  , state_names(everything.size() + 1)
	  , transition_table()
	{
		size_t state_number = 0;

		std::set<input_type> range_markers;
		range_markers.insert(maximum_input_value);
		for (auto s_t : everything)
		{
			state_names.at(state_number) = s_t.s;
			states[s_t.s] = state_number++;
			for (auto t : s_t.t)
			{
				range_markers.insert(t.begin - 1);
				range_markers.insert(t.end);
			}
		}

		state_names.back() = "Error";
		states["Error"] = everything.size();

		range_ends.assign(range_markers.begin(), range_markers.end());

		transition_table = allocate_table();

		fill_table(everything);

		print_function();
	}

	~function_generator() { }

	void fill_table(const std::initializer_list<s_and_t<IN_T>> & everything)
	{
		for (auto s_t : everything)
		{
			std::array<size_t, 2> index;
			size_t target = states[s_t.s];
			for (auto t : s_t.t)
			{
				index[0] = states[t.from];
				for (size_t r_idx = 0; r_idx < range_ends.size(); ++r_idx)
				{
					if ( (range_ends[r_idx] >= t.begin)
					  && (range_ends[r_idx] <= t.end) )
					{
						index[1] = r_idx;
						transition_table->at(index) = target;
					}
				}
			}
		}
	}

	void print_function()
	{
		printf("Number of states: %zu\n", states.size());
		printf("Number of inputs: %zu\n", number_of_inputs);
		printf("Number of input classes: %zd\n", range_ends.size());

		printf("%20s %-2s  ", "", "");
		for (size_t x = 0; x < range_ends.size(); ++x)
			printf("%4zu", x);
		printf("\n%20s %-2s  ", "", "");
		for (auto r : range_ends)
			printf("%4x", r);
		printf("\n------------------------------"
		       "--------------------------------------------\n");
		for (auto name : state_names)
		{
			printf("%20s:%-2zd |", name.c_str(), states[name]);
			for (size_t j = 0; j < range_ends.size(); ++j)
				printf("%4zu", transition_table->at({{states[name], j}}));
			printf("\n");
		}
	}

	std::unique_ptr<lookup_table<size_t, 2>> allocate_table()
	{
		std::array<size_t, 2> table_dimensions{{states.size(),
		                                        range_ends.size()}};
		std::unique_ptr<lookup_table<size_t, 2>> ret{
			new lookup_table<size_t, 2>{table_dimensions, states.size() - 1}};

		return ret;
	}

	size_t operator () (size_t current_state, IN_T input)
	{
		size_t input_class = 0;
		auto class_iter = std::lower_bound(range_ends.begin(),
		                                   range_ends.end(),
		                                   static_cast<input_type>(input));
		input_class = std::distance(range_ends.begin(), class_iter);

		size_t ret =  (transition_table->at({{current_state, input_class}}));
//		printf("(%zu, %zu) -> %zu\n", current_state, input_class, ret);
		return ret;
	}

};

int main()
{
	function_generator<char> utf8_machine{ {
		{ "BOM Start", { } },
		{ "BOM 1", {
			{ "BOM Start", 0xef, 0xef }
		} },
		{ "BOM 2", {
			{ "BOM 1", 0xbb, 0xbb }
		} },
		{ "Complete BOM", {
			{ "BOM 2", 0xbf, 0xbf }
		} },
		{ "Complete Character", {
			{ "Complete Character", 0x0, 0x7f },
			{ "One Left", 0x80, 0xbf },
			{ "Complete BOM", 0x0, 0x7f },
			{ "BOM 2", 0x80, 0xbe },
			{ "BOM Start", 0x0, 0x7f },
		} },
		{ "One Left", {
			{ "Two Left", 0x80, 0xbf },
			{ "Complete Character", 0xc0, 0xdf },
			{ "Complete BOM", 0xc0, 0xdf },
			{ "BOM Start", 0xc0, 0xdf },
			{ "BOM 1", 0x80, 0xba },
			{ "BOM 1", 0xbc, 0xbf },
		} },
		{ "Two Left", {
			{ "BOM Start", 0xe0, 0xee },
			{ "Complete BOM", 0xe0, 0xef },
			{ "Complete Character", 0xe0, 0xef },
			{ "Three Left", 0x80, 0xbf },
		} },
		{ "Three Left", {
			{ "BOM Start", 0xf0, 0xf7 },
			{ "Complete BOM", 0xf0, 0xf7 },
			{ "Four Left", 0x80, 0xbf },
			{ "Complete Character", 0xf0, 0xf7 },
		} },
		{ "Four Left", {
			{ "Complete Character", 0xf8, 0xfb },
			{ "Complete BOM", 0xf8, 0xfb },
			{ "Five Left", 0x80, 0xbf },
			{ "BOM Start", 0xf8, 0xfb },
		} },
		{ "Five Left", {
			{ "Complete Character", 0xfc, 0xfd },
			{ "Complete BOM", 0xfc, 0xfd },
			{ "BOM Start", 0xfc, 0xfd },
		} },
	} };

//	const char * ptr = "\x01\x7f\x80\xba\xbb\xbc\xbe\xbf\xc0\xdf"
//	                   "\xe0\xee\xef\xf0\xf7\xf8\xfb\xfc\xfd\xfe\xff";

	const char * ptr = sample_utf8;

	size_t state = 0;

	while (*ptr)
	{
		state = utf8_machine(state, *ptr);
		++ptr;
	}

	return 0;
}
<commit_msg>Added inception of dot generation<commit_after>
#include <limits>
#include <cstdio>
#include <memory>
#include <set>
#include <string>
#include <map>
#include <vector>

#include "table.h"
#include "utfsample.h"

//////////////////////////////////////////////////////////////////////
template <typename IN_T>
struct transition {
	std::string from;
	typename std::make_unsigned<IN_T>::type begin;
	typename std::make_unsigned<IN_T>::type end;
};

//////////////////////////////////////////////////////////////////////
template <typename IN_T>
struct s_and_t {
	std::string s;
	std::initializer_list<transition<IN_T>> t;
};

//////////////////////////////////////////////////////////////////////
template<typename IN_T = char>
class transition_function
{
 public:
	transition_function(std::initializer_list<IN_T> input_classes,
	                    std::vector<size_t> states);

	size_t operator () (const IN_T & in, size_t current_state);

 private:
	std::vector<IN_T> input_classes;
};

//////////////////////////////////////////////////////////////////////
template <typename IN_T = char>
class function_generator
{
 public:
	typedef typename std::make_unsigned<IN_T>::type input_type;
	typedef std::numeric_limits<input_type> input_limits;

 protected:
	const input_type minimum_input_value;
	const input_type maximum_input_value;
	const size_t number_of_inputs;
	std::vector<input_type> range_ends;
	std::map<std::string, size_t> states;
	std::vector<std::string> state_names;
	std::unique_ptr<lookup_table<size_t, 2>> transition_table;

 public:

	function_generator(input_type min = input_limits::min(),
	                   input_type max = input_limits::max())
	  : function_generator({}, min, max) { }

	function_generator(std::initializer_list<s_and_t<IN_T>> everything,
	                   input_type min = input_limits::min(),
	                   input_type max = input_limits::max())
	  : minimum_input_value(min)
	  , maximum_input_value(max)
	  , number_of_inputs(1ul + max - min)
	  , range_ends()
	  , states()
	  , state_names(everything.size() + 1)
	  , transition_table()
	{
		size_t state_number = 0;

		std::set<input_type> range_markers;
		range_markers.insert(maximum_input_value);
		for (auto s_t : everything)
		{
			state_names.at(state_number) = s_t.s;
			states[s_t.s] = state_number++;
			for (auto t : s_t.t)
			{
				range_markers.insert(t.begin - 1);
				range_markers.insert(t.end);
			}
		}

		state_names.back() = "Error";
		states["Error"] = everything.size();

		range_ends.assign(range_markers.begin(), range_markers.end());

		transition_table = allocate_table();

		fill_table(everything);

		print_function();
	}

	~function_generator() { }

	void fill_table(const std::initializer_list<s_and_t<IN_T>> & everything)
	{
		for (auto s_t : everything)
		{
			std::array<size_t, 2> index;
			size_t target = states[s_t.s];
			for (auto t : s_t.t)
			{
				index[0] = states[t.from];
				for (size_t r_idx = 0; r_idx < range_ends.size(); ++r_idx)
				{
					if ( (range_ends[r_idx] >= t.begin)
					  && (range_ends[r_idx] <= t.end) )
					{
						index[1] = r_idx;
						transition_table->at(index) = target;
					}
				}
			}
		}
	}

	void print_function()
	{
		printf("Number of states: %zu\n", states.size());
		printf("Number of inputs: %zu\n", number_of_inputs);
		printf("Number of input classes: %zd\n", range_ends.size());

		printf("%20s %-2s  ", "", "");
		for (size_t x = 0; x < range_ends.size(); ++x)
			printf("%4zu", x);
		printf("\n%20s %-2s  ", "", "");
		for (auto r : range_ends)
			printf("%4x", r);
		printf("\n------------------------------"
		       "--------------------------------------------\n");
		for (auto name : state_names)
		{
			printf("%20s:%-2zd |", name.c_str(), states[name]);
			for (size_t j = 0; j < range_ends.size(); ++j)
				printf("%4zu", transition_table->at({{states[name], j}}));
			printf("\n");
		}
	}

	std::unique_ptr<lookup_table<size_t, 2>> allocate_table()
	{
		std::array<size_t, 2> table_dimensions{{states.size(),
		                                        range_ends.size()}};
		std::unique_ptr<lookup_table<size_t, 2>> ret{
			new lookup_table<size_t, 2>{table_dimensions, states.size() - 1}};

		return ret;
	}

	size_t operator () (size_t current_state, IN_T input)
	{
		size_t input_class = 0;
		auto class_iter = std::lower_bound(range_ends.begin(),
		                                   range_ends.end(),
		                                   static_cast<input_type>(input));
		input_class = std::distance(range_ends.begin(), class_iter);

		size_t ret =  (transition_table->at({{current_state, input_class}}));
//		printf("(%zu, %zu) -> %zu\n", current_state, input_class, ret);
		return ret;
	}

	void print_dot()
	{
		printf("digraph machine {\n"
		       "\tStart [shape=point]\n");

		for (auto name : state_names)
		{
			printf("\t\"%s\" [shape=circle]\n", name.c_str());
		}

		for (auto name : state_names)
		{
			for (size_t j = 0; j < range_ends.size(); ++j)
				printf("\t\"%s\" -> \"%s\"\n",
				       name.c_str(),
				       state_names[transition_table->at({{states[name],
				                                          j}})].c_str());

			printf("\n");
		}
		printf("}\n");

//		for (auto name : state_names)
//		{
//			printf("%20s:%-2zd |", name.c_str(), states[name]);
//			for (size_t j = 0; j < range_ends.size(); ++j)
//				printf("%4zu", transition_table->at({{states[name], j}}));
//			printf("\n");
//		}
	}
};

int main()
{
	function_generator<char> utf8_machine{ {
		{ "BOM Start", { } },
		{ "BOM 1", {
			{ "BOM Start", 0xef, 0xef }
		} },
		{ "BOM 2", {
			{ "BOM 1", 0xbb, 0xbb }
		} },
		{ "Complete BOM", {
			{ "BOM 2", 0xbf, 0xbf }
		} },
		{ "Complete Character", {
			{ "Complete Character", 0x0, 0x7f },
			{ "One Left", 0x80, 0xbf },
			{ "Complete BOM", 0x0, 0x7f },
			{ "BOM 2", 0x80, 0xbe },
			{ "BOM Start", 0x0, 0x7f },
		} },
		{ "One Left", {
			{ "Two Left", 0x80, 0xbf },
			{ "Complete Character", 0xc0, 0xdf },
			{ "Complete BOM", 0xc0, 0xdf },
			{ "BOM Start", 0xc0, 0xdf },
			{ "BOM 1", 0x80, 0xba },
			{ "BOM 1", 0xbc, 0xbf },
		} },
		{ "Two Left", {
			{ "BOM Start", 0xe0, 0xee },
			{ "Complete BOM", 0xe0, 0xef },
			{ "Complete Character", 0xe0, 0xef },
			{ "Three Left", 0x80, 0xbf },
		} },
		{ "Three Left", {
			{ "BOM Start", 0xf0, 0xf7 },
			{ "Complete BOM", 0xf0, 0xf7 },
			{ "Four Left", 0x80, 0xbf },
			{ "Complete Character", 0xf0, 0xf7 },
		} },
		{ "Four Left", {
			{ "Complete Character", 0xf8, 0xfb },
			{ "Complete BOM", 0xf8, 0xfb },
			{ "Five Left", 0x80, 0xbf },
			{ "BOM Start", 0xf8, 0xfb },
		} },
		{ "Five Left", {
			{ "Complete Character", 0xfc, 0xfd },
			{ "Complete BOM", 0xfc, 0xfd },
			{ "BOM Start", 0xfc, 0xfd },
		} },
	} };

//	const char * ptr = "\x01\x7f\x80\xba\xbb\xbc\xbe\xbf\xc0\xdf"
//	                   "\xe0\xee\xef\xf0\xf7\xf8\xfb\xfc\xfd\xfe\xff";

	const char * ptr = sample_utf8;

	size_t state = 0;

	while (*ptr)
	{
		state = utf8_machine(state, *ptr);
		++ptr;
	}

	utf8_machine.print_dot();
	return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007 The Regents of The University of Michigan
 * 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 the copyright holders 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.
 *
 * Authors: Ali Saidi
 */

#ifndef __BASE_RANGE_OPS_HH__
#define __BASE_RANGE_OPS_HH__

#include <list>
#include <vector>

#include "base/range.hh"

template <class T>
inline void
FilterRangeList(std::vector<Range<T> > filter_list,
                std::list<Range<T> > &range_list)
{
    typedef typename std::list<Range<T> > RangeList;

    for (typename RangeList::size_type x = 0; x < filter_list.size(); x++) {
        typename RangeList::iterator i = range_list.begin();
        while (i != range_list.end()) {
            // Is the range within one of our filter ranges?
            if (filter_list[x] == i->start || filter_list[x] == i->end)
                i = range_list.erase(i);
            else
                ++i;
        }
    }
}

#endif //__BASE_RANGE_OPS_HH__

<commit_msg>AddrRange: Remove the unused range_ops header<commit_after><|endoftext|>


<commit_before>#ifndef BAUERT_TCP_SVR
#define BAUERT_TCP_SVR

#include <iostream>
#include <string.h>
#include "socket_facade.h"
#include "bauer_node.hpp"
#include "bauer_types.hpp"
#include "bauer_tcp.hpp"

namespace bauer {
  class bauer_tcp_svr
  {
  private:
    bauer_node local;
  public:

    bauer_tcp_svr(bauer_node _local) {
      /* Create a local communication endpoint */
      if ( _local.get_socket() < 0 ) _local.set_socket(tcp_socket());
      local = _local;

      setup_svr();
    }

    ~bauer_tcp_svr();

    void force() {
      local.set_socket( tcp_socket() );
    }

    void setup_svr(){
      sckt::sockaddr_in addr; /* local address */

      /* Setup the local address */
      memset((void *) &addr, 0, sizeof(addr)); /* zero out structure */
      addr.sin_family = sckt::_AF_INET; /* Internet address family */
      addr.sin_addr.s_addr = sckt::htonl(sckt::_INADDR_ANY); /* any incoming interface */
      addr.sin_port = sckt::htons(local.get_port()); /* local port */

      /* Bind to the local address */
      if (sckt::bind(local.get_socket(), (sckt::sockaddr *) &addr, sizeof(addr)) < 0){
        throw new int; //TODO: Bind failed
      }

      /* Mark the socket so it will listen for incoming connections */
      // TODO VER MAXPENDING no codigo da Silvana
      if (sckt::listen(local.get_socket(), 3) < 0){
        throw new int; //TODO: Listen faileds
      }

    }

    bauer_node accept(){
      bauer_node client_node;
      sckt::sockaddr_in cliAddr; /* client address */
      unsigned int cliLen; /* length of client address data structure */

      /* Set the size of the in-out parameter */
      cliLen = sizeof(cliAddr);

      /* Wait for a client to connect */
      bsocket_t accept_d = sckt::accept(local.get_socket(), (sckt::sockaddr*) &cliAddr, &cliLen);

      if ( accept_d < 0) {
          throw new int; //TODO "Accept failed
      } else {
        client_node.set_socket(accept_d);
      }

      client_node.set_ip(sckt::inet_ntoa(cliAddr.sin_addr));
      client_node.set_port(cliAddr.sin_port);
      return client_node;
    }

    void start() {
      while (true) {
        //aceitando conexão de um nó remoto
        bauer_node remote = accept();
        //TODO: Implementar o Task Manager

      }
    }

  };
}

#endif<commit_msg>Implementa o server start<commit_after>#ifndef BAUERT_TCP_SVR
#define BAUERT_TCP_SVR

#include <iostream>
#include <string.h>
#include "socket_facade.h"
#include "bauer_node.hpp"
#include "bauer_types.hpp"
#include "bauer_tcp.hpp"

namespace bauer {
  template<class Tasker>
  class bauer_tcp_svr
  {
  private:
    bauer_node local;
    Tasker task_mng;
  public:

    bauer_tcp_svr(bauer_node _local) {
      /* Create a local communication endpoint */
      if ( _local.get_socket() < 0 ) _local.set_socket(tcp_socket());
      Tasker _task_mng();
      local = _local;
      task_mng = _task_mng;

      setup_svr();
    }

    ~bauer_tcp_svr();

    void force() {
      local.set_socket( tcp_socket() );
    }

    void setup_svr(){
      sckt::sockaddr_in addr; /* local address */

      /* Setup the local address */
      memset((void *) &addr, 0, sizeof(addr)); /* zero out structure */
      addr.sin_family = sckt::_AF_INET; /* Internet address family */
      addr.sin_addr.s_addr = sckt::htonl(sckt::_INADDR_ANY); /* any incoming interface */
      addr.sin_port = sckt::htons(local.get_port()); /* local port */

      /* Bind to the local address */
      if (sckt::bind(local.get_socket(), (sckt::sockaddr *) &addr, sizeof(addr)) < 0){
        throw new int; //TODO: Bind failed
      }

      /* Mark the socket so it will listen for incoming connections */
      // TODO VER MAXPENDING no codigo da Silvana
      if (sckt::listen(local.get_socket(), 3) < 0){
        throw new int; //TODO: Listen faileds
      }

    }

    bauer_node accept(){
      bauer_node client_node;
      sckt::sockaddr_in cliAddr; /* client address */
      unsigned int cliLen; /* length of client address data structure */

      /* Set the size of the in-out parameter */
      cliLen = sizeof(cliAddr);

      /* Wait for a client to connect */
      bsocket_t accept_d = sckt::accept(local.get_socket(), (sckt::sockaddr*) &cliAddr, &cliLen);

      if ( accept_d < 0) {
          throw new int; //TODO "Accept failed
      } else {
        client_node.set_socket(accept_d);
      }

      client_node.set_ip(sckt::inet_ntoa(cliAddr.sin_addr));
      client_node.set_port(cliAddr.sin_port);
      return client_node;
    }

    void start() {
      while (true) {
        //aceitando conexão de um nó remoto
        bauer_node remote = accept();
        task_mng.dispatcher_exec(remote);
      }
    }

  };
}

#endif<|endoftext|>


<commit_before>#include <cstdio>
#include <cstdlib>

#include <boost/filesystem.hpp>

#include <QPainter>
#include <QCache>

#include <tmx/TMX.h>
#include <tmx/TileLayer.h>

namespace fs = boost::filesystem;

class LayerRenderer : public tmx::LayerVisitor {
public:
  LayerRenderer()
  : map(nullptr), painter(), tilewidth(0), tileheight(0), width(0), height(0) { }

  void renderMap(const fs::path& map_path) {

    map = tmx::parseMapFile(map_path);

    if (!map) {
      return;
    }

    if (map->getOrientation() != tmx::Orientation::ORTHOGONAL) {
      std::printf("Can render only orthogonal maps. Exiting.\n");
      return;
    }

    tilewidth = map->getTileWidth();
    assert(tilewidth);

    tileheight = map->getTileHeight();
    assert(tileheight);

    width = map->getWidth();
    assert(width);

    height = map->getHeight();
    assert(height);

    // create surface

    QImage image(width * tilewidth, height * tileheight, QImage::Format_ARGB32);
    painter.begin(&image);
    map->visitLayers(*this);
    painter.end();

    std::printf("Saving image...\n");
    image.save("map.png");

    delete map;
  }

private:
  tmx::Map *map;

  QPainter painter;

  unsigned tilewidth;
  unsigned tileheight;
  unsigned width;
  unsigned height;

  QCache<QString, QImage> cache;

  QImage *getTexture(const fs::path& path) {
    QString str(path.string().c_str());
    QImage *img = cache.object(str);

    if (img != nullptr) {
      return img;
    }

    img = new QImage(str);
    assert(!img->isNull());

    cache.insert(str, img);
    return img;
  }

  void drawGID(const QPoint& origin, unsigned gid) {
    auto tileset = map->getTileSetFromGID(gid);
    assert(tileset);
    gid = gid - tileset->getFirstGID();

    if (tileset->hasImage()) {

      auto image = tileset->getImage();
      assert(image);

      QImage *texture = getTexture(image->getSource());
      QSize size = texture->size();

      unsigned margin = tileset->getMargin();
      unsigned spacing = tileset->getSpacing();
      QSize tilesize;
      tilesize.setWidth((size.width() - 2 * margin + spacing) / (tilewidth + spacing));
      tilesize.setHeight((size.height() - 2 * margin + spacing) / (tileheight + spacing));

      unsigned tu = gid % tilesize.width();
      unsigned tv = gid / tilesize.width();
      assert(tv < tilesize.height());

      unsigned du = margin + tu * spacing;
      unsigned dv = margin + tv * spacing;
      assert((tu + 1) * tilewidth + du < size.width());
      assert((tv + 1) * tileheight + dv < size.height());

      QRect rect(tu * tilewidth + du, tv * tileheight + dv, tilewidth, tileheight);
      painter.drawImage(origin, *texture, rect);

    } else {

      auto tile = tileset->getTile(gid);
      assert(tile);
      assert(tile->hasImage());

      auto image = tile->getImage();
      assert(image);

      QImage *texture = getTexture(image->getSource());
      painter.drawImage(origin, *texture);

    }
  }

public:
  virtual void visitTileLayer(tmx::TileLayer& layer) {
    if (!layer.isVisible()) {
      return;
    }

    std::printf("Rendering layer '%s'.\n", layer.getName().c_str());

    int k = 0;
    for (auto cell : layer) {
      int i = k % width;
      int j = k / width;
      assert(j < height);

      QPoint origin(i * tilewidth, j * tileheight);

      unsigned gid = cell.getGID();

      if (gid != 0) {
        drawGID(origin, gid);
      }

      k++;
    }

  }

};

int main(int argc, char *argv[]) {
  if (argc != 2) {
    std::printf("Usage: tmx_render <file.tmx>\n");
    return 1;
  }

  fs::path map_path(argv[1]);

  LayerRenderer renderer;
  renderer.renderMap(map_path);

  return 0;
}
<commit_msg>show images defined in objects<commit_after>#include <cstdio>
#include <cstdlib>

#include <boost/filesystem.hpp>

#include <QPainter>
#include <QCache>

#include <tmx/TMX.h>
#include <tmx/TileLayer.h>
#include <tmx/ObjectLayer.h>

namespace fs = boost::filesystem;

class LayerRenderer : public tmx::LayerVisitor {
public:
  LayerRenderer()
  : map(nullptr), painter(), tilewidth(0), tileheight(0), width(0), height(0) { }

  void renderMap(const fs::path& map_path) {

    map = tmx::parseMapFile(map_path);

    if (!map) {
      return;
    }

    if (map->getOrientation() != tmx::Orientation::ORTHOGONAL) {
      std::printf("Can render only orthogonal maps. Exiting.\n");
      return;
    }

    tilewidth = map->getTileWidth();
    assert(tilewidth);

    tileheight = map->getTileHeight();
    assert(tileheight);

    width = map->getWidth();
    assert(width);

    height = map->getHeight();
    assert(height);

    // create surface

    QImage image(width * tilewidth, height * tileheight, QImage::Format_ARGB32);
    painter.begin(&image);
    map->visitLayers(*this);
    painter.end();

    std::printf("Saving image...\n");
    image.save("map.png");

    delete map;
  }

private:
  tmx::Map *map;

  QPainter painter;

  unsigned tilewidth;
  unsigned tileheight;
  unsigned width;
  unsigned height;

  QCache<QString, QImage> cache;

  QImage *getTexture(const fs::path& path) {
    QString str(path.string().c_str());
    QImage *img = cache.object(str);

    if (img != nullptr) {
      return img;
    }

    img = new QImage(str);
    assert(!img->isNull());

    cache.insert(str, img);
    return img;
  }

  enum class Alignment {
    TOP_LEFT,
    BOTTOM_LEFT,
  };

  void drawGID(const QPoint& origin, unsigned gid, Alignment align) {
    auto tileset = map->getTileSetFromGID(gid);
    assert(tileset);
    gid = gid - tileset->getFirstGID();

    if (tileset->hasImage()) {

      auto image = tileset->getImage();
      assert(image);

      QImage *texture = getTexture(image->getSource());
      QSize size = texture->size();
      assert(size.width() >= 0);
      assert(size.height() >= 0);

      tmx::Rect rect = tileset->getCoords(gid, { static_cast<unsigned>(size.width()), static_cast<unsigned>(size.height()) });
      QPoint offset;

      if (align == Alignment::BOTTOM_LEFT) {
        offset.ry() -= rect.height;
      }

      painter.drawImage(origin + offset, *texture, QRect(rect.x, rect.y, rect.width, rect.height));

    } else {

      auto tile = tileset->getTile(gid);
      assert(tile);
      assert(tile->hasImage());

      auto image = tile->getImage();
      assert(image);

      QImage *texture = getTexture(image->getSource());
      painter.drawImage(origin, *texture);

    }
  }

public:
  virtual void visitTileLayer(tmx::TileLayer& layer) {
    if (!layer.isVisible()) {
      return;
    }

    std::printf("Rendering tile layer '%s'.\n", layer.getName().c_str());

    unsigned k = 0;
    for (auto cell : layer) {
      unsigned i = k % width;
      unsigned j = k / width;
      assert(j < height);

      QPoint origin(i * tilewidth, j * tileheight);

      unsigned gid = cell.getGID();

      if (gid != 0) {
        drawGID(origin, gid, Alignment::TOP_LEFT);
      }

      k++;
    }

  }

  virtual void visitObjectLayer(tmx::ObjectLayer &layer) {
    if (!layer.isVisible()) {
      return;
    }

    std::printf("Rendering object layer '%s'.\n", layer.getName().c_str());

    for (auto obj : layer) {
      if (!obj->isTile()) {
        continue;
      }

      auto tile = static_cast<tmx::TileObject *>(obj);

      QPoint origin(tile->getX(), tile->getY());

      unsigned gid = tile->getGID();
      assert(gid != 0);

      drawGID(origin, gid, Alignment::BOTTOM_LEFT);
    }

  }

};

int main(int argc, char *argv[]) {
  if (argc != 2) {
    std::printf("Usage: tmx_render <file.tmx>\n");
    return 1;
  }

  fs::path map_path(argv[1]);

  LayerRenderer renderer;
  renderer.renderMap(map_path);

  return 0;
}
<|endoftext|>


<commit_before>// Sandstorm Blackrock
// Copyright (c) 2015 Sandstorm Development Group, 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 "gce.h"
#include <kj/debug.h>
#include <unistd.h>
#include <fcntl.h>
#include <sandstorm/util.h>
#include <capnp/serialize-async.h>

#include <stdio.h>
#include <stdlib.h>

namespace blackrock {

namespace {

// TODO(cleanup): Share this code with version in master.c++.
kj::Promise<kj::String> readAllAsync(kj::AsyncInputStream& input,
                                     kj::Vector<char> buffer = kj::Vector<char>()) {
  buffer.resize(buffer.size() + 4096);
  auto promise = input.tryRead(buffer.end() - 4096, 4096, 4096);
  return promise.then([KJ_MVCAP(buffer),&input](size_t n) mutable -> kj::Promise<kj::String> {
    if (n < 4096) {
      buffer.resize(buffer.size() - 4096 + n);
      buffer.add('\0');
      return kj::String(buffer.releaseAsArray());
    } else {
      return readAllAsync(input, kj::mv(buffer));
    }
  });
}

static kj::String getImageName() {
  char buffer[256];
  ssize_t n;
  KJ_SYSCALL(n = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1));
  buffer[n] = '\0';
  kj::StringPtr exeName(buffer);
  return sandstorm::trim(exeName.slice(KJ_ASSERT_NONNULL(exeName.findLast('/')) + 1));
}

}  // namespace

GceDriver::GceDriver(sandstorm::SubprocessSet& subprocessSet,
                     kj::LowLevelAsyncIoProvider& ioProvider,
                     GceConfig::Reader config)
    : subprocessSet(subprocessSet), ioProvider(ioProvider), config(config), image(getImageName()),
      masterBindAddress(SimpleAddress::getInterfaceAddress(AF_INET, "eth0")),
      logTask(nullptr), logSinkAddress(masterBindAddress) {
  // Create socket for the log sink acceptor.
  int sock;
  KJ_SYSCALL(sock = socket(masterBindAddress.family(),
      SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
  {
    KJ_ON_SCOPE_FAILURE(close(sock));
    logSinkAddress.setPort(0);
    KJ_SYSCALL(bind(sock, logSinkAddress.asSockaddr(), logSinkAddress.getSockaddrSize()));
    KJ_SYSCALL(listen(sock, SOMAXCONN));

    // Read back the assigned port number.
    logSinkAddress = SimpleAddress::getLocal(sock);
  }

  // Accept log connections.
  auto listener = ioProvider.wrapListenSocketFd(sock,
      kj::LowLevelAsyncIoProvider::TAKE_OWNERSHIP |
      kj::LowLevelAsyncIoProvider::ALREADY_CLOEXEC |
      kj::LowLevelAsyncIoProvider::ALREADY_NONBLOCK);

  logTask = logSink.acceptLoop(kj::mv(listener))
      .eagerlyEvaluate([](kj::Exception&& exception) {
    KJ_LOG(ERROR, "LogSink accept loop failed", exception);
  });
}

GceDriver::~GceDriver() noexcept(false) {}

SimpleAddress GceDriver::getMasterBindAddress() {
  return masterBindAddress;
}

auto GceDriver::listMachines() -> kj::Promise<kj::Array<MachineId>> {
  int fds[2];
  KJ_SYSCALL(pipe2(fds, O_CLOEXEC));
  kj::AutoCloseFd writeEnd(fds[1]);
  auto input = ioProvider.wrapInputFd(fds[0],
      kj::LowLevelAsyncIoProvider::Flags::TAKE_OWNERSHIP |
      kj::LowLevelAsyncIoProvider::Flags::ALREADY_CLOEXEC);

  auto exitPromise = gceCommand({"echo","list-all-machine"}, STDIN_FILENO, writeEnd);

  auto outputPromise = readAllAsync(*input);
  return outputPromise.attach(kj::mv(input))
      .then([this,KJ_MVCAP(exitPromise)](kj::String allText) mutable {
    kj::Vector<MachineId> result;

    kj::StringPtr text = allText;
    kj::Maybe<MachineId> lastSeenMachine;
    kj::Vector<kj::Promise<void>> promises;

    promises.add(kj::mv(exitPromise));

    lastSeenMachine = MachineId("frontend0");
    result.add(KJ_ASSERT_NONNULL(lastSeenMachine));

    lastSeenMachine = MachineId("mongo0");
    result.add(KJ_ASSERT_NONNULL(lastSeenMachine));

    lastSeenMachine = MachineId("storage0");
    result.add(KJ_ASSERT_NONNULL(lastSeenMachine));

    lastSeenMachine = MachineId("worker0");
    result.add(KJ_ASSERT_NONNULL(lastSeenMachine));

    KJ_LOG(INFO, "add all machines");

    return kj::joinPromises(promises.releaseAsArray())
        .then([KJ_MVCAP(result)]() mutable { return result.releaseAsArray(); });
  });
}

kj::Promise<void> GceDriver::boot(MachineId id) {
  kj::String name = kj::str(id);
  args.addAll(std::initializer_list<const kj::StringPtr> { "echo", name, "NEED-BOOT" });
  return gceCommand(args);
}

kj::Promise<VatPath::Reader> GceDriver::run(
    MachineId id, blackrock::VatId::Reader masterVatId, bool requireRestartProcess) {
  kj::String name = kj::str(id);

  int fds[2];
  KJ_SYSCALL(pipe2(fds, O_CLOEXEC));
  kj::AutoCloseFd stdinReadEnd(fds[0]);
  auto stdinWriteEnd = ioProvider.wrapOutputFd(fds[1],
      kj::LowLevelAsyncIoProvider::Flags::TAKE_OWNERSHIP |
      kj::LowLevelAsyncIoProvider::Flags::ALREADY_CLOEXEC);
  KJ_SYSCALL(pipe2(fds, O_CLOEXEC));
  kj::AutoCloseFd stdoutWriteEnd(fds[1]);
  auto stdoutReadEnd = ioProvider.wrapInputFd(fds[0],
      kj::LowLevelAsyncIoProvider::Flags::TAKE_OWNERSHIP |
      kj::LowLevelAsyncIoProvider::Flags::ALREADY_CLOEXEC);

  auto addr = kj::str(logSinkAddress, '/', name);
  auto target = kj::str("root@", name);
  kj::Vector<kj::StringPtr> args;
  auto command = kj::str("/blackrock/bin/blackrock slave --log ", addr, " if4:eth0");
  args.addAll(kj::ArrayPtr<const kj::StringPtr>({
      "ssh", target, command}));

  auto exitPromise = gceCommand(args, stdinReadEnd, stdoutWriteEnd);

  auto message = kj::heap<capnp::MallocMessageBuilder>(masterVatId.totalSize().wordCount + 4);
  message->setRoot(masterVatId);

  auto& stdoutReadEndRef = *stdoutReadEnd;
  return capnp::writeMessage(*stdinWriteEnd, *message)
      .attach(kj::mv(stdinWriteEnd), kj::mv(message))
      .then([&stdoutReadEndRef]() {
    return capnp::readMessage(stdoutReadEndRef);
  }).then([this,id,KJ_MVCAP(exitPromise),KJ_MVCAP(stdoutReadEnd)](
      kj::Own<capnp::MessageReader> reader) mutable {
    auto path = reader->getRoot<VatPath>();
    vatPaths[id] = kj::mv(reader);
    return exitPromise.then([path]() { return path; });
  });
}

kj::Promise<void> GceDriver::stop(MachineId id) {
  kj::String name = kj::str(id);
  return gceCommand({"echo", name, "NEED-STOP"});
}

kj::Promise<void> GceDriver::gceCommand(kj::ArrayPtr<const kj::StringPtr> args,
                                        int stdin, int stdout) {
  auto fullArgs = kj::heapArrayBuilder<const kj::StringPtr>(args.size());
  fullArgs.addAll(args);

  sandstorm::Subprocess::Options options(fullArgs.finish());
  auto command = kj::strArray(options.argv, " ");
  KJ_LOG(INFO, command);
  options.stdin = stdin;
  options.stdout = stdout;
  return subprocessSet.waitForSuccess(kj::mv(options));
}

} // namespace blackrock

<commit_msg>clear code<commit_after>// Sandstorm Blackrock
// Copyright (c) 2015 Sandstorm Development Group, 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 "gce.h"
#include <kj/debug.h>
#include <unistd.h>
#include <fcntl.h>
#include <sandstorm/util.h>
#include <capnp/serialize-async.h>

#include <stdio.h>
#include <stdlib.h>

namespace blackrock {

namespace {

// TODO(cleanup): Share this code with version in master.c++.
kj::Promise<kj::String> readAllAsync(kj::AsyncInputStream& input,
                                     kj::Vector<char> buffer = kj::Vector<char>()) {
  buffer.resize(buffer.size() + 4096);
  auto promise = input.tryRead(buffer.end() - 4096, 4096, 4096);
  return promise.then([KJ_MVCAP(buffer),&input](size_t n) mutable -> kj::Promise<kj::String> {
    if (n < 4096) {
      buffer.resize(buffer.size() - 4096 + n);
      buffer.add('\0');
      return kj::String(buffer.releaseAsArray());
    } else {
      return readAllAsync(input, kj::mv(buffer));
    }
  });
}

static kj::String getImageName() {
  char buffer[256];
  ssize_t n;
  KJ_SYSCALL(n = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1));
  buffer[n] = '\0';
  kj::StringPtr exeName(buffer);
  return sandstorm::trim(exeName.slice(KJ_ASSERT_NONNULL(exeName.findLast('/')) + 1));
}

}  // namespace

GceDriver::GceDriver(sandstorm::SubprocessSet& subprocessSet,
                     kj::LowLevelAsyncIoProvider& ioProvider,
                     GceConfig::Reader config)
    : subprocessSet(subprocessSet), ioProvider(ioProvider), config(config), image(getImageName()),
      masterBindAddress(SimpleAddress::getInterfaceAddress(AF_INET, "eth0")),
      logTask(nullptr), logSinkAddress(masterBindAddress) {
  // Create socket for the log sink acceptor.
  int sock;
  KJ_SYSCALL(sock = socket(masterBindAddress.family(),
      SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
  {
    KJ_ON_SCOPE_FAILURE(close(sock));
    logSinkAddress.setPort(0);
    KJ_SYSCALL(bind(sock, logSinkAddress.asSockaddr(), logSinkAddress.getSockaddrSize()));
    KJ_SYSCALL(listen(sock, SOMAXCONN));

    // Read back the assigned port number.
    logSinkAddress = SimpleAddress::getLocal(sock);
  }

  // Accept log connections.
  auto listener = ioProvider.wrapListenSocketFd(sock,
      kj::LowLevelAsyncIoProvider::TAKE_OWNERSHIP |
      kj::LowLevelAsyncIoProvider::ALREADY_CLOEXEC |
      kj::LowLevelAsyncIoProvider::ALREADY_NONBLOCK);

  logTask = logSink.acceptLoop(kj::mv(listener))
      .eagerlyEvaluate([](kj::Exception&& exception) {
    KJ_LOG(ERROR, "LogSink accept loop failed", exception);
  });
}

GceDriver::~GceDriver() noexcept(false) {}

SimpleAddress GceDriver::getMasterBindAddress() {
  return masterBindAddress;
}

auto GceDriver::listMachines() -> kj::Promise<kj::Array<MachineId>> {
  int fds[2];
  KJ_SYSCALL(pipe2(fds, O_CLOEXEC));
  kj::AutoCloseFd writeEnd(fds[1]);
  auto input = ioProvider.wrapInputFd(fds[0],
      kj::LowLevelAsyncIoProvider::Flags::TAKE_OWNERSHIP |
      kj::LowLevelAsyncIoProvider::Flags::ALREADY_CLOEXEC);

  auto exitPromise = gceCommand({"echo","list-all-machine"}, STDIN_FILENO, writeEnd);

  auto outputPromise = readAllAsync(*input);
  return outputPromise.attach(kj::mv(input))
      .then([this,KJ_MVCAP(exitPromise)](kj::String allText) mutable {
    kj::Vector<MachineId> result;

    kj::StringPtr text = allText;
    kj::Maybe<MachineId> lastSeenMachine;
    kj::Vector<kj::Promise<void>> promises;

    promises.add(kj::mv(exitPromise));

    lastSeenMachine = MachineId("frontend0");
    result.add(KJ_ASSERT_NONNULL(lastSeenMachine));

    lastSeenMachine = MachineId("mongo0");
    result.add(KJ_ASSERT_NONNULL(lastSeenMachine));

    lastSeenMachine = MachineId("storage0");
    result.add(KJ_ASSERT_NONNULL(lastSeenMachine));

    lastSeenMachine = MachineId("worker0");
    result.add(KJ_ASSERT_NONNULL(lastSeenMachine));

    return kj::joinPromises(promises.releaseAsArray())
        .then([KJ_MVCAP(result)]() mutable { return result.releaseAsArray(); });
  });
}

kj::Promise<void> GceDriver::boot(MachineId id) {
  kj::String name = kj::str(id);
  args.addAll(std::initializer_list<const kj::StringPtr> { "echo", name, "NEED-BOOT" });
  return gceCommand(args);
}

kj::Promise<VatPath::Reader> GceDriver::run(
    MachineId id, blackrock::VatId::Reader masterVatId, bool requireRestartProcess) {
  kj::String name = kj::str(id);

  int fds[2];
  KJ_SYSCALL(pipe2(fds, O_CLOEXEC));
  kj::AutoCloseFd stdinReadEnd(fds[0]);
  auto stdinWriteEnd = ioProvider.wrapOutputFd(fds[1],
      kj::LowLevelAsyncIoProvider::Flags::TAKE_OWNERSHIP |
      kj::LowLevelAsyncIoProvider::Flags::ALREADY_CLOEXEC);
  KJ_SYSCALL(pipe2(fds, O_CLOEXEC));
  kj::AutoCloseFd stdoutWriteEnd(fds[1]);
  auto stdoutReadEnd = ioProvider.wrapInputFd(fds[0],
      kj::LowLevelAsyncIoProvider::Flags::TAKE_OWNERSHIP |
      kj::LowLevelAsyncIoProvider::Flags::ALREADY_CLOEXEC);

  auto addr = kj::str(logSinkAddress, '/', name);
  auto target = kj::str("root@", name);
  kj::Vector<kj::StringPtr> args;
  auto command = kj::str("/blackrock/bin/blackrock slave --log ", addr, " if4:eth0");
  args.addAll(kj::ArrayPtr<const kj::StringPtr>({
      "ssh", target, command}));

  auto exitPromise = gceCommand(args, stdinReadEnd, stdoutWriteEnd);

  auto message = kj::heap<capnp::MallocMessageBuilder>(masterVatId.totalSize().wordCount + 4);
  message->setRoot(masterVatId);

  auto& stdoutReadEndRef = *stdoutReadEnd;
  return capnp::writeMessage(*stdinWriteEnd, *message)
      .attach(kj::mv(stdinWriteEnd), kj::mv(message))
      .then([&stdoutReadEndRef]() {
    return capnp::readMessage(stdoutReadEndRef);
  }).then([this,id,KJ_MVCAP(exitPromise),KJ_MVCAP(stdoutReadEnd)](
      kj::Own<capnp::MessageReader> reader) mutable {
    auto path = reader->getRoot<VatPath>();
    vatPaths[id] = kj::mv(reader);
    return exitPromise.then([path]() { return path; });
  });
}

kj::Promise<void> GceDriver::stop(MachineId id) {
  kj::String name = kj::str(id);
  return gceCommand({"echo", name, "NEED-STOP"});
}

kj::Promise<void> GceDriver::gceCommand(kj::ArrayPtr<const kj::StringPtr> args,
                                        int stdin, int stdout) {
  auto fullArgs = kj::heapArrayBuilder<const kj::StringPtr>(args.size());
  fullArgs.addAll(args);
  sandstorm::Subprocess::Options options(fullArgs.finish());
  auto command = kj::strArray(options.argv, " ");
  KJ_LOG(INFO, command);
  options.stdin = stdin;
  options.stdout = stdout;
  return subprocessSet.waitForSuccess(kj::mv(options));
}

} // namespace blackrock

<|endoftext|>


<commit_before>#include "board_metrics.h"

#include <iostream>

namespace {

bool CellStatusChangesInDirection(
    const TBoard& board,
    const TSegment& from,
    EMoveOperations to
) {
    const auto& fromPos = from.GetPosition();
    bool status1 = board.CellIsLocked(fromPos.Column, fromPos.Row);
    TSegment afterMove = from.Slide(to);

    if (board.SegmentPosIsValid(afterMove)) {
        const auto& afterMovePos = afterMove.GetPosition();
        bool status2 = board.CellIsLocked(afterMovePos.Column, afterMovePos.Row);

        return status1 != status2;
    }

    return false;
}

} // unnamed namespace

int CalulateMetrics(const TBoard& board, const TUnit& unit) {
    TBoard modifiedBoard(board);

    for (const auto& segment : unit.GetSegments()) {
        const auto& position = segment.GetPosition();
        modifiedBoard.LockCell(position.Column, position.Row);
    }

    size_t numOfRowTransitions = 0;
    size_t numOfSouthEastTransitions = 0;
    size_t numOfSouthWestTransitions = 0;

    for (size_t columnNum = 0; columnNum < modifiedBoard.GetColumnCount(); ++columnNum) {
        for (size_t rowNum = 0; rowNum < modifiedBoard.GetRowCount(); ++rowNum) {
            TSegment segment(Coords::TColRowPoint(columnNum, rowNum));

            bool rowTransitionPresent = CellStatusChangesInDirection(
                modifiedBoard,
                segment,
                EMoveOperations::SLIDE_EAST
            );
            bool seTransitionPresent = CellStatusChangesInDirection(
                modifiedBoard,
                segment,
                EMoveOperations::SLIDE_SOUTHEAST
            );
            bool swTransitionPresent = CellStatusChangesInDirection(
                modifiedBoard,
                segment,
                EMoveOperations::SLIDE_SOUTHWEST
            );

            numOfRowTransitions += rowTransitionPresent ? 1 : 0;
            numOfSouthEastTransitions += seTransitionPresent ? 1 : 0;
            numOfSouthWestTransitions += swTransitionPresent ? 1 : 0;
        }
    }

    size_t rowsCollaped = modifiedBoard.CollapseRows();

    int ret = -3.2178882868487753 * numOfRowTransitions
        + -4.674347653 * numOfSouthEastTransitions
        + -4.674347653 * numOfSouthWestTransitions
        + 3.4181268101392694 * rowsCollaped;

    std::cout << "Metrics: " << ret << std::endl;
    std::cout << rowsCollaped << " " << numOfRowTransitions << " "
        << numOfSouthEastTransitions << " "
        << numOfSouthWestTransitions << std::endl;

    return ret;
}
<commit_msg>added unit height to metrics calculations<commit_after>#include "board_metrics.h"

#include <iostream>

namespace {

bool CellStatusChangesInDirection(
    const TBoard& board,
    const TSegment& from,
    EMoveOperations to
) {
    const auto& fromPos = from.GetPosition();
    bool status1 = board.CellIsLocked(fromPos.Column, fromPos.Row);
    TSegment afterMove = from.Slide(to);

    if (board.SegmentPosIsValid(afterMove)) {
        const auto& afterMovePos = afterMove.GetPosition();
        bool status2 = board.CellIsLocked(afterMovePos.Column, afterMovePos.Row);

        return status1 != status2;
    }

    return false;
}

} // unnamed namespace

int CalulateMetrics(const TBoard& board, const TUnit& unit) {
    TBoard modifiedBoard(board);

    for (const auto& segment : unit.GetSegments()) {
        const auto& position = segment.GetPosition();
        modifiedBoard.LockCell(position.Column, position.Row);
    }

    size_t numOfRowTransitions = 0;
    size_t numOfSouthEastTransitions = 0;
    size_t numOfSouthWestTransitions = 0;

    for (size_t columnNum = 0; columnNum < modifiedBoard.GetColumnCount(); ++columnNum) {
        for (size_t rowNum = 0; rowNum < modifiedBoard.GetRowCount(); ++rowNum) {
            TSegment segment(Coords::TColRowPoint(columnNum, rowNum));

            bool rowTransitionPresent = CellStatusChangesInDirection(
                modifiedBoard,
                segment,
                EMoveOperations::SLIDE_EAST
            );
            bool seTransitionPresent = CellStatusChangesInDirection(
                modifiedBoard,
                segment,
                EMoveOperations::SLIDE_SOUTHEAST
            );
            bool swTransitionPresent = CellStatusChangesInDirection(
                modifiedBoard,
                segment,
                EMoveOperations::SLIDE_SOUTHWEST
            );

            numOfRowTransitions += rowTransitionPresent ? 1 : 0;
            numOfSouthEastTransitions += seTransitionPresent ? 1 : 0;
            numOfSouthWestTransitions += swTransitionPresent ? 1 : 0;
        }
    }

    size_t rowsCollaped = modifiedBoard.CollapseRows();
    size_t pivotRow = unit.GetPivot().GetPosition().Row;

    int ret = -3.2178882868487753 * numOfRowTransitions
        + -4.674347653 * numOfSouthEastTransitions
        + -4.674347653 * numOfSouthWestTransitions
        + 3.4181268101392694 * rowsCollaped
        + 4.500158825082766 * pivotRow;

    std::cout << "Metrics: " << ret << std::endl;
    std::cout << rowsCollaped << " " << pivotRow << "\t\t" << numOfRowTransitions << " "
        << numOfSouthEastTransitions << " "
        << numOfSouthWestTransitions << std::endl;

    return ret;
}
<|endoftext|>


<commit_before>/*
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * 1. Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``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
 * <COPYRIGHT HOLDER> 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 "tree_index.h"
#include "tuple.h"
#include "space.h"
#include "exception.h"
#include "errinj.h"
#include "memory.h"
#include "fiber.h"
#include <third_party/qsort_arg.h>

/** For all memory used by all tree indexes. */
static struct mempool tree_extent_pool;
/** Number of allocated extents. */
static int tree_extent_pool_initialized = 0;

/* {{{ Utilities. *************************************************/

struct key_data
{
	const char *key;
	uint32_t part_count;
};

int
tree_index_compare(const tuple *a, const tuple *b, struct key_def *key_def)
{
	int r = tuple_compare(a, b, key_def);
	if (r == 0 && !key_def->is_unique)
		r = a < b ? -1 : a > b;
	return r;
}
int
tree_index_compare_key(const tuple *a, const key_data *key_data,
		       struct key_def *key_def)
{
	return tuple_compare_with_key(a, key_data->key, key_data->part_count,
				      key_def);
}
int tree_index_qcompare(const void* a, const void *b, void *c)
{
	return tree_index_compare(*(struct tuple **)a,
		*(struct tuple **)b, (struct key_def *)c);
}

/* {{{ TreeIndex Iterators ****************************************/
struct tree_iterator {
	struct iterator base;
	const struct bps_tree_index *tree;
	struct key_def *key_def;
	struct bps_tree_index_iterator bps_tree_iter;
	struct key_data key_data;
};

static void
tree_iterator_free(struct iterator *iterator);

static inline struct tree_iterator *
tree_iterator(struct iterator *it)
{
	assert(it->free == tree_iterator_free);
	return (struct tree_iterator *) it;
}

static void
tree_iterator_free(struct iterator *iterator)
{
	free(iterator);
}

static struct tuple *
tree_iterator_dummie(struct iterator *iterator)
{
	(void)iterator;
	return 0;
}

static struct tuple *
tree_iterator_fwd(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	tuple **res = bps_tree_index_itr_get_elem(it->tree, &it->bps_tree_iter);
	if (!res)
		return 0;
	bps_tree_index_itr_next(it->tree, &it->bps_tree_iter);
	return *res;
}

static struct tuple *
tree_iterator_bwd(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	tuple **res = bps_tree_index_itr_get_elem(it->tree, &it->bps_tree_iter);
	if (!res)
		return 0;
	bps_tree_index_itr_prev(it->tree, &it->bps_tree_iter);
	return *res;
}

static struct tuple *
tree_iterator_fwd_check_equality(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	tuple **res = bps_tree_index_itr_get_elem(it->tree, &it->bps_tree_iter);
	if (!res)
		return 0;
	if (tree_index_compare_key(*res, &it->key_data, it->key_def) != 0) {
		it->bps_tree_iter = bps_tree_index_invalid_iterator();
		return 0;
	}
	bps_tree_index_itr_next(it->tree, &it->bps_tree_iter);
	return *res;
}

static struct tuple *
tree_iterator_fwd_check_next_equality(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	tuple **res = bps_tree_index_itr_get_elem(it->tree, &it->bps_tree_iter);
	if (!res)
		return 0;
	bps_tree_index_itr_next(it->tree, &it->bps_tree_iter);
	iterator->next = tree_iterator_fwd_check_equality;
	return *res;
}

static struct tuple *
tree_iterator_bwd_skip_one(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	bps_tree_index_itr_prev(it->tree, &it->bps_tree_iter);
	iterator->next = tree_iterator_bwd;
	return tree_iterator_bwd(iterator);
}

static struct tuple *
tree_iterator_bwd_check_equality(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	tuple **res = bps_tree_index_itr_get_elem(it->tree, &it->bps_tree_iter);
	if (!res)
		return 0;
	if (tree_index_compare_key(*res, &it->key_data, it->key_def) != 0) {
		it->bps_tree_iter = bps_tree_index_invalid_iterator();
		return 0;
	}
	bps_tree_index_itr_prev(it->tree, &it->bps_tree_iter);
	return *res;
}

static struct tuple *
tree_iterator_bwd_skip_one_check_next_equality(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	bps_tree_index_itr_prev(it->tree, &it->bps_tree_iter);
	iterator->next = tree_iterator_bwd_check_equality;
	return tree_iterator_bwd_check_equality(iterator);
}
/* }}} */

/* {{{ TreeIndex  **********************************************************/

static void *
extent_alloc()
{
	ERROR_INJECT(ERRINJ_INDEX_ALLOC, return 0);
	return mempool_alloc(&tree_extent_pool);
}

static void
extent_free(void *extent)
{
	return mempool_free(&tree_extent_pool, extent);
}

TreeIndex::TreeIndex(struct key_def *key_def_arg)
	: Index(key_def_arg), build_array(0), build_array_size(0),
	  build_array_alloc_size(0)
{
	if (tree_extent_pool_initialized == 0) {
		mempool_create(&tree_extent_pool, &memtx_slab_cache,
			       BPS_TREE_EXTENT_SIZE);
		tree_extent_pool_initialized = 1;
	}
	bps_tree_index_create(&tree, key_def, extent_alloc, extent_free);
}

TreeIndex::~TreeIndex()
{
	bps_tree_index_destroy(&tree);
	free(build_array);
}

size_t
TreeIndex::size() const
{
	return bps_tree_index_size(&tree);
}

size_t
TreeIndex::memsize() const
{
	return bps_tree_index_mem_used(&tree);
}

struct tuple *
TreeIndex::random(uint32_t rnd) const
{
	struct tuple **res = bps_tree_index_random(&tree, rnd);
	return res ? *res : 0;
}

struct tuple *
TreeIndex::findByKey(const char *key, uint32_t part_count) const
{
	assert(key_def->is_unique && part_count == key_def->part_count);

	struct key_data key_data;
	key_data.key = key;
	key_data.part_count = part_count;
	struct tuple **res = bps_tree_index_find(&tree, &key_data);
	return res ? *res : 0;
}

struct tuple *
TreeIndex::replace(struct tuple *old_tuple, struct tuple *new_tuple,
		   enum dup_replace_mode mode)
{
	uint32_t errcode;

	if (new_tuple) {
		struct tuple *dup_tuple = NULL;

		/* Try to optimistically replace the new_tuple. */
		bool tree_res =
		bps_tree_index_insert(&tree, new_tuple, &dup_tuple);
		if (!tree_res) {
			tnt_raise(ClientError, ER_MEMORY_ISSUE,
				  BPS_TREE_EXTENT_SIZE, "TreeIndex", "replace");
		}

		errcode = replace_check_dup(old_tuple, dup_tuple, mode);

		if (errcode) {
			bps_tree_index_delete(&tree, new_tuple);
			if (dup_tuple)
				bps_tree_index_insert(&tree, dup_tuple, 0);
			tnt_raise(ClientError, errcode, index_id(this));
		}
		if (dup_tuple)
			return dup_tuple;
	}
	if (old_tuple) {
		bps_tree_index_delete(&tree, old_tuple);
	}
	return old_tuple;
}

struct iterator *
TreeIndex::allocIterator() const
{
	struct tree_iterator *it = (struct tree_iterator *)
			calloc(1, sizeof(*it));
	if (it == NULL) {
		tnt_raise(ClientError, ER_MEMORY_ISSUE,
			  sizeof(struct tree_iterator),
			  "TreeIndex", "iterator");
	}

	it->key_def = key_def;
	it->tree = &tree;
	it->base.free = tree_iterator_free;
	it->bps_tree_iter = bps_tree_index_invalid_iterator();
	return (struct iterator *) it;
}

void
TreeIndex::initIterator(struct iterator *iterator, enum iterator_type type,
			const char *key, uint32_t part_count) const
{
	assert(part_count == 0 || key != NULL);
	struct tree_iterator *it = tree_iterator(iterator);

	if (part_count == 0) {
		/*
		 * If no key is specified, downgrade equality
		 * iterators to a full range.
		 */
		if (type < 0 || type > ITER_GT)
			tnt_raise(ClientError, ER_UNSUPPORTED,
				  "Tree index", "requested iterator type");
		type = iterator_type_is_reverse(type) ? ITER_LE : ITER_GE;
		key = 0;
	}
	it->key_data.key = key;
	it->key_data.part_count = part_count;

	bool exact = false;
	if (key == 0) {
		if (iterator_type_is_reverse(type))
			it->bps_tree_iter = bps_tree_index_invalid_iterator();
		else
			it->bps_tree_iter = bps_tree_index_itr_first(&tree);
	} else {
		if (type == ITER_ALL || type == ITER_EQ || type == ITER_GE || type == ITER_LT) {
			it->bps_tree_iter = bps_tree_index_lower_bound(&tree, &it->key_data, &exact);
			if (type == ITER_EQ && !exact) {
				it->base.next = tree_iterator_dummie;
				return;
			}
		} else { // ITER_GT, ITER_REQ, ITER_LE
			it->bps_tree_iter = bps_tree_index_upper_bound(&tree, &it->key_data, &exact);
			if (type == ITER_REQ && !exact) {
				it->base.next = tree_iterator_dummie;
				return;
			}
		}
	}

	switch (type) {
	case ITER_EQ:
		it->base.next = tree_iterator_fwd_check_next_equality;
		break;
	case ITER_REQ:
		it->base.next = tree_iterator_bwd_skip_one_check_next_equality;
		break;
	case ITER_ALL:
	case ITER_GE:
		it->base.next = tree_iterator_fwd;
		break;
	case ITER_GT:
		it->base.next = tree_iterator_fwd;
		break;
	case ITER_LE:
		it->base.next = tree_iterator_bwd_skip_one;
		break;
	case ITER_LT:
		it->base.next = tree_iterator_bwd_skip_one;
		break;
	default:
		tnt_raise(ClientError, ER_UNSUPPORTED,
			  "Tree index", "requested iterator type");
	}
}

void
TreeIndex::beginBuild()
{
	assert(bps_tree_index_size(&tree) == 0);
}

void
TreeIndex::reserve(uint32_t size_hint)
{
	if (size_hint < build_array_alloc_size)
		return;
	build_array = (struct tuple**)
		realloc(build_array, size_hint * sizeof(struct tuple *));
	build_array_alloc_size = size_hint;
}

void
TreeIndex::buildNext(struct tuple *tuple)
{
	if (!build_array) {
		build_array = (struct tuple**)malloc(BPS_TREE_EXTENT_SIZE);
		build_array_alloc_size =
			BPS_TREE_EXTENT_SIZE / sizeof(struct tuple*);
	}
	assert(build_array_size <= build_array_alloc_size);
	if (build_array_size == build_array_alloc_size) {
		build_array_alloc_size = build_array_alloc_size +
					 build_array_alloc_size / 2;
		build_array = (struct tuple**)
			realloc(build_array,
				build_array_alloc_size *
				sizeof(struct tuple *));
	}
	build_array[build_array_size++] = tuple;
}

void
TreeIndex::endBuild()
{
	qsort_arg(build_array, build_array_size, sizeof(struct tuple *), tree_index_qcompare, key_def);
	bps_tree_index_build(&tree, build_array, build_array_size);

	free(build_array);
	build_array = 0;
	build_array_size = 0;
	build_array_alloc_size = 0;
}

<commit_msg>Remove a regression I introduced by switching TreeIndex to memtx_arena<commit_after>/*
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * 1. Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``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
 * <COPYRIGHT HOLDER> 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 "tree_index.h"
#include "tuple.h"
#include "space.h"
#include "exception.h"
#include "errinj.h"
#include "memory.h"
#include "fiber.h"
#include <third_party/qsort_arg.h>

/** For all memory used by all tree indexes. */
static struct mempool tree_extent_pool;
/** Number of allocated extents. */
static int tree_extent_pool_initialized = 0;

/* {{{ Utilities. *************************************************/

struct key_data
{
	const char *key;
	uint32_t part_count;
};

int
tree_index_compare(const tuple *a, const tuple *b, struct key_def *key_def)
{
	int r = tuple_compare(a, b, key_def);
	if (r == 0 && !key_def->is_unique)
		r = a < b ? -1 : a > b;
	return r;
}
int
tree_index_compare_key(const tuple *a, const key_data *key_data,
		       struct key_def *key_def)
{
	return tuple_compare_with_key(a, key_data->key, key_data->part_count,
				      key_def);
}
int tree_index_qcompare(const void* a, const void *b, void *c)
{
	return tree_index_compare(*(struct tuple **)a,
		*(struct tuple **)b, (struct key_def *)c);
}

/* {{{ TreeIndex Iterators ****************************************/
struct tree_iterator {
	struct iterator base;
	const struct bps_tree_index *tree;
	struct key_def *key_def;
	struct bps_tree_index_iterator bps_tree_iter;
	struct key_data key_data;
};

static void
tree_iterator_free(struct iterator *iterator);

static inline struct tree_iterator *
tree_iterator(struct iterator *it)
{
	assert(it->free == tree_iterator_free);
	return (struct tree_iterator *) it;
}

static void
tree_iterator_free(struct iterator *iterator)
{
	free(iterator);
}

static struct tuple *
tree_iterator_dummie(struct iterator *iterator)
{
	(void)iterator;
	return 0;
}

static struct tuple *
tree_iterator_fwd(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	tuple **res = bps_tree_index_itr_get_elem(it->tree, &it->bps_tree_iter);
	if (!res)
		return 0;
	bps_tree_index_itr_next(it->tree, &it->bps_tree_iter);
	return *res;
}

static struct tuple *
tree_iterator_bwd(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	tuple **res = bps_tree_index_itr_get_elem(it->tree, &it->bps_tree_iter);
	if (!res)
		return 0;
	bps_tree_index_itr_prev(it->tree, &it->bps_tree_iter);
	return *res;
}

static struct tuple *
tree_iterator_fwd_check_equality(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	tuple **res = bps_tree_index_itr_get_elem(it->tree, &it->bps_tree_iter);
	if (!res)
		return 0;
	if (tree_index_compare_key(*res, &it->key_data, it->key_def) != 0) {
		it->bps_tree_iter = bps_tree_index_invalid_iterator();
		return 0;
	}
	bps_tree_index_itr_next(it->tree, &it->bps_tree_iter);
	return *res;
}

static struct tuple *
tree_iterator_fwd_check_next_equality(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	tuple **res = bps_tree_index_itr_get_elem(it->tree, &it->bps_tree_iter);
	if (!res)
		return 0;
	bps_tree_index_itr_next(it->tree, &it->bps_tree_iter);
	iterator->next = tree_iterator_fwd_check_equality;
	return *res;
}

static struct tuple *
tree_iterator_bwd_skip_one(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	bps_tree_index_itr_prev(it->tree, &it->bps_tree_iter);
	iterator->next = tree_iterator_bwd;
	return tree_iterator_bwd(iterator);
}

static struct tuple *
tree_iterator_bwd_check_equality(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	tuple **res = bps_tree_index_itr_get_elem(it->tree, &it->bps_tree_iter);
	if (!res)
		return 0;
	if (tree_index_compare_key(*res, &it->key_data, it->key_def) != 0) {
		it->bps_tree_iter = bps_tree_index_invalid_iterator();
		return 0;
	}
	bps_tree_index_itr_prev(it->tree, &it->bps_tree_iter);
	return *res;
}

static struct tuple *
tree_iterator_bwd_skip_one_check_next_equality(struct iterator *iterator)
{
	struct tree_iterator *it = tree_iterator(iterator);
	bps_tree_index_itr_prev(it->tree, &it->bps_tree_iter);
	iterator->next = tree_iterator_bwd_check_equality;
	return tree_iterator_bwd_check_equality(iterator);
}
/* }}} */

/* {{{ TreeIndex  **********************************************************/

static void *
extent_alloc()
{
	ERROR_INJECT(ERRINJ_INDEX_ALLOC, return 0);
	return mempool_alloc(&tree_extent_pool);
}

static void
extent_free(void *extent)
{
	return mempool_free(&tree_extent_pool, extent);
}

TreeIndex::TreeIndex(struct key_def *key_def_arg)
	: Index(key_def_arg), build_array(0), build_array_size(0),
	  build_array_alloc_size(0)
{
	if (tree_extent_pool_initialized == 0) {
		mempool_create(&tree_extent_pool, &cord()->slabc,
			       BPS_TREE_EXTENT_SIZE);
		tree_extent_pool_initialized = 1;
	}
	bps_tree_index_create(&tree, key_def, extent_alloc, extent_free);
}

TreeIndex::~TreeIndex()
{
	bps_tree_index_destroy(&tree);
	free(build_array);
}

size_t
TreeIndex::size() const
{
	return bps_tree_index_size(&tree);
}

size_t
TreeIndex::memsize() const
{
	return bps_tree_index_mem_used(&tree);
}

struct tuple *
TreeIndex::random(uint32_t rnd) const
{
	struct tuple **res = bps_tree_index_random(&tree, rnd);
	return res ? *res : 0;
}

struct tuple *
TreeIndex::findByKey(const char *key, uint32_t part_count) const
{
	assert(key_def->is_unique && part_count == key_def->part_count);

	struct key_data key_data;
	key_data.key = key;
	key_data.part_count = part_count;
	struct tuple **res = bps_tree_index_find(&tree, &key_data);
	return res ? *res : 0;
}

struct tuple *
TreeIndex::replace(struct tuple *old_tuple, struct tuple *new_tuple,
		   enum dup_replace_mode mode)
{
	uint32_t errcode;

	if (new_tuple) {
		struct tuple *dup_tuple = NULL;

		/* Try to optimistically replace the new_tuple. */
		bool tree_res =
		bps_tree_index_insert(&tree, new_tuple, &dup_tuple);
		if (!tree_res) {
			tnt_raise(ClientError, ER_MEMORY_ISSUE,
				  BPS_TREE_EXTENT_SIZE, "TreeIndex", "replace");
		}

		errcode = replace_check_dup(old_tuple, dup_tuple, mode);

		if (errcode) {
			bps_tree_index_delete(&tree, new_tuple);
			if (dup_tuple)
				bps_tree_index_insert(&tree, dup_tuple, 0);
			tnt_raise(ClientError, errcode, index_id(this));
		}
		if (dup_tuple)
			return dup_tuple;
	}
	if (old_tuple) {
		bps_tree_index_delete(&tree, old_tuple);
	}
	return old_tuple;
}

struct iterator *
TreeIndex::allocIterator() const
{
	struct tree_iterator *it = (struct tree_iterator *)
			calloc(1, sizeof(*it));
	if (it == NULL) {
		tnt_raise(ClientError, ER_MEMORY_ISSUE,
			  sizeof(struct tree_iterator),
			  "TreeIndex", "iterator");
	}

	it->key_def = key_def;
	it->tree = &tree;
	it->base.free = tree_iterator_free;
	it->bps_tree_iter = bps_tree_index_invalid_iterator();
	return (struct iterator *) it;
}

void
TreeIndex::initIterator(struct iterator *iterator, enum iterator_type type,
			const char *key, uint32_t part_count) const
{
	assert(part_count == 0 || key != NULL);
	struct tree_iterator *it = tree_iterator(iterator);

	if (part_count == 0) {
		/*
		 * If no key is specified, downgrade equality
		 * iterators to a full range.
		 */
		if (type < 0 || type > ITER_GT)
			tnt_raise(ClientError, ER_UNSUPPORTED,
				  "Tree index", "requested iterator type");
		type = iterator_type_is_reverse(type) ? ITER_LE : ITER_GE;
		key = 0;
	}
	it->key_data.key = key;
	it->key_data.part_count = part_count;

	bool exact = false;
	if (key == 0) {
		if (iterator_type_is_reverse(type))
			it->bps_tree_iter = bps_tree_index_invalid_iterator();
		else
			it->bps_tree_iter = bps_tree_index_itr_first(&tree);
	} else {
		if (type == ITER_ALL || type == ITER_EQ || type == ITER_GE || type == ITER_LT) {
			it->bps_tree_iter = bps_tree_index_lower_bound(&tree, &it->key_data, &exact);
			if (type == ITER_EQ && !exact) {
				it->base.next = tree_iterator_dummie;
				return;
			}
		} else { // ITER_GT, ITER_REQ, ITER_LE
			it->bps_tree_iter = bps_tree_index_upper_bound(&tree, &it->key_data, &exact);
			if (type == ITER_REQ && !exact) {
				it->base.next = tree_iterator_dummie;
				return;
			}
		}
	}

	switch (type) {
	case ITER_EQ:
		it->base.next = tree_iterator_fwd_check_next_equality;
		break;
	case ITER_REQ:
		it->base.next = tree_iterator_bwd_skip_one_check_next_equality;
		break;
	case ITER_ALL:
	case ITER_GE:
		it->base.next = tree_iterator_fwd;
		break;
	case ITER_GT:
		it->base.next = tree_iterator_fwd;
		break;
	case ITER_LE:
		it->base.next = tree_iterator_bwd_skip_one;
		break;
	case ITER_LT:
		it->base.next = tree_iterator_bwd_skip_one;
		break;
	default:
		tnt_raise(ClientError, ER_UNSUPPORTED,
			  "Tree index", "requested iterator type");
	}
}

void
TreeIndex::beginBuild()
{
	assert(bps_tree_index_size(&tree) == 0);
}

void
TreeIndex::reserve(uint32_t size_hint)
{
	if (size_hint < build_array_alloc_size)
		return;
	build_array = (struct tuple**)
		realloc(build_array, size_hint * sizeof(struct tuple *));
	build_array_alloc_size = size_hint;
}

void
TreeIndex::buildNext(struct tuple *tuple)
{
	if (!build_array) {
		build_array = (struct tuple**)malloc(BPS_TREE_EXTENT_SIZE);
		build_array_alloc_size =
			BPS_TREE_EXTENT_SIZE / sizeof(struct tuple*);
	}
	assert(build_array_size <= build_array_alloc_size);
	if (build_array_size == build_array_alloc_size) {
		build_array_alloc_size = build_array_alloc_size +
					 build_array_alloc_size / 2;
		build_array = (struct tuple**)
			realloc(build_array,
				build_array_alloc_size *
				sizeof(struct tuple *));
	}
	build_array[build_array_size++] = tuple;
}

void
TreeIndex::endBuild()
{
	qsort_arg(build_array, build_array_size, sizeof(struct tuple *), tree_index_qcompare, key_def);
	bps_tree_index_build(&tree, build_array, build_array_size);

	free(build_array);
	build_array = 0;
	build_array_size = 0;
	build_array_alloc_size = 0;
}

<|endoftext|>


<commit_before>// Copyright 2014 eric schkufza
//
// 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 "src/cfg/dot_writer.h"

using namespace std;
using namespace x64asm;

namespace stoke {

void DotWriter::write_entry(ostream& os, const Cfg& cfg) const {
  os << "bb" << cfg.get_entry() << " [";
  os << "shape=record  ";
  os << "label=\"{ENTRY";
  if (def_in_block_) {
    os << "|def-in: ";
    write_reg_set(os, cfg.def_ins());
  }
  os << "}\"];" << endl;
}

void DotWriter::write_exit(ostream& os, const Cfg& cfg) const {
  const auto id = cfg.get_exit();
  os << "bb" << id << " [";
  os << "shape=record ";
  os << "label=\"{EXIT";
  if (live_out_block_) {
    os << "|live-out: ";
    write_reg_set(os, cfg.live_outs());
  }
  if (def_in_block_) {
    os << "|def-in: ";
    write_reg_set(os, cfg.def_ins(id));
  }
  os << "}\"];" << endl;
}

void DotWriter::write_block(ostream& os, const Cfg& cfg, Cfg::id_type id) const {
  os << "bb" << id << "[";
  os << "shape=record, style=filled, fillcolor=white, ";
  if (!cfg.is_reachable(id)) {
    os << "color = grey, ";
  }
  os << "label=\"{";
  os << "#" << id;
  if (dom_ && cfg.is_reachable(id)) {
    os << "|dominates: ";
    write_dominators(os, cfg, id);
  }
  if (def_in_block_ && cfg.is_reachable(id)) {
    os << "|def-in: ";
    write_reg_set(os, cfg.def_ins(id));
  }
  for (size_t j = 0, je = cfg.num_instrs(id); j < je; ++j) {
    if (def_in_instr_ && cfg.is_reachable(id)) {
      os << "|def-in: ";
      write_reg_set(os, cfg.def_ins({id, j}));
    }

    os << "|";
    os << cfg.get_instr({id, j});
    os << "\\l";
  }
  os << "}\"];" << endl;
}

void DotWriter::write_blocks(ostream& os, const Cfg& cfg) const {
  map<size_t, vector<Cfg::id_type>> nestings;
  for (size_t i = cfg.get_entry() + 1, ie = cfg.get_exit(); i < ie; ++i) {
    nestings[cfg.nesting_depth(i)].push_back(i);
  }

  for (const auto& n : nestings) {
    os << "subgraph cluster_" << n.first << " {" << endl;
    os << "style = filled" << endl;
    os << "color = " << (n.first + 1) << endl;

    for (const auto id : n.second) {
      write_block(os, cfg, id);
    }
  }

  for (size_t i = 0, ie = nestings.size(); i < ie; ++i) {
    os << "}" << endl;
  }
}

void DotWriter::write_dominators(ostream& os, const Cfg& cfg, Cfg::id_type bb) const {
  os << "\\{";
  for (auto i = cfg.reachable_begin(), ie = cfg.reachable_end(); i != ie; ++i) {
    if (cfg.dom(bb, *i)) {
      os << " #" << *i;
    }
  }
  os << " \\}";
}

void DotWriter::write_edges(ostream& os, const Cfg& cfg) const {
  for (size_t i = cfg.get_entry(), ie = cfg.get_exit(); i < ie; ++i)
    for (auto s = cfg.succ_begin(i), se = cfg.succ_end(i); s != se; ++s) {
      os << "bb" << i << "->bb" << *s << " [";
      os << "style=";
      if (cfg.has_fallthrough_target(i) && cfg.fallthrough_target(i) == *s) {
        os << "bold";
      } else {
        os << "dashed";
      }
      os << " color=";
      if (cfg.is_back_edge({i, *s})) {
        os << "red";
      } else if (cfg.is_reachable(i) || cfg.is_entry(i)) {
        os << "black";
      } else {
        os << "grey";
      }
      os << "];" << endl;
    }
}

void DotWriter::write_reg_set(ostream& os, const RegSet& rs) const {
  os << "\\{";
  for (auto i = 0; i < 16; ++i) {
    if (rs.contains(r64s[i])) {
      os << " " << r64s[i];
    } else if (rs.contains(r32s[i])) {
      os << " " << r32s[i];
    } else if (rs.contains(r16s[i])) {
      os << " " << r16s[i];
    } else if (i < 4) {
      if (rs.contains(rls[i])) {
        os << " " << rls[i];
      } else if (rs.contains(rhs[i])) {
        os << " " << rhs[i];
      }
    } else if (rs.contains(rbs[i - 4])) {
      os << " " << rbs[i - 4];
    }
  }

  for (auto i = 0; i < 16; ++i)
    if (rs.contains(ymms[i])) {
      os << " " << ymms[i];
    } else if (rs.contains(xmms[i])) {
      os << " " << xmms[i];
    }

  os << " \\}";
}

} // namespace stoke
<commit_msg>Bug fix: basic block numbers were coming out as hex sometimes.<commit_after>// Copyright 2014 eric schkufza
//
// 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 "src/cfg/dot_writer.h"

using namespace std;
using namespace x64asm;

namespace stoke {

void DotWriter::write_entry(ostream& os, const Cfg& cfg) const {
  os << "bb" << dec << cfg.get_entry() << " [";
  os << "shape=record  ";
  os << "label=\"{ENTRY";
  if (def_in_block_) {
    os << "|def-in: ";
    write_reg_set(os, cfg.def_ins());
  }
  os << "}\"];" << endl;
}

void DotWriter::write_exit(ostream& os, const Cfg& cfg) const {
  const auto id = cfg.get_exit();
  os << "bb" << dec << id << " [";
  os << "shape=record ";
  os << "label=\"{EXIT";
  if (live_out_block_) {
    os << "|live-out: ";
    write_reg_set(os, cfg.live_outs());
  }
  if (def_in_block_) {
    os << "|def-in: ";
    write_reg_set(os, cfg.def_ins(id));
  }
  os << "}\"];" << endl;
}

void DotWriter::write_block(ostream& os, const Cfg& cfg, Cfg::id_type id) const {
  os << "bb" << dec << id << "[";
  os << "shape=record, style=filled, fillcolor=white, ";
  if (!cfg.is_reachable(id)) {
    os << "color = grey, ";
  }
  os << "label=\"{";
  os << "#" << id;
  if (dom_ && cfg.is_reachable(id)) {
    os << "|dominates: ";
    write_dominators(os, cfg, id);
  }
  if (def_in_block_ && cfg.is_reachable(id)) {
    os << "|def-in: ";
    write_reg_set(os, cfg.def_ins(id));
  }
  for (size_t j = 0, je = cfg.num_instrs(id); j < je; ++j) {
    if (def_in_instr_ && cfg.is_reachable(id)) {
      os << "|def-in: ";
      write_reg_set(os, cfg.def_ins({id, j}));
    }

    os << "|";
    os << cfg.get_instr({id, j});
    os << "\\l";
  }
  os << "}\"];" << endl;
}

void DotWriter::write_blocks(ostream& os, const Cfg& cfg) const {
  map<size_t, vector<Cfg::id_type>> nestings;
  for (size_t i = cfg.get_entry() + 1, ie = cfg.get_exit(); i < ie; ++i) {
    nestings[cfg.nesting_depth(i)].push_back(i);
  }

  for (const auto& n : nestings) {
    os << "subgraph cluster_" << n.first << " {" << endl;
    os << "style = filled" << endl;
    os << "color = " << (n.first + 1) << endl;

    for (const auto id : n.second) {
      write_block(os, cfg, id);
    }
  }

  for (size_t i = 0, ie = nestings.size(); i < ie; ++i) {
    os << "}" << endl;
  }
}

void DotWriter::write_dominators(ostream& os, const Cfg& cfg, Cfg::id_type bb) const {
  os << "\\{";
  for (auto i = cfg.reachable_begin(), ie = cfg.reachable_end(); i != ie; ++i) {
    if (cfg.dom(bb, *i)) {
      os << " #" << *i;
    }
  }
  os << " \\}";
}

void DotWriter::write_edges(ostream& os, const Cfg& cfg) const {
  for (size_t i = cfg.get_entry(), ie = cfg.get_exit(); i < ie; ++i)
    for (auto s = cfg.succ_begin(i), se = cfg.succ_end(i); s != se; ++s) {
      os << "bb" << dec << i << "->bb" << dec << *s << " [";
      os << "style=";
      if (cfg.has_fallthrough_target(i) && cfg.fallthrough_target(i) == *s) {
        os << "bold";
      } else {
        os << "dashed";
      }
      os << " color=";
      if (cfg.is_back_edge({i, *s})) {
        os << "red";
      } else if (cfg.is_reachable(i) || cfg.is_entry(i)) {
        os << "black";
      } else {
        os << "grey";
      }
      os << "];" << endl;
    }
}

void DotWriter::write_reg_set(ostream& os, const RegSet& rs) const {
  os << "\\{";
  for (auto i = 0; i < 16; ++i) {
    if (rs.contains(r64s[i])) {
      os << " " << r64s[i];
    } else if (rs.contains(r32s[i])) {
      os << " " << r32s[i];
    } else if (rs.contains(r16s[i])) {
      os << " " << r16s[i];
    } else if (i < 4) {
      if (rs.contains(rls[i])) {
        os << " " << rls[i];
      } else if (rs.contains(rhs[i])) {
        os << " " << rhs[i];
      }
    } else if (rs.contains(rbs[i - 4])) {
      os << " " << rbs[i - 4];
    }
  }

  for (auto i = 0; i < 16; ++i)
    if (rs.contains(ymms[i])) {
      os << " " << ymms[i];
    } else if (rs.contains(xmms[i])) {
      os << " " << xmms[i];
    }

  os << " \\}";
}

} // namespace stoke
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/filerepository.h"
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/random.h"
#include "fnord-base/thread/eventloop.h"
#include "fnord-base/thread/threadpool.h"
#include "fnord-base/thread/FixedSizeThreadPool.h"
#include "fnord-base/wallclock.h"
#include "fnord-base/VFS.h"
#include "fnord-rpc/ServerGroup.h"
#include "fnord-rpc/RPC.h"
#include "fnord-rpc/RPCClient.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-json/json.h"
#include "fnord-json/jsonrpc.h"
#include "fnord-http/httprouter.h"
#include "fnord-http/httpserver.h"
#include "fnord-http/VFSFileServlet.h"
#include "fnord-feeds/FeedService.h"
#include "fnord-feeds/RemoteFeedFactory.h"
#include "fnord-feeds/RemoteFeedReader.h"
#include "fnord-base/stats/statsdagent.h"
#include "fnord-sstable/SSTableServlet.h"
#include "fnord-eventdb/EventDBServlet.h"
#include "fnord-eventdb/TableRepository.h"
#include "fnord-eventdb/TableJanitor.h"
#include "fnord-eventdb/TableReplication.h"
#include "fnord-eventdb/ArtifactReplication.h"
#include "fnord-eventdb/NumericBoundsSummary.h"
#include "fnord-mdb/MDB.h"
#include "fnord-mdb/MDBUtil.h"
#include "common.h"
#include "schemas.h"
#include "CustomerNamespace.h"
#include "FeatureSchema.h"
#include "JoinedQuery.h"
#include "analytics/AnalyticsServlet.h"
#include "analytics/CTRByPageServlet.h"
#include "analytics/CTRStatsServlet.h"
#include "analytics/CTRByPositionQuery.h"
#include "analytics/CTRByPageQuery.h"
#include "analytics/TopSearchQueriesQuery.h"
#include "analytics/DiscoveryKPIQuery.h"
#include "analytics/DiscoveryCategoryStatsQuery.h"
#include "analytics/AnalyticsQueryEngine.h"
#include "analytics/AnalyticsQueryEngine.h"

using namespace fnord;

std::atomic<bool> shutdown_sig;
fnord::thread::EventLoop ev;

void quit(int n) {
  shutdown_sig = true;
  fnord::logInfo("cm.chunkserver", "Shutting down...");
  // FIXPAUL: wait for http server stop...
  ev.shutdown();
}

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  /* shutdown hook */
  shutdown_sig = false;
  struct sigaction sa;
  memset(&sa, 0, sizeof(struct sigaction));
  sa.sa_handler = quit;
  sigaction(SIGTERM, &sa, NULL);
  sigaction(SIGQUIT, &sa, NULL);
  sigaction(SIGINT, &sa, NULL);

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "http_port",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8000",
      "Start the public http server on this port",
      "<port>");

  flags.defineFlag(
      "readonly",
      cli::FlagParser::T_SWITCH,
      false,
      NULL,
      NULL,
      "readonly",
      "readonly");

  flags.defineFlag(
      "replica",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "replica id",
      "<id>");

  flags.defineFlag(
      "datadir",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "datadir path",
      "<path>");

  flags.defineFlag(
      "replicate_from",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "url",
      "<url>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  /* start http server */
  fnord::thread::ThreadPool tpool;
  fnord::thread::FixedSizeThreadPool wpool(8);
  fnord::thread::FixedSizeThreadPool repl_wpool(8);
  fnord::http::HTTPRouter http_router;
  fnord::http::HTTPServer http_server(&http_router, &ev);
  http_server.listen(flags.getInt("http_port"));

  wpool.start();
  repl_wpool.start();

  /* eventdb */
  auto dir = flags.getString("datadir");
  auto readonly = flags.isSet("readonly");
  auto replica = flags.getString("replica");

  Set<String> tbls  = { "dawanda_joined_sessions", "joined_sessions-dawanda" };
  http::HTTPConnectionPool http(&ev);
  eventdb::ArtifactIndex artifacts(dir, replica, readonly);
  eventdb::TableRepository table_repo(
      &artifacts,
      dir,
      replica,
      readonly,
      &wpool);

  auto joined_sessions_schema = joinedSessionsSchema();
  for (const auto& tbl : tbls) {
    table_repo.addTable(tbl, joined_sessions_schema);
  }

  if (!readonly) {
    for (const auto& tbl : tbls) {
      auto joined_sessions_table =table_repo.findTableWriter(tbl);

      joined_sessions_table->addSummary(
          [joined_sessions_schema] () -> RefPtr<eventdb::TableChunkSummaryBuilder> {
            return new eventdb::NumericBoundsSummaryBuilder(
                "queries.time-bounds",
                joined_sessions_schema.id("queries.time"));
          });
    }
  }

  eventdb::TableReplication table_replication(&http);
  eventdb::ArtifactReplication artifact_replication(
      &artifacts,
      &http,
      &repl_wpool,
      8);

  for (const auto& rep : flags.getStrings("replicate_from")) {
    for (const auto& tbl : tbls) {
      table_replication.replicateTableFrom(
          table_repo.findTableWriter(tbl),
          URI(StringUtil::format("http://$0:7003/eventdb", rep)));
    }

    artifact_replication.addSource(
        URI(StringUtil::format("http://$0:7005/chunks", rep)));
  }

  eventdb::TableJanitor table_janitor(&table_repo);
  if (!readonly) {
    table_janitor.start();
    table_replication.start();
    artifact_replication.start();
  }

  eventdb::EventDBServlet eventdb_servlet(&table_repo);

  /* analytics */
  cm::AnalyticsQueryEngine analytics(32, dir, &table_repo);
  cm::AnalyticsServlet analytics_servlet(&analytics);
  http_router.addRouteByPrefixMatch("/analytics", &analytics_servlet, &tpool);
  http_router.addRouteByPrefixMatch("/eventdb", &eventdb_servlet, &tpool);

  analytics.registerQueryFactory("ctr_by_position", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::CTRByPositionQuery(scan, segments);
  });

  analytics.registerQueryFactory("ctr_by_page", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::CTRByPageQuery(scan, segments);
  });

  analytics.registerQueryFactory("discovery_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryKPIQuery(
        scan,
        segments,
        query.start_time,
        query.end_time);
  });

  analytics.registerQueryFactory("discovery_category0_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category1",
        "queries.category1",
        params);
  });

  analytics.registerQueryFactory("discovery_category1_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category1",
        "queries.category2",
        params);
  });

  analytics.registerQueryFactory("discovery_category2_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category2",
        "queries.category3",
        params);
  });

  analytics.registerQueryFactory("discovery_category3_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category3",
        "queries.category3",
        params);
  });

  analytics.registerQueryFactory("top_search_queries", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::TopSearchQueriesQuery(scan, segments, params);
  });

  ev.run();

  if (!readonly) {
    table_janitor.stop();
    table_janitor.check();
    table_replication.stop();
    artifact_replication.stop();
  }

  fnord::logInfo("cm.chunkserver", "Exiting...");

  exit(0);
}

<commit_msg>consistency check<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/filerepository.h"
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/random.h"
#include "fnord-base/thread/eventloop.h"
#include "fnord-base/thread/threadpool.h"
#include "fnord-base/thread/FixedSizeThreadPool.h"
#include "fnord-base/wallclock.h"
#include "fnord-base/VFS.h"
#include "fnord-rpc/ServerGroup.h"
#include "fnord-rpc/RPC.h"
#include "fnord-rpc/RPCClient.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-json/json.h"
#include "fnord-json/jsonrpc.h"
#include "fnord-http/httprouter.h"
#include "fnord-http/httpserver.h"
#include "fnord-http/VFSFileServlet.h"
#include "fnord-feeds/FeedService.h"
#include "fnord-feeds/RemoteFeedFactory.h"
#include "fnord-feeds/RemoteFeedReader.h"
#include "fnord-base/stats/statsdagent.h"
#include "fnord-sstable/SSTableServlet.h"
#include "fnord-eventdb/EventDBServlet.h"
#include "fnord-eventdb/TableRepository.h"
#include "fnord-eventdb/TableJanitor.h"
#include "fnord-eventdb/TableReplication.h"
#include "fnord-eventdb/ArtifactReplication.h"
#include "fnord-eventdb/NumericBoundsSummary.h"
#include "fnord-mdb/MDB.h"
#include "fnord-mdb/MDBUtil.h"
#include "common.h"
#include "schemas.h"
#include "CustomerNamespace.h"
#include "FeatureSchema.h"
#include "JoinedQuery.h"
#include "analytics/AnalyticsServlet.h"
#include "analytics/CTRByPageServlet.h"
#include "analytics/CTRStatsServlet.h"
#include "analytics/CTRByPositionQuery.h"
#include "analytics/CTRByPageQuery.h"
#include "analytics/TopSearchQueriesQuery.h"
#include "analytics/DiscoveryKPIQuery.h"
#include "analytics/DiscoveryCategoryStatsQuery.h"
#include "analytics/AnalyticsQueryEngine.h"
#include "analytics/AnalyticsQueryEngine.h"

using namespace fnord;

std::atomic<bool> shutdown_sig;
fnord::thread::EventLoop ev;

void quit(int n) {
  shutdown_sig = true;
  fnord::logInfo("cm.chunkserver", "Shutting down...");
  // FIXPAUL: wait for http server stop...
  ev.shutdown();
}

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  /* shutdown hook */
  shutdown_sig = false;
  struct sigaction sa;
  memset(&sa, 0, sizeof(struct sigaction));
  sa.sa_handler = quit;
  sigaction(SIGTERM, &sa, NULL);
  sigaction(SIGQUIT, &sa, NULL);
  sigaction(SIGINT, &sa, NULL);

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "http_port",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8000",
      "Start the public http server on this port",
      "<port>");

  flags.defineFlag(
      "readonly",
      cli::FlagParser::T_SWITCH,
      false,
      NULL,
      NULL,
      "readonly",
      "readonly");

  flags.defineFlag(
      "replica",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "replica id",
      "<id>");

  flags.defineFlag(
      "datadir",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "datadir path",
      "<path>");

  flags.defineFlag(
      "replicate_from",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "url",
      "<url>");

  flags.defineFlag(
      "fsck",
      cli::FlagParser::T_SWITCH,
      false,
      NULL,
      NULL,
      "fsck",
      "fsck");

  flags.defineFlag(
      "repair",
      cli::FlagParser::T_SWITCH,
      false,
      NULL,
      NULL,
      "repair",
      "repair");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  /* start http server */
  fnord::thread::ThreadPool tpool;
  fnord::thread::FixedSizeThreadPool wpool(8);
  fnord::thread::FixedSizeThreadPool repl_wpool(8);
  fnord::http::HTTPRouter http_router;
  fnord::http::HTTPServer http_server(&http_router, &ev);
  http_server.listen(flags.getInt("http_port"));

  wpool.start();
  repl_wpool.start();

  /* eventdb */
  auto dir = flags.getString("datadir");
  auto readonly = flags.isSet("readonly");
  auto replica = flags.getString("replica");

  Set<String> tbls  = { "dawanda_joined_sessions", "joined_sessions-dawanda" };
  http::HTTPConnectionPool http(&ev);
  eventdb::ArtifactIndex artifacts(dir, replica, readonly);
  artifacts.runConsistencyCheck(
      flags.isSet("fsck"),
      flags.isSet("repair"));

  eventdb::TableRepository table_repo(
      &artifacts,
      dir,
      replica,
      readonly,
      &wpool);

  auto joined_sessions_schema = joinedSessionsSchema();
  for (const auto& tbl : tbls) {
    table_repo.addTable(tbl, joined_sessions_schema);
  }

  if (!readonly) {
    for (const auto& tbl : tbls) {
      auto joined_sessions_table =table_repo.findTableWriter(tbl);

      joined_sessions_table->addSummary(
          [joined_sessions_schema] () -> RefPtr<eventdb::TableChunkSummaryBuilder> {
            return new eventdb::NumericBoundsSummaryBuilder(
                "queries.time-bounds",
                joined_sessions_schema.id("queries.time"));
          });
    }
  }

  eventdb::TableReplication table_replication(&http);
  eventdb::ArtifactReplication artifact_replication(
      &artifacts,
      &http,
      &repl_wpool,
      8);

  for (const auto& rep : flags.getStrings("replicate_from")) {
    for (const auto& tbl : tbls) {
      table_replication.replicateTableFrom(
          table_repo.findTableWriter(tbl),
          URI(StringUtil::format("http://$0:7003/eventdb", rep)));
    }

    artifact_replication.addSource(
        URI(StringUtil::format("http://$0:7005/chunks", rep)));
  }

  eventdb::TableJanitor table_janitor(&table_repo);
  if (!readonly) {
    table_janitor.start();
    table_replication.start();
    artifact_replication.start();
  }

  eventdb::EventDBServlet eventdb_servlet(&table_repo);

  /* analytics */
  cm::AnalyticsQueryEngine analytics(32, dir, &table_repo);
  cm::AnalyticsServlet analytics_servlet(&analytics);
  http_router.addRouteByPrefixMatch("/analytics", &analytics_servlet, &tpool);
  http_router.addRouteByPrefixMatch("/eventdb", &eventdb_servlet, &tpool);

  analytics.registerQueryFactory("ctr_by_position", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::CTRByPositionQuery(scan, segments);
  });

  analytics.registerQueryFactory("ctr_by_page", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::CTRByPageQuery(scan, segments);
  });

  analytics.registerQueryFactory("discovery_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryKPIQuery(
        scan,
        segments,
        query.start_time,
        query.end_time);
  });

  analytics.registerQueryFactory("discovery_category0_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category1",
        "queries.category1",
        params);
  });

  analytics.registerQueryFactory("discovery_category1_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category1",
        "queries.category2",
        params);
  });

  analytics.registerQueryFactory("discovery_category2_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category2",
        "queries.category3",
        params);
  });

  analytics.registerQueryFactory("discovery_category3_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        query.start_time,
        query.end_time,
        "queries.category3",
        "queries.category3",
        params);
  });

  analytics.registerQueryFactory("top_search_queries", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::TopSearchQueriesQuery(scan, segments, params);
  });

  ev.run();

  if (!readonly) {
    table_janitor.stop();
    table_janitor.check();
    table_replication.stop();
    artifact_replication.stop();
  }

  fnord::logInfo("cm.chunkserver", "Exiting...");

  exit(0);
}

<|endoftext|>