<commit_before>/*
// $Id$
// Fennel is a library of data storage and processing components.
// Copyright (C) 2005-2009 The Eigenbase Project
// Copyright (C) 2004-2010 SQLstream, Inc.
// Copyright (C) 2009-2009 LucidEra, Inc.
//
// 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 approved by The Eigenbase Project.
//
// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "fennel/common/CommonPreamble.h"
#include "fennel/calculator/ExtendedInstructionTable.h"
#include "fennel/calculator/ExtendedInstructionContext.h"
#include "fennel/calculator/SqlRegExp.h"

FENNEL_BEGIN_NAMESPACE

// Context for storing cached and reusable pattern and regexp
class ExtRegExpContext : public ExtendedInstructionContext
{
public:
    explicit
    ExtRegExpContext(
        boost::regex const & re,
        string const pat)
        : regex(re),
          pattern(pat)
    {
    }
    boost::regex regex;
    string pattern;
};

void
strLikeEscapeA(
    boost::scoped_ptr<ExtendedInstructionContext>& context,
    RegisterRef<bool>* result,
    RegisterRef<char*>* matchValue,
    RegisterRef<char*>* pattern,
    RegisterRef<char*>* escape) // may be NULL if called by strLikeA
{
    assert(StandardTypeDescriptor::isTextArray(matchValue->type()));
    assert(StandardTypeDescriptor::isTextArray(pattern->type()));

    // SQL99 Part 2 Section 8.5 General Rule 3.a, cases i & ii
    if (matchValue->isNull()
        || pattern->isNull()
        || (escape ? escape->isNull() : false))
    {
        result->toNull();
        result->length(0);
    } else {
        boost::regex* regexP;
        string* patP;
        ExtRegExpContext* ctxP;

        ctxP = static_cast<ExtRegExpContext*>(context.get());
        if (!ctxP) {
            string pat;
            SqlLikePrep<1, 1>(
                pattern->pointer(),
                pattern->length(),
                (escape ? escape->pointer() : 0),
                (escape ? escape->length() : 0),
                pat);
            try {
                boost::regex regex(pat);
                context.reset(new ExtRegExpContext(regex, pat));
            } catch (boost::bad_expression badexp) {
                // SQL99 Part 2 Section 8.5 General Rule 3.b.i2 *seems* like
                // best fit here.
                // Data Exception - Invalid Escape Sequence
                throw SqlState::instance().code22025();
            }
            // get context anew
            ctxP = static_cast<ExtRegExpContext*>(context.get());
        }
        regexP = &(ctxP->regex);
        patP = &(ctxP->pattern);

        result->value(
            SqlRegExp<1, 1>(
                matchValue->pointer(),
                matchValue->length(),
                pattern->length(),
                *regexP));
    }
}

void
strLikeA(
    boost::scoped_ptr<ExtendedInstructionContext>& context,
    RegisterRef<bool>* result,
    RegisterRef<char*>* matchValue,
    RegisterRef<char*>* pattern)
{
    strLikeEscapeA(context, result, matchValue, pattern, 0);
}

// escape may be NULL if called by strSimilarA
void
strSimilarEscapeA(
    boost::scoped_ptr<ExtendedInstructionContext>& context,
    RegisterRef<bool>* result,
    RegisterRef<char*>* matchValue,
    RegisterRef<char*>* pattern,
    RegisterRef<char*>* escape)
{
    assert(StandardTypeDescriptor::isTextArray(matchValue->type()));
    assert(StandardTypeDescriptor::isTextArray(pattern->type()));

    // SQL2003 Part 2 Section 8.5 General Rule 4.a,b
    if (matchValue->isNull()
        || pattern->isNull()
        || (escape ? escape->isNull() : false))
    {
        result->toNull();
        result->length(0);
    } else {
        boost::regex* regexP;
        string* patP;
        ExtRegExpContext* ctxP;

        ctxP = static_cast<ExtRegExpContext*>(context.get());
        if (!ctxP) {
            string pat;
            SqlSimilarPrep<1, 1>(
                pattern->pointer(),
                pattern->length(),
                (escape ? escape->pointer() : 0),
                (escape ? escape->length() : 0),
                pat);
            try {
                boost::regex regex(pat);
                context.reset(new ExtRegExpContext(regex, pat));
            } catch (boost::bad_expression badexp) {
                // SQL2003 Part 2 Section 8.6 General Rule 2
                // Data Exception - Invalid Regular Expression
                throw "2201B";
            }
            // get context anew
            ctxP = static_cast<ExtRegExpContext*>(context.get());
        }
        regexP = &(ctxP->regex);
        patP = &(ctxP->pattern);

        result->value(
            SqlRegExp<1, 1>(
                matchValue->pointer(),
                matchValue->length(),
                pattern->length(),
                *regexP));
    }
}

void
strSimilarA(
    boost::scoped_ptr<ExtendedInstructionContext>& context,
    RegisterRef<bool>* result,
    RegisterRef<char*>* matchValue,
    RegisterRef<char*>* pattern)
{
    strSimilarEscapeA(context, result, matchValue, pattern, 0);
}

void
ExtRegExpRegister(ExtendedInstructionTable* eit)
{
    assert(eit != NULL);

    // JK 2004/5/27: Are all of these combinations really needed?
    int i;
    for (i = 0; i < 8; i++) {
        vector<StandardTypeDescriptorOrdinal> params;

        params.push_back(STANDARD_TYPE_BOOL);

        if (i & 0x01) {
            params.push_back(STANDARD_TYPE_CHAR);
        } else {
            params.push_back(STANDARD_TYPE_VARCHAR);
        }
        if (i & 0x02) {
            params.push_back(STANDARD_TYPE_CHAR);
        } else {
            params.push_back(STANDARD_TYPE_VARCHAR);
        }

        eit->add(
            "strLikeA3", params,
            (ExtendedInstruction3Context<bool, char*, char*>*) NULL,
            &strLikeA);
        eit->add(
            "strSimilarA3", params,
            (ExtendedInstruction3Context<bool, char*, char*>*) NULL,
            &strSimilarA);

        // tack on escape parameter
        if (i & 0x04) {
            params.push_back(STANDARD_TYPE_CHAR);
        } else {
            params.push_back(STANDARD_TYPE_VARCHAR);
        }

        eit->add(
            "strLikeA4", params,
            (ExtendedInstruction4Context<bool, char*, char*, char*>*) NULL,
            &strLikeEscapeA);
        eit->add(
            "strSimilarA4", params,
            (ExtendedInstruction4Context<bool, char*, char*, char*>*) NULL,
            &strSimilarEscapeA);
    }
}

FENNEL_END_NAMESPACE

// End ExtRegExp.cpp
<commit_msg>FENNEL: Oops, missed one 'throw'.<commit_after>/*
// $Id$
// Fennel is a library of data storage and processing components.
// Copyright (C) 2005-2009 The Eigenbase Project
// Copyright (C) 2004-2010 SQLstream, Inc.
// Copyright (C) 2009-2009 LucidEra, Inc.
//
// 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 approved by The Eigenbase Project.
//
// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "fennel/common/CommonPreamble.h"
#include "fennel/calculator/ExtendedInstructionTable.h"
#include "fennel/calculator/ExtendedInstructionContext.h"
#include "fennel/calculator/SqlRegExp.h"

FENNEL_BEGIN_NAMESPACE

// Context for storing cached and reusable pattern and regexp
class ExtRegExpContext : public ExtendedInstructionContext
{
public:
    explicit
    ExtRegExpContext(
        boost::regex const & re,
        string const pat)
        : regex(re),
          pattern(pat)
    {
    }
    boost::regex regex;
    string pattern;
};

void
strLikeEscapeA(
    boost::scoped_ptr<ExtendedInstructionContext>& context,
    RegisterRef<bool>* result,
    RegisterRef<char*>* matchValue,
    RegisterRef<char*>* pattern,
    RegisterRef<char*>* escape) // may be NULL if called by strLikeA
{
    assert(StandardTypeDescriptor::isTextArray(matchValue->type()));
    assert(StandardTypeDescriptor::isTextArray(pattern->type()));

    // SQL99 Part 2 Section 8.5 General Rule 3.a, cases i & ii
    if (matchValue->isNull()
        || pattern->isNull()
        || (escape ? escape->isNull() : false))
    {
        result->toNull();
        result->length(0);
    } else {
        boost::regex* regexP;
        string* patP;
        ExtRegExpContext* ctxP;

        ctxP = static_cast<ExtRegExpContext*>(context.get());
        if (!ctxP) {
            string pat;
            SqlLikePrep<1, 1>(
                pattern->pointer(),
                pattern->length(),
                (escape ? escape->pointer() : 0),
                (escape ? escape->length() : 0),
                pat);
            try {
                boost::regex regex(pat);
                context.reset(new ExtRegExpContext(regex, pat));
            } catch (boost::bad_expression badexp) {
                // SQL99 Part 2 Section 8.5 General Rule 3.b.i2 *seems* like
                // best fit here.
                // Data Exception - Invalid Escape Sequence
                throw SqlState::instance().code22025();
            }
            // get context anew
            ctxP = static_cast<ExtRegExpContext*>(context.get());
        }
        regexP = &(ctxP->regex);
        patP = &(ctxP->pattern);

        result->value(
            SqlRegExp<1, 1>(
                matchValue->pointer(),
                matchValue->length(),
                pattern->length(),
                *regexP));
    }
}

void
strLikeA(
    boost::scoped_ptr<ExtendedInstructionContext>& context,
    RegisterRef<bool>* result,
    RegisterRef<char*>* matchValue,
    RegisterRef<char*>* pattern)
{
    strLikeEscapeA(context, result, matchValue, pattern, 0);
}

// escape may be NULL if called by strSimilarA
void
strSimilarEscapeA(
    boost::scoped_ptr<ExtendedInstructionContext>& context,
    RegisterRef<bool>* result,
    RegisterRef<char*>* matchValue,
    RegisterRef<char*>* pattern,
    RegisterRef<char*>* escape)
{
    assert(StandardTypeDescriptor::isTextArray(matchValue->type()));
    assert(StandardTypeDescriptor::isTextArray(pattern->type()));

    // SQL2003 Part 2 Section 8.5 General Rule 4.a,b
    if (matchValue->isNull()
        || pattern->isNull()
        || (escape ? escape->isNull() : false))
    {
        result->toNull();
        result->length(0);
    } else {
        boost::regex* regexP;
        string* patP;
        ExtRegExpContext* ctxP;

        ctxP = static_cast<ExtRegExpContext*>(context.get());
        if (!ctxP) {
            string pat;
            SqlSimilarPrep<1, 1>(
                pattern->pointer(),
                pattern->length(),
                (escape ? escape->pointer() : 0),
                (escape ? escape->length() : 0),
                pat);
            try {
                boost::regex regex(pat);
                context.reset(new ExtRegExpContext(regex, pat));
            } catch (boost::bad_expression badexp) {
                // SQL2003 Part 2 Section 8.6 General Rule 2
                // Data Exception - Invalid Regular Expression
                throw SqlState::instance().code2201B();
            }
            // get context anew
            ctxP = static_cast<ExtRegExpContext*>(context.get());
        }
        regexP = &(ctxP->regex);
        patP = &(ctxP->pattern);

        result->value(
            SqlRegExp<1, 1>(
                matchValue->pointer(),
                matchValue->length(),
                pattern->length(),
                *regexP));
    }
}

void
strSimilarA(
    boost::scoped_ptr<ExtendedInstructionContext>& context,
    RegisterRef<bool>* result,
    RegisterRef<char*>* matchValue,
    RegisterRef<char*>* pattern)
{
    strSimilarEscapeA(context, result, matchValue, pattern, 0);
}

void
ExtRegExpRegister(ExtendedInstructionTable* eit)
{
    assert(eit != NULL);

    // JK 2004/5/27: Are all of these combinations really needed?
    int i;
    for (i = 0; i < 8; i++) {
        vector<StandardTypeDescriptorOrdinal> params;

        params.push_back(STANDARD_TYPE_BOOL);

        if (i & 0x01) {
            params.push_back(STANDARD_TYPE_CHAR);
        } else {
            params.push_back(STANDARD_TYPE_VARCHAR);
        }
        if (i & 0x02) {
            params.push_back(STANDARD_TYPE_CHAR);
        } else {
            params.push_back(STANDARD_TYPE_VARCHAR);
        }

        eit->add(
            "strLikeA3", params,
            (ExtendedInstruction3Context<bool, char*, char*>*) NULL,
            &strLikeA);
        eit->add(
            "strSimilarA3", params,
            (ExtendedInstruction3Context<bool, char*, char*>*) NULL,
            &strSimilarA);

        // tack on escape parameter
        if (i & 0x04) {
            params.push_back(STANDARD_TYPE_CHAR);
        } else {
            params.push_back(STANDARD_TYPE_VARCHAR);
        }

        eit->add(
            "strLikeA4", params,
            (ExtendedInstruction4Context<bool, char*, char*, char*>*) NULL,
            &strLikeEscapeA);
        eit->add(
            "strSimilarA4", params,
            (ExtendedInstruction4Context<bool, char*, char*, char*>*) NULL,
            &strSimilarEscapeA);
    }
}

FENNEL_END_NAMESPACE

// End ExtRegExp.cpp
<|endoftext|>


<commit_before>/* -*- mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
// vim:sts=4:sw=4:ts=4:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s

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

namespace FFLAS
{

	template<class Field, class AlgoT, class FieldTrait>
	typename Field::Element_ptr
	pfgemv(const Field& F,
		   const FFLAS_TRANSPOSE ta,
		   const size_t m,
		   const size_t n,
		   const typename Field::Element alpha,
		   const typename Field::ConstElement_ptr A, const size_t lda,
		   const typename Field::ConstElement_ptr X, const size_t incX,
		   const typename Field::Element beta,
		   typename Field::Element_ptr Y, const size_t incY,
		   MMHelper<Field, AlgoT, FieldTrait, ParSeqHelper::Parallel<CuttingStrategy::Recursive, StrategyParameter::Threads> > & H){

		if (H.parseq.numthreads()>=m){
			fgemv(F, ta,  m, n,  alpha, A, lda, X, incX, beta, Y, incY);

		}else{
			typedef MMHelper<Field,AlgoT,FieldTrait,ParSeqHelper::Parallel<CuttingStrategy::Recursive, StrategyParameter::Threads> > MMH_t;
			MMH_t H1(H);
			MMH_t H2(H);
			size_t M2 = m>>1;
			PAR_BLOCK{

				if(H1.parseq.numthreads()>1){
					H1.parseq.set_numthreads(H.parseq.numthreads() >> 1);
					H2.parseq.set_numthreads(H.parseq.numthreads() - H1.parseq.numthreads());
				}else{
					H1.parseq.set_numthreads(H.parseq.numthreads());
					H2.parseq.set_numthreads(H.parseq.numthreads());
				}

				typename Field::ConstElement_ptr A1 = A;
				typename Field::ConstElement_ptr A2 = A + M2*lda;
				typename Field::Element_ptr C1 = Y;
				typename Field::Element_ptr C2 = Y + M2;

				TASK(CONSTREFERENCE(F,H1) MODE( READ(A1,X) READWRITE(C1)),
					 {pfgemv( F, ta,  M2, n, alpha, A1, lda, X, incX, beta, C1, incY, H1);}
					 );

				TASK(MODE(CONSTREFERENCE(F,H2) READ(A2,X) READWRITE(C2)),
					 {pfgemv(F, ta, m-M2, n, alpha, A2, lda, X, incX, beta, C2, incY, H2);}
					 );
			}

		}
		return Y;

	}

	template<class Field, class AlgoT, class FieldTrait>
	typename Field::Element_ptr
	pfgemv(const Field& F,
		   const FFLAS_TRANSPOSE ta,
		   const size_t m,
		   const size_t n,
		   const typename Field::Element alpha,
		   const typename Field::ConstElement_ptr A, const size_t lda,
		   const typename Field::ConstElement_ptr X, const size_t incX,
		   const typename Field::Element beta,
		   typename Field::Element_ptr Y, const size_t incY,
		   MMHelper<Field, AlgoT, FieldTrait, ParSeqHelper::Parallel<CuttingStrategy::Row, StrategyParameter::Threads> > & H){

		if(H.parseq.numthreads()<2){
			fgemv( F, ta, m, n, alpha, A , lda, X, incX, beta, Y, incY);
		}else{

			PAR_BLOCK{
				using FFLAS::CuttingStrategy::Row;
				using FFLAS::StrategyParameter::Threads;
				typedef MMHelper<Field,AlgoT,FieldTrait,ParSeqHelper::Parallel<CuttingStrategy::Row, StrategyParameter::Threads> > MMH_t;
				MMH_t HH(H);
				ParSeqHelper::Parallel<CuttingStrategy::Row, StrategyParameter::Threads> pH;

				HH.parseq.set_numthreads(H.parseq.numthreads());

				FORBLOCK1D(iter, m,	 pH,
						   TASK(CONSTREFERENCE(F) MODE( READ(A1,X) READWRITE(Y)),
								{
									pfgemv( F, ta, (iter.end()-iter.begin()), n, alpha, A + iter.begin()*lda, lda, X, incX, beta, Y + iter.begin(), incY, HH);
								}
								)
						   );
			}
		}

		return Y;

	}

//////////////////////////////////////Possible Cache-friendly with blocking///////////////////////////////////////////
	template<class Field>
	void partfgemv(const Field& F,
				   const FFLAS_TRANSPOSE ta,
				   const size_t m,
				   const size_t n,
				   const typename Field::Element alpha,
				   const typename Field::ConstElement_ptr A, const size_t lda,
				   const typename Field::ConstElement_ptr X, const size_t incX,
				   const typename Field::Element beta,
				   typename Field::Element_ptr Y, const size_t incY){
		/*FFLAS::WriteMatrix (std::cout << "A::in ="<< std::endl, F, m, n, A, lda) << std::endl;
		FFLAS::WriteMatrix (std::cout << "X::in ="<< std::endl, F, n, incX, X, incX) << std::endl;
		FFLAS::WriteMatrix (std::cout << "Y::in ="<< std::endl, F, m, incY, Y, incY) << std::endl;*/

		typename Field::Element_ptr tmp  = FFLAS::fflas_new(F, m, incY);
		fassign (F, m, incY, Y, incY, tmp, incY);

		fgemv( F, ta, m, n, alpha, A, lda, X, incX, beta, Y, incY); WAIT;

		fadd (F, m, Y, incY, tmp, incY, Y, incY);
		FFLAS::fflas_delete(tmp);
		//FFLAS::WriteMatrix (std::cout << "Y::out ="<< std::endl, F, m, incY, Y, incY) << std::endl;
		return;
	}

	template<class Field, class AlgoT, class FieldTrait>
	typename Field::Element_ptr
	pfgemv(const Field& F,
		   const FFLAS_TRANSPOSE ta,
		   const size_t m,
		   const size_t n,
		   const typename Field::Element alpha,
		   const typename Field::ConstElement_ptr A, const size_t lda,
		   const typename Field::ConstElement_ptr X, const size_t incX,
		   const typename Field::Element beta,
		   typename Field::Element_ptr Y, const size_t incY,
		   size_t GS_Cache,
		   MMHelper<Field, AlgoT, FieldTrait, ParSeqHelper::Parallel<CuttingStrategy::Row, StrategyParameter::Grain> > & H){

		typedef MMHelper<Field,AlgoT,FieldTrait,ParSeqHelper::Parallel<CuttingStrategy::Row, StrategyParameter::Grain> > MMH_t;
		MMH_t HH(H);

		size_t N = min(m,n);
		const int TILE = min(min(m,GS_Cache), min(n,GS_Cache) );
		//Compute tiles in each dimension
		const int nEven = N - N%TILE;

		/*FFLAS::WriteMatrix (std::cout << "A:in ="<< std::endl, F, m, n, A, lda) << std::endl;
		FFLAS::WriteMatrix (std::cout << "X:in ="<< std::endl, F, n, incX, X, incX) << std::endl;
		FFLAS::WriteMatrix (std::cout << "Y:in ="<< std::endl, F, m, incY, Y, incY) << std::endl;	*/

		SYNCH_GROUP(
					PAR_BLOCK{ 	//omp_set_num_threads(4);
				using FFLAS::CuttingStrategy::Row;
				using FFLAS::StrategyParameter::Grain;
				typedef MMHelper<Field,AlgoT,FieldTrait,ParSeqHelper::Parallel<CuttingStrategy::Row, StrategyParameter::Grain> > MMH_t;
				MMH_t HH(H);
				HH.parseq.set_numthreads(H.parseq.numthreads());
				ParSeqHelper::Parallel<CuttingStrategy::Row, StrategyParameter::Grain> pH;
						//Main body of the matrix

						/*for(int ii=0; ii<nEven; ii+=TILE){

							fgemv( F, ta, TILE, TILE, alpha, A+ii*lda, lda, X, incX, beta, Y+ii, incY);WAIT;

						}*/

				FOR1D(ii, nEven/TILE, pH,

								{
									fgemv( F, ta, TILE, TILE, alpha, A+TILE*ii*lda, lda, X, incX, beta, Y+ii*TILE, incY);
								}

						   );

/********************************************************************************
Maybe use FOR2D so that:
(1)taking ii from 0 to N/TILE then replace all ii index by ii*TILE -->DONE
(2)taking jj from 1 to N/TILE then replace all jj index by jj*TILE  ??????
*********************************************************************************/
FOR1D(ii, nEven/TILE, pH,
						//for(int ii=0; ii<nEven; ii+=TILE)
						{

							for(int jj=TILE; jj<nEven; jj+=TILE){

								//partfgemv( F, ta, TILE, TILE, alpha, A+lda*ii+jj, lda, X+jj, incX, beta, Y+ii, incY);	WAIT;
partfgemv( F, ta, TILE, TILE, alpha, A+lda*(ii*TILE)+jj, lda, X+jj, incX, beta, Y+(ii*TILE), incY);

							}
						}
);

						//Right columns in the peel zone around the perimeter of the matrix

						/*for(int jj=0; jj<nEven; jj+=TILE){
							partfgemv( F, ta, TILE, n-nEven, alpha, A+nEven+jj*lda, lda, X+nEven, incX, beta, Y+jj, incY); WAIT;
						}*/

				FOR1D(jj, nEven/TILE, pH,

								{
									partfgemv( F, ta, TILE, n-nEven, alpha, A+nEven+jj*TILE*lda, lda, X+nEven, incX, beta, Y+jj*TILE, incY);
								}

						   );

						//Bottom rows in the peel zone around the perimeter of the matrix
						if( m-nEven>0){
							fgemv( F, ta, m-nEven, TILE, alpha, A+nEven*lda, lda, X, incX, beta, Y+nEven, incY);WAIT;
/*****************************************************************************************
Possible to use FOR1D taking jj from 0 to N/TILE then replace all jj index by jj*TILE ???
******************************************************************************************/
							for(int jj=TILE; jj<nEven; jj+=TILE){

								partfgemv( F, ta, m-nEven, TILE, alpha, A+nEven*lda+jj, lda, X+jj, incX, beta, Y+nEven, incY); WAIT;

							}

				/*FOR1D(jj,  nEven/TILE-1, pH,

								{

									//std::cout<<"jj="<<jj<<std::endl;WAIT;
                                    //std::cout<<"jj*TILE="<<jj*TILE<<std::endl;WAIT;
//std::cout<<"=====================1==================="<<std::endl;WAIT;
									//if(0!=jj)partfgemv( F, ta, m-nEven, TILE, alpha, A+nEven*lda+(jj)*TILE, lda, X+(jj)*TILE, incX, beta, Y+nEven, incY);WAIT;
partfgemv( F, ta, m-nEven, TILE, alpha, A+nEven*lda+(jj+1)*TILE, lda, X+(jj+1)*TILE, incX, beta, Y+nEven, incY);WAIT;
//std::cout<<"====================2===================="<<std::endl;WAIT;

								}

						   );*/

						}

						//Bottom right corner of the matrix
						if( n-nEven>0&&m-nEven>0){

							partfgemv( F, ta, m-nEven, n-nEven, alpha, A+nEven*lda+nEven, lda, X+nEven, incX, beta, Y+nEven, incY);WAIT;

						}

					}   //PAR_BLOCK
						); //SYNCH_GROUP

		return Y;

	}

} // FFLAS

