<commit_before>#include <cilantro/voxel_grid.hpp>

VoxelGrid::VoxelGrid(const std::vector<Eigen::Vector3f> &points, float bin_size)
        : input_points_(&points),
          input_normals_(NULL),
          input_colors_(NULL),
          bin_size_(bin_size),
          min_pt_map_(min_pt_.data()),
          empty_indices_(0)
{
    build_lookup_table_();
}

VoxelGrid::VoxelGrid(const PointCloud &cloud, float bin_size)
        : input_points_(&cloud.points),
          input_normals_(cloud.hasNormals()?&cloud.normals:NULL),
          input_colors_(cloud.hasColors()?&cloud.colors:NULL),
          bin_size_(bin_size),
          min_pt_map_(min_pt_.data()),
          empty_indices_(0)
{
    build_lookup_table_();
}

std::vector<Eigen::Vector3f> VoxelGrid::getDownsampledPoints(size_t min_points_in_bin) const {
    std::vector<Eigen::Vector3f> points;
    points.reserve(grid_lookup_table_.size());
    for (size_t k = 0; k < map_iterators_.size(); k++) {
        auto it = map_iterators_[k];

        if (it->second.size() < min_points_in_bin) continue;

        Eigen::MatrixXf bin_points(3, it->second.size());
        for (size_t i = 0; i < it->second.size(); i++) {
            bin_points.col(i) = (*input_points_)[it->second[i]];
        }
        Eigen::Vector3f pt(bin_points.rowwise().mean());

        points.emplace_back(pt);
    }

    return points;
}

std::vector<Eigen::Vector3f> VoxelGrid::getDownsampledNormals(size_t min_points_in_bin) const {
    std::vector<Eigen::Vector3f> normals;
    if (input_normals_ == NULL) {
        return normals;
    }

//    normals.reserve(grid_lookup_table_.size());
//    for (auto it = grid_lookup_table_.begin(); it != grid_lookup_table_.end(); ++it) {
//        if (it->second.size() < min_points_in_bin) continue;
//
//        Eigen::MatrixXf bin_normals(3, it->second.size()*2);
//        Eigen::Vector3f ref_dir = (*input_normals_)[it->second[0]];
//        size_t pos = 0, neg = 0;
//        for (size_t i = 0; i < it->second.size(); i++) {
//            const Eigen::Vector3f& curr_normal = (*input_normals_)[it->second[i]];
//            if (ref_dir.dot(curr_normal) < 0.0f) neg++; else pos++;
//            bin_normals.col(2*i) = -curr_normal;
//            bin_normals.col(2*i+1) = curr_normal;
//        }
//        if (neg > pos) ref_dir = -ref_dir;
//
//        PCA3D pca(bin_normals.data(), 3, it->second.size()*2);
//        Eigen::Vector3f avg = pca.getEigenVectorsMatrix().col(0);
//        if (ref_dir.dot(avg) < 0.0f) {
//            normals.emplace_back(-avg);
//        } else {
//            normals.emplace_back(avg);
//        }
//    }

    normals.reserve(grid_lookup_table_.size());
    for (size_t k = 0; k < map_iterators_.size(); k++) {
        auto it = map_iterators_[k];

        if (it->second.size() < min_points_in_bin) continue;

        Eigen::MatrixXf bin_normals(3, it->second.size());
        Eigen::Vector3f ref_dir = (*input_normals_)[it->second[0]];
        size_t pos = 0, neg = 0;
        for (size_t i = 0; i < it->second.size(); i++) {
            const Eigen::Vector3f& curr_normal = (*input_normals_)[it->second[i]];
            if (ref_dir.dot(curr_normal) < 0.0f) {
                bin_normals.col(i) = -curr_normal;
                neg++;
            } else {
                bin_normals.col(i) = curr_normal;
                pos++;
            }
        }
        Eigen::Vector3f avg = (neg > pos) ? -bin_normals.rowwise().mean().normalized() : bin_normals.rowwise().mean().normalized();
        normals.emplace_back(avg);
    }

    return normals;
}

std::vector<Eigen::Vector3f> VoxelGrid::getDownsampledColors(size_t min_points_in_bin) const {
    std::vector<Eigen::Vector3f> colors;
    if (input_colors_ == NULL) return colors;

    colors.reserve(grid_lookup_table_.size());
    for (size_t k = 0; k < map_iterators_.size(); k++) {
        auto it = map_iterators_[k];

        if (it->second.size() < min_points_in_bin) continue;

        Eigen::MatrixXf bin_colors(3, it->second.size());
        for (size_t i = 0; i < it->second.size(); i++) {
            bin_colors.col(i) = (*input_colors_)[it->second[i]];
        }

        Eigen::Vector3f avg = bin_colors.rowwise().mean();

        colors.emplace_back(avg);
    }

    return colors;
}

PointCloud VoxelGrid::getDownsampledCloud(size_t min_points_in_bin) const {
    std::vector<Eigen::Vector3f> points, normals, colors;
    Eigen::Vector3f point, normal, color;

    bool do_normals = input_normals_ != NULL;
    bool do_colors = input_colors_ != NULL;

    points.reserve(grid_lookup_table_.size());
    if (do_normals) normals.reserve(grid_lookup_table_.size());
    if (do_colors) colors.reserve(grid_lookup_table_.size());

//#pragma omp parallel for shared (points, normals, colors) private (point, normal, color)
    for (size_t k = 0; k < map_iterators_.size(); k++) {
        auto it = map_iterators_[k];

        std::vector<size_t>& bin_ind(it->second);

        if (bin_ind.size() < min_points_in_bin) continue;

        Eigen::MatrixXf bin_points(3, bin_ind.size());
        for (size_t i = 0; i < bin_ind.size(); i++) {
            bin_points.col(i) = (*input_points_)[bin_ind[i]];
        }
        point = bin_points.rowwise().mean();
        points.emplace_back(point);

        if (do_normals) {
            Eigen::MatrixXf bin_normals(3, bin_ind.size());
            Eigen::Vector3f ref_dir = (*input_normals_)[bin_ind[0]];
            size_t pos = 0, neg = 0;
            for (size_t i = 0; i < bin_ind.size(); i++) {
                const Eigen::Vector3f& curr_normal = (*input_normals_)[bin_ind[i]];
                if (ref_dir.dot(curr_normal) < 0.0f) {
                    bin_normals.col(i) = -curr_normal;
                    neg++;
                } else {
                    bin_normals.col(i) = curr_normal;
                    pos++;
                }
            }
            normal = (neg > pos) ? -bin_normals.rowwise().mean().normalized() : bin_normals.rowwise().mean().normalized();
            normals.emplace_back(normal);
        }

        if (do_colors) {
            Eigen::MatrixXf bin_colors(3, bin_ind.size());
            for (size_t i = 0; i < bin_ind.size(); i++) {
                bin_colors.col(i) = (*input_colors_)[bin_ind[i]];
            }

            color = bin_colors.rowwise().mean();
            colors.emplace_back(color);
        }

//#pragma omp critical
//        {
//            points.emplace_back(point);
//            if (do_normals) normals.emplace_back(normal);
//            if (do_colors) colors.emplace_back(color);
//        }
    }

    return PointCloud(points, normals, colors);
}

const std::vector<size_t>& VoxelGrid::getGridBinNeighbors(const Eigen::Vector3f &point) const {
    std::array<int,3> grid_coords = {(int)((point[0] - min_pt_[0])/bin_size_), (int)((point[1] - min_pt_[1])/bin_size_), (int)((point[2] - min_pt_[2])/bin_size_)};
    auto it = grid_lookup_table_.find(grid_coords);
    if (it == grid_lookup_table_.end()) return empty_indices_;
    return it->second;
}

const std::vector<size_t>& VoxelGrid::getGridBinNeighbors(size_t point_ind) const {
    return VoxelGrid::getGridBinNeighbors((*input_points_)[point_ind]);
}

void VoxelGrid::build_lookup_table_() {
    if (input_points_->empty()) return;

    min_pt_map_.setConstant(std::numeric_limits<float>::infinity());
//    min_pt_[0] = std::numeric_limits<float>::infinity();
//    min_pt_[1] = std::numeric_limits<float>::infinity();
//    min_pt_[2] = std::numeric_limits<float>::infinity();
    for (size_t i = 0; i < input_points_->size(); i++) {
        if ((*input_points_)[i][0] < min_pt_[0]) min_pt_[0] = (*input_points_)[i][0];
        if ((*input_points_)[i][1] < min_pt_[1]) min_pt_[1] = (*input_points_)[i][1];
        if ((*input_points_)[i][2] < min_pt_[2]) min_pt_[2] = (*input_points_)[i][2];
    }

    map_iterators_.reserve(input_points_->size());
    std::vector<std::array<int,3> > grid_coords(input_points_->size());
    for (size_t i = 0; i < input_points_->size(); i++) {
        grid_coords[i][0] = (int)(((*input_points_)[i][0] - min_pt_[0])/bin_size_);
        grid_coords[i][1] = (int)(((*input_points_)[i][1] - min_pt_[1])/bin_size_);
        grid_coords[i][2] = (int)(((*input_points_)[i][2] - min_pt_[2])/bin_size_);

        auto it = grid_lookup_table_.find(grid_coords[i]);
        if (it == grid_lookup_table_.end()) {
//            grid_lookup_table_.insert(std::make_pair(grid_coords[i], std::vector<size_t>(1, i)));
            map_iterators_.emplace_back(grid_lookup_table_.insert(std::make_pair(grid_coords[i], std::vector<size_t>(1, i))).first);
        } else {
            it->second.emplace_back(i);
        }
    }

}
<commit_msg>Minor change<commit_after>#include <cilantro/voxel_grid.hpp>

VoxelGrid::VoxelGrid(const std::vector<Eigen::Vector3f> &points, float bin_size)
        : input_points_(&points),
          input_normals_(NULL),
          input_colors_(NULL),
          bin_size_(bin_size),
          min_pt_map_(min_pt_.data()),
          empty_indices_(0)
{
    build_lookup_table_();
}

VoxelGrid::VoxelGrid(const PointCloud &cloud, float bin_size)
        : input_points_(&cloud.points),
          input_normals_(cloud.hasNormals()?&cloud.normals:NULL),
          input_colors_(cloud.hasColors()?&cloud.colors:NULL),
          bin_size_(bin_size),
          min_pt_map_(min_pt_.data()),
          empty_indices_(0)
{
    build_lookup_table_();
}

std::vector<Eigen::Vector3f> VoxelGrid::getDownsampledPoints(size_t min_points_in_bin) const {
    std::vector<Eigen::Vector3f> points;
    points.reserve(grid_lookup_table_.size());
    for (size_t k = 0; k < map_iterators_.size(); k++) {
        auto it = map_iterators_[k];

        if (it->second.size() < min_points_in_bin) continue;

        Eigen::MatrixXf bin_points(3, it->second.size());
        for (size_t i = 0; i < it->second.size(); i++) {
            bin_points.col(i) = (*input_points_)[it->second[i]];
        }
        Eigen::Vector3f pt(bin_points.rowwise().mean());

        points.emplace_back(pt);
    }

    return points;
}

