<commit_before>// Copyright 2018 Google LLC
//
// 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 "cc/logging.h"
#include "cc/tf_utils.h"

namespace minigo {
namespace tf_utils {

void WriteGameExamples(const std::string& output_dir,
                       const std::string& output_name, const Game& game) {
  MG_LOG(FATAL)
      << "Can't write TensorFlow examples without TensorFlow support enabled. "
         "Please recompile, passing --define=tf=1 to bazel build.";
}

}  // namespace tf_utils
}  // namespace minigo
<commit_msg>fix signature for WriteGameExamples dummy implementation<commit_after>// Copyright 2018 Google LLC
//
// 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 "cc/logging.h"
#include "cc/tf_utils.h"

namespace minigo {
namespace tf_utils {

void WriteGameExamples(const std::string& output_dir,
                       const std::string& output_name,
                       const FeatureDescriptor& feature_desc,
                       const Game& game) {
  MG_LOG(FATAL)
      << "Can't write TensorFlow examples without TensorFlow support enabled. "
         "Please recompile, passing --define=tf=1 to bazel build.";
}

}  // namespace tf_utils
}  // namespace minigo
<|endoftext|>


<commit_before>#include <iostream>

#include "core/chatbot.h"
#include "core/cmdline.h"

#include "core/os.h"
#include "core/vfs.h"

int
main()
{
  ChatBot chatbot;

  const auto current_directory = GetCurrentDirectory();
  vfs::FileSystem file_system;
  vfs::FileSystemRootFolder::AddRoot(&file_system, current_directory);

  const auto error = chatbot.LoadFromFile(&file_system, "chatbot.json");
  if(!error.empty())
  {
    std::cerr << "Failed to load chatbot: " << error << "\n";
    return -2;
  }

  std::string input;
  CmdLine     cmdline{&std::cout};
  cmdline.Register("debug", [&chatbot](const CmdLine::Args& args) {
    std::cout << chatbot.DebugLastResponse(args);
    std::cout << "\n\n";
  });
  cmdline.Register("kill", [&chatbot](const CmdLine::Args& args) {
    chatbot.is_in_conversation = false;
    std::cout << "Killing chatbot.\n\n";
  });

  std::cout << chatbot.GetSignOnMessage() << "\n";

  bool first = true;
  do
  {
    if(!first)
    {
      if(!input.empty() && input[0] == '@')
      {
        const std::string in{input.begin() + 1, input.end()};
        cmdline.Run(in);
      }
      else
      {
        const std::string response = chatbot.GetResponse(input);
        std::cout << response << "\n";
      }
    }
    std::cout << "> ";
    first = false;
  } while(chatbot.IsInConversation() && std::getline(std::cin, input));

  return 0;
}
<commit_msg>(fix) chatbot_test compiles<commit_after>#include <iostream>

#include "core/chatbot.h"
#include "core/cmdline.h"

#include "core/os.h"
#include "core/vfs.h"

using namespace euphoria::core;

int
main()
{
  ChatBot chatbot;

  const auto current_directory = GetCurrentDirectory();
  vfs::FileSystem file_system;
  vfs::FileSystemRootFolder::AddRoot(&file_system, current_directory);

  const auto error = chatbot.LoadFromFile(&file_system, "chatbot.json");
  if(!error.empty())
  {
    std::cerr << "Failed to load chatbot: " << error << "\n";
    return -2;
  }

  std::string input;
  CmdLine     cmdline{&std::cout};
  cmdline.Register("debug", [&chatbot](const CmdLine::Args& args) {
    std::cout << chatbot.DebugLastResponse(args);
    std::cout << "\n\n";
  });
  cmdline.Register("kill", [&chatbot](const CmdLine::Args& args) {
    chatbot.is_in_conversation = false;
    std::cout << "Killing chatbot.\n\n";
  });

  std::cout << chatbot.GetSignOnMessage() << "\n";

  bool first = true;
  do
  {
    if(!first)
    {
      if(!input.empty() && input[0] == '@')
      {
        const std::string in{input.begin() + 1, input.end()};
        cmdline.Run(in);
      }
      else
      {
        const std::string response = chatbot.GetResponse(input);
        std::cout << response << "\n";
      }
    }
    std::cout << "> ";
    first = false;
  } while(chatbot.IsInConversation() && std::getline(std::cin, input));

  return 0;
}
<|endoftext|>


<commit_before>#include "Font.h"

#include <ExceptionSDL.h>

#ifdef WIN32
#include "windows.h"
#endif
#include <GL/gl.h>

namespace Chimera {

Font::Font ( const char* _fontFile, int _size ) {

#ifdef TTF_NOVO

    pFont = TTF_OpenFont( _fontFile, _size );
    if(!pFont)
       throw ExceptionSDL ( ExceptionCode::READ, "Arquivo de fonte falha ao carregar:" + std::string(_fontFile ) );

    TTF_SetFontStyle(pFont, TTF_STYLE_NORMAL);

#else
    if ( _fontFile == nullptr )
       ExceptionChimera ( ExceptionCode::READ,"Arquivo de Fonte Nulo" );

    pFont = new FTGLPixmapFont ( _fontFile );
    if ( pFont==nullptr )
       ExceptionChimera ( ExceptionCode::READ,"Carga de arquivo invalida" );

    if ( pFont->Error() )
       ExceptionChimera ( ExceptionCode::READ,"Carga de Fonte invalida" );

    if ( pFont->FaceSize ( _size ) ==false ) {
       if ( pFont ) {
           delete pFont;
           pFont = nullptr;
       }
       ExceptionChimera ( ExceptionCode::READ,"Tamanho Fonte invalida" );
    }

#endif
}

Font::~Font ( void ) {

    if ( pFont != nullptr ) {
       delete pFont;
       pFont = nullptr;
    }

}

void Font::render (const float &_x, const float &_y,const float &_z ,const Color &_color, std::string *_pTxt ) {

#ifdef TTF_NOVO
        SDL_Color Color = {_color.r , _color.g , _color.b};
        SDL_Surface *Message = TTF_RenderText_Blended(const_cast<TTF_Font*>(pFont), _pTxt->c_str(), Color);
        unsigned Texture = 0;

        /*Generate an OpenGL 2D texture from the SDL_Surface*.*/
        glGenTextures(1, &Texture);
        glBindTexture(GL_TEXTURE_2D, Texture);

        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        glTexImage2D(GL_TEXTURE_2D, 0, 3, Message->w, Message->h, 0, GL_BGR, GL_UNSIGNED_BYTE, Message->pixels);
        //glTexImage2D(GL_TEXTURE_2D, 0, 3, pImage->w,pImage->h, 0, GL_BGR_EXT,GL_UNSIGNED_BYTE, pImage->pixels);

        /*Draw this texture on a quad with the given xyz coordinates.*/
//         glBegin(GL_QUADS);
//                 glTexCoord2d(1, 1); glVertex3d(_x, _y, _z);
//                 glTexCoord2d(0, 1); glVertex3d(_x+Message->w, _y, _z);
//                 glTexCoord2d(0, 0); glVertex3d(_x+Message->w, _y+Message->h, _z);
//                 glTexCoord2d(1, 0); glVertex3d(_x, _y+Message->h, _z);
//         glEnd();
        glBegin(GL_QUADS);
                glTexCoord2d(0, 0); glVertex3d(_x, _y, _z);
                glTexCoord2d(1, 0); glVertex3d(_x+Message->w, _y, _z);
                glTexCoord2d(1, 1); glVertex3d(_x+Message->w, _y+Message->h, _z);
                glTexCoord2d(0, 1); glVertex3d(_x, _y+Message->h, _z);
        glEnd();

        /*Clean up.*/
        glDeleteTextures(1, &Texture);
        SDL_FreeSurface(Message);
#else

    glColor3fv ( _color.ptr() );
    glRasterPos2f ( _x, _y );
    pFont->Render ( _pTxt->c_str(), _pTxt->size() );

#endif
}

}
// kate: indent-mode cstyle; indent-width 4; replace-tabs on;
<commit_msg>fonte invertida visivel posix<commit_after>#include "Font.h"

#include <ExceptionSDL.h>

#ifdef WIN32
#include "windows.h"
#endif
#include <GL/gl.h>

namespace Chimera {

Font::Font ( const char* _fontFile, int _size ) {

#ifdef TTF_NOVO

    pFont = TTF_OpenFont( _fontFile, _size );
    if(!pFont)
       throw ExceptionSDL ( ExceptionCode::READ, "Arquivo de fonte falha ao carregar:" + std::string(_fontFile ) );

    TTF_SetFontStyle(pFont, TTF_STYLE_NORMAL);

#else
    if ( _fontFile == nullptr )
       ExceptionChimera ( ExceptionCode::READ,"Arquivo de Fonte Nulo" );

    pFont = new FTGLPixmapFont ( _fontFile );
    if ( pFont==nullptr )
       ExceptionChimera ( ExceptionCode::READ,"Carga de arquivo invalida" );

    if ( pFont->Error() )
       ExceptionChimera ( ExceptionCode::READ,"Carga de Fonte invalida" );

    if ( pFont->FaceSize ( _size ) ==false ) {
       if ( pFont ) {
           delete pFont;
           pFont = nullptr;
       }
       ExceptionChimera ( ExceptionCode::READ,"Tamanho Fonte invalida" );
    }

#endif
}

Font::~Font ( void ) {

    if ( pFont != nullptr ) {
       delete pFont;
       pFont = nullptr;
    }

}

void Font::render (const float &_x, const float &_y,const float &_z ,const Color &_color, std::string *_pTxt ) {

#ifdef TTF_NOVO
        SDL_Color Color = {_color.r , _color.g , _color.b};
        SDL_Surface *Message = TTF_RenderText_Blended(const_cast<TTF_Font*>(pFont), _pTxt->c_str(), Color);
        unsigned Texture = 0;

        /*Generate an OpenGL 2D texture from the SDL_Surface*.*/
        glGenTextures(1, &Texture);
        glBindTexture(GL_TEXTURE_2D, Texture);

        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Message->w, Message->h, 0,GL_BGRA,
                     GL_UNSIGNED_BYTE, Message->pixels);

