<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 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
 *
 *****************************************************************************/

// mapnik
#include <mapnik/global.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/projection.hpp>
#include <mapnik/proj_transform.hpp>
#include <mapnik/coord.hpp>
#include <mapnik/utils.hpp>

#ifdef MAPNIK_USE_PROJ4
// proj4
#include <proj_api.h>
#endif

// stl
#include <vector>
#include <stdexcept>

namespace mapnik {

proj_transform::proj_transform(projection const& source,
                               projection const& dest)
    : source_(source),
      dest_(dest),
      is_source_longlat_(false),
      is_dest_longlat_(false),
      wgs84_to_merc_(false),
      merc_to_wgs84_(false),
      is_source_equal_dest_(false)
{
    is_source_equal_dest_ = (source_ == dest_);
    if (!is_source_equal_dest_)
    {
        is_source_longlat_ = source_.is_geographic();
        is_dest_longlat_ = dest_.is_geographic();
        boost::optional<well_known_srs_e> src_k = source.well_known();
        boost::optional<well_known_srs_e> dest_k = dest.well_known();
        bool known_trans = false;
        if (src_k && dest_k)
        {
            if (*src_k == WGS_84 && *dest_k == G_MERC)
            {
                wgs84_to_merc_ = true;
                known_trans = true;
            }
            else if (*src_k == G_MERC && *dest_k == WGS_84)
            {
                merc_to_wgs84_ = true;
                known_trans = true;
            }
        }
        if (!known_trans)
        {
#ifdef MAPNIK_USE_PROJ4
            source_.init_proj4();
            dest_.init_proj4();
#else
            throw std::runtime_error(std::string("Cannot initialize proj_transform for given projections without proj4 support (-DMAPNIK_USE_PROJ4): '") + source_.params() + "'->'" + dest_.params() + "'");
#endif
        }
    }
}

bool proj_transform::equal() const
{
    return is_source_equal_dest_;
}

bool proj_transform::forward (double & x, double & y , double & z) const
{
    return forward(&x, &y, &z, 1);
}

bool proj_transform::forward (double * x, double * y , double * z, int point_count) const
{

    if (is_source_equal_dest_)
        return true;

    if (wgs84_to_merc_)
    {
        return lonlat2merc(x,y,point_count);
    }
    else if (merc_to_wgs84_)
    {
        return merc2lonlat(x,y,point_count);
    }

#ifdef MAPNIK_USE_PROJ4
    if (is_source_longlat_)
    {
        int i;
        for(i=0; i<point_count; i++) {
            x[i] *= DEG_TO_RAD;
            y[i] *= DEG_TO_RAD;
        }
    }

    if (pj_transform( source_.proj_, dest_.proj_, point_count,
                      0, x,y,z) != 0)
    {
        return false;
    }

    if (is_dest_longlat_)
    {
        int i;
        for(i=0; i<point_count; i++) {
            x[i] *= RAD_TO_DEG;
            y[i] *= RAD_TO_DEG;
        }
    }
#endif
    return true;
}

bool proj_transform::backward (double * x, double * y , double * z, int point_count) const
{
    if (is_source_equal_dest_)
        return true;

    if (wgs84_to_merc_)
    {
        return merc2lonlat(x,y,point_count);
    }
    else if (merc_to_wgs84_)
    {
        return lonlat2merc(x,y,point_count);
    }

#ifdef MAPNIK_USE_PROJ4
    if (is_dest_longlat_)
    {
        int i;
        for(i=0; i<point_count; i++) {
            x[i] *= DEG_TO_RAD;
            y[i] *= DEG_TO_RAD;
        }
    }

    if (pj_transform( dest_.proj_, source_.proj_, point_count,
                      0, x,y,z) != 0)
    {
        return false;
    }

    if (is_source_longlat_)
    {
        int i;
        for(i=0; i<point_count; i++) {
            x[i] *= RAD_TO_DEG;
            y[i] *= RAD_TO_DEG;
        }
    }
#endif
    return true;
}

bool proj_transform::backward (double & x, double & y , double & z) const
{
    return backward(&x, &y, &z, 1);
}

bool proj_transform::forward (box2d<double> & box) const
{
    if (is_source_equal_dest_)
        return true;

    double minx = box.minx();
    double miny = box.miny();
    double maxx = box.maxx();
    double maxy = box.maxy();
    double z = 0.0;
    if (!forward(minx,miny,z))
        return false;
    if (!forward(maxx,maxy,z))
        return false;
    box.init(minx,miny,maxx,maxy);
    return true;
}

bool proj_transform::backward (box2d<double> & box) const
{
    if (is_source_equal_dest_)
        return true;

    double minx = box.minx();
    double miny = box.miny();
    double maxx = box.maxx();
    double maxy = box.maxy();
    double z = 0.0;
    if (!backward(minx,miny,z))
        return false;
    if (!backward(maxx,maxy,z))
        return false;
    box.init(minx,miny,maxx,maxy);
    return true;
}

void envelope_points(std::vector< coord<double,2> > & coords, box2d<double>& env, int points)
{
    double width = env.width();
    double height = env.height();

    int steps;

    if (points <= 4) {
        steps = 0;
    } else {
        steps = static_cast<int>(std::ceil((points - 4) / 4.0));
    }

    steps += 1;
    double xstep = width / steps;
    double ystep = height / steps;

    for (int i=0; i<=steps; i++) {
        coords.push_back(coord<double,2>(env.minx() + i * xstep, env.miny()));
        coords.push_back(coord<double,2>(env.minx() + i * xstep, env.maxy()));

    }
    for (int i=1; i<steps; i++) {
        coords.push_back(coord<double,2>(env.minx(), env.miny() + i * ystep));
        coords.push_back(coord<double,2>(env.maxx(), env.miny() + i * ystep));
    }
}

box2d<double> calculate_bbox(std::vector<coord<double,2> > & points) {
    std::vector<coord<double,2> >::iterator it = points.begin();
    std::vector<coord<double,2> >::iterator it_end = points.end();

    box2d<double> env(*it, *(++it));
    for (; it!=it_end; ++it) {
        env.expand_to_include(*it);
    }
    return env;
}

/* More robust, but expensive, bbox transform
 * in the face of proj4 out of bounds conditions.
 * Can result in 20 -> 10 r/s performance hit.
 * Alternative is to provide proper clipping box
 * in the target srs by setting map 'maximum-extent'
 */
bool proj_transform::backward(box2d<double>& env, int points) const
{
    if (is_source_equal_dest_)
        return true;

    if (wgs84_to_merc_ || merc_to_wgs84_)
    {
        return backward(env);
    }

    std::vector<coord<double,2> > coords;
    envelope_points(coords, env, points);

    double z;
    for (std::vector<coord<double,2> >::iterator it = coords.begin(); it!=coords.end(); ++it) {
        z = 0;
        if (!backward(it->x, it->y, z)) {
            return false;
        }
    }

    box2d<double> result = calculate_bbox(coords);

    env.re_center(result.center().x, result.center().y);
    env.height(result.height());
    env.width(result.width());

    return true;
}

bool proj_transform::forward(box2d<double>& env, int points) const
{
    if (is_source_equal_dest_)
        return true;

    if (wgs84_to_merc_ || merc_to_wgs84_)
    {
        return forward(env);
    }

    std::vector<coord<double,2> > coords;
    envelope_points(coords, env, points);

    double z;
    for (std::vector<coord<double,2> >::iterator it = coords.begin(); it!=coords.end(); ++it) {
        z = 0;
        if (!forward(it->x, it->y, z)) {
            return false;
        }
    }

    box2d<double> result = calculate_bbox(coords);

    env.re_center(result.center().x, result.center().y);
    env.height(result.height());
    env.width(result.width());

    return true;
}

mapnik::projection const& proj_transform::source() const
{
    return source_;
}
mapnik::projection const& proj_transform::dest() const
{
    return dest_;
}

}
<commit_msg>fix initialization order in proj_transform<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 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
 *
 *****************************************************************************/

// mapnik
#include <mapnik/global.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/projection.hpp>
#include <mapnik/proj_transform.hpp>
#include <mapnik/coord.hpp>
#include <mapnik/utils.hpp>

#ifdef MAPNIK_USE_PROJ4
// proj4
#include <proj_api.h>
#endif

// stl
#include <vector>
#include <stdexcept>