std::vector<Eigen::Vector3f> VoxelGrid::getDownsampledNormals(size_t min_points_in_bin) const {
    std::vector<Eigen::Vector3f> normals;
    if (input_normals_ == NULL) {
        return normals;
    }

//    normals.reserve(grid_lookup_table_.size());
//    for (auto it = grid_lookup_table_.begin(); it != grid_lookup_table_.end(); ++it) {
//        if (it->second.size() < min_points_in_bin) continue;
//
//        Eigen::MatrixXf bin_normals(3, it->second.size()*2);
//        Eigen::Vector3f ref_dir = (*input_normals_)[it->second[0]];
//        size_t pos = 0, neg = 0;
//        for (size_t i = 0; i < it->second.size(); i++) {
//            const Eigen::Vector3f& curr_normal = (*input_normals_)[it->second[i]];
//            if (ref_dir.dot(curr_normal) < 0.0f) neg++; else pos++;
//            bin_normals.col(2*i) = -curr_normal;
//            bin_normals.col(2*i+1) = curr_normal;
//        }
//        if (neg > pos) ref_dir = -ref_dir;
//
//        PCA3D pca(bin_normals.data(), 3, it->second.size()*2);
//        Eigen::Vector3f avg = pca.getEigenVectorsMatrix().col(0);
//        if (ref_dir.dot(avg) < 0.0f) {
//            normals.emplace_back(-avg);
//        } else {
//            normals.emplace_back(avg);
//        }
//    }

    normals.reserve(grid_lookup_table_.size());
    for (size_t k = 0; k < map_iterators_.size(); k++) {
        auto it = map_iterators_[k];

        if (it->second.size() < min_points_in_bin) continue;

        Eigen::MatrixXf bin_normals(3, it->second.size());
        Eigen::Vector3f ref_dir = (*input_normals_)[it->second[0]];
        size_t pos = 0, neg = 0;
        for (size_t i = 0; i < it->second.size(); i++) {
            const Eigen::Vector3f& curr_normal = (*input_normals_)[it->second[i]];
            if (ref_dir.dot(curr_normal) < 0.0f) {
                bin_normals.col(i) = -curr_normal;
                neg++;
            } else {
                bin_normals.col(i) = curr_normal;
                pos++;
            }
        }
        Eigen::Vector3f avg = (neg > pos) ? -bin_normals.rowwise().mean().normalized() : bin_normals.rowwise().mean().normalized();
        normals.emplace_back(avg);
    }

    return normals;
}

std::vector<Eigen::Vector3f> VoxelGrid::getDownsampledColors(size_t min_points_in_bin) const {
    std::vector<Eigen::Vector3f> colors;
    if (input_colors_ == NULL) return colors;

    colors.reserve(grid_lookup_table_.size());
    for (size_t k = 0; k < map_iterators_.size(); k++) {
        auto it = map_iterators_[k];

        if (it->second.size() < min_points_in_bin) continue;

        Eigen::MatrixXf bin_colors(3, it->second.size());
        for (size_t i = 0; i < it->second.size(); i++) {
            bin_colors.col(i) = (*input_colors_)[it->second[i]];
        }

        Eigen::Vector3f avg = bin_colors.rowwise().mean();

        colors.emplace_back(avg);
    }

    return colors;
}

PointCloud VoxelGrid::getDownsampledCloud(size_t min_points_in_bin) const {
    std::vector<Eigen::Vector3f> points, normals, colors;
    Eigen::Vector3f point, normal, color;

    bool do_normals = input_normals_ != NULL;
    bool do_colors = input_colors_ != NULL;

    points.reserve(grid_lookup_table_.size());
    if (do_normals) normals.reserve(grid_lookup_table_.size());
    if (do_colors) colors.reserve(grid_lookup_table_.size());

//#pragma omp parallel for shared (points, normals, colors) private (point, normal, color)
    for (size_t k = 0; k < map_iterators_.size(); k++) {
        auto it = map_iterators_[k];

        const std::vector<size_t>& bin_ind(it->second);

        if (bin_ind.size() < min_points_in_bin) continue;

        Eigen::MatrixXf bin_points(3, bin_ind.size());
        for (size_t i = 0; i < bin_ind.size(); i++) {
            bin_points.col(i) = (*input_points_)[bin_ind[i]];
        }
        point = bin_points.rowwise().mean();
        points.emplace_back(point);

        if (do_normals) {
            Eigen::MatrixXf bin_normals(3, bin_ind.size());
            Eigen::Vector3f ref_dir = (*input_normals_)[bin_ind[0]];
            size_t pos = 0, neg = 0;
            for (size_t i = 0; i < bin_ind.size(); i++) {
                const Eigen::Vector3f& curr_normal = (*input_normals_)[bin_ind[i]];
                if (ref_dir.dot(curr_normal) < 0.0f) {
                    bin_normals.col(i) = -curr_normal;
                    neg++;
                } else {
                    bin_normals.col(i) = curr_normal;
                    pos++;
                }
            }
            normal = (neg > pos) ? -bin_normals.rowwise().mean().normalized() : bin_normals.rowwise().mean().normalized();
            normals.emplace_back(normal);
        }

        if (do_colors) {
            Eigen::MatrixXf bin_colors(3, bin_ind.size());
            for (size_t i = 0; i < bin_ind.size(); i++) {
                bin_colors.col(i) = (*input_colors_)[bin_ind[i]];
            }

            color = bin_colors.rowwise().mean();
            colors.emplace_back(color);
        }

//#pragma omp critical
//        {
//            points.emplace_back(point);
//            if (do_normals) normals.emplace_back(normal);
//            if (do_colors) colors.emplace_back(color);
//        }
    }

    return PointCloud(points, normals, colors);
}

const std::vector<size_t>& VoxelGrid::getGridBinNeighbors(const Eigen::Vector3f &point) const {
    std::array<int,3> grid_coords = {(int)((point[0] - min_pt_[0])/bin_size_), (int)((point[1] - min_pt_[1])/bin_size_), (int)((point[2] - min_pt_[2])/bin_size_)};
    auto it = grid_lookup_table_.find(grid_coords);
    if (it == grid_lookup_table_.end()) return empty_indices_;
    return it->second;
}

const std::vector<size_t>& VoxelGrid::getGridBinNeighbors(size_t point_ind) const {
    return VoxelGrid::getGridBinNeighbors((*input_points_)[point_ind]);
}

void VoxelGrid::build_lookup_table_() {
    if (input_points_->empty()) return;

    min_pt_map_.setConstant(std::numeric_limits<float>::infinity());
//    min_pt_[0] = std::numeric_limits<float>::infinity();
//    min_pt_[1] = std::numeric_limits<float>::infinity();
//    min_pt_[2] = std::numeric_limits<float>::infinity();
    for (size_t i = 0; i < input_points_->size(); i++) {
        if ((*input_points_)[i][0] < min_pt_[0]) min_pt_[0] = (*input_points_)[i][0];
        if ((*input_points_)[i][1] < min_pt_[1]) min_pt_[1] = (*input_points_)[i][1];
        if ((*input_points_)[i][2] < min_pt_[2]) min_pt_[2] = (*input_points_)[i][2];
    }

    map_iterators_.reserve(input_points_->size());
    std::vector<std::array<int,3> > grid_coords(input_points_->size());
    for (size_t i = 0; i < input_points_->size(); i++) {
        grid_coords[i][0] = (int)(((*input_points_)[i][0] - min_pt_[0])/bin_size_);
        grid_coords[i][1] = (int)(((*input_points_)[i][1] - min_pt_[1])/bin_size_);
        grid_coords[i][2] = (int)(((*input_points_)[i][2] - min_pt_[2])/bin_size_);

        auto it = grid_lookup_table_.find(grid_coords[i]);
        if (it == grid_lookup_table_.end()) {
//            grid_lookup_table_.insert(std::make_pair(grid_coords[i], std::vector<size_t>(1, i)));
            map_iterators_.emplace_back(grid_lookup_table_.insert(std::make_pair(grid_coords[i], std::vector<size_t>(1, i))).first);
        } else {
            it->second.emplace_back(i);
        }
    }

}
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2018 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.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.
 *
 * 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
 * FOUNDATION 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 "Output.hxx"
#include "Error.hxx"
#include "event/SocketEvent.hxx"
#include "event/TimerEvent.hxx"
#include "io/Splice.hxx"
#include "io/SpliceSupport.hxx"
#include "io/FileDescriptor.hxx"
#include "system/Error.hxx"
#include "istream/Bucket.hxx"
#include "istream/Handler.hxx"
#include "istream/Pointer.hxx"
#include "istream/UnusedPtr.hxx"
#include "pool/pool.hxx"
#include "pool/LeakDetector.hxx"
#include "util/StaticArray.hxx"

#include <was/protocol.h>

#include <sys/uio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

static constexpr Event::Duration was_output_timeout = std::chrono::minutes(2);

class WasOutput final : IstreamHandler, PoolLeakDetector {
	FileDescriptor fd;
	SocketEvent event;
	TimerEvent timeout_event;

	WasOutputHandler &handler;

	IstreamPointer input;

	uint64_t sent = 0;

	bool known_length = false;

public:
	WasOutput(struct pool &pool, EventLoop &event_loop, FileDescriptor _fd,
		  UnusedIstreamPtr _input,
		  WasOutputHandler &_handler) noexcept
		:PoolLeakDetector(pool), fd(_fd),
		 event(event_loop, BIND_THIS_METHOD(WriteEventCallback),
		       SocketDescriptor::FromFileDescriptor(fd)),
		 timeout_event(event_loop, BIND_THIS_METHOD(OnTimeout)),
		 handler(_handler),
		 input(std::move(_input), *this)
	{
		input.SetDirect(ISTREAM_TO_PIPE);

		ScheduleWrite();
	}

	uint64_t Close() noexcept {
		if (input.IsDefined())
			input.ClearAndClose();

		const auto _sent = sent;
		Destroy();
		return _sent;
	}

	bool CheckLength() noexcept;

private:
	void Destroy() noexcept {
		this->~WasOutput();
	}

	void DestroyEof() noexcept {
		auto &_handler = handler;
		Destroy();
		_handler.WasOutputEof();
	}

	void DestroyPremature(std::exception_ptr ep) noexcept {
		const auto _sent = sent;
		auto &_handler = handler;
		Destroy();
		_handler.WasOutputPremature(_sent, ep);
	}

	void DestroyError(std::exception_ptr ep) noexcept {
		auto &_handler = handler;
		Destroy();
		_handler.WasOutputError(ep);
	}

	void ScheduleWrite() noexcept {
		event.ScheduleWrite();
		timeout_event.Schedule(was_output_timeout);
	}

	void AbortError(std::exception_ptr ep) noexcept {
		if (input.IsDefined())
			input.ClearAndClose();

		DestroyError(ep);
	}

	void WriteEventCallback(unsigned events) noexcept;

	void OnTimeout() noexcept {
		AbortError(std::make_exception_ptr(WasError("send timeout")));
	}

	/* virtual methods from class IstreamHandler */
	bool OnIstreamReady() noexcept override;
	size_t OnData(const void *data, size_t length) noexcept override;
	ssize_t OnDirect(FdType type, int fd, size_t max_length) noexcept override;
	void OnEof() noexcept override;
	void OnError(std::exception_ptr ep) noexcept override;
};

bool
WasOutput::CheckLength() noexcept
{
	if (known_length)
		return true;

	off_t available = input.GetAvailable(false);
	if (available < 0)
		return true;

	known_length = true;
	return handler.WasOutputLength(sent + available);
}