        /*Draw this texture on a quad with the given xyz coordinates.*/
//         glBegin(GL_QUADS);
//                 glTexCoord2d(1, 1); glVertex3d(_x, _y, _z);
//                 glTexCoord2d(0, 1); glVertex3d(_x+Message->w, _y, _z);
//                 glTexCoord2d(0, 0); glVertex3d(_x+Message->w, _y+Message->h, _z);
//                 glTexCoord2d(1, 0); glVertex3d(_x, _y+Message->h, _z);
//         glEnd();
        glBegin(GL_QUADS);
                glTexCoord2d(0, 0); glVertex3d(_x, _y, _z);
                glTexCoord2d(1, 0); glVertex3d(_x+Message->w, _y, _z);
                glTexCoord2d(1, 1); glVertex3d(_x+Message->w, _y+Message->h, _z);
                glTexCoord2d(0, 1); glVertex3d(_x, _y+Message->h, _z);
        glEnd();

        /*Clean up.*/
        glDeleteTextures(1, &Texture);
        SDL_FreeSurface(Message);
#else

    glColor3fv ( _color.ptr() );
    glRasterPos2f ( _x, _y );
    pFont->Render ( _pTxt->c_str(), _pTxt->size() );

#endif
}

}
// kate: indent-mode cstyle; indent-width 4; replace-tabs on;
<|endoftext|>


<commit_before>#pragma once

#include <vector>

#include "channel9.hpp"
#include "memory_pool.hpp"
#include "string.hpp"

namespace Channel9
{
	union Value
	{
		enum {
			TYPE_SHIFT		= 56,
			TYPE_MASK 		= 0xf000000000000000ULL,
			HEAP_TYPE_MASK  = 0xff00000000000000ULL,
			VALUE_MASK 		= 0x0fffffffffffffffULL,
			POINTER_MASK 	= 0x00007fffffffffffULL,
		};

		uint64_t raw;
		int64_t machine_num;
		double float_num;

		const String *str_p;
		const Tuple *tuple_p;
		const Message *msg_p;
		CallableContext *call_ctx_p;
		RunnableContext *ret_ctx_p;
	};

	extern Value Nil;
	extern Value True;
	extern Value False;
	extern Value Undef;

	inline uint64_t type_mask(ValueType type)
	{
		return (uint64_t)(type) << Value::TYPE_SHIFT;
	}

	inline ValueType basic_type(const Value &val)
	{
		return ValueType((val.raw & Value::TYPE_MASK) >> Value::TYPE_SHIFT);
	}

	inline ValueType type(const Value &val)
	{
		ValueType t = basic_type(val);
		if (t != HEAP_TYPE)
			return t;
		else
			return ValueType((val.raw & Value::HEAP_TYPE_MASK) >> Value::TYPE_SHIFT);
	}
	inline bool is(const Value &val, ValueType t)
	{
		return type(val) == t;
	}
	inline bool is_truthy(const Value &val) { return !((basic_type(val) & FALSY_MASK) == FALSY_PATTERN); }
	inline bool is_number(const Value &val) { ValueType t = basic_type(val); return t == POSITIVE_NUMBER || t == NEGATIVE_NUMBER; }
	inline bool same_type(const Value &l, const Value &r)
	{
		return type(l) == type(r);
	}

	bool complex_compare(const Value &l, const Value &r);

	inline bool operator==(const Value &l, const Value &r)
	{
		if (memcmp(&l, &r, sizeof(Value)) == 0)
			return true;
		else if (same_type(l, r)) {
			return complex_compare(l, r);
		} else {
			return false;
		}
	}
	inline bool operator!=(const Value &l, const Value &r)
	{
		return !(l == r);
	}

	inline const Value &bvalue(bool truthy) { return truthy ? True : False; }

	template <typename tPtr>
	tPtr *ptr(const Value &val)
	{
		DO_DEBUG if (!is(val, CALLABLE_CONTEXT)) assert(value_pool.validate((tPtr*)(val.raw & Value::POINTER_MASK)));
		return (tPtr*)(val.raw & Value::POINTER_MASK);
	}

	template <typename tPtr>
	inline Value make_value_ptr(ValueType type, tPtr value)
	{
		Value val = {type_mask(type) | ((uint64_t)value & Value::VALUE_MASK)};
		return val;
	}
	inline Value value(long long machine_num)
	{//cut off the top 4 bits, maintaining the sign
		uint64_t type = (uint64_t)(machine_num >> 4) & Value::TYPE_MASK;
		uint64_t num = type | ((uint64_t)(machine_num) & Value::VALUE_MASK);
		Value val = {((uint64_t)(num))};
		return val;
	}
	inline Value value(double float_num)
	{//cut off the bottom 4 bits of precision
		uint64_t num = type_mask(FLOAT_NUM) | (*reinterpret_cast<uint64_t*>(&float_num) >> 4);
		Value val = {((uint64_t)(num))};
		return val;
	}
	inline double float_num(Value val)
	{
		uint64_t num = (val.raw & Value::VALUE_MASK) << 4;
		return *reinterpret_cast<double*>(&num);
	}

	inline Value value(const std::string &str) { return make_value_ptr(STRING, new_string(str)); }
	inline Value value(const String *str) { return make_value_ptr(STRING, str); }

	inline Value value(CallableContext *call_ctx) { return make_value_ptr(CALLABLE_CONTEXT, call_ctx); }
	inline Value value(RunnableContext *ret_ctx) { return make_value_ptr(RUNNABLE_CONTEXT, ret_ctx); }
	inline Value value(RunningContext *ret_ctx) { return make_value_ptr(RUNNING_CONTEXT, ret_ctx); }

	void gc_scan(Value &from);

	std::string inspect(const Value &val);

	template <typename tVal>
	class GCRef : private GCRoot
	{
	private:
		tVal m_val;

	public:
		GCRef(const tVal &val)
		 : GCRoot(value_pool), m_val(val)
		{}
		GCRef(const GCRef<tVal> &ref)
		 : GCRoot(value_pool), m_val(ref.m_val)
		{}

		void scan()
		{
			value_pool.mark(&m_val);
		}

		const tVal &operator*() const { return m_val; }
		tVal &operator*() { return m_val; }
		const tVal &operator->() const { return m_val; }
		tVal &operator->() { return m_val; }
	};

	// Specialize GCRef::scan for Values as we only scan them.
	// They take care of marking themselves.
	template <>
	inline void GCRef<Value>::scan()
	{
		gc_scan(m_val);
	}

	template <typename tVal>
	inline GCRef<tVal> gc_ref(const tVal &val)
	{
		return GCRef<tVal>(val);
	}
}
#include "tuple.hpp"

<commit_msg>Fix a sign extension bug for 32bit platforms<commit_after>#pragma once

#include <vector>

#include "channel9.hpp"
#include "memory_pool.hpp"
#include "string.hpp"

namespace Channel9
{
	union Value
	{
		enum {
			TYPE_SHIFT		= 56,
			TYPE_MASK 		= 0xf000000000000000ULL,
			HEAP_TYPE_MASK  = 0xff00000000000000ULL,
			VALUE_MASK 		= 0x0fffffffffffffffULL,
			POINTER_MASK 	= 0x00007fffffffffffULL,
		};

		uint64_t raw;
		int64_t machine_num;
		double float_num;

		const String *str_p;
		const Tuple *tuple_p;
		const Message *msg_p;
		CallableContext *call_ctx_p;
		RunnableContext *ret_ctx_p;
	};

	extern Value Nil;
	extern Value True;
	extern Value False;
	extern Value Undef;

	inline uint64_t type_mask(ValueType type)
	{
		return (uint64_t)(type) << Value::TYPE_SHIFT;
	}

	inline ValueType basic_type(const Value &val)
	{
		return ValueType((val.raw & Value::TYPE_MASK) >> Value::TYPE_SHIFT);
	}

	inline ValueType type(const Value &val)
	{
		ValueType t = basic_type(val);
		if (t != HEAP_TYPE)
			return t;
		else
			return ValueType((val.raw & Value::HEAP_TYPE_MASK) >> Value::TYPE_SHIFT);
	}
	inline bool is(const Value &val, ValueType t)
	{
		return type(val) == t;
	}
	inline bool is_truthy(const Value &val) { return !((basic_type(val) & FALSY_MASK) == FALSY_PATTERN); }
	inline bool is_number(const Value &val) { ValueType t = basic_type(val); return t == POSITIVE_NUMBER || t == NEGATIVE_NUMBER; }
	inline bool same_type(const Value &l, const Value &r)
	{
		return type(l) == type(r);
	}

	bool complex_compare(const Value &l, const Value &r);

	inline bool operator==(const Value &l, const Value &r)
	{
		if (memcmp(&l, &r, sizeof(Value)) == 0)
			return true;
		else if (same_type(l, r)) {
			return complex_compare(l, r);
		} else {
			return false;
		}
	}
	inline bool operator!=(const Value &l, const Value &r)
	{
		return !(l == r);
	}

	inline const Value &bvalue(bool truthy) { return truthy ? True : False; }

	template <typename tPtr>
	tPtr *ptr(const Value &val)
	{
		DO_DEBUG if (!is(val, CALLABLE_CONTEXT)) assert(value_pool.validate((tPtr*)(val.raw & Value::POINTER_MASK)));
		return (tPtr*)(val.raw & Value::POINTER_MASK);
	}

	template <typename tPtr>
	inline Value make_value_ptr(ValueType type, tPtr value)
	{
		Value val = {type_mask(type) | ((uint64_t)value & Value::POINTER_MASK)};
		return val;
	}
	inline Value value(long long machine_num)
	{//cut off the top 4 bits, maintaining the sign
		uint64_t type = (uint64_t)(machine_num >> 4) & Value::TYPE_MASK;
		uint64_t num = type | ((uint64_t)(machine_num) & Value::VALUE_MASK);
		Value val = {((uint64_t)(num))};
		return val;
	}
	inline Value value(double float_num)
	{//cut off the bottom 4 bits of precision
		uint64_t num = type_mask(FLOAT_NUM) | (*reinterpret_cast<uint64_t*>(&float_num) >> 4);
		Value val = {((uint64_t)(num))};
		return val;
	}
	inline double float_num(Value val)
	{
		uint64_t num = (val.raw & Value::VALUE_MASK) << 4;
		return *reinterpret_cast<double*>(&num);
	}

	inline Value value(const std::string &str) { return make_value_ptr(STRING, new_string(str)); }
	inline Value value(const String *str) { return make_value_ptr(STRING, str); }

	inline Value value(CallableContext *call_ctx) { return make_value_ptr(CALLABLE_CONTEXT, call_ctx); }
	inline Value value(RunnableContext *ret_ctx) { return make_value_ptr(RUNNABLE_CONTEXT, ret_ctx); }
	inline Value value(RunningContext *ret_ctx) { return make_value_ptr(RUNNING_CONTEXT, ret_ctx); }