<commit_msg>Parallel implementation of function fgemv using row cutting strategy and grain strategy parameter rewritten as required<commit_after>/* -*- mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
// vim:sts=4:sw=4:ts=4:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s
/* fflas/fflas_pfgemv.inl
 *
 * ========LICENCE========
 * This file is part of the library FFLAS-FFPACK.
 *
 * FFLAS-FFPACK is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 *.
 */

namespace FFLAS
{

	template<class Field, class AlgoT, class FieldTrait>
	typename Field::Element_ptr
	pfgemv(const Field& F,
		   const FFLAS_TRANSPOSE ta,
		   const size_t m,
		   const size_t n,
		   const typename Field::Element alpha,
		   const typename Field::ConstElement_ptr A, const size_t lda,
		   const typename Field::ConstElement_ptr X, const size_t incX,
		   const typename Field::Element beta,
		   typename Field::Element_ptr Y, const size_t incY,
		   MMHelper<Field, AlgoT, FieldTrait, ParSeqHelper::Parallel<CuttingStrategy::Recursive, StrategyParameter::Threads> > & H){

		if (H.parseq.numthreads()==1 || m <= 1){
			fgemv(F, ta,  m, n,  alpha, A, lda, X, incX, beta, Y, incY);

		}else{
			typedef MMHelper<Field,AlgoT,FieldTrait,ParSeqHelper::Parallel<CuttingStrategy::Recursive, StrategyParameter::Threads> > MMH_t;
			MMH_t H1(H);
			MMH_t H2(H);
			size_t M2 = m>>1;
			PAR_BLOCK{

				H1.parseq.set_numthreads(H.parseq.numthreads() >> 1);
				H2.parseq.set_numthreads(H.parseq.numthreads() - H1.parseq.numthreads());

				typename Field::ConstElement_ptr A1 = A;
				typename Field::ConstElement_ptr A2 = A + M2*lda;
				typename Field::Element_ptr C1 = Y;
				typename Field::Element_ptr C2 = Y + M2;

				TASK(CONSTREFERENCE(F,H1) MODE( READ(A1,X) READWRITE(C1)),
					 {pfgemv( F, ta,  M2, n, alpha, A1, lda, X, incX, beta, C1, incY, H1);}
					 );

				TASK(MODE(CONSTREFERENCE(F,H2) READ(A2,X) READWRITE(C2)),
					 {pfgemv(F, ta, m-M2, n, alpha, A2, lda, X, incX, beta, C2, incY, H2);}
					 );
			}

		}
		return Y;

	}