namespace mapnik {

proj_transform::proj_transform(projection const& source,
                               projection const& dest)
    : source_(source),
      dest_(dest),
      is_source_longlat_(false),
      is_dest_longlat_(false),
      is_source_equal_dest_(false),
      wgs84_to_merc_(false),
      merc_to_wgs84_(false)
{
    is_source_equal_dest_ = (source_ == dest_);
    if (!is_source_equal_dest_)
    {
        is_source_longlat_ = source_.is_geographic();
        is_dest_longlat_ = dest_.is_geographic();
        boost::optional<well_known_srs_e> src_k = source.well_known();
        boost::optional<well_known_srs_e> dest_k = dest.well_known();
        bool known_trans = false;
        if (src_k && dest_k)
        {
            if (*src_k == WGS_84 && *dest_k == G_MERC)
            {
                wgs84_to_merc_ = true;
                known_trans = true;
            }
            else if (*src_k == G_MERC && *dest_k == WGS_84)
            {
                merc_to_wgs84_ = true;
                known_trans = true;
            }
        }
        if (!known_trans)
        {
#ifdef MAPNIK_USE_PROJ4
            source_.init_proj4();
            dest_.init_proj4();
#else
            throw std::runtime_error(std::string("Cannot initialize proj_transform for given projections without proj4 support (-DMAPNIK_USE_PROJ4): '") + source_.params() + "'->'" + dest_.params() + "'");
#endif
        }
    }
}

bool proj_transform::equal() const
{
    return is_source_equal_dest_;
}

bool proj_transform::forward (double & x, double & y , double & z) const
{
    return forward(&x, &y, &z, 1);
}

bool proj_transform::forward (double * x, double * y , double * z, int point_count) const
{

    if (is_source_equal_dest_)
        return true;

    if (wgs84_to_merc_)
    {
        return lonlat2merc(x,y,point_count);
    }
    else if (merc_to_wgs84_)
    {
        return merc2lonlat(x,y,point_count);
    }

#ifdef MAPNIK_USE_PROJ4
    if (is_source_longlat_)
    {
        int i;
        for(i=0; i<point_count; i++) {
            x[i] *= DEG_TO_RAD;
            y[i] *= DEG_TO_RAD;
        }
    }

    if (pj_transform( source_.proj_, dest_.proj_, point_count,
                      0, x,y,z) != 0)
    {
        return false;
    }

    if (is_dest_longlat_)
    {
        int i;
        for(i=0; i<point_count; i++) {
            x[i] *= RAD_TO_DEG;
            y[i] *= RAD_TO_DEG;
        }
    }
#endif
    return true;
}

bool proj_transform::backward (double * x, double * y , double * z, int point_count) const
{
    if (is_source_equal_dest_)
        return true;

    if (wgs84_to_merc_)
    {
        return merc2lonlat(x,y,point_count);
    }
    else if (merc_to_wgs84_)
    {
        return lonlat2merc(x,y,point_count);
    }

#ifdef MAPNIK_USE_PROJ4
    if (is_dest_longlat_)
    {
        int i;
        for(i=0; i<point_count; i++) {
            x[i] *= DEG_TO_RAD;
            y[i] *= DEG_TO_RAD;
        }
    }

    if (pj_transform( dest_.proj_, source_.proj_, point_count,
                      0, x,y,z) != 0)
    {
        return false;
    }

    if (is_source_longlat_)
    {
        int i;
        for(i=0; i<point_count; i++) {
            x[i] *= RAD_TO_DEG;
            y[i] *= RAD_TO_DEG;
        }
    }
#endif
    return true;
}

bool proj_transform::backward (double & x, double & y , double & z) const
{
    return backward(&x, &y, &z, 1);
}

bool proj_transform::forward (box2d<double> & box) const
{
    if (is_source_equal_dest_)
        return true;

    double minx = box.minx();
    double miny = box.miny();
    double maxx = box.maxx();
    double maxy = box.maxy();
    double z = 0.0;
    if (!forward(minx,miny,z))
        return false;
    if (!forward(maxx,maxy,z))
        return false;
    box.init(minx,miny,maxx,maxy);
    return true;
}

bool proj_transform::backward (box2d<double> & box) const
{
    if (is_source_equal_dest_)
        return true;

    double minx = box.minx();
    double miny = box.miny();
    double maxx = box.maxx();
    double maxy = box.maxy();
    double z = 0.0;
    if (!backward(minx,miny,z))
        return false;
    if (!backward(maxx,maxy,z))
        return false;
    box.init(minx,miny,maxx,maxy);
    return true;
}

void envelope_points(std::vector< coord<double,2> > & coords, box2d<double>& env, int points)
{
    double width = env.width();
    double height = env.height();

    int steps;

    if (points <= 4) {
        steps = 0;
    } else {
        steps = static_cast<int>(std::ceil((points - 4) / 4.0));
    }

    steps += 1;
    double xstep = width / steps;
    double ystep = height / steps;

    for (int i=0; i<=steps; i++) {
        coords.push_back(coord<double,2>(env.minx() + i * xstep, env.miny()));
        coords.push_back(coord<double,2>(env.minx() + i * xstep, env.maxy()));

    }
    for (int i=1; i<steps; i++) {
        coords.push_back(coord<double,2>(env.minx(), env.miny() + i * ystep));
        coords.push_back(coord<double,2>(env.maxx(), env.miny() + i * ystep));
    }
}

box2d<double> calculate_bbox(std::vector<coord<double,2> > & points) {
    std::vector<coord<double,2> >::iterator it = points.begin();
    std::vector<coord<double,2> >::iterator it_end = points.end();

    box2d<double> env(*it, *(++it));
    for (; it!=it_end; ++it) {
        env.expand_to_include(*it);
    }
    return env;
}

/* More robust, but expensive, bbox transform
 * in the face of proj4 out of bounds conditions.
 * Can result in 20 -> 10 r/s performance hit.
 * Alternative is to provide proper clipping box
 * in the target srs by setting map 'maximum-extent'
 */
bool proj_transform::backward(box2d<double>& env, int points) const
{
    if (is_source_equal_dest_)
        return true;

    if (wgs84_to_merc_ || merc_to_wgs84_)
    {
        return backward(env);
    }

    std::vector<coord<double,2> > coords;
    envelope_points(coords, env, points);

    double z;
    for (std::vector<coord<double,2> >::iterator it = coords.begin(); it!=coords.end(); ++it) {
        z = 0;
        if (!backward(it->x, it->y, z)) {
            return false;
        }
    }

    box2d<double> result = calculate_bbox(coords);

    env.re_center(result.center().x, result.center().y);
    env.height(result.height());
    env.width(result.width());

    return true;
}

bool proj_transform::forward(box2d<double>& env, int points) const
{
    if (is_source_equal_dest_)
        return true;

    if (wgs84_to_merc_ || merc_to_wgs84_)
    {
        return forward(env);
    }

    std::vector<coord<double,2> > coords;
    envelope_points(coords, env, points);

    double z;
    for (std::vector<coord<double,2> >::iterator it = coords.begin(); it!=coords.end(); ++it) {
        z = 0;
        if (!forward(it->x, it->y, z)) {
            return false;
        }
    }

    box2d<double> result = calculate_bbox(coords);

    env.re_center(result.center().x, result.center().y);
    env.height(result.height());
    env.width(result.width());

    return true;
}

mapnik::projection const& proj_transform::source() const
{
    return source_;
}
mapnik::projection const& proj_transform::dest() const
{
    return dest_;
}

}
<|endoftext|>


<commit_before><commit_msg>Bugfix: `Universe` constructor: compute `aspect_ratio` properly.<commit_after><|endoftext|>


<commit_before>#include <reactive/bridge.hpp>
#include <reactive/ptr_observable.hpp>
#include <reactive/buffer.hpp>
#include <reactive/generate.hpp>
#include <reactive/transform.hpp>
#include <SDL2/SDL.h>
#include <boost/system/system_error.hpp>
#include <boost/scope_exit.hpp>
#include <boost/variant.hpp>

namespace rx
{
	template <class In, class State, class Step>
	struct variable
			: public observable<State>
			, private observer<typename In::element_type>
	{
		typedef State element_type;

		variable(In in, element_type initial_state, Step step)
			: in(std::move(in))
			, state(std::move(initial_state))
			, step(std::move(step))
		{
		}

		virtual void async_get_one(observer<element_type> &receiver) SILICIUM_OVERRIDE
		{
			check_fetch();
			receiver.got_element(state);
		}

		virtual void cancel() SILICIUM_OVERRIDE
		{
		}

	private:

		In in;
		element_type state;
		Step step;
		bool fetching = false;

		virtual void got_element(typename In::element_type value) SILICIUM_OVERRIDE
		{
			assert(fetching);
			fetching = false;
			check_fetch();
			state = step(std::move(state), std::move(value));
		}

		virtual void ended() SILICIUM_OVERRIDE
		{
			assert(fetching);
			fetching = false;
			check_fetch();
		}

		void check_fetch()
		{
			if (!fetching)
			{
				fetching = true;
				in.async_get_one(*this);
			}
		}
	};

	template <class In, class State, class Step>
	auto make_var(In &&in, State &&initial_state, Step &&step)
	{
		return variable<
				typename std::decay<In>::type,
				typename std::decay<State>::type,
				typename std::decay<Step>::type>(std::forward<In>(in), std::forward<State>(initial_state), std::forward<Step>(step));
	}

	template <class Element>
	auto ref(rx::observable<Element> &identity)
	{
		return rx::ptr_observable<Element, rx::observable<Element> *>(&identity);
	}

	template <class Input, class Predicate>
	struct filter_observable
			: public observable<typename Input::element_type>
			, private observer<typename Input::element_type>
	{
		typedef typename Input::element_type element_type;

		filter_observable(Input input, Predicate is_propagated)
			: input(std::move(input))
			, is_propagated(std::move(is_propagated))
		{
		}

		virtual void async_get_one(observer<element_type> &receiver) SILICIUM_OVERRIDE
		{
			assert(!receiver_);
			receiver_ = &receiver;
			input.async_get_one(*this);
		}

		virtual void cancel() SILICIUM_OVERRIDE
		{
			assert(receiver_);
		}

	private:

		Input input;
		Predicate is_propagated;
		observer<element_type> *receiver_ = nullptr;

		virtual void got_element(element_type value) SILICIUM_OVERRIDE
		{
			assert(receiver_);
			if (!is_propagated(static_cast<typename std::add_const<element_type>::type>(value)))
			{
				input.async_get_one(*this);
				return;
			}
			exchange(receiver_, nullptr)->got_element(std::move(value));
		}

		virtual void ended() SILICIUM_OVERRIDE
		{
			assert(receiver_);
			exchange(receiver_, nullptr)->ended();
		}
	};

	template <class Input, class Predicate>
	auto filter(Input &&input, Predicate &&is_propagated)
	{
		return filter_observable<
				typename std::decay<Input>::type,
				typename std::decay<Predicate>::type>(std::forward<Input>(input), std::forward<Predicate>(is_propagated));
	}
}

namespace
{
	void throw_error()
	{
		throw std::runtime_error(std::string("SDL error :") + SDL_GetError());
	}

	void check_sdl(int rc)
	{
		if (rc < 0)
		{
			throw_error();
		}
	}

	struct window_destructor
	{
		void operator()(SDL_Window *w) const
		{
			SDL_DestroyWindow(w);
		}
	};

	struct renderer_destructor
	{
		void operator()(SDL_Renderer *r) const
		{
			SDL_DestroyRenderer(r);
		}
	};

	struct draw_filled_rect
	{
		SDL_Color color;
		SDL_Rect where;
	};

	typedef boost::variant<
		draw_filled_rect
	> draw_operation;

