<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011-2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <list>

#include "Type.hpp"
#include "FunctionContext.hpp"
#include "GlobalContext.hpp"
#include "Variable.hpp"

#include "mtac/DeadCodeElimination.hpp"
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/LiveVariableAnalysisProblem.hpp"
#include "mtac/Utils.hpp"
#include "mtac/Offset.hpp"
#include "mtac/Statement.hpp"

#include "ltac/Statement.hpp"

using namespace eddic;

bool mtac::dead_code_elimination::operator()(mtac::function_p function){
    bool optimized = false;

    mtac::LiveVariableAnalysisProblem problem;
    auto results = mtac::data_flow(function, problem);

    for(auto& block : function){
        auto it = iterate(block->statements);

        while(it.has_next()){
            auto statement = *it;

            if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&statement)){
                if(mtac::erase_result((*ptr)->op)){
                    if(results->OUT_S[statement].values().find((*ptr)->result) == results->OUT_S[statement].values().end()){
                        it.erase();
                        optimized=true;
                        continue;
                    }
                }
            }

            ++it;
        }
    }

    std::unordered_set<Offset, mtac::OffsetHash> used_offsets;

    for(auto& block : function){
        for(auto& statement : block->statements){
            if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&statement)){
                auto quadruple = *ptr;

                if(quadruple->op == mtac::Operator::DOT || quadruple->op == mtac::Operator::FDOT || quadruple->op == mtac::Operator::PDOT){
                    if(auto* var_ptr = boost::get<std::shared_ptr<Variable>>(&*quadruple->arg1)){
                        if(auto* offset_ptr = boost::get<int>(&*quadruple->arg2)){
                            mtac::Offset offset(*var_ptr, *offset_ptr);
                            used_offsets.insert(offset);
                        }
                    }
                }
            }
        }
    }

    for(auto& block : function){
        auto it = block->statements.begin();
        auto end = block->statements.end();

        while(it != end){
            auto statement = *it;

            if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&statement)){
                auto quadruple = *ptr;

                if(quadruple->op == mtac::Operator::DOT_ASSIGN || quadruple->op == mtac::Operator::DOT_FASSIGN || quadruple->op == mtac::Operator::DOT_PASSIGN){
                    //Arrays are a problem because they are not considered as escaped after being passed in parameters
                    if(!quadruple->result->type()->is_pointer() && !quadruple->result->type()->is_array()){
                        if(auto* offset_ptr = boost::get<int>(&*quadruple->arg1)){
                            if(quadruple->result->type()->is_custom_type() || quadruple->result->type()->is_template()){
                                auto struct_type = function->context->global()->get_struct(quadruple->result->type()->mangle());
                                auto member_type = function->context->global()->member_type(struct_type, *offset_ptr);

                                if(member_type->is_pointer()){
                                    ++it;
                                    continue;
                                }
                            }

                            mtac::Offset offset(quadruple->result, *offset_ptr);

                            if(problem.pointer_escaped->find(quadruple->result) == problem.pointer_escaped->end() && used_offsets.find(offset) == used_offsets.end()){
                                it = block->statements.erase(it);
                                end = block->statements.end();
                                optimized=true;
                                continue;
                            }
                        }
                    }
                }
            }

            ++it;
        }
    }

    return optimized;
}
<commit_msg>Remove as much Dead Code as possible in one pass<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011-2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <list>

#include "Type.hpp"
#include "FunctionContext.hpp"
#include "GlobalContext.hpp"
#include "Variable.hpp"

#include "mtac/DeadCodeElimination.hpp"
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/LiveVariableAnalysisProblem.hpp"
#include "mtac/Utils.hpp"
#include "mtac/Offset.hpp"
#include "mtac/Statement.hpp"

#include "ltac/Statement.hpp"

using namespace eddic;

bool mtac::dead_code_elimination::operator()(mtac::function_p function){
    bool optimized_once = false;

    bool optimized;
    do {
        optimized = false;

        mtac::LiveVariableAnalysisProblem problem;
        auto results = mtac::data_flow(function, problem);

        for(auto& block : function){
            auto it = iterate(block->statements);

            while(it.has_next()){
                auto statement = *it;

                if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&statement)){
                    if(mtac::erase_result((*ptr)->op)){
                        if(results->OUT_S[statement].values().find((*ptr)->result) == results->OUT_S[statement].values().end()){
                            it.erase();
                            optimized_once = true;
                            optimized=true;
                            continue;
                        }
                    }
                }

                ++it;
            }
        }

        std::unordered_set<Offset, mtac::OffsetHash> used_offsets;

        for(auto& block : function){
            for(auto& statement : block->statements){
                if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&statement)){
                    auto quadruple = *ptr;

                    if(quadruple->op == mtac::Operator::DOT || quadruple->op == mtac::Operator::FDOT || quadruple->op == mtac::Operator::PDOT){
                        if(auto* var_ptr = boost::get<std::shared_ptr<Variable>>(&*quadruple->arg1)){
                            if(auto* offset_ptr = boost::get<int>(&*quadruple->arg2)){
                                mtac::Offset offset(*var_ptr, *offset_ptr);
                                used_offsets.insert(offset);
                            }
                        }
                    }
                }
            }
        }

        for(auto& block : function){
            auto it = block->statements.begin();
            auto end = block->statements.end();

            while(it != end){
                auto statement = *it;

                if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&statement)){
                    auto quadruple = *ptr;

                    if(quadruple->op == mtac::Operator::DOT_ASSIGN || quadruple->op == mtac::Operator::DOT_FASSIGN || quadruple->op == mtac::Operator::DOT_PASSIGN){
                        //Arrays are a problem because they are not considered as escaped after being passed in parameters
                        if(!quadruple->result->type()->is_pointer() && !quadruple->result->type()->is_array()){
                            if(auto* offset_ptr = boost::get<int>(&*quadruple->arg1)){
                                if(quadruple->result->type()->is_custom_type() || quadruple->result->type()->is_template()){
                                    auto struct_type = function->context->global()->get_struct(quadruple->result->type()->mangle());
                                    auto member_type = function->context->global()->member_type(struct_type, *offset_ptr);

                                    if(member_type->is_pointer()){
                                        ++it;
                                        continue;
                                    }
                                }

                                mtac::Offset offset(quadruple->result, *offset_ptr);

                                if(problem.pointer_escaped->find(quadruple->result) == problem.pointer_escaped->end() && used_offsets.find(offset) == used_offsets.end()){
                                    it = block->statements.erase(it);
                                    end = block->statements.end();
                                    optimized=true;
                                    optimized_once = true;
                                    continue;
                                }
                            }
                        }
                    }
                }

                ++it;
            }
        }
    } while(optimized);

    return optimized_once;
}
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2013, Balazs Racz
 * 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.
 *
 * 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 HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file WriteFlow.hxx
 *
 * Class that allows enqueing an outgoing message.
 *
 * @author Balazs Racz
 * @date 3 Nov 2013
 */

#ifndef _NMRAnetWriteFlow_hxx_
#define _NMRAnetWriteFlow_hxx_

#include "nmranet_config.h"
#include "executor/executor.hxx"
#include "executor/notifiable.hxx"

#include "utils/BufferQueue.hxx"
#include "nmranet/NMRAnetNode.hxx"

namespace NMRAnet
{

Executor* DefaultWriteFlowExecutor();

class WriteHelper : private Executable
{
public:
    static NodeHandle global()
    {
        return {0, 0};
    }

    WriteHelper(Executor* executor)
        : done_(nullptr),
          executor_(executor)
    {
    }

    /** Originales an NMRAnet message from a particular node.
     *
     * @param node is the originating node.
     * @param mti is the message to send
     * @param dst is the destination node to send to (may be Global())
     * @param buffer is the message payload.
     * @param done will be notified when the packet has been enqueued to the
     * physical layer. If done == nullptr, the sending is invoked synchronously.
     */
    void write_async(Node *node, If::MTI mti, NodeHandle dst,
                     Buffer *buffer, Notifiable* done)
    {
        HASSERT(!done_);
        node_ = node;
        mti_ = mti;
        dst_ = dst;
        buffer_ = buffer;
        if (done)
        {
            done_ = done;
            executor_->Add(this);
        }
        else
        {
            done_ = nullptr;
            Run();
        }
    }

private:
    /** Callback in the executor thread.
     */
    virtual void Run();

    Node *node_;
    If::MTI mti_;
    NodeHandle dst_;
    Buffer *buffer_;
    Notifiable* done_;
    Executor* executor_;
};

Buffer *EventIdToBuffer(uint64_t eventid);

}; /* namespace NMRAnet */

#endif  /* _NMRAnetWriteFlow_hxx_ */
<commit_msg>fix typo<commit_after>/** \copyright
 * Copyright (c) 2013, Balazs Racz
 * 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.
 *
 * 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 HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file WriteFlow.hxx
 *
 * Class that allows enqueing an outgoing message.
 *
 * @author Balazs Racz
 * @date 3 Nov 2013
 */

#ifndef _NMRAnetWriteFlow_hxx_
#define _NMRAnetWriteFlow_hxx_

#include "nmranet_config.h"
#include "executor/executor.hxx"
#include "executor/notifiable.hxx"

#include "utils/BufferQueue.hxx"
#include "nmranet/NMRAnetNode.hxx"

namespace NMRAnet
{

Executor* DefaultWriteFlowExecutor();

class WriteHelper : private Executable
{
public:
    static NodeHandle global()
    {
        return {0, 0};
    }