	void gc_scan(Value &from);

	std::string inspect(const Value &val);

	template <typename tVal>
	class GCRef : private GCRoot
	{
	private:
		tVal m_val;

	public:
		GCRef(const tVal &val)
		 : GCRoot(value_pool), m_val(val)
		{}
		GCRef(const GCRef<tVal> &ref)
		 : GCRoot(value_pool), m_val(ref.m_val)
		{}

		void scan()
		{
			value_pool.mark(&m_val);
		}

		const tVal &operator*() const { return m_val; }
		tVal &operator*() { return m_val; }
		const tVal &operator->() const { return m_val; }
		tVal &operator->() { return m_val; }
	};

	// Specialize GCRef::scan for Values as we only scan them.
	// They take care of marking themselves.
	template <>
	inline void GCRef<Value>::scan()
	{
		gc_scan(m_val);
	}

	template <typename tVal>
	inline GCRef<tVal> gc_ref(const tVal &val)
	{
		return GCRef<tVal>(val);
	}
}
#include "tuple.hpp"

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef GEOJSON_DATASOURCE_HPP
#define GEOJSON_DATASOURCE_HPP

// mapnik
#include <mapnik/datasource.hpp>
#include <mapnik/params.hpp>
#include <mapnik/query.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/coord.hpp>
#include <mapnik/feature_layer_desc.hpp>
#include <mapnik/unicode.hpp>

// boost
#include <boost/optional.hpp>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry.hpp>
#include <boost/version.hpp>
#if BOOST_VERSION >= 105600
#include <boost/geometry/index/rtree.hpp>
#else
#include <boost/geometry/extensions/index/rtree/rtree.hpp>
#endif
#pragma clang diagnostic pop

// stl
#include <memory>
#include <vector>
#include <string>
#include <map>
#include <deque>

class geojson_datasource : public mapnik::datasource
{
public:
    using point_type = boost::geometry::model::d2::point_xy<double>;
    using box_type = boost::geometry::model::box<point_type>;

#if BOOST_VERSION >= 105600
    using item_type = std::pair<box_type,std::size_t>;
    using linear_type = boost::geometry::index::linear<16,1>;
    using spatial_index_type = boost::geometry::index::rtree<item_type,linear_type>;
#else
    using item_type = std::size_t;
    using spatial_index_type = boost::geometry::index::rtree<box_type,std::size_t>;
#endif

    // constructor
    geojson_datasource(mapnik::parameters const& params);
    virtual ~geojson_datasource ();
    mapnik::datasource::datasource_t type() const;
    static const char * name();
    mapnik::featureset_ptr features(mapnik::query const& q) const;
    mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt, double tol = 0) const;
    mapnik::box2d<double> envelope() const;
    mapnik::layer_descriptor get_descriptor() const;
    boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
    template <typename T>
    void parse_geojson(T const& buffer);
private:
    mapnik::datasource::datasource_t type_;
    mapnik::layer_descriptor desc_;
    std::string filename_;
    std::string inline_string_;
    mapnik::box2d<double> extent_;
    std::vector<mapnik::feature_ptr> features_;
    spatial_index_type tree_;
};

#endif // GEOJSON_DATASOURCE_HPP
<commit_msg>use finer control over rtree instantiation<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef GEOJSON_DATASOURCE_HPP
#define GEOJSON_DATASOURCE_HPP

// mapnik
#include <mapnik/datasource.hpp>
#include <mapnik/params.hpp>
#include <mapnik/query.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/coord.hpp>
#include <mapnik/feature_layer_desc.hpp>
#include <mapnik/unicode.hpp>

// boost
#include <boost/optional.hpp>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry.hpp>
#include <boost/version.hpp>
#if BOOST_VERSION >= 105600
#include <boost/geometry/index/rtree.hpp>
#else
#include <boost/geometry/extensions/index/rtree/rtree.hpp>
#endif
#pragma clang diagnostic pop

// stl
#include <memory>
#include <vector>
#include <string>
#include <map>
#include <deque>

#if BOOST_VERSION >= 105600
template <std::size_t Max, std::size_t Min>
struct geojson_linear : boost::geometry::index::linear<Max,Min> {};

namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree {

template <std::size_t Max, std::size_t Min>
struct options_type<geojson_linear<Max,Min> >
{
    using type = options<geojson_linear<Max, Min>,
                         insert_default_tag,
                         choose_by_content_diff_tag,
                         split_default_tag,
                         linear_tag,
                         node_s_mem_static_tag>;
};

}}}}}

#endif //BOOST_VERSION >= 105600

class geojson_datasource : public mapnik::datasource
{
public:
    using point_type = boost::geometry::model::point<double, 2, boost::geometry::cs::cartesian>;
    using box_type = boost::geometry::model::box<point_type>;

#if BOOST_VERSION >= 105600
    using item_type = std::pair<box_type,std::size_t>;
    using spatial_index_type = boost::geometry::index::rtree<item_type,geojson_linear<16,4> >;
#else
    using item_type = std::size_t;
    using spatial_index_type = boost::geometry::index::rtree<box_type,std::size_t>;
#endif

    // constructor
    geojson_datasource(mapnik::parameters const& params);
    virtual ~geojson_datasource ();
    mapnik::datasource::datasource_t type() const;
    static const char * name();
    mapnik::featureset_ptr features(mapnik::query const& q) const;
    mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt, double tol = 0) const;
    mapnik::box2d<double> envelope() const;
    mapnik::layer_descriptor get_descriptor() const;
    boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
    template <typename T>
    void parse_geojson(T const& buffer);
private:
    mapnik::datasource::datasource_t type_;
    mapnik::layer_descriptor desc_;
    std::string filename_;
    std::string inline_string_;
    mapnik::box2d<double> extent_;
    std::vector<mapnik::feature_ptr> features_;
    spatial_index_type tree_;
};

#endif // GEOJSON_DATASOURCE_HPP
<|endoftext|>


<commit_before><commit_msg>Revert r4259<commit_after><|endoftext|>


<commit_before>#include "gc.hh"
#include "atomic.hh"
#include "radix.hh"
#include "cpputil.hh"
#include "hwvm.hh"
#include "uwq.hh"
#include "distref.hh"
#include "bit_spinlock.hh"
#include "radix_array.hh"
#include "kalloc.hh"
#include "page_info.hh"

struct padded_length;

using std::atomic;

// A virtual memory descriptor that maintains metadata for pages in an
// address space.  This plays a similar role to the more traditional
// "virtual memory area," but this does not know its size (it could
// represent a single page or the entire address space).
struct vmdesc
{
  enum {
    // Bit used for radix tree range locking
    FLAG_LOCK_BIT = 0,
    FLAG_LOCK = 1<<FLAG_LOCK_BIT,

    // Set if this virtual page frame has been mapped
    FLAG_MAPPED = 1<<1,

    // Set if this virtual page frame is copy-on-write.  A write fault
    // to this page frame should copy page and unset the COW bit.  A
    // read fault should map the existing page read-only.  This flag
    // should be zero if this VPF has no backing page.
    FLAG_COW = 1<<2,

    // Set if this page frame maps anonymous memory.  Cleared if this
    // page frame maps a file (in which case ip and start are used).
    FLAG_ANON = 1<<3,
  };

  // Flags
  u64 flags;

  // The physical page mapped in this frame, or null if no page has
  // been allocated for this frame.
  sref<class page_info> page;

  // XXX We could pack the following fields into a union if there's
  // anything we can overlap with them for anonymous memory.  However,
  // then we have to use C++11 unrestricted unions because of the
  // sref, so we'd have to define all of vmdesc's special methods
  // ourselves.

  // The file mapped at this page frame.
  sref<struct inode> inode;

  // If a file is mapped at this page frame, the virtual address of
  // that file's 0 byte.  For anonymous memory, this must be 0.  We
  // record this instead of the page frame's offset in the file so
  // that a range of page frames mapping a sequence of pages from a
  // file will be identical (and hence compressable in the radix
  // tree).
  intptr_t start;

  // Construct a descriptor for unmapped memory.
  vmdesc() : flags(0), start(0) { }

  // Construct a descriptor that maps the beginning of ip's file to
  // virtual address start (which may be negative).
  vmdesc(const sref<struct inode> &ip, intptr_t start)
    : flags(FLAG_MAPPED), inode(ip), start(start) { }

  // The anonymous memory descriptor.
  static struct vmdesc anon_desc;

  // Radix_array element methods

  bit_spinlock get_lock()
  {
    return bit_spinlock(&flags, FLAG_LOCK_BIT);
  }

  bool is_set() const
  {
    return flags & FLAG_MAPPED;
  }

private:
  constexpr vmdesc(u64 flags)
    : flags(flags), page(), inode(), start() { }
};

void to_stream(class print_stream *s, const vmdesc &vmd);

// An address space. This manages the mapping from virtual addresses
// to virtual memory descriptors.
struct vmap {
  struct radix vmas;

  static vmap* alloc();

  atomic<u64> ref;
  char *const kshared;

  void decref();
  void incref();

  // Copy this vmap's structure and share pages copy-on-write.
  vmap* copy(proc_pgmap* pgmap);

  // Map desc from virtual addresses start to start+len.
  long insert(const vmdesc &desc, uptr start, uptr len, proc_pgmap* pgmap,
              bool dotlb = true);

  // Unmap from virtual addresses start to start+len.
  int remove(uptr start, uptr len, proc_pgmap* pgmap);

  int pagefault(uptr va, u32 err, proc_pgmap* pgmap);

  // Map virtual address va in this address space to a kernel virtual
  // address, performing the equivalent of a read page fault if
  // necessary.  Returns nullptr if va is not mapped.  Needless to
  // say, this mapping is only valid within the returned page.
  void* pagelookup(uptr va);

  // Copy len bytes from p to user address va in vmap.  Most useful
  // when vmap is not the current page table.
  int copyout(uptr va, void *p, u64 len);
  int sbrk(ssize_t n, uptr *addr);

  void add_pgmap(proc_pgmap* pgmap);
  void rem_pgmap(proc_pgmap* pgmap);

  // Print this vmap to the console
  void dump();

  uptr brk_;                    // Top of heap

private:
  vmap();
  vmap(const vmap&);
  vmap& operator=(const vmap&);
  ~vmap();
  NEW_DELETE_OPS(vmap)
  uptr unmapped_area(size_t n);

  // Virtual page frames
  typedef radix_array<vmdesc, USERTOP / PGSIZE, PGSIZE,
                      kalloc_allocator<vmdesc> > vpf_array;
  vpf_array vpfs_;