/*
 * libevent callback
 *
 */

inline void
WasOutput::WriteEventCallback(unsigned) noexcept
{
	assert(fd.IsDefined());
	assert(input.IsDefined());

	event.CancelWrite();
	timeout_event.Cancel();

	if (CheckLength())
		input.Read();
}

/*
 * istream handler for the request
 *
 */

bool
WasOutput::OnIstreamReady() noexcept
{
	assert(fd.IsDefined());
	assert(input.IsDefined());

	/* collect buckets */

	IstreamBucketList list;

	try {
		input.FillBucketList(list);
	} catch (...) {
		input.Clear();
		AbortError(std::current_exception());
		return false;
	}

	if (list.IsEmpty() && !list.HasMore()) {
		/* our input has ended */

		input.ClearAndClose();
		event.Cancel();
		timeout_event.Cancel();

		if (!known_length && !handler.WasOutputLength(sent))
			return false;

		DestroyEof();
		return false;
	}

	/* convert buckets to struct iovec array */

	StaticArray<struct iovec, 64> v;
	bool more = list.HasMore(), result = false;
	size_t total = 0;

	for (const auto &i : list) {
		if (!i.IsBuffer()) {
			result = true;
			more = true;
			break;
		}

		if (v.full()) {
			more = true;
			break;
		}

		const auto buffer = i.GetBuffer();

		auto &w = v.append();
		w.iov_base = const_cast<void *>(buffer.data);
		w.iov_len = buffer.size;
		total += buffer.size;
	}

	if (v.empty())
		return true;

	/* write this struct iovec array */

	ssize_t nbytes = writev(fd.Get(), &v.front(), v.size());
	if (nbytes < 0) {
		int e = errno;
		if (e == EAGAIN) {
			ScheduleWrite();
			return false;
		}

		AbortError(std::make_exception_ptr(MakeErrno("Write to WAS process failed")));
		return false;
	}

	sent += nbytes;
	input.ConsumeBucketList(nbytes);

	if (!more && size_t(nbytes) == total) {
		/* we've just reached end of our input */

		input.ClearAndClose();
		event.Cancel();
		timeout_event.Cancel();

		if (!known_length && !handler.WasOutputLength(sent))
			return false;

		DestroyEof();
		return false;
	}

	ScheduleWrite();
	return result;
}

inline size_t
WasOutput::OnData(const void *p, size_t length) noexcept
{
	assert(fd.IsDefined());
	assert(input.IsDefined());

	ssize_t nbytes = fd.Write(p, length);
	if (gcc_likely(nbytes > 0)) {
		sent += nbytes;
		ScheduleWrite();
	} else if (nbytes < 0) {
		if (errno == EAGAIN) {
			ScheduleWrite();
			return 0;
		}

		AbortError(std::make_exception_ptr(MakeErrno("Write to WAS process failed")));
		return 0;
	}

	return (size_t)nbytes;
}

inline ssize_t
WasOutput::OnDirect(gcc_unused FdType type, int source_fd, size_t max_length) noexcept
{
	assert(fd.IsDefined());

	ssize_t nbytes = SpliceToPipe(source_fd, fd.Get(), max_length);
	if (gcc_likely(nbytes > 0)) {
		sent += nbytes;
		ScheduleWrite();
	} else if (nbytes < 0 && errno == EAGAIN) {
		if (!fd.IsReadyForWriting()) {
			ScheduleWrite();
			return ISTREAM_RESULT_BLOCKING;
		}

		/* try again, just in case fd has become ready between
		   the first istream_direct_to_pipe() call and
		   fd.IsReadyForWriting() */
		nbytes = SpliceToPipe(source_fd, fd.Get(), max_length);
	}

	return nbytes;
}

void
WasOutput::OnEof() noexcept
{
	assert(input.IsDefined());

	input.Clear();
	event.Cancel();
	timeout_event.Cancel();

	if (!known_length && !handler.WasOutputLength(sent))
		return;

	DestroyEof();
}

void
WasOutput::OnError(std::exception_ptr ep) noexcept
{
	assert(input.IsDefined());

	input.Clear();

	DestroyPremature(ep);
}

/*
 * constructor
 *
 */

WasOutput *
was_output_new(struct pool &pool, EventLoop &event_loop,
	       FileDescriptor fd, UnusedIstreamPtr input,
	       WasOutputHandler &handler) noexcept
{
	assert(fd.IsDefined());

	return NewFromPool<WasOutput>(pool, pool, event_loop, fd,
				      std::move(input), handler);
}

uint64_t
was_output_free(WasOutput *output) noexcept
{
	assert(output != nullptr);

	return output->Close();
}

bool
was_output_check_length(WasOutput &output) noexcept
{
	return output.CheckLength();
}
<commit_msg>was/output: add method GetPipe()<commit_after>/*
 * Copyright 2007-2018 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.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.
 *
 * 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
 * FOUNDATION 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 "Output.hxx"
#include "Error.hxx"
#include "event/SocketEvent.hxx"
#include "event/TimerEvent.hxx"
#include "io/Splice.hxx"
#include "io/SpliceSupport.hxx"
#include "io/FileDescriptor.hxx"
#include "system/Error.hxx"
#include "istream/Bucket.hxx"
#include "istream/Handler.hxx"
#include "istream/Pointer.hxx"
#include "istream/UnusedPtr.hxx"
#include "pool/pool.hxx"
#include "pool/LeakDetector.hxx"
#include "util/StaticArray.hxx"

#include <was/protocol.h>

#include <sys/uio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

static constexpr Event::Duration was_output_timeout = std::chrono::minutes(2);

class WasOutput final : IstreamHandler, PoolLeakDetector {
	FileDescriptor fd;
	SocketEvent event;
	TimerEvent timeout_event;

	WasOutputHandler &handler;

	IstreamPointer input;

	uint64_t sent = 0;

	bool known_length = false;

public:
	WasOutput(struct pool &pool, EventLoop &event_loop, FileDescriptor _fd,
		  UnusedIstreamPtr _input,
		  WasOutputHandler &_handler) noexcept
		:PoolLeakDetector(pool), fd(_fd),
		 event(event_loop, BIND_THIS_METHOD(WriteEventCallback),
		       SocketDescriptor::FromFileDescriptor(fd)),
		 timeout_event(event_loop, BIND_THIS_METHOD(OnTimeout)),
		 handler(_handler),
		 input(std::move(_input), *this)
	{
		input.SetDirect(ISTREAM_TO_PIPE);

		ScheduleWrite();
	}

	uint64_t Close() noexcept {
		if (input.IsDefined())
			input.ClearAndClose();

		const auto _sent = sent;
		Destroy();
		return _sent;
	}

	bool CheckLength() noexcept;

private:
	bool HasPipe() const noexcept {
		return fd.IsDefined();
	}

	FileDescriptor GetPipe() noexcept {
		return fd;
	}

	void Destroy() noexcept {
		this->~WasOutput();
	}

	void DestroyEof() noexcept {
		auto &_handler = handler;
		Destroy();
		_handler.WasOutputEof();
	}

	void DestroyPremature(std::exception_ptr ep) noexcept {
		const auto _sent = sent;
		auto &_handler = handler;
		Destroy();
		_handler.WasOutputPremature(_sent, ep);
	}

	void DestroyError(std::exception_ptr ep) noexcept {
		auto &_handler = handler;
		Destroy();
		_handler.WasOutputError(ep);
	}

	void ScheduleWrite() noexcept {
		event.ScheduleWrite();
		timeout_event.Schedule(was_output_timeout);
	}

	void AbortError(std::exception_ptr ep) noexcept {
		if (input.IsDefined())
			input.ClearAndClose();

		DestroyError(ep);
	}

	void WriteEventCallback(unsigned events) noexcept;

	void OnTimeout() noexcept {
		AbortError(std::make_exception_ptr(WasError("send timeout")));
	}

	/* virtual methods from class IstreamHandler */
	bool OnIstreamReady() noexcept override;
	size_t OnData(const void *data, size_t length) noexcept override;
	ssize_t OnDirect(FdType type, int fd, size_t max_length) noexcept override;
	void OnEof() noexcept override;
	void OnError(std::exception_ptr ep) noexcept override;
};

bool
WasOutput::CheckLength() noexcept
{
	if (known_length)
		return true;

	off_t available = input.GetAvailable(false);
	if (available < 0)
		return true;

	known_length = true;
	return handler.WasOutputLength(sent + available);
}

/*
 * libevent callback
 *
 */

inline void
WasOutput::WriteEventCallback(unsigned) noexcept
{
	assert(HasPipe());
	assert(input.IsDefined());

	event.CancelWrite();
	timeout_event.Cancel();

	if (CheckLength())
		input.Read();
}

/*
 * istream handler for the request
 *
 */

bool
WasOutput::OnIstreamReady() noexcept
{
	assert(HasPipe());
	assert(input.IsDefined());

	/* collect buckets */

	IstreamBucketList list;

	try {
		input.FillBucketList(list);
	} catch (...) {
		input.Clear();
		AbortError(std::current_exception());
		return false;
	}

	if (list.IsEmpty() && !list.HasMore()) {
		/* our input has ended */

		input.ClearAndClose();
		event.Cancel();
		timeout_event.Cancel();

		if (!known_length && !handler.WasOutputLength(sent))
			return false;

		DestroyEof();
		return false;
	}

	/* convert buckets to struct iovec array */

	StaticArray<struct iovec, 64> v;
	bool more = list.HasMore(), result = false;
	size_t total = 0;

	for (const auto &i : list) {
		if (!i.IsBuffer()) {
			result = true;
			more = true;
			break;
		}

		if (v.full()) {
			more = true;
			break;
		}

		const auto buffer = i.GetBuffer();

		auto &w = v.append();
		w.iov_base = const_cast<void *>(buffer.data);
		w.iov_len = buffer.size;
		total += buffer.size;
	}

	if (v.empty())
		return true;

	/* write this struct iovec array */

	ssize_t nbytes = writev(GetPipe().Get(), &v.front(), v.size());
	if (nbytes < 0) {
		int e = errno;
		if (e == EAGAIN) {
			ScheduleWrite();
			return false;
		}

		AbortError(std::make_exception_ptr(MakeErrno("Write to WAS process failed")));
		return false;
	}

	sent += nbytes;
	input.ConsumeBucketList(nbytes);

	if (!more && size_t(nbytes) == total) {
		/* we've just reached end of our input */

		input.ClearAndClose();
		event.Cancel();
		timeout_event.Cancel();

		if (!known_length && !handler.WasOutputLength(sent))
			return false;

		DestroyEof();
		return false;
	}

	ScheduleWrite();
	return result;
}

inline size_t
WasOutput::OnData(const void *p, size_t length) noexcept
{
	assert(HasPipe());
	assert(input.IsDefined());

	ssize_t nbytes = GetPipe().Write(p, length);
	if (gcc_likely(nbytes > 0)) {
		sent += nbytes;
		ScheduleWrite();
	} else if (nbytes < 0) {
		if (errno == EAGAIN) {
			ScheduleWrite();
			return 0;
		}

		AbortError(std::make_exception_ptr(MakeErrno("Write to WAS process failed")));
		return 0;
	}

	return (size_t)nbytes;
}

