<commit_before>// Copyright (c) 2011 Timur Iskhodzhanov and MIPT students. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// author: Dima Arkhangelskiy
// project: Math Expression Analyser and Calculator

#include "gtest/gtest.h"

class MathExpressionCalculator {
 public:
  enum StatusCode {
    kOk = 0,
    kDivisionByZero,
    kEmptyExpression,
    kSyntaxError,
    kUndefinedStatus,
    kUndefinedVariable,
    kUnbalancedParentheses
  };

  MathExpressionCalculator() {}

  StatusCode Calculate(const char *expr, double *result) {
    return kUndefinedStatus;
  }

  void SetVariable(const char *var_name, double value) {
    return;
  }

  // Find value by name. If there isn't variable with
  // such name return false.
  bool Lookup(const char *var_name, double *out_value) {
    return false;
  }
};

TEST(MathExpressionTests, DISABLED_SimpleExpressions) {
  MathExpressionCalculator calc;
  double result;

  // For each expression, check it is parsed and calculated correctly.
  ASSERT_EQ(calc.kOk, calc.Calculate("1 + 2", &result));
  ASSERT_DOUBLE_EQ(3.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("10 - 5", &result));
  ASSERT_DOUBLE_EQ(5.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("2 * 3", &result));
  ASSERT_DOUBLE_EQ(6.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("6 / 3", &result));
  ASSERT_DOUBLE_EQ(2.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("10 % 3", &result));
  ASSERT_DOUBLE_EQ(1.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("2 ^ 3", &result));
  ASSERT_DOUBLE_EQ(8.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("2 + 3 * 2", &result));
  ASSERT_DOUBLE_EQ(8.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("(2 + 3) * 2", &result));
  ASSERT_DOUBLE_EQ(10.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("7 + 6 * 20 / 5/ 4 - 3", &result));
  ASSERT_DOUBLE_EQ(10.0, result);
}

TEST(MathExpressionTests, DISABLED_ErrorHandling) {
  MathExpressionCalculator calc;
  double result;

  ASSERT_EQ(MathExpressionCalculator::kSyntaxError,
            calc.Calculate("2***2", &result));

  ASSERT_EQ(MathExpressionCalculator::kEmptyExpression,
            calc.Calculate("", &result));

  ASSERT_EQ(MathExpressionCalculator::kUnbalancedParentheses,
            calc.Calculate("((2 + 3)", &result));

  ASSERT_EQ(MathExpressionCalculator::kDivisionByZero,
            calc.Calculate("2 / 0", &result));
}

TEST(MathExpressionTests, DISABLED_VariableHandling) {
  MathExpressionCalculator calc;
  calc.SetVariable("x", 10);

  // Check the variable value is stored correctly.
  double var;
  ASSERT_TRUE(calc.Lookup("x", &var));
  ASSERT_DOUBLE_EQ(10.0, var);

  // Check that we use variable correctly.
  double result, default_result;
  ASSERT_EQ(calc.kOk, calc.Calculate("2 * 10 + 1", &default_result));

  ASSERT_EQ(calc.kOk, calc.Calculate("2 * x + 1", &result));

  ASSERT_DOUBLE_EQ(21.0, default_result);
  ASSERT_DOUBLE_EQ(default_result, result);
}

TEST(MathExpressionTests, DISABLED_UndefinedVariable) {
  MathExpressionCalculator calc;
  double var, result;
  ASSERT_FALSE(calc.Lookup("x", &var));
  ASSERT_EQ(MathExpressionCalculator::kUndefinedVariable,
            calc.Calculate("2 * x + 1", &result));
}

<commit_msg>Fix the uninitialized variable in MathExpressionTests<commit_after>// Copyright (c) 2011 Timur Iskhodzhanov and MIPT students. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// author: Dima Arkhangelskiy
// project: Math Expression Analyser and Calculator

#include "gtest/gtest.h"

class MathExpressionCalculator {
 public:
  enum StatusCode {
    kOk = 0,
    kDivisionByZero,
    kEmptyExpression,
    kSyntaxError,
    kUndefinedStatus,
    kUndefinedVariable,
    kUnbalancedParentheses
  };

  MathExpressionCalculator() {}

  StatusCode Calculate(const char *expr, double *result) {
    return kUndefinedStatus;
  }

  void SetVariable(const char *var_name, double value) {
    return;
  }

  // Find value by name. If there isn't variable with
  // such name return false.
  bool Lookup(const char *var_name, double *out_value) {
    return false;
  }
};

TEST(MathExpressionTests, DISABLED_SimpleExpressions) {
  MathExpressionCalculator calc;
  double result = 42.0;

  // For each expression, check it is parsed and calculated correctly.
  ASSERT_EQ(calc.kOk, calc.Calculate("1 + 2", &result));
  ASSERT_DOUBLE_EQ(3.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("10 - 5", &result));
  ASSERT_DOUBLE_EQ(5.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("2 * 3", &result));
  ASSERT_DOUBLE_EQ(6.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("6 / 3", &result));
  ASSERT_DOUBLE_EQ(2.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("10 % 3", &result));
  ASSERT_DOUBLE_EQ(1.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("2 ^ 3", &result));
  ASSERT_DOUBLE_EQ(8.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("2 + 3 * 2", &result));
  ASSERT_DOUBLE_EQ(8.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("(2 + 3) * 2", &result));
  ASSERT_DOUBLE_EQ(10.0, result);

  ASSERT_EQ(calc.kOk, calc.Calculate("7 + 6 * 20 / 5/ 4 - 3", &result));
  ASSERT_DOUBLE_EQ(10.0, result);
}

TEST(MathExpressionTests, DISABLED_ErrorHandling) {
  MathExpressionCalculator calc;
  double result;

  ASSERT_EQ(MathExpressionCalculator::kSyntaxError,
            calc.Calculate("2***2", &result));

  ASSERT_EQ(MathExpressionCalculator::kEmptyExpression,
            calc.Calculate("", &result));

  ASSERT_EQ(MathExpressionCalculator::kUnbalancedParentheses,
            calc.Calculate("((2 + 3)", &result));

  ASSERT_EQ(MathExpressionCalculator::kDivisionByZero,
            calc.Calculate("2 / 0", &result));
}

TEST(MathExpressionTests, DISABLED_VariableHandling) {
  MathExpressionCalculator calc;
  calc.SetVariable("x", 10);

  // Check the variable value is stored correctly.
  double var;
  ASSERT_TRUE(calc.Lookup("x", &var));
  ASSERT_DOUBLE_EQ(10.0, var);

  // Check that we use variable correctly.
  double result, default_result;
  ASSERT_EQ(calc.kOk, calc.Calculate("2 * 10 + 1", &default_result));

  ASSERT_EQ(calc.kOk, calc.Calculate("2 * x + 1", &result));

  ASSERT_DOUBLE_EQ(21.0, default_result);
  ASSERT_DOUBLE_EQ(default_result, result);
}