  struct spinlock brklock_;

  enum class access_type
  {
    READ, WRITE
  };

  // Ensure there is a backing page at @c it.  The caller is
  // responsible for ensuring that there is a mapping at @c it and for
  // locking vpfs_ at @c it.  This throws bad_alloc if a page must be
  // allocated and cannot be.
  page_info *ensure_page(const vpf_array::iterator &it, access_type type);

  // XXX(sbw) most likely an awful hash function
  static u64 proc_pgmap_hash(proc_pgmap* const & p)
  {
    return (u64) p;
  }
  xns<proc_pgmap*, proc_pgmap*, proc_pgmap_hash> pgmap_list_;
};
<commit_msg>vm.hh tweaks for clang compatibility<commit_after>#include "gc.hh"
#include "atomic.hh"
#include "radix.hh"
#include "cpputil.hh"
#include "hwvm.hh"
#include "uwq.hh"
#include "distref.hh"
#include "bit_spinlock.hh"
#include "radix_array.hh"
#include "kalloc.hh"
#include "page_info.hh"

struct padded_length;

using std::atomic;

// A virtual memory descriptor that maintains metadata for pages in an
// address space.  This plays a similar role to the more traditional
// "virtual memory area," but this does not know its size (it could
// represent a single page or the entire address space).
struct vmdesc
{
  enum {
    // Bit used for radix tree range locking
    FLAG_LOCK_BIT = 0,
    FLAG_LOCK = 1<<FLAG_LOCK_BIT,

    // Set if this virtual page frame has been mapped
    FLAG_MAPPED = 1<<1,

    // Set if this virtual page frame is copy-on-write.  A write fault
    // to this page frame should copy page and unset the COW bit.  A
    // read fault should map the existing page read-only.  This flag
    // should be zero if this VPF has no backing page.
    FLAG_COW = 1<<2,

    // Set if this page frame maps anonymous memory.  Cleared if this
    // page frame maps a file (in which case ip and start are used).
    FLAG_ANON = 1<<3,
  };

  // Flags
  u64 flags;

  // The physical page mapped in this frame, or null if no page has
  // been allocated for this frame.
  sref<class page_info> page;

  // XXX We could pack the following fields into a union if there's
  // anything we can overlap with them for anonymous memory.  However,
  // then we have to use C++11 unrestricted unions because of the
  // sref, so we'd have to define all of vmdesc's special methods
  // ourselves.

  // The file mapped at this page frame.
  sref<struct inode> inode;

  // If a file is mapped at this page frame, the virtual address of
  // that file's 0 byte.  For anonymous memory, this must be 0.  We
  // record this instead of the page frame's offset in the file so
  // that a range of page frames mapping a sequence of pages from a
  // file will be identical (and hence compressable in the radix
  // tree).
  intptr_t start;

  // Construct a descriptor for unmapped memory.
  vmdesc() : flags(0), start(0) { }

  // Construct a descriptor that maps the beginning of ip's file to
  // virtual address start (which may be negative).
  vmdesc(const sref<struct inode> &ip, intptr_t start)
    : flags(FLAG_MAPPED), inode(ip), start(start) { }

  // The anonymous memory descriptor.
  static struct vmdesc anon_desc;

  // Radix_array element methods

  bit_spinlock get_lock()
  {
    return bit_spinlock(&flags, FLAG_LOCK_BIT);
  }

  bool is_set() const
  {
    return flags & FLAG_MAPPED;
  }

private:
  vmdesc(u64 flags)
    : flags(flags), page(), inode(), start() { }
};

void to_stream(class print_stream *s, const vmdesc &vmd);

// An address space. This manages the mapping from virtual addresses
// to virtual memory descriptors.
struct vmap {
  struct radix vmas;

  static vmap* alloc();

  atomic<u64> ref;
  char *const kshared;

  void decref();
  void incref();

  // Copy this vmap's structure and share pages copy-on-write.
  vmap* copy(proc_pgmap* pgmap);

  // Map desc from virtual addresses start to start+len.
  long insert(const vmdesc &desc, uptr start, uptr len, proc_pgmap* pgmap,
              bool dotlb = true);

  // Unmap from virtual addresses start to start+len.
  int remove(uptr start, uptr len, proc_pgmap* pgmap);

  int pagefault(uptr va, u32 err, proc_pgmap* pgmap);

  // Map virtual address va in this address space to a kernel virtual
  // address, performing the equivalent of a read page fault if
  // necessary.  Returns nullptr if va is not mapped.  Needless to
  // say, this mapping is only valid within the returned page.
  void* pagelookup(uptr va);

  // Copy len bytes from p to user address va in vmap.  Most useful
  // when vmap is not the current page table.
  int copyout(uptr va, void *p, u64 len);
  int sbrk(ssize_t n, uptr *addr);

  void add_pgmap(proc_pgmap* pgmap);
  void rem_pgmap(proc_pgmap* pgmap);

  // Print this vmap to the console
  void dump();

  uptr brk_;                    // Top of heap

private:
  vmap();
  vmap(const vmap&);
  vmap& operator=(const vmap&);
  ~vmap();
  NEW_DELETE_OPS(vmap)
  uptr unmapped_area(size_t n);

  // Virtual page frames
  typedef radix_array<vmdesc, USERTOP / PGSIZE, PGSIZE,
                      kalloc_allocator<vmdesc> > vpf_array;
  vpf_array vpfs_;

  struct spinlock brklock_;

  enum class access_type
  {
    READ, WRITE
  };

  // Ensure there is a backing page at @c it.  The caller is
  // responsible for ensuring that there is a mapping at @c it and for
  // locking vpfs_ at @c it.  This throws bad_alloc if a page must be
  // allocated and cannot be.
  page_info *ensure_page(const vpf_array::iterator &it, access_type type);

  // XXX(sbw) most likely an awful hash function
  static u64 proc_pgmap_hash(proc_pgmap* const & p)
  {
    return (u64) p;
  }
  xns<proc_pgmap*, proc_pgmap*, proc_pgmap_hash> pgmap_list_;
};
<|endoftext|>


<commit_before>/* <src/HttpWorker.cpp>
 *
 * This file is part of the x0 web server project and is released under AGPL-3.
 * http://www.xzero.io/
 *
 * (c) 2009-2014 Christian Parpart <trapni@gmail.com>
 */

#include <x0/http/HttpWorker.h>
#include <x0/http/HttpRequest.h>
#include <x0/http/HttpServer.h>
#include <x0/http/HttpConnection.h>
#include <x0/ServerSocket.h>
#include <x0/DebugLogger.h>
#include <x0/sysconfig.h>

#include <algorithm>
#include <cstdarg>
#include <ev++.h>
#include <signal.h>
#include <pthread.h>

// XXX one a connection has been passed to a worker, it is *bound* to it.

#if 0//!defined(XZERO_NDEBUG)
//#	define TRACE(n, msg...) X0_DEBUG("worker", (n), msg)
#	define TRACE(n, msg...) log(Severity::debug ## n, msg)
#else
#	define TRACE(n, msg...) do {} while (0)
#endif