    WriteHelper(Executor* executor)
        : done_(nullptr),
          executor_(executor)
    {
    }

    /** Originates an NMRAnet message from a particular node.
     *
     * @param node is the originating node.
     * @param mti is the message to send
     * @param dst is the destination node to send to (may be Global())
     * @param buffer is the message payload.
     * @param done will be notified when the packet has been enqueued to the
     * physical layer. If done == nullptr, the sending is invoked synchronously.
     */
    void write_async(Node *node, If::MTI mti, NodeHandle dst,
                     Buffer *buffer, Notifiable* done)
    {
        HASSERT(!done_);
        node_ = node;
        mti_ = mti;
        dst_ = dst;
        buffer_ = buffer;
        if (done)
        {
            done_ = done;
            executor_->Add(this);
        }
        else
        {
            done_ = nullptr;
            Run();
        }
    }

private:
    /** Callback in the executor thread.
     */
    virtual void Run();

    Node *node_;
    If::MTI mti_;
    NodeHandle dst_;
    Buffer *buffer_;
    Notifiable* done_;
    Executor* executor_;
};

Buffer *EventIdToBuffer(uint64_t eventid);

}; /* namespace NMRAnet */

#endif  /* _NMRAnetWriteFlow_hxx_ */
<|endoftext|>


<commit_before>// This code is in the public domain -- castanyo@yahoo.es

#include <nvmath/SphericalHarmonic.h>

using namespace nv;

namespace
{

	// Basic integer factorial.
	inline static int factorial( int v )
	{
		const static int fac_table[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800 };

		if(v <= 11){
			return fac_table[v];
		}

		int result = v;
		while (--v > 0) {
			result *= v;
		}
		return result;
	}

	// Double factorial.
	// Defined as: n!! = n*(n - 2)*(n - 4)..., n!!(0,-1) = 1.
	inline static int doubleFactorial( int x )
	{
		if (x == 0 || x == -1) {
			return 1;
		}

		int result = x;
		while ((x -= 2) > 0) {
			result *= x;
		}

		return result;
	}

	/// Normalization constant for spherical harmonic.
	/// @param l is the band.
	/// @param m is the argument, in the range [0, m]
	inline static float K( int l, int m )
	{
		nvDebugCheck( m >= 0 );
		return sqrtf(((2 * l + 1) * factorial(l - m)) / (4 * PI * factorial(l + m)));
	}

	/// Normalization constant for hemispherical harmonic.
	inline static float HK( int l, int m )
	{
		nvDebugCheck( m >= 0 );
		return sqrtf(((2 * l + 1) * factorial(l - m)) / (2 * PI * factorial(l + m)));
	}

	/// Evaluate Legendre polynomial. */
	static float legendre( int l, int m, float x )
	{
	//	piDebugCheck( m >= 0 );
	//	piDebugCheck( m <= l );
	//	piDebugCheck( fabs(x) <= 1 );

		// Rule 2 needs no previous results
		if (l == m) {
			return powf(-1.0f, float(m)) * doubleFactorial(2 * m - 1) * powf(1 - x*x, 0.5f * m);
		}

		// Rule 3 requires the result for the same argument of the previous band
		if (l == m + 1) {
			return x * (2 * m + 1) * legendrePolynomial(m, m, x);
		}

		// Main reccurence used by rule 1 that uses result of the same argument from
		// the previous two bands
		return (x * (2 * l - 1) * legendrePolynomial(l - 1, m, x) - (l + m - 1) * legendrePolynomial(l - 2, m, x)) / (l - m);
	}

	template <int l, int m> float legendre(float x);

	template <> float legendre<0, 0>(float x) {
		return 1;
	}

	template <> float legendre<1, 0>(float x) {
		return x;
	}
	template <> float legendre<1, 1>(float x) {
		return -sqrtf(1 - x * x);
	}

	template <> float legendre<2, 0>(float x) {
		return -0.5f + (3 * x * x) / 2;
	}
	template <> float legendre<2, 1>(float x) {
		return -3 * x * sqrtf(1 - x * x);
	}
	template <> float legendre<2, 2>(float x) {
		return -3 * (-1 + x * x);
	}

	template <> float legendre<3, 0>(float x) {
		return -(3 * x) / 2 + (5 * x * x * x) / 2;
	}
	template <> float legendre<3, 1>(float x) {
		return -3 * sqrtf(1 - x * x) / 2 * (-1 + 5 * x * x);
	}
	template <> float legendre<3, 2>(float x) {
		return -15 * (-x + x * x * x);
	}
	template <> float legendre<3, 3>(float x) {
		return -15 * powf(1 - x * x, 1.5f);
	}

	template <> float legendre<4, 0>(float x) {
		return 0.125f * (3.0f - 30.0f * x * x + 35.0f * x * x * x * x);
	}
	template <> float legendre<4, 1>(float x) {
		return -2.5f * x * sqrtf(1.0f - x * x) * (7.0f * x * x - 3.0f);
	}
	template <> float legendre<4, 2>(float x) {
		return -7.5f * (1.0f - 8.0f * x * x + 7.0f * x * x * x * x);
	}
	template <> float legendre<4, 3>(float x) {
		return -105.0f * x * powf(1 - x * x, 1.5f);
	}
	template <> float legendre<4, 4>(float x) {
		return 105.0f * (x * x - 1.0f) * (x * x - 1.0f);
	}

} // namespace

float nv::legendrePolynomial(int l, int m, float x)
{
	switch(l)
	{
		case 0:
			return legendre<0, 0>(x);
		case 1:
			if(m == 0) return legendre<1, 0>(x);
			return legendre<1, 1>(x);
		case 2:
			if(m == 0) return legendre<2, 0>(x);
			else if(m == 1) return legendre<2, 1>(x);
			return legendre<2, 2>(x);
		case 3:
			if(m == 0) return legendre<3, 0>(x);
			else if(m == 1) return legendre<3, 1>(x);
			else if(m == 2) return legendre<3, 2>(x);
			return legendre<3, 3>(x);
		case 4:
			if(m == 0) return legendre<4, 0>(x);
			else if(m == 1) return legendre<4, 1>(x);
			else if(m == 2) return legendre<4, 2>(x);
			else if(m == 3) return legendre<4, 3>(x);
			else return legendre<4, 4>(x);
	}

	// Fallback to the expensive version.
	return legendre(l, m, x);
}

/**
 * Evaluate the spherical harmonic function for the given angles.
 * @param l is the band.
 * @param m is the argument, in the range [-l,l]
 * @param theta is the altitude, in the range [0, PI]
 * @param phi is the azimuth, in the range [0, 2*PI]
 */
float nv::y( int l, int m, float theta, float phi )
{
	if( m == 0 ) {
		// K(l, 0) = sqrt((2*l+1)/(4*PI))
		return sqrtf((2 * l + 1) / (4 * PI)) * legendrePolynomial(l, 0, cosf(theta));
	}
	else if( m > 0 ) {
		return sqrtf(2.0f) * K(l, m) * cosf(m * phi) * legendrePolynomial(l, m, cosf(theta));
	}
	else {
		return sqrtf(2.0f) * K(l, -m) * sinf(-m * phi) * legendrePolynomial(l, -m, cosf(theta));
	}
}

/**
 * Real spherical harmonic function of an unit vector. Uses the following
 * equalities to call the angular function:
 * x = sin(theta)*cos(phi)
 * y = sin(theta)*sin(phi)
 * z = cos(theta)
 */
float nv::y( int l, int m, Vector3::Arg v )
{
	float theta = acosf(v.z());
	float phi = atan2f(v.y(), v.x());
	return y( l, m, theta, phi );
}

/**
 * Evaluate the hemispherical harmonic function for the given angles.
 * @param l is the band.
 * @param m is the argument, in the range [-l,l]
 * @param theta is the altitude, in the range [0, PI/2]
 * @param phi is the azimuth, in the range [0, 2*PI]
 */
float nv::hy( int l, int m, float theta, float phi )
{
	if( m == 0 ) {
		// HK(l, 0) = sqrt((2*l+1)/(2*PI))
		return sqrtf((2 * l + 1) / (2 * PI)) * legendrePolynomial(l, 0, 2*cosf(theta)-1);
	}
	else if( m > 0 ) {
		return sqrtf(2.0f) * HK(l, m) * cosf(m * phi) * legendrePolynomial(l, m, 2*cosf(theta)-1);
	}
	else {
		return sqrtf(2.0f) * HK(l, -m) * sinf(-m * phi) * legendrePolynomial(l, -m, 2*cosf(theta)-1);
	}
}

/**
 * Real hemispherical harmonic function of an unit vector. Uses the following
 * equalities to call the angular function:
 * x = sin(theta)*cos(phi)
 * y = sin(theta)*sin(phi)
 * z = cos(theta)
 */
float nv::hy( int l, int m, Vector3::Arg v )
{
	float theta = acosf(v.z());
	float phi = atan2f(v.y(), v.x());
	return y( l, m, theta, phi );
}

<commit_msg>Remove gcc-4.3 warning.<commit_after>// This code is in the public domain -- castanyo@yahoo.es

#include <nvmath/SphericalHarmonic.h>

using namespace nv;

namespace
{