	template<class Field, class AlgoT, class FieldTrait>
	typename Field::Element_ptr
	pfgemv(const Field& F,
		   const FFLAS_TRANSPOSE ta,
		   const size_t m,
		   const size_t n,
		   const typename Field::Element alpha,
		   const typename Field::ConstElement_ptr A, const size_t lda,
		   const typename Field::ConstElement_ptr X, const size_t incX,
		   const typename Field::Element beta,
		   typename Field::Element_ptr Y, const size_t incY,
		   MMHelper<Field, AlgoT, FieldTrait, ParSeqHelper::Parallel<CuttingStrategy::Row, StrategyParameter::Threads> > & H){

		if(H.parseq.numthreads()<2){
			fgemv( F, ta, m, n, alpha, A , lda, X, incX, beta, Y, incY);
		}else{

			SYNCH_GROUP(
				FORBLOCK1D(iter, m,	 H.parseq,
						   TASK(CONSTREFERENCE(F) MODE( READ(A1,X) READWRITE(Y)),
								{
									fgemv( F, ta, (iter.end()-iter.begin()), n, alpha, A + iter.begin()*lda, lda, X, incX, beta, Y + iter.begin()*incY, incY);
								}
								)
						   );
						);
		}

		return Y;

	}

	template<class Field, class AlgoT, class FieldTrait>
	typename Field::Element_ptr
	pfgemv(const Field& F,
		   const FFLAS_TRANSPOSE ta,
		   const size_t m,
		   const size_t n,
		   const typename Field::Element alpha,
		   const typename Field::ConstElement_ptr A, const size_t lda,
		   const typename Field::ConstElement_ptr X, const size_t incX,
		   const typename Field::Element beta,
		   typename Field::Element_ptr Y, const size_t incY,
		   MMHelper<Field, AlgoT, FieldTrait, ParSeqHelper::Parallel<CuttingStrategy::Row, StrategyParameter::Grain> > & H){

		const int RG = m/H.parseq.numthreads();
		size_t N1 = (m-m/H.parseq.numthreads()*H.parseq.numthreads()>0)?(m-m/H.parseq.numthreads()*H.parseq.numthreads()):0;
		size_t N2 = H.parseq.numthreads()-N1;

		if(H.parseq.numthreads()==1||m<=1){
			fgemv( F, ta, m, n, alpha, A , lda, X, incX, beta, Y, incY);
		}else{
			ParSeqHelper::Parallel<CuttingStrategy::Row, StrategyParameter::Grain> pH;
			if(N1>0){
				SYNCH_GROUP(

							FORBLOCK1D(iter, N1, pH,
									   TASK(CONSTREFERENCE(F) MODE( READ(A,X) READWRITE(Y)),
											{
												fgemv( F, ta, RG+1, n, alpha,  A+(RG+1)*iter.blockindex()*lda, lda, X, incX, beta,  Y+iter.blockindex()*(RG+1)*incY, incY);
											}
											)
									   );

							 );
			}

			if(N2>0){
				SYNCH_GROUP(

							FORBLOCK1D(iter, N2, pH,
									   TASK(CONSTREFERENCE(F) MODE( READ(A,X) READWRITE(Y)),
											{

												fgemv( F, ta, RG, n, alpha, A+(RG+1)*N1*lda+RG*iter.blockindex()*lda, lda, X, incX, beta, Y+(RG+1)*N1+iter.blockindex()*RG*incY, incY);

											}
											)
									   );

							 );
			}

		}

		return Y;

	}

	template<class Field, class Cut, class Param>
	typename Field::Element_ptr
	pfgemv(const Field& F,
		   const FFLAS_TRANSPOSE ta,
		   const size_t m,
		   const size_t n,
		   const typename Field::Element alpha,
		   const typename Field::ConstElement_ptr A, const size_t lda,
		   const typename Field::ConstElement_ptr X, const size_t incX,
		   const typename Field::Element beta,
		   typename Field::Element_ptr Y, const size_t incY,
		   ParSeqHelper::Parallel<Cut,Param> par ){

		MMHelper<Field, MMHelperAlgo::Auto, typename FFLAS::ModeTraits<Field>::value, ParSeqHelper::Parallel<Cut,Param> > H (F,m,n,1,par);
		return pfgemv(F, ta, m, n, alpha, A, lda, X, incX, beta, Y, incY, H);
	}

} // FFLAS

<|endoftext|>