namespace x0 {

/*!
 * Creates an HTTP worker instance.
 *
 * \param server   the worker parents server instance
 * \param loop     the event loop to be used within this worker
 * \param id       unique ID within the server instance
 * \param threaded whether or not to spawn a thread to actually run this worker
 */
HttpWorker::HttpWorker(HttpServer& server, struct ev_loop *loop, unsigned int id, bool threaded) :
	id_(id),
	state_(Inactive),
	server_(server),
	loop_(loop),
	startupTime_(ev_now(loop_)),
	now_(),
	connectionLoad_(0),
	requestCount_(0),
	connectionCount_(0),
	thread_(pthread_self()),
	queue_(),
	resumeLock_(),
	resumeCondition_(),
	performanceCounter_(),
	stopHandler_(),
	killHandler_(),
	connections_(nullptr),
	freeConnections_(nullptr),
	evLoopCheck_(loop_),
	evNewConnection_(loop_),
	evWakeup_(loop_),
#if !defined(X0_WORKER_POST_LIBEV)
	postLock_(),
	postQueue_(),
#endif
	fileinfo(loop_, &server_.fileinfoConfig_)
{
#if !defined(X0_WORKER_POST_LIBEV)
	pthread_mutex_init(&postLock_, nullptr);
#endif

	evLoopCheck_.set<HttpWorker, &HttpWorker::onLoopCheck>(this);
	evLoopCheck_.start();

	evNewConnection_.set<HttpWorker, &HttpWorker::onNewConnection>(this);
	evNewConnection_.start();

	evWakeup_.set<HttpWorker, &HttpWorker::onWakeup>(this);
	evWakeup_.start();

	pthread_mutex_init(&resumeLock_, nullptr);
	pthread_cond_init(&resumeCondition_, nullptr);

	if (threaded) {
		pthread_create(&thread_, nullptr, &HttpWorker::_run, this);
	}

	setName("xzero-io/%d", id_);

	TRACE(1, "spawned");
}

HttpWorker::~HttpWorker()
{
	TRACE(1, "destroying");

	clearCustomData();

#if !defined(X0_WORKER_POST_LIBEV)
	pthread_mutex_destroy(&postLock_);
#endif

	pthread_cond_destroy(&resumeCondition_);
	pthread_mutex_destroy(&resumeLock_);

	evLoopCheck_.stop();
	evNewConnection_.stop();
	evWakeup_.stop();

	freeCache();
}

void* HttpWorker::_run(void* p)
{
	reinterpret_cast<HttpWorker*>(p)->run();
	return nullptr;
}

void HttpWorker::run()
{
	state_ = Running;

	// XXX invoke onWorkerSpawned-hook here because we want to ensure this hook is
	// XXX being invoked from *within* the worker-thread.
	server_.onWorkerSpawn(this);

	TRACE(1, "enter loop");
	ev_loop(loop_, 0);

	while (connections_)
		_kill();

	server_.onWorkerUnspawn(this);

	state_ = Inactive;
}

/*!
 * Sets the thread/process name that's running this worker.
 */
void HttpWorker::setName(const char* fmt, ...)
{
	char buf[17]; // the name may be at most 16 bytes long.
	va_list va;

	va_start(va, fmt);
	vsnprintf(buf, sizeof(buf), fmt, va);
	va_end(va);

#if defined(HAVE_PTHREAD_SETNAME_NP)
	pthread_setname_np(thread_, buf);
#endif
}

void HttpWorker::log(LogMessage&& msg)
{
	msg.addTag("worker/%u", id());

	server().log(std::forward<LogMessage>(msg));
}

/** enqueues/assigns/registers given client connection information to this worker.
 */
void HttpWorker::enqueue(std::pair<Socket*, ServerSocket*>&& client)
{
	queue_.enqueue(client);
	evNewConnection_.send();
}

/** callback to be invoked when new connection(s) have been assigned to this worker.
 */
void HttpWorker::onNewConnection(ev::async& /*w*/, int /*revents*/)
{
	std::pair<Socket*, ServerSocket*> client;

	while (queue_.dequeue(&client)) {
		spawnConnection(client.first, client.second);
	}
}

void HttpWorker::onWakeup(ev::async& w, int revents)
{
	std::function<void()> fn;

	while (true) {
		pthread_mutex_lock(&postLock_);
		if (postQueue_.empty())
			goto out;

		fn = postQueue_.front();
		postQueue_.pop_front();
		pthread_mutex_unlock(&postLock_);

		if (fn) {
			fn();
		}
	}

out:
	pthread_mutex_unlock(&postLock_);
}

void HttpWorker::spawnConnection(Socket* client, ServerSocket* listener)
{
	TRACE(1, "client connected; fd:%d", client->handle());

	++connectionLoad_;
	++connectionCount_;

	// XXX since socket has not been used so far, I might be able to defer its creation out of its socket descriptor
	// XXX so that I do not have to double-initialize libev's loop handles for this socket.
	client->setLoop(loop_);

	HttpConnection* c;
	if (likely(freeConnections_ != nullptr)) {
		c = freeConnections_;
		freeConnections_ = c->next_;

        c->revive(connectionCount_/*id*/);
	}
	else {
		c = new HttpConnection(this, connectionCount_/*id*/);
	}

	if (connections_)
		connections_->prev_ = c;

	c->next_ = connections_;
	connections_ = c;

	c->start(listener, client);
}

/** releases/unregisters given (and to-be-destroyed) connection from this worker.
 *
 * This decrements the connection-load counter by one.
 */
void HttpWorker::release(HttpConnection* c)
{
	//    /--<--\   /--<--\   /--<--\
	// NULL     item1     item2     item3     NULL
	//              \-->--/   \-->--/   \-->--/

	--connectionLoad_;

	// unlink from active-list
	HttpConnection* prev = c->prev_;
	HttpConnection* next = c->next_;

	if (prev)
		prev->next_ = next;

	if (next)
		next->prev_ = prev;

	if (c == connections_)
		connections_ = next;

	// link into free-list
	c->next_ = freeConnections_;
	c->prev_ = nullptr;					// not needed
	if (freeConnections_ && freeConnections_->prev_)
		freeConnections_->prev_ = c;	// not needed
	freeConnections_ = c;
}

/**
 * Clear some cached objects to free up memory.
 */
void HttpWorker::freeCache()
{
	size_t i = 0;
	while (freeConnections_) {
		auto next = freeConnections_->next_;
		delete freeConnections_;
		freeConnections_ = next;
		++i;
	}
	TRACE(1, "cleared %zu free-connections items", i);
}

void HttpWorker::handleRequest(HttpRequest *r)
{
	++requestCount_;
	performanceCounter_.touch(now_.value());

	BufferRef expectHeader = r->requestHeader("Expect");
	bool contentRequired = r->method == "POST" || r->method == "PUT";

	if (contentRequired) {
		if (r->connection.contentLength() == -1 && !r->connection.isChunked()) {
			r->status = HttpStatus::LengthRequired;
			r->finish();
			return;
		}
	} else {
		if (r->contentAvailable()) {
			r->status = HttpStatus::BadRequest; // FIXME do we have a better status code?
			r->finish();
			return;
		}
	}

	if (expectHeader) {
		r->expectingContinue = equals(expectHeader, "100-continue");

		if (!r->expectingContinue || !r->supportsProtocol(1, 1)) {
			r->status = HttpStatus::ExpectationFailed;
			r->finish();
			return;
		}
	}

	server_.onPreProcess(r);

	if (!server_.requestHandler(r))
		r->finish();
}

void HttpWorker::_stop()
{
	TRACE(1, "_stop");

	evLoopCheck_.stop();
	evNewConnection_.stop();
	evWakeup_.stop();

	for (auto handler: stopHandler_)
		handler();
}

void HttpWorker::onLoopCheck(ev::check& /*w*/, int /*revents*/)
{
	// update server time
	now_.update(ev_now(loop_));
}

void HttpWorker::setAffinity(int cpu)
{
#ifdef HAVE_PTHREAD_SETAFFINITY_NP
	cpu_set_t set;

	CPU_ZERO(&set);
	CPU_SET(cpu, &set);

	TRACE(1, "setAffinity: %d", cpu);

	int rv = pthread_setaffinity_np(thread_, sizeof(set), &set);
	if (rv < 0) {
		log(Severity::error, "setting scheduler affinity on CPU %d failed for worker %u. %s", cpu, id_, strerror(errno));
	}
#else
	log(Severity::error, "setting scheduler affinity on CPU %d failed for worker %u. %s", cpu, id_, strerror(ENOTSUP));
#endif
}

void HttpWorker::bind(ServerSocket* s)
{
	s->set<HttpWorker, &HttpWorker::spawnConnection>(this);
}

/** suspend the execution of the worker thread until resume() is invoked.
 *
 * \note has no effect on main worker
 * \see resume()
 */
void HttpWorker::suspend()
{
	TRACE(1, "suspend");

	if (id_ != 0)
		post<HttpWorker, &HttpWorker::_suspend>(this);
}

void HttpWorker::_suspend()
{
	TRACE(1, "_suspend");
	pthread_mutex_lock(&resumeLock_);
	state_ = Suspended;
	pthread_cond_wait(&resumeCondition_, &resumeLock_);
	state_ = Running;
	pthread_mutex_unlock(&resumeLock_);
}

/** resumes the previousely suspended worker thread.
 *
 * \note has no effect on main worker
 * \see suspend()
 */
void HttpWorker::resume()
{
	TRACE(1, "resume");
	if (id_ != 0)
		pthread_cond_signal(&resumeCondition_);
}

void HttpWorker::stop()
{
	TRACE(1, "stop: post -> _stop() (while in state: %d)", state_);

	if (state_ != Running)
		return;

//	fileinfo.stop();

	post<HttpWorker, &HttpWorker::_stop>(this);
}

void HttpWorker::join()
{
	if (thread_ != pthread_self()) {
		pthread_join(thread_, nullptr);
	}
}

/*! Actually aborts all active connections.
 *
 * \see HttpConnection::abort()
 */
void HttpWorker::kill()
{
	TRACE(1, "kill: post -> _kill()");
	post<HttpWorker, &HttpWorker::_kill>(this);
}

/*! Actually aborts all active connections.
 *
 * \note Must be invoked from within the worker's thread.
 *
 * \see HttpConnection::abort()
 */
void HttpWorker::_kill()
{
	TRACE(1, "_kill()");
	while (connections_) {
		std::list<HttpConnection*> copy;

		for (HttpConnection* c = connections_; c != nullptr; c = c->next_)
			copy.push_back(c);

		for (auto c: copy)
			c->abort();

#ifndef XZERO_NDEBUG
		for (HttpConnection* c = connections_; c != nullptr; c = c->next_)
			c->log(Severity::debug, "connection still open");
#endif
	}

	for (auto handler: killHandler_) {
		TRACE(1, "_kill: invoke kill handler");
		handler();
	}
}

std::list<std::function<void()>>::iterator HttpWorker::registerStopHandler(std::function<void()> callback)
{
	stopHandler_.push_front(callback);
	return stopHandler_.begin();
}

void HttpWorker::unregisterStopHandler(std::list<std::function<void()>>::iterator handle)
{
	stopHandler_.erase(handle);
}

std::list<std::function<void()>>::iterator HttpWorker::registerKillHandler(std::function<void()> callback)
{
	killHandler_.push_front(callback);
	return killHandler_.begin();
}

void HttpWorker::unregisterKillHandler(std::list<std::function<void()>>::iterator handle)
{
	killHandler_.erase(handle);
}

void HttpWorker::post_thunk3(int revents, void* arg)
{
	std::function<void()>* callback = static_cast<std::function<void()>*>(arg);
	(*callback)();
	delete callback;
}

} // namespace x0
<commit_msg>http: respect max_request_body_size cvar<commit_after>/* <src/HttpWorker.cpp>
 *
 * This file is part of the x0 web server project and is released under AGPL-3.
 * http://www.xzero.io/
 *
 * (c) 2009-2014 Christian Parpart <trapni@gmail.com>
 */

#include <x0/http/HttpWorker.h>
#include <x0/http/HttpRequest.h>
#include <x0/http/HttpServer.h>
#include <x0/http/HttpConnection.h>
#include <x0/ServerSocket.h>
#include <x0/DebugLogger.h>
#include <x0/sysconfig.h>

#include <algorithm>
#include <cstdarg>
#include <ev++.h>
#include <signal.h>
#include <pthread.h>

// XXX one a connection has been passed to a worker, it is *bound* to it.

#if 0//!defined(XZERO_NDEBUG)
//#	define TRACE(n, msg...) X0_DEBUG("worker", (n), msg)
#	define TRACE(n, msg...) log(Severity::debug ## n, msg)
#else
#	define TRACE(n, msg...) do {} while (0)
#endif