	// Basic integer factorial.
	inline static int factorial( int v )
	{
		const static int fac_table[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800 };

		if(v <= 11){
			return fac_table[v];
		}

		int result = v;
		while (--v > 0) {
			result *= v;
		}
		return result;
	}

	// Double factorial.
	// Defined as: n!! = n*(n - 2)*(n - 4)..., n!!(0,-1) = 1.
	inline static int doubleFactorial( int x )
	{
		if (x == 0 || x == -1) {
			return 1;
		}

		int result = x;
		while ((x -= 2) > 0) {
			result *= x;
		}

		return result;
	}

	/// Normalization constant for spherical harmonic.
	/// @param l is the band.
	/// @param m is the argument, in the range [0, m]
	inline static float K( int l, int m )
	{
		nvDebugCheck( m >= 0 );
		return sqrtf(((2 * l + 1) * factorial(l - m)) / (4 * PI * factorial(l + m)));
	}

	/// Normalization constant for hemispherical harmonic.
	inline static float HK( int l, int m )
	{
		nvDebugCheck( m >= 0 );
		return sqrtf(((2 * l + 1) * factorial(l - m)) / (2 * PI * factorial(l + m)));
	}

	/// Evaluate Legendre polynomial. */
	static float legendre( int l, int m, float x )
	{
	//	piDebugCheck( m >= 0 );
	//	piDebugCheck( m <= l );
	//	piDebugCheck( fabs(x) <= 1 );

		// Rule 2 needs no previous results
		if (l == m) {
			return powf(-1.0f, float(m)) * doubleFactorial(2 * m - 1) * powf(1 - x*x, 0.5f * m);
		}

		// Rule 3 requires the result for the same argument of the previous band
		if (l == m + 1) {
			return x * (2 * m + 1) * legendrePolynomial(m, m, x);
		}

		// Main reccurence used by rule 1 that uses result of the same argument from
		// the previous two bands
		return (x * (2 * l - 1) * legendrePolynomial(l - 1, m, x) - (l + m - 1) * legendrePolynomial(l - 2, m, x)) / (l - m);
	}

	template <int l, int m> float legendre(float x);

	template <> float legendre<0, 0>(float ) {
		return 1;
	}

	template <> float legendre<1, 0>(float x) {
		return x;
	}
	template <> float legendre<1, 1>(float x) {
		return -sqrtf(1 - x * x);
	}

	template <> float legendre<2, 0>(float x) {
		return -0.5f + (3 * x * x) / 2;
	}
	template <> float legendre<2, 1>(float x) {
		return -3 * x * sqrtf(1 - x * x);
	}
	template <> float legendre<2, 2>(float x) {
		return -3 * (-1 + x * x);
	}

	template <> float legendre<3, 0>(float x) {
		return -(3 * x) / 2 + (5 * x * x * x) / 2;
	}
	template <> float legendre<3, 1>(float x) {
		return -3 * sqrtf(1 - x * x) / 2 * (-1 + 5 * x * x);
	}
	template <> float legendre<3, 2>(float x) {
		return -15 * (-x + x * x * x);
	}
	template <> float legendre<3, 3>(float x) {
		return -15 * powf(1 - x * x, 1.5f);
	}

	template <> float legendre<4, 0>(float x) {
		return 0.125f * (3.0f - 30.0f * x * x + 35.0f * x * x * x * x);
	}
	template <> float legendre<4, 1>(float x) {
		return -2.5f * x * sqrtf(1.0f - x * x) * (7.0f * x * x - 3.0f);
	}
	template <> float legendre<4, 2>(float x) {
		return -7.5f * (1.0f - 8.0f * x * x + 7.0f * x * x * x * x);
	}
	template <> float legendre<4, 3>(float x) {
		return -105.0f * x * powf(1 - x * x, 1.5f);
	}
	template <> float legendre<4, 4>(float x) {
		return 105.0f * (x * x - 1.0f) * (x * x - 1.0f);
	}

} // namespace

float nv::legendrePolynomial(int l, int m, float x)
{
	switch(l)
	{
		case 0:
			return legendre<0, 0>(x);
		case 1:
			if(m == 0) return legendre<1, 0>(x);
			return legendre<1, 1>(x);
		case 2:
			if(m == 0) return legendre<2, 0>(x);
			else if(m == 1) return legendre<2, 1>(x);
			return legendre<2, 2>(x);
		case 3:
			if(m == 0) return legendre<3, 0>(x);
			else if(m == 1) return legendre<3, 1>(x);
			else if(m == 2) return legendre<3, 2>(x);
			return legendre<3, 3>(x);
		case 4:
			if(m == 0) return legendre<4, 0>(x);
			else if(m == 1) return legendre<4, 1>(x);
			else if(m == 2) return legendre<4, 2>(x);
			else if(m == 3) return legendre<4, 3>(x);
			else return legendre<4, 4>(x);
	}

	// Fallback to the expensive version.
	return legendre(l, m, x);
}

/**
 * Evaluate the spherical harmonic function for the given angles.
 * @param l is the band.
 * @param m is the argument, in the range [-l,l]
 * @param theta is the altitude, in the range [0, PI]
 * @param phi is the azimuth, in the range [0, 2*PI]
 */
float nv::y( int l, int m, float theta, float phi )
{
	if( m == 0 ) {
		// K(l, 0) = sqrt((2*l+1)/(4*PI))
		return sqrtf((2 * l + 1) / (4 * PI)) * legendrePolynomial(l, 0, cosf(theta));
	}
	else if( m > 0 ) {
		return sqrtf(2.0f) * K(l, m) * cosf(m * phi) * legendrePolynomial(l, m, cosf(theta));
	}
	else {
		return sqrtf(2.0f) * K(l, -m) * sinf(-m * phi) * legendrePolynomial(l, -m, cosf(theta));
	}
}

/**
 * Real spherical harmonic function of an unit vector. Uses the following
 * equalities to call the angular function:
 * x = sin(theta)*cos(phi)
 * y = sin(theta)*sin(phi)
 * z = cos(theta)
 */
float nv::y( int l, int m, Vector3::Arg v )
{
	float theta = acosf(v.z());
	float phi = atan2f(v.y(), v.x());
	return y( l, m, theta, phi );
}

/**
 * Evaluate the hemispherical harmonic function for the given angles.
 * @param l is the band.
 * @param m is the argument, in the range [-l,l]
 * @param theta is the altitude, in the range [0, PI/2]
 * @param phi is the azimuth, in the range [0, 2*PI]
 */
float nv::hy( int l, int m, float theta, float phi )
{
	if( m == 0 ) {
		// HK(l, 0) = sqrt((2*l+1)/(2*PI))
		return sqrtf((2 * l + 1) / (2 * PI)) * legendrePolynomial(l, 0, 2*cosf(theta)-1);
	}
	else if( m > 0 ) {
		return sqrtf(2.0f) * HK(l, m) * cosf(m * phi) * legendrePolynomial(l, m, 2*cosf(theta)-1);
	}
	else {
		return sqrtf(2.0f) * HK(l, -m) * sinf(-m * phi) * legendrePolynomial(l, -m, 2*cosf(theta)-1);
	}
}

/**
 * Real hemispherical harmonic function of an unit vector. Uses the following
 * equalities to call the angular function:
 * x = sin(theta)*cos(phi)
 * y = sin(theta)*sin(phi)
 * z = cos(theta)
 */
float nv::hy( int l, int m, Vector3::Arg v )
{
	float theta = acosf(v.z());
	float phi = atan2f(v.y(), v.x());
	return y( l, m, theta, phi );
}

<|endoftext|>


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

#include "acpi.hpp"
#include "apic.hpp"
#include "apic_timer.hpp"
#include "gdt.hpp"
#include "pit.hpp"
#include "smp.hpp"
#include <kernel/irq_manager.hpp>
#include <kernel/pci_manager.hpp>
#include <kernel/os.hpp>
#include <hw/devices.hpp>
#include <info>
#define MYINFO(X,...) INFO("x86", X, ##__VA_ARGS__)

extern "C" uint16_t _cpu_sampling_freq_divider_;
extern "C" void* get_cpu_esp();
extern "C" void* get_cpu_ebp();

namespace tls {
  size_t get_tls_size();
  void   fill_tls_data(char*);
}
struct smp_table
{
  // thread self-pointer
  smp_table* tls_data;
  // per-cpu data
  int cpuid;
  int unused;
};

using namespace x86;
namespace x86 {
  void initialize_tls_for_smp();
}

void __platform_init()
{
  // read ACPI tables
  ACPI::init();

  // setup APIC, APIC timer, SMP etc.
  APIC::init();

  initialize_tls_for_smp();

  // enable fs/gs for local APIC
  initialize_gdt_for_cpu(APIC::get().get_id());

  // IDT manager: Interrupt and exception handlers
  IRQ_manager::init();

  // initialize and start registered APs found in ACPI-tables
#ifndef INCLUDEOS_SINGLE_THREADED
  x86::init_SMP();
#endif

  // enable interrupts
  MYINFO("Enabling interrupts");
  IRQ_manager::enable_interrupts();

  // Estimate CPU frequency
  MYINFO("Estimating CPU-frequency");
  INFO2("|");
  INFO2("+--(%d samples, %f sec. interval)", 18,
        (x86::PIT::FREQUENCY / _cpu_sampling_freq_divider_).count());
  INFO2("|");

  if (OS::cpu_freq().count() <= 0.0) {
    OS::cpu_mhz_ = MHz(PIT::get().estimate_CPU_frequency());
  }
  INFO2("+--> %f MHz", OS::cpu_freq().count());

  // Note: CPU freq must be known before we can start timer system
  // Initialize APIC timers and timer systems
  // Deferred call to Service::ready() when calibration is complete
  APIC_Timer::calibrate();

  // Initialize PCI devices
  PCI_manager::init();

  // Print registered devices
  hw::Devices::print_devices();
}