<commit_before>/** @file
 *
 * @ingroup modularLibrary
 *
 * @brief A Mirror Object
 *
 * @details
 *
 * @authors Théo de la Hogue
 *
 * @copyright © 2010, Théo de la Hogue @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTMirror.h"

#define thisTTClass			TTMirror
#define thisTTClassName		"Mirror"
#define thisTTClassTags		"mirror"

TT_MODULAR_CONSTRUCTOR,
mType(kTTSymEmpty),
mGetAttributeCallback(NULL),
mSetAttributeCallback(NULL),
mSendMessageCallback(NULL),
mListenAttributeCallback(NULL)
{
	TTValue				attributeNames, messageNames, args;
	TTSymbol			name;
	TTAttributePtr		anAttribute;
	TTAttributeFlags	attributeFlags = kTTAttrPassObject;
	TTMessagePtr		aMessage;

	TT_ASSERT("Correct number of args to create TTMirror", arguments.size() == 5);

	if (arguments.size() >= 1)
		mType = arguments[0];

    if (mType != kTTSymEmpty) {

        if (arguments.size() >= 2)
            mGetAttributeCallback = TTCallbackPtr((TTObjectBasePtr)arguments[1]);

        if (arguments.size() >= 3)
            mSetAttributeCallback = TTCallbackPtr((TTObjectBasePtr)arguments[2]);

        if (arguments.size() >= 4)
            mSendMessageCallback = TTCallbackPtr((TTObjectBasePtr)arguments[3]);

        if (arguments.size() >= 5)
            mListenAttributeCallback = TTCallbackPtr((TTObjectBasePtr)arguments[4]);

        // instantiate a temp object to copy visible attributes and messages
        TTObjectBasePtr anObject = NULL;
        args.resize(32);
        TTObjectBaseInstantiate(mType,  &anObject, args);

        anObject->getAttributeNames(attributeNames);
        for (TTUInt32 i = 0; i < attributeNames.size(); i++) {

            anAttribute = NULL;
            name = attributeNames[i];
            anObject->getAttribute(name, &anAttribute);

            if (mGetAttributeCallback)
                addMirrorAttribute(name, anAttribute->type);

            // else cache the attribute value
            else {

                addMirrorCachedAttribute(name, anAttribute->type);

                mAttributeValueCache.append(name, kTTValNONE);
            }

            setAttributeGetterFlags(name, attributeFlags);
            setAttributeSetterFlags(name, attributeFlags);

            // TODO : addMirrorAttributeProperty
            //addMirrorAttributeProperty(name, readOnly, anAttribute->readOnly);
        }

        anObject->getMessageNames(messageNames);
        for (TTUInt32 i = 0; i < messageNames.size(); i++) {

            name = messageNames[i];
            anObject->getMessage(name, &aMessage);

            addMirrorMessage(name, aMessage->flags);

            // TODO : addMirrorMessageProperty
        }

        TTObjectBaseRelease(&anObject);
    }
}

TTMirror::~TTMirror()
{
	;
}

TTSymbol TTMirror::getName()
{
    return mType;
}

TTErr TTMirror::getMirrorAttribute(TTAttribute& anAttribute, TTValue& value)
{
	TTValue data;

	if (mGetAttributeCallback) {

		data.append(anAttribute.name);
		data.append((TTPtr)&value);

		return mGetAttributeCallback->notify(data, kTTValNONE);
	}

	return kTTErrGeneric;
}

TTErr TTMirror::setMirrorAttribute(TTAttribute& anAttribute, const TTValue& value)
{
	TTValue data;
	TTErr	err = kTTErrNone;

	if (mSetAttributeCallback) {

		data.append(anAttribute.name);
		data.append((TTPtr)&value);

		err = mSetAttributeCallback->notify(data, kTTValNONE);

        // if the mirror cannot listen value : notify observers ourself
        if (!mListenAttributeCallback)
            anAttribute.sendNotification(kTTSym_notify, value);	// we use kTTSym_notify because we know that observers are TTCallback
	}

	return err;
}

TTErr TTMirror::getMirrorCachedAttribute(TTAttribute& anAttribute, TTValue& value)
{
	TTValue data;

    data.append(anAttribute.name);

    // get the value from the cache
    if (!mAttributeValueCache.lookup(anAttribute.name, value)) {

        data.append((TTPtr)&value);
		return kTTErrNone;
	}

	return kTTErrGeneric;
}

TTErr TTMirror::setMirrorCachedAttribute(TTAttribute& anAttribute, const TTValue& value)
{
	TTValue data, cached;
	TTErr	err = kTTErrNone;

	if (mSetAttributeCallback) {

		data.append(anAttribute.name);
		data.append((TTPtr)&value);

        // update the cache with the value
        if (!mAttributeValueCache.lookup(anAttribute.name, cached)) {
            mAttributeValueCache.remove(anAttribute.name);
            mAttributeValueCache.append(anAttribute.name, value);
        }

		err = mSetAttributeCallback->notify(data, kTTValNONE);

        // if the mirror cannot listen value : notify observers ourself
        if (!mListenAttributeCallback)
            anAttribute.sendNotification(kTTSym_notify, value);	// we use kTTSym_notify because we know that observers are TTCallback
	}

	return err;
}

TTErr TTMirror::sendMirrorMessage(const TTSymbol* messageName, const TTValue& inputValue, TTValue& outputValue)
{
	TTValue data;
    TTErr   err = kTTErrNone;

	if (mSendMessageCallback) {

		data.append(messageName);
		data.append((TTPtr)&inputValue);

		err = mSetAttributeCallback->notify(data, kTTValNONE);
	}

	return err;
}

TTErr TTMirror::updateAttributeValue(const TTSymbol attributeName, TTValue& value)
{
	TTAttributePtr	anAttribute = NULL;
	TTErr			err;

	err = this->findAttribute(attributeName, &anAttribute);

    // if attributes are cached
    if (!mGetAttributeCallback) {

        TTValue cached;

        // update the cache with the value
        if (!mAttributeValueCache.lookup(attributeName, cached)) {
            mAttributeValueCache.remove(attributeName);
            mAttributeValueCache.append(attributeName, value);
        }
    }

	if (!err)
		anAttribute->sendNotification(kTTSym_notify, value);	// we use kTTSym_notify because we know that observers are TTCallback

	return err;
}

TTErr TTMirror::enableListening(const TTAttribute& anAttribute, TTBoolean enable)
{
	TTValue data;
    TTErr   err = kTTErrNone;

	if (mListenAttributeCallback) {

		data.append(anAttribute.name);
		data.append(enable);

		err = mListenAttributeCallback->notify(data, kTTValNONE);
	}

	return err;
}

#if 0
#pragma mark -
#pragma mark Some Methods
#endif
<commit_msg>Testing if the object exist before to copy attributes<commit_after>/** @file
 *
 * @ingroup modularLibrary
 *
 * @brief A Mirror Object
 *
 * @details
 *
 * @authors Théo de la Hogue
 *
 * @copyright © 2010, Théo de la Hogue @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTMirror.h"

#define thisTTClass			TTMirror
#define thisTTClassName		"Mirror"
#define thisTTClassTags		"mirror"

TT_MODULAR_CONSTRUCTOR,
mType(kTTSymEmpty),
mGetAttributeCallback(NULL),
mSetAttributeCallback(NULL),
mSendMessageCallback(NULL),
mListenAttributeCallback(NULL)
{
	TTValue				attributeNames, messageNames, args;
	TTSymbol			name;
	TTAttributePtr		anAttribute;
	TTAttributeFlags	attributeFlags = kTTAttrPassObject;
	TTMessagePtr		aMessage;
    TTErr               err;

	TT_ASSERT("Correct number of args to create TTMirror", arguments.size() == 5);

	if (arguments.size() >= 1)
		mType = arguments[0];

    if (mType != kTTSymEmpty) {

        if (arguments.size() >= 2)
            mGetAttributeCallback = TTCallbackPtr((TTObjectBasePtr)arguments[1]);

        if (arguments.size() >= 3)
            mSetAttributeCallback = TTCallbackPtr((TTObjectBasePtr)arguments[2]);

        if (arguments.size() >= 4)
            mSendMessageCallback = TTCallbackPtr((TTObjectBasePtr)arguments[3]);

        if (arguments.size() >= 5)
            mListenAttributeCallback = TTCallbackPtr((TTObjectBasePtr)arguments[4]);

        // instantiate a temp object to copy visible attributes and messages
        TTObjectBasePtr anObject = NULL;
        args.resize(32);
        err = TTObjectBaseInstantiate(mType,  &anObject, args);

        if (!err) {

            anObject->getAttributeNames(attributeNames);
            for (TTUInt32 i = 0; i < attributeNames.size(); i++) {

                anAttribute = NULL;
                name = attributeNames[i];
                anObject->getAttribute(name, &anAttribute);

                if (mGetAttributeCallback)
                    addMirrorAttribute(name, anAttribute->type);

                // else cache the attribute value
                else {

                    addMirrorCachedAttribute(name, anAttribute->type);

                    mAttributeValueCache.append(name, kTTValNONE);
                }

                setAttributeGetterFlags(name, attributeFlags);
                setAttributeSetterFlags(name, attributeFlags);

                // TODO : addMirrorAttributeProperty
                //addMirrorAttributeProperty(name, readOnly, anAttribute->readOnly);
            }

            anObject->getMessageNames(messageNames);
            for (TTUInt32 i = 0; i < messageNames.size(); i++) {

                name = messageNames[i];
                anObject->getMessage(name, &aMessage);

                addMirrorMessage(name, aMessage->flags);

                // TODO : addMirrorMessageProperty
            }

            TTObjectBaseRelease(&anObject);
        }
    }
}

TTMirror::~TTMirror()
{
	;
}

TTSymbol TTMirror::getName()
{
    return mType;
}

TTErr TTMirror::getMirrorAttribute(TTAttribute& anAttribute, TTValue& value)
{
	TTValue data;

	if (mGetAttributeCallback) {

		data.append(anAttribute.name);
		data.append((TTPtr)&value);

		return mGetAttributeCallback->notify(data, kTTValNONE);
	}

	return kTTErrGeneric;
}

TTErr TTMirror::setMirrorAttribute(TTAttribute& anAttribute, const TTValue& value)
{
	TTValue data;
	TTErr	err = kTTErrNone;

	if (mSetAttributeCallback) {

		data.append(anAttribute.name);
		data.append((TTPtr)&value);

		err = mSetAttributeCallback->notify(data, kTTValNONE);

        // if the mirror cannot listen value : notify observers ourself
        if (!mListenAttributeCallback)
            anAttribute.sendNotification(kTTSym_notify, value);	// we use kTTSym_notify because we know that observers are TTCallback
	}

	return err;
}

TTErr TTMirror::getMirrorCachedAttribute(TTAttribute& anAttribute, TTValue& value)
{
	TTValue data;

    data.append(anAttribute.name);

    // get the value from the cache
    if (!mAttributeValueCache.lookup(anAttribute.name, value)) {

        data.append((TTPtr)&value);
		return kTTErrNone;
	}

	return kTTErrGeneric;
}

TTErr TTMirror::setMirrorCachedAttribute(TTAttribute& anAttribute, const TTValue& value)
{
	TTValue data, cached;
	TTErr	err = kTTErrNone;

	if (mSetAttributeCallback) {

		data.append(anAttribute.name);
		data.append((TTPtr)&value);

        // update the cache with the value
        if (!mAttributeValueCache.lookup(anAttribute.name, cached)) {
            mAttributeValueCache.remove(anAttribute.name);
            mAttributeValueCache.append(anAttribute.name, value);
        }

		err = mSetAttributeCallback->notify(data, kTTValNONE);

        // if the mirror cannot listen value : notify observers ourself
        if (!mListenAttributeCallback)
            anAttribute.sendNotification(kTTSym_notify, value);	// we use kTTSym_notify because we know that observers are TTCallback
	}

	return err;
}

TTErr TTMirror::sendMirrorMessage(const TTSymbol* messageName, const TTValue& inputValue, TTValue& outputValue)
{
	TTValue data;
    TTErr   err = kTTErrNone;

	if (mSendMessageCallback) {

		data.append(messageName);
		data.append((TTPtr)&inputValue);

		err = mSetAttributeCallback->notify(data, kTTValNONE);
	}

	return err;
}

TTErr TTMirror::updateAttributeValue(const TTSymbol attributeName, TTValue& value)
{
	TTAttributePtr	anAttribute = NULL;
	TTErr			err;

	err = this->findAttribute(attributeName, &anAttribute);

    // if attributes are cached
    if (!mGetAttributeCallback) {

        TTValue cached;

        // update the cache with the value
        if (!mAttributeValueCache.lookup(attributeName, cached)) {
            mAttributeValueCache.remove(attributeName);
            mAttributeValueCache.append(attributeName, value);
        }
    }

	if (!err)
		anAttribute->sendNotification(kTTSym_notify, value);	// we use kTTSym_notify because we know that observers are TTCallback

	return err;
}

TTErr TTMirror::enableListening(const TTAttribute& anAttribute, TTBoolean enable)
{
	TTValue data;
    TTErr   err = kTTErrNone;

	if (mListenAttributeCallback) {

		data.append(anAttribute.name);
		data.append(enable);

		err = mListenAttributeCallback->notify(data, kTTValNONE);
	}

	return err;
}

#if 0
#pragma mark -
#pragma mark Some Methods
#endif
<|endoftext|>


<commit_before>#ifndef RBX_CONFIGURATION_HPP
#define RBX_CONFIGURATION_HPP

#include "util/configuration.hpp"

namespace rubinius {
  class Configuration : public config::Configuration {
  public:
    // GC
    config::Integer gc_bytes;
    config::Integer gc_large_object;
    config::Integer gc_lifetime;
    config::Bool    gc_autotune;
    config::Bool    gc_show;
    config::Bool    gc_immix_debug;

    // JIT/Interpreter
    config::Bool    dynamic_interpreter_enabled;
    config::Integer jit_dump_code;
    config::Integer jit_call_til_compile;
    config::Integer jit_max_method_size;
    config::Bool    jit_show_compiling;
    config::Bool    jit_profile;
    config::Bool    jit_inline_generic;
    config::Bool    jit_inline_debug;
    config::Bool    jit_inline_blocks;
    config::String  jit_log;
    config::Bool    jit_disabled;
    config::Bool    jit_debug;

    // Query Agent
    config::Integer qa_port;
    config::Bool    qa_verbose;

    // Debug
    config::Bool    gil_debug;
    config::Integer print_config;
    config::Bool    ic_stats;
    config::Bool    profile;

    // defaults
    static const int default_gc_bytes = 1048576 * 3;
    static const int default_gc_large_object = 2700;
    static const int default_gc_lifetime = 3;
    static const int default_jit_dump_code = 0;
    static const int default_jit_call_til_compile = 4000;
    static const int default_jit_max_method_size = 2048;
    static const bool default_jit_on = true;
    static const bool default_gc_autotune = true;

    Configuration()
      : gc_bytes(this,        "gc.bytes", default_gc_bytes)
      , gc_large_object(this, "gc.large_object", default_gc_large_object)
      , gc_lifetime(this,     "gc.lifetime", default_gc_lifetime)
      , gc_autotune(this,     "gc.autotune", default_gc_autotune)
      , gc_show(this,         "gc.show")
      , gc_immix_debug(this,  "gc.immix.debug")
      , dynamic_interpreter_enabled(this, "interpreter.dynamic")
      , jit_dump_code(this,   "jit.dump_code", default_jit_dump_code)
      , jit_call_til_compile(this, "jit.call_til_compile",
                             default_jit_call_til_compile)
      , jit_max_method_size(this, "jit.max_method_size",
                            default_jit_max_method_size)
      , jit_show_compiling(this, "jit.show")
      , jit_profile(this,     "jit.profile")
      , jit_inline_generic(this, "jit.inline.generic", true)
      , jit_inline_debug(this, "jit.inline.debug")
      , jit_inline_blocks(this, "jit.inline.blocks")
      , jit_log(this,        "jit.log")
      , jit_disabled(this,   "int")
      , jit_debug(this,      "jit.debug", false)
      , qa_port(this,         "agent.port")
      , qa_verbose(this,      "agent.verbose")
      , gil_debug(this,       "vm.gil.debug")
      , print_config(this,    "config.print")
      , ic_stats(this,        "ic.stats")
      , profile(this,         "profile")
    {
      gc_bytes.set_description(
          "The number of bytes the young generation of the GC should use");

      gc_large_object.set_description(
          "The size (in bytes) of the large object threshold");

      gc_lifetime.set_description(
          "How many young GC cycles an object lives before promoption");

      gc_autotune.set_description(
          "Set whether or not the GC should adjust itself for performance");

      jit_dump_code.set_description(
          "1 == show simple IR, 2 == show optimized IR, 4 == show machine code");

      jit_call_til_compile.set_description(
          "How many times a method is called before the JIT is run on it");

      jit_max_method_size.set_description(
          "The max size of a method that will be JIT");

      jit_show_compiling.set_description(
          "Print out a status message when the JIT is operating");

      jit_profile.set_description(
          "The JIT will emit code to be sure JITd methods can be profile");

      jit_inline_generic.set_description(
          "Have the JIT inline generic methods");

      jit_inline_debug.set_description(
          "Have the JIT print out information about inlining");

      jit_inline_blocks.set_description(
          "Have the JIT try and inline methods and their literal blocks");

      jit_log.set_description(
          "Send JIT debugging output to this file rather than stdout");

      jit_disabled.set_description(
          "Force the JIT to never turn on");

      print_config.set_description(
          "blank or 1 == names and values, 2 == description as well");

      gil_debug.set_description(
          "Print out debugging when the GIL is locked/unlocked");

      gc_show.set_description(
          "Print out whenever the GC runs");

      gc_immix_debug.set_description(
          "Print out collection stats when the Immix collector finishes");

      ic_stats.set_description(
          "Print out stats about the InlineCaches before exiting");

      qa_port.set_description(
          "The TCP port for the query agent to listen on");

      qa_verbose.set_description(
          "Whether or not the query agent should print out status to stderr");

      profile.set_description(
          "Configure the system to profile ruby code");
    }

    void finalize() {
      if(profile) {
        jit_disabled.value = true;
      }
    }
  };
}

#endif
<commit_msg>Rename agent.port to agent.start<commit_after>#ifndef RBX_CONFIGURATION_HPP
#define RBX_CONFIGURATION_HPP

#include "util/configuration.hpp"

namespace rubinius {
  class Configuration : public config::Configuration {
  public:
    // GC
    config::Integer gc_bytes;
    config::Integer gc_large_object;
    config::Integer gc_lifetime;
    config::Bool    gc_autotune;
    config::Bool    gc_show;
    config::Bool    gc_immix_debug;

    // JIT/Interpreter
    config::Bool    dynamic_interpreter_enabled;
    config::Integer jit_dump_code;
    config::Integer jit_call_til_compile;
    config::Integer jit_max_method_size;
    config::Bool    jit_show_compiling;
    config::Bool    jit_profile;
    config::Bool    jit_inline_generic;
    config::Bool    jit_inline_debug;
    config::Bool    jit_inline_blocks;
    config::String  jit_log;
    config::Bool    jit_disabled;
    config::Bool    jit_debug;

    // Query Agent
    config::Integer qa_port;
    config::Bool    qa_verbose;

    // Debug
    config::Bool    gil_debug;
    config::Integer print_config;
    config::Bool    ic_stats;
    config::Bool    profile;

    // defaults
    static const int default_gc_bytes = 1048576 * 3;
    static const int default_gc_large_object = 2700;
    static const int default_gc_lifetime = 3;
    static const int default_jit_dump_code = 0;
    static const int default_jit_call_til_compile = 4000;
    static const int default_jit_max_method_size = 2048;
    static const bool default_jit_on = true;
    static const bool default_gc_autotune = true;

    Configuration()
      : gc_bytes(this,        "gc.bytes", default_gc_bytes)
      , gc_large_object(this, "gc.large_object", default_gc_large_object)
      , gc_lifetime(this,     "gc.lifetime", default_gc_lifetime)
      , gc_autotune(this,     "gc.autotune", default_gc_autotune)
      , gc_show(this,         "gc.show")
      , gc_immix_debug(this,  "gc.immix.debug")
      , dynamic_interpreter_enabled(this, "interpreter.dynamic")
      , jit_dump_code(this,   "jit.dump_code", default_jit_dump_code)
      , jit_call_til_compile(this, "jit.call_til_compile",
                             default_jit_call_til_compile)
      , jit_max_method_size(this, "jit.max_method_size",
                            default_jit_max_method_size)
      , jit_show_compiling(this, "jit.show")
      , jit_profile(this,     "jit.profile")
      , jit_inline_generic(this, "jit.inline.generic", true)
      , jit_inline_debug(this, "jit.inline.debug")
      , jit_inline_blocks(this, "jit.inline.blocks")
      , jit_log(this,        "jit.log")
      , jit_disabled(this,   "int")
      , jit_debug(this,      "jit.debug", false)
      , qa_port(this,         "agent.start")
      , qa_verbose(this,      "agent.verbose")
      , gil_debug(this,       "vm.gil.debug")
      , print_config(this,    "config.print")
      , ic_stats(this,        "ic.stats")
      , profile(this,         "profile")
    {
      gc_bytes.set_description(
          "The number of bytes the young generation of the GC should use");

      gc_large_object.set_description(
          "The size (in bytes) of the large object threshold");

      gc_lifetime.set_description(
          "How many young GC cycles an object lives before promoption");

      gc_autotune.set_description(
          "Set whether or not the GC should adjust itself for performance");

      jit_dump_code.set_description(
          "1 == show simple IR, 2 == show optimized IR, 4 == show machine code");

      jit_call_til_compile.set_description(
          "How many times a method is called before the JIT is run on it");

      jit_max_method_size.set_description(
          "The max size of a method that will be JIT");

      jit_show_compiling.set_description(
          "Print out a status message when the JIT is operating");

      jit_profile.set_description(
          "The JIT will emit code to be sure JITd methods can be profile");

      jit_inline_generic.set_description(
          "Have the JIT inline generic methods");

      jit_inline_debug.set_description(
          "Have the JIT print out information about inlining");

      jit_inline_blocks.set_description(
          "Have the JIT try and inline methods and their literal blocks");

      jit_log.set_description(
          "Send JIT debugging output to this file rather than stdout");

      jit_disabled.set_description(
          "Force the JIT to never turn on");

      print_config.set_description(
          "blank or 1 == names and values, 2 == description as well");

      gil_debug.set_description(
          "Print out debugging when the GIL is locked/unlocked");

      gc_show.set_description(
          "Print out whenever the GC runs");

      gc_immix_debug.set_description(
          "Print out collection stats when the Immix collector finishes");

      ic_stats.set_description(
          "Print out stats about the InlineCaches before exiting");

      qa_port.set_description(
          "Start the QueryAgent on a TCP port. Default port is a random port");

      qa_verbose.set_description(
          "Whether or not the query agent should print out status to stderr");

      profile.set_description(
          "Configure the system to profile ruby code");
    }

    void finalize() {
      if(profile) {
        jit_disabled.value = true;
      }
    }
  };
}

#endif
<|endoftext|>


<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */
/*
 * Copyright (C) 2017 ScyllaDB.
 */