namespace x0 {

/*!
 * Creates an HTTP worker instance.
 *
 * \param server   the worker parents server instance
 * \param loop     the event loop to be used within this worker
 * \param id       unique ID within the server instance
 * \param threaded whether or not to spawn a thread to actually run this worker
 */
HttpWorker::HttpWorker(HttpServer& server, struct ev_loop *loop, unsigned int id, bool threaded) :
	id_(id),
	state_(Inactive),
	server_(server),
	loop_(loop),
	startupTime_(ev_now(loop_)),
	now_(),
	connectionLoad_(0),
	requestCount_(0),
	connectionCount_(0),
	thread_(pthread_self()),
	queue_(),
	resumeLock_(),
	resumeCondition_(),
	performanceCounter_(),
	stopHandler_(),
	killHandler_(),
	connections_(nullptr),
	freeConnections_(nullptr),
	evLoopCheck_(loop_),
	evNewConnection_(loop_),
	evWakeup_(loop_),
#if !defined(X0_WORKER_POST_LIBEV)
	postLock_(),
	postQueue_(),
#endif
	fileinfo(loop_, &server_.fileinfoConfig_)
{
#if !defined(X0_WORKER_POST_LIBEV)
	pthread_mutex_init(&postLock_, nullptr);
#endif

	evLoopCheck_.set<HttpWorker, &HttpWorker::onLoopCheck>(this);
	evLoopCheck_.start();

	evNewConnection_.set<HttpWorker, &HttpWorker::onNewConnection>(this);
	evNewConnection_.start();

	evWakeup_.set<HttpWorker, &HttpWorker::onWakeup>(this);
	evWakeup_.start();

	pthread_mutex_init(&resumeLock_, nullptr);
	pthread_cond_init(&resumeCondition_, nullptr);

	if (threaded) {
		pthread_create(&thread_, nullptr, &HttpWorker::_run, this);
	}

	setName("xzero-io/%d", id_);

	TRACE(1, "spawned");
}

HttpWorker::~HttpWorker()
{
	TRACE(1, "destroying");

	clearCustomData();

#if !defined(X0_WORKER_POST_LIBEV)
	pthread_mutex_destroy(&postLock_);
#endif

	pthread_cond_destroy(&resumeCondition_);
	pthread_mutex_destroy(&resumeLock_);

	evLoopCheck_.stop();
	evNewConnection_.stop();
	evWakeup_.stop();

	freeCache();
}

void* HttpWorker::_run(void* p)
{
	reinterpret_cast<HttpWorker*>(p)->run();
	return nullptr;
}

void HttpWorker::run()
{
	state_ = Running;

	// XXX invoke onWorkerSpawned-hook here because we want to ensure this hook is
	// XXX being invoked from *within* the worker-thread.
	server_.onWorkerSpawn(this);

	TRACE(1, "enter loop");
	ev_loop(loop_, 0);

	while (connections_)
		_kill();

	server_.onWorkerUnspawn(this);

	state_ = Inactive;
}

/*!
 * Sets the thread/process name that's running this worker.
 */
void HttpWorker::setName(const char* fmt, ...)
{
	char buf[17]; // the name may be at most 16 bytes long.
	va_list va;

	va_start(va, fmt);
	vsnprintf(buf, sizeof(buf), fmt, va);
	va_end(va);

#if defined(HAVE_PTHREAD_SETNAME_NP)
	pthread_setname_np(thread_, buf);
#endif
}

void HttpWorker::log(LogMessage&& msg)
{
	msg.addTag("worker/%u", id());

	server().log(std::forward<LogMessage>(msg));
}

/** enqueues/assigns/registers given client connection information to this worker.
 */
void HttpWorker::enqueue(std::pair<Socket*, ServerSocket*>&& client)
{
	queue_.enqueue(client);
	evNewConnection_.send();
}

/** callback to be invoked when new connection(s) have been assigned to this worker.
 */
void HttpWorker::onNewConnection(ev::async& /*w*/, int /*revents*/)
{
	std::pair<Socket*, ServerSocket*> client;

	while (queue_.dequeue(&client)) {
		spawnConnection(client.first, client.second);
	}
}

void HttpWorker::onWakeup(ev::async& w, int revents)
{
	std::function<void()> fn;

	while (true) {
		pthread_mutex_lock(&postLock_);
		if (postQueue_.empty())
			goto out;

		fn = postQueue_.front();
		postQueue_.pop_front();
		pthread_mutex_unlock(&postLock_);

		if (fn) {
			fn();
		}
	}

out:
	pthread_mutex_unlock(&postLock_);
}

void HttpWorker::spawnConnection(Socket* client, ServerSocket* listener)
{
	TRACE(1, "client connected; fd:%d", client->handle());

	++connectionLoad_;
	++connectionCount_;

	// XXX since socket has not been used so far, I might be able to defer its creation out of its socket descriptor
	// XXX so that I do not have to double-initialize libev's loop handles for this socket.
	client->setLoop(loop_);

	HttpConnection* c;
	if (likely(freeConnections_ != nullptr)) {
		c = freeConnections_;
		freeConnections_ = c->next_;

        c->revive(connectionCount_/*id*/);
	}
	else {
		c = new HttpConnection(this, connectionCount_/*id*/);
	}

	if (connections_)
		connections_->prev_ = c;

	c->next_ = connections_;
	connections_ = c;

	c->start(listener, client);
}

/** releases/unregisters given (and to-be-destroyed) connection from this worker.
 *
 * This decrements the connection-load counter by one.
 */
void HttpWorker::release(HttpConnection* c)
{
	//    /--<--\   /--<--\   /--<--\
	// NULL     item1     item2     item3     NULL
	//              \-->--/   \-->--/   \-->--/

	--connectionLoad_;

	// unlink from active-list
	HttpConnection* prev = c->prev_;
	HttpConnection* next = c->next_;

	if (prev)
		prev->next_ = next;

	if (next)
		next->prev_ = prev;

	if (c == connections_)
		connections_ = next;

	// link into free-list
	c->next_ = freeConnections_;
	c->prev_ = nullptr;					// not needed
	if (freeConnections_ && freeConnections_->prev_)
		freeConnections_->prev_ = c;	// not needed
	freeConnections_ = c;
}

/**
 * Clear some cached objects to free up memory.
 */
void HttpWorker::freeCache()
{
	size_t i = 0;
	while (freeConnections_) {
		auto next = freeConnections_->next_;
		delete freeConnections_;
		freeConnections_ = next;
		++i;
	}
	TRACE(1, "cleared %zu free-connections items", i);
}

void HttpWorker::handleRequest(HttpRequest *r)
{
	++requestCount_;
	performanceCounter_.touch(now_.value());

	BufferRef expectHeader = r->requestHeader("Expect");
	bool contentRequired = r->method == "POST" || r->method == "PUT";

	if (contentRequired) {
		if (r->connection.contentLength() == -1 && !r->connection.isChunked()) {
			r->status = HttpStatus::LengthRequired;
			r->finish();
			return;
		}
        if (r->connection.contentLength() > server().maxRequestBodySize()) {
			r->status = HttpStatus::RequestEntityTooLarge;
			r->finish();
			return;
        }
	} else {
		if (r->contentAvailable()) {
			r->status = HttpStatus::BadRequest; // FIXME do we have a better status code?
			r->finish();
			return;
		}
	}

	if (expectHeader) {
		r->expectingContinue = equals(expectHeader, "100-continue");

		if (!r->expectingContinue || !r->supportsProtocol(1, 1)) {
			r->status = HttpStatus::ExpectationFailed;
			r->finish();
			return;
		}
	}

	server_.onPreProcess(r);

	if (!server_.requestHandler(r))
		r->finish();
}

void HttpWorker::_stop()
{
	TRACE(1, "_stop");

	evLoopCheck_.stop();
	evNewConnection_.stop();
	evWakeup_.stop();

	for (auto handler: stopHandler_)
		handler();
}

void HttpWorker::onLoopCheck(ev::check& /*w*/, int /*revents*/)
{
	// update server time
	now_.update(ev_now(loop_));
}

void HttpWorker::setAffinity(int cpu)
{
#ifdef HAVE_PTHREAD_SETAFFINITY_NP
	cpu_set_t set;

	CPU_ZERO(&set);
	CPU_SET(cpu, &set);

	TRACE(1, "setAffinity: %d", cpu);

	int rv = pthread_setaffinity_np(thread_, sizeof(set), &set);
	if (rv < 0) {
		log(Severity::error, "setting scheduler affinity on CPU %d failed for worker %u. %s", cpu, id_, strerror(errno));
	}
#else
	log(Severity::error, "setting scheduler affinity on CPU %d failed for worker %u. %s", cpu, id_, strerror(ENOTSUP));
#endif
}

void HttpWorker::bind(ServerSocket* s)
{
	s->set<HttpWorker, &HttpWorker::spawnConnection>(this);
}

/** suspend the execution of the worker thread until resume() is invoked.
 *
 * \note has no effect on main worker
 * \see resume()
 */
void HttpWorker::suspend()
{
	TRACE(1, "suspend");

	if (id_ != 0)
		post<HttpWorker, &HttpWorker::_suspend>(this);
}

void HttpWorker::_suspend()
{
	TRACE(1, "_suspend");
	pthread_mutex_lock(&resumeLock_);
	state_ = Suspended;
	pthread_cond_wait(&resumeCondition_, &resumeLock_);
	state_ = Running;
	pthread_mutex_unlock(&resumeLock_);
}

/** resumes the previousely suspended worker thread.
 *
 * \note has no effect on main worker
 * \see suspend()
 */
void HttpWorker::resume()
{
	TRACE(1, "resume");
	if (id_ != 0)
		pthread_cond_signal(&resumeCondition_);
}

void HttpWorker::stop()
{
	TRACE(1, "stop: post -> _stop() (while in state: %d)", state_);

	if (state_ != Running)
		return;

//	fileinfo.stop();

	post<HttpWorker, &HttpWorker::_stop>(this);
}

void HttpWorker::join()
{
	if (thread_ != pthread_self()) {
		pthread_join(thread_, nullptr);
	}
}

/*! Actually aborts all active connections.
 *
 * \see HttpConnection::abort()
 */
void HttpWorker::kill()
{
	TRACE(1, "kill: post -> _kill()");
	post<HttpWorker, &HttpWorker::_kill>(this);
}

/*! Actually aborts all active connections.
 *
 * \note Must be invoked from within the worker's thread.
 *
 * \see HttpConnection::abort()
 */
void HttpWorker::_kill()
{
	TRACE(1, "_kill()");
	while (connections_) {
		std::list<HttpConnection*> copy;

		for (HttpConnection* c = connections_; c != nullptr; c = c->next_)
			copy.push_back(c);

		for (auto c: copy)
			c->abort();

#ifndef XZERO_NDEBUG
		for (HttpConnection* c = connections_; c != nullptr; c = c->next_)
			c->log(Severity::debug, "connection still open");
#endif
	}

	for (auto handler: killHandler_) {
		TRACE(1, "_kill: invoke kill handler");
		handler();
	}
}

std::list<std::function<void()>>::iterator HttpWorker::registerStopHandler(std::function<void()> callback)
{
	stopHandler_.push_front(callback);
	return stopHandler_.begin();
}

void HttpWorker::unregisterStopHandler(std::list<std::function<void()>>::iterator handle)
{
	stopHandler_.erase(handle);
}

std::list<std::function<void()>>::iterator HttpWorker::registerKillHandler(std::function<void()> callback)
{
	killHandler_.push_front(callback);
	return killHandler_.begin();
}

void HttpWorker::unregisterKillHandler(std::list<std::function<void()>>::iterator handle)
{
	killHandler_.erase(handle);
}

void HttpWorker::post_thunk3(int revents, void* arg)
{
	std::function<void()>* callback = static_cast<std::function<void()>*>(arg);
	(*callback)();
	delete callback;
}

} // namespace x0
<|endoftext|>