	struct frame
	{
		std::vector<draw_operation> operations;
	};

	SDL_Color make_color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
	{
		SDL_Color result;
		result.r = red;
		result.g = green;
		result.b = blue;
		result.a = alpha;
		return result;
	}

	SDL_Rect make_rect(int x, int y, int w, int h)
	{
		SDL_Rect result;
		result.x = x;
		result.y = y;
		result.w = w;
		result.h = h;
		return result;
	}

	struct game_state
	{
		int x = 100;
		int y = 100;
		int count = 1;
	};

	int const max_rect_count = 5;

	frame draw_game_state(game_state const &state)
	{
		std::vector<draw_operation> operations;
		for (int i = 0; i < state.count; ++i)
		{
			int const max_width = 80;
			int const single_offset = (max_width / 2) / max_rect_count;
			int const total_offset = single_offset * i;
			int const width = max_width - total_offset * 2;
			operations.emplace_back(draw_filled_rect{make_color(0xff, 0x00, 0x00, 0xff), make_rect(state.x + total_offset, state.y + total_offset, width, width)});
		}
		return frame
		{
			std::move(operations)
		};
	}

	game_state step_game_state(game_state previous, SDL_Event event_)
	{
		switch (event_.type)
		{
		case SDL_KEYUP:
			{
				switch (event_.key.keysym.sym)
				{
				case SDLK_LEFT:
					previous.x -= 10;
					break;

				case SDLK_RIGHT:
					previous.x += 10;
					break;

				case SDLK_UP:
					previous.y -= 10;
					break;

				case SDLK_DOWN:
					previous.y += 10;
					break;

				case SDLK_PLUS:
					previous.count = std::min(max_rect_count, previous.count + 1);
					break;

				case SDLK_MINUS:
					previous.count = std::max(1, previous.count - 1);
					break;
				}
				break;
			}
		}
		return previous;
	}

	auto make_frames(rx::observable<SDL_Event> &input)
	{
		game_state initial_state;
		auto interesting_input = rx::filter(rx::ref(input), [](SDL_Event const &event_)
		{
			return event_.type == SDL_KEYUP;
		});
		return rx::transform(rx::make_var(interesting_input, initial_state, step_game_state), draw_game_state);
	}

	void set_render_draw_color(SDL_Renderer &renderer, SDL_Color color)
	{
		SDL_SetRenderDrawColor(&renderer, color.r, color.g, color.b, color.a);
	}

	struct draw_operation_renderer : boost::static_visitor<>
	{
		explicit draw_operation_renderer(SDL_Renderer &sdl)
			: sdl(&sdl)
		{
		}

		void operator()(draw_filled_rect const &operation) const
		{
			set_render_draw_color(*sdl, operation.color);
			SDL_RenderDrawRect(sdl, &operation.where);
		}

	private:

		SDL_Renderer *sdl;
	};

	struct frame_renderer : rx::observer<frame>
	{
		explicit frame_renderer(SDL_Renderer &sdl)
			: sdl(&sdl)
		{
		}

		virtual void got_element(frame value) SILICIUM_OVERRIDE
		{
			set_render_draw_color(*sdl, make_color(0, 0, 0, 0xff));
			SDL_RenderClear(sdl);
			for (auto const &operation : value.operations)
			{
				boost::apply_visitor(draw_operation_renderer{*sdl}, operation);
			}
			SDL_RenderPresent(sdl);
		}

		virtual void ended() SILICIUM_OVERRIDE
		{
		}

	private:

		SDL_Renderer *sdl;
	};
}

int main()
{
	check_sdl(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS));
	BOOST_SCOPE_EXIT(void)
	{
		SDL_Quit();
	}
	BOOST_SCOPE_EXIT_END;

	std::unique_ptr<SDL_Window, window_destructor> window(SDL_CreateWindow("Silicium react.cpp", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, 0));
	if (!window)
	{
		throw_error();
		return 1;
	}

	std::unique_ptr<SDL_Renderer, renderer_destructor> renderer(SDL_CreateRenderer(window.get(), -1, 0));

	rx::bridge<SDL_Event> input;
	auto frames = rx::wrap<frame>(make_frames(input));

	frame_renderer frame_renderer_(*renderer);
	for (;;)
	{
		frames.async_get_one(frame_renderer_);

		SDL_Event event;
		while (SDL_PollEvent(&event))
		{
			switch (event.type)
			{
			case SDL_QUIT:
				return 0;
			}
			input.got_element(event);
		}
	}
}
<commit_msg>add delay to save CPU time<commit_after>#include <reactive/bridge.hpp>
#include <reactive/ptr_observable.hpp>
#include <reactive/buffer.hpp>
#include <reactive/generate.hpp>
#include <reactive/transform.hpp>
#include <SDL2/SDL.h>
#include <boost/system/system_error.hpp>
#include <boost/scope_exit.hpp>
#include <boost/variant.hpp>

namespace rx
{
	template <class In, class State, class Step>
	struct variable
			: public observable<State>
			, private observer<typename In::element_type>
	{
		typedef State element_type;

		variable(In in, element_type initial_state, Step step)
			: in(std::move(in))
			, state(std::move(initial_state))
			, step(std::move(step))
		{
		}

		virtual void async_get_one(observer<element_type> &receiver) SILICIUM_OVERRIDE
		{
			check_fetch();
			receiver.got_element(state);
		}

		virtual void cancel() SILICIUM_OVERRIDE
		{
		}

	private:

		In in;
		element_type state;
		Step step;
		bool fetching = false;

		virtual void got_element(typename In::element_type value) SILICIUM_OVERRIDE
		{
			assert(fetching);
			fetching = false;
			check_fetch();
			state = step(std::move(state), std::move(value));
		}

		virtual void ended() SILICIUM_OVERRIDE
		{
			assert(fetching);
			fetching = false;
			check_fetch();
		}

		void check_fetch()
		{
			if (!fetching)
			{
				fetching = true;
				in.async_get_one(*this);
			}
		}
	};

	template <class In, class State, class Step>
	auto make_var(In &&in, State &&initial_state, Step &&step)
	{
		return variable<
				typename std::decay<In>::type,
				typename std::decay<State>::type,
				typename std::decay<Step>::type>(std::forward<In>(in), std::forward<State>(initial_state), std::forward<Step>(step));
	}

	template <class Element>
	auto ref(rx::observable<Element> &identity)
	{
		return rx::ptr_observable<Element, rx::observable<Element> *>(&identity);
	}

	template <class Input, class Predicate>
	struct filter_observable
			: public observable<typename Input::element_type>
			, private observer<typename Input::element_type>
	{
		typedef typename Input::element_type element_type;

		filter_observable(Input input, Predicate is_propagated)
			: input(std::move(input))
			, is_propagated(std::move(is_propagated))
		{
		}

		virtual void async_get_one(observer<element_type> &receiver) SILICIUM_OVERRIDE
		{
			assert(!receiver_);
			receiver_ = &receiver;
			input.async_get_one(*this);
		}

		virtual void cancel() SILICIUM_OVERRIDE
		{
			assert(receiver_);
		}

	private:

		Input input;
		Predicate is_propagated;
		observer<element_type> *receiver_ = nullptr;

		virtual void got_element(element_type value) SILICIUM_OVERRIDE
		{
			assert(receiver_);
			if (!is_propagated(static_cast<typename std::add_const<element_type>::type>(value)))
			{
				input.async_get_one(*this);
				return;
			}
			exchange(receiver_, nullptr)->got_element(std::move(value));
		}

		virtual void ended() SILICIUM_OVERRIDE
		{
			assert(receiver_);
			exchange(receiver_, nullptr)->ended();
		}
	};

	template <class Input, class Predicate>
	auto filter(Input &&input, Predicate &&is_propagated)
	{
		return filter_observable<
				typename std::decay<Input>::type,
				typename std::decay<Predicate>::type>(std::forward<Input>(input), std::forward<Predicate>(is_propagated));
	}
}

namespace
{
	void throw_error()
	{
		throw std::runtime_error(std::string("SDL error :") + SDL_GetError());
	}

	void check_sdl(int rc)
	{
		if (rc < 0)
		{
			throw_error();
		}
	}

	struct window_destructor
	{
		void operator()(SDL_Window *w) const
		{
			SDL_DestroyWindow(w);
		}
	};

	struct renderer_destructor
	{
		void operator()(SDL_Renderer *r) const
		{
			SDL_DestroyRenderer(r);
		}
	};

	struct draw_filled_rect
	{
		SDL_Color color;
		SDL_Rect where;
	};

	typedef boost::variant<
		draw_filled_rect
	> draw_operation;

	struct frame
	{
		std::vector<draw_operation> operations;
	};

	SDL_Color make_color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
	{
		SDL_Color result;
		result.r = red;
		result.g = green;
		result.b = blue;
		result.a = alpha;
		return result;
	}

	SDL_Rect make_rect(int x, int y, int w, int h)
	{
		SDL_Rect result;
		result.x = x;
		result.y = y;
		result.w = w;
		result.h = h;
		return result;
	}

	struct game_state
	{
		int x = 100;
		int y = 100;
		int count = 1;
	};

	int const max_rect_count = 5;

	frame draw_game_state(game_state const &state)
	{
		std::vector<draw_operation> operations;
		for (int i = 0; i < state.count; ++i)
		{
			int const max_width = 80;
			int const single_offset = (max_width / 2) / max_rect_count;
			int const total_offset = single_offset * i;
			int const width = max_width - total_offset * 2;
			operations.emplace_back(draw_filled_rect{make_color(0xff, 0x00, 0x00, 0xff), make_rect(state.x + total_offset, state.y + total_offset, width, width)});
		}
		return frame
		{
			std::move(operations)
		};
	}