#pragma once

#include <boost/variant.hpp>
#include <boost/version.hpp>

#if (BOOST_VERSION < 105800)

#error "Boost version >= 1.58 is required for using variant visitation helpers."
#error "Earlier versions lack support for return value deduction and move-only return values"

#endif

namespace seastar {

/// \cond internal
namespace internal {

#if __cplusplus >= 201703L // C++17

template<typename... Args>
struct variant_visitor : Args... {
    variant_visitor(Args&&... a) : Args(std::move(a))... {}
    using Args::operator()...;
};

template<typename... Args> variant_visitor(Args&&...) -> variant_visitor<Args...>;

#else

template <typename... Args>
struct variant_visitor;

template <typename FuncObj, typename... Args>
struct variant_visitor<FuncObj, Args...> : FuncObj, variant_visitor<Args...>
{
    variant_visitor(FuncObj&& func_obj, Args&&... args)
        : FuncObj(std::move(func_obj))
        , variant_visitor<Args...>(std::move(args)...) {}

    using FuncObj::operator();
    using variant_visitor<Args...>::operator();
};

template <typename FuncObj>
struct variant_visitor<FuncObj> : FuncObj
{
    variant_visitor(FuncObj&& func_obj) : FuncObj(std::forward<FuncObj>(func_obj)) {}

    using FuncObj::operator();
};

#endif

}
/// \endcond

/// \addtogroup utilities
/// @{

/// Creates a visitor from function objects.
///
/// Returns a visitor object comprised of the provided function objects. Can be
/// used with std::variant, boost::variant or any other custom variant
/// implementation.
///
/// \param args function objects each accepting one or some types stored in the variant as input
template <typename... Args>
auto make_visitor(Args&&... args)
{
    return internal::variant_visitor<Args...>(std::forward<Args>(args)...);
}

/// Applies a static visitor comprised of supplied lambdas to a variant.
/// Note that the lambdas should cover all the types that the variant can possibly hold.
///
/// Returns the common type of return types of all lambdas.
///
/// \tparam Variant the type of a variant
/// \tparam Args types of lambda objects
/// \param variant the variant object
/// \param args lambda objects each accepting one or some types stored in the variant as input
/// \return
template <typename Variant, typename... Args>
inline auto visit(Variant&& variant, Args&&... args)
{
    static_assert(sizeof...(Args) > 0, "At least one lambda must be provided for visitation");
    return boost::apply_visitor(
        make_visitor(std::forward<Args>(args)...),
        std::forward<Variant>(variant));
};

/// @}

}
<commit_msg>variant_utils: don't pass variant by rref to boost::apply_visitor<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */
/*
 * Copyright (C) 2017 ScyllaDB.
 */

#pragma once

#include <boost/variant.hpp>
#include <boost/version.hpp>

#if (BOOST_VERSION < 105800)

#error "Boost version >= 1.58 is required for using variant visitation helpers."
#error "Earlier versions lack support for return value deduction and move-only return values"

#endif

namespace seastar {

/// \cond internal
namespace internal {

#if __cplusplus >= 201703L // C++17

template<typename... Args>
struct variant_visitor : Args... {
    variant_visitor(Args&&... a) : Args(std::move(a))... {}
    using Args::operator()...;
};

template<typename... Args> variant_visitor(Args&&...) -> variant_visitor<Args...>;

#else

template <typename... Args>
struct variant_visitor;

template <typename FuncObj, typename... Args>
struct variant_visitor<FuncObj, Args...> : FuncObj, variant_visitor<Args...>
{
    variant_visitor(FuncObj&& func_obj, Args&&... args)
        : FuncObj(std::move(func_obj))
        , variant_visitor<Args...>(std::move(args)...) {}

    using FuncObj::operator();
    using variant_visitor<Args...>::operator();
};

template <typename FuncObj>
struct variant_visitor<FuncObj> : FuncObj
{
    variant_visitor(FuncObj&& func_obj) : FuncObj(std::forward<FuncObj>(func_obj)) {}