<commit_before>// Time:  O(n)
// Space: O(n)

class Solution {
public:
    int findMaxLength(vector<int>& nums) {
        int result = 0, count = 0;
        unordered_map<int, int> lookup;
        lookup[0] = 0;
        for (int i = 0; i < nums.size(); ++i) {
            count += nums[i] == 1 ? 1 : -1;
            if (lookup.count(count)) {
                result = max(result, i + 1 - lookup[count]);
            } else {
                lookup[count] = i + 1;
            }
        }
        return result;
    }
};
<commit_msg>Update contiguous-array.cpp<commit_after>// Time:  O(n)
// Space: O(n)

class Solution {
public:
    int findMaxLength(vector<int>& nums) {
        int result = 0, count = 0;
        unordered_map<int, int> lookup;
        lookup[0] = -1;
        for (int i = 0; i < nums.size(); ++i) {
            count += nums[i] == 1 ? 1 : -1;
            if (lookup.count(count)) {
                result = max(result, i - lookup[count]);
            } else {
                lookup[count] = i;
            }
        }
        return result;
    }
};
<|endoftext|>


<commit_before>#include <oculus_viewer/viewer.h>
#include <iostream>

namespace oculus_viewer
{

    Viewer::Viewer(const std::string& window_name): window_name_(window_name), display_size_(1280, 800)
    {

    }

    void Viewer::show(const cv::Mat& right_image,const cv::Mat& left_image)
    {
        cv::Mat dst_right;
        cv::Mat dst_left;
        const double scale = static_cast<double>(display_size_.width/2) / right_image.cols;
        cv::resize(right_image, dst_right, cv::Size(), scale, scale);
        cv::resize(left_image, dst_left, cv::Size(), scale, scale);

        const double centering_offset_y =(display_size_.height - dst_right.rows) / 2;

        cv::Mat combined(display_size_.height,display_size_.width,dst_right.type());
        cv::Mat roi_right = combined(cv::Rect(display_size_.width/2 - display_offset_x_/2,
                            centering_offset_y,
                            dst_left.cols,
                            dst_left.rows));
        dst_right.copyTo(roi_right);
        cv::Mat roi_left = combined(cv::Rect(display_offset_x_/2 + display_offset_x_/2,
                            display_offset_y_ + centering_offset_y,
                            dst_right.cols,
                            dst_right.rows));
        dst_left.copyTo(roi_left);
        cv::imshow(window_name_, combined);
    }

}  // namespace oculus_viewer
<commit_msg>apply display_offset_y_ to both images<commit_after>#include <oculus_viewer/viewer.h>
#include <iostream>

namespace oculus_viewer
{

    Viewer::Viewer(const std::string& window_name): window_name_(window_name), display_size_(1280, 800)
    {

    }

    void Viewer::show(const cv::Mat& right_image,const cv::Mat& left_image)
    {
        cv::Mat dst_right;
        cv::Mat dst_left;
        const double scale = static_cast<double>(display_size_.width/2) / right_image.cols;
        cv::resize(right_image, dst_right, cv::Size(), scale, scale);
        cv::resize(left_image, dst_left, cv::Size(), scale, scale);

        const double centering_offset_y =(display_size_.height - dst_right.rows) / 2;

        cv::Mat combined(display_size_.height,display_size_.width,dst_right.type());
        cv::Mat roi_right = combined(cv::Rect(display_size_.width/2 - display_offset_x_/2,
                            display_offset_y_ + centering_offset_y,
                            dst_left.cols,
                            dst_left.rows));
        dst_right.copyTo(roi_right);
        cv::Mat roi_left = combined(cv::Rect(display_offset_x_/2 + display_offset_x_/2,
                            display_offset_y_ + centering_offset_y,
                            dst_right.cols,
                            dst_right.rows));
        dst_left.copyTo(roi_left);
        cv::imshow(window_name_, combined);
    }

}  // namespace oculus_viewer
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Daniele Bartolini, Michele Rossi
Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

#include "Allocator.h"
#include "File.h"
#include "Filesystem.h"
#include "StringUtils.h"
#include "JSONParser.h"
#include "Log.h"
#include "PackageResource.h"
#include "TempAllocator.h"