	game_state step_game_state(game_state previous, SDL_Event event_)
	{
		switch (event_.type)
		{
		case SDL_KEYUP:
			{
				switch (event_.key.keysym.sym)
				{
				case SDLK_LEFT:
					previous.x -= 10;
					break;

				case SDLK_RIGHT:
					previous.x += 10;
					break;

				case SDLK_UP:
					previous.y -= 10;
					break;

				case SDLK_DOWN:
					previous.y += 10;
					break;

				case SDLK_PLUS:
					previous.count = std::min(max_rect_count, previous.count + 1);
					break;

				case SDLK_MINUS:
					previous.count = std::max(1, previous.count - 1);
					break;
				}
				break;
			}
		}
		return previous;
	}

	auto make_frames(rx::observable<SDL_Event> &input)
	{
		game_state initial_state;
		auto interesting_input = rx::filter(rx::ref(input), [](SDL_Event const &event_)
		{
			return event_.type == SDL_KEYUP;
		});
		return rx::transform(rx::make_var(interesting_input, initial_state, step_game_state), draw_game_state);
	}

	void set_render_draw_color(SDL_Renderer &renderer, SDL_Color color)
	{
		SDL_SetRenderDrawColor(&renderer, color.r, color.g, color.b, color.a);
	}

	struct draw_operation_renderer : boost::static_visitor<>
	{
		explicit draw_operation_renderer(SDL_Renderer &sdl)
			: sdl(&sdl)
		{
		}

		void operator()(draw_filled_rect const &operation) const
		{
			set_render_draw_color(*sdl, operation.color);
			SDL_RenderDrawRect(sdl, &operation.where);
		}

	private:

		SDL_Renderer *sdl;
	};

	struct frame_renderer : rx::observer<frame>
	{
		explicit frame_renderer(SDL_Renderer &sdl)
			: sdl(&sdl)
		{
		}

		virtual void got_element(frame value) SILICIUM_OVERRIDE
		{
			set_render_draw_color(*sdl, make_color(0, 0, 0, 0xff));
			SDL_RenderClear(sdl);
			for (auto const &operation : value.operations)
			{
				boost::apply_visitor(draw_operation_renderer{*sdl}, operation);
			}
			SDL_RenderPresent(sdl);
		}

		virtual void ended() SILICIUM_OVERRIDE
		{
		}

	private:

		SDL_Renderer *sdl;
	};
}

int main()
{
	check_sdl(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS));
	BOOST_SCOPE_EXIT(void)
	{
		SDL_Quit();
	}
	BOOST_SCOPE_EXIT_END;

	std::unique_ptr<SDL_Window, window_destructor> window(SDL_CreateWindow("Silicium react.cpp", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, 0));
	if (!window)
	{
		throw_error();
		return 1;
	}

	std::unique_ptr<SDL_Renderer, renderer_destructor> renderer(SDL_CreateRenderer(window.get(), -1, 0));

	rx::bridge<SDL_Event> input;
	auto frames = rx::wrap<frame>(make_frames(input));

	frame_renderer frame_renderer_(*renderer);
	for (;;)
	{
		frames.async_get_one(frame_renderer_);

		SDL_Event event;
		while (SDL_PollEvent(&event))
		{
			switch (event.type)
			{
			case SDL_QUIT:
				return 0;
			}
			input.got_element(event);
		}

		SDL_Delay(16);
	}
}
<|endoftext|>


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

#include <node.h>

#include "grpc/grpc.h"
#include "grpc/grpc_security.h"
#include "grpc/support/log.h"
#include "credentials.h"