    using FuncObj::operator();
};

#endif

}
/// \endcond

/// \addtogroup utilities
/// @{

/// Creates a visitor from function objects.
///
/// Returns a visitor object comprised of the provided function objects. Can be
/// used with std::variant, boost::variant or any other custom variant
/// implementation.
///
/// \param args function objects each accepting one or some types stored in the variant as input
template <typename... Args>
auto make_visitor(Args&&... args)
{
    return internal::variant_visitor<Args...>(std::forward<Args>(args)...);
}

/// Applies a static visitor comprised of supplied lambdas to a variant.
/// Note that the lambdas should cover all the types that the variant can possibly hold.
///
/// Returns the common type of return types of all lambdas.
///
/// \tparam Variant the type of a variant
/// \tparam Args types of lambda objects
/// \param variant the variant object
/// \param args lambda objects each accepting one or some types stored in the variant as input
/// \return
template <typename Variant, typename... Args>
inline auto visit(Variant&& variant, Args&&... args)
{
    static_assert(sizeof...(Args) > 0, "At least one lambda must be provided for visitation");
    return boost::apply_visitor(
        make_visitor(std::forward<Args>(args)...),
        variant);
};

/// @}

}
<|endoftext|>


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

#include "cyber/common/file.h"

#include <dirent.h>
#include <errno.h>
#include <glob.h>
#include <stddef.h>
#include <unistd.h>
#include <fstream>
#include <string>

namespace apollo {
namespace cyber {
namespace common {

bool SetProtoToASCIIFile(const google::protobuf::Message &message,
                         int file_descriptor) {
  using google::protobuf::TextFormat;
  using google::protobuf::io::FileOutputStream;
  using google::protobuf::io::ZeroCopyOutputStream;
  if (file_descriptor < 0) {
    AERROR << "Invalid file descriptor.";
    return false;
  }
  ZeroCopyOutputStream *output = new FileOutputStream(file_descriptor);
  bool success = TextFormat::Print(message, output);
  delete output;
  close(file_descriptor);
  return success;
}

bool SetProtoToASCIIFile(const google::protobuf::Message &message,
                         const std::string &file_name) {
  int fd = open(file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
  if (fd < 0) {
    AERROR << "Unable to open file " << file_name << " to write.";
    return false;
  }
  return SetProtoToASCIIFile(message, fd);
}

bool GetProtoFromASCIIFile(const std::string &file_name,
                           google::protobuf::Message *message) {
  using google::protobuf::TextFormat;
  using google::protobuf::io::FileInputStream;
  using google::protobuf::io::ZeroCopyInputStream;
  int file_descriptor = open(file_name.c_str(), O_RDONLY);
  if (file_descriptor < 0) {
    AERROR << "Failed to open file " << file_name << " in text mode.";
    // Failed to open;
    return false;
  }

  ZeroCopyInputStream *input = new FileInputStream(file_descriptor);
  bool success = TextFormat::Parse(input, message);
  if (!success) {
    AERROR << "Failed to parse file " << file_name << " as text proto.";
  }
  delete input;
  close(file_descriptor);
  return success;
}

bool SetProtoToBinaryFile(const google::protobuf::Message &message,
                          const std::string &file_name) {
  std::fstream output(file_name,
                      std::ios::out | std::ios::trunc | std::ios::binary);
  return message.SerializeToOstream(&output);
}

bool GetProtoFromBinaryFile(const std::string &file_name,
                            google::protobuf::Message *message) {
  std::fstream input(file_name, std::ios::in | std::ios::binary);
  if (!input.good()) {
    AERROR << "Failed to open file " << file_name << " in binary mode.";
    return false;
  }
  if (!message->ParseFromIstream(&input)) {
    AERROR << "Failed to parse file " << file_name << " as binary proto.";
    return false;
  }
  return true;
}

bool GetProtoFromFile(const std::string &file_name,
                      google::protobuf::Message *message) {
  // Try the binary parser first if it's much likely a binary proto.
  static const std::string kBinExt = ".bin";
  if (std::equal(kBinExt.rbegin(), kBinExt.rend(), file_name.rbegin())) {
    return GetProtoFromBinaryFile(file_name, message) ||
           GetProtoFromASCIIFile(file_name, message);
  }

  return GetProtoFromASCIIFile(file_name, message) ||
         GetProtoFromBinaryFile(file_name, message);
}

bool GetContent(const std::string &file_name, std::string *content) {
  std::ifstream fin(file_name);
  if (!fin) {
    return false;
  }

  std::stringstream str_stream;
  str_stream << fin.rdbuf();
  *content = str_stream.str();
  return true;
}

std::string GetAbsolutePath(const std::string &prefix,
                            const std::string &relative_path) {
  if (relative_path.empty()) {
    return prefix;
  }
  // If prefix is empty or relative_path is already absolute.
  if (prefix.empty() || relative_path.front() == '/') {
    return relative_path;
  }

  if (prefix.back() == '/') {
    return prefix + relative_path;
  }
  return prefix + "/" + relative_path;
}

bool PathExists(const std::string &path) {
  struct stat info;
  return stat(path.c_str(), &info) == 0;
}

bool DirectoryExists(const std::string &directory_path) {
  struct stat info;
  return stat(directory_path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR);
}

std::vector<std::string> Glob(const std::string &pattern) {
  glob_t globs = {};
  std::vector<std::string> results;
  if (glob(pattern.c_str(), GLOB_TILDE, nullptr, &globs) == 0) {
    for (size_t i = 0; i < globs.gl_pathc; ++i) {
      results.emplace_back(globs.gl_pathv[i]);
    }
  }
  globfree(&globs);
  return results;
}

bool CopyFile(const std::string &from, const std::string &to) {
  std::ifstream src(from, std::ios::binary);
  if (!src) {
    AERROR << "Source path doesn't exist: " << from;
    return false;
  }

  std::ofstream dst(to, std::ios::binary);
  if (!dst) {
    AERROR << "Target path is not writable: " << to;
    return false;
  }

  dst << src.rdbuf();
  return true;
}

bool CopyDir(const std::string &from, const std::string &to) {
  DIR *directory = opendir(from.c_str());
  if (directory == nullptr) {
    AERROR << "Cannot open directory " << from;
    return false;
  }

  bool ret = true;
  if (EnsureDirectory(to)) {
    struct dirent *entry;
    while ((entry = readdir(directory)) != nullptr) {
      // skip directory_path/. and directory_path/..
      if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
        continue;
      }
      const std::string sub_path_from = from + "/" + entry->d_name;
      const std::string sub_path_to = to + "/" + entry->d_name;
      if (entry->d_type == DT_DIR) {
        ret &= CopyDir(sub_path_from, sub_path_to);
      } else {
        ret &= CopyFile(sub_path_from, sub_path_to);
      }
    }
  } else {
    AERROR << "Cannot create target directory " << to;
    ret = false;
  }
  closedir(directory);
  return ret;
}

bool Copy(const std::string &from, const std::string &to) {
  return DirectoryExists(from) ? CopyDir(from, to) : CopyFile(from, to);
}

bool EnsureDirectory(const std::string &directory_path) {
  std::string path = directory_path;
  for (size_t i = 1; i < directory_path.size(); ++i) {
    if (directory_path[i] == '/') {
      // Whenever a '/' is encountered, create a temporary view from
      // the start of the path to the character right before this.
      path[i] = 0;

      if (mkdir(path.c_str(), S_IRWXU) != 0) {
        if (errno != EEXIST) {
          return false;
        }
      }

      // Revert the temporary view back to the original.
      path[i] = '/';
    }
  }

  // Make the final (full) directory.
  if (mkdir(path.c_str(), S_IRWXU) != 0) {
    if (errno != EEXIST) {
      return false;
    }
  }

  return true;
}

bool RemoveAllFiles(const std::string &directory_path) {
  DIR *directory = opendir(directory_path.c_str());
  if (directory == nullptr) {
    AERROR << "Cannot open directory " << directory_path;
    return false;
  }

  struct dirent *file;
  while ((file = readdir(directory)) != nullptr) {
    // skip directory_path/. and directory_path/..
    if (!strcmp(file->d_name, ".") || !strcmp(file->d_name, "..")) {
      continue;
    }
    // build the path for each file in the folder
    std::string file_path = directory_path + "/" + file->d_name;
    if (unlink(file_path.c_str()) < 0) {
      AERROR << "Fail to remove file " << file_path << ": " << strerror(errno);
      closedir(directory);
      return false;
    }
  }
  closedir(directory);
  return true;
}

std::vector<std::string> ListSubPaths(const std::string &directory_path,
                                      const unsigned char d_type) {
  std::vector<std::string> result;
  DIR *directory = opendir(directory_path.c_str());
  if (directory == nullptr) {
    AERROR << "Cannot open directory " << directory_path;
    return result;
  }

  struct dirent *entry;
  while ((entry = readdir(directory)) != nullptr) {
    // Skip "." and "..".
    if (entry->d_type == d_type && strcmp(entry->d_name, ".") != 0 &&
        strcmp(entry->d_name, "..") != 0) {
      result.emplace_back(entry->d_name);
    }
  }
  closedir(directory);
  return result;
}

std::string GetFileName(const std::string &path, const bool remove_extension) {
  std::string::size_type start = path.rfind('/');
  if (start == std::string::npos) {
    start = 0;
  } else {
    // Move to the next char after '/'.
    ++start;
  }

  std::string::size_type end = std::string::npos;
  if (remove_extension) {
    end = path.rfind('.');
    // The last '.' is found before last '/', ignore.
    if (end != std::string::npos && end < start) {
      end = std::string::npos;
    }
  }
  const auto len = (end != std::string::npos) ? end - start : end;
  return path.substr(start, len);
}

std::string GetCurrentPath() {
  char tmp[PATH_MAX];
  return getcwd(tmp, sizeof(tmp)) ? std::string(tmp) : std::string("");
}

}  // namespace common
}  // namespace cyber
}  // namespace apollo
<commit_msg>cyber:support to copy softlink file<commit_after>/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "cyber/common/file.h"

#include <dirent.h>
#include <errno.h>
#include <glob.h>
#include <stddef.h>
#include <unistd.h>
#include <fstream>
#include <string>