void __arch_enable_legacy_irq(uint8_t irq)
{
  APIC::enable_irq(irq);
}
void __arch_disable_legacy_irq(uint8_t irq)
{
  APIC::disable_irq(irq);
}

void __arch_poweroff()
{
  ACPI::shutdown();
  __builtin_unreachable();
}
void __arch_reboot()
{
  ACPI::reboot();
  __builtin_unreachable();
}

#include <malloc.h>
namespace x86
{
  constexpr size_t smp_table_aligned_size()
  {
    size_t size = sizeof(smp_table);
    if (size & 63) size += 64 - (size & 63);
    return size;
  }

  static std::vector<char*> tls_buffers;

  void initialize_tls_for_smp()
  {
    const size_t thread_size = tls::get_tls_size();
    const size_t total_size  = thread_size + smp_table_aligned_size();
    const size_t cpu_count = ACPI::get_cpus().size();

    char* buffer = (char*) memalign(64, total_size * cpu_count);
    tls_buffers.reserve(cpu_count);
    for (auto cpu = 0u; cpu < cpu_count; cpu++)
        tls_buffers.push_back(&buffer[total_size * cpu]);
  }

#ifdef ARCH_i686
  struct alignas(SMP_ALIGN) segtable
  {
    int cpuid;
    struct GDT gdt;
  };
  static std::array<segtable, SMP_MAX_CORES> gdtables;
#endif