namespace grpc {
namespace node {

using ::node::Buffer;
using v8::Arguments;
using v8::Exception;
using v8::External;
using v8::Function;
using v8::FunctionTemplate;
using v8::Handle;
using v8::HandleScope;
using v8::Integer;
using v8::Local;
using v8::Object;
using v8::ObjectTemplate;
using v8::Persistent;
using v8::Value;

Persistent<Function> Credentials::constructor;
Persistent<FunctionTemplate> Credentials::fun_tpl;

Credentials::Credentials(grpc_credentials *credentials)
    : wrapped_credentials(credentials) {}

Credentials::~Credentials() {
  grpc_credentials_release(wrapped_credentials);
}

void Credentials::Init(Handle<Object> exports) {
  NanScope();
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  tpl->SetClassName(NanNew("Credentials"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  NanAssignPersistent(fun_tpl, tpl);
  NanAssignPersistent(constructor, tpl->GetFunction());
  constructor->Set(NanNew("createDefault"),
                   FunctionTemplate::New(CreateDefault)->GetFunction());
  constructor->Set(NanNew("createSsl"),
                   FunctionTemplate::New(CreateSsl)->GetFunction());
  constructor->Set(NanNew("createComposite"),
                   FunctionTemplate::New(CreateComposite)->GetFunction());
  constructor->Set(NanNew("createGce"),
                   FunctionTemplate::New(CreateGce)->GetFunction());
  constructor->Set(NanNew("createFake"),
                   FunctionTemplate::New(CreateFake)->GetFunction());
  constructor->Set(NanNew("createIam"),
                   FunctionTemplate::New(CreateIam)->GetFunction());
  exports->Set(NanNew("Credentials"), constructor);
}

bool Credentials::HasInstance(Handle<Value> val) {
  NanScope();
  return NanHasInstance(fun_tpl, val);
}

Handle<Value> Credentials::WrapStruct(grpc_credentials *credentials) {
  NanEscapableScope();
  if (credentials == NULL) {
    return NanEscapeScope(NanNull());
  }
  const int argc = 1;
  Handle<Value> argv[argc] = {
      External::New(reinterpret_cast<void *>(credentials))};
  return NanEscapeScope(constructor->NewInstance(argc, argv));
}

grpc_credentials *Credentials::GetWrappedCredentials() {
  return wrapped_credentials;
}

NAN_METHOD(Credentials::New) {
  NanScope();

  if (args.IsConstructCall()) {
    if (!args[0]->IsExternal()) {
      return NanThrowTypeError(
          "Credentials can only be created with the provided functions");
    }
    grpc_credentials *creds_value =
        reinterpret_cast<grpc_credentials *>(External::Unwrap(args[0]));
    Credentials *credentials = new Credentials(creds_value);
    credentials->Wrap(args.This());
    NanReturnValue(args.This());
  } else {
    const int argc = 1;
    Local<Value> argv[argc] = {args[0]};
    NanReturnValue(constructor->NewInstance(argc, argv));
  }
}

NAN_METHOD(Credentials::CreateDefault) {
  NanScope();
  NanReturnValue(WrapStruct(grpc_default_credentials_create()));
}

NAN_METHOD(Credentials::CreateSsl) {
  NanScope();
  char *root_certs = NULL;
  grpc_ssl_pem_key_cert_pair key_cert_pair = {NULL, NULL};
  if (Buffer::HasInstance(args[0])) {
    root_certs = Buffer::Data(args[0]);
  } else if (!(args[0]->IsNull() || args[0]->IsUndefined())) {
    return NanThrowTypeError("createSsl's first argument must be a Buffer");
  }
  if (Buffer::HasInstance(args[1])) {
    key_cert_pair.private_key = Buffer::Data(args[1]);
  } else if (!(args[1]->IsNull() || args[1]->IsUndefined())) {
    return NanThrowTypeError(
        "createSSl's second argument must be a Buffer if provided");
  }
  if (Buffer::HasInstance(args[2])) {
    key_cert_pair.cert_chain = Buffer::Data(args[2]);
  } else if (!(args[2]->IsNull() || args[2]->IsUndefined())) {
    return NanThrowTypeError(
        "createSSl's third argument must be a Buffer if provided");
  }

  NanReturnValue(WrapStruct(grpc_ssl_credentials_create(
      root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair)));
}

NAN_METHOD(Credentials::CreateComposite) {
  NanScope();
  if (!HasInstance(args[0])) {
    return NanThrowTypeError(
        "createComposite's first argument must be a Credentials object");
  }
  if (!HasInstance(args[1])) {
    return NanThrowTypeError(
        "createComposite's second argument must be a Credentials object");
  }
  Credentials *creds1 = ObjectWrap::Unwrap<Credentials>(args[0]->ToObject());
  Credentials *creds2 = ObjectWrap::Unwrap<Credentials>(args[1]->ToObject());
  NanReturnValue(WrapStruct(grpc_composite_credentials_create(
      creds1->wrapped_credentials, creds2->wrapped_credentials)));
}

NAN_METHOD(Credentials::CreateGce) {
  NanScope();
  NanReturnValue(WrapStruct(grpc_compute_engine_credentials_create()));
}

NAN_METHOD(Credentials::CreateFake) {
  NanScope();
  NanReturnValue(WrapStruct(grpc_fake_transport_security_credentials_create()));
}

NAN_METHOD(Credentials::CreateIam) {
  NanScope();
  if (!args[0]->IsString()) {
    return NanThrowTypeError("createIam's first argument must be a string");
  }
  if (!args[1]->IsString()) {
    return NanThrowTypeError("createIam's second argument must be a string");
  }
  NanUtf8String auth_token(args[0]);
  NanUtf8String auth_selector(args[1]);
  NanReturnValue(
      WrapStruct(grpc_iam_credentials_create(*auth_token, *auth_selector)));
}

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

#include <node.h>

#include "grpc/grpc.h"
#include "grpc/grpc_security.h"
#include "grpc/support/log.h"
#include "credentials.h"

namespace grpc {
namespace node {

using ::node::Buffer;
using v8::Arguments;
using v8::Exception;
using v8::External;
using v8::Function;
using v8::FunctionTemplate;
using v8::Handle;
using v8::HandleScope;
using v8::Integer;
using v8::Local;
using v8::Object;
using v8::ObjectTemplate;
using v8::Persistent;
using v8::Value;

Persistent<Function> Credentials::constructor;
Persistent<FunctionTemplate> Credentials::fun_tpl;

Credentials::Credentials(grpc_credentials *credentials)
    : wrapped_credentials(credentials) {}

Credentials::~Credentials() {
  grpc_credentials_release(wrapped_credentials);
}

void Credentials::Init(Handle<Object> exports) {
  NanScope();
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  tpl->SetClassName(NanNew("Credentials"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  NanAssignPersistent(fun_tpl, tpl);
  NanAssignPersistent(constructor, tpl->GetFunction());
  constructor->Set(NanNew("createDefault"),
                   FunctionTemplate::New(CreateDefault)->GetFunction());
  constructor->Set(NanNew("createSsl"),
                   FunctionTemplate::New(CreateSsl)->GetFunction());
  constructor->Set(NanNew("createComposite"),
                   FunctionTemplate::New(CreateComposite)->GetFunction());
  constructor->Set(NanNew("createGce"),
                   FunctionTemplate::New(CreateGce)->GetFunction());
  constructor->Set(NanNew("createFake"),
                   FunctionTemplate::New(CreateFake)->GetFunction());
  constructor->Set(NanNew("createIam"),
                   FunctionTemplate::New(CreateIam)->GetFunction());
  exports->Set(NanNew("Credentials"), constructor);
}

bool Credentials::HasInstance(Handle<Value> val) {
  NanScope();
  return NanHasInstance(fun_tpl, val);
}

Handle<Value> Credentials::WrapStruct(grpc_credentials *credentials) {
  NanEscapableScope();
  if (credentials == NULL) {
    return NanEscapeScope(NanNull());
  }
  const int argc = 1;
  Handle<Value> argv[argc] = {
      External::New(reinterpret_cast<void *>(credentials))};
  return NanEscapeScope(constructor->NewInstance(argc, argv));
}

grpc_credentials *Credentials::GetWrappedCredentials() {
  return wrapped_credentials;
}

NAN_METHOD(Credentials::New) {
  NanScope();

  if (args.IsConstructCall()) {
    if (!args[0]->IsExternal()) {
      return NanThrowTypeError(
          "Credentials can only be created with the provided functions");
    }
    grpc_credentials *creds_value =
        reinterpret_cast<grpc_credentials *>(External::Unwrap(args[0]));
    Credentials *credentials = new Credentials(creds_value);
    credentials->Wrap(args.This());
    NanReturnValue(args.This());
  } else {
    const int argc = 1;
    Local<Value> argv[argc] = {args[0]};
    NanReturnValue(constructor->NewInstance(argc, argv));
  }
}

NAN_METHOD(Credentials::CreateDefault) {
  NanScope();
  NanReturnValue(WrapStruct(grpc_google_default_credentials_create()));
}

NAN_METHOD(Credentials::CreateSsl) {
  NanScope();
  char *root_certs = NULL;
  grpc_ssl_pem_key_cert_pair key_cert_pair = {NULL, NULL};
  if (Buffer::HasInstance(args[0])) {
    root_certs = Buffer::Data(args[0]);
  } else if (!(args[0]->IsNull() || args[0]->IsUndefined())) {
    return NanThrowTypeError("createSsl's first argument must be a Buffer");
  }
  if (Buffer::HasInstance(args[1])) {
    key_cert_pair.private_key = Buffer::Data(args[1]);
  } else if (!(args[1]->IsNull() || args[1]->IsUndefined())) {
    return NanThrowTypeError(
        "createSSl's second argument must be a Buffer if provided");
  }
  if (Buffer::HasInstance(args[2])) {
    key_cert_pair.cert_chain = Buffer::Data(args[2]);
  } else if (!(args[2]->IsNull() || args[2]->IsUndefined())) {
    return NanThrowTypeError(
        "createSSl's third argument must be a Buffer if provided");
  }

  NanReturnValue(WrapStruct(grpc_ssl_credentials_create(
      root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair)));
}

NAN_METHOD(Credentials::CreateComposite) {
  NanScope();
  if (!HasInstance(args[0])) {
    return NanThrowTypeError(
        "createComposite's first argument must be a Credentials object");
  }
  if (!HasInstance(args[1])) {
    return NanThrowTypeError(
        "createComposite's second argument must be a Credentials object");
  }
  Credentials *creds1 = ObjectWrap::Unwrap<Credentials>(args[0]->ToObject());
  Credentials *creds2 = ObjectWrap::Unwrap<Credentials>(args[1]->ToObject());
  NanReturnValue(WrapStruct(grpc_composite_credentials_create(
      creds1->wrapped_credentials, creds2->wrapped_credentials)));
}

NAN_METHOD(Credentials::CreateGce) {
  NanScope();
  NanReturnValue(WrapStruct(grpc_compute_engine_credentials_create()));
}

NAN_METHOD(Credentials::CreateFake) {
  NanScope();
  NanReturnValue(WrapStruct(grpc_fake_transport_security_credentials_create()));
}

NAN_METHOD(Credentials::CreateIam) {
  NanScope();
  if (!args[0]->IsString()) {
    return NanThrowTypeError("createIam's first argument must be a string");
  }
  if (!args[1]->IsString()) {
    return NanThrowTypeError("createIam's second argument must be a string");
  }
  NanUtf8String auth_token(args[0]);
  NanUtf8String auth_selector(args[1]);
  NanReturnValue(
      WrapStruct(grpc_iam_credentials_create(*auth_token, *auth_selector)));
}

}  // namespace node
}  // namespace grpc
<|endoftext|>


<commit_before>/*
    This file is part of libkcal.
    Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <qdir.h>
#include <qfile.h>
#include <qtextstream.h>

#include <klocale.h>
#include <kdebug.h>
#include <kstandarddirs.h>

#include "event.h"
#include "todo.h"
#include "freebusy.h"
#include "icalformat.h"
#include "calendar.h"

#include "scheduler.h"

using namespace KCal;

ScheduleMessage::ScheduleMessage(IncidenceBase *incidence,int method,ScheduleMessage::Status status)
{
  mIncidence = incidence;
  mMethod = method;
  mStatus = status;
}

QString ScheduleMessage::statusName(ScheduleMessage::Status status)
{
  switch (status) {
    case PublishNew:
      return i18n("Publish");
    case Obsolete:
      return i18n("Obsolete");
    case RequestNew:
      return i18n("New Request");
    case RequestUpdate:
      return i18n("Updated Request");
    default:
      return i18n("Unknown Status: %1").arg(QString::number(status));
  }
}

Scheduler::Scheduler(Calendar *calendar)
{
  mCalendar = calendar;
  mFormat = new ICalFormat();
}

Scheduler::~Scheduler()
{
  delete mFormat;
}

bool Scheduler::acceptTransaction(IncidenceBase *incidence,Method method,ScheduleMessage::Status status)
{
  kdDebug() << "Scheduler::acceptTransaction " << endl;
  switch (method) {
    case Publish:
      return acceptPublish(incidence, status, method);
    case Request:
      return acceptRequest(incidence, status);
    case Add:
      return acceptAdd(incidence, status);
    case Cancel:
      return acceptCancel(incidence, status);
    case Declinecounter:
      return acceptDeclineCounter(incidence, status);
    case Reply:
      return acceptReply(incidence, status, method);
    case Refresh:
      return acceptRefresh(incidence, status);
    case Counter:
      return acceptCounter(incidence, status);
    default:
      deleteTransaction(incidence);
      return false;
  }
  deleteTransaction(incidence);
  return false;
}

QString Scheduler::methodName(Method method)
{
  switch (method) {
    case Publish:
      return i18n("Publish");
    case Request:
      return i18n("Request");
    case Refresh:
      return i18n("Refresh");
    case Cancel:
      return i18n("Cancel");
    case Add:
      return i18n("Add");
    case Reply:
      return i18n("Reply");
    case Counter:
      return i18n("counter proposal","Counter");
    case Declinecounter:
      return i18n("decline counter proposal","Decline Counter");
    default:
      return i18n("Unknown");
  }
}

bool Scheduler::deleteTransaction(IncidenceBase *)
{
  return true;
}

bool Scheduler::acceptPublish(IncidenceBase *incidence,ScheduleMessage::Status status, Method method)
{
  if(incidence->type()=="FreeBusy") {
    return acceptFreeBusy(incidence, method);
  }
  switch (status) {
    case ScheduleMessage::PublishNew:
      if (!mCalendar->event(incidence->uid())) {
	Incidence *inc = static_cast<Incidence *>(incidence);
        mCalendar->addIncidence(inc);
        deleteTransaction(incidence);
      }
      return true;
    case ScheduleMessage::Obsolete:
      return true;
    default:
      deleteTransaction(incidence);
      return false;
  }
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptRequest(IncidenceBase *incidence,ScheduleMessage::Status status)
{
  Incidence *inc = static_cast<Incidence *>(incidence);
  if (inc->type()=="FreeBusy") {
    // reply to this request is handled in korganizer's incomingdialog
    return true;
  } else {
//    switch (status) {
//    case ScheduleMessage::Obsolete: {
      // why the same s "RequestUpdate?
      Event *even = mCalendar->event(incidence->uid());
      if (even) {
	mCalendar->deleteEvent(even);
      } else {
	Todo *todo = mCalendar->todo(incidence->uid());
	if (todo) {
	  mCalendar->deleteTodo(todo);
	}
      }
      mCalendar->addIncidence(inc);
      deleteTransaction(incidence);
      return true;
/*    }
    case ScheduleMessage::RequestNew:
      mCalendar->addIncidence(inc);
      deleteTransaction(incidence);
      return true;
    case ScheduleMessage::RequestUpdate: {
      Event *even = mCalendar->event(incidence->uid());
      if (even) {
	mCalendar->deleteEvent(even);
      } else {
	Todo *todo = mCalendar->todo(incidence->uid());
	if (todo) {
	  mCalendar->deleteTodo(todo);
	}
      }
      mCalendar->addIncidence(inc);
      deleteTransaction(incidence);
      return true;
    }
    default:
      return false;
    }
  }
  deleteTransaction(incidence);
  return false;*/
}

bool Scheduler::acceptAdd(IncidenceBase *incidence,ScheduleMessage::Status status)
{
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptCancel(IncidenceBase *incidence,ScheduleMessage::Status status)
{
  bool ret = false;
  Event *even = mCalendar->event(incidence->uid());
  if (even) {
    mCalendar->deleteEvent(even);
    ret = true;
  } else {
    Todo *todo = mCalendar->todo(incidence->uid());
    if (todo) {
      mCalendar->deleteTodo(todo);
      ret = true;
    }
  }
  deleteTransaction(incidence);
  return ret;
}

bool Scheduler::acceptDeclineCounter(IncidenceBase *incidence,ScheduleMessage::Status status)
{
  deleteTransaction(incidence);
  return false;
}

//bool Scheduler::acceptFreeBusy(Incidence *incidence,ScheduleMessage::Status status)
//{
//  deleteTransaction(incidence);
//  return false;
//}

bool Scheduler::acceptReply(IncidenceBase *incidence,ScheduleMessage::Status status, Method method)
{
  if(incidence->type()=="FreeBusy") {
    return acceptFreeBusy(incidence, method);
  }
  bool ret = false;
  Event *ev = mCalendar->event(incidence->uid());
  Todo *to = mCalendar->todo(incidence->uid());
  if (ev || to) {
    //get matching attendee in calendar
    kdDebug(5800) << "Scheduler::acceptTransaction match found!" << endl;
    QPtrList<Attendee> attendeesIn = incidence->attendees();
    QPtrList<Attendee> attendeesEv;
    if (ev) attendeesEv = ev->attendees();
    if (to) attendeesEv = to->attendees();
    Attendee *attIn;
    Attendee *attEv;
    for ( attIn = attendeesIn.first(); attIn; attIn = attendeesIn.next() ) {
      for ( attEv = attendeesEv.first(); attEv; attEv = attendeesEv.next() ) {
        if (attIn->email()==attEv->email()) {
          //update attendee-info
          kdDebug(5800) << "Scheduler::acceptTransaction update attendee" << endl;
          attEv->setStatus(attIn->status());
	  // better to not update the sequence number with replys
          //if (ev) ev->setRevision(ev->revision()+1);
	  //if (to) to->setRevision(to->revision()+1);
          ret = true;
        }
      }
    }
  }
  if (ret) deleteTransaction(incidence);
  return ret;
}

bool Scheduler::acceptRefresh(IncidenceBase *incidence,ScheduleMessage::Status status)
{
  // handled in korganizer's IncomingDialog
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptCounter(IncidenceBase *incidence,ScheduleMessage::Status status)
{
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptFreeBusy(IncidenceBase *incidence, Method method)
{
  FreeBusy *freebusy = static_cast<FreeBusy *>(incidence);

  QString freeBusyDirName = locateLocal("appdata","freebusy");
  kdDebug() << "acceptFreeBusy:: freeBusyDirName: " << freeBusyDirName << endl;

  QString from;
  if(method == Scheduler::Publish) {
    from = freebusy->organizer();
  }
  if((method == Scheduler::Reply) && (freebusy->attendeeCount() == 1)) {
    Attendee *attendee = freebusy->attendees().first();
    from = attendee->email();
  }

  QDir freeBusyDir(freeBusyDirName);
  if (!freeBusyDir.exists()) {
    kdDebug() << "Directory " << freeBusyDirName << " does not exist!" << endl;
    kdDebug() << "Creating directory: " << freeBusyDirName << endl;

    if(!freeBusyDir.mkdir(freeBusyDirName, TRUE)) {
      kdDebug() << "Could not create directory: " << freeBusyDirName << endl;
      return false;
    }
  }

  QString filename(freeBusyDirName);
  filename += "/";
  filename += from;
  filename += ".ifb";
  QFile f(filename);

  kdDebug() << "acceptFreeBusy: filename" << filename << endl;

  freebusy->clearAttendees();
  freebusy->setOrganizer(from);

  QString messageText = mFormat->createScheduleMessage(freebusy, Publish);

  if (!f.open(IO_ReadWrite)) {
   kdDebug() << "acceptFreeBusy: Can't open:" << filename << " for writing" << endl;
   return false;
  }
  QTextStream t(&f);
  t << messageText;
  f.close();

  deleteTransaction(incidence);
  return true;
}
<commit_msg>hande sequence number with requests/updates<commit_after>/*
    This file is part of libkcal.
    Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <qdir.h>
#include <qfile.h>
#include <qtextstream.h>

#include <klocale.h>
#include <kdebug.h>
#include <kstandarddirs.h>

#include "event.h"
#include "todo.h"
#include "freebusy.h"
#include "icalformat.h"
#include "calendar.h"

#include "scheduler.h"

using namespace KCal;

ScheduleMessage::ScheduleMessage(IncidenceBase *incidence,int method,ScheduleMessage::Status status)
{
  mIncidence = incidence;
  mMethod = method;
  mStatus = status;
}

QString ScheduleMessage::statusName(ScheduleMessage::Status status)
{
  switch (status) {
    case PublishNew:
      return i18n("Publish");
    case Obsolete:
      return i18n("Obsolete");
    case RequestNew:
      return i18n("New Request");
    case RequestUpdate:
      return i18n("Updated Request");
    default:
      return i18n("Unknown Status: %1").arg(QString::number(status));
  }
}

Scheduler::Scheduler(Calendar *calendar)
{
  mCalendar = calendar;
  mFormat = new ICalFormat();
}

Scheduler::~Scheduler()
{
  delete mFormat;
}

bool Scheduler::acceptTransaction(IncidenceBase *incidence,Method method,ScheduleMessage::Status status)
{
  kdDebug() << "Scheduler::acceptTransaction " << endl;
  switch (method) {
    case Publish:
      return acceptPublish(incidence, status, method);
    case Request:
      return acceptRequest(incidence, status);
    case Add:
      return acceptAdd(incidence, status);
    case Cancel:
      return acceptCancel(incidence, status);
    case Declinecounter:
      return acceptDeclineCounter(incidence, status);
    case Reply:
      return acceptReply(incidence, status, method);
    case Refresh:
      return acceptRefresh(incidence, status);
    case Counter:
      return acceptCounter(incidence, status);
    default:
      deleteTransaction(incidence);
      return false;
  }
  deleteTransaction(incidence);
  return false;
}

QString Scheduler::methodName(Method method)
{
  switch (method) {
    case Publish:
      return i18n("Publish");
    case Request:
      return i18n("Request");
    case Refresh:
      return i18n("Refresh");
    case Cancel:
      return i18n("Cancel");
    case Add:
      return i18n("Add");
    case Reply:
      return i18n("Reply");
    case Counter:
      return i18n("counter proposal","Counter");
    case Declinecounter:
      return i18n("decline counter proposal","Decline Counter");
    default:
      return i18n("Unknown");
  }
}

bool Scheduler::deleteTransaction(IncidenceBase *)
{
  return true;
}

bool Scheduler::acceptPublish(IncidenceBase *incidence,ScheduleMessage::Status status, Method method)
{
  if(incidence->type()=="FreeBusy") {
    return acceptFreeBusy(incidence, method);
  }
  switch (status) {
    case ScheduleMessage::PublishNew:
      if (!mCalendar->event(incidence->uid())) {
	Incidence *inc = static_cast<Incidence *>(incidence);
        mCalendar->addIncidence(inc);
        deleteTransaction(incidence);
      }
      return true;
    case ScheduleMessage::Obsolete:
      return true;
    default:
      deleteTransaction(incidence);
      return false;
  }
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptRequest(IncidenceBase *incidence,ScheduleMessage::Status status)
{
  Incidence *inc = static_cast<Incidence *>(incidence);
  if (inc->type()=="FreeBusy") {
    // reply to this request is handled in korganizer's incomingdialog
    return true;
  } else {
    Event *even = mCalendar->event(incidence->uid());
    if (even) {
      if ( even->revision()<=inc->revision() ) {
        if ( even->revision()==inc->revision() &&
             even->lastModified()>inc->lastModified()) {
          deleteTransaction(incidence);
          return false;
        }
        mCalendar->deleteEvent(even);
      } else {
        deleteTransaction(incidence);
        return false;
      }
    } else {
      Todo *todo = mCalendar->todo(incidence->uid());
      if (todo) {
        if ( todo->revision()<=inc->revision() ) {
          if ( todo->revision()==inc->revision() &&
               todo->lastModified()>inc->lastModified()) {
            deleteTransaction(incidence);
            return false;
          }
          mCalendar->deleteTodo(todo);
        } else {
          deleteTransaction(incidence);
          return false;
        }
      }
    }
  }
  mCalendar->addIncidence(inc);
  deleteTransaction(incidence);
  return true;
}

bool Scheduler::acceptAdd(IncidenceBase *incidence,ScheduleMessage::Status status)
{
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptCancel(IncidenceBase *incidence,ScheduleMessage::Status status)
{
  bool ret = false;
  Event *even = mCalendar->event(incidence->uid());
  if (even) {
    mCalendar->deleteEvent(even);
    ret = true;
  } else {
    Todo *todo = mCalendar->todo(incidence->uid());
    if (todo) {
      mCalendar->deleteTodo(todo);
      ret = true;
    }
  }
  deleteTransaction(incidence);
  return ret;
}

bool Scheduler::acceptDeclineCounter(IncidenceBase *incidence,ScheduleMessage::Status status)
{
  deleteTransaction(incidence);
  return false;
}

//bool Scheduler::acceptFreeBusy(Incidence *incidence,ScheduleMessage::Status status)
//{
//  deleteTransaction(incidence);
//  return false;
//}

bool Scheduler::acceptReply(IncidenceBase *incidence,ScheduleMessage::Status status, Method method)
{
  if(incidence->type()=="FreeBusy") {
    return acceptFreeBusy(incidence, method);
  }
  bool ret = false;
  Event *ev = mCalendar->event(incidence->uid());
  Todo *to = mCalendar->todo(incidence->uid());
  if (ev || to) {
    //get matching attendee in calendar
    kdDebug(5800) << "Scheduler::acceptTransaction match found!" << endl;
    QPtrList<Attendee> attendeesIn = incidence->attendees();
    QPtrList<Attendee> attendeesEv;
    if (ev) attendeesEv = ev->attendees();
    if (to) attendeesEv = to->attendees();
    Attendee *attIn;
    Attendee *attEv;
    for ( attIn = attendeesIn.first(); attIn; attIn = attendeesIn.next() ) {
      for ( attEv = attendeesEv.first(); attEv; attEv = attendeesEv.next() ) {
        if (attIn->email()==attEv->email()) {
          //update attendee-info
          kdDebug(5800) << "Scheduler::acceptTransaction update attendee" << endl;
          attEv->setStatus(attIn->status());
	  // better to not update the sequence number with replys
          //if (ev) ev->setRevision(ev->revision()+1);
	  //if (to) to->setRevision(to->revision()+1);
          ret = true;
        }
      }
    }
  }
  if (ret) deleteTransaction(incidence);
  return ret;
}

bool Scheduler::acceptRefresh(IncidenceBase *incidence,ScheduleMessage::Status status)
{
  // handled in korganizer's IncomingDialog
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptCounter(IncidenceBase *incidence,ScheduleMessage::Status status)
{
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptFreeBusy(IncidenceBase *incidence, Method method)
{
  FreeBusy *freebusy = static_cast<FreeBusy *>(incidence);

  QString freeBusyDirName = locateLocal("appdata","freebusy");
  kdDebug() << "acceptFreeBusy:: freeBusyDirName: " << freeBusyDirName << endl;

  QString from;
  if(method == Scheduler::Publish) {
    from = freebusy->organizer();
  }
  if((method == Scheduler::Reply) && (freebusy->attendeeCount() == 1)) {
    Attendee *attendee = freebusy->attendees().first();
    from = attendee->email();
  }

  QDir freeBusyDir(freeBusyDirName);
  if (!freeBusyDir.exists()) {
    kdDebug() << "Directory " << freeBusyDirName << " does not exist!" << endl;
    kdDebug() << "Creating directory: " << freeBusyDirName << endl;

    if(!freeBusyDir.mkdir(freeBusyDirName, TRUE)) {
      kdDebug() << "Could not create directory: " << freeBusyDirName << endl;
      return false;
    }
  }

  QString filename(freeBusyDirName);
  filename += "/";
  filename += from;
  filename += ".ifb";
  QFile f(filename);

  kdDebug() << "acceptFreeBusy: filename" << filename << endl;

  freebusy->clearAttendees();
  freebusy->setOrganizer(from);

  QString messageText = mFormat->createScheduleMessage(freebusy, Publish);

  if (!f.open(IO_ReadWrite)) {
   kdDebug() << "acceptFreeBusy: Can't open:" << filename << " for writing" << endl;
   return false;
  }
  QTextStream t(&f);
  t << messageText;
  f.close();

  deleteTransaction(incidence);
  return true;
}
<|endoftext|>


<commit_before>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Libmemcached library
 *
 *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
 *
 *  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.
 *
 *      * The names of its contributors may not be used to endorse or
 *  promote products derived from this software without specific prior
 *  written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <libmemcached/common.h>

static memcached_return_t memcached_flush_binary(memcached_st *ptr,
                                                 time_t expiration);
static memcached_return_t memcached_flush_textual(memcached_st *ptr,
                                                  time_t expiration);

memcached_return_t memcached_flush(memcached_st *ptr, time_t expiration)
{
  memcached_return_t rc;
  if (memcached_failed(rc= initialize_query(ptr)))
  {
    return rc;
  }

  LIBMEMCACHED_MEMCACHED_FLUSH_START();
  if (ptr->flags.binary_protocol)
  {
    rc= memcached_flush_binary(ptr, expiration);
  }
  else
  {
    rc= memcached_flush_textual(ptr, expiration);
  }
  LIBMEMCACHED_MEMCACHED_FLUSH_END();

  return rc;
}

static memcached_return_t memcached_flush_textual(memcached_st *ptr,
                                                  time_t expiration)
{
  bool reply= ptr->flags.no_reply ? false : true;

  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
  int send_length;
  if (expiration)
  {
    send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
                          "flush_all %llu%s\r\n",
                          (unsigned long long)expiration, reply ? "" :  " noreply");
  }
  else
  {
    send_length= snprintf(buffer, MEMCACHED_DEFAULT_COMMAND_SIZE,
                          "flush_all%s\r\n", reply ? "" : " noreply");
  }

  if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE or send_length < 0)
  {
    return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
                               memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
  }

  memcached_return_t rc= MEMCACHED_SUCCESS;
  for (unsigned int x= 0; x < memcached_server_count(ptr); x++)
  {
    memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x);

    memcached_return_t rrc= memcached_do(instance, buffer, (size_t)send_length, true);
    if (rrc == MEMCACHED_SUCCESS and reply == true)
    {
      char response_buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
      rrc= memcached_response(instance, response_buffer, sizeof(response_buffer), NULL);
    }

    if (memcached_failed(rrc))
    {
      // If an error has already been reported, then don't add to it
      if (instance->error_messages == NULL)
      {
        memcached_set_error(*instance, rrc, MEMCACHED_AT);
      }
      rc= MEMCACHED_SOME_ERRORS;
    }
  }

  return rc;
}

static memcached_return_t memcached_flush_binary(memcached_st *ptr,
                                                 time_t expiration)
{
  protocol_binary_request_flush request= {};

  request.message.header.request.magic= (uint8_t)PROTOCOL_BINARY_REQ;
  request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH;
  request.message.header.request.extlen= 4;
  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
  request.message.header.request.bodylen= htonl(request.message.header.request.extlen);
  request.message.body.expiration= htonl((uint32_t) expiration);

  memcached_return_t rc= MEMCACHED_SUCCESS;

  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
  {
    memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x);

    if (ptr->flags.no_reply)
    {
      request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSHQ;
    }
    else
    {
      request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH;
    }

    memcached_return_t rrc;
    if ((rrc= memcached_do(instance, request.bytes, sizeof(request.bytes), true)))
    {
      memcached_set_error(*instance, rrc, MEMCACHED_AT);
      memcached_io_reset(instance);
      rc= MEMCACHED_SOME_ERRORS;
    }
  }

  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
  {
    memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x);

    if (memcached_server_response_count(instance) > 0)
    {
      (void)memcached_response(instance, NULL, 0, NULL);
    }
  }

  return rc;
}
<commit_msg>Update flush.<commit_after>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Libmemcached library
 *
 *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
 *
 *  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.
 *
 *      * The names of its contributors may not be used to endorse or
 *  promote products derived from this software without specific prior
 *  written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <libmemcached/common.h>

static memcached_return_t memcached_flush_binary(memcached_st *ptr,
                                                 time_t expiration);
static memcached_return_t memcached_flush_textual(memcached_st *ptr,
                                                  time_t expiration);

memcached_return_t memcached_flush(memcached_st *ptr, time_t expiration)
{
  memcached_return_t rc;
  if (memcached_failed(rc= initialize_query(ptr)))
  {
    return rc;
  }

  LIBMEMCACHED_MEMCACHED_FLUSH_START();
  if (ptr->flags.binary_protocol)
  {
    rc= memcached_flush_binary(ptr, expiration);
  }
  else
  {
    rc= memcached_flush_textual(ptr, expiration);
  }
  LIBMEMCACHED_MEMCACHED_FLUSH_END();

  return rc;
}

static memcached_return_t memcached_flush_textual(memcached_st *ptr,
                                                  time_t expiration)
{
  // Invert the logic to make it simpler to read the code
  bool reply= (ptr->flags.no_reply) ? false : true;

  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
  int send_length= 0;
  if (expiration)
  {
    send_length= snprintf(buffer, sizeof(buffer), "%llu", (unsigned long long)expiration);
  }

  if (send_length >= MEMCACHED_DEFAULT_COMMAND_SIZE or send_length < 0)
  {
    return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
                               memcached_literal_param("snprintf(MEMCACHED_DEFAULT_COMMAND_SIZE)"));
  }

  struct libmemcached_io_vector_st vector[]=
  {
    { memcached_literal_param("flush_all ") },
    { buffer, send_length },
    { " noreply", reply ? 0 : memcached_literal_param_size(" noreply") },
    { memcached_literal_param("\r\n") }
  };

  memcached_return_t rc= MEMCACHED_SUCCESS;
  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
  {
    memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x);

    memcached_return_t rrc= memcached_vdo(instance, vector, 4, true);
    if (rrc == MEMCACHED_SUCCESS and reply == true)
    {
      char response_buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
      rrc= memcached_response(instance, response_buffer, sizeof(response_buffer), NULL);
    }

    if (memcached_failed(rrc))
    {
      // If an error has already been reported, then don't add to it
      if (instance->error_messages == NULL)
      {
        memcached_set_error(*instance, rrc, MEMCACHED_AT);
      }
      rc= MEMCACHED_SOME_ERRORS;
    }
  }

  return rc;
}

static memcached_return_t memcached_flush_binary(memcached_st *ptr,
                                                 time_t expiration)
{
  protocol_binary_request_flush request= {};

  request.message.header.request.magic= (uint8_t)PROTOCOL_BINARY_REQ;
  request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH;
  request.message.header.request.extlen= 4;
  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
  request.message.header.request.bodylen= htonl(request.message.header.request.extlen);
  request.message.body.expiration= htonl((uint32_t) expiration);

  memcached_return_t rc= MEMCACHED_SUCCESS;

  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
  {
    memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x);

    if (ptr->flags.no_reply)
    {
      request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSHQ;
    }
    else
    {
      request.message.header.request.opcode= PROTOCOL_BINARY_CMD_FLUSH;
    }

    memcached_return_t rrc;
    if ((rrc= memcached_do(instance, request.bytes, sizeof(request.bytes), true)))
    {
      memcached_set_error(*instance, rrc, MEMCACHED_AT);
      memcached_io_reset(instance);
      rc= MEMCACHED_SOME_ERRORS;
    }
  }

  for (uint32_t x= 0; x < memcached_server_count(ptr); x++)
  {
    memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, x);

    if (memcached_server_response_count(instance) > 0)
    {
      (void)memcached_response(instance, NULL, 0, NULL);
    }
  }

  return rc;
}
<|endoftext|>


<commit_before>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Libmemcached library
 *
 *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2006-2009 Brian Aker 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.
 *
 *      * The names of its contributors may not be used to endorse or
 *  promote products derived from this software without specific prior
 *  written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <libmemcached/common.h>
#include <libmemcached/memcached/protocol_binary.h>

static memcached_return_t ascii_touch(memcached_server_write_instance_st instance,
                                      const char *key, size_t key_length,
                                      time_t expiration)
{
  char buffer[21];

  int buffer_length= snprintf(buffer, sizeof(buffer), " %u", uint32_t(expiration));
  struct libmemcached_io_vector_st vector[]=
  {
    { memcached_literal_param("touch ") },
    { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
    { key, key_length },
    { buffer, buffer_length },
    { memcached_literal_param("\r\n") }
  };

  memcached_return_t rc;
  if (memcached_failed(rc= memcached_vdo(instance, vector, 5, true)))
  {
    memcached_io_reset(instance);
    return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT);
  }

  return rc;
}

static memcached_return_t binary_touch(memcached_server_write_instance_st instance,
                                       const char *key, size_t key_length,
                                       time_t expiration)
{
  protocol_binary_request_touch request= {}; //{.bytes= {0}};
  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
  request.message.header.request.opcode= PROTOCOL_BINARY_CMD_TOUCH;
  request.message.header.request.extlen= 4;
  request.message.header.request.keylen= htons((uint16_t)(key_length +memcached_array_size(instance->root->_namespace)));
  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
  request.message.header.request.bodylen= htonl((uint32_t)(key_length +memcached_array_size(instance->root->_namespace) +request.message.header.request.extlen));
  request.message.body.expiration= htonl((uint32_t) expiration);

  struct libmemcached_io_vector_st vector[]=
  {
    { request.bytes, sizeof(request.bytes) },
    { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
    { key, key_length }
  };

  memcached_return_t rc;
  if (memcached_failed(rc= memcached_vdo(instance, vector, 3, true)))
  {
    memcached_io_reset(instance);
    return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT);
  }

  return rc;
}

memcached_return_t memcached_touch(memcached_st *ptr,
                                   const char *key, size_t key_length,
                                   time_t expiration)
{
  return memcached_touch_by_key(ptr, key, key_length, key, key_length, expiration);
}

memcached_return_t memcached_touch_by_key(memcached_st *ptr,
                                          const char *group_key, size_t group_key_length,
                                          const char *key, size_t key_length,
                                          time_t expiration)
{
  LIBMEMCACHED_MEMCACHED_TOUCH_START();

  memcached_return_t rc;
  if (memcached_failed(rc= initialize_query(ptr)))
  {
    return rc;
  }

  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
  {
    return memcached_set_error(*ptr, rc, MEMCACHED_AT);
  }

  uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
  memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, server_key);

  if (ptr->flags.binary_protocol)
  {
    rc= binary_touch(instance, key, key_length, expiration);
  }
  else
  {
    rc= ascii_touch(instance, key, key_length, expiration);
  }

  if (memcached_failed(rc))
  {
    return memcached_set_error(*instance, rc, MEMCACHED_AT, memcached_literal_param("Error occcured while writing touch command to server"));
  }

  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
  rc= memcached_read_one_response(instance, buffer, sizeof(buffer), NULL);

  if (rc == MEMCACHED_SUCCESS or rc == MEMCACHED_NOTFOUND)
  {
    return rc;
  }

  return memcached_set_error(*instance, rc, MEMCACHED_AT, memcached_literal_param("Error occcured while reading response"));
}
<commit_msg>Update touch for batching.<commit_after>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Libmemcached library
 *
 *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2006-2009 Brian Aker 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.
 *
 *      * The names of its contributors may not be used to endorse or
 *  promote products derived from this software without specific prior
 *  written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <libmemcached/common.h>
#include <libmemcached/memcached/protocol_binary.h>

static memcached_return_t ascii_touch(memcached_server_write_instance_st instance,
                                      const char *key, size_t key_length,
                                      time_t expiration)
{
  char expiration_buffer[MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH +1];
  int expiration_buffer_length= snprintf(expiration_buffer, sizeof(expiration_buffer), " %llu", (unsigned long long)expiration);
  if (size_t(expiration_buffer_length) >= sizeof(expiration_buffer) or expiration_buffer_length < 0)
  {
    return memcached_set_error(*instance, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
                               memcached_literal_param("snprintf(MEMCACHED_MAXIMUM_INTEGER_DISPLAY_LENGTH)"));
  }

  struct libmemcached_io_vector_st vector[]=
  {
    { memcached_literal_param("touch ") },
    { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
    { key, key_length },
    { expiration_buffer, expiration_buffer_length },
    { memcached_literal_param("\r\n") }
  };

  memcached_return_t rc;
  if (memcached_failed(rc= memcached_vdo(instance, vector, 5, true)))
  {
    memcached_io_reset(instance);
    return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT);
  }

  return rc;
}

static memcached_return_t binary_touch(memcached_server_write_instance_st instance,
                                       const char *key, size_t key_length,
                                       time_t expiration)
{
  protocol_binary_request_touch request= {}; //{.bytes= {0}};
  request.message.header.request.magic= PROTOCOL_BINARY_REQ;
  request.message.header.request.opcode= PROTOCOL_BINARY_CMD_TOUCH;
  request.message.header.request.extlen= 4;
  request.message.header.request.keylen= htons((uint16_t)(key_length +memcached_array_size(instance->root->_namespace)));
  request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES;
  request.message.header.request.bodylen= htonl((uint32_t)(key_length +memcached_array_size(instance->root->_namespace) +request.message.header.request.extlen));
  request.message.body.expiration= htonl((uint32_t) expiration);

  struct libmemcached_io_vector_st vector[]=
  {
    { request.bytes, sizeof(request.bytes) },
    { memcached_array_string(instance->root->_namespace), memcached_array_size(instance->root->_namespace) },
    { key, key_length }
  };

  memcached_return_t rc;
  if (memcached_failed(rc= memcached_vdo(instance, vector, 3, true)))
  {
    memcached_io_reset(instance);
    return memcached_set_error(*instance, MEMCACHED_WRITE_FAILURE, MEMCACHED_AT);
  }

  return rc;
}

memcached_return_t memcached_touch(memcached_st *ptr,
                                   const char *key, size_t key_length,
                                   time_t expiration)
{
  return memcached_touch_by_key(ptr, key, key_length, key, key_length, expiration);
}

memcached_return_t memcached_touch_by_key(memcached_st *ptr,
                                          const char *group_key, size_t group_key_length,
                                          const char *key, size_t key_length,
                                          time_t expiration)
{
  LIBMEMCACHED_MEMCACHED_TOUCH_START();

  memcached_return_t rc;
  if (memcached_failed(rc= initialize_query(ptr)))
  {
    return rc;
  }

  if (memcached_failed(rc= memcached_validate_key_length(key_length, ptr->flags.binary_protocol)))
  {
    return memcached_set_error(*ptr, rc, MEMCACHED_AT);
  }

  uint32_t server_key= memcached_generate_hash_with_redistribution(ptr, group_key, group_key_length);
  memcached_server_write_instance_st instance= memcached_server_instance_fetch(ptr, server_key);

  if (ptr->flags.binary_protocol)
  {
    rc= binary_touch(instance, key, key_length, expiration);
  }
  else
  {
    rc= ascii_touch(instance, key, key_length, expiration);
  }

  if (memcached_failed(rc))
  {
    return memcached_set_error(*instance, rc, MEMCACHED_AT, memcached_literal_param("Error occcured while writing touch command to server"));
  }

  char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
  rc= memcached_response(instance, buffer, sizeof(buffer), NULL);

  if (rc == MEMCACHED_SUCCESS or rc == MEMCACHED_NOTFOUND)
  {
    return rc;
  }

  return memcached_set_error(*instance, rc, MEMCACHED_AT, memcached_literal_param("Error occcured while reading response"));
}
<|endoftext|>


<commit_before>#include <boost/asio.hpp>
#include <silicium/observable/coroutine.hpp>
#include <silicium/asio/timer.hpp>
#include <silicium/observable/total_consumer.hpp>
#include <silicium/observable/constant.hpp>
#include <iostream>
//TODO: fewer includes for such a simple example?

template <class Duration>
void sleep(boost::asio::io_service &io, Si::yield_context yield, Duration duration)
{
	auto timer = Si::asio::make_timer(io);
	timer.expires_from_now(duration);
	//TODO: use the call operator instead of a get_one method?
	boost::optional<Si::asio::timer_elapsed> result = yield.get_one(timer);
	//TODO: this should work without the optional wrapper
	assert(result);
}

int main()
{
	boost::asio::io_service io;
	//TODO: this has to work without total_consumer
	auto coro = Si::make_total_consumer(Si::make_coroutine([&io](Si::yield_context yield) -> Si::nothing //TODO: the return type should be void
	{
		std::cout << "Going to sleep" << std::endl;
		sleep(io, yield, std::chrono::seconds(1));
		std::cout << "Waking up\n";
		return {};
	}));
	//TODO: should coroutines start immediately by default?
	coro.start();
	io.run();
}
<commit_msg>update timer example<commit_after>#include <silicium/asio/timer.hpp>
#include <silicium/observable/spawn_coroutine.hpp>
#include <silicium/observable/ref.hpp>
#include <iostream>

template <class YieldContext, class Duration>
void sleep(boost::asio::io_service &io, YieldContext &&yield, Duration duration)
{
	auto timer = Si::asio::make_timer(io);
	timer.expires_from_now(duration);
	//TODO: use the call operator instead of a get_one method?
	boost::optional<Si::asio::timer_elapsed> result = yield.get_one(Si::ref(timer));
	//TODO: this should work without the optional wrapper
	assert(result);
}

int main()
{
	boost::asio::io_service io;
	Si::spawn_coroutine([&io](Si::spawn_context yield)
	{
		std::cout << "Going to sleep" << std::endl;
		sleep(io, yield, std::chrono::seconds(1));
		std::cout << "Waking up\n";
	});
	io.run();
}
<|endoftext|>