namespace apollo {
namespace cyber {
namespace common {

bool SetProtoToASCIIFile(const google::protobuf::Message &message,
                         int file_descriptor) {
  using google::protobuf::TextFormat;
  using google::protobuf::io::FileOutputStream;
  using google::protobuf::io::ZeroCopyOutputStream;
  if (file_descriptor < 0) {
    AERROR << "Invalid file descriptor.";
    return false;
  }
  ZeroCopyOutputStream *output = new FileOutputStream(file_descriptor);
  bool success = TextFormat::Print(message, output);
  delete output;
  close(file_descriptor);
  return success;
}

bool SetProtoToASCIIFile(const google::protobuf::Message &message,
                         const std::string &file_name) {
  int fd = open(file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
  if (fd < 0) {
    AERROR << "Unable to open file " << file_name << " to write.";
    return false;
  }
  return SetProtoToASCIIFile(message, fd);
}

bool GetProtoFromASCIIFile(const std::string &file_name,
                           google::protobuf::Message *message) {
  using google::protobuf::TextFormat;
  using google::protobuf::io::FileInputStream;
  using google::protobuf::io::ZeroCopyInputStream;
  int file_descriptor = open(file_name.c_str(), O_RDONLY);
  if (file_descriptor < 0) {
    AERROR << "Failed to open file " << file_name << " in text mode.";
    // Failed to open;
    return false;
  }

  ZeroCopyInputStream *input = new FileInputStream(file_descriptor);
  bool success = TextFormat::Parse(input, message);
  if (!success) {
    AERROR << "Failed to parse file " << file_name << " as text proto.";
  }
  delete input;
  close(file_descriptor);
  return success;
}

bool SetProtoToBinaryFile(const google::protobuf::Message &message,
                          const std::string &file_name) {
  std::fstream output(file_name,
                      std::ios::out | std::ios::trunc | std::ios::binary);
  return message.SerializeToOstream(&output);
}

bool GetProtoFromBinaryFile(const std::string &file_name,
                            google::protobuf::Message *message) {
  std::fstream input(file_name, std::ios::in | std::ios::binary);
  if (!input.good()) {
    AERROR << "Failed to open file " << file_name << " in binary mode.";
    return false;
  }
  if (!message->ParseFromIstream(&input)) {
    AERROR << "Failed to parse file " << file_name << " as binary proto.";
    return false;
  }
  return true;
}

bool GetProtoFromFile(const std::string &file_name,
                      google::protobuf::Message *message) {
  // Try the binary parser first if it's much likely a binary proto.
  static const std::string kBinExt = ".bin";
  if (std::equal(kBinExt.rbegin(), kBinExt.rend(), file_name.rbegin())) {
    return GetProtoFromBinaryFile(file_name, message) ||
           GetProtoFromASCIIFile(file_name, message);
  }

  return GetProtoFromASCIIFile(file_name, message) ||
         GetProtoFromBinaryFile(file_name, message);
}

bool GetContent(const std::string &file_name, std::string *content) {
  std::ifstream fin(file_name);
  if (!fin) {
    return false;
  }

  std::stringstream str_stream;
  str_stream << fin.rdbuf();
  *content = str_stream.str();
  return true;
}

std::string GetAbsolutePath(const std::string &prefix,
                            const std::string &relative_path) {
  if (relative_path.empty()) {
    return prefix;
  }
  // If prefix is empty or relative_path is already absolute.
  if (prefix.empty() || relative_path.front() == '/') {
    return relative_path;
  }

  if (prefix.back() == '/') {
    return prefix + relative_path;
  }
  return prefix + "/" + relative_path;
}

bool PathExists(const std::string &path) {
  struct stat info;
  return stat(path.c_str(), &info) == 0;
}

bool DirectoryExists(const std::string &directory_path) {
  struct stat info;
  return stat(directory_path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR);
}

std::vector<std::string> Glob(const std::string &pattern) {
  glob_t globs = {};
  std::vector<std::string> results;
  if (glob(pattern.c_str(), GLOB_TILDE, nullptr, &globs) == 0) {
    for (size_t i = 0; i < globs.gl_pathc; ++i) {
      results.emplace_back(globs.gl_pathv[i]);
    }
  }
  globfree(&globs);
  return results;
}

bool CopyFile(const std::string &from, const std::string &to) {
  std::ifstream src(from, std::ios::binary);
  if (!src) {
    AWARN << "Source path could not be normally opened: " << from;
    std::string command = "cp -r " + from + " " + to;
    ADEBUG << command;
    const int ret = std::system(command.c_str());
    if (ret == 0) {
      ADEBUG << "Copy success, command returns " << ret;
      return true;
    } else {
      ADEBUG << "Copy error, command returns " << ret;
      return false;
    }
  }

  std::ofstream dst(to, std::ios::binary);
  if (!dst) {
    AERROR << "Target path is not writable: " << to;
    return false;
  }

  dst << src.rdbuf();
  return true;
}

bool CopyDir(const std::string &from, const std::string &to) {
  DIR *directory = opendir(from.c_str());
  if (directory == nullptr) {
    AERROR << "Cannot open directory " << from;
    return false;
  }

  bool ret = true;
  if (EnsureDirectory(to)) {
    struct dirent *entry;
    while ((entry = readdir(directory)) != nullptr) {
      // skip directory_path/. and directory_path/..
      if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
        continue;
      }
      const std::string sub_path_from = from + "/" + entry->d_name;
      const std::string sub_path_to = to + "/" + entry->d_name;
      if (entry->d_type == DT_DIR) {
        ret &= CopyDir(sub_path_from, sub_path_to);
      } else {
        ret &= CopyFile(sub_path_from, sub_path_to);
      }
    }
  } else {
    AERROR << "Cannot create target directory " << to;
    ret = false;
  }
  closedir(directory);
  return ret;
}

bool Copy(const std::string &from, const std::string &to) {
  return DirectoryExists(from) ? CopyDir(from, to) : CopyFile(from, to);
}

bool EnsureDirectory(const std::string &directory_path) {
  std::string path = directory_path;
  for (size_t i = 1; i < directory_path.size(); ++i) {
    if (directory_path[i] == '/') {
      // Whenever a '/' is encountered, create a temporary view from
      // the start of the path to the character right before this.
      path[i] = 0;

      if (mkdir(path.c_str(), S_IRWXU) != 0) {
        if (errno != EEXIST) {
          return false;
        }
      }

      // Revert the temporary view back to the original.
      path[i] = '/';
    }
  }

  // Make the final (full) directory.
  if (mkdir(path.c_str(), S_IRWXU) != 0) {
    if (errno != EEXIST) {
      return false;
    }
  }

  return true;
}

bool RemoveAllFiles(const std::string &directory_path) {
  DIR *directory = opendir(directory_path.c_str());
  if (directory == nullptr) {
    AERROR << "Cannot open directory " << directory_path;
    return false;
  }

  struct dirent *file;
  while ((file = readdir(directory)) != nullptr) {
    // skip directory_path/. and directory_path/..
    if (!strcmp(file->d_name, ".") || !strcmp(file->d_name, "..")) {
      continue;
    }
    // build the path for each file in the folder
    std::string file_path = directory_path + "/" + file->d_name;
    if (unlink(file_path.c_str()) < 0) {
      AERROR << "Fail to remove file " << file_path << ": " << strerror(errno);
      closedir(directory);
      return false;
    }
  }
  closedir(directory);
  return true;
}

std::vector<std::string> ListSubPaths(const std::string &directory_path,
                                      const unsigned char d_type) {
  std::vector<std::string> result;
  DIR *directory = opendir(directory_path.c_str());
  if (directory == nullptr) {
    AERROR << "Cannot open directory " << directory_path;
    return result;
  }

  struct dirent *entry;
  while ((entry = readdir(directory)) != nullptr) {
    // Skip "." and "..".
    if (entry->d_type == d_type && strcmp(entry->d_name, ".") != 0 &&
        strcmp(entry->d_name, "..") != 0) {
      result.emplace_back(entry->d_name);
    }
  }
  closedir(directory);
  return result;
}

std::string GetFileName(const std::string &path, const bool remove_extension) {
  std::string::size_type start = path.rfind('/');
  if (start == std::string::npos) {
    start = 0;
  } else {
    // Move to the next char after '/'.
    ++start;
  }

  std::string::size_type end = std::string::npos;
  if (remove_extension) {
    end = path.rfind('.');
    // The last '.' is found before last '/', ignore.
    if (end != std::string::npos && end < start) {
      end = std::string::npos;
    }
  }
  const auto len = (end != std::string::npos) ? end - start : end;
  return path.substr(start, len);
}

std::string GetCurrentPath() {
  char tmp[PATH_MAX];
  return getcwd(tmp, sizeof(tmp)) ? std::string(tmp) : std::string("");
}

}  // namespace common
}  // namespace cyber
}  // namespace apollo
<|endoftext|>


<commit_before>/*
 * StructureObjectImplementation.cpp
 *
 *  Created on: Aug 15, 2010
 *      Author: crush
 */

#include "StructureObject.h"
#include "server/zone/ZoneServer.h"
#include "server/zone/Zone.h"
#include "server/zone/templates/tangible/SharedStructureObjectTemplate.h"
#include "server/zone/objects/structure/events/StructureMaintenanceTask.h"
#include "server/zone/objects/installation/InstallationObject.h"
#include "server/zone/objects/building/BuildingObject.h"
#include "server/zone/objects/tangible/sign/SignObject.h"
#include "server/zone/managers/player/PlayerManager.h"
#include "server/zone/managers/object/ObjectManager.h"
#include "server/zone/objects/player/PlayerObject.h"

#include "server/zone/objects/player/sessions/vendor/CreateVendorSession.h"

#include "server/zone/objects/player/sui/listbox/SuiListBox.h"
#include "server/zone/objects/player/sui/inputbox/SuiInputBox.h"
#include "server/zone/objects/player/sui/transferbox/SuiTransferBox.h"

#include "server/zone/templates/appearance/MeshAppearanceTemplate.h"
#include "server/zone/templates/appearance/PortalLayout.h"
#include "server/zone/templates/tangible/SharedStructureObjectTemplate.h"

void StructureObjectImplementation::loadTemplateData(SharedObjectTemplate* templateData) {
	TangibleObjectImplementation::loadTemplateData(templateData);

	SharedStructureObjectTemplate* structureTemplate = dynamic_cast<SharedStructureObjectTemplate*>(templateData);

	baseMaintenanceRate = structureTemplate->getBaseMaintenanceRate();

	basePowerRate = structureTemplate->getBasePowerRate();

	structureTemplate->getPortalLayout();
	structureTemplate->getAppearanceTemplate();
}

void StructureObjectImplementation::initializeTransientMembers() {
	TangibleObjectImplementation::initializeTransientMembers();

	Logger::setLoggingName("StructureObject");

	//Schedule maintenance expiration event when everything is loaded, guess 10 minuts?
	//Todo: solve this by either saving scheduled taks somehow or find a way to schedule after
	//everything has been loaded.
	scheduleMaintenanceTask(10 * 60);
}

void StructureObjectImplementation::finalize() {
}

int StructureObjectImplementation::getLotSize() {
	SharedStructureObjectTemplate* ssot = dynamic_cast<SharedStructureObjectTemplate*>(templateObject.get());

	if (ssot == NULL)
		return 0;

	return ssot->getLotSize();
}

CreatureObject* StructureObjectImplementation::getOwnerCreatureObject() {
 	//Get the owner of the structure
 	ManagedReference<SceneObject*> owner = zone->getZoneServer()->getObject(getOwnerObjectID());
 	if (owner != NULL && owner->isCreatureObject()) {
 		return cast<CreatureObject* >(owner.get());
 	} else {
 		return NULL;
 	}
}

float StructureObjectImplementation::getMaintenanceRate() {
	if (maintenanceReduced) {
		return (int)((float)baseMaintenanceRate * 0.8f);
	}

	return baseMaintenanceRate;
}

String StructureObjectImplementation::getMaintenanceMods() {
	if (maintenanceReduced) {
			return "-20%";
	}

	return "-";
}

AABBTree* StructureObjectImplementation::getAABBTree() {
	PortalLayout* portalLayout = templateObject->getPortalLayout();

	if (portalLayout == NULL)
		return NULL;

	MeshAppearanceTemplate* app = portalLayout->getMeshAppearanceTemplate(0);

	return app->getAABBTree();
}

String StructureObjectImplementation::getTimeString(uint32 timestamp) {
	String abbrvs[4] = {"seconds", "minutes", "hours", "days"};

	int intervals[4] = {1, 60, 3600, 86400};
	int values[4] = {0, 0, 0, 0};

	StringBuffer str;

	for (int i = 3; i > -1; --i) {
		values[i] = floor((float)(timestamp / intervals[i]));
		timestamp -= values[i] * intervals[i];

		if (values[i] > 0) {
			if (str.length() > 0)
				str << ", ";

			str << ((i == 0) ? "and " : "") << values[i] << " " << abbrvs[i];
		}
	}

	return str.toString();
}

//Only gets called when maintenance has been changed by an outside source
void StructureObjectImplementation::scheduleMaintenanceExpirationEvent() {
	updateStructureStatus();

	int timeRemaining = (int) (surplusMaintenance * 3600.f / getMaintenanceRate());

	if (timeRemaining < 0) {
		//Decaying structures should be scheduled as soon as possible. Maintenance task will handle
		//any further rescheduling.
		timeRemaining = 1;
	}

	maintenanceExpires.updateToCurrentTime();
	maintenanceExpires.addMiliTime(timeRemaining * 1000);

	scheduleMaintenanceTask(timeRemaining);
}

void StructureObjectImplementation::scheduleMaintenanceTask(int timeFromNow) {
	if (structureMaintenanceTask == NULL) {
		structureMaintenanceTask = new StructureMaintenanceTask(_this);
	}

	if (structureMaintenanceTask->isScheduled()) {
		structureMaintenanceTask->reschedule(timeFromNow * 1000);
	} else {
		structureMaintenanceTask->schedule(timeFromNow * 1000);
	}
}