inline ssize_t
WasOutput::OnDirect(gcc_unused FdType type, int source_fd, size_t max_length) noexcept
{
	assert(HasPipe());

	ssize_t nbytes = SpliceToPipe(source_fd, GetPipe().Get(), max_length);
	if (gcc_likely(nbytes > 0)) {
		sent += nbytes;
		ScheduleWrite();
	} else if (nbytes < 0 && errno == EAGAIN) {
		if (!GetPipe().IsReadyForWriting()) {
			ScheduleWrite();
			return ISTREAM_RESULT_BLOCKING;
		}

		/* try again, just in case fd has become ready between
		   the first istream_direct_to_pipe() call and
		   fd.IsReadyForWriting() */
		nbytes = SpliceToPipe(source_fd, GetPipe().Get(), max_length);
	}

	return nbytes;
}

void
WasOutput::OnEof() noexcept
{
	assert(input.IsDefined());

	input.Clear();
	event.Cancel();
	timeout_event.Cancel();

	if (!known_length && !handler.WasOutputLength(sent))
		return;

	DestroyEof();
}

void
WasOutput::OnError(std::exception_ptr ep) noexcept
{
	assert(input.IsDefined());

	input.Clear();

	DestroyPremature(ep);
}

/*
 * constructor
 *
 */

WasOutput *
was_output_new(struct pool &pool, EventLoop &event_loop,
	       FileDescriptor fd, UnusedIstreamPtr input,
	       WasOutputHandler &handler) noexcept
{
	assert(fd.IsDefined());

	return NewFromPool<WasOutput>(pool, pool, event_loop, fd,
				      std::move(input), handler);
}

uint64_t
was_output_free(WasOutput *output) noexcept
{
	assert(output != nullptr);

	return output->Close();
}

bool
was_output_check_length(WasOutput &output) noexcept
{
	return output.CheckLength();
}
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////////
// This file is part of EasyRPG.
//
// EasyRPG is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// EasyRPG 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
/// Headers
////////////////////////////////////////////////////////////
#include "writer_lcf.h"

////////////////////////////////////////////////////////////
LcfWriter::LcfWriter(const char* filename, std::string encoding) :
	filename(filename),
	encoding(encoding),
	stream(fopen(filename, "wb"))
{
}

////////////////////////////////////////////////////////////
LcfWriter::LcfWriter(const std::string& filename, std::string encoding) :
	filename(filename),
	encoding(encoding),
	stream(fopen(filename.c_str(), "wb"))
{
}

////////////////////////////////////////////////////////////
LcfWriter::~LcfWriter() {
	Close();
}

////////////////////////////////////////////////////////////
void LcfWriter::Close() {
	if (stream != NULL)
		fclose(stream);
	stream = NULL;
}