  void initialize_gdt_for_cpu(int cpu_id)
  {
#ifdef ARCH_x86_64
    char* data = tls_buffers.at(cpu_id);
    // TLS data at front of buffer
    tls::fill_tls_data(data);
    // SMP control block after data
    const size_t thread_size = tls::get_tls_size();
    auto* table = (smp_table*) &data[thread_size];
    table->tls_data = table;
    table->cpuid    = cpu_id;
    GDT::set_fs(table); // TLS self-ptr in fs
    GDT::set_gs(&table->cpuid); // PER_CPU on gs
    __sync_synchronize();
    //for (int i = 0; i < 2; i++)
    //SMP_PRINT("fs: %p\n", (void*) CPU::read_msr(MSR_FS_BASE));

#else
    tlstables[id].tls_data = tls::get_tls_data(id);
    gdtables[id].cpuid = id;
    // initialize GDT for this core
    auto& gdt = gdtables.at(id).gdt;
    gdt.initialize();
    // create per-thread segment
    int gs = gdt.create_data(&tlstables[id], 1);
    // create PER-CPU segment
    int fs = gdt.create_data(&gdtables[id], 1);
    // load GDT and refresh segments
    GDT::reload_gdt(gdt);
    // enable per-cpu and per-thread
    GDT::set_fs(fs);
    GDT::set_gs(gs);

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

#include "acpi.hpp"
#include "apic.hpp"
#include "apic_timer.hpp"
#include "gdt.hpp"
#include "pit.hpp"
#include "smp.hpp"
#include <kernel/irq_manager.hpp>
#include <kernel/pci_manager.hpp>
#include <kernel/os.hpp>
#include <hw/devices.hpp>
#include <info>
#define MYINFO(X,...) INFO("x86", X, ##__VA_ARGS__)

extern "C" uint16_t _cpu_sampling_freq_divider_;
extern "C" void* get_cpu_esp();
extern "C" void* get_cpu_ebp();

namespace tls {
  size_t get_tls_size();
  void   fill_tls_data(char*);
}
struct smp_table
{
  // thread self-pointer
  smp_table* tls_data;
  // per-cpu data
  int cpuid;
  int unused;
};

using namespace x86;
namespace x86 {
  void initialize_tls_for_smp();
}

void __platform_init()
{
  // read ACPI tables
  ACPI::init();

  // setup APIC, APIC timer, SMP etc.
  APIC::init();

  initialize_tls_for_smp();

  // enable fs/gs for local APIC
  initialize_gdt_for_cpu(APIC::get().get_id());

  // IDT manager: Interrupt and exception handlers
  IRQ_manager::init();

  // initialize and start registered APs found in ACPI-tables
#ifndef INCLUDEOS_SINGLE_THREADED
  x86::init_SMP();
#endif

  // enable interrupts
  MYINFO("Enabling interrupts");
  IRQ_manager::enable_interrupts();

  // Estimate CPU frequency
  MYINFO("Estimating CPU-frequency");
  INFO2("|");
  INFO2("+--(%d samples, %f sec. interval)", 18,
        (x86::PIT::FREQUENCY / _cpu_sampling_freq_divider_).count());
  INFO2("|");

  if (OS::cpu_freq().count() <= 0.0) {
    OS::cpu_mhz_ = MHz(PIT::get().estimate_CPU_frequency());
  }
  INFO2("+--> %f MHz", OS::cpu_freq().count());

  // Note: CPU freq must be known before we can start timer system
  // Initialize APIC timers and timer systems
  // Deferred call to Service::ready() when calibration is complete
  APIC_Timer::calibrate();

  // Initialize PCI devices
  PCI_manager::init();

  // Print registered devices
  hw::Devices::print_devices();
}

void __arch_enable_legacy_irq(uint8_t irq)
{
  APIC::enable_irq(irq);
}
void __arch_disable_legacy_irq(uint8_t irq)
{
  APIC::disable_irq(irq);
}

void __arch_poweroff()
{
  ACPI::shutdown();
  __builtin_unreachable();
}
void __arch_reboot()
{
  ACPI::reboot();
  __builtin_unreachable();
}

#include <malloc.h>
namespace x86
{
  constexpr size_t smp_table_aligned_size()
  {
    size_t size = sizeof(smp_table);
    if (size & 63) size += 64 - (size & 63);
    return size;
  }

  static std::vector<char*> tls_buffers;

  void initialize_tls_for_smp()
  {
    const size_t thread_size = tls::get_tls_size();
    const size_t total_size  = thread_size + smp_table_aligned_size();
    const size_t cpu_count = ACPI::get_cpus().size();

    //printf("TLS buffers are %lu bytes, SMP table %lu bytes\n", total_size, smp_table_aligned_size());
    char* buffer = (char*) memalign(64, total_size * cpu_count);
    tls_buffers.reserve(cpu_count);
    for (auto cpu = 0u; cpu < cpu_count; cpu++)
        tls_buffers.push_back(&buffer[total_size * cpu]);
  }

#ifdef ARCH_i686
  struct alignas(SMP_ALIGN) segtable
  {
    int cpuid;
    struct GDT gdt;
  };
  static std::array<segtable, SMP_MAX_CORES> gdtables;
#endif

  void initialize_gdt_for_cpu(int cpu_id)
  {
    char* data = tls_buffers.at(cpu_id);
    // TLS data at front of buffer
    tls::fill_tls_data(data);
    // SMP control block after data
    const size_t thread_size = tls::get_tls_size();
    auto* table = (smp_table*) &data[thread_size];
    table->tls_data = table;
    table->cpuid    = cpu_id;
    // should be at least 8-byte aligned
    assert((((uintptr_t) table) & 7) == 0);
#ifdef ARCH_x86_64
    GDT::set_fs(table); // TLS self-ptr in fs
    GDT::set_gs(&table->cpuid); // PER_CPU on gs
    __sync_synchronize();
    //for (int i = 0; i < 2; i++)
    //SMP_PRINT("fs: %p\n", (void*) CPU::read_msr(MSR_FS_BASE));
#else
    gdtables[cpu_id].cpuid = cpu_id;
    // initialize GDT for this core
    auto& gdt = gdtables.at(cpu_id).gdt;
    gdt.initialize();
    // create PER-CPU segment
    int fs = gdt.create_data(&gdtables[cpu_id], 1);
    // create per-thread segment
    int gs = gdt.create_data(table, 1);
    // load GDT and refresh segments
    GDT::reload_gdt(gdt);
    // enable per-cpu and per-thread
    GDT::set_fs(fs);
    GDT::set_gs(gs);
    __sync_synchronize();
#endif
  }
} // x86
<|endoftext|>


<commit_before>#include <map>
#include <string>
#include <set>
#include <memory>
#include <utility>
#include <iostream>
#include <uv.h>

#include "../log.h"
#include "../message.h"
#include "../helper/common.h"
#include "polling_iterator.h"
#include "directory_record.h"

using std::string;
using std::set;
using std::endl;
using std::move;
using std::shared_ptr;

struct FSReq {
  uv_fs_t req;

  ~FSReq() {
    uv_fs_req_cleanup(&req);
  }
};

inline bool ts_less_than(const uv_timespec_t &left, const uv_timespec_t &right)
{
  return left.tv_sec < right.tv_sec ||
    (left.tv_sec == right.tv_sec && left.tv_nsec < right.tv_nsec);
}

inline EntryKind kind_from_stat(const uv_stat_t &st)
{
  if (st.st_flags & S_IFDIR) return KIND_DIRECTORY;
  if (st.st_flags & S_IFREG) return KIND_FILE;
  return KIND_UNKNOWN;
}

DirectoryRecord::DirectoryRecord(string &&name) :
  parent{nullptr},
  name{move(name)},
  populated{false}
{
  //
}

string DirectoryRecord::path()
{
  return parent == nullptr ? name : path_join(parent->path(), name);
}

void DirectoryRecord::scan(BoundPollingIterator *it)
{
  FSReq scan_req;
  set<string> scanned_entries;

  string dir = path();
  int scan_err = uv_fs_scandir(nullptr, &scan_req.req, dir.c_str(), 0, nullptr);
  if (scan_err != 0) {
    LOGGER << "Unable to scan directory " << dir << ": " << uv_strerror(scan_err) << "." << endl;
    return;
  }

  uv_dirent_t dirent;
  int next_err = uv_fs_scandir_next(&scan_req.req, &dirent);
  while (next_err == 0) {
    string entry_name(dirent.name);

    EntryKind entry_kind = KIND_UNKNOWN;
    if (dirent.type == UV_DIRENT_FILE) entry_kind = KIND_FILE;
    if (dirent.type == UV_DIRENT_DIR) entry_kind = KIND_DIRECTORY;

    it->push_entry(string(entry_name), entry_kind);
    scanned_entries.emplace(move(entry_name));

    next_err = uv_fs_scandir_next(&scan_req.req, &dirent);
  }

  if (next_err != UV_EOF) {
    LOGGER << "Unable to list entries in directory " << dir << ": " << uv_strerror(next_err) << "." << endl;
  }
}

void DirectoryRecord::entry(
  BoundPollingIterator *it,
  const string &entry_name,
  const string &entry_path,
  EntryKind scan_kind
) {
  FSReq lstat_req;
  EntryKind previous_kind = scan_kind;
  EntryKind current_kind = scan_kind;

  int lstat_err = uv_fs_lstat(nullptr, &lstat_req.req, entry_path.c_str(), nullptr);
  if (lstat_err != 0 && lstat_err != UV_ENOENT && lstat_err != UV_EACCES) {
    LOGGER << "Unable to stat " << entry_path << ": " << uv_strerror(lstat_err) << "." << endl;
  }

  auto previous = entries.find(entry_name);

  bool existed_before = previous != entries.end();
  bool exists_now = lstat_err == 0;

  if (existed_before) previous_kind = kind_from_stat(previous->second);
  if (exists_now) current_kind = kind_from_stat(lstat_req.req.statbuf);

  if (existed_before && exists_now) {
    // Modification or no change
    uv_stat_t &previous_stat = previous->second;
    uv_stat_t &current_stat = lstat_req.req.statbuf;

    // TODO consider modifications to mode or ownership bits?
    if (kinds_are_different(previous_kind, current_kind)) {
      entry_deleted(it, entry_path, previous_kind);
      entry_created(it, entry_path, current_kind);
    } else if (
      previous_stat.st_flags != current_stat.st_flags ||
      previous_stat.st_ino != current_stat.st_ino ||
      ts_less_than(previous_stat.st_mtim, current_stat.st_mtim) ||
      ts_less_than(previous_stat.st_ctim, current_stat.st_ctim)
    ) {
      entry_modified(it, entry_path, current_kind);
    }

  } else if (existed_before && !exists_now) {
    // Deletion

    entry_deleted(it, entry_path, previous_kind);

  } else if (!existed_before && exists_now) {
    // Creation

    if (kinds_are_different(scan_kind, current_kind)) {
      // Entry was created as a file, deleted, then recreated as a directory between scan() and entry()
      // (or vice versa)
      entry_created(it, entry_path, scan_kind);
      entry_deleted(it, entry_path, scan_kind);
    }
    entry_created(it, entry_path, current_kind);

  } else if (!existed_before && !exists_now) {
    // Entry was deleted between scan() and entry().
    // Emit a deletion and creation event pair. Note that the kinds will likely both be KIND_UNKNOWN.

    entry_created(it, entry_path, previous_kind);
    entry_deleted(it, entry_path, current_kind);

  }

  // Update entries with the latest stat information
  if (existed_before) entries.erase(previous);
  if (exists_now) entries.emplace(entry_name, lstat_req.req.statbuf);

  // Update subdirectories if this is or was a subdirectory
  auto dir = subdirectories.find(entry_name);
  if (current_kind != KIND_DIRECTORY && current_kind != KIND_UNKNOWN && dir != subdirectories.end()) {
    subdirectories.erase(dir);
  }
  if (current_kind == KIND_DIRECTORY) {
    if (dir == subdirectories.end()) {
      shared_ptr<DirectoryRecord> subdir(new DirectoryRecord(this, entry_name));
      subdirectories.emplace(entry_name, subdir);
      it->push_directory(subdir);
    } else {
      it->push_directory(dir->second);
    }
  }
}

void DirectoryRecord::entry_deleted(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().deleted(string(entry_path), kind);
}

void DirectoryRecord::entry_created(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().created(string(entry_path), kind);
}

void DirectoryRecord::entry_modified(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().modified(string(entry_path), kind);
}
<commit_msg>Emit deletion events for entries that are missing during scan<commit_after>#include <map>
#include <string>
#include <set>
#include <memory>
#include <utility>
#include <iostream>
#include <uv.h>

#include "../log.h"
#include "../message.h"
#include "../helper/common.h"
#include "polling_iterator.h"
#include "directory_record.h"

using std::string;
using std::set;
using std::endl;
using std::move;
using std::shared_ptr;

struct FSReq {
  uv_fs_t req;

  ~FSReq() {
    uv_fs_req_cleanup(&req);
  }
};

inline bool ts_less_than(const uv_timespec_t &left, const uv_timespec_t &right)
{
  return left.tv_sec < right.tv_sec ||
    (left.tv_sec == right.tv_sec && left.tv_nsec < right.tv_nsec);
}

inline EntryKind kind_from_stat(const uv_stat_t &st)
{
  if (st.st_flags & S_IFDIR) return KIND_DIRECTORY;
  if (st.st_flags & S_IFREG) return KIND_FILE;
  return KIND_UNKNOWN;
}

DirectoryRecord::DirectoryRecord(string &&name) :
  parent{nullptr},
  name{move(name)},
  populated{false}
{
  //
}

string DirectoryRecord::path()
{
  return parent == nullptr ? name : path_join(parent->path(), name);
}

void DirectoryRecord::scan(BoundPollingIterator *it)
{
  FSReq scan_req;
  set<Entry> scanned_entries;

  string dir = path();
  int scan_err = uv_fs_scandir(nullptr, &scan_req.req, dir.c_str(), 0, nullptr);
  if (scan_err != 0) {
    LOGGER << "Unable to scan directory " << dir << ": " << uv_strerror(scan_err) << "." << endl;
    return;
  }

  uv_dirent_t dirent;
  int next_err = uv_fs_scandir_next(&scan_req.req, &dirent);
  while (next_err == 0) {
    string entry_name(dirent.name);

    EntryKind entry_kind = KIND_UNKNOWN;
    if (dirent.type == UV_DIRENT_FILE) entry_kind = KIND_FILE;
    if (dirent.type == UV_DIRENT_DIR) entry_kind = KIND_DIRECTORY;

    it->push_entry(string(entry_name), entry_kind);
    if (populated) scanned_entries.emplace(move(entry_name), entry_kind);

    next_err = uv_fs_scandir_next(&scan_req.req, &dirent);
  }

  if (next_err != UV_EOF) {
    LOGGER << "Unable to list entries in directory " << dir << ": " << uv_strerror(next_err) << "." << endl;
  } else {
    // Report entries that were present the last time we scanned this directory, but aren't included in this
    // scan.
    for (auto &previous : entries) {
      const string &previous_entry_name = previous.first;
      EntryKind previous_entry_kind = kind_from_stat(previous.second);
      Entry previous_entry(previous_entry_name, previous_entry_kind);

      if (scanned_entries.count(previous_entry) == 0) {
        entry_deleted(it, previous_entry_name, previous_entry_kind);
      }
    }
  }
}

void DirectoryRecord::entry(
  BoundPollingIterator *it,
  const string &entry_name,
  const string &entry_path,
  EntryKind scan_kind
) {
  FSReq lstat_req;
  EntryKind previous_kind = scan_kind;
  EntryKind current_kind = scan_kind;

  int lstat_err = uv_fs_lstat(nullptr, &lstat_req.req, entry_path.c_str(), nullptr);
  if (lstat_err != 0 && lstat_err != UV_ENOENT && lstat_err != UV_EACCES) {
    LOGGER << "Unable to stat " << entry_path << ": " << uv_strerror(lstat_err) << "." << endl;
  }

  auto previous = entries.find(entry_name);

  bool existed_before = previous != entries.end();
  bool exists_now = lstat_err == 0;

  if (existed_before) previous_kind = kind_from_stat(previous->second);
  if (exists_now) current_kind = kind_from_stat(lstat_req.req.statbuf);

  if (existed_before && exists_now) {
    // Modification or no change
    uv_stat_t &previous_stat = previous->second;
    uv_stat_t &current_stat = lstat_req.req.statbuf;

    // TODO consider modifications to mode or ownership bits?
    if (kinds_are_different(previous_kind, current_kind)) {
      entry_deleted(it, entry_path, previous_kind);
      entry_created(it, entry_path, current_kind);
    } else if (
      previous_stat.st_flags != current_stat.st_flags ||
      previous_stat.st_ino != current_stat.st_ino ||
      ts_less_than(previous_stat.st_mtim, current_stat.st_mtim) ||
      ts_less_than(previous_stat.st_ctim, current_stat.st_ctim)
    ) {
      entry_modified(it, entry_path, current_kind);
    }

  } else if (existed_before && !exists_now) {
    // Deletion

    entry_deleted(it, entry_path, previous_kind);

  } else if (!existed_before && exists_now) {
    // Creation

    if (kinds_are_different(scan_kind, current_kind)) {
      // Entry was created as a file, deleted, then recreated as a directory between scan() and entry()
      // (or vice versa)
      entry_created(it, entry_path, scan_kind);
      entry_deleted(it, entry_path, scan_kind);
    }
    entry_created(it, entry_path, current_kind);

  } else if (!existed_before && !exists_now) {
    // Entry was deleted between scan() and entry().
    // Emit a deletion and creation event pair. Note that the kinds will likely both be KIND_UNKNOWN.

    entry_created(it, entry_path, previous_kind);
    entry_deleted(it, entry_path, current_kind);

  }

  // Update entries with the latest stat information
  if (existed_before) entries.erase(previous);
  if (exists_now) entries.emplace(entry_name, lstat_req.req.statbuf);

  // Update subdirectories if this is or was a subdirectory
  auto dir = subdirectories.find(entry_name);
  if (current_kind != KIND_DIRECTORY && current_kind != KIND_UNKNOWN && dir != subdirectories.end()) {
    subdirectories.erase(dir);
  }
  if (current_kind == KIND_DIRECTORY) {
    if (dir == subdirectories.end()) {
      shared_ptr<DirectoryRecord> subdir(new DirectoryRecord(this, entry_name));
      subdirectories.emplace(entry_name, subdir);
      it->push_directory(subdir);
    } else {
      it->push_directory(dir->second);
    }
  }
}

void DirectoryRecord::entry_deleted(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().deleted(string(entry_path), kind);
}

void DirectoryRecord::entry_created(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().created(string(entry_path), kind);
}

void DirectoryRecord::entry_modified(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().modified(string(entry_path), kind);
}
<|endoftext|>


<commit_before>#include "handler_factory.h"

#include <string>

using namespace std;

namespace server
{

const static string alpn_protos_default[]
{
	"\x2h2",
	"\x5h2-16",
	"\x5h2-14",
	"\x8http/1.1",
	"\x8http/1.0"
};
const static string alpn_protos_legacy[]
{\
	"\x8http/1.1",
	"\x8http/1.0"
};

const static unsigned char npn_protos[]
{
	2,'h','2',
	5,'h','2','-','1','6',
	5,'h','2','-','1','4',
	8,'h','t','t','p','/','1','.','1',
	8,'h','t','t','p','/','1','.','0'
};

using alpn_cb = int (*)
(ssl_st*, const unsigned char**, unsigned char*, const unsigned char*, unsigned int, void*);

alpn_cb alpn_select_cb = [](ssl_st *ctx, const unsigned char** out, unsigned char* outlen,
const unsigned char* in, unsigned int inlen, void *data)
{
	for( auto& proto : alpn_protos_default )
		if(SSL_select_next_proto((unsigned char**)out, outlen, (const unsigned char*)proto.c_str(), proto.size()-1, in, inlen) == OPENSSL_NPN_NEGOTIATED)
			return SSL_TLSEXT_ERR_OK;

	return SSL_TLSEXT_ERR_NOACK;
};

using npn_cb = int (*) (SSL *ssl, const unsigned char** out, unsigned int* outlen, void *arg);
npn_cb npn_adv_cb = [](ssl_st *ctx, const unsigned char** out, unsigned int* outlen, void *arg)
{
	*out = npn_protos;
	*outlen = sizeof(npn_protos);
	return SSL_TLSEXT_ERR_OK;
};

void handler_factory::register_protocol_selection_callbacks(SSL_CTX* ctx)
{
	SSL_CTX_set_next_protos_advertised_cb(ctx, npn_adv_cb, nullptr);
	SSL_CTX_set_alpn_select_cb(ctx, alpn_select_cb, nullptr);
}

std::shared_ptr<http::server_connection> handler_factory::negotiate_handler(std::shared_ptr<ssl_socket> sck) const noexcept
{
	const unsigned char* proto{nullptr};
	unsigned int len{0};

	const SSL *ssl_handle = sck->native_handle();

	//ALPN
	SSL_get0_alpn_selected(ssl_handle, &proto, &len);
	if( !len )
		//NPN
		SSL_get0_next_proto_negotiated(ssl_handle, &proto, &len);

	handler_type type{handler_type::ht_h1};
	if( len )
	{
		LOGDEBUG("Protocol negotiated: ", std::string(reinterpret_cast<const char*>(proto), len));
		switch(len)
		{
		case 2:
		case 3:
		case 5:
			type = handler_type::ht_h2;
			break;
		}
	}

	http::proto_version version = (type == handler_type::ht_h2) ? http::proto_version::HTTP20 : ((proto == nullptr ||   proto[len-1] == '0') ? http::proto_version::HTTP10 : http::proto_version::HTTP11);

	return build_handler( type , version, sck);
}

} //namespace
<commit_msg>minor<commit_after>#include "handler_factory.h"

#include <string>

using namespace std;

namespace server
{

const static string alpn_protos_default[]
{
	"\x2h2",
	"\x5h2-16",
	"\x5h2-14",
	"\x8http/1.1",
	"\x8http/1.0"
};

const static unsigned char npn_protos[]
{
	2,'h','2',
	5,'h','2','-','1','6',
	5,'h','2','-','1','4',
	8,'h','t','t','p','/','1','.','1',
	8,'h','t','t','p','/','1','.','0'
};

using alpn_cb = int (*)
(ssl_st*, const unsigned char**, unsigned char*, const unsigned char*, unsigned int, void*);

alpn_cb alpn_select_cb = [](ssl_st *ctx, const unsigned char** out, unsigned char* outlen,
const unsigned char* in, unsigned int inlen, void *data)
{
	for( auto& proto : alpn_protos_default )
		if(SSL_select_next_proto((unsigned char**)out, outlen, (const unsigned char*)proto.c_str(), proto.size()-1, in, inlen) == OPENSSL_NPN_NEGOTIATED)
			return SSL_TLSEXT_ERR_OK;

	return SSL_TLSEXT_ERR_NOACK;
};

using npn_cb = int (*) (SSL *ssl, const unsigned char** out, unsigned int* outlen, void *arg);
npn_cb npn_adv_cb = [](ssl_st *ctx, const unsigned char** out, unsigned int* outlen, void *arg)
{
	*out = npn_protos;
	*outlen = sizeof(npn_protos);
	return SSL_TLSEXT_ERR_OK;
};

void handler_factory::register_protocol_selection_callbacks(SSL_CTX* ctx)
{
	SSL_CTX_set_next_protos_advertised_cb(ctx, npn_adv_cb, nullptr);
	SSL_CTX_set_alpn_select_cb(ctx, alpn_select_cb, nullptr);
}

std::shared_ptr<http::server_connection> handler_factory::negotiate_handler(std::shared_ptr<ssl_socket> sck) const noexcept
{
	const unsigned char* proto{nullptr};
	unsigned int len{0};

	const SSL *ssl_handle = sck->native_handle();

	//ALPN
	SSL_get0_alpn_selected(ssl_handle, &proto, &len);
	if( !len )
		//NPN
		SSL_get0_next_proto_negotiated(ssl_handle, &proto, &len);

	handler_type type{handler_type::ht_h1};
	if( len )
	{
		LOGDEBUG("Protocol negotiated: ", std::string(reinterpret_cast<const char*>(proto), len));
		switch(len)
		{
		case 2:
		case 3:
		case 5:
			type = handler_type::ht_h2;
			break;
		}
	}

	http::proto_version version = (type == handler_type::ht_h2) ? http::proto_version::HTTP20 : ((proto == nullptr ||   proto[len-1] == '0') ? http::proto_version::HTTP10 : http::proto_version::HTTP11);

	return build_handler( type , version, sck);
}

} //namespace
<|endoftext|>


<commit_before>/*******************************************************************************
 * This program 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 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 2015
 *******************************************************************************/

#include "drivers/BC417.hpp"

#include <global.hpp>
#include <errors.hpp>

void BC417::is_connected()
{
  rawcmd(CMD::AT, CMDMODE::RAW);
  if (!wait_for_reply(CMD::AT, AT_OK, REPLY_TIMEOUT))
  {
    THROW(ERROR_BC471_COMMTEST_FAILED);
  }
  else
  {
    THROW(ERROR_BC471_COMMTEST_OK);
  }
}

void BC417::set_name(const char *name)
{
  ok = false;
  rawcmd(CMD::NAME, CMDMODE::RAW, name);
  if (!wait_for_reply(CMD::AT, AT_OK, REPLY_TIMEOUT))
  {
    THROW(ERROR_BC471_SET_NAME_FAILED);
  }
  ok = true;
}

void BC417::set_pin(const char *pin)
{
  ok = false;
  rawcmd(CMD::PIN, CMDMODE::RAW, pin);
  if (!wait_for_reply(CMD::AT, AT_OK, REPLY_TIMEOUT))
  {
    THROW(ERROR_BC471_SET_PIN_FAILED);
  }
  ok = true;
}
<commit_msg>fixed Linux build<commit_after>/*******************************************************************************
 * This program 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 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 2015
 *******************************************************************************/

#include "drivers/bc417.hpp"

#include <global.hpp>
#include <errors.hpp>

void BC417::is_connected()
{
  rawcmd(CMD::AT, CMDMODE::RAW);
  if (!wait_for_reply(CMD::AT, AT_OK, REPLY_TIMEOUT))
  {
    THROW(ERROR_BC471_COMMTEST_FAILED);
  }
  else
  {
    THROW(ERROR_BC471_COMMTEST_OK);
  }
}

void BC417::set_name(const char *name)
{
  ok = false;
  rawcmd(CMD::NAME, CMDMODE::RAW, name);
  if (!wait_for_reply(CMD::AT, AT_OK, REPLY_TIMEOUT))
  {
    THROW(ERROR_BC471_SET_NAME_FAILED);
  }
  ok = true;
}

void BC417::set_pin(const char *pin)
{
  ok = false;
  rawcmd(CMD::PIN, CMDMODE::RAW, pin);
  if (!wait_for_reply(CMD::AT, AT_OK, REPLY_TIMEOUT))
  {
    THROW(ERROR_BC471_SET_PIN_FAILED);
  }
  ok = true;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <folly/Demangle.h>

#include <algorithm>
#include <cstring>

#include <folly/lang/CString.h>
#include <folly/portability/Config.h>

#if __has_include(<cxxabi.h>)
#include <cxxabi.h>
#endif

//  The headers <libiberty.h> (binutils) and <string.h> (glibc) both declare the
//  symbol basename. Unfortunately, the declarations are different. So including
//  both headers in the same translation unit fails due to the two conflicting
//  declarations. Since <demangle.h> includes <libiberty.h> we must be careful.
#if __has_include(<demangle.h>)
#pragma push_macro("HAVE_DECL_BASENAME")
#define HAVE_DECL_BASENAME 1
#include <demangle.h> // @manual
#pragma pop_macro("HAVE_DECL_BASENAME")
#endif

//  try to find cxxabi demangle
//
//  prefer using a weak symbol

#if FOLLY_HAVE_WEAK_SYMBOLS

namespace __cxxabiv1 {
extern "C" FOLLY_ATTR_WEAK char* __cxa_demangle(
    char const*, char*, size_t*, int*);
}

static auto const cxxabi_demangle = __cxxabiv1::__cxa_demangle;

#else // FOLLY_HAVE_WEAK_SYMBOLS

static constexpr auto cxxabi_demangle = static_cast<char* (*)(...)>(nullptr);

#endif // FOLLY_HAVE_WEAK_SYMBOLS

//  try to find liberty demangle
//
//  cannot use a weak symbol since it may be the only referenced symbol in
//  liberty
//
//  in contrast with cxxabi, where there are certainly other referenced symbols

#if __has_include(<demangle.h>)

static constexpr auto liberty_demangle = cplus_demangle_v3_callback;

#if defined(DMGL_NO_RECURSE_LIMIT)
static constexpr auto liberty_demangle_options_no_recurse_limit =
    DMGL_NO_RECURSE_LIMIT;
#else
static constexpr auto liberty_demangle_options_no_recurse_limit = 0;
#endif

static constexpr auto liberty_demangle_options = //
    DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES | //
    liberty_demangle_options_no_recurse_limit;

#else // __has_include(<demangle.h>)

static constexpr auto liberty_demangle = static_cast<int (*)(...)>(nullptr);
static constexpr auto liberty_demangle_options = 0;

#endif // __has_include(<demangle.h>)

//  implementations

namespace folly {

//  reinterpret-cast currently evades -Waddress
bool const demangle_build_has_cxxabi = cxxabi_demangle;
bool const demangle_build_has_liberty =
    reinterpret_cast<void*>(liberty_demangle);

fbstring demangle(const char* name) {
  if (!name) {
    return fbstring();
  }

  if (demangle_max_symbol_size) {
    // GCC's __cxa_demangle() uses on-stack data structures for the
    // parser state which are linear in the number of components of the
    // symbol. For extremely long symbols, this can cause a stack
    // overflow. We set an arbitrary symbol length limit above which we
    // just return the mangled name.
    size_t mangledLen = strlen(name);
    if (mangledLen > demangle_max_symbol_size) {
      return fbstring(name, mangledLen);
    }
  }

  if (cxxabi_demangle) {
    int status;
    size_t len = 0;
    // malloc() memory for the demangled type name
    char* demangled = cxxabi_demangle(name, nullptr, &len, &status);
    if (status != 0) {
      return name;
    }
    // len is the length of the buffer (including NUL terminator and maybe
    // other junk)
    return fbstring(
        demangled, strlen(demangled), len, AcquireMallocatedString());
  } else {
    return fbstring(name);
  }
}

namespace {

struct DemangleBuf {
  char* dest;
  size_t remaining;
  size_t total;
};

void demangleCallback(const char* str, size_t size, void* p) {
  DemangleBuf* buf = static_cast<DemangleBuf*>(p);
  size_t n = std::min(buf->remaining, size);
  memcpy(buf->dest, str, n);
  buf->dest += n;
  buf->remaining -= n;
  buf->total += size;
}

} // namespace

size_t demangle(const char* name, char* out, size_t outSize) {
  if (demangle_max_symbol_size) {
    size_t mangledLen = strlen(name);
    if (mangledLen > demangle_max_symbol_size) {
      if (outSize) {
        size_t n = std::min(mangledLen, outSize - 1);
        memcpy(out, name, n);
        out[n] = '\0';
      }
      return mangledLen;
    }
  }

  if (reinterpret_cast<void*>(liberty_demangle)) {
    DemangleBuf dbuf;
    dbuf.dest = out;
    dbuf.remaining = outSize ? outSize - 1 : 0; // leave room for null term
    dbuf.total = 0;

    // Unlike most library functions, this returns 1 on success and 0 on failure
    int status = liberty_demangle(
        name, liberty_demangle_options, demangleCallback, &dbuf);
    if (status == 0) { // failed, return original
      return folly::strlcpy(out, name, outSize);
    }
    if (outSize != 0) {
      *dbuf.dest = '\0';
    }
    return dbuf.total;
  } else {
    return folly::strlcpy(out, name, outSize);
  }
}

} // namespace folly
<commit_msg>use weakref for cxxabi demangle<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <folly/Demangle.h>

#include <algorithm>
#include <cstring>

#include <folly/lang/CString.h>

#if __has_include(<cxxabi.h>)
#include <cxxabi.h>
#endif

//  The headers <libiberty.h> (binutils) and <string.h> (glibc) both declare the
//  symbol basename. Unfortunately, the declarations are different. So including
//  both headers in the same translation unit fails due to the two conflicting
//  declarations. Since <demangle.h> includes <libiberty.h> we must be careful.
#if __has_include(<demangle.h>)
#pragma push_macro("HAVE_DECL_BASENAME")
#define HAVE_DECL_BASENAME 1
#include <demangle.h> // @manual
#pragma pop_macro("HAVE_DECL_BASENAME")
#endif

//  try to find cxxabi demangle
//
//  prefer using a weakref

#if __has_include(<cxxabi.h>)

[[gnu::weakref("__cxa_demangle")]] static char* cxxabi_demangle(
    char const*, char*, size_t*, int*);

#else // __has_include(<cxxabi.h>)

static constexpr auto cxxabi_demangle = static_cast<char* (*)(...)>(nullptr);

#endif // __has_include(<cxxabi.h>)

//  try to find liberty demangle
//
//  cannot use a weak symbol since it may be the only referenced symbol in
//  liberty
//
//  in contrast with cxxabi, where there are certainly other referenced symbols

#if __has_include(<demangle.h>)

static constexpr auto liberty_demangle = cplus_demangle_v3_callback;

#if defined(DMGL_NO_RECURSE_LIMIT)
static constexpr auto liberty_demangle_options_no_recurse_limit =
    DMGL_NO_RECURSE_LIMIT;
#else
static constexpr auto liberty_demangle_options_no_recurse_limit = 0;
#endif

static constexpr auto liberty_demangle_options = //
    DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES | //
    liberty_demangle_options_no_recurse_limit;

#else // __has_include(<demangle.h>)

static constexpr auto liberty_demangle = static_cast<int (*)(...)>(nullptr);
static constexpr auto liberty_demangle_options = 0;

#endif // __has_include(<demangle.h>)

//  implementations

namespace folly {

//  reinterpret-cast currently evades -Waddress
bool const demangle_build_has_cxxabi = cxxabi_demangle;
bool const demangle_build_has_liberty =
    reinterpret_cast<void*>(liberty_demangle);

fbstring demangle(const char* name) {
  if (!name) {
    return fbstring();
  }

  if (demangle_max_symbol_size) {
    // GCC's __cxa_demangle() uses on-stack data structures for the
    // parser state which are linear in the number of components of the
    // symbol. For extremely long symbols, this can cause a stack
    // overflow. We set an arbitrary symbol length limit above which we
    // just return the mangled name.
    size_t mangledLen = strlen(name);
    if (mangledLen > demangle_max_symbol_size) {
      return fbstring(name, mangledLen);
    }
  }

  if (cxxabi_demangle) {
    int status;
    size_t len = 0;
    // malloc() memory for the demangled type name
    char* demangled = cxxabi_demangle(name, nullptr, &len, &status);
    if (status != 0) {
      return name;
    }
    // len is the length of the buffer (including NUL terminator and maybe
    // other junk)
    return fbstring(
        demangled, strlen(demangled), len, AcquireMallocatedString());
  } else {
    return fbstring(name);
  }
}

namespace {

struct DemangleBuf {
  char* dest;
  size_t remaining;
  size_t total;
};

void demangleCallback(const char* str, size_t size, void* p) {
  DemangleBuf* buf = static_cast<DemangleBuf*>(p);
  size_t n = std::min(buf->remaining, size);
  memcpy(buf->dest, str, n);
  buf->dest += n;
  buf->remaining -= n;
  buf->total += size;
}

} // namespace

size_t demangle(const char* name, char* out, size_t outSize) {
  if (demangle_max_symbol_size) {
    size_t mangledLen = strlen(name);
    if (mangledLen > demangle_max_symbol_size) {
      if (outSize) {
        size_t n = std::min(mangledLen, outSize - 1);
        memcpy(out, name, n);
        out[n] = '\0';
      }
      return mangledLen;
    }
  }

  if (reinterpret_cast<void*>(liberty_demangle)) {
    DemangleBuf dbuf;
    dbuf.dest = out;
    dbuf.remaining = outSize ? outSize - 1 : 0; // leave room for null term
    dbuf.total = 0;

    // Unlike most library functions, this returns 1 on success and 0 on failure
    int status = liberty_demangle(
        name, liberty_demangle_options, demangleCallback, &dbuf);
    if (status == 0) { // failed, return original
      return folly::strlcpy(out, name, outSize);
    }
    if (outSize != 0) {
      *dbuf.dest = '\0';
    }
    return dbuf.total;
  } else {
    return folly::strlcpy(out, name, outSize);
  }
}

} // namespace folly
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: ndnotxt.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: mib $ $Date: 2002-07-24 13:07:45 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _NDNOTXT_HXX
#define _NDNOTXT_HXX

#include "node.hxx"

class PolyPolygon;

// --------------------
// SwNoTxtNode
// --------------------

class SwNoTxtNode : public SwCntntNode
{
    friend class SwNodes;
    friend class SwNoTxtFrm;

    String aAlternateText;      // alternativer Text  (HTML)

    PolyPolygon *pContour;      // Polygon fuer Konturumlauf
    BOOL bAutomaticContour : 1; // automatic contour polygon, not manipulated
    BOOL bContourMapModeValid : 1; // contour map mode is not the graphics's
                                   // prefered map mode, but either
                                      // MM100 or or pixel
    BOOL bPixelContour : 1;     // contour map mode is invalid and pixel.

    // erzeugt fuer alle Ableitungen einen AttrSet mit Bereichen
    // fuer Frame- und Grafik-Attributen (wird nur vom SwCntntNode gerufen)
    virtual void NewAttrSet( SwAttrPool& );

    SwNoTxtNode( const SwNoTxtNode& );              //nicht erlaubt
    SwNoTxtNode &operator=( const SwNoTxtNode& );   //nicht erlaubt

protected:
    SwNoTxtNode( const SwNodeIndex &rWhere, const BYTE nNdType,
                SwGrfFmtColl *pGrColl, SwAttrSet* pAutoAttr = 0 );

public:
    ~SwNoTxtNode();

    virtual SwCntntFrm *MakeFrm();

    inline SwGrfFmtColl *GetGrfColl() const;

    virtual Size GetTwipSize() const = 0;

    virtual BOOL SavePersistentData();
    virtual BOOL RestorePersistentData();

    // alternativen Text abfragen/setzen
    const String& GetAlternateText() const      { return aAlternateText; }
    void SetAlternateText( const String& rTxt, sal_Bool bBroadcast=sal_False );

    void               SetContour( const PolyPolygon *pPoly,
                                   BOOL bAutomatic = FALSE );
    const PolyPolygon *HasContour() const;
    const BOOL         _HasContour() const { return pContour!=0; };
    void               GetContour( PolyPolygon &rPoly ) const;
    void               CreateContour();

    void               SetAutomaticContour( BOOL bSet ) { bAutomaticContour = bSet; }
    const BOOL         HasAutomaticContour() const { return bAutomaticContour; }

    // set either a MM100 or pixel contour
    void               SetContourAPI( const PolyPolygon *pPoly );

    // get either a MM100 or pixel contour, return FALSE if no contour is set.
    BOOL               GetContourAPI( PolyPolygon &rPoly ) const;

    void               SetPixelContour( BOOL bSet ) { bPixelContour = bSet; }
    const BOOL         IsPixelContour() const;

    const BOOL         IsContourMapModeValid() const { return bContourMapModeValid; }

    //Besorgt die Graphic, mit SwapIn fuer GrfNode, per GetData fuer OLE.
    Graphic GetGraphic() const;
};

inline SwGrfFmtColl* SwNoTxtNode::GetGrfColl() const
{
    return (SwGrfFmtColl*)GetRegisteredIn();
}

// Inline Metoden aus Node.hxx - erst hier ist der TxtNode bekannt !!
inline SwNoTxtNode *SwNode::GetNoTxtNode()
{
    return ND_NOTXTNODE & nNodeType ? (SwNoTxtNode*)this : 0;
}
inline const SwNoTxtNode *SwNode::GetNoTxtNode() const
{
    return ND_NOTXTNODE & nNodeType ? (const SwNoTxtNode*)this : 0;
}

#endif  // _NDNOTXT_HXX
<commit_msg>#101685#,#i6886# merge OOO_STABLE_1_PORTS (1.3-1.3.20.1) -> HEAD<commit_after>/*************************************************************************
 *
 *  $RCSfile: ndnotxt.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2002-08-23 14:18:41 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _NDNOTXT_HXX
#define _NDNOTXT_HXX

#include "node.hxx"

class PolyPolygon;

// --------------------
// SwNoTxtNode
// --------------------

class SwNoTxtNode : public SwCntntNode
{
    friend class SwNodes;
    friend class SwNoTxtFrm;

    String aAlternateText;      // alternativer Text  (HTML)

    PolyPolygon *pContour;      // Polygon fuer Konturumlauf
    BOOL bAutomaticContour : 1; // automatic contour polygon, not manipulated
    BOOL bContourMapModeValid : 1; // contour map mode is not the graphics's
                                   // prefered map mode, but either
                                      // MM100 or or pixel
    BOOL bPixelContour : 1;     // contour map mode is invalid and pixel.

    // erzeugt fuer alle Ableitungen einen AttrSet mit Bereichen
    // fuer Frame- und Grafik-Attributen (wird nur vom SwCntntNode gerufen)
    virtual void NewAttrSet( SwAttrPool& );

    SwNoTxtNode( const SwNoTxtNode& );              //nicht erlaubt
    SwNoTxtNode &operator=( const SwNoTxtNode& );   //nicht erlaubt

protected:
    SwNoTxtNode( const SwNodeIndex &rWhere, const BYTE nNdType,
                SwGrfFmtColl *pGrColl, SwAttrSet* pAutoAttr = 0 );

public:
    ~SwNoTxtNode();

    virtual SwCntntFrm *MakeFrm();

    inline SwGrfFmtColl *GetGrfColl() const;

    virtual Size GetTwipSize() const = 0;

    virtual BOOL SavePersistentData();
    virtual BOOL RestorePersistentData();

    // alternativen Text abfragen/setzen
    const String& GetAlternateText() const      { return aAlternateText; }
    void SetAlternateText( const String& rTxt, sal_Bool bBroadcast=sal_False );

    void               SetContour( const PolyPolygon *pPoly,
                                   BOOL bAutomatic = FALSE );
    const PolyPolygon *HasContour() const;
    const BOOL         _HasContour() const { return pContour!=0; };
    void               GetContour( PolyPolygon &rPoly ) const;
    void               CreateContour();

    void               SetAutomaticContour( BOOL bSet ) { bAutomaticContour = bSet; }
    const BOOL         HasAutomaticContour() const { return bAutomaticContour; }

    // set either a MM100 or pixel contour
    void               SetContourAPI( const PolyPolygon *pPoly );

    // get either a MM100 or pixel contour, return FALSE if no contour is set.
    BOOL               GetContourAPI( PolyPolygon &rPoly ) const;

    void               SetPixelContour( BOOL bSet ) { bPixelContour = bSet; }
    const BOOL         IsPixelContour() const;

    const BOOL         IsContourMapModeValid() const { return bContourMapModeValid; }

    //Besorgt die Graphic, mit SwapIn fuer GrfNode, per GetData fuer OLE.
    Graphic GetGraphic() const;
};

inline SwGrfFmtColl* SwNoTxtNode::GetGrfColl() const
{
    return (SwGrfFmtColl*)GetRegisteredIn();
}

// Inline Metoden aus Node.hxx - erst hier ist der TxtNode bekannt !!
#ifndef MACOSX
// GrP moved to gcc_outl.cxx; revisit with gcc3
inline SwNoTxtNode *SwNode::GetNoTxtNode()
{
    return ND_NOTXTNODE & nNodeType ? (SwNoTxtNode*)this : 0;
}
inline const SwNoTxtNode *SwNode::GetNoTxtNode() const
{
    return ND_NOTXTNODE & nNodeType ? (const SwNoTxtNode*)this : 0;
}
#endif

#endif  // _NDNOTXT_HXX
<|endoftext|>