bool StructureObjectImplementation::isOwnerOf(SceneObject* obj) {
	if (obj->isCreatureObject()) {
		ManagedReference<PlayerObject*> ghost = (cast<CreatureObject*>( obj))->getPlayerObject();

		if (ghost->isPrivileged())
			return true;
	}

	return obj->getObjectID() == ownerObjectID;
}

bool StructureObjectImplementation::isOwnerOf(uint64 objid) {
	ManagedReference<SceneObject*> obj = server->getZoneServer()->getObject(objid);

	if (obj != NULL && obj->isPlayerCreature()) {
		CreatureObject* player = cast<CreatureObject*>( obj.get());

		if (player->getPlayerObject()->isPrivileged())
			return true;
	}

	return objid == ownerObjectID;
}

void StructureObjectImplementation::createVendor(CreatureObject* player) {
	if (!isPublicStructure()) {
		player->sendSystemMessage("@player_structure:vendor_public_only");
		return;
	}

	//Create Session
	ManagedReference<CreateVendorSession*> session = new CreateVendorSession(player);
	session->initalizeWindow(player);

}

void StructureObjectImplementation::updateStructureStatus() {
	/** Points when updateStructureStatus should occur:
	 * Prior to inserting or withdrawing maintenance or power, and after the deposit/withdrawal.
	 * When requesting a Structure Status report.
	 * When correct maintenance/power values are needed.
	 * Any time the maintenance or power surplus is changed by a hand other than this method.
	 */
	float timeDiff = ((float) lastUpdateTimestamp.miliDifference()) / 1000.f;

	float maintenanceDue = (getMaintenanceRate() / 3600.f) * timeDiff;
	float powerDue = ((float) basePowerRate / 3600.f) * timeDiff;

	if (maintenanceDue > 0 || powerDue > 0) {
		//Only update last time if we actually progressed to get correct consumption.
		lastUpdateTimestamp.updateToCurrentTime();
	}

	//Maintenance is used as decay as well so let it go below 0.
	surplusMaintenance -= maintenanceDue;

	if (surplusPower > 0.f)
		surplusPower -= powerDue;
	//else if installation, shutdown.
}

bool StructureObjectImplementation::isDecayed() {
	return (getDecayPercentage() == 0);
}

int StructureObjectImplementation::getDecayPercentage() {
	//It takes 4 weeks for a building to decay.
	//Todo: Correct the decay time.
	int decayedBelowMaintenance = (baseMaintenanceRate * 24 * 7 *4);
	int percentage = (decayedBelowMaintenance + surplusMaintenance) * 100 / decayedBelowMaintenance;
	//Calculation above truncates the percentage value but we want to round it upwards.
	percentage += 1;
	if (percentage < 0) {
		percentage = 0;
	} else if (percentage > 100) {
		percentage = 100;
	}
	return percentage;
}

void StructureObjectImplementation::payMaintenance(int maintenance, CreatureObject* payer) {
	//Pay maintenance.
	payer->substractBankCredits(maintenance);
	addMaintenance(maintenance);

	//Update maintenance reduced.
	ManagedReference<PlayerObject* > ghost = payer->getPlayerObject();
	if (ghost != NULL) {
		setMaintenanceReduced(ghost->hasAbility("maintenance_fees_1"));
	} else {
		setMaintenanceReduced(false);
	}
}
<commit_msg>[fixed] crash<commit_after>/*
 * StructureObjectImplementation.cpp
 *
 *  Created on: Aug 15, 2010
 *      Author: crush
 */

#include "StructureObject.h"
#include "server/zone/ZoneServer.h"
#include "server/zone/Zone.h"
#include "server/zone/templates/tangible/SharedStructureObjectTemplate.h"
#include "server/zone/objects/structure/events/StructureMaintenanceTask.h"
#include "server/zone/objects/installation/InstallationObject.h"
#include "server/zone/objects/building/BuildingObject.h"
#include "server/zone/objects/tangible/sign/SignObject.h"
#include "server/zone/managers/player/PlayerManager.h"
#include "server/zone/managers/object/ObjectManager.h"
#include "server/zone/objects/player/PlayerObject.h"

#include "server/zone/objects/player/sessions/vendor/CreateVendorSession.h"

#include "server/zone/objects/player/sui/listbox/SuiListBox.h"
#include "server/zone/objects/player/sui/inputbox/SuiInputBox.h"
#include "server/zone/objects/player/sui/transferbox/SuiTransferBox.h"

#include "server/zone/templates/appearance/MeshAppearanceTemplate.h"
#include "server/zone/templates/appearance/PortalLayout.h"
#include "server/zone/templates/tangible/SharedStructureObjectTemplate.h"

void StructureObjectImplementation::loadTemplateData(SharedObjectTemplate* templateData) {
	TangibleObjectImplementation::loadTemplateData(templateData);

	SharedStructureObjectTemplate* structureTemplate = dynamic_cast<SharedStructureObjectTemplate*>(templateData);

	baseMaintenanceRate = structureTemplate->getBaseMaintenanceRate();

	basePowerRate = structureTemplate->getBasePowerRate();

	structureTemplate->getPortalLayout();
	structureTemplate->getAppearanceTemplate();
}

void StructureObjectImplementation::initializeTransientMembers() {
	TangibleObjectImplementation::initializeTransientMembers();

	Logger::setLoggingName("StructureObject");

	//Schedule maintenance expiration event when everything is loaded, guess 10 minuts?
	//Todo: solve this by either saving scheduled taks somehow or find a way to schedule after
	//everything has been loaded.
	scheduleMaintenanceTask(10 * 60);
}

void StructureObjectImplementation::finalize() {
}

int StructureObjectImplementation::getLotSize() {
	SharedStructureObjectTemplate* ssot = dynamic_cast<SharedStructureObjectTemplate*>(templateObject.get());

	if (ssot == NULL)
		return 0;

	return ssot->getLotSize();
}

CreatureObject* StructureObjectImplementation::getOwnerCreatureObject() {
 	//Get the owner of the structure
 	ManagedReference<SceneObject*> owner = getZoneServer()->getObject(getOwnerObjectID());

 	if (owner != NULL && owner->isCreatureObject()) {
 		return cast<CreatureObject* >(owner.get());
 	} else {
 		return NULL;
 	}
}

float StructureObjectImplementation::getMaintenanceRate() {
	if (maintenanceReduced) {
		return (int)((float)baseMaintenanceRate * 0.8f);
	}

	return baseMaintenanceRate;
}

String StructureObjectImplementation::getMaintenanceMods() {
	if (maintenanceReduced) {
			return "-20%";
	}

	return "-";
}

AABBTree* StructureObjectImplementation::getAABBTree() {
	PortalLayout* portalLayout = templateObject->getPortalLayout();

	if (portalLayout == NULL)
		return NULL;

	MeshAppearanceTemplate* app = portalLayout->getMeshAppearanceTemplate(0);

	return app->getAABBTree();
}

String StructureObjectImplementation::getTimeString(uint32 timestamp) {
	String abbrvs[4] = {"seconds", "minutes", "hours", "days"};

	int intervals[4] = {1, 60, 3600, 86400};
	int values[4] = {0, 0, 0, 0};

	StringBuffer str;

	for (int i = 3; i > -1; --i) {
		values[i] = floor((float)(timestamp / intervals[i]));
		timestamp -= values[i] * intervals[i];

		if (values[i] > 0) {
			if (str.length() > 0)
				str << ", ";

			str << ((i == 0) ? "and " : "") << values[i] << " " << abbrvs[i];
		}
	}

	return str.toString();
}

//Only gets called when maintenance has been changed by an outside source
void StructureObjectImplementation::scheduleMaintenanceExpirationEvent() {
	updateStructureStatus();

	int timeRemaining = (int) (surplusMaintenance * 3600.f / getMaintenanceRate());

	if (timeRemaining < 0) {
		//Decaying structures should be scheduled as soon as possible. Maintenance task will handle
		//any further rescheduling.
		timeRemaining = 1;
	}

	maintenanceExpires.updateToCurrentTime();
	maintenanceExpires.addMiliTime(timeRemaining * 1000);

	scheduleMaintenanceTask(timeRemaining);
}

void StructureObjectImplementation::scheduleMaintenanceTask(int timeFromNow) {
	if (structureMaintenanceTask == NULL) {
		structureMaintenanceTask = new StructureMaintenanceTask(_this);
	}

	if (structureMaintenanceTask->isScheduled()) {
		structureMaintenanceTask->reschedule(timeFromNow * 1000);
	} else {
		structureMaintenanceTask->schedule(timeFromNow * 1000);
	}
}

bool StructureObjectImplementation::isOwnerOf(SceneObject* obj) {
	if (obj->isCreatureObject()) {
		ManagedReference<PlayerObject*> ghost = (cast<CreatureObject*>( obj))->getPlayerObject();

		if (ghost->isPrivileged())
			return true;
	}

	return obj->getObjectID() == ownerObjectID;
}

bool StructureObjectImplementation::isOwnerOf(uint64 objid) {
	ManagedReference<SceneObject*> obj = server->getZoneServer()->getObject(objid);

	if (obj != NULL && obj->isPlayerCreature()) {
		CreatureObject* player = cast<CreatureObject*>( obj.get());

		if (player->getPlayerObject()->isPrivileged())
			return true;
	}

	return objid == ownerObjectID;
}

void StructureObjectImplementation::createVendor(CreatureObject* player) {
	if (!isPublicStructure()) {
		player->sendSystemMessage("@player_structure:vendor_public_only");
		return;
	}

	//Create Session
	ManagedReference<CreateVendorSession*> session = new CreateVendorSession(player);
	session->initalizeWindow(player);

}

void StructureObjectImplementation::updateStructureStatus() {
	/** Points when updateStructureStatus should occur:
	 * Prior to inserting or withdrawing maintenance or power, and after the deposit/withdrawal.
	 * When requesting a Structure Status report.
	 * When correct maintenance/power values are needed.
	 * Any time the maintenance or power surplus is changed by a hand other than this method.
	 */
	float timeDiff = ((float) lastUpdateTimestamp.miliDifference()) / 1000.f;

	float maintenanceDue = (getMaintenanceRate() / 3600.f) * timeDiff;
	float powerDue = ((float) basePowerRate / 3600.f) * timeDiff;

	if (maintenanceDue > 0 || powerDue > 0) {
		//Only update last time if we actually progressed to get correct consumption.
		lastUpdateTimestamp.updateToCurrentTime();
	}

	//Maintenance is used as decay as well so let it go below 0.
	surplusMaintenance -= maintenanceDue;

	if (surplusPower > 0.f)
		surplusPower -= powerDue;
	//else if installation, shutdown.
}

bool StructureObjectImplementation::isDecayed() {
	return (getDecayPercentage() == 0);
}

int StructureObjectImplementation::getDecayPercentage() {
	//It takes 4 weeks for a building to decay.
	//Todo: Correct the decay time.
	int decayedBelowMaintenance = (baseMaintenanceRate * 24 * 7 *4);
	int percentage = (decayedBelowMaintenance + surplusMaintenance) * 100 / decayedBelowMaintenance;
	//Calculation above truncates the percentage value but we want to round it upwards.
	percentage += 1;
	if (percentage < 0) {
		percentage = 0;
	} else if (percentage > 100) {
		percentage = 100;
	}
	return percentage;
}

void StructureObjectImplementation::payMaintenance(int maintenance, CreatureObject* payer) {
	//Pay maintenance.
	payer->substractBankCredits(maintenance);
	addMaintenance(maintenance);

	//Update maintenance reduced.
	ManagedReference<PlayerObject* > ghost = payer->getPlayerObject();
	if (ghost != NULL) {
		setMaintenanceReduced(ghost->hasAbility("maintenance_fees_1"));
	} else {
		setMaintenanceReduced(false);
	}
}
<|endoftext|>