////////////////////////////////////////////////////////////
void LcfWriter::Write(const void *ptr, size_t size, size_t nmemb) {
#ifndef NDEBUG
	assert(fwrite(ptr, size, nmemb, stream) == nmemb);
#else
	fwrite(ptr, size, nmemb, stream);
#endif
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<uint8_t>(uint8_t val) {
	Write(&val, 1, 1);
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<int16_t>(int16_t val) {
#ifdef READER_BIG_ENDIAN
	SwapByteOrder(val);
#endif
	Write(&val, 2, 1);
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<uint32_t>(uint32_t val) {
#ifdef READER_BIG_ENDIAN
	SwapByteOrder(val);
#endif
	Write(&val, 4, 1);
}

////////////////////////////////////////////////////////////
void LcfWriter::WriteInt(int val) {
	uint32_t value = (uint32_t) val;
	for (int i = 28; i >= 0; i -= 7)
		if (value >= (1U << i) || i == 0)
			Write<uint8_t>((uint8_t)(((value >> i) & 0x7F) | (i > 0 ? 0x80 : 0)));
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<int>(int val) {
	WriteInt(val);
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<bool>(bool val) {
	uint8_t x = val ? 1 : 0;
	Write(x);
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<double>(double val) {
#ifdef READER_BIG_ENDIAN
#warning "Need 64-bit Double byte swap"
#endif
	Write(&val, 8, 1);
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<bool>(const std::vector<bool>& buffer) {
	std::vector<bool>::const_iterator it;
	for (it = buffer.begin(); it != buffer.end(); it++) {
		uint8_t val = *it ? 1 : 0;
		Write(val);
	}
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<uint8_t>(const std::vector<uint8_t>& buffer) {
	Write(&buffer.front(), 1, buffer.size());
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<int16_t>(const std::vector<int16_t>& buffer) {
#ifdef READER_BIG_ENDIAN
	std::vector<int16_t>::const_iterator it;
	for (it = buffer.begin(); it != buffer.end(); it++)
		Write16(*it);
#else
	Write(&buffer.front(), 2, buffer.size());
#endif
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<uint32_t>(const std::vector<uint32_t>& buffer) {
#ifdef READER_BIG_ENDIAN
	std::vector<uint32_t>::const_iterator it;
	for (it = buffer.begin(); it != buffer.end(); it++)
		Write32((uint32_t)*it);
#else
	Write(&buffer.front(), 4, buffer.size());
#endif
}

////////////////////////////////////////////////////////////
void LcfWriter::Write(const std::string& _str) {
	std::string str = Decode(_str);
	Write(&*str.begin(), 1, str.size());
}

////////////////////////////////////////////////////////////
bool LcfWriter::IsOk() const {
	return (stream != NULL && !ferror(stream));
}

////////////////////////////////////////////////////////////
std::string LcfWriter::Decode(const std::string& str_to_encode) {
#ifdef _WIN32
	return ReaderUtil::Recode(str_to_encode, "65001", encoding);
#else
	return ReaderUtil::Recode(str_to_encode, "UTF-8", encoding);
#endif
}

////////////////////////////////////////////////////////////
#ifdef READER_BIG_ENDIAN
void LcfWriter::SwapByteOrder(int16_t& u)
{
	uint16_t us = (uint16_t) s;
	us =	(us >> 8) |
			(us << 8);
	s = (int16_t) us;
}

void LcfWriter::SwapByteOrder(uint32_t& ui)
{
	ui =	(ui >> 24) |
			((ui<<8) & 0x00FF0000) |
			((ui>>8) & 0x0000FF00) |
			(ui << 24);
}
#endif
<commit_msg>cmake fix<commit_after>/////////////////////////////////////////////////////////////////////////////
// This file is part of EasyRPG.
//
// EasyRPG is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// EasyRPG 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
/// Headers
////////////////////////////////////////////////////////////
#include "writer_lcf.h"

////////////////////////////////////////////////////////////
LcfWriter::LcfWriter(const char* filename, std::string encoding) :
	filename(filename),
	encoding(encoding),
	stream(fopen(filename, "wb"))
{
}

////////////////////////////////////////////////////////////
LcfWriter::LcfWriter(const std::string& filename, std::string encoding) :
	filename(filename),
	encoding(encoding),
	stream(fopen(filename.c_str(), "wb"))
{
}

////////////////////////////////////////////////////////////
LcfWriter::~LcfWriter() {
	Close();
}

////////////////////////////////////////////////////////////
void LcfWriter::Close() {
	if (stream != NULL)
		fclose(stream);
	stream = NULL;
}

////////////////////////////////////////////////////////////
void LcfWriter::Write(const void *ptr, size_t size, size_t nmemb) {
#ifndef NDEBUG
	assert(fwrite(ptr, size, nmemb, stream) == nmemb);
#else
	fwrite(ptr, size, nmemb, stream);
#endif
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<uint8_t>(uint8_t val) {
	Write(&val, 1, 1);
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<int16_t>(int16_t val) {
#ifdef READER_BIG_ENDIAN
	SwapByteOrder(val);
#endif
	Write(&val, 2, 1);
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<uint32_t>(uint32_t val) {
#ifdef READER_BIG_ENDIAN
	SwapByteOrder(val);
#endif
	Write(&val, 4, 1);
}

////////////////////////////////////////////////////////////
void LcfWriter::WriteInt(int val) {
	uint32_t value = (uint32_t) val;
	for (int i = 28; i >= 0; i -= 7)
		if (value >= (1U << i) || i == 0)
			Write<uint8_t>((uint8_t)(((value >> i) & 0x7F) | (i > 0 ? 0x80 : 0)));
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<int>(int val) {
	WriteInt(val);
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<size_t>(size_t val) {
	WriteInt(val);
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<bool>(bool val) {
	uint8_t x = val ? 1 : 0;
	Write(x);
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<double>(double val) {
#ifdef READER_BIG_ENDIAN
#warning "Need 64-bit Double byte swap"
#endif
	Write(&val, 8, 1);
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<bool>(const std::vector<bool>& buffer) {
	std::vector<bool>::const_iterator it;
	for (it = buffer.begin(); it != buffer.end(); it++) {
		uint8_t val = *it ? 1 : 0;
		Write(val);
	}
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<uint8_t>(const std::vector<uint8_t>& buffer) {
	Write(&buffer.front(), 1, buffer.size());
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<int16_t>(const std::vector<int16_t>& buffer) {
#ifdef READER_BIG_ENDIAN
	std::vector<int16_t>::const_iterator it;
	for (it = buffer.begin(); it != buffer.end(); it++)
		Write16(*it);
#else
	Write(&buffer.front(), 2, buffer.size());
#endif
}

////////////////////////////////////////////////////////////
template <>
void LcfWriter::Write<uint32_t>(const std::vector<uint32_t>& buffer) {
#ifdef READER_BIG_ENDIAN
	std::vector<uint32_t>::const_iterator it;
	for (it = buffer.begin(); it != buffer.end(); it++)
		Write32((uint32_t)*it);
#else
	Write(&buffer.front(), 4, buffer.size());
#endif
}

////////////////////////////////////////////////////////////
void LcfWriter::Write(const std::string& _str) {
	std::string str = Decode(_str);
	Write(&*str.begin(), 1, str.size());
}

////////////////////////////////////////////////////////////
bool LcfWriter::IsOk() const {
	return (stream != NULL && !ferror(stream));
}

////////////////////////////////////////////////////////////
std::string LcfWriter::Decode(const std::string& str_to_encode) {
#ifdef _WIN32
	return ReaderUtil::Recode(str_to_encode, "65001", encoding);
#else
	return ReaderUtil::Recode(str_to_encode, "UTF-8", encoding);
#endif
}

////////////////////////////////////////////////////////////
#ifdef READER_BIG_ENDIAN
void LcfWriter::SwapByteOrder(int16_t& u)
{
	uint16_t us = (uint16_t) s;
	us =	(us >> 8) |
			(us << 8);
	s = (int16_t) us;
}

void LcfWriter::SwapByteOrder(uint32_t& ui)
{
	ui =	(ui >> 24) |
			((ui<<8) & 0x00FF0000) |
			((ui>>8) & 0x0000FF00) |
			(ui << 24);
}
#endif
<|endoftext|>


<commit_before>
#include <xmppstream.h>
#include <xmppserver.h>
#include <tagbuilder.h>
#include <nanosoft/base64.h>

// for debug only
#include <string>
#include <iostream>

using namespace std;
using namespace nanosoft;

/**
* Конструктор потока
*/
XMPPStream::XMPPStream(XMPPServer *srv, int sock): AsyncXMLStream(sock), server(srv), XMLWriter(1024), state(init)
{
	depth = 0;
	builder = new ATTagBuilder();
}

/**
* Деструктор потока
*/
XMPPStream::~XMPPStream()
{
	delete builder;
}

/**
* Запись XML
*/
void XMPPStream::onWriteXML(const char *data, size_t len)
{
	int r = write(data, len);
	if ( r != len ) onError("write fault");
	cout << "written: \033[22;34m" << string(data, len) << "\033[0m\n";
}

/**
* Событие готовности к записи
*
* Вызывается, когда в поток готов принять
* данные для записи без блокировки
*/
void XMPPStream::onWrite()
{
	cerr << "not implemented XMPPStream::onWrite()" << endl;
}

/**
* Событие закрытие соединения
*
* Вызывается если peer закрыл соединение
*/
void XMPPStream::onShutdown()
{
	server->onOffline(this);
	AsyncXMLStream::onShutdown();
	XMLWriter::flush();
	cerr << "[TestStream]: peer shutdown connection" << endl;
	if ( shutdown(fd, SHUT_RDWR) != 0 )
	{
		stderror();
	}
	server->daemon->removeObject(this);
	delete this;
}

/**
* Обработчик открытия тега
*/
void XMPPStream::onStartElement(const std::string &name, const attributtes_t &attributes)
{
	depth ++;
	switch ( depth )
	{
	case 1:
		onStartStream(name, attributes);
		break;
	case 2: // начало станзы
		builder->startElement(name, attributes, depth);
	break;
	default: // добавить тег в станзу
		builder->startElement(name, attributes, depth);
	}
}

/**
* Обработчик символьных данных
*/
void XMPPStream::onCharacterData(const std::string &cdata)
{
	builder->characterData(cdata);
}

/**
* Обработчик закрытия тега
*/
void XMPPStream::onEndElement(const std::string &name)
{
	switch (depth)
	{
	case 1:
		onEndStream();
		break;
	case 2: {
		builder->endElement(name);
		Stanza *s = new Stanza(builder->fetchResult());
		onStanza(s);
		delete s; // Внимание — станза удаляется здесь
		break;
	}
	default:
		builder->endElement(name);
	}
	depth --;
}

/**
* Обработчик станз
*/
void XMPPStream::onStanza(Stanza *stanza)
{
	cout << "stanza: " << stanza->tag()->name() << endl;
	if (stanza->tag()->name() == "iq") onIqStanza(stanza);
	else if (stanza->tag()->name() == "auth") onAuthStanza(stanza);
	else if (stanza->tag()->name() == "response" ) onResponseStanza(stanza);
	else if (stanza->tag()->name() == "message") onMessageStanza(stanza);
	else if (stanza->tag()->name() == "presence") onPresenceStanza(stanza);
	else ; // ...
}

/**
* Обработчик авторизации
*/
void XMPPStream::onAuthStanza(Stanza *stanza)
{
	string mechanism = stanza->tag()->getAttribute("mechanism");

	sasl = server->start("xmpp", client_jid.hostname(), mechanism);
	onSASLStep(string());
}

/**
* Обработка этапа авторизации SASL
*/
void XMPPStream::onSASLStep(const std::string &input)
{
	string output;
	switch ( server->step(sasl, input, output) )
	{
	case SASLServer::ok:
		client_jid.setUsername(server->getUsername(sasl));
		server->close(sasl);
		startElement("success");
			setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
		endElement("success");
		flush();
		resetWriter();
		state = authorized;
		depth = 1; // после выхода из onAuthStanza/onStanza() будет стандартный depth--
		resetParser();
		break;
	case SASLServer::next:
		startElement("challenge");
			setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
			characterData(base64_encode(output));
		endElement("challenge");
		flush();
		break;
	case SASLServer::error:
		server->close(sasl);
		startElement("failure");
			setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
			addElement("temporary-auth-failure", "");
		endElement("failure");
		flush();
		break;
	}
}

/**
* Обработчик авторизации: ответ клиента
*/
void XMPPStream::onResponseStanza(Stanza *stanza)
{
	onSASLStep(base64_decode(stanza->tag()->getCharacterData()));
}

/**
* Обработчик iq-станзы
*/
void XMPPStream::onIqStanza(Stanza *stanza)
{
	if(stanza->tag()->hasChild("bind") && (stanza->type() == "set" || stanza->type() == "get")) {
		client_jid.setResource(stanza->type() == "set" ? stanza->tag()->getChild("bind")->getChild("resource")->getCharacterData() : "foo");
		startElement("iq");
			setAttribute("type", "result");
			setAttribute("id", stanza->tag()->getAttribute("id"));
			startElement("bind");
				setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-bind");
				startElement("jid");
					characterData(jid().full());
				endElement("jid");
			endElement("bind");
		endElement("iq");
		flush();
	}
	if(stanza->tag()->hasChild("session") && stanza->type() == "set") {
		startElement("iq");
			setAttribute("id", stanza->tag()->getAttribute("id"));
			setAttribute("type", "result");
			startElement("session");
				setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-session");
			endElement("session");
		endElement("iq");
		flush();
		server->onOnline(this);
	}
	if(stanza->tag()->hasChild("query") && stanza->type() == "get") {
		// Входящие запросы информации
		std::string query_xmlns = stanza->tag()->getChild("query")->getAttribute("xmlns");
		if(query_xmlns == "jabber:iq:version") {
			// Отправить версию сервера
			// send(Stanza::serverVersion(сервер, stanza->from(), stanza->id()));
		} else if (query_xmlns == "jabber:iq:roster") {
			startElement("iq");
				setAttribute("type", "result");
				setAttribute("id", stanza->tag()->getAttribute("id"));
				startElement("query");
					setAttribute("xmlns", "jabber:iq:roster");
					XMPPServer::users_t users = server->getUserList();
					for(XMPPServer::users_t::iterator pos = users.begin(); pos != users.end(); ++pos)
					{
						startElement("item");
							setAttribute("jid", *pos);
							setAttribute("name", *pos);
							setAttribute("subscription", "both");
							addElement("group", "Friends");
						endElement("item");
					}
				endElement("query");
			endElement("iq");
			flush();

			// Ниже идёт костыль — рассылка присутствий от всех онлайнеров
			// TODO: конечно же, декостылизация ;)
			Stanza *roster_presence;
			for(XMPPServer::sessions_t::iterator it = server->onliners.begin(); it != server->onliners.end(); it++) {
				for(XMPPServer::reslist_t::iterator jt = it->second.begin(); jt != it->second.end(); jt++) {
					roster_presence = Stanza::presence(jt->second->jid(), jid(), jt->second->presence());
					sendStanza(roster_presence);
					delete roster_presence;
				}
			}
		} else {
		    // Неизвестный запрос
			Stanza *s = Stanza::badRequest(client_jid.hostname(), stanza->from(), stanza->id());
		    sendStanza(s);
			delete s;
		}
	}
}

ClientPresence XMPPStream::presence() {
	return client_presence;
}

void XMPPStream::onMessageStanza(Stanza *stanza) {
	stanza->tag()->insertAttribute("from", jid().full());

	XMPPServer::sessions_t::iterator it;
	XMPPServer::reslist_t reslist;
	XMPPServer::reslist_t::iterator jt;

	it = server->onliners.find(stanza->to().bare());
	if(it != server->onliners.end()) {
		// Проверить, есть ли ресурс, если он указан
		JID to = stanza->to();
		if(to.resource() != "") {
			jt = it->second.find(to.resource());
			if(jt != it->second.end()) {
				jt->second->sendStanza(stanza);
				return;
			}
			// Не отправили на выбранный ресурс, смотрим дальше…
		}
		std::list<XMPPStream *> sendto_list;
		std::list<XMPPStream *>::iterator kt;
		int max_priority = 0;
		for(jt = it->second.begin(); jt != it->second.end(); jt++) {
			if(jt->second->presence().priority == max_priority) {
				sendto_list.push_back(jt->second);
			} else if(jt->second->presence().priority > max_priority) {
				sendto_list.clear();
				sendto_list.push_back(jt->second);
			}
		}
		if(sendto_list.empty()) {
			cout << "Offline message for: " << stanza->to().bare() << endl;
			return;
		}
		for(kt = sendto_list.begin(); kt != sendto_list.end(); kt++) {
			(*kt)->sendStanza(stanza);
		}
	} else {
		cout << "Offline message for: " << stanza->to().bare() << endl;
	}
}

void XMPPStream::onPresenceStanza(Stanza *stanza)
{
	client_presence.priority = atoi(stanza->tag()->getChildValue("priority", "0").c_str()); // TODO
	client_presence.status_text = stanza->tag()->getChildValue("status", "");
	client_presence.setShow(stanza->tag()->getChildValue("show", "Available"));

	for(XMPPServer::sessions_t::iterator it = server->onliners.begin(); it != server->onliners.end(); it++) {
		stanza->tag()->insertAttribute("to", it->first);
		stanza->tag()->insertAttribute("from", client_jid.full());
		for(XMPPServer::reslist_t::iterator jt = it->second.begin(); jt != it->second.end(); jt++) {
			jt->second->sendStanza(stanza);
		}
	}
}

/**
* Событие: начало потока
*/
void XMPPStream::onStartStream(const std::string &name, const attributes_t &attributes)
{
	cout << "new stream" << endl;
	initXML();
	startElement("stream:stream");
	setAttribute("xmlns", "jabber:client");
	setAttribute("xmlns:stream", "http://etherx.jabber.org/streams");
	setAttribute("id", "123456"); // Требования к id — непредсказуемость и уникальность
	setAttribute("from", "localhost");
	setAttribute("version", "1.0");
	setAttribute("xml:lang", "en");

	startElement("stream:features");
	if ( state == init )
	{
		client_jid.setHostname(attributes.find("to")->second);
		startElement("mechanisms");
			setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
			SASLServer::mechanisms_t list = server->getMechanisms();
			for(SASLServer::mechanisms_t::const_iterator pos = list.begin(); pos != list.end(); ++pos)
			{
				addElement("mechanism", *pos);
			}
		endElement("mechanisms");
		startElement("register");
			setAttribute("xmlns", "http://jabber.org/features/iq-register");
		endElement("register");
	}
	else
	{
		startElement("bind");
			setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-bind");
		endElement("bind");
		/*
		startElement("session");
			setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-session");
		endElement("session");
		*/
	}
	endElement("stream:features");
	flush();
}

/**
* Событие: конец потока
*/
void XMPPStream::onEndStream()
{
	cerr << "session closed" << endl;
	endElement("stream:stream");
}

/**
* JID потока
*/
JID XMPPStream::jid()
{
	return client_jid;
}

void XMPPStream::sendTag(ATXmlTag * tag) {
	startElement(tag->name());
	attributes_t attributes = tag->getAttributes();
	for(attributes_t::iterator it = attributes.begin(); it != attributes.end(); it++) {
		setAttribute(it->first, it->second);
	}
	nodes_list_t nodes = tag->getChildNodes();
	for(nodes_list_t::iterator it = nodes.begin(); it != nodes.end(); it++) {
		if((*it)->type == TTag) {
			sendTag((*it)->tag);
		} else {
			characterData((*it)->cdata);
		}
	}
	endElement(tag->name());
	// send(tag->asString()); — так будет куда проще…
}

void XMPPStream::sendStanza(Stanza * stanza) {
	sendTag(stanza->tag());
	flush();
}
<commit_msg>Прошу прощения, забыл раскомментировать и подправить пару строк. Это добавление к предыдущей ревизии.<commit_after>
#include <xmppstream.h>
#include <xmppserver.h>
#include <tagbuilder.h>
#include <nanosoft/base64.h>

// for debug only
#include <string>
#include <iostream>

using namespace std;
using namespace nanosoft;

/**
* Конструктор потока
*/
XMPPStream::XMPPStream(XMPPServer *srv, int sock): AsyncXMLStream(sock), server(srv), XMLWriter(1024), state(init)
{
	depth = 0;
	builder = new ATTagBuilder();
}

/**
* Деструктор потока
*/
XMPPStream::~XMPPStream()
{
	delete builder;
}

/**
* Запись XML
*/
void XMPPStream::onWriteXML(const char *data, size_t len)
{
	int r = write(data, len);
	if ( r != len ) onError("write fault");
	cout << "written: \033[22;34m" << string(data, len) << "\033[0m\n";
}

/**
* Событие готовности к записи
*
* Вызывается, когда в поток готов принять
* данные для записи без блокировки
*/
void XMPPStream::onWrite()
{
	cerr << "not implemented XMPPStream::onWrite()" << endl;
}

/**
* Событие закрытие соединения
*
* Вызывается если peer закрыл соединение
*/
void XMPPStream::onShutdown()
{
	server->onOffline(this);
	AsyncXMLStream::onShutdown();
	XMLWriter::flush();
	cerr << "[TestStream]: peer shutdown connection" << endl;
	if ( shutdown(fd, SHUT_RDWR) != 0 )
	{
		stderror();
	}
	server->daemon->removeObject(this);
	delete this;
}

/**
* Обработчик открытия тега
*/
void XMPPStream::onStartElement(const std::string &name, const attributtes_t &attributes)
{
	depth ++;
	switch ( depth )
	{
	case 1:
		onStartStream(name, attributes);
		break;
	case 2: // начало станзы
		builder->startElement(name, attributes, depth);
	break;
	default: // добавить тег в станзу
		builder->startElement(name, attributes, depth);
	}
}

/**
* Обработчик символьных данных
*/
void XMPPStream::onCharacterData(const std::string &cdata)
{
	builder->characterData(cdata);
}

/**
* Обработчик закрытия тега
*/
void XMPPStream::onEndElement(const std::string &name)
{
	switch (depth)
	{
	case 1:
		onEndStream();
		break;
	case 2: {
		builder->endElement(name);
		Stanza *s = new Stanza(builder->fetchResult());
		onStanza(s);
		delete s; // Внимание — станза удаляется здесь
		break;
	}
	default:
		builder->endElement(name);
	}
	depth --;
}

/**
* Обработчик станз
*/
void XMPPStream::onStanza(Stanza *stanza)
{
	cout << "stanza: " << stanza->tag()->name() << endl;
	if (stanza->tag()->name() == "iq") onIqStanza(stanza);
	else if (stanza->tag()->name() == "auth") onAuthStanza(stanza);
	else if (stanza->tag()->name() == "response" ) onResponseStanza(stanza);
	else if (stanza->tag()->name() == "message") onMessageStanza(stanza);
	else if (stanza->tag()->name() == "presence") onPresenceStanza(stanza);
	else ; // ...
}

/**
* Обработчик авторизации
*/
void XMPPStream::onAuthStanza(Stanza *stanza)
{
	string mechanism = stanza->tag()->getAttribute("mechanism");

	sasl = server->start("xmpp", client_jid.hostname(), mechanism);
	onSASLStep(string());
}

/**
* Обработка этапа авторизации SASL
*/
void XMPPStream::onSASLStep(const std::string &input)
{
	string output;
	switch ( server->step(sasl, input, output) )
	{
	case SASLServer::ok:
		client_jid.setUsername(server->getUsername(sasl));
		server->close(sasl);
		startElement("success");
			setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
		endElement("success");
		flush();
		resetWriter();
		state = authorized;
		depth = 1; // после выхода из onAuthStanza/onStanza() будет стандартный depth--
		resetParser();
		break;
	case SASLServer::next:
		startElement("challenge");
			setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
			characterData(base64_encode(output));
		endElement("challenge");
		flush();
		break;
	case SASLServer::error:
		server->close(sasl);
		startElement("failure");
			setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
			addElement("temporary-auth-failure", "");
		endElement("failure");
		flush();
		break;
	}
}

/**
* Обработчик авторизации: ответ клиента
*/
void XMPPStream::onResponseStanza(Stanza *stanza)
{
	onSASLStep(base64_decode(stanza->tag()->getCharacterData()));
}

/**
* Обработчик iq-станзы
*/
void XMPPStream::onIqStanza(Stanza *stanza)
{
	if(stanza->tag()->hasChild("bind") && (stanza->type() == "set" || stanza->type() == "get")) {
		client_jid.setResource(stanza->type() == "set" ? stanza->tag()->getChild("bind")->getChild("resource")->getCharacterData() : "foo");
		startElement("iq");
			setAttribute("type", "result");
			setAttribute("id", stanza->tag()->getAttribute("id"));
			startElement("bind");
				setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-bind");
				startElement("jid");
					characterData(jid().full());
				endElement("jid");
			endElement("bind");
		endElement("iq");
		flush();
	}
	if(stanza->tag()->hasChild("session") && stanza->type() == "set") {
		startElement("iq");
			setAttribute("id", stanza->tag()->getAttribute("id"));
			setAttribute("type", "result");
			startElement("session");
				setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-session");
			endElement("session");
		endElement("iq");
		flush();
		server->onOnline(this);
	}
	if(stanza->tag()->hasChild("query") && stanza->type() == "get") {
		// Входящие запросы информации
		std::string query_xmlns = stanza->tag()->getChild("query")->getAttribute("xmlns");
		if(query_xmlns == "jabber:iq:version") {
			// Отправить версию сервера
			Stanza *s = Stanza::serverVersion(client_jid.hostname(), stanza->from(), stanza->id());
		    sendStanza(s);
			delete s;
		} else if (query_xmlns == "jabber:iq:roster") {
			startElement("iq");
				setAttribute("type", "result");
				setAttribute("id", stanza->tag()->getAttribute("id"));
				startElement("query");
					setAttribute("xmlns", "jabber:iq:roster");
					XMPPServer::users_t users = server->getUserList();
					for(XMPPServer::users_t::iterator pos = users.begin(); pos != users.end(); ++pos)
					{
						startElement("item");
							setAttribute("jid", *pos);
							setAttribute("name", *pos);
							setAttribute("subscription", "both");
							addElement("group", "Friends");
						endElement("item");
					}
				endElement("query");
			endElement("iq");
			flush();

			// Ниже идёт костыль — рассылка присутствий от всех онлайнеров
			// TODO: конечно же, декостылизация ;)
			Stanza *roster_presence;
			for(XMPPServer::sessions_t::iterator it = server->onliners.begin(); it != server->onliners.end(); it++) {
				for(XMPPServer::reslist_t::iterator jt = it->second.begin(); jt != it->second.end(); jt++) {
					roster_presence = Stanza::presence(jt->second->jid(), jid(), jt->second->presence());
					sendStanza(roster_presence);
					delete roster_presence;
				}
			}
		} else {
		    // Неизвестный запрос
			Stanza *s = Stanza::badRequest(client_jid.hostname(), stanza->from(), stanza->id());
		    sendStanza(s);
			delete s;
		}
	}
}

ClientPresence XMPPStream::presence() {
	return client_presence;
}

void XMPPStream::onMessageStanza(Stanza *stanza) {
	stanza->tag()->insertAttribute("from", jid().full());

	XMPPServer::sessions_t::iterator it;
	XMPPServer::reslist_t reslist;
	XMPPServer::reslist_t::iterator jt;

	it = server->onliners.find(stanza->to().bare());
	if(it != server->onliners.end()) {
		// Проверить, есть ли ресурс, если он указан
		JID to = stanza->to();
		if(to.resource() != "") {
			jt = it->second.find(to.resource());
			if(jt != it->second.end()) {
				jt->second->sendStanza(stanza);
				return;
			}
			// Не отправили на выбранный ресурс, смотрим дальше…
		}
		std::list<XMPPStream *> sendto_list;
		std::list<XMPPStream *>::iterator kt;
		int max_priority = 0;
		for(jt = it->second.begin(); jt != it->second.end(); jt++) {
			if(jt->second->presence().priority == max_priority) {
				sendto_list.push_back(jt->second);
			} else if(jt->second->presence().priority > max_priority) {
				sendto_list.clear();
				sendto_list.push_back(jt->second);
			}
		}
		if(sendto_list.empty()) {
			cout << "Offline message for: " << stanza->to().bare() << endl;
			return;
		}
		for(kt = sendto_list.begin(); kt != sendto_list.end(); kt++) {
			(*kt)->sendStanza(stanza);
		}
	} else {
		cout << "Offline message for: " << stanza->to().bare() << endl;
	}
}

void XMPPStream::onPresenceStanza(Stanza *stanza)
{
	client_presence.priority = atoi(stanza->tag()->getChildValue("priority", "0").c_str()); // TODO
	client_presence.status_text = stanza->tag()->getChildValue("status", "");
	client_presence.setShow(stanza->tag()->getChildValue("show", "Available"));

	for(XMPPServer::sessions_t::iterator it = server->onliners.begin(); it != server->onliners.end(); it++) {
		stanza->tag()->insertAttribute("to", it->first);
		stanza->tag()->insertAttribute("from", client_jid.full());
		for(XMPPServer::reslist_t::iterator jt = it->second.begin(); jt != it->second.end(); jt++) {
			jt->second->sendStanza(stanza);
		}
	}
}

/**
* Событие: начало потока
*/
void XMPPStream::onStartStream(const std::string &name, const attributes_t &attributes)
{
	cout << "new stream" << endl;
	initXML();
	startElement("stream:stream");
	setAttribute("xmlns", "jabber:client");
	setAttribute("xmlns:stream", "http://etherx.jabber.org/streams");
	setAttribute("id", "123456"); // Требования к id — непредсказуемость и уникальность
	setAttribute("from", "localhost");
	setAttribute("version", "1.0");
	setAttribute("xml:lang", "en");

	startElement("stream:features");
	if ( state == init )
	{
		client_jid.setHostname(attributes.find("to")->second);
		startElement("mechanisms");
			setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
			SASLServer::mechanisms_t list = server->getMechanisms();
			for(SASLServer::mechanisms_t::const_iterator pos = list.begin(); pos != list.end(); ++pos)
			{
				addElement("mechanism", *pos);
			}
		endElement("mechanisms");
		startElement("register");
			setAttribute("xmlns", "http://jabber.org/features/iq-register");
		endElement("register");
	}
	else
	{
		startElement("bind");
			setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-bind");
		endElement("bind");
		/*
		startElement("session");
			setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-session");
		endElement("session");
		*/
	}
	endElement("stream:features");
	flush();
}

/**
* Событие: конец потока
*/
void XMPPStream::onEndStream()
{
	cerr << "session closed" << endl;
	endElement("stream:stream");
}

/**
* JID потока
*/
JID XMPPStream::jid()
{
	return client_jid;
}

void XMPPStream::sendTag(ATXmlTag * tag) {
	startElement(tag->name());
	attributes_t attributes = tag->getAttributes();
	for(attributes_t::iterator it = attributes.begin(); it != attributes.end(); it++) {
		setAttribute(it->first, it->second);
	}
	nodes_list_t nodes = tag->getChildNodes();
	for(nodes_list_t::iterator it = nodes.begin(); it != nodes.end(); it++) {
		if((*it)->type == TTag) {
			sendTag((*it)->tag);
		} else {
			characterData((*it)->cdata);
		}
	}
	endElement(tag->name());
	// send(tag->asString()); — так будет куда проще…
}

void XMPPStream::sendStanza(Stanza * stanza) {
	sendTag(stanza->tag());
	flush();
}
<|endoftext|>


<commit_before>#ifndef GNR_STRUCTITERATOR_HPP
# define GNR_STRUCTITERATOR_HPP
# pragma once

#include <iterator>

#include <memory> //std::addressof()

#include "boost/pfr.hpp"

namespace gnr
{

namespace detail::struct_iterator
{

template <class S>
constexpr auto all_same() noexcept
{
  if constexpr (constexpr auto N(boost::pfr::tuple_size_v<S>); N > 1)
  {
    return [&]<auto ...I>(std::index_sequence<I...>) noexcept
      {
        return (
            (
              std::is_same_v<
                boost::pfr::tuple_element_t<I, S>,
                boost::pfr::tuple_element_t<I + 1, S>
              >
            ) && ...
          );
      }(std::make_index_sequence<N - 1>());
  }
  else
  {
    return true;
  }
}

template <class S>
static constexpr auto is_proper_v(std::is_class_v<S> && all_same<S>());

}

template <typename S>
  requires detail::struct_iterator::is_proper_v<S>
class struct_iterator
{
  S& s_;
  std::size_t i_;

public:
  using iterator_category = std::random_access_iterator_tag;
  using difference_type = std::ptrdiff_t;
  using pointer = decltype(&boost::pfr::get<0>(s_));
  using reference = decltype(boost::pfr::get<0>(s_));
  using value_type = std::remove_reference_t<reference>;

public:
  constexpr explicit struct_iterator(S& s,
    std::size_t const i = boost::pfr::tuple_size<S>{}) noexcept:
    s_{s},
    i_{i}
  {
  }

  // increment, decrement
  constexpr auto& operator++() noexcept { return ++i_, *this; }
  constexpr auto& operator--() noexcept { return --i_, *this; }

  constexpr auto operator++(int) const noexcept
  {
    return struct_iterator(s_, i_ + 1);
  }

  constexpr auto operator--(int) const noexcept
  {
    return struct_iterator(s_, i_ - 1);
  }

  // arithmetic
  constexpr auto operator-(struct_iterator const other) const noexcept
  {
    return difference_type(i_ - other.i_);
  }

  constexpr auto operator+(std::size_t const N) const noexcept
  {
    return struct_iterator(s_, i_ + N);
  }

  constexpr auto operator-(std::size_t const N) const noexcept
  {
    return struct_iterator(s_, i_ - N);
  }

  // comparison
  constexpr auto operator==(struct_iterator const other) const noexcept
  {
    return (std::addressof(other.s_) == std::addressof(s_)) &&
      (other.i_ == i_);
  }

  constexpr auto operator!=(struct_iterator const other) const noexcept
  {
    return !(*this == other);
  }

  constexpr auto operator<(struct_iterator const other) const noexcept
  {
    return i_ < other.i_;
  }

  //
  constexpr auto& operator*() const noexcept
  {
    return [&]<auto ...I>(std::index_sequence<I...>) noexcept -> auto&
      {
/*
        pointer r{};

        (
          (
            r = I == i_ ? &boost::pfr::get<I>(s_) : r
          ),
          ...
        );

        return *r;
*/

        auto const p0(&boost::pfr::get<0>(s_));

        return *(p0 +
          (
            (
              I == i_ ? &boost::pfr::get<I>(s_) - p0 : std::ptrdiff_t{}
            ) |
            ...
          )
        );
      }(std::make_index_sequence<boost::pfr::tuple_size_v<S>>());
  }

  constexpr auto& operator[](std::size_t const i) const noexcept
  {
    return *(*this + i);
  }
};

template <typename S>
  requires detail::struct_iterator::is_proper_v<S>
class range
{
  S& s_;

public:
  constexpr explicit range(S& s) noexcept : s_{s}
  {
  }

  constexpr auto begin() const noexcept
  {
    return struct_iterator{s_, {}};
  }

  constexpr auto end() const noexcept
  {
    return struct_iterator{s_};
  }
};

template <typename S>
  requires detail::struct_iterator::is_proper_v<S>
constexpr auto begin(S& s) noexcept
{
  return struct_iterator{s, {}};
}

template <typename S>
  requires detail::struct_iterator::is_proper_v<S>
constexpr auto end(S& s) noexcept
{
  return struct_iterator{s};
}

template <typename S>
  requires detail::struct_iterator::is_proper_v<S>
constexpr auto size(S& s) noexcept
{
  return boost::pfr::tuple_size_v<S>;
}

}

#endif // GNR_STRUCTITERATOR_HPP
<commit_msg>some fixes<commit_after>#ifndef GNR_STRUCTITERATOR_HPP
# define GNR_STRUCTITERATOR_HPP
# pragma once

#include <iterator>

#include <memory> //std::addressof()

#include "boost/pfr.hpp"

namespace gnr
{

namespace detail::struct_iterator
{

template <class S>
constexpr auto all_same() noexcept
{
  if constexpr (constexpr auto N(boost::pfr::tuple_size_v<S>); N > 1)
  {
    return [&]<auto ...I>(std::index_sequence<I...>) noexcept
      {
        return (
            (
              std::is_same_v<
                boost::pfr::tuple_element_t<I, S>,
                boost::pfr::tuple_element_t<I + 1, S>
              >
            ) && ...
          );
      }(std::make_index_sequence<N - 1>());
  }
  else
  {
    return true;
  }
}

template <class S>
static constexpr auto is_proper_v(std::is_class_v<S> && all_same<S>());

}

template <typename S>
  requires detail::struct_iterator::is_proper_v<S>
class struct_iterator
{
  S& s_;
  std::size_t i_;

public:
  using iterator_category = std::random_access_iterator_tag;
  using difference_type = std::ptrdiff_t;
  using pointer = decltype(&boost::pfr::get<0>(s_));
  using reference = decltype(boost::pfr::get<0>(s_));
  using value_type = std::remove_reference_t<reference>;

public:
  constexpr explicit struct_iterator(S& s,
    std::size_t const i = boost::pfr::tuple_size<S>{}) noexcept:
    s_{s},
    i_{i}
  {
  }

  // increment, decrement
  constexpr auto& operator++() noexcept { return ++i_, *this; }
  constexpr auto& operator--() noexcept { return --i_, *this; }

  constexpr auto operator++(int) const noexcept
  {
    return struct_iterator(s_, i_ + 1);
  }

  constexpr auto operator--(int) const noexcept
  {
    return struct_iterator(s_, i_ - 1);
  }

  // arithmetic
  constexpr auto operator-(struct_iterator const other) const noexcept
  {
    return difference_type(i_ - other.i_);
  }

  constexpr auto operator+(std::size_t const N) const noexcept
  {
    return struct_iterator(s_, i_ + N);
  }

  constexpr auto operator-(std::size_t const N) const noexcept
  {
    return struct_iterator(s_, i_ - N);
  }

  // comparison
  constexpr auto operator==(struct_iterator const other) const noexcept
  {
    return (std::addressof(other.s_) == std::addressof(s_)) &&
      (other.i_ == i_);
  }

  constexpr auto operator!=(struct_iterator const other) const noexcept
  {
    return !(*this == other);
  }

  constexpr auto operator<(struct_iterator const other) const noexcept
  {
    return i_ < other.i_;
  }

  //
  constexpr auto& operator*() const noexcept
  {
    return [&]<auto ...I>(std::index_sequence<I...>) noexcept -> auto&
      {
        auto const p0(&boost::pfr::get<0>(s_));

        return *(p0 +
          (
            (
              I == i_ ? &boost::pfr::get<I>(s_) - p0 : std::ptrdiff_t{}
            ) |
            ...
          )
        );
      }(std::make_index_sequence<boost::pfr::tuple_size_v<S>>());
  }

  constexpr auto& operator[](std::size_t const i) const noexcept
  {
    return *(*this + i);
  }
};

template <typename S>
  requires detail::struct_iterator::is_proper_v<S>
class range
{
  S& s_;

public:
  constexpr explicit range(S& s) noexcept : s_{s}
  {
  }

  constexpr auto begin() const noexcept
  {
    return struct_iterator{s_, {}};
  }

  constexpr auto end() const noexcept
  {
    return struct_iterator{s_};
  }
};

template <typename S>
  requires detail::struct_iterator::is_proper_v<S>
constexpr auto begin(S& s) noexcept
{
  return struct_iterator{s, {}};
}

template <typename S>
  requires detail::struct_iterator::is_proper_v<S>
constexpr auto end(S& s) noexcept
{
  return struct_iterator{s};
}

template <typename S>
  requires detail::struct_iterator::is_proper_v<S>
constexpr auto size(S& s) noexcept
{
  return boost::pfr::tuple_size_v<S>;
}

}

#endif // GNR_STRUCTITERATOR_HPP
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: charfmt.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2006-12-01 15:31:37 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _CHARFMT_HXX
#define _CHARFMT_HXX

#ifndef _FORMAT_HXX
#include <format.hxx>
#endif

class SwCharFmt : public SwFmt
{
    friend class SwDoc;
    friend class SwTxtFmtColl;

    SwCharFmt( SwAttrPool& rPool, const sal_Char* pFmtName,
                SwCharFmt *pDerivedFrom )
          : SwFmt( rPool, pFmtName, aCharFmtSetRange, pDerivedFrom, RES_CHRFMT )
    {}
    SwCharFmt( SwAttrPool& rPool, const String &rFmtName,
                SwCharFmt *pDerivedFrom )
          : SwFmt( rPool, rFmtName, aCharFmtSetRange, pDerivedFrom, RES_CHRFMT )
    {}

public:
    TYPEINFO();    //Bereits in Basisklasse Client drin.
};

namespace CharFmt
{
    extern const SfxItemSet* GetItemSet( const SfxPoolItem& rAttr );
    extern const SfxPoolItem* GetItem( const SwTxtAttr& rAttr, USHORT nWhich );
    extern BOOL IsItemIncluded( const USHORT nWhich, const SwTxtAttr *pAttr );
}

#endif

<commit_msg>INTEGRATION: CWS changefileheader (1.3.630); FILE MERGED 2008/04/01 12:53:27 thb 1.3.630.2: #i85898# Stripping all external header guards 2008/03/31 16:52:34 rt 1.3.630.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: charfmt.hxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#ifndef _CHARFMT_HXX
#define _CHARFMT_HXX

#include <format.hxx>

class SwCharFmt : public SwFmt
{
    friend class SwDoc;
    friend class SwTxtFmtColl;

    SwCharFmt( SwAttrPool& rPool, const sal_Char* pFmtName,
                SwCharFmt *pDerivedFrom )
          : SwFmt( rPool, pFmtName, aCharFmtSetRange, pDerivedFrom, RES_CHRFMT )
    {}
    SwCharFmt( SwAttrPool& rPool, const String &rFmtName,
                SwCharFmt *pDerivedFrom )
          : SwFmt( rPool, rFmtName, aCharFmtSetRange, pDerivedFrom, RES_CHRFMT )
    {}

public:
    TYPEINFO();    //Bereits in Basisklasse Client drin.
};

namespace CharFmt
{
    extern const SfxItemSet* GetItemSet( const SfxPoolItem& rAttr );
    extern const SfxPoolItem* GetItem( const SwTxtAttr& rAttr, USHORT nWhich );
    extern BOOL IsItemIncluded( const USHORT nWhich, const SwTxtAttr *pAttr );
}

#endif

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: checkit.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2005-11-16 09:28:13 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _CHECKIT_HXX
#define _CHECKIT_HXX

#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif

#ifndef _COM_SUN_STAR_I18N_XEXTENDEDINPUTSEQUENCECHECKER_HDL_
#include <com/sun/star/i18n/XExtendedInputSequenceChecker.hpp>
#endif

/*************************************************************************
 * Input strings with length > MAX_SEQUENCE_CHECK_LEN are not checked.
 *************************************************************************/

#define MAX_SEQUENCE_CHECK_LEN 5

/*************************************************************************
 *                      class SwCheckIt
 *
 * Wrapper for the XInputSequenceChecker
 *************************************************************************/

class SwCheckIt
{
public:
    com::sun::star::uno::Reference < com::sun::star::i18n::XExtendedInputSequenceChecker > xCheck;

    SwCheckIt();
};

extern SwCheckIt* pCheckIt;

#endif

<commit_msg>INTEGRATION: CWS tl19 (1.4.116); FILE MERGED 2006/02/23 14:51:45 tl 1.4.116.1: #i61994# apply input sequence checking/correction to keyboard input only; have Undo working<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: checkit.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: vg $ $Date: 2006-03-14 09:37:32 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _CHECKIT_HXX
#define _CHECKIT_HXX

#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif

#ifndef _COM_SUN_STAR_I18N_XEXTENDEDINPUTSEQUENCECHECKER_HDL_
#include <com/sun/star/i18n/XExtendedInputSequenceChecker.hpp>
#endif

/*************************************************************************
 *                      class SwCheckIt
 *
 * Wrapper for the XInputSequenceChecker
 *************************************************************************/

class SwCheckIt
{
public:
    com::sun::star::uno::Reference < com::sun::star::i18n::XExtendedInputSequenceChecker > xCheck;

    SwCheckIt();
};

extern SwCheckIt* pCheckIt;

#endif

<|endoftext|>


<commit_before>#include "SysControl.h"
#include "ControlsApp.h"
#include "ControlsXPad360.h"

//ƽַ̨
#ifdef _WIN32
#pragma execution_character_set("utf-8")
#endif

using namespace MathLib;

class CSysControlLocal : public CSysControl
{
public:
	CSysControlLocal();
    virtual ~CSysControlLocal();

	virtual void Init();	//ɫҪʼɫҪʼ
	virtual void Update(float ifps);
	virtual void Shutdown();

	virtual int GetState(int state);		//״̬״̬״̬ӵ״̬ȵȡ
	virtual int ClearState(int state);

	virtual float GetMouseDX();
	virtual float GetMouseDY();

	virtual void SetMouseGrab(int g);		//Ƿʾ
	virtual int GetMouseGrab();			//ȡ״̬ʾػǲʾ״̬

	virtual void SetControlMode(ControlMode mode);			//ģʽ
	virtual ControlMode GetControlMode() const;				//ȡģʽ

private:
	void Update_Mouse(float ifps);
	void Update_Keyboard(float ifps);
	void Update_XPad360(float ifps);

	CControlsApp        *m_pControlsApp;		//Ϸƶ
	CControlsXPad360    *m_pControlsXPad360;
	ControlMode         m_nControlMode;			//ģʽ

	int                 m_nOldMouseX;			//һX
	int                 m_nOldMouseY;			//һY

}<commit_msg>Signed-off-by: mrlitong <litongtongxue@gmail.com><commit_after>#include "SysControl.h"
#include "ControlsApp.h"
#include "ControlsXPad360.h"

//ƽַ̨
#ifdef _WIN32
#pragma execution_character_set("utf-8")
#endif

using namespace MathLib;

class CSysControlLocal : public CSysControl
{
public:
	CSysControlLocal();
    virtual ~CSysControlLocal();

	virtual void Init();	//ɫҪʼɫҪʼ
	virtual void Update(float ifps);
	virtual void Shutdown();

	virtual int GetState(int state);		//״̬״̬״̬ӵ״̬ȵȡ
	virtual int ClearState(int state);

	virtual float GetMouseDX();
	virtual float GetMouseDY();

	virtual void SetMouseGrab(int g);		//Ƿʾ
	virtual int GetMouseGrab();			//ȡ״̬ʾػǲʾ״̬

	virtual void SetControlMode(ControlMode mode);			//ģʽ
	virtual ControlMode GetControlMode() const;				//ȡģʽ

private:
	void Update_Mouse(float ifps);
	void Update_Keyboard(float ifps);
	void Update_XPad360(float ifps);

	CControlsApp        *m_pControlsApp;		//Ϸƶ
	CControlsXPad360    *m_pControlsXPad360;
	ControlMode         m_nControlMode;			//ģʽ

	int                 m_nOldMouseX;			//һX
	int                 m_nOldMouseY;			//һY

	CObjectGui          *m_pTest3DUI;
	CWidgetLabel        *m_pTestMessageLabel;

}<|endoftext|>


<commit_before>
#ifndef __SOFTXMT_HPP__
#define __SOFTXMT_HPP__

#include <gflags/gflags.h>
#include <glog/logging.h>

#include "Communicator.hpp"
#include "Aggregator.hpp"

#include "thread.h"

void SoftXMT_init( int * argc_p, char ** argv_p[] );
void SoftXMT_activate();

bool SoftXMT_done();
void SoftXMT_finish( int retval );

Node SoftXMT_nodes();
Node SoftXMT_mynode();

void SoftXMT_poll();
void SoftXMT_flush( Node n );

void SoftXMT_barrier();

void SoftXMT_barrier_commsafe();

/// Spawn and run user main function. TODO: get return values working
/// TODO: remove thread * arg
int SoftXMT_run_user_main( void (* fn_p)(thread *, void *), void * args );

/// Spawn a user function. TODO: get return values working
/// TODO: remove thread * arg
thread * SoftXMT_spawn( void (* fn_p)(thread *, void *), void * args );

template< typename T >
thread * SoftXMT_template_spawn( void (* fn_p)(thread *, T *), T * args )
{
  typedef void (* fn_t)(thread *, void *);

  thread * th = SoftXMT_spawn( (fn_t)fn_p, (void *)args );
  DVLOG(5) << "Spawned thread " << th;
  return th;
}

/// Active message for spawning a thread on a remote node (used by SoftXMT_remote_spawn())
template< typename T >
static void am_remote_spawn(T* args, size_t args_size, void* payload, size_t payload_size) {
  typedef void (*thread_fn)(thread*,T*);
  void (*fn_p)(thread*,T*) = static_cast<thread_fn>(payload);
  T* aa = new T;
  *aa = *args;
  SoftXMT_template_spawn(&fn_p, aa);
}

/// Spawn a user thread on a remote node. Copies the passed arguments
/// to the remote node.
/// Note: the thread function should take ownership of the arguments
/// and clean them up at the end of the function call.
template< typename T >
void SoftXMT_remote_spawn( void (*fn_p)(thread*,T*), T* args, Node target) {
  SoftXMT_call_on(target, &am_remote_spawn, args, sizeof(T), fn_p, sizeof(fn_p));
}

/// Yield to scheduler, placing current thread on run queue.
void SoftXMT_yield( );

/// Yield to scheduler, suspending current thread.
void SoftXMT_suspend( );

/// Wake a thread by putting it on the run queue, leaving the current thread running.
void SoftXMT_wake( thread * t );

/// Wake a thread t by placing current thread on run queue and running t next.
void SoftXMT_yield_wake( thread * t );

/// Wake a thread t by suspending current thread and running t next.
void SoftXMT_suspend_wake( thread * t );

/// Join on thread t
void SoftXMT_join( thread * t );

/// TODO: remove this
void SoftXMT_signal_done();

#endif
<commit_msg>Commented out remote_spawn (templating fn ptr probs)<commit_after>
#ifndef __SOFTXMT_HPP__
#define __SOFTXMT_HPP__

#include <gflags/gflags.h>
#include <glog/logging.h>

#include "Communicator.hpp"
#include "Aggregator.hpp"

#include "thread.h"

void SoftXMT_init( int * argc_p, char ** argv_p[] );
void SoftXMT_activate();

bool SoftXMT_done();
void SoftXMT_finish( int retval );

Node SoftXMT_nodes();
Node SoftXMT_mynode();

void SoftXMT_poll();
void SoftXMT_flush( Node n );

void SoftXMT_barrier();

void SoftXMT_barrier_commsafe();

/// Spawn and run user main function. TODO: get return values working
/// TODO: remove thread * arg
int SoftXMT_run_user_main( void (* fn_p)(thread *, void *), void * args );

/// Spawn a user function. TODO: get return values working
/// TODO: remove thread * arg
thread * SoftXMT_spawn( void (* fn_p)(thread *, void *), void * args );

template< typename T >
thread * SoftXMT_template_spawn( void (* fn_p)(thread *, T *), T * args )
{
  typedef void (* fn_t)(thread *, void *);

  thread * th = SoftXMT_spawn( (fn_t)fn_p, (void *)args );
  DVLOG(5) << "Spawned thread " << th;
  return th;
}

// I'm not sure that this is even possible (unable to resolve templated function pointer)... commenting out for now...
///// Active message for spawning a thread on a remote node (used by SoftXMT_remote_spawn())
//template< typename T >
//static void am_remote_spawn(T* args, size_t args_size, void* payload, size_t payload_size) {
//  typedef void (*thread_fn)(thread*,T*);
//  void (*fn_p)(thread*,T*) = static_cast<thread_fn>(payload);
//  T* aa = new T;
//  *aa = *args;
//  SoftXMT_template_spawn(&fn_p, aa);
//}
//
///// Spawn a user thread on a remote node. Copies the passed arguments
///// to the remote node.
///// Note: the thread function should take ownership of the arguments
///// and clean them up at the end of the function call.
//template< typename T >
//void SoftXMT_remote_spawn( void (*fn_p)(thread*,T*), const T* args, Node target) {
//  SoftXMT_call_on(target, &am_remote_spawn<T>, args, sizeof(T), fn_p, sizeof(fn_p));
//}

/// Yield to scheduler, placing current thread on run queue.
void SoftXMT_yield( );

/// Yield to scheduler, suspending current thread.
void SoftXMT_suspend( );

/// Wake a thread by putting it on the run queue, leaving the current thread running.
void SoftXMT_wake( thread * t );

/// Wake a thread t by placing current thread on run queue and running t next.
void SoftXMT_yield_wake( thread * t );

/// Wake a thread t by suspending current thread and running t next.
void SoftXMT_suspend_wake( thread * t );

/// Join on thread t
void SoftXMT_join( thread * t );

/// TODO: remove this
void SoftXMT_signal_done();

#endif
<|endoftext|>