TEST(MathExpressionTests, DISABLED_UndefinedVariable) {
  MathExpressionCalculator calc;
  double var, result;
  ASSERT_FALSE(calc.Lookup("x", &var));
  ASSERT_EQ(MathExpressionCalculator::kUndefinedVariable,
            calc.Calculate("2 * x + 1", &result));
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dp_ucb.cxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: ihi $ $Date: 2007-06-05 15:05:48 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_desktop.hxx"

#include "dp_misc.hrc"
#include "dp_misc.h"
#include "dp_ucb.h"
#include "rtl/uri.hxx"
#include "rtl/ustrbuf.hxx"
#include "ucbhelper/content.hxx"
#include "xmlscript/xml_helper.hxx"
#include "com/sun/star/io/XInputStream.hpp"
#include "com/sun/star/ucb/CommandFailedException.hpp"
#include "com/sun/star/ucb/XContentCreator.hpp"
#include "com/sun/star/ucb/ContentInfo.hpp"
#include "com/sun/star/ucb/ContentInfoAttribute.hpp"

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::ucb;
using ::rtl::OUString;

namespace dp_misc
{

const OUString StrTitle::operator () ()
{
    return OUSTR("Title");
}

//==============================================================================
bool create_ucb_content(
    ::ucbhelper::Content * ret_ucbContent, OUString const & url,
    Reference<XCommandEnvironment> const & xCmdEnv,
    bool throw_exc )
{
    try {
        // dilemma: no chance to use the given iahandler here, because it would
        //          raise no such file dialogs, else no interaction for
        //          passwords, ...? xxx todo
        ::ucbhelper::Content ucbContent(
            url, Reference<XCommandEnvironment>() );
        if (! ucbContent.isFolder())
            ucbContent.openStream()->closeInput();
        if (ret_ucbContent != 0)
            *ret_ucbContent = ::ucbhelper::Content( url, xCmdEnv );
        return true;
    }
    catch (RuntimeException &) {
        throw;
    }
    catch (Exception &) {
        if (throw_exc)
            throw;
    }
    return false;
}

//==============================================================================
bool create_folder(
    ::ucbhelper::Content * ret_ucb_content, OUString const & url_,
    Reference<XCommandEnvironment> const & xCmdEnv, bool throw_exc )
{
    ::ucbhelper::Content ucb_content;
    if (create_ucb_content(
            &ucb_content, url_, xCmdEnv, false /* no throw */ ))
    {
        if (ucb_content.isFolder()) {
            if (ret_ucb_content != 0)
                *ret_ucb_content = ucb_content;
            return true;
        }
    }

    OUString url( url_ );
    // xxx todo: find parent
    sal_Int32 slash = url.lastIndexOf( '/' );
    if (slash < 0) {
        // fallback:
        url = expandUnoRcUrl( url );
        slash = url.lastIndexOf( '/' );
    }
    if (slash < 0) {
        // invalid: has to be at least "auth:/..."
        if (throw_exc)
            throw ContentCreationException(
                OUSTR("Cannot create folder (invalid path): ") + url,
                Reference<XInterface>(), ContentCreationError_UNKNOWN );
        return false;
    }
    ::ucbhelper::Content parentContent;
    if (! create_folder(
            &parentContent, url.copy( 0, slash ), xCmdEnv, throw_exc ))
        return false;
    Reference<XContentCreator> xCreator( parentContent.get(), UNO_QUERY );
    if (xCreator.is())
    {
        const Any title( ::rtl::Uri::decode( url.copy( slash + 1 ),
                                             rtl_UriDecodeWithCharset,
                                             RTL_TEXTENCODING_UTF8 ) );
        const Sequence<ContentInfo> infos(
            xCreator->queryCreatableContentsInfo() );
        for ( sal_Int32 pos = 0; pos < infos.getLength(); ++pos )
        {
            // look KIND_FOLDER:
            ContentInfo const & info = infos[ pos ];
            if ((info.Attributes & ContentInfoAttribute::KIND_FOLDER) != 0)
            {
                // make sure the only required bootstrap property is "Title":
                Sequence<beans::Property> const & rProps = info.Properties;
                if (rProps.getLength() != 1 ||
                    !rProps[ 0 ].Name.equalsAsciiL(
                        RTL_CONSTASCII_STRINGPARAM("Title") ))
                    continue;

                try {
                    if (parentContent.insertNewContent(
                            info.Type,
                            Sequence<OUString>( &StrTitle::get(), 1 ),
                            Sequence<Any>( &title, 1 ),
                            ucb_content )) {
                        if (ret_ucb_content != 0)
                            *ret_ucb_content = ucb_content;
                        return true;
                    }
                }
                catch (RuntimeException &) {
                    throw;
                }
                catch (CommandFailedException &) {
                    // Interaction Handler already handled the error
                    // that has occured...
                }
                catch (Exception &) {
                    if (throw_exc)
                        throw;
                    return false;
                }
            }
        }
    }
    if (throw_exc)
        throw ContentCreationException(
            OUSTR("Cannot create folder: ") + url,
            Reference<XInterface>(), ContentCreationError_UNKNOWN );
    return false;
}

//==============================================================================
bool erase_path( OUString const & url,
                 Reference<XCommandEnvironment> const & xCmdEnv,
                 bool throw_exc )
{
    ::ucbhelper::Content ucb_content;
    if (create_ucb_content( &ucb_content, url, xCmdEnv, false /* no throw */ ))
    {
        try {
            ucb_content.executeCommand(
                OUSTR("delete"), Any( true /* delete physically */ ) );
        }
        catch (RuntimeException &) {
            throw;
        }
        catch (Exception &) {
            if (throw_exc)
                throw;
            return false;
        }
    }
    return true;
}

//==============================================================================
::rtl::ByteSequence readFile( ::ucbhelper::Content & ucb_content )
{
    ::rtl::ByteSequence bytes;
    Reference<io::XOutputStream> xStream(
        ::xmlscript::createOutputStream( &bytes ) );
    if (! ucb_content.openStream( xStream ))
        throw RuntimeException(
            OUSTR(
                "::ucbhelper::Content::openStream( XOutputStream ) failed!"),
            0 );
    return bytes;
}

//==============================================================================
bool readLine( OUString * res, OUString const & startingWith,
               ::ucbhelper::Content & ucb_content, rtl_TextEncoding textenc )
{
    // read whole file:
    ::rtl::ByteSequence bytes( readFile( ucb_content ) );
    OUString file( reinterpret_cast<sal_Char const *>(bytes.getConstArray()),
                   bytes.getLength(), textenc );
    sal_Int32 pos = 0;
    for (;;)
    {
        if (file.match( startingWith, pos ))
        {
            ::rtl::OUStringBuffer buf;
            sal_Int32 start = pos;
            pos += startingWith.getLength();
            for (;;)
            {
                pos = file.indexOf( LF, pos );
                if (pos < 0) { // EOF
                    buf.append( file.copy( start ) );
                }
                else
                {
                    if (pos > 0 && file[ pos - 1 ] == CR)
                    {
                        // consume extra CR
                        buf.append( file.copy( start, pos - start - 1 ) );
                        ++pos;
                    }
                    else
                        buf.append( file.copy( start, pos - start ) );
                    ++pos; // consume LF
                    // check next line:
                    if (pos < file.getLength() &&
                        (file[ pos ] == ' ' || file[ pos ] == '\t'))
                    {
                        buf.append( static_cast<sal_Unicode>(' ') );
                        ++pos;
                        start = pos;
                        continue;
                    }
                }
                break;
            }
            *res = buf.makeStringAndClear();
            return true;
        }
        // next line:
        sal_Int32 next_lf = file.indexOf( LF, pos );
        if (next_lf < 0) // EOF
            break;
        pos = next_lf + 1;
    }
    return false;
}

}
<commit_msg>INTEGRATION: CWS ucbfixes04 (1.11.138); FILE MERGED 2007/12/06 15:33:29 kso 1.11.138.1: #81459# - Removed useless openStream() call from create_ucb_content(). Issue number: Submitted by: Reviewed by:<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dp_ucb.cxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: obo $ $Date: 2008-01-04 14:34:05 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_desktop.hxx"

#include "dp_misc.hrc"
#include "dp_misc.h"
#include "dp_ucb.h"
#include "rtl/uri.hxx"
#include "rtl/ustrbuf.hxx"
#include "ucbhelper/content.hxx"
#include "xmlscript/xml_helper.hxx"
#include "com/sun/star/io/XInputStream.hpp"
#include "com/sun/star/ucb/CommandFailedException.hpp"
#include "com/sun/star/ucb/XContentCreator.hpp"
#include "com/sun/star/ucb/ContentInfo.hpp"
#include "com/sun/star/ucb/ContentInfoAttribute.hpp"

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::ucb;
using ::rtl::OUString;

namespace dp_misc
{

const OUString StrTitle::operator () ()
{
    return OUSTR("Title");
}

//==============================================================================
bool create_ucb_content(
    ::ucbhelper::Content * ret_ucbContent, OUString const & url,
    Reference<XCommandEnvironment> const & xCmdEnv,
    bool throw_exc )
{
    try {
        // Existense check...
        // content ctor/isFolder() will throw exception in case the resource
        // does not exist.

        // dilemma: no chance to use the given iahandler here, because it would
        //          raise no such file dialogs, else no interaction for
        //          passwords, ...? xxx todo
        ::ucbhelper::Content ucbContent(
            url, Reference<XCommandEnvironment>() );

        ucbContent.isFolder();

        if (ret_ucbContent != 0)
        {
            ucbContent.setCommandEnvironment( xCmdEnv );
            *ret_ucbContent = ucbContent;
        }
        return true;
    }
    catch (RuntimeException &) {
        throw;
    }
    catch (Exception &) {
        if (throw_exc)
            throw;
    }
    return false;
}

//==============================================================================
bool create_folder(
    ::ucbhelper::Content * ret_ucb_content, OUString const & url_,
    Reference<XCommandEnvironment> const & xCmdEnv, bool throw_exc )
{
    ::ucbhelper::Content ucb_content;
    if (create_ucb_content(
            &ucb_content, url_, xCmdEnv, false /* no throw */ ))
    {
        if (ucb_content.isFolder()) {
            if (ret_ucb_content != 0)
                *ret_ucb_content = ucb_content;
            return true;
        }
    }

    OUString url( url_ );
    // xxx todo: find parent
    sal_Int32 slash = url.lastIndexOf( '/' );
    if (slash < 0) {
        // fallback:
        url = expandUnoRcUrl( url );
        slash = url.lastIndexOf( '/' );
    }
    if (slash < 0) {
        // invalid: has to be at least "auth:/..."
        if (throw_exc)
            throw ContentCreationException(
                OUSTR("Cannot create folder (invalid path): ") + url,
                Reference<XInterface>(), ContentCreationError_UNKNOWN );
        return false;
    }
    ::ucbhelper::Content parentContent;
    if (! create_folder(
            &parentContent, url.copy( 0, slash ), xCmdEnv, throw_exc ))
        return false;
    Reference<XContentCreator> xCreator( parentContent.get(), UNO_QUERY );
    if (xCreator.is())
    {
        const Any title( ::rtl::Uri::decode( url.copy( slash + 1 ),
                                             rtl_UriDecodeWithCharset,
                                             RTL_TEXTENCODING_UTF8 ) );
        const Sequence<ContentInfo> infos(
            xCreator->queryCreatableContentsInfo() );
        for ( sal_Int32 pos = 0; pos < infos.getLength(); ++pos )
        {
            // look KIND_FOLDER:
            ContentInfo const & info = infos[ pos ];
            if ((info.Attributes & ContentInfoAttribute::KIND_FOLDER) != 0)
            {
                // make sure the only required bootstrap property is "Title":
                Sequence<beans::Property> const & rProps = info.Properties;
                if (rProps.getLength() != 1 ||
                    !rProps[ 0 ].Name.equalsAsciiL(
                        RTL_CONSTASCII_STRINGPARAM("Title") ))
                    continue;

                try {
                    if (parentContent.insertNewContent(
                            info.Type,
                            Sequence<OUString>( &StrTitle::get(), 1 ),
                            Sequence<Any>( &title, 1 ),
                            ucb_content )) {
                        if (ret_ucb_content != 0)
                            *ret_ucb_content = ucb_content;
                        return true;
                    }
                }
                catch (RuntimeException &) {
                    throw;
                }
                catch (CommandFailedException &) {
                    // Interaction Handler already handled the error
                    // that has occured...
                }
                catch (Exception &) {
                    if (throw_exc)
                        throw;
                    return false;
                }
            }
        }
    }
    if (throw_exc)
        throw ContentCreationException(
            OUSTR("Cannot create folder: ") + url,
            Reference<XInterface>(), ContentCreationError_UNKNOWN );
    return false;
}

//==============================================================================
bool erase_path( OUString const & url,
                 Reference<XCommandEnvironment> const & xCmdEnv,
                 bool throw_exc )
{
    ::ucbhelper::Content ucb_content;
    if (create_ucb_content( &ucb_content, url, xCmdEnv, false /* no throw */ ))
    {
        try {
            ucb_content.executeCommand(
                OUSTR("delete"), Any( true /* delete physically */ ) );
        }
        catch (RuntimeException &) {
            throw;
        }
        catch (Exception &) {
            if (throw_exc)
                throw;
            return false;
        }
    }
    return true;
}

//==============================================================================
::rtl::ByteSequence readFile( ::ucbhelper::Content & ucb_content )
{
    ::rtl::ByteSequence bytes;
    Reference<io::XOutputStream> xStream(
        ::xmlscript::createOutputStream( &bytes ) );
    if (! ucb_content.openStream( xStream ))
        throw RuntimeException(
            OUSTR(
                "::ucbhelper::Content::openStream( XOutputStream ) failed!"),
            0 );
    return bytes;
}

//==============================================================================
bool readLine( OUString * res, OUString const & startingWith,
               ::ucbhelper::Content & ucb_content, rtl_TextEncoding textenc )
{
    // read whole file:
    ::rtl::ByteSequence bytes( readFile( ucb_content ) );
    OUString file( reinterpret_cast<sal_Char const *>(bytes.getConstArray()),
                   bytes.getLength(), textenc );
    sal_Int32 pos = 0;
    for (;;)
    {
        if (file.match( startingWith, pos ))
        {
            ::rtl::OUStringBuffer buf;
            sal_Int32 start = pos;
            pos += startingWith.getLength();
            for (;;)
            {
                pos = file.indexOf( LF, pos );
                if (pos < 0) { // EOF
                    buf.append( file.copy( start ) );
                }
                else
                {
                    if (pos > 0 && file[ pos - 1 ] == CR)
                    {
                        // consume extra CR
                        buf.append( file.copy( start, pos - start - 1 ) );
                        ++pos;
                    }
                    else
                        buf.append( file.copy( start, pos - start ) );
                    ++pos; // consume LF
                    // check next line:
                    if (pos < file.getLength() &&
                        (file[ pos ] == ' ' || file[ pos ] == '\t'))
                    {
                        buf.append( static_cast<sal_Unicode>(' ') );
                        ++pos;
                        start = pos;
                        continue;
                    }
                }
                break;
            }
            *res = buf.makeStringAndClear();
            return true;
        }
        // next line:
        sal_Int32 next_lf = file.indexOf( LF, pos );
        if (next_lf < 0) // EOF
            break;
        pos = next_lf + 1;
    }
    return false;
}

}
<|endoftext|>


<commit_before>#ifndef sorter_threaded_exception_hpp
#define sorter_threaded_exception_hpp

struct SorterThreadedException : std::exception {
  enum Error {TooFewPivots = 1,
              NoOpenMP = 2,
              SplinterOrder = 3,
              SplinterSize = 4};
  inline SorterThreadedException(Error code) : error(code) {}
  const Error error;
};

#endif
<commit_msg>added and exception to splinter and got rid of unused exceptions<commit_after>#ifndef sorter_threaded_exception_hpp
#define sorter_threaded_exception_hpp

struct SorterThreadedException : std::exception {
  enum Error {SplinterOrder = 1,
              SplinterSize = 2};
  inline SorterThreadedException(Error code) : error(code) {}
  const Error error;
};

#endif
<|endoftext|>


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

#include "openma/body/inversedynamicsmatrix.h"
#include "openma/body/inversedynamicsprocessor_p.h"

#include "openma/body/anchor.h"
#include "openma/body/chain.h"
#include "openma/body/inertialparameters.h"
#include "openma/body/joint.h"
#include "openma/body/model.h"
#include "openma/body/segment.h"
#include "openma/body/utils.h"
#include "openma/base/trial.h"
#include "openma/instrument/forceplate.h"
#include "openma/math.h"

// -------------------------------------------------------------------------- //
//                                 PRIVATE API                                //
// -------------------------------------------------------------------------- //

#ifndef DOXYGEN_SHOULD_SKIP_THIS

namespace ma
{
namespace body
{
  class InverseDynamicMatrixPrivate : public InverseDynamicProcessorPrivate
  {
    OPENMA_DECLARE_PINT_ACCESSOR(InverseDynamicMatrix)

  public:
    InverseDynamicMatrixPrivate(InverseDynamicMatrix* pint);
    ~InverseDynamicMatrixPrivate();
  };

  InverseDynamicMatrixPrivate::InverseDynamicMatrixPrivate(InverseDynamicMatrix* pint)
  : InverseDynamicProcessorPrivate(pint,"InverseDynamicMatrix")
  {};

  InverseDynamicMatrixPrivate::~InverseDynamicMatrixPrivate() = default;
};
};

#endif

// -------------------------------------------------------------------------- //
//                                 PUBLIC API                                 //
// -------------------------------------------------------------------------- //

OPENMA_INSTANCE_STATIC_TYPEID(ma::body::InverseDynamicMatrix);

namespace ma
{
namespace body
{
  /**
   * @class InverseDynamicMatrix openma/body/matrixinversedynamics.h
   * @brief Algorithm to compute joint kinetics expressed in the global frame
   *
   * @TODO Explain in details the required element to use this algorithm (model configure, external wrench, etc.).
   *
   * @ingroup openma_body
   */

  /**
   * Constructor
   */
  InverseDynamicMatrix::InverseDynamicMatrix(Node* parent)
  : InverseDynamicProcessor(*new InverseDynamicMatrixPrivate(this), parent)
  {};

  /**
   * Destructor
   */
  InverseDynamicMatrix::~InverseDynamicMatrix() _OPENMA_NOEXCEPT = default;

  /**
   * Internally this method is a combination of two algorithms published in the litterature [1,2].
   * Both of these algorithms are known to be less sensitive to noise [3]. The reason to use this is only to reduce computation time.
   *  - No need to convert to quaternion
   *  - No need to create sparse 6x6 matrices
   *  - Angular velocity and angular acceleration computed directly from rotation matrices
   *  - All the results are express in the inertial (global) coordinate system
   *
   * @par References
   *  1. Dumas et al., 2004, A 3D generic inverse dynamic method using wrench notation and quaternion algebra, Computer methods in Biomechanics and Biomedical Engineering, 7 (3), pp. 159-166
   *  2. Doriot & Chèze, 2004, A Three-Dimensional Kinematic and Dynamic Study of the Lower Limb During the Stance Phase of Gait Using an Homogeneous Matrix Approach, IEEE Transactions on Biomedical Engineering, 51 (1), pp. 21-27
   *  3. Dumas et al., 2007, Influence of the 3D Inverse Dynamic Method on the Joint Forces and Moments During Gait, ￼Journal of￼Biomechanical￼Engineering, 129, pp. 786-790
   */
  bool InverseDynamicMatrix::run(Node* inout)
  {
#if !defined(_MSC_VER)
#warning WE NEED TO MANAGE UNITS FOR FORCES AND MOMENTS
#endif

    auto models = inout->findChildren<Model*>({},{},false);
    for (auto& model : models)
    {
      math::Array<3> Fp, Md, pd;
      auto chains = model->chains()->findChildren<Chain*>({},{},false);
      for (auto& chain : chains)
      {
        auto joints = chain->findChildren<Joint*>({},{},false);
        if (joints.empty())
        {
          warning("No joint found in the chain '%s'. Inverse dynamics for this chain aborted.", chain->name().c_str());
          continue;
        }
        // Properties check
        std::vector<TimeSequence*> tss(joints.size());
        unsigned inc = 0;
        for (const auto& joint : joints)
          tss[inc++] = joint->distalSegment()->pose();
        double rate = 0.0, start = 0.0;
        unsigned samples = 0;
        if (!compare_timesequences_properties(tss, rate, start, samples))
        {
          error("At least one segment's pose does not have the same sample rate, start time or number of samples in the chain '%s'.", chain->name().c_str());
          continue;
        }
        assert(rate > 0.);
        double dt = 1. / rate;
        double gres = 0.;
        math::Vector Fd, Md, pd;
        auto g = math::Map<const math::Vector>(1, model->gravity(), &gres).replicate(samples);
        // Iteration computation of joint kinetics
        for (auto itJ = joints.rbegin() ; itJ != joints.rend() ; ++itJ)
        {
          auto jnt = *itJ;
          auto seg = jnt->distalSegment();
          auto bsip = seg->findChild<InertialParameters*>();
          if (bsip == nullptr)
          {
            error("The segment '%s' does not have body segment inertial parameters. Inverse dynamics for the chain '%s' aborted.", seg->name().c_str(), chain->name().c_str());
            break;
          }

          // Internal variables used
          // -----------------------

          // - Pose of the segment
          auto pose = math::to_pose(seg->pose());
          // - Rotation component of the pose in the Inertial Coordinate System (ICS)
          auto R = pose.block<9>(0);
          // - Tensor of inertia expressed in the ICS
          math::Array<9> I = transform_relative_inertia(bsip, seg, pose);
          // - Centre of mass expressed in the ICS
          math::Position com = transform_relative_com(bsip, seg, pose);
          // - Mass of the segment
          double m = bsip->mass();
          // - Proximal end point of the segment
          auto pp = math::to_position(jnt->proximalAnchor()->position());
          if (!pp.isValid())
          {
            error("Unexpected error in the computation of proximal anchor position for the joint '%s'. Inverse dynamics for the chain '%s' aborted.", jnt->name().c_str(), chain->name().c_str());
            break;
          }
          // - Lever arm between the proximal end point and the centre of mass
          math::Position c = com - pp;

          // Derivatives computation
          // -----------------------
          // TODO Would it be possible to reduce the computation time by compute the angular velocity for the lower triangle only (same for the angular acceleration)

          // - Angular velocity of the segment in the ICS
          math::Array<3> omega = R.derivative<1>(dt).transform(R.transpose()).skewRedux();
          // - Angular acceleration of the segment in the ICS
          math::Array<3> alpha = R.derivative<2>(dt).transform(R.transpose()).skewRedux();
          // - Linear acceleration of the CoM in the ICS
          auto a = com.derivative<2>(dt);

          // Forces and moments computed at the proximal end point
          // -----------------------------------------------------

          // - External contact (ground, etc.)
          math::Vector Fext(samples); Fext.values().setZero(); Fext.residuals().setZero();
          math::Vector Mext(samples); Mext.values().setZero(); Mext.residuals().setZero();
          auto externals = seg->findChildren<const TimeSequence*>({}, {{"type", TimeSequence::Wrench}});
          for (const auto& external : externals)
          {
            auto wrench = math::to_wrench(external);
            if (!wrench.isValid())
            {
              warning("The external wrench '%s' is not valid or does not have the same sample rate, start time or number of sample than the rest of the chain '%s'.", external->name().c_str(), chain->name().c_str());
              continue;
            }
            Fext += wrench.block<3>(0);
            Mext += wrench.block<3>(3) + (wrench.block<3>(6) - pp).cross(wrench.block<3>(0));
          }
          // - Add the forces and moments of distal joint (if any)
          // NOTE: The opposite sign (-=) is because of the use of the action forces and moments computed for the previous segment. In the current segment, they represent reaction forces and moments.
          if (pd.isValid())
          {
            Fext -= Fd;
            Mext -= Md + (pd - pp).cross(Fd);
          }
          // - Weight
          auto Fwei = m * g / 1000.0;
          auto Mwei = c.cross(m * g / 1000.0);
          // - Dynamics
          auto Fdyn = m * a / 1000.0;
          auto Mdyn = (I.transform(alpha) + omega.cross(I.transform(omega))) / 1000.0 + c.cross(m * a / 1000.0);
          // - Proximal joint (result)
          math::Vector Fp = Fdyn - Fwei - Fext;
          math::Vector Mp = Mdyn - Mwei - Mext;
          math::to_timesequence(Fp, jnt->name() + ".Force", rate, start, TimeSequence::Force, "N", jnt);
          math::to_timesequence(Mp, jnt->name() + ".Moment", rate, start, TimeSequence::Moment, "Nmm" , jnt);

          // Set the next (reaction) distal joint variables
          Fd = Fp;
          Md = Mp;
          pd = pp;
        }
      }
    }
    return true;
  };

  /**
   * Create a deep copy of the object and return it as another object.
   */
  InverseDynamicMatrix* InverseDynamicMatrix::clone(Node* parent) const
  {
    auto dest = new InverseDynamicMatrix;
    dest->copy(this);
    dest->addParent(parent);
    return dest;
  };

  /**
   * Do a deep copy of the the given @a source. The previous content is replaced.
   */
  void InverseDynamicMatrix::copy(const Node* source) _OPENMA_NOEXCEPT
  {
    auto src = node_cast<const InverseDynamicMatrix*>(source);
    if (src == nullptr)
      return;
    this->InverseDynamicProcessor::copy(src);
  };

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

#include "openma/body/inversedynamicsmatrix.h"
#include "openma/body/inversedynamicsprocessor_p.h"

#include "openma/body/anchor.h"
#include "openma/body/chain.h"
#include "openma/body/inertialparameters.h"
#include "openma/body/joint.h"
#include "openma/body/model.h"
#include "openma/body/segment.h"
#include "openma/body/utils.h"
#include "openma/base/trial.h"
#include "openma/instrument/forceplate.h"
#include "openma/math.h"

// -------------------------------------------------------------------------- //
//                                 PRIVATE API                                //
// -------------------------------------------------------------------------- //

#ifndef DOXYGEN_SHOULD_SKIP_THIS

namespace ma
{
namespace body
{
  class InverseDynamicMatrixPrivate : public InverseDynamicProcessorPrivate
  {
    OPENMA_DECLARE_PINT_ACCESSOR(InverseDynamicMatrix)

  public:
    InverseDynamicMatrixPrivate(InverseDynamicMatrix* pint);
    ~InverseDynamicMatrixPrivate();
  };

  InverseDynamicMatrixPrivate::InverseDynamicMatrixPrivate(InverseDynamicMatrix* pint)
  : InverseDynamicProcessorPrivate(pint,"InverseDynamicMatrix")
  {};

  InverseDynamicMatrixPrivate::~InverseDynamicMatrixPrivate() = default;
};
};

#endif

// -------------------------------------------------------------------------- //
//                                 PUBLIC API                                 //
// -------------------------------------------------------------------------- //

OPENMA_INSTANCE_STATIC_TYPEID(ma::body::InverseDynamicMatrix);

namespace ma
{
namespace body
{
  /**
   * @class InverseDynamicMatrix openma/body/matrixinversedynamics.h
   * @brief Algorithm to compute joint kinetics expressed in the global frame
   *
   * @TODO Explain in details the required element to use this algorithm (model configure, external wrench, etc.).
   *
   * @ingroup openma_body
   */

  /**
   * Constructor
   */
  InverseDynamicMatrix::InverseDynamicMatrix(Node* parent)
  : InverseDynamicProcessor(*new InverseDynamicMatrixPrivate(this), parent)
  {};

  /**
   * Destructor
   */
  InverseDynamicMatrix::~InverseDynamicMatrix() _OPENMA_NOEXCEPT = default;

  /**
   * Internally this method is a combination of two algorithms published in the litterature [1,2].
   * Both of these algorithms are known to be less sensitive to noise [3]. The reason to use this is only to reduce computation time.
   *  - No need to convert to quaternion
   *  - No need to create sparse 6x6 matrices
   *  - Angular velocity and angular acceleration computed directly from rotation matrices
   *  - All the results are express in the inertial (global) coordinate system
   *
   * @par References
   *  1. Dumas et al., 2004, A 3D generic inverse dynamic method using wrench notation and quaternion algebra, Computer methods in Biomechanics and Biomedical Engineering, 7 (3), pp. 159-166
   *  2. Doriot & Chèze, 2004, A Three-Dimensional Kinematic and Dynamic Study of the Lower Limb During the Stance Phase of Gait Using an Homogeneous Matrix Approach, IEEE Transactions on Biomedical Engineering, 51 (1), pp. 21-27
   *  3. Dumas et al., 2007, Influence of the 3D Inverse Dynamic Method on the Joint Forces and Moments During Gait, ￼Journal of￼Biomechanical￼Engineering, 129, pp. 786-790
   */
  bool InverseDynamicMatrix::run(Node* inout)
  {
#if !defined(_MSC_VER)
#warning WE NEED TO MANAGE UNITS FOR FORCES AND MOMENTS
#endif

    auto models = inout->findChildren<Model*>({},{},false);
    for (auto& model : models)
    {
      auto chains = model->chains()->findChildren<Chain*>({},{},false);
      for (auto& chain : chains)
      {
        auto joints = chain->findChildren<Joint*>({},{},false);
        if (joints.empty())
        {
          warning("No joint found in the chain '%s'. Inverse dynamics for this chain aborted.", chain->name().c_str());
          continue;
        }
        // Properties check
        std::vector<TimeSequence*> tss(joints.size());
        unsigned inc = 0;
        for (const auto& joint : joints)
          tss[inc++] = joint->distalSegment()->pose();
        double rate = 0.0, start = 0.0;
        unsigned samples = 0;
        if (!compare_timesequences_properties(tss, rate, start, samples))
        {
          error("At least one segment's pose does not have the same sample rate, start time or number of samples in the chain '%s'.", chain->name().c_str());
          continue;
        }
        assert(rate > 0.);
        double dt = 1. / rate;
        double gres = 0.;
        math::Vector Fd, Md, pd;
        auto g = math::Map<const math::Vector>(1, model->gravity(), &gres).replicate(samples);
        // Iteration computation of joint kinetics
        for (auto itJ = joints.rbegin() ; itJ != joints.rend() ; ++itJ)
        {
          auto jnt = *itJ;
          auto seg = jnt->distalSegment();
          auto bsip = seg->findChild<InertialParameters*>();
          if (bsip == nullptr)
          {
            error("The segment '%s' does not have body segment inertial parameters. Inverse dynamics for the chain '%s' aborted.", seg->name().c_str(), chain->name().c_str());
            break;
          }

          // Internal variables used
          // -----------------------

          // - Pose of the segment
          auto pose = math::to_pose(seg->pose());
          // - Rotation component of the pose in the Inertial Coordinate System (ICS)
          auto R = pose.block<9>(0);
          // - Tensor of inertia expressed in the ICS
          math::Array<9> I = transform_relative_inertia(bsip, seg, pose);
          // - Centre of mass expressed in the ICS
          math::Position com = transform_relative_com(bsip, seg, pose);
          // - Mass of the segment
          double m = bsip->mass();
          // - Proximal end point of the segment
          auto pp = math::to_position(jnt->proximalAnchor()->position());
          if (!pp.isValid())
          {
            error("Unexpected error in the computation of proximal anchor position for the joint '%s'. Inverse dynamics for the chain '%s' aborted.", jnt->name().c_str(), chain->name().c_str());
            break;
          }
          // - Lever arm between the proximal end point and the centre of mass
          math::Position c = com - pp;

          // Derivatives computation
          // -----------------------
          // TODO Would it be possible to reduce the computation time by compute the angular velocity for the lower triangle only (same for the angular acceleration)

          // - Angular velocity of the segment in the ICS
          math::Array<3> omega = R.derivative<1>(dt).transform(R.transpose()).skewRedux();
          // - Angular acceleration of the segment in the ICS
          math::Array<3> alpha = R.derivative<2>(dt).transform(R.transpose()).skewRedux();
          // - Linear acceleration of the CoM in the ICS
          auto a = com.derivative<2>(dt);

          // Forces and moments computed at the proximal end point
          // -----------------------------------------------------

          // - External contact (ground, etc.)
          math::Vector Fext(samples); Fext.values().setZero(); Fext.residuals().setZero();
          math::Vector Mext(samples); Mext.values().setZero(); Mext.residuals().setZero();
          auto externals = seg->findChildren<const TimeSequence*>({}, {{"type", TimeSequence::Wrench}});
          for (const auto& external : externals)
          {
            auto wrench = math::to_wrench(external);
            if (!wrench.isValid())
            {
              warning("The external wrench '%s' is not valid or does not have the same sample rate, start time or number of sample than the rest of the chain '%s'.", external->name().c_str(), chain->name().c_str());
              continue;
            }
            Fext += wrench.block<3>(0);
            Mext += wrench.block<3>(3) + (wrench.block<3>(6) - pp).cross(wrench.block<3>(0));
          }
          // - Add the forces and moments of distal joint (if any)
          // NOTE: The opposite sign (-=) is because of the use of the action forces and moments computed for the previous segment. In the current segment, they represent reaction forces and moments.
          if (pd.isValid())
          {
            Fext -= Fd;
            Mext -= Md + (pd - pp).cross(Fd);
          }
          // - Weight
          auto Fwei = m * g / 1000.0;
          auto Mwei = c.cross(m * g / 1000.0);
          // - Dynamics
          auto Fdyn = m * a / 1000.0;
          auto Mdyn = (I.transform(alpha) + omega.cross(I.transform(omega))) / 1000.0 + c.cross(m * a / 1000.0);
          // - Proximal joint (result)
          math::Vector Fp = Fdyn - Fwei - Fext;
          math::Vector Mp = Mdyn - Mwei - Mext;
          math::to_timesequence(Fp, jnt->name() + ".Force", rate, start, TimeSequence::Force, "N", jnt);
          math::to_timesequence(Mp, jnt->name() + ".Moment", rate, start, TimeSequence::Moment, "Nmm" , jnt);

          // Set the next (reaction) distal joint variables
          Fd = Fp;
          Md = Mp;
          pd = pp;
        }
      }
    }
    return true;
  };

  /**
   * Create a deep copy of the object and return it as another object.
   */
  InverseDynamicMatrix* InverseDynamicMatrix::clone(Node* parent) const
  {
    auto dest = new InverseDynamicMatrix;
    dest->copy(this);
    dest->addParent(parent);
    return dest;
  };

  /**
   * Do a deep copy of the the given @a source. The previous content is replaced.
   */
  void InverseDynamicMatrix::copy(const Node* source) _OPENMA_NOEXCEPT
  {
    auto src = node_cast<const InverseDynamicMatrix*>(source);
    if (src == nullptr)
      return;
    this->InverseDynamicProcessor::copy(src);
  };

 };
};<|endoftext|>


<commit_before>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <strings.h>
#include <string>
#include <sstream>
#include <signal.h>
#include "config/cmd_args.hpp"
#include "config/code.hpp"
#include "utils.hpp"
#include "worker_pool.hpp"
#include "buffer_cache/mirrored.hpp"
#include "buffer_cache/page_map/array.hpp"
#include "buffer_cache/page_repl/page_repl_random.hpp"
#include "buffer_cache/writeback/writeback.hpp"
#include "buffer_cache/concurrency/rwi_conc.hpp"
#include "serializer/in_place.hpp"
#include "conn_fsm.hpp"
#include "buffer_cache/concurrency/rwi_conc.hpp"

#include "btree/get_fsm.hpp"
#include "btree/set_fsm.hpp"
#include "btree/incr_decr_fsm.hpp"
#include "btree/append_prepend_fsm.hpp"
#include "btree/delete_fsm.hpp"

worker_t::worker_t(int _workerid, int _nqueues,
        worker_pool_t *parent_pool, cmd_config_t *cmd_config) {
    ref_count = 0;
    event_queue = gnew<event_queue_t>(_workerid, _nqueues, parent_pool, this, cmd_config);

    total_connections = 0;
    curr_connections = 0;
    perfmon.monitor(var_monitor_t(var_monitor_t::vt_int, "total_connections", (void*)&total_connections));
    perfmon.monitor(var_monitor_t(var_monitor_t::vt_int, "curr_connections", (void*)&curr_connections));

    // Init the slices
    nworkers = _nqueues;
    workerid = _workerid;
    nslices = cmd_config->n_slices;

    mkdir(DATA_DIRECTORY, 0777);

    for (int i = 0; i < nslices; i++) {
        typedef std::basic_string<char, std::char_traits<char>, gnew_alloc<char> > rdbstring_t;
        typedef std::basic_stringstream<char, std::char_traits<char>, gnew_alloc<char> > rdbstringstream_t;
        rdbstringstream_t out;
        rdbstring_t str((char*)cmd_config->db_file_name);
        out << workerid << "_" << i;
        str += out.str();
        slices[i] = gnew<cache_t>(
                (char*)str.c_str(),
                BTREE_BLOCK_SIZE,
                cmd_config->max_cache_size / nworkers,
                cmd_config->wait_for_flush,
                cmd_config->flush_timer_ms,
                cmd_config->flush_threshold_percent);
    }
    active_slices  = true;
}

worker_t::~worker_t() {
    check("Error in ~worker_t, cannot delete a worker_t without first deleting its slices", active_slices == true);
    delete event_queue;
}

void worker_t::start_worker() {
    event_queue->start_queue(this);
}

void worker_t::start_slices() {
    for (int i = 0; i < nslices; i++)
        slices[i]->start();
}

void worker_t::shutdown() {
    shutting_down = true;

    for (int i = 0; i < nslices; i++) {
        ref_count++;
        slices[i]->shutdown(this);
    }
}

void worker_t::delete_slices() {
    for (int i = 0; i < nslices; i++)
        gdelete(slices[i]);
    active_slices = false;
}

void worker_t::new_fsm(int data, int &resource, void **source) {
    worker_t::conn_fsm_t *fsm =
        new worker_t::conn_fsm_t(data, event_queue);
    live_fsms.push_back(fsm);
    resource = fsm->get_source();
    *source = fsm;
    printf("Opened socket %d\n", resource);
    curr_connections++;
    total_connections++;
}

void worker_t::deregister_fsm(void *fsm, int &resource) {
    worker_t::conn_fsm_t *cfsm = (worker_t::conn_fsm_t *) fsm;
    logf(INF, "Closing socket %d\n", cfsm->get_source());
    resource = cfsm->get_source();
    live_fsms.remove(cfsm);
    shutdown_fsms.push_back(cfsm);
    curr_connections--;
    // TODO: there might be outstanding btrees that we're missing (if
    // we're quitting before the the operation completes). We need to
    // free the btree structure in this case (more likely the request
    // and all the btrees associated with it).
}

bool worker_t::deregister_fsm(int &resource) {
    if (live_fsms.empty()) {
        return false;
    } else {
        worker_t::conn_fsm_t *cfsm = live_fsms.head();
        deregister_fsm(cfsm, resource);
        return true;
    }
}

void worker_t::clean_fsms() {
    shutdown_fsms.clear();
}

void worker_t::initiate_conn_fsm_transition(event_t *event) {
    code_config_t::conn_fsm_t *fsm = (code_config_t::conn_fsm_t*)event->state;
    int res = fsm->do_transition(event);

void worker_t::process_perfmon_msg(perfmon_msg_t *msg)
{
    worker_t *worker = get_cpu_context()->worker;
    event_queue_t *queue = worker->event_queue;
    int this_cpu = get_cpu_context()->worker->workerid;
    int return_cpu = msg->return_cpu;

    switch(msg->state) {
    case perfmon_msg_t::sm_request:
        // Copy our statistics into the perfmon message and send a response
        msg->perfmon = new perfmon_t();
        msg->perfmon->copy_from(worker->perfmon);
        msg->state = perfmon_msg_t::sm_response;
        break;
    case perfmon_msg_t::sm_response:
        msg->request->on_request_part_completed();
        return;
    case perfmon_msg_t::sm_copy_cleanup:
        // Response has been sent to the client, time to delete the
        // copy
        delete msg->perfmon;
        msg->state = perfmon_msg_t::sm_msg_cleanup;
        break;
    case perfmon_msg_t::sm_msg_cleanup:
        // Copy has been deleted, delete the final message and return
        delete msg;
        return;
    }

    msg->return_cpu = this_cpu;
    queue->message_hub.store_message(return_cpu, msg);
}

void worker_t::process_lock_msg(event_t *event, rwi_lock_t::lock_request_t *lr) {
    lr->callback->on_lock_available();
    delete lr;
}

void worker_t::process_log_msg(log_msg_t *msg) {
    if (msg->del) {
        ref_count--;
        delete msg;
    } else {
        assert(workerid == LOG_WORKER);
        log_writer.writef("(%s)Q%d:%s:%d:", msg->level_str(), msg->return_cpu, msg->src_file, msg->src_line);
        log_writer.write(msg->str);

        msg->del = true;
        // No need to change return_cpu because the message will be deleted immediately.
        event_queue->message_hub.store_message(msg->return_cpu, msg);
    }
}

// Handle events coming from the event queue
void worker_t::event_handler(event_t *event) {
    if(event->event_type == et_sock) {
        // Got some socket action, let the connection fsm know
        initiate_conn_fsm_transition(event);
    } else if(event->event_type == et_cpu_event) {
        cpu_message_t *msg = (cpu_message_t*)event->state;
        switch(msg->type) {
        case cpu_message_t::mt_btree:
            process_btree_msg((code_config_t::btree_fsm_t*)msg);
            break;
        case cpu_message_t::mt_lock:
            process_lock_msg(event, (rwi_lock_t::lock_request_t*)msg);
            break;
        case cpu_message_t::mt_perfmon:
            process_perfmon_msg((perfmon_msg_t*)msg);
            break;
        case cpu_message_t::mt_log:
            process_log_msg((log_msg_t *) msg);
            break;
        }
    } else {
        check("Unknown event in event_handler", 1);
    }
}

void worker_t::incr_ref_count() {
    ref_count++;
}

void worker_t::decr_ref_count() {
    ref_count--;
    if (ref_count == 0 && shutting_down) {
        event_queue->send_shutdown();
    }
}

void worker_t::on_sync() {
    decr_ref_count();
}

void worker_pool_t::create_worker_pool(pthread_t main_thread,
                                       int _nworkers, int _nslices)
{
    this->main_thread = main_thread;

    // Create the workers
    if (_nworkers != 0)
        nworkers =  std::min(_nworkers, MAX_CPUS);
    else
        nworkers = get_cpu_count();

    if (_nslices != 0)
        nslices = std::min(_nslices, MAX_SLICES);
    else
        nslices = DEFAULT_SLICES;

    cmd_config->n_workers = nworkers;
    cmd_config->n_slices = nslices;

    for(int i = 0; i < nworkers; i++) {
        workers[i] = gnew<worker_t>(i, nworkers, this, cmd_config);
    }
    active_worker = 0;

    for(int i = 0; i < nworkers; i++) {
        workers[i]->event_queue->message_hub.init(i, nworkers, workers);
    }

    // Start the actual queue
    for(int i = 0; i < nworkers; i++) {
        workers[i]->start_worker();
    }

    // TODO: can we move the printing out of here?
    printf("Physical cores: %d\n", get_cpu_count());
    printf("Using cores: %d\n", nworkers);
    printf("Slices per core: %d\n", nslices);
    printf("Total RAM: %ldMB\n", get_total_ram() / 1024 / 1024);
    printf("Free RAM: %ldMB (%.2f%%)\n",
           get_available_ram() / 1024 / 1024,
           (double)get_available_ram() / (double)get_total_ram() * 100.0f);
    printf("Max cache size: %ldMB\n",
           cmd_config->max_cache_size / 1024 / 1024);

    // TODO: this whole queue creation business is a mess, refactor
    // the way it works.
}

worker_pool_t::worker_pool_t(pthread_t main_thread,
                             cmd_config_t *_cmd_config)
    : cmd_config(_cmd_config)
{
    create_worker_pool(main_thread, cmd_config->n_workers, cmd_config->n_slices);
}

worker_pool_t::worker_pool_t(pthread_t main_thread,
                             int _nworkers, int _nslices, cmd_config_t *_cmd_config)
    : cmd_config(_cmd_config)
{
    create_worker_pool(main_thread, _nworkers, _nslices);
}

worker_pool_t::~worker_pool_t() {

    // Start stopping each event queue
    for(int i = 0; i < nworkers; i++) {
        workers[i]->event_queue->begin_stopping_queue();
    }

    // Wait for all of the event queues to finish stopping before destroying any of them
    for (int i = 0; i < nworkers; i++) {
        workers[i]->event_queue->finish_stopping_queue();
    }

    // Free the event queues
    for(int i = 0; i < nworkers; i++) {
        gdelete(workers[i]);
    }
    nworkers = 0;

    // Delete all the custom allocators in the system
    for(size_t i = 0; i < all_allocs.size(); i++) {
        tls_small_obj_alloc_accessor<alloc_t>::alloc_vector_t *allocs
            = (tls_small_obj_alloc_accessor<alloc_t>::alloc_vector_t*)(all_allocs[i]);
        if(allocs) {
            for(size_t j = 0; j < allocs->size(); j++) {
                gdelete(allocs->operator[](j));
            }
        }
        delete allocs;
    }
}

worker_t* worker_pool_t::next_active_worker() {
    int worker = active_worker++;
    if(active_worker >= nworkers)
        active_worker = 0;
    return workers[worker];
    // TODO: consider introducing randomness to avoid potential
    // (intentional and unintentional) attacks on memory allocation
    // and CPU utilization.
}

<commit_msg>Change connection notifications back to printfs because I can't figure out how to fix the bug right now.<commit_after>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <strings.h>
#include <string>
#include <sstream>
#include <signal.h>
#include "config/cmd_args.hpp"
#include "config/code.hpp"
#include "utils.hpp"
#include "worker_pool.hpp"
#include "buffer_cache/mirrored.hpp"
#include "buffer_cache/page_map/array.hpp"
#include "buffer_cache/page_repl/page_repl_random.hpp"
#include "buffer_cache/writeback/writeback.hpp"
#include "buffer_cache/concurrency/rwi_conc.hpp"
#include "serializer/in_place.hpp"
#include "conn_fsm.hpp"
#include "buffer_cache/concurrency/rwi_conc.hpp"

#include "btree/get_fsm.hpp"
#include "btree/set_fsm.hpp"
#include "btree/incr_decr_fsm.hpp"
#include "btree/append_prepend_fsm.hpp"
#include "btree/delete_fsm.hpp"

worker_t::worker_t(int _workerid, int _nqueues,
        worker_pool_t *parent_pool, cmd_config_t *cmd_config) {
    ref_count = 0;
    event_queue = gnew<event_queue_t>(_workerid, _nqueues, parent_pool, this, cmd_config);

    total_connections = 0;
    curr_connections = 0;
    perfmon.monitor(var_monitor_t(var_monitor_t::vt_int, "total_connections", (void*)&total_connections));
    perfmon.monitor(var_monitor_t(var_monitor_t::vt_int, "curr_connections", (void*)&curr_connections));

    // Init the slices
    nworkers = _nqueues;
    workerid = _workerid;
    nslices = cmd_config->n_slices;

    mkdir(DATA_DIRECTORY, 0777);

    for (int i = 0; i < nslices; i++) {
        typedef std::basic_string<char, std::char_traits<char>, gnew_alloc<char> > rdbstring_t;
        typedef std::basic_stringstream<char, std::char_traits<char>, gnew_alloc<char> > rdbstringstream_t;
        rdbstringstream_t out;
        rdbstring_t str((char*)cmd_config->db_file_name);
        out << workerid << "_" << i;
        str += out.str();
        slices[i] = gnew<cache_t>(
                (char*)str.c_str(),
                BTREE_BLOCK_SIZE,
                cmd_config->max_cache_size / nworkers,
                cmd_config->wait_for_flush,
                cmd_config->flush_timer_ms,
                cmd_config->flush_threshold_percent);
    }
    active_slices  = true;
}

worker_t::~worker_t() {
    check("Error in ~worker_t, cannot delete a worker_t without first deleting its slices", active_slices == true);
    delete event_queue;
}

void worker_t::start_worker() {
    event_queue->start_queue(this);
}

void worker_t::start_slices() {
    for (int i = 0; i < nslices; i++)
        slices[i]->start();
}

void worker_t::shutdown() {
    shutting_down = true;

    for (int i = 0; i < nslices; i++) {
        ref_count++;
        slices[i]->shutdown(this);
    }
}

void worker_t::delete_slices() {
    for (int i = 0; i < nslices; i++)
        gdelete(slices[i]);
    active_slices = false;
}

void worker_t::new_fsm(int data, int &resource, void **source) {
    worker_t::conn_fsm_t *fsm =
        new worker_t::conn_fsm_t(data, event_queue);
    live_fsms.push_back(fsm);
    resource = fsm->get_source();
    *source = fsm;
    printf("Opened socket %d\n", resource);
    curr_connections++;
    total_connections++;
}

void worker_t::deregister_fsm(void *fsm, int &resource) {
    worker_t::conn_fsm_t *cfsm = (worker_t::conn_fsm_t *) fsm;
    printf("Closing socket %d\n", cfsm->get_source());
    resource = cfsm->get_source();
    live_fsms.remove(cfsm);
    shutdown_fsms.push_back(cfsm);
    curr_connections--;
    // TODO: there might be outstanding btrees that we're missing (if
    // we're quitting before the the operation completes). We need to
    // free the btree structure in this case (more likely the request
    // and all the btrees associated with it).
}

bool worker_t::deregister_fsm(int &resource) {
    if (live_fsms.empty()) {
        return false;
    } else {
        worker_t::conn_fsm_t *cfsm = live_fsms.head();
        deregister_fsm(cfsm, resource);
        return true;
    }
}

void worker_t::clean_fsms() {
    shutdown_fsms.clear();
}

void worker_t::initiate_conn_fsm_transition(event_t *event) {
    code_config_t::conn_fsm_t *fsm = (code_config_t::conn_fsm_t*)event->state;
    int res = fsm->do_transition(event);

void worker_t::process_perfmon_msg(perfmon_msg_t *msg)
{
    worker_t *worker = get_cpu_context()->worker;
    event_queue_t *queue = worker->event_queue;
    int this_cpu = get_cpu_context()->worker->workerid;
    int return_cpu = msg->return_cpu;

    switch(msg->state) {
    case perfmon_msg_t::sm_request:
        // Copy our statistics into the perfmon message and send a response
        msg->perfmon = new perfmon_t();
        msg->perfmon->copy_from(worker->perfmon);
        msg->state = perfmon_msg_t::sm_response;
        break;
    case perfmon_msg_t::sm_response:
        msg->request->on_request_part_completed();
        return;
    case perfmon_msg_t::sm_copy_cleanup:
        // Response has been sent to the client, time to delete the
        // copy
        delete msg->perfmon;
        msg->state = perfmon_msg_t::sm_msg_cleanup;
        break;
    case perfmon_msg_t::sm_msg_cleanup:
        // Copy has been deleted, delete the final message and return
        delete msg;
        return;
    }

    msg->return_cpu = this_cpu;
    queue->message_hub.store_message(return_cpu, msg);
}

void worker_t::process_lock_msg(event_t *event, rwi_lock_t::lock_request_t *lr) {
    lr->callback->on_lock_available();
    delete lr;
}

void worker_t::process_log_msg(log_msg_t *msg) {
    if (msg->del) {
        ref_count--;
        delete msg;
    } else {
        assert(workerid == LOG_WORKER);
        log_writer.writef("(%s)Q%d:%s:%d:", msg->level_str(), msg->return_cpu, msg->src_file, msg->src_line);
        log_writer.write(msg->str);

        msg->del = true;
        // No need to change return_cpu because the message will be deleted immediately.
        event_queue->message_hub.store_message(msg->return_cpu, msg);
    }
}

// Handle events coming from the event queue
void worker_t::event_handler(event_t *event) {
    if(event->event_type == et_sock) {
        // Got some socket action, let the connection fsm know
        initiate_conn_fsm_transition(event);
    } else if(event->event_type == et_cpu_event) {
        cpu_message_t *msg = (cpu_message_t*)event->state;
        switch(msg->type) {
        case cpu_message_t::mt_btree:
            process_btree_msg((code_config_t::btree_fsm_t*)msg);
            break;
        case cpu_message_t::mt_lock:
            process_lock_msg(event, (rwi_lock_t::lock_request_t*)msg);
            break;
        case cpu_message_t::mt_perfmon:
            process_perfmon_msg((perfmon_msg_t*)msg);
            break;
        case cpu_message_t::mt_log:
            process_log_msg((log_msg_t *) msg);
            break;
        }
    } else {
        check("Unknown event in event_handler", 1);
    }
}

void worker_t::incr_ref_count() {
    ref_count++;
}

void worker_t::decr_ref_count() {
    ref_count--;
    if (ref_count == 0 && shutting_down) {
        event_queue->send_shutdown();
    }
}

void worker_t::on_sync() {
    decr_ref_count();
}

void worker_pool_t::create_worker_pool(pthread_t main_thread,
                                       int _nworkers, int _nslices)
{
    this->main_thread = main_thread;

    // Create the workers
    if (_nworkers != 0)
        nworkers =  std::min(_nworkers, MAX_CPUS);
    else
        nworkers = get_cpu_count();

    if (_nslices != 0)
        nslices = std::min(_nslices, MAX_SLICES);
    else
        nslices = DEFAULT_SLICES;

    cmd_config->n_workers = nworkers;
    cmd_config->n_slices = nslices;

    for(int i = 0; i < nworkers; i++) {
        workers[i] = gnew<worker_t>(i, nworkers, this, cmd_config);
    }
    active_worker = 0;

    for(int i = 0; i < nworkers; i++) {
        workers[i]->event_queue->message_hub.init(i, nworkers, workers);
    }

    // Start the actual queue
    for(int i = 0; i < nworkers; i++) {
        workers[i]->start_worker();
    }

    // TODO: can we move the printing out of here?
    printf("Physical cores: %d\n", get_cpu_count());
    printf("Using cores: %d\n", nworkers);
    printf("Slices per core: %d\n", nslices);
    printf("Total RAM: %ldMB\n", get_total_ram() / 1024 / 1024);
    printf("Free RAM: %ldMB (%.2f%%)\n",
           get_available_ram() / 1024 / 1024,
           (double)get_available_ram() / (double)get_total_ram() * 100.0f);
    printf("Max cache size: %ldMB\n",
           cmd_config->max_cache_size / 1024 / 1024);

    // TODO: this whole queue creation business is a mess, refactor
    // the way it works.
}

worker_pool_t::worker_pool_t(pthread_t main_thread,
                             cmd_config_t *_cmd_config)
    : cmd_config(_cmd_config)
{
    create_worker_pool(main_thread, cmd_config->n_workers, cmd_config->n_slices);
}

worker_pool_t::worker_pool_t(pthread_t main_thread,
                             int _nworkers, int _nslices, cmd_config_t *_cmd_config)
    : cmd_config(_cmd_config)
{
    create_worker_pool(main_thread, _nworkers, _nslices);
}

worker_pool_t::~worker_pool_t() {

    // Start stopping each event queue
    for(int i = 0; i < nworkers; i++) {
        workers[i]->event_queue->begin_stopping_queue();
    }

    // Wait for all of the event queues to finish stopping before destroying any of them
    for (int i = 0; i < nworkers; i++) {
        workers[i]->event_queue->finish_stopping_queue();
    }

    // Free the event queues
    for(int i = 0; i < nworkers; i++) {
        gdelete(workers[i]);
    }
    nworkers = 0;

    // Delete all the custom allocators in the system
    for(size_t i = 0; i < all_allocs.size(); i++) {
        tls_small_obj_alloc_accessor<alloc_t>::alloc_vector_t *allocs
            = (tls_small_obj_alloc_accessor<alloc_t>::alloc_vector_t*)(all_allocs[i]);
        if(allocs) {
            for(size_t j = 0; j < allocs->size(); j++) {
                gdelete(allocs->operator[](j));
            }
        }
        delete allocs;
    }
}

worker_t* worker_pool_t::next_active_worker() {
    int worker = active_worker++;
    if(active_worker >= nworkers)
        active_worker = 0;
    return workers[worker];
    // TODO: consider introducing randomness to avoid potential
    // (intentional and unintentional) attacks on memory allocation
    // and CPU utilization.
}

<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2018-2019 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwopy/pylogging.h>

#include <inviwo/core/util/logcentral.h>
#include <inviwo/core/util/consolelogger.h>
#include <inviwo/core/util/filelogger.h>
#include <inviwo/core/processors/processor.h>

namespace inviwo {

void exposeLogging(pybind11::module& m) {
    namespace py = pybind11;

    py::class_<Logger, std::shared_ptr<Logger>>(m, "Logger")
        .def("log", &Logger::log)
        .def("logProcessor", &Logger::logProcessor)
        .def("logNetwork", &Logger::logNetwork)
        .def("logAssertion", &Logger::logAssertion);

    py::class_<LogCentral, Logger, std::shared_ptr<LogCentral>>(m, "LogCentral")
        .def(py::init([]() {
            auto lc = std::make_unique<LogCentral>();
            if (!LogCentral::isInitialized()) {
                LogCentral::init(lc.get());
            }
            return lc;
        }))
        .def("registerLogger",
             [](LogCentral* lc, std::shared_ptr<Logger> logger) { lc->registerLogger(logger); })
        .def_static("get", &LogCentral::getPtr, py::return_value_policy::reference);

        py::class_<ConsoleLogger, Logger, std::shared_ptr<ConsoleLogger>>(m, "ConsoleLogger")
            .def(py::init<>())
            .def("log", &ConsoleLogger::log);

        py::class_<FileLogger, Logger, std::shared_ptr<FileLogger>>(m, "FileLogger")
            .def(py::init<std::string>())
            .def("log", &FileLogger::log);
}

}  // namespace inviwo
<commit_msg>Python: Formating<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2018-2019 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwopy/pylogging.h>

#include <inviwo/core/util/logcentral.h>
#include <inviwo/core/util/consolelogger.h>
#include <inviwo/core/util/filelogger.h>
#include <inviwo/core/processors/processor.h>

namespace inviwo {

void exposeLogging(pybind11::module& m) {
    namespace py = pybind11;

    py::class_<Logger, std::shared_ptr<Logger>>(m, "Logger")
        .def("log", &Logger::log)
        .def("logProcessor", &Logger::logProcessor)
        .def("logNetwork", &Logger::logNetwork)
        .def("logAssertion", &Logger::logAssertion);

    py::class_<LogCentral, Logger, std::shared_ptr<LogCentral>>(m, "LogCentral")
        .def(py::init([]() {
            auto lc = std::make_unique<LogCentral>();
            if (!LogCentral::isInitialized()) {
                LogCentral::init(lc.get());
            }
            return lc;
        }))
        .def("registerLogger",
             [](LogCentral* lc, std::shared_ptr<Logger> logger) { lc->registerLogger(logger); })
        .def_static("get", &LogCentral::getPtr, py::return_value_policy::reference);

    py::class_<ConsoleLogger, Logger, std::shared_ptr<ConsoleLogger>>(m, "ConsoleLogger")
        .def(py::init<>())
        .def("log", &ConsoleLogger::log);

    py::class_<FileLogger, Logger, std::shared_ptr<FileLogger>>(m, "FileLogger")
        .def(py::init<std::string>())
        .def("log", &FileLogger::log);
}

}  // namespace inviwo
<|endoftext|>