namespace crown
{
namespace package_resource
{

//-----------------------------------------------------------------------------
void compile(Filesystem& fs, const char* resource_path, File* out_file)
{
	File* file = fs.open(resource_path, FOM_READ);

	char file_buf[4096];
	file->read(file_buf, file->size());
	fs.close(file);

	JSONParser json(file_buf);
	JSONElement root = json.root();

	Array<ResourceId> m_texture(default_allocator());
	Array<ResourceId> m_script(default_allocator());
	Array<ResourceId> m_sound(default_allocator());
	Array<ResourceId> m_mesh(default_allocator());
	Array<ResourceId> m_unit(default_allocator());
	Array<ResourceId> m_sprite(default_allocator());
	Array<ResourceId> m_physics(default_allocator());
	Array<ResourceId> m_materials(default_allocator());
	Array<ResourceId> m_guis(default_allocator());
	Array<ResourceId> m_fonts(default_allocator());
	Array<ResourceId> m_levels(default_allocator());

	// Check for resource types
	if (root.has_key("texture"))
	{
		JSONElement texture_array = root.key("texture");
		uint32_t texture_array_size = texture_array.size();

		for (uint32_t i = 0; i < texture_array_size; i++)
		{
			DynamicString texture_name;
			texture_array[i].to_string(texture_name); texture_name += ".texture";

			if (!fs.is_file(texture_name.c_str()))
			{
				CE_LOGE("Texture '%s' does not exist.", texture_name.c_str());
				return;
			}

			array::push_back(m_texture, ResourceId(texture_name.c_str()));
		}
	}

	// Check for scripts
	if (root.has_key("lua"))
	{
		JSONElement lua_array = root.key("lua");
		//lua_array = root.key("lua");
		uint32_t lua_array_size = lua_array.size();

		for (uint32_t i = 0; i < lua_array_size; i++)
		{
			DynamicString lua_name;
			lua_array[i].to_string(lua_name); lua_name += ".lua";

			if (!fs.is_file(lua_name.c_str()))
			{
				CE_LOGE("Lua script '%s' does not exist.", lua_name.c_str());
				return;
			}

			array::push_back(m_script, ResourceId(lua_name.c_str()));
		}
	}

	// Check for sounds
	if (root.has_key("sound"))
	{
		JSONElement sound_array = root.key("sound");
		uint32_t sound_array_size = sound_array.size();

		for (uint32_t i = 0; i < sound_array_size; i++)
		{
			DynamicString sound_name;
			sound_array[i].to_string(sound_name); sound_name += ".sound";

			if (!fs.is_file(sound_name.c_str()))
			{
				CE_LOGE("Sound '%s' does not exist.", sound_name.c_str());
				return;
			}

			array::push_back(m_sound, ResourceId(sound_name.c_str()));
		}
	}

	// Check for meshes
	if (root.has_key("mesh"))
	{
		JSONElement mesh_array = root.key("mesh");
		uint32_t mesh_array_size = mesh_array.size();

		for (uint32_t i = 0; i < mesh_array_size; i++)
		{
			DynamicString mesh_name;
			mesh_array[i].to_string(mesh_name); mesh_name += ".mesh";

			if (!fs.is_file(mesh_name.c_str()))
			{
				CE_LOGE("Mesh '%s' does not exist.", mesh_name.c_str());
				return;
			}

			array::push_back(m_mesh, ResourceId(mesh_name.c_str()));
		}
	}

	// Check for units
	if (root.has_key("unit"))
	{
		JSONElement unit_array = root.key("unit");
		uint32_t unit_array_size = unit_array.size();

		for (uint32_t i = 0; i < unit_array_size; i++)
		{
			DynamicString unit_name;
			unit_array[i].to_string(unit_name); unit_name += ".unit";

			if (!fs.is_file(unit_name.c_str()))
			{
				CE_LOGE("Unit '%s' does not exist.", unit_name.c_str());
			}

			array::push_back(m_unit, ResourceId(unit_name.c_str()));
		}
	}

	// Check for meshes
	if (root.has_key("sprite"))
	{
		JSONElement sprite_array = root.key("sprite");
		uint32_t sprite_array_size = sprite_array.size();

		for (uint32_t i = 0; i < sprite_array_size; i++)
		{
			DynamicString sprite_name;
			sprite_array[i].to_string(sprite_name); sprite_name += ".sprite";

			if (!fs.is_file(sprite_name.c_str()))
			{
				CE_LOGE("Sprite '%s' does not exist.", sprite_name.c_str());
				return;
			}

			array::push_back(m_sprite, ResourceId(sprite_name.c_str()));
		}
	}

	// Check for physics
	if (root.has_key("physics"))
	{
		JSONElement physics_array = root.key("physics");
		uint32_t physics_array_size = physics_array.size();

		for (uint32_t i = 0; i < physics_array_size; i++)
		{
			DynamicString physics_name;
			physics_array[i].to_string(physics_name); physics_name += ".physics";

			if (!fs.is_file(physics_name.c_str()))
			{
				CE_LOGE("Physics '%s' does not exist.", physics_name.c_str());
				return;
			}

			array::push_back(m_physics, ResourceId(physics_name.c_str()));
		}
	}

	// Check for materials
	if (root.has_key("material"))
	{
		JSONElement materials_array = root.key("material");
		uint32_t materials_array_size = materials_array.size();

		for (uint32_t i = 0; i < materials_array_size; i++)
		{
			DynamicString materials_name;
			materials_array[i].to_string(materials_name); materials_name += ".material";

			if (!fs.is_file(materials_name.c_str()))
			{
				CE_LOGE("Material '%s' does not exist.", materials_name.c_str());
				return;
			}

			array::push_back(m_materials, ResourceId(materials_name.c_str()));
		}
	}

	// Check for materials
	if (root.has_key("gui"))
	{
		JSONElement guis_array = root.key("gui");
		uint32_t guis_array_size = guis_array.size();

		for (uint32_t i = 0; i < guis_array_size; i++)
		{
			DynamicString guis_name;
			guis_array[i].to_string(guis_name); guis_name += ".gui";

			if (!fs.is_file(guis_name.c_str()))
			{
				CE_LOGE("gui '%s' does not exist.", guis_name.c_str());
				return;
			}

			array::push_back(m_guis, ResourceId(guis_name.c_str()));
		}
	}

	// Check for fonts
	if (root.has_key("font"))
	{
		JSONElement fonts_array = root.key("font");
		uint32_t fonts_array_size = fonts_array.size();

		for (uint32_t i = 0; i < fonts_array_size; i++)
		{
			DynamicString font_name;
			fonts_array[i].to_string(font_name); font_name += ".font";

			if (!fs.is_file(font_name.c_str()))
			{
				CE_LOGE("font '%s' does not exist.", font_name.c_str());
				return;
			}

			array::push_back(m_fonts, ResourceId(font_name.c_str()));
		}
	}

	// Check for fonts
	if (root.has_key("level"))
	{
		JSONElement levels_array = root.key("level");
		uint32_t levels_array_size = levels_array.size();

		for (uint32_t i = 0; i < levels_array_size; i++)
		{
			DynamicString level_name;
			levels_array[i].to_string(level_name); level_name += ".level";

			if (!fs.is_file(level_name.c_str()))
			{
				CE_LOGE("level '%s' does not exist.", level_name.c_str());
				return;
			}

			array::push_back(m_levels, ResourceId(level_name.c_str()));
		}
	}

	PackageHeader header;
	header.num_textures = array::size(m_texture);
	header.num_scripts = array::size(m_script);
	header.num_sounds = array::size(m_sound);
	header.num_meshes = array::size(m_mesh);
	header.num_units = array::size(m_unit);
	header.num_sprites = array::size(m_sprite);
	header.num_physics = array::size(m_physics);
	header.num_materials = array::size(m_materials);
	header.num_guis = array::size(m_guis);
	header.num_fonts = array::size(m_fonts);
	header.num_levels = array::size(m_levels);

	header.textures_offset = sizeof(PackageHeader);
	header.scripts_offset  = header.textures_offset + sizeof(ResourceId) * header.num_textures;
	header.sounds_offset = header.scripts_offset + sizeof(ResourceId) * header.num_scripts;
	header.meshes_offset = header.sounds_offset + sizeof(ResourceId) * header.num_sounds;
	header.units_offset = header.meshes_offset + sizeof(ResourceId) * header.num_meshes;
	header.sprites_offset = header.units_offset + sizeof(ResourceId) * header.num_units;
	header.physics_offset = header.sprites_offset + sizeof(ResourceId) * header.num_sprites;
	header.materials_offset = header.physics_offset + sizeof(ResourceId) * header.num_physics;
	header.guis_offset = header.materials_offset + sizeof(ResourceId) * header.num_materials;
	header.fonts_offset = header.guis_offset + sizeof(ResourceId) * header.num_guis;
	header.levels_offset = header.fonts_offset + sizeof(ResourceId) * header.num_fonts;

	out_file->write((char*) &header, sizeof(PackageHeader));

	if (array::size(m_texture) > 0)
	{
		out_file->write((char*) array::begin(m_texture), sizeof(ResourceId) * header.num_textures);
	}
	if (array::size(m_script) > 0)
	{
		out_file->write((char*) array::begin(m_script), sizeof(ResourceId) * header.num_scripts);
	}
	if (array::size(m_sound) > 0)
	{
		out_file->write((char*) array::begin(m_sound), sizeof(ResourceId) * header.num_sounds);
	}
	if (array::size(m_mesh) > 0)
	{
		out_file->write((char*) array::begin(m_mesh), sizeof(ResourceId) * header.num_meshes);
	}
	if (array::size(m_unit) > 0)
	{
		out_file->write((char*) array::begin(m_unit), sizeof(ResourceId) * header.num_units);
	}
	if (array::size(m_sprite) > 0)
	{
		out_file->write((char*) array::begin(m_sprite), sizeof(ResourceId) * header.num_sprites);
	}
	if (array::size(m_physics) > 0)
	{
		out_file->write((char*) array::begin(m_physics), sizeof(ResourceId) * header.num_physics);
	}
	if (array::size(m_materials) > 0)
	{
		out_file->write((char*) array::begin(m_materials), sizeof(ResourceId) * header.num_materials);
	}
	if (array::size(m_guis) > 0)
	{
		out_file->write((char*) array::begin(m_guis), sizeof(ResourceId) * header.num_guis);
	}
	if (array::size(m_fonts) > 0)
	{
		out_file->write((char*) array::begin(m_fonts), sizeof(ResourceId) * header.num_fonts);
	}
	if (array::size(m_levels) > 0)
	{
		out_file->write((char*) array::begin(m_levels), sizeof(ResourceId) * header.num_levels);
	}
}

} // namespace package_resource
} // namespace crown
<commit_msg>Simplify PackageResource compiler<commit_after>/*
Copyright (c) 2013 Daniele Bartolini, Michele Rossi
Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

#include "Allocator.h"
#include "File.h"
#include "Filesystem.h"
#include "StringUtils.h"
#include "JSONParser.h"
#include "Log.h"
#include "PackageResource.h"
#include "TempAllocator.h"

namespace crown
{
namespace package_resource
{

//-----------------------------------------------------------------------------
void parse_resources(JSONElement arr, const char* type, Array<ResourceId>& out)
{
	const uint32_t num = arr.size();

	for (uint32_t i = 0; i < num; i++)
	{
		DynamicString name;
		arr[i].to_string(name);
		array::push_back(out, ResourceId(type, name.c_str()));
	}
}

//-----------------------------------------------------------------------------
void compile(Filesystem& fs, const char* resource_path, File* out_file)
{
	File* file = fs.open(resource_path, FOM_READ);

	char file_buf[4096];
	file->read(file_buf, file->size());
	fs.close(file);

	JSONParser json(file_buf);
	JSONElement root = json.root();

	Array<ResourceId> textures(default_allocator());
	Array<ResourceId> scripts(default_allocator());
	Array<ResourceId> sounds(default_allocator());
	Array<ResourceId> meshes(default_allocator());
	Array<ResourceId> units(default_allocator());
	Array<ResourceId> sprites(default_allocator());
	Array<ResourceId> physics(default_allocator());
	Array<ResourceId> materials(default_allocator());
	Array<ResourceId> guis(default_allocator());
	Array<ResourceId> fonts(default_allocator());
	Array<ResourceId> levels(default_allocator());

	if (root.has_key("texture"))
		parse_resources(root.key("texture"), "texture", textures);

	if (root.has_key("lua"))
		parse_resources(root.key("lua"), "lua", scripts);

	if (root.has_key("sound"))
		parse_resources(root.key("sound"), "sound", sounds);

	if (root.has_key("mesh"))
		parse_resources(root.key("mesh"), "mesh", meshes);

	if (root.has_key("unit"))
		parse_resources(root.key("unit"), "unit", units);

	if (root.has_key("sprite"))
		parse_resources(root.key("sprite"), "sprite", sprites);

	if (root.has_key("physics"))
		parse_resources(root.key("physics"), "physics", physics);

	if (root.has_key("material"))
		parse_resources(root.key("material"), "material", materials);

	if (root.has_key("gui"))
		parse_resources(root.key("gui"), "gui", guis);

	if (root.has_key("font"))
		parse_resources(root.key("font"), "font", fonts);

	if (root.has_key("level"))
		parse_resources(root.key("level"), "level", levels);

	PackageHeader header;
	header.num_textures = array::size(textures);
	header.num_scripts = array::size(scripts);
	header.num_sounds = array::size(sounds);
	header.num_meshes = array::size(meshes);
	header.num_units = array::size(units);
	header.num_sprites = array::size(sprites);
	header.num_physics = array::size(physics);
	header.num_materials = array::size(materials);
	header.num_guis = array::size(guis);
	header.num_fonts = array::size(fonts);
	header.num_levels = array::size(levels);

	header.textures_offset = sizeof(PackageHeader);
	header.scripts_offset  = header.textures_offset + sizeof(ResourceId) * header.num_textures;
	header.sounds_offset = header.scripts_offset + sizeof(ResourceId) * header.num_scripts;
	header.meshes_offset = header.sounds_offset + sizeof(ResourceId) * header.num_sounds;
	header.units_offset = header.meshes_offset + sizeof(ResourceId) * header.num_meshes;
	header.sprites_offset = header.units_offset + sizeof(ResourceId) * header.num_units;
	header.physics_offset = header.sprites_offset + sizeof(ResourceId) * header.num_sprites;
	header.materials_offset = header.physics_offset + sizeof(ResourceId) * header.num_physics;
	header.guis_offset = header.materials_offset + sizeof(ResourceId) * header.num_materials;
	header.fonts_offset = header.guis_offset + sizeof(ResourceId) * header.num_guis;
	header.levels_offset = header.fonts_offset + sizeof(ResourceId) * header.num_fonts;

	out_file->write((char*) &header, sizeof(PackageHeader));

	if (array::size(textures) > 0)
	{
		out_file->write((char*) array::begin(textures), sizeof(ResourceId) * header.num_textures);
	}
	if (array::size(scripts) > 0)
	{
		out_file->write((char*) array::begin(scripts), sizeof(ResourceId) * header.num_scripts);
	}
	if (array::size(sounds) > 0)
	{
		out_file->write((char*) array::begin(sounds), sizeof(ResourceId) * header.num_sounds);
	}
	if (array::size(meshes) > 0)
	{
		out_file->write((char*) array::begin(meshes), sizeof(ResourceId) * header.num_meshes);
	}
	if (array::size(units) > 0)
	{
		out_file->write((char*) array::begin(units), sizeof(ResourceId) * header.num_units);
	}
	if (array::size(sprites) > 0)
	{
		out_file->write((char*) array::begin(sprites), sizeof(ResourceId) * header.num_sprites);
	}
	if (array::size(physics) > 0)
	{
		out_file->write((char*) array::begin(physics), sizeof(ResourceId) * header.num_physics);
	}
	if (array::size(materials) > 0)
	{
		out_file->write((char*) array::begin(materials), sizeof(ResourceId) * header.num_materials);
	}
	if (array::size(guis) > 0)
	{
		out_file->write((char*) array::begin(guis), sizeof(ResourceId) * header.num_guis);
	}
	if (array::size(fonts) > 0)
	{
		out_file->write((char*) array::begin(fonts), sizeof(ResourceId) * header.num_fonts);
	}
	if (array::size(levels) > 0)
	{
		out_file->write((char*) array::begin(levels), sizeof(ResourceId) * header.num_levels);
	}
}

} // namespace package_resource
} // namespace crown
<|endoftext|>