<commit_before>// Ignore unused parameter warnings coming from cppunit headers
#include <libmesh/ignore_warnings.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
#include <libmesh/restore_warnings.h>

#include <libmesh/libmesh.h>
#include <libmesh/elem.h>

#include "test_comm.h"

using namespace libMesh;

class ContainsPointTest : public CppUnit::TestCase
{
  /**
   * The goal of this test is to verify proper operation of the contains_point
   * method that is used extensively in the point locator. This test focusses on
   * the specializes contains_point implementaion in TRI3.
   */
public:
  CPPUNIT_TEST_SUITE( ContainsPointTest );

  CPPUNIT_TEST( testContainsPointTri3 );

  CPPUNIT_TEST_SUITE_END();

public:
  void setUp() {}

  void tearDown() {}

  // TRI3 test
  void testContainsPointTri3() {
    // tri corner nodes
    Node a(3,1,2, 0);
    Node b(1,2,3, 1);
    Node c(2,3,1, 2);

    // helper vectors to span the tri and point out of plane
    Point va(a-c);
    Point vb(b-c);
    Point oop(va.cross(vb));

    UniquePtr<Elem> elem = Elem::build(TRI3);

    elem->set_node(0) = &a;
    elem->set_node(1) = &b;
    elem->set_node(2) = &c;

    // midpoint
    Point mid = 1.0/3.0 * (a + b + c);
    CPPUNIT_ASSERT (elem->contains_point(mid));

    // out of plane from the mid point
    CPPUNIT_ASSERT (!elem->contains_point(mid + 0.1 * oop));

    // check all corners
    CPPUNIT_ASSERT (elem->contains_point(a));
    CPPUNIT_ASSERT (elem->contains_point(b));
    CPPUNIT_ASSERT (elem->contains_point(c));

    // check outside
    CPPUNIT_ASSERT (!elem->contains_point(a + va * TOLERANCE * 10));
    CPPUNIT_ASSERT (!elem->contains_point(b + vb * TOLERANCE * 10));
    CPPUNIT_ASSERT (!elem->contains_point(c - (va + vb) * TOLERANCE * 10));
  }
};

CPPUNIT_TEST_SUITE_REGISTRATION( ContainsPointTest );
<commit_msg>Add unit test of new contains_point() routine.<commit_after>// Ignore unused parameter warnings coming from cppunit headers
#include <libmesh/ignore_warnings.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
#include <libmesh/restore_warnings.h>

#include <libmesh/libmesh.h>
#include <libmesh/elem.h>

#include "test_comm.h"

using namespace libMesh;

class ContainsPointTest : public CppUnit::TestCase
{
  /**
   * The goal of this test is to verify proper operation of the contains_point
   * method that is used extensively in the point locator. This test focusses on
   * the specializes contains_point implementaion in TRI3.
   */
public:
  CPPUNIT_TEST_SUITE( ContainsPointTest );

  CPPUNIT_TEST( testContainsPointTri3 );

  CPPUNIT_TEST( testContainsPointTet4 );

  CPPUNIT_TEST_SUITE_END();

public:
  void setUp() {}

  void tearDown() {}

  // TRI3 test
  void testContainsPointTri3() {
    // tri corner nodes
    Node a(3,1,2, 0);
    Node b(1,2,3, 1);
    Node c(2,3,1, 2);

    // helper vectors to span the tri and point out of plane
    Point va(a-c);
    Point vb(b-c);
    Point oop(va.cross(vb));

    UniquePtr<Elem> elem = Elem::build(TRI3);

    elem->set_node(0) = &a;
    elem->set_node(1) = &b;
    elem->set_node(2) = &c;

    // midpoint
    Point mid = 1.0/3.0 * (a + b + c);
    CPPUNIT_ASSERT (elem->contains_point(mid));

    // out of plane from the mid point
    CPPUNIT_ASSERT (!elem->contains_point(mid + 0.1 * oop));

    // check all corners
    CPPUNIT_ASSERT (elem->contains_point(a));
    CPPUNIT_ASSERT (elem->contains_point(b));
    CPPUNIT_ASSERT (elem->contains_point(c));

    // check outside
    CPPUNIT_ASSERT (!elem->contains_point(a + va * TOLERANCE * 10));
    CPPUNIT_ASSERT (!elem->contains_point(b + vb * TOLERANCE * 10));
    CPPUNIT_ASSERT (!elem->contains_point(c - (va + vb) * TOLERANCE * 10));
  }

  // TET4 test
  void testContainsPointTet4()
  {
    // Construct unit Tet.
    {
      Node zero  (0., 0., 0., 0);
      Node one   (1., 0., 0., 1);
      Node two   (0., 1., 0., 2);
      Node three (0., 0., 1., 3);

      UniquePtr<Elem> elem = Elem::build(TET4);
      elem->set_node(0) = &zero;
      elem->set_node(1) = &one;
      elem->set_node(2) = &two;
      elem->set_node(3) = &three;

      // The centroid must be inside the element.
      CPPUNIT_ASSERT (elem->contains_point(elem->centroid()));

      // The vertices must be contained in the element.
      CPPUNIT_ASSERT (elem->contains_point(zero));
      CPPUNIT_ASSERT (elem->contains_point(one));
      CPPUNIT_ASSERT (elem->contains_point(two));
      CPPUNIT_ASSERT (elem->contains_point(three));

      // Make sure that outside points are not contained.
      CPPUNIT_ASSERT (!elem->contains_point(Point(.34, .34, .34)));
      CPPUNIT_ASSERT (!elem->contains_point(Point(.33, .33, -.1)));
      CPPUNIT_ASSERT (!elem->contains_point(Point(0., -.1, .5)));
    }

    // Construct a nearly degenerate (sliver) tet.  A unit tet with
    // nodes "one" and "two" moved to within a distance of epsilon
    // from the origin.
    {
      Real epsilon = 1.e-4;

      Node zero  (0., 0., 0., 0);
      Node one   (epsilon, 0., 0., 1);
      Node two   (0., epsilon, 0., 2);
      Node three (0., 0., 1., 3);

      UniquePtr<Elem> elem = Elem::build(TET4);
      elem->set_node(0) = &zero;
      elem->set_node(1) = &one;
      elem->set_node(2) = &two;
      elem->set_node(3) = &three;

      // The centroid must be inside the element.
      CPPUNIT_ASSERT (elem->contains_point(elem->centroid()));

      // The vertices must be contained in the element.
      CPPUNIT_ASSERT (elem->contains_point(zero));
      CPPUNIT_ASSERT (elem->contains_point(one));
      CPPUNIT_ASSERT (elem->contains_point(two));
      CPPUNIT_ASSERT (elem->contains_point(three));

      // Verify that a point which is on a mid-edge is contained in the element.
      CPPUNIT_ASSERT (elem->contains_point(Point(epsilon/2, 0, 0.5)));

      // Make sure that "just barely" outside points are outside.
      CPPUNIT_ASSERT (!elem->contains_point(Point(epsilon, epsilon, epsilon/2)));
      CPPUNIT_ASSERT (!elem->contains_point(Point(epsilon/10, epsilon/10, 1.0)));
      CPPUNIT_ASSERT (!elem->contains_point(Point(epsilon/2, -epsilon/10, 0.5)));
    }
  }
};

CPPUNIT_TEST_SUITE_REGISTRATION( ContainsPointTest );
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: regpathhelper.cxx,v $
 *
 *  $Revision: 1.16 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 17:13: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_comphelper.hxx"

#include <stdio.h>

#ifndef _OSL_FILE_HXX_
#include <osl/file.hxx>
#endif
#ifndef _OSL_SECURITY_HXX_
#include <osl/security.hxx>
#endif
#ifndef _OSL_THREAD_H_
#include <osl/thread.h>
#endif
#ifndef _VOS_PROCESS_HXX_
#include <vos/process.hxx>
#endif
#ifndef _RTL_TEXTENC_H
#include <rtl/textenc.h>
#endif
#ifndef _RTL_URI_H_
#include <rtl/uri.h>
#endif
#ifndef _RTL_URI_HXX_
#include <rtl/uri.hxx>
#endif

using namespace vos;
using namespace osl;
using namespace rtl;

#define PATH_DELEMITTER '/'

#define USER_REGISTRY_NAME_ENV      "STAR_USER_REGISTRY"
#define SYSTEM_REGISTRY_NAME_ENV    "STAR_REGISTRY"
#define REGISTRY_SYSTEM_NAME    "services.rdb"

#define REGISTRY_LOCAL_NAME     "user60.rdb"

#ifdef SAL_UNX
#define CONFIG_PATH_PREFIX      "."
#else
#define CONFIG_PATH_PREFIX      ""
#endif

namespace comphelper
{

/**
   @return sal_True, if the office is started in a portal
                     environment.
           sal_False, if the common office is started
 */
static sal_Bool retrievePortalUserDir( OUString *pDirectory )
{
    OStartupInfo startInfo;
    sal_uInt32 nArgs = startInfo.getCommandArgCount();
    sal_Bool bIsPortalUser = sal_False;
    OUString sArg;
    while( nArgs > 0 )
      {
        if ( !startInfo.getCommandArg(--nArgs, sArg) )
          {
            if ( sArg.indexOf(OUString::createFromAscii("-userid")) == 0 )
            {

                  bIsPortalUser = sal_True;
                sal_Int32 nStart = sArg.lastIndexOf( '[' );
                sal_Int32 nEnd   = sArg.lastIndexOf( ']' );
                if( -1 == nStart || -1 == nEnd || nEnd < nStart)
                {
                    *pDirectory = OUString();
                }
                else
                {
                    OUString aEncHome = sArg.copy( nStart + 1 , nEnd - nStart -1 );
                    *pDirectory = rtl::Uri::decode(aEncHome,
                                                   rtl_UriDecodeWithCharset,
                                                   RTL_TEXTENCODING_UTF8);
                }
                  break;
            }
          }
     }
    return bIsPortalUser;
}

static OUString getDefaultLocalRegistry()
{
    OUString uBuffer, userRegistryName;
    OUString portalUserDir;

    sal_Bool bIsPortalUser = retrievePortalUserDir( &portalUserDir );

    if ( bIsPortalUser )
       {
        if(  portalUserDir.getLength() )
        {
            FileBase::getFileURLFromSystemPath( portalUserDir , portalUserDir );
            userRegistryName = portalUserDir;
            userRegistryName += OUString( RTL_CONSTASCII_USTRINGPARAM(
                "/user/" REGISTRY_LOCAL_NAME ) );

            // Directory creation is probably necessary for bootstrapping a new
            // user in the portal environment (the ucb uses this function).
            // This should be solved differently, as
            // no one expects this function to create anything ...
            OUString sSeparator(RTL_CONSTASCII_USTRINGPARAM("/"));
            OUString sPath(RTL_CONSTASCII_USTRINGPARAM("file://"));
            FileBase::RC retRC = FileBase::E_None;

            sal_Int32 nIndex = 3;
            sPath += userRegistryName.getToken(2, '/', nIndex);
            while( nIndex != -1 )
            {
                sPath += sSeparator;
                sPath += userRegistryName.getToken(0, '/', nIndex);
                if( nIndex == -1 )
                    break;
                Directory aDir( sPath );
                if( aDir.open() == FileBase::E_NOENT )
                {
                    retRC = Directory::create(sPath);
                    if ( retRC != FileBase::E_None && retRC != FileBase::E_EXIST)
                    {
                        return OUString();
                    }
                }
            }
        }
    }
    else /* bIsPortalUser */
    {
        ::osl::Security aUserSecurity;
        aUserSecurity.getConfigDir( userRegistryName );
        userRegistryName += OUString( RTL_CONSTASCII_USTRINGPARAM(
            "/" CONFIG_PATH_PREFIX REGISTRY_LOCAL_NAME ) );
    }

    return userRegistryName;
}

OUString getPathToUserRegistry()
{
    OUString    userRegistryName;
    FILE        *f=NULL;

    // search the environment STAR_USER_REGISTRY
    OString sBuffer( getenv(USER_REGISTRY_NAME_ENV) );
    if ( sBuffer.getLength() > 0 )
    {
        f = fopen( sBuffer.getStr(), "r" );

        if (f != NULL)
        {
            fclose(f);
            userRegistryName = OStringToOUString( sBuffer, osl_getThreadTextEncoding() );
        }
    }

    if ( !userRegistryName.getLength() )
    {
        userRegistryName = getDefaultLocalRegistry();
    }

    return userRegistryName;
}

OUString getPathToSystemRegistry()
{
    OUString uBuffer;
    OUString registryBaseName( RTL_CONSTASCII_USTRINGPARAM(REGISTRY_SYSTEM_NAME) );
    OUString systemRegistryName;
    FILE     *f=NULL;

    // search in the directory of the executable
    OStartupInfo info;
    if( OStartupInfo::E_None == info.getExecutableFile(uBuffer) )
    {
        sal_uInt32  lastIndex = uBuffer.lastIndexOf(PATH_DELEMITTER);
        if (lastIndex > 0)
        {
            uBuffer = uBuffer.copy(0, lastIndex + 1);
        }

        uBuffer += registryBaseName;

        if (!FileBase::getSystemPathFromFileURL(uBuffer, systemRegistryName))
        {
            OString tmpStr( OUStringToOString(systemRegistryName, osl_getThreadTextEncoding()) );
            f = fopen( tmpStr.getStr(), "r" );
        }
    }

    if (f == NULL)
    {
        // search the environment STAR_REGISTRY
        OString tmpStr( getenv(SYSTEM_REGISTRY_NAME_ENV) );
        if ( tmpStr.getLength() > 0 )
        {
            f = fopen(tmpStr.getStr(), "r");

            if (f != NULL)
            {
                fclose(f);
                systemRegistryName = OStringToOUString( tmpStr, osl_getThreadTextEncoding() );
            } else
            {
                systemRegistryName = OUString();
            }
        }
    } else
    {
        fclose(f);
    }

    return systemRegistryName;
}

}

<commit_msg>INTEGRATION: CWS changefileheader (1.16.160); FILE MERGED 2008/04/01 15:05:28 thb 1.16.160.2: #i85898# Stripping all external header guards 2008/03/31 12:19:33 rt 1.16.160.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: regpathhelper.cxx,v $
 * $Revision: 1.17 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

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

#include <stdio.h>
#include <osl/file.hxx>
#include <osl/security.hxx>
#include <osl/thread.h>
#include <vos/process.hxx>
#include <rtl/textenc.h>
#include <rtl/uri.h>
#include <rtl/uri.hxx>

using namespace vos;
using namespace osl;
using namespace rtl;

#define PATH_DELEMITTER '/'

#define USER_REGISTRY_NAME_ENV      "STAR_USER_REGISTRY"
#define SYSTEM_REGISTRY_NAME_ENV    "STAR_REGISTRY"
#define REGISTRY_SYSTEM_NAME    "services.rdb"

#define REGISTRY_LOCAL_NAME     "user60.rdb"

#ifdef SAL_UNX
#define CONFIG_PATH_PREFIX      "."
#else
#define CONFIG_PATH_PREFIX      ""
#endif

namespace comphelper
{

/**
   @return sal_True, if the office is started in a portal
                     environment.
           sal_False, if the common office is started
 */
static sal_Bool retrievePortalUserDir( OUString *pDirectory )
{
    OStartupInfo startInfo;
    sal_uInt32 nArgs = startInfo.getCommandArgCount();
    sal_Bool bIsPortalUser = sal_False;
    OUString sArg;
    while( nArgs > 0 )
      {
        if ( !startInfo.getCommandArg(--nArgs, sArg) )
          {
            if ( sArg.indexOf(OUString::createFromAscii("-userid")) == 0 )
            {

                  bIsPortalUser = sal_True;
                sal_Int32 nStart = sArg.lastIndexOf( '[' );
                sal_Int32 nEnd   = sArg.lastIndexOf( ']' );
                if( -1 == nStart || -1 == nEnd || nEnd < nStart)
                {
                    *pDirectory = OUString();
                }
                else
                {
                    OUString aEncHome = sArg.copy( nStart + 1 , nEnd - nStart -1 );
                    *pDirectory = rtl::Uri::decode(aEncHome,
                                                   rtl_UriDecodeWithCharset,
                                                   RTL_TEXTENCODING_UTF8);
                }
                  break;
            }
          }
     }
    return bIsPortalUser;
}

static OUString getDefaultLocalRegistry()
{
    OUString uBuffer, userRegistryName;
    OUString portalUserDir;

    sal_Bool bIsPortalUser = retrievePortalUserDir( &portalUserDir );

    if ( bIsPortalUser )
       {
        if(  portalUserDir.getLength() )
        {
            FileBase::getFileURLFromSystemPath( portalUserDir , portalUserDir );
            userRegistryName = portalUserDir;
            userRegistryName += OUString( RTL_CONSTASCII_USTRINGPARAM(
                "/user/" REGISTRY_LOCAL_NAME ) );

            // Directory creation is probably necessary for bootstrapping a new
            // user in the portal environment (the ucb uses this function).
            // This should be solved differently, as
            // no one expects this function to create anything ...
            OUString sSeparator(RTL_CONSTASCII_USTRINGPARAM("/"));
            OUString sPath(RTL_CONSTASCII_USTRINGPARAM("file://"));
            FileBase::RC retRC = FileBase::E_None;

            sal_Int32 nIndex = 3;
            sPath += userRegistryName.getToken(2, '/', nIndex);
            while( nIndex != -1 )
            {
                sPath += sSeparator;
                sPath += userRegistryName.getToken(0, '/', nIndex);
                if( nIndex == -1 )
                    break;
                Directory aDir( sPath );
                if( aDir.open() == FileBase::E_NOENT )
                {
                    retRC = Directory::create(sPath);
                    if ( retRC != FileBase::E_None && retRC != FileBase::E_EXIST)
                    {
                        return OUString();
                    }
                }
            }
        }
    }
    else /* bIsPortalUser */
    {
        ::osl::Security aUserSecurity;
        aUserSecurity.getConfigDir( userRegistryName );
        userRegistryName += OUString( RTL_CONSTASCII_USTRINGPARAM(
            "/" CONFIG_PATH_PREFIX REGISTRY_LOCAL_NAME ) );
    }

    return userRegistryName;
}

OUString getPathToUserRegistry()
{
    OUString    userRegistryName;
    FILE        *f=NULL;

    // search the environment STAR_USER_REGISTRY
    OString sBuffer( getenv(USER_REGISTRY_NAME_ENV) );
    if ( sBuffer.getLength() > 0 )
    {
        f = fopen( sBuffer.getStr(), "r" );

        if (f != NULL)
        {
            fclose(f);
            userRegistryName = OStringToOUString( sBuffer, osl_getThreadTextEncoding() );
        }
    }

    if ( !userRegistryName.getLength() )
    {
        userRegistryName = getDefaultLocalRegistry();
    }

    return userRegistryName;
}

OUString getPathToSystemRegistry()
{
    OUString uBuffer;
    OUString registryBaseName( RTL_CONSTASCII_USTRINGPARAM(REGISTRY_SYSTEM_NAME) );
    OUString systemRegistryName;
    FILE     *f=NULL;

    // search in the directory of the executable
    OStartupInfo info;
    if( OStartupInfo::E_None == info.getExecutableFile(uBuffer) )
    {
        sal_uInt32  lastIndex = uBuffer.lastIndexOf(PATH_DELEMITTER);
        if (lastIndex > 0)
        {
            uBuffer = uBuffer.copy(0, lastIndex + 1);
        }

        uBuffer += registryBaseName;

        if (!FileBase::getSystemPathFromFileURL(uBuffer, systemRegistryName))
        {
            OString tmpStr( OUStringToOString(systemRegistryName, osl_getThreadTextEncoding()) );
            f = fopen( tmpStr.getStr(), "r" );
        }
    }

    if (f == NULL)
    {
        // search the environment STAR_REGISTRY
        OString tmpStr( getenv(SYSTEM_REGISTRY_NAME_ENV) );
        if ( tmpStr.getLength() > 0 )
        {
            f = fopen(tmpStr.getStr(), "r");

            if (f != NULL)
            {
                fclose(f);
                systemRegistryName = OStringToOUString( tmpStr, osl_getThreadTextEncoding() );
            } else
            {
                systemRegistryName = OUString();
            }
        }
    } else
    {
        fclose(f);
    }

    return systemRegistryName;
}

}

<|endoftext|>


<commit_before>#pragma once

namespace kengine {
    struct CommandLineComponent {
        int argc = 0;
        const char ** argv = nullptr;
    };
}<commit_msg>reflectible CommandLineComponent<commit_after>#pragma once

#include <vector>
#include <string>
#include "reflection.hpp"

namespace kengine {
    struct CommandLineComponent {
        std::vector<std::string> arguments;
    };
}

#define refltype kengine::CommandLineComponent
putils_reflection_info{
    putils_reflection_class_name;
    putils_reflection_attributes(
        putils_reflection_attribute(arguments)
    );
};
#undef refltype<|endoftext|>


<commit_before>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * 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 <grpcpp/channel.h>

#include <chrono>
#include <condition_variable>
#include <cstring>
#include <memory>
#include <mutex>

#include <grpc/grpc.h>
#include <grpc/slice.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
#include <grpcpp/client_context.h>
#include <grpcpp/completion_queue.h>
#include <grpcpp/impl/call.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/grpc_library.h>
#include <grpcpp/impl/rpc_method.h>
#include <grpcpp/security/credentials.h>
#include <grpcpp/support/channel_arguments.h>
#include <grpcpp/support/config.h>
#include <grpcpp/support/status.h>
#include <grpcpp/support/time.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/surface/completion_queue.h"

namespace grpc {

static internal::GrpcLibraryInitializer g_gli_initializer;
Channel::Channel(const grpc::string& host, grpc_channel* channel)
    : host_(host), c_channel_(channel) {
  g_gli_initializer.summon();
}

Channel::~Channel() {
  grpc_channel_destroy(c_channel_);
  if (callback_cq_ != nullptr) {
    callback_cq_->Shutdown();
  }
}

namespace {

grpc::string GetChannelInfoField(grpc_channel* channel,
                                 grpc_channel_info* channel_info,
                                 char*** channel_info_field) {
  char* value = nullptr;
  memset(channel_info, 0, sizeof(*channel_info));
  *channel_info_field = &value;
  grpc_channel_get_info(channel, channel_info);
  if (value == nullptr) return "";
  grpc::string result = value;
  gpr_free(value);
  return result;
}

}  // namespace

grpc::string Channel::GetLoadBalancingPolicyName() const {
  grpc_channel_info channel_info;
  return GetChannelInfoField(c_channel_, &channel_info,
                             &channel_info.lb_policy_name);
}

grpc::string Channel::GetServiceConfigJSON() const {
  grpc_channel_info channel_info;
  return GetChannelInfoField(c_channel_, &channel_info,
                             &channel_info.service_config_json);
}

namespace experimental {

void ChannelResetConnectionBackoff(Channel* channel) {
  grpc_channel_reset_connect_backoff(channel->c_channel_);
}

}  // namespace experimental

internal::Call Channel::CreateCall(const internal::RpcMethod& method,
                                   ClientContext* context,
                                   CompletionQueue* cq) {
  const bool kRegistered = method.channel_tag() && context->authority().empty();
  grpc_call* c_call = nullptr;
  if (kRegistered) {
    c_call = grpc_channel_create_registered_call(
        c_channel_, context->propagate_from_call_,
        context->propagation_options_.c_bitmask(), cq->cq(),
        method.channel_tag(), context->raw_deadline(), nullptr);
  } else {
    const char* host_str = nullptr;
    if (!context->authority().empty()) {
      host_str = context->authority_.c_str();
    } else if (!host_.empty()) {
      host_str = host_.c_str();
    }
    grpc_slice method_slice =
        SliceFromArray(method.name(), strlen(method.name()));
    grpc_slice host_slice;
    if (host_str != nullptr) {
      host_slice = SliceFromArray(host_str, strlen(host_str));
    }
    c_call = grpc_channel_create_call(
        c_channel_, context->propagate_from_call_,
        context->propagation_options_.c_bitmask(), cq->cq(), method_slice,
        host_str == nullptr ? nullptr : &host_slice, context->raw_deadline(),
        nullptr);
    grpc_slice_unref(method_slice);
    if (host_str != nullptr) {
      grpc_slice_unref(host_slice);
    }
  }
  grpc_census_call_set_context(c_call, context->census_context());
  context->set_call(c_call, shared_from_this());
  return internal::Call(c_call, this, cq);
}

void Channel::PerformOpsOnCall(internal::CallOpSetInterface* ops,
                               internal::Call* call) {
  static const size_t MAX_OPS = 8;
  size_t nops = 0;
  grpc_op cops[MAX_OPS];
  ops->FillOps(call->call(), cops, &nops);
  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call->call(), cops, nops,
                                                   ops->cq_tag(), nullptr));
}

void* Channel::RegisterMethod(const char* method) {
  return grpc_channel_register_call(
      c_channel_, method, host_.empty() ? nullptr : host_.c_str(), nullptr);
}

grpc_connectivity_state Channel::GetState(bool try_to_connect) {
  return grpc_channel_check_connectivity_state(c_channel_, try_to_connect);
}

namespace {

class TagSaver final : public internal::CompletionQueueTag {
 public:
  explicit TagSaver(void* tag) : tag_(tag) {}
  ~TagSaver() override {}
  bool FinalizeResult(void** tag, bool* status) override {
    *tag = tag_;
    delete this;
    return true;
  }

 private:
  void* tag_;
};

}  // namespace

void Channel::NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
                                      gpr_timespec deadline,
                                      CompletionQueue* cq, void* tag) {
  TagSaver* tag_saver = new TagSaver(tag);
  grpc_channel_watch_connectivity_state(c_channel_, last_observed, deadline,
                                        cq->cq(), tag_saver);
}

bool Channel::WaitForStateChangeImpl(grpc_connectivity_state last_observed,
                                     gpr_timespec deadline) {
  CompletionQueue cq;
  bool ok = false;
  void* tag = nullptr;
  NotifyOnStateChangeImpl(last_observed, deadline, &cq, nullptr);
  cq.Next(&tag, &ok);
  GPR_ASSERT(tag == nullptr);
  return ok;
}

namespace {
class ShutdownCallback : public grpc_experimental_completion_queue_functor {
 public:
  ShutdownCallback() { functor_run = &ShutdownCallback::Run; }
  // TakeCQ takes ownership of the cq into the shutdown callback
  // so that the shutdown callback will be responsible for destroying it
  void TakeCQ(CompletionQueue* cq) { cq_ = cq; }

  // The Run function will get invoked by the completion queue library
  // when the shutdown is actually complete
  static void Run(grpc_experimental_completion_queue_functor* cb, int) {
    auto* callback = static_cast<ShutdownCallback*>(cb);
    delete callback->cq_;
    grpc_core::Delete(callback);
  }

 private:
  CompletionQueue* cq_ = nullptr;
};
}  // namespace

CompletionQueue* Channel::CallbackCQ() {
  // TODO(vjpai): Consider using a single global CQ for the default CQ
  // if there is no explicit per-channel CQ registered
  std::lock_guard<std::mutex> l(mu_);
  if (callback_cq_ == nullptr) {
    auto* shutdown_callback = grpc_core::New<ShutdownCallback>();
    callback_cq_ = new CompletionQueue(grpc_completion_queue_attributes{
        GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING,
        shutdown_callback});

    // Transfer ownership of the new cq to its own shutdown callback
    shutdown_callback->TakeCQ(callback_cq_);
  }
  return callback_cq_;
}

}  // namespace grpc
<commit_msg>Use SliceFromCopiedString() for host name.<commit_after>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * 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 <grpcpp/channel.h>

#include <chrono>
#include <condition_variable>
#include <cstring>
#include <memory>
#include <mutex>

#include <grpc/grpc.h>
#include <grpc/slice.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
#include <grpcpp/client_context.h>
#include <grpcpp/completion_queue.h>
#include <grpcpp/impl/call.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/grpc_library.h>
#include <grpcpp/impl/rpc_method.h>
#include <grpcpp/security/credentials.h>
#include <grpcpp/support/channel_arguments.h>
#include <grpcpp/support/config.h>
#include <grpcpp/support/status.h>
#include <grpcpp/support/time.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/surface/completion_queue.h"

namespace grpc {

static internal::GrpcLibraryInitializer g_gli_initializer;
Channel::Channel(const grpc::string& host, grpc_channel* channel)
    : host_(host), c_channel_(channel) {
  g_gli_initializer.summon();
}

Channel::~Channel() {
  grpc_channel_destroy(c_channel_);
  if (callback_cq_ != nullptr) {
    callback_cq_->Shutdown();
  }
}

namespace {

grpc::string GetChannelInfoField(grpc_channel* channel,
                                 grpc_channel_info* channel_info,
                                 char*** channel_info_field) {
  char* value = nullptr;
  memset(channel_info, 0, sizeof(*channel_info));
  *channel_info_field = &value;
  grpc_channel_get_info(channel, channel_info);
  if (value == nullptr) return "";
  grpc::string result = value;
  gpr_free(value);
  return result;
}

}  // namespace

grpc::string Channel::GetLoadBalancingPolicyName() const {
  grpc_channel_info channel_info;
  return GetChannelInfoField(c_channel_, &channel_info,
                             &channel_info.lb_policy_name);
}

grpc::string Channel::GetServiceConfigJSON() const {
  grpc_channel_info channel_info;
  return GetChannelInfoField(c_channel_, &channel_info,
                             &channel_info.service_config_json);
}

namespace experimental {

void ChannelResetConnectionBackoff(Channel* channel) {
  grpc_channel_reset_connect_backoff(channel->c_channel_);
}

}  // namespace experimental

internal::Call Channel::CreateCall(const internal::RpcMethod& method,
                                   ClientContext* context,
                                   CompletionQueue* cq) {
  const bool kRegistered = method.channel_tag() && context->authority().empty();
  grpc_call* c_call = nullptr;
  if (kRegistered) {
    c_call = grpc_channel_create_registered_call(
        c_channel_, context->propagate_from_call_,
        context->propagation_options_.c_bitmask(), cq->cq(),
        method.channel_tag(), context->raw_deadline(), nullptr);
  } else {
    const string* host_str = nullptr;
    if (!context->authority().empty()) {
      host_str = &context->authority_;
    } else if (!host_.empty()) {
      host_str = &host_;
    }
    grpc_slice method_slice =
        SliceFromArray(method.name(), strlen(method.name()));
    grpc_slice host_slice;
    if (host_str != nullptr) {
      host_slice = SliceFromCopiedString(*host_str);
    }
    c_call = grpc_channel_create_call(
        c_channel_, context->propagate_from_call_,
        context->propagation_options_.c_bitmask(), cq->cq(), method_slice,
        host_str == nullptr ? nullptr : &host_slice, context->raw_deadline(),
        nullptr);
    grpc_slice_unref(method_slice);
    if (host_str != nullptr) {
      grpc_slice_unref(host_slice);
    }
  }
  grpc_census_call_set_context(c_call, context->census_context());
  context->set_call(c_call, shared_from_this());
  return internal::Call(c_call, this, cq);
}

void Channel::PerformOpsOnCall(internal::CallOpSetInterface* ops,
                               internal::Call* call) {
  static const size_t MAX_OPS = 8;
  size_t nops = 0;
  grpc_op cops[MAX_OPS];
  ops->FillOps(call->call(), cops, &nops);
  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call->call(), cops, nops,
                                                   ops->cq_tag(), nullptr));
}

void* Channel::RegisterMethod(const char* method) {
  return grpc_channel_register_call(
      c_channel_, method, host_.empty() ? nullptr : host_.c_str(), nullptr);
}

grpc_connectivity_state Channel::GetState(bool try_to_connect) {
  return grpc_channel_check_connectivity_state(c_channel_, try_to_connect);
}

namespace {

class TagSaver final : public internal::CompletionQueueTag {
 public:
  explicit TagSaver(void* tag) : tag_(tag) {}
  ~TagSaver() override {}
  bool FinalizeResult(void** tag, bool* status) override {
    *tag = tag_;
    delete this;
    return true;
  }

 private:
  void* tag_;
};

}  // namespace

void Channel::NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
                                      gpr_timespec deadline,
                                      CompletionQueue* cq, void* tag) {
  TagSaver* tag_saver = new TagSaver(tag);
  grpc_channel_watch_connectivity_state(c_channel_, last_observed, deadline,
                                        cq->cq(), tag_saver);
}

bool Channel::WaitForStateChangeImpl(grpc_connectivity_state last_observed,
                                     gpr_timespec deadline) {
  CompletionQueue cq;
  bool ok = false;
  void* tag = nullptr;
  NotifyOnStateChangeImpl(last_observed, deadline, &cq, nullptr);
  cq.Next(&tag, &ok);
  GPR_ASSERT(tag == nullptr);
  return ok;
}

namespace {
class ShutdownCallback : public grpc_experimental_completion_queue_functor {
 public:
  ShutdownCallback() { functor_run = &ShutdownCallback::Run; }
  // TakeCQ takes ownership of the cq into the shutdown callback
  // so that the shutdown callback will be responsible for destroying it
  void TakeCQ(CompletionQueue* cq) { cq_ = cq; }

  // The Run function will get invoked by the completion queue library
  // when the shutdown is actually complete
  static void Run(grpc_experimental_completion_queue_functor* cb, int) {
    auto* callback = static_cast<ShutdownCallback*>(cb);
    delete callback->cq_;
    grpc_core::Delete(callback);
  }

 private:
  CompletionQueue* cq_ = nullptr;
};
}  // namespace

CompletionQueue* Channel::CallbackCQ() {
  // TODO(vjpai): Consider using a single global CQ for the default CQ
  // if there is no explicit per-channel CQ registered
  std::lock_guard<std::mutex> l(mu_);
  if (callback_cq_ == nullptr) {
    auto* shutdown_callback = grpc_core::New<ShutdownCallback>();
    callback_cq_ = new CompletionQueue(grpc_completion_queue_attributes{
        GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING,
        shutdown_callback});

    // Transfer ownership of the new cq to its own shutdown callback
    shutdown_callback->TakeCQ(callback_cq_);
  }
  return callback_cq_;
}

}  // namespace grpc
<|endoftext|>


<commit_before>/*
 * Funambol is a mobile platform developed by Funambol, Inc.
 * Copyright (C) 2003 - 2007 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * 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 Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

#include "base/winlog.h"
#include "base/util/utils.h"
#include "base/util/StringBuffer.h"
#include "base/util/WString.h"
#include "base/globalsdef.h"

USE_NAMESPACE

#ifdef _WIN32_WCE
#define FUNAMBOL_HEADER "Funambol Windows Mobile Client Log"
#elif WIN32
#define FUNAMBOL_HEADER "Funambol Win32 Client Log"
#endif

static FILE* logFile = NULL;

static WString      wlogDir(TEXT("\\"));
static StringBuffer logName(LOG_NAME);
static StringBuffer logPath("\\");
static WCHAR mutexName[128];

HANDLE winLog::wait() {

    HANDLE hMutex = CreateMutex(NULL, TRUE, mutexName);
    switch(GetLastError()) {
        case ERROR_SUCCESS:
            break;
        case ERROR_ALREADY_EXISTS:
            CloseHandle(hMutex);
            hMutex = NULL;
            break;
        default:
            {}
    }
    return hMutex;
}

void winLog::signal(HANDLE hMutex) {
    CloseHandle(hMutex);
}

winLog::winLog(bool resetLog, const char* path, const char* name) {

    setLogPath(path);
    setLogName(name);

    // MUST use a wchar_t* logDir to manage correctly international chars.
    // If using char* logDir and UTF-8, fopen() is not working correctly and
    // will fail to open the log file. (with UTF-8... why?)
    // So we use _wfopen() and a wchar_t* logDir.
    StringBuffer logDir;
    logDir.sprintf("%s\\%s", logPath.c_str(), logName.c_str());
    WCHAR* tmp = toWideChar(logDir.c_str());
    wlogDir = tmp;
    delete [] tmp;

    //
    // Test to ensure the log file is writable (only if path is set)
    //
    if (path) {
        logFile = _wfopen(wlogDir.c_str(), TEXT("a+"));
        if (logFile == NULL) {
            WCHAR tmp[512];
            wsprintf(tmp, TEXT("Unable to write log file: \"%s\".\nPlease check your user's permissions."), wlogDir.c_str());
            MessageBox(NULL, tmp, TEXT("Funambol"), MB_SETFOREGROUND | MB_OK);
        }
        else {
            fclose(logFile);

            if (resetLog) {
                reset(FUNAMBOL_HEADER);
            }
        }
    }
}

winLog::~winLog() {
    if (logFile != NULL) {
        fclose(logFile);
    }
}

void winLog::setLogPath(const char* configLogPath) {

    if (configLogPath != NULL) {
        logPath = configLogPath;
    } else {
        logPath = ".";
    }
    if (logName.length() > 0){
        StringBuffer logDir;
        logDir.sprintf("%s\\%s", logPath.c_str(), logName.c_str());
        WCHAR* tmp = toWideChar(logDir.c_str());
        wlogDir = tmp;
        delete [] tmp;
    }
}

void winLog::setLogName(const char* configLogName) {

    if (configLogName != NULL) {
        logName = configLogName;
        wsprintf(mutexName, TEXT("%S"), logName);
    }
    else {
        logName = LOG_NAME;
    }
    if (logPath){
        StringBuffer logDir;
        logDir.sprintf("%s\\%s", logPath.c_str(), logName.c_str());
        WCHAR* tmp = toWideChar(logDir.c_str());
        wlogDir = tmp;
        delete [] tmp;
    }
}

/*
* return a the time to write into log file. If complete is true, it return
* the date too, else only hours, minutes, seconds and milliseconds
*/
static StringBuffer createCurrentTime(bool complete) {

    SYSTEMTIME sys_time;
    TIME_ZONE_INFORMATION timezone;
    GetLocalTime(&sys_time);
    GetTimeZoneInformation(&timezone);

    StringBuffer ret;

    // calculate offset from UTC/GMT in hours:min, positive value
    // means east of Greenwich (e.g. CET = GMT +1)
    char direction = timezone.Bias <= 0 ? '+' : '-';
    int hours      = abs(timezone.Bias / 60) ;
    int minutes    = abs(timezone.Bias % 60);

    if (complete) {
        char fmtComplete[] = "%04d-%02d-%02d %02d:%02d:%02d GMT %c%d:%02d";
        ret.sprintf(fmtComplete, sys_time.wYear, sys_time.wMonth, sys_time.wDay,
                    sys_time.wHour, sys_time.wMinute, sys_time.wSecond,
                    direction, hours, minutes);
    }
    else {
        char fmt[] = "%02d:%02d:%02d GMT %c%d:%02d";
        ret.sprintf(fmt, sys_time.wHour, sys_time.wMinute, sys_time.wSecond,
                    direction, hours, minutes);
    }
    return ret;
}

void winLog::error(const char*  msg, ...) {
   HANDLE h = wait();
   if (!h) return;
    va_list argList;
    va_start (argList, msg);
    printMessage(LOG_ERROR, msg, argList);
    va_end(argList);

   signal(h);
}

void winLog::info(const char*  msg, ...) {
    HANDLE h = wait();
    if (!h) return;
    if (isLoggable(LOG_LEVEL_INFO)) {
        va_list argList;
        va_start (argList, msg);
        printMessage(LOG_INFO, msg, argList);
        va_end(argList);
    }
    signal(h);
}

void winLog::debug(const char*  msg, ...) {
    HANDLE h = wait();
    if (!h) return;
    if (isLoggable(LOG_LEVEL_DEBUG)) {
        va_list argList;
        va_start (argList, msg);
        printMessage(LOG_DEBUG, msg, argList);
        va_end(argList);
    }
    signal(h);
}

void winLog::developer(const char*  msg, ...) {
    HANDLE h = wait();
    if (!h) return;
    if (isLoggable(LOG_LEVEL_INFO)) {
        va_list argList;
        va_start (argList, msg);
        printMessage(LOG_DEBUG, msg, argList);
        va_end(argList);
    }
    signal(h);
}

void winLog::printMessage(const char* level, const char* msg, va_list argList) {

    StringBuffer currentTime = createCurrentTime(false);
    logFile = _wfopen(wlogDir.c_str(), TEXT("a+"));
    if (logFile) {
        fprintf(logFile, "%s [%s] - ", currentTime.c_str(), level);
        vfprintf(logFile, msg, argList);
	    fprintf(logFile, "\n");
	    fclose(logFile);
    }
}

void winLog::reset(const char* title) {
    const char *t = (title) ? title : FUNAMBOL_HEADER;

    StringBuffer currentTime = createCurrentTime(true);
    logFile = _wfopen(wlogDir.c_str(), TEXT("w+"));
    if (logFile) {
        fprintf(logFile, "%s - # %s\n\n", currentTime.c_str(), t);
        fclose(logFile);
    }
}

size_t winLog::getLogSize() {
    size_t ret = 0;

    logFile = _wfopen(wlogDir.c_str(), TEXT("r"));
    if (logFile) {
        ret = fgetsize(logFile);
        fclose(logFile);
    }
    return ret;
}

Log *Log::logger;

Log &Log::instance() {
    if (!logger) {
        logger = new winLog();
    }
    return *logger;
}
<commit_msg>just added the .c_str(), otherwise it won't work on debug mode<commit_after>/*
 * Funambol is a mobile platform developed by Funambol, Inc.
 * Copyright (C) 2003 - 2007 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * 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 Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

#include "base/winlog.h"
#include "base/util/utils.h"
#include "base/util/StringBuffer.h"
#include "base/util/WString.h"
#include "base/globalsdef.h"

USE_NAMESPACE

#ifdef _WIN32_WCE
#define FUNAMBOL_HEADER "Funambol Windows Mobile Client Log"
#elif WIN32
#define FUNAMBOL_HEADER "Funambol Win32 Client Log"
#endif

static FILE* logFile = NULL;

static WString      wlogDir(TEXT("\\"));
static StringBuffer logName(LOG_NAME);
static StringBuffer logPath("\\");
static WCHAR mutexName[128];

HANDLE winLog::wait() {

    HANDLE hMutex = CreateMutex(NULL, TRUE, mutexName);
    switch(GetLastError()) {
        case ERROR_SUCCESS:
            break;
        case ERROR_ALREADY_EXISTS:
            CloseHandle(hMutex);
            hMutex = NULL;
            break;
        default:
            {}
    }
    return hMutex;
}

void winLog::signal(HANDLE hMutex) {
    CloseHandle(hMutex);
}

winLog::winLog(bool resetLog, const char* path, const char* name) {

    setLogPath(path);
    setLogName(name);

    // MUST use a wchar_t* logDir to manage correctly international chars.
    // If using char* logDir and UTF-8, fopen() is not working correctly and
    // will fail to open the log file. (with UTF-8... why?)
    // So we use _wfopen() and a wchar_t* logDir.
    StringBuffer logDir;
    logDir.sprintf("%s\\%s", logPath.c_str(), logName.c_str());
    WCHAR* tmp = toWideChar(logDir.c_str());
    wlogDir = tmp;
    delete [] tmp;

    //
    // Test to ensure the log file is writable (only if path is set)
    //
    if (path) {
        logFile = _wfopen(wlogDir.c_str(), TEXT("a+"));
        if (logFile == NULL) {
            WCHAR tmp[512];
            wsprintf(tmp, TEXT("Unable to write log file: \"%s\".\nPlease check your user's permissions."), wlogDir.c_str());
            MessageBox(NULL, tmp, TEXT("Funambol"), MB_SETFOREGROUND | MB_OK);
        }
        else {
            fclose(logFile);

            if (resetLog) {
                reset(FUNAMBOL_HEADER);
            }
        }
    }
}

winLog::~winLog() {
    if (logFile != NULL) {
        fclose(logFile);
    }
}

void winLog::setLogPath(const char* configLogPath) {

    if (configLogPath != NULL) {
        logPath = configLogPath;
    } else {
        logPath = ".";
    }
    if (logName.length() > 0){
        StringBuffer logDir;
        logDir.sprintf("%s\\%s", logPath.c_str(), logName.c_str());
        WCHAR* tmp = toWideChar(logDir.c_str());
        wlogDir = tmp;
        delete [] tmp;
    }
}

void winLog::setLogName(const char* configLogName) {

    if (configLogName != NULL) {
        logName = configLogName;
        wsprintf(mutexName, TEXT("%S"), logName.c_str());
    }
    else {
        logName = LOG_NAME;
    }
    if (logPath){
        StringBuffer logDir;
        logDir.sprintf("%s\\%s", logPath.c_str(), logName.c_str());
        WCHAR* tmp = toWideChar(logDir.c_str());
        wlogDir = tmp;
        delete [] tmp;
    }
}

/*
* return a the time to write into log file. If complete is true, it return
* the date too, else only hours, minutes, seconds and milliseconds
*/
static StringBuffer createCurrentTime(bool complete) {

    SYSTEMTIME sys_time;
    TIME_ZONE_INFORMATION timezone;
    GetLocalTime(&sys_time);
    GetTimeZoneInformation(&timezone);

    StringBuffer ret;

    // calculate offset from UTC/GMT in hours:min, positive value
    // means east of Greenwich (e.g. CET = GMT +1)
    char direction = timezone.Bias <= 0 ? '+' : '-';
    int hours      = abs(timezone.Bias / 60) ;
    int minutes    = abs(timezone.Bias % 60);

    if (complete) {
        char fmtComplete[] = "%04d-%02d-%02d %02d:%02d:%02d GMT %c%d:%02d";
        ret.sprintf(fmtComplete, sys_time.wYear, sys_time.wMonth, sys_time.wDay,
                    sys_time.wHour, sys_time.wMinute, sys_time.wSecond,
                    direction, hours, minutes);
    }
    else {
        char fmt[] = "%02d:%02d:%02d GMT %c%d:%02d";
        ret.sprintf(fmt, sys_time.wHour, sys_time.wMinute, sys_time.wSecond,
                    direction, hours, minutes);
    }
    return ret;
}

void winLog::error(const char*  msg, ...) {
   HANDLE h = wait();
   if (!h) return;
    va_list argList;
    va_start (argList, msg);
    printMessage(LOG_ERROR, msg, argList);
    va_end(argList);

   signal(h);
}

void winLog::info(const char*  msg, ...) {
    HANDLE h = wait();
    if (!h) return;
    if (isLoggable(LOG_LEVEL_INFO)) {
        va_list argList;
        va_start (argList, msg);
        printMessage(LOG_INFO, msg, argList);
        va_end(argList);
    }
    signal(h);
}

void winLog::debug(const char*  msg, ...) {
    HANDLE h = wait();
    if (!h) return;
    if (isLoggable(LOG_LEVEL_DEBUG)) {
        va_list argList;
        va_start (argList, msg);
        printMessage(LOG_DEBUG, msg, argList);
        va_end(argList);
    }
    signal(h);
}

void winLog::developer(const char*  msg, ...) {
    HANDLE h = wait();
    if (!h) return;
    if (isLoggable(LOG_LEVEL_INFO)) {
        va_list argList;
        va_start (argList, msg);
        printMessage(LOG_DEBUG, msg, argList);
        va_end(argList);
    }
    signal(h);
}

void winLog::printMessage(const char* level, const char* msg, va_list argList) {

    StringBuffer currentTime = createCurrentTime(false);
    logFile = _wfopen(wlogDir.c_str(), TEXT("a+"));
    if (logFile) {
        fprintf(logFile, "%s [%s] - ", currentTime.c_str(), level);
        vfprintf(logFile, msg, argList);
	    fprintf(logFile, "\n");
	    fclose(logFile);
    }
}

void winLog::reset(const char* title) {
    const char *t = (title) ? title : FUNAMBOL_HEADER;

    StringBuffer currentTime = createCurrentTime(true);
    logFile = _wfopen(wlogDir.c_str(), TEXT("w+"));
    if (logFile) {
        fprintf(logFile, "%s - # %s\n\n", currentTime.c_str(), t);
        fclose(logFile);
    }
}

size_t winLog::getLogSize() {
    size_t ret = 0;

    logFile = _wfopen(wlogDir.c_str(), TEXT("r"));
    if (logFile) {
        ret = fgetsize(logFile);
        fclose(logFile);
    }
    return ret;
}

Log *Log::logger;

Log &Log::instance() {
    if (!logger) {
        logger = new winLog();
    }
    return *logger;
}
<|endoftext|>


<commit_before>#include "LuaPbIntfImpl.h"

#include <google/protobuf/compiler/importer.h>  // for DiskSourceTree

#include <sstream>  // for ostringstream

// See CommandLineInterface::Run().

class ErrorCollector : public google::protobuf::compiler::MultiFileErrorCollector
{
public:
    void Clear() { m_sError.clear(); }
    const std::string& GetError() const { return m_sError; }

    // Only record the last error.
    void AddError(const std::string & filename,
        int line, int column, const std::string & message) override
    {
        std::ostringstream oss;
        oss << filename << ":" << line << ": " << message;
        m_sError = oss.str();
    }
private:
    std::string m_sError;
};

LuaPbIntfImpl::LuaPbIntfImpl()
    : m_pDiskSourceTree(new DiskSourceTree),  // unique_ptr
    m_pErrorCollector(new ErrorCollector),  // unique_ptr
    m_pImporter(new Importer(m_pDiskSourceTree.get(),  // unique_ptr
        m_pErrorCollector.get()))
{
}

LuaPbIntfImpl::~LuaPbIntfImpl()
{
}

// e.g. AddProtoPath("proto")
// e.g. AddProtoPath("d:/proto")
void LuaPbIntfImpl::AddProtoPath(const string& sProtoPath)
{
    MapPath("", sProtoPath);
}

void LuaPbIntfImpl::MapPath(
    const string& sVirtualPath,
    const string& sDiskPath)
{
    m_pDiskSourceTree->MapPath(sVirtualPath, sDiskPath);
}

// e.g. CompileProtoFile("bar/foo.proto")
std::tuple<bool, std::string>
LuaPbIntfImpl::CompileProtoFile(const string& sProtoFile)
{
    m_pErrorCollector->Clear();
    const google::protobuf::FileDescriptor* desc =
        m_pImporter->Import(sProtoFile);
    if (desc) return std::make_tuple(true, "");
    return std::make_tuple(false, "Proto file compile error: "
        + m_pErrorCollector->GetError());
}

<commit_msg>Add the current dir as the default proto path.<commit_after>#include "LuaPbIntfImpl.h"

#include <google/protobuf/compiler/importer.h>  // for DiskSourceTree

#include <sstream>  // for ostringstream

// See CommandLineInterface::Run().

class ErrorCollector : public google::protobuf::compiler::MultiFileErrorCollector
{
public:
    void Clear() { m_sError.clear(); }
    const std::string& GetError() const { return m_sError; }

    // Only record the last error.
    void AddError(const std::string & filename,
        int line, int column, const std::string & message) override
    {
        std::ostringstream oss;
        oss << filename << ":" << line << ": " << message;
        m_sError = oss.str();
    }
private:
    std::string m_sError;
};

LuaPbIntfImpl::LuaPbIntfImpl()
    : m_pDiskSourceTree(new DiskSourceTree),  // unique_ptr
    m_pErrorCollector(new ErrorCollector),  // unique_ptr
    m_pImporter(new Importer(m_pDiskSourceTree.get(),  // unique_ptr
        m_pErrorCollector.get()))
{
    // The current dir is the default proto path.
    AddProtoPath("");
}

LuaPbIntfImpl::~LuaPbIntfImpl()
{
}

// e.g. AddProtoPath("proto")
// e.g. AddProtoPath("d:/proto")
void LuaPbIntfImpl::AddProtoPath(const string& sProtoPath)
{
    MapPath("", sProtoPath);
}

void LuaPbIntfImpl::MapPath(
    const string& sVirtualPath,
    const string& sDiskPath)
{
    m_pDiskSourceTree->MapPath(sVirtualPath, sDiskPath);
}

// e.g. CompileProtoFile("bar/foo.proto")
std::tuple<bool, std::string>
LuaPbIntfImpl::CompileProtoFile(const string& sProtoFile)
{
    m_pErrorCollector->Clear();
    const google::protobuf::FileDescriptor* desc =
        m_pImporter->Import(sProtoFile);
    if (desc) return std::make_tuple(true, "");
    return std::make_tuple(false, "Proto file compile error: "
        + m_pErrorCollector->GetError());
}

<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.6  2000/02/06 07:47:33  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.5  2000/02/04 01:49:26  aruna1
 * TreeWalker and NodeIterator changes
 *
 * Revision 1.4  1999/11/30 21:16:25  roddey
 * Changes to add the transcode() method to DOMString, which returns a transcoded
 * version (to local code page) of the DOM string contents. And I changed all of the
 * exception 'throw by pointer' to 'throw by value' style.
 *
 * Revision 1.3  1999/11/23 01:48:16  rahulj
 * Changed 0L to 0. CC under HPUX is happy now.
 *
 * Revision 1.2  1999/11/20 00:56:39  rahulj
 * Source files must end with an un-escaped newline.
 *
 * Revision 1.1.1.1  1999/11/09 01:09:15  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:44:30  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// NodeIteratorImpl.cpp: implementation of the NodeIteratorImpl class.
//
//////////////////////////////////////////////////////////////////////

#include "NodeIteratorImpl.hpp"
#include "DOM_Document.hpp"
#include "DOM_DOMException.hpp"
#include "DocumentImpl.hpp"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

NodeIteratorImpl::NodeIteratorImpl ()
: fDetached(false),
    fNodeFilter(0)
{
}

NodeIteratorImpl::~NodeIteratorImpl ()
{
	fDetached = false;
}

void NodeIteratorImpl::detach ()
{
	fDetached = true;
}

NodeIteratorImpl::NodeIteratorImpl (
                                    DOM_Node root,
                                    unsigned long whatToShow,
                                    DOM_NodeFilter* nodeFilter,
                                    bool expandEntityRef)
:   fDetached(false),
    fRoot(root),
    fCurrentNode(0),
    fWhatToShow(whatToShow),
    fNodeFilter(nodeFilter),
    fForward(true),
    fExpandEntityReferences(expandEntityRef)
{

}

NodeIteratorImpl::NodeIteratorImpl ( const NodeIteratorImpl& toCopy)
    :   fDetached(toCopy.fDetached),
    fRoot(toCopy.fRoot),
    fCurrentNode(toCopy.fCurrentNode),
    fWhatToShow(toCopy.fWhatToShow),
    fNodeFilter(toCopy.fNodeFilter),
    fForward(toCopy.fForward),
    fExpandEntityReferences(toCopy.fExpandEntityReferences)
{
}

NodeIteratorImpl& NodeIteratorImpl::operator= (const NodeIteratorImpl& other) {
    fRoot                   = other.fRoot;
    fCurrentNode            = other.fRoot;
    fWhatToShow             = other.fWhatToShow;
    fNodeFilter             = other.fNodeFilter;
    fForward                = other.fForward;
	fDetached               = other.fDetached;
    fExpandEntityReferences = other.fExpandEntityReferences;
    return *this;
}

// Implementation Note: Note that the iterator looks at whatToShow
// and filter values at each call, and therefore one _could_ add
// setters for these values and alter them while iterating!

/** Return the whatToShow value */

unsigned long NodeIteratorImpl::getWhatToShow () {
    return fWhatToShow;
}

/** Return the filter */

DOM_NodeFilter* NodeIteratorImpl::getFilter () {
    return fNodeFilter;
}

/** Get the expandEntity reference flag. */
bool NodeIteratorImpl::getExpandEntityReferences()
{
    return fExpandEntityReferences;
}

/** Return the next DOM_Node in the Iterator. The node is the next node in
 *  depth-first order which also passes the filter, and whatToShow.
 *  A null return means either that
 */

DOM_Node NodeIteratorImpl::nextNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if root is null there is no next node.
    if (fRoot.isNull())
			return result;

    DOM_Node aNextNode = fCurrentNode;
    bool accepted = false; // the next node has not been accepted.

    while (!accepted) {

        // if last direction is not forward, repeat node.
        if (!fForward && !aNextNode.isNull()) {
            //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName());
            aNextNode = fCurrentNode;
        } else {
        // else get the next node via depth-first
            aNextNode = nextNode(aNextNode, true);
        }

        fForward = true; //REVIST: should direction be set forward before null check?

        // nothing in the list. return null.
        if (aNextNode.isNull())
					return result;

        // does node pass the filters and whatToShow?
        accepted = acceptNode(aNextNode);
        if (accepted) {
            // if so, then the node is the current node.
            fCurrentNode = aNextNode;
            return fCurrentNode;
				}

    }

    // no nodes, or no accepted nodes.
    return result;
}

/** Return the previous Node in the Iterator. The node is the next node in
 *  _backwards_ depth-first order which also passes the filter, and whatToShow.
 */

DOM_Node NodeIteratorImpl::previousNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if the root is null, or the current node is null, return null.
    if (fRoot.isNull() || fCurrentNode.isNull())
			return result;

    DOM_Node aPreviousNode = fCurrentNode;
    bool accepted = false;

    while (!accepted) {

        if (fForward && ! aPreviousNode.isNull()) {
            //repeat last node.
            aPreviousNode = fCurrentNode;
        } else {
            // get previous node in backwards depth first order.
            aPreviousNode = previousNode(aPreviousNode);
        }

        // we are going backwards
        fForward = false;

        // if the new previous node is null, we're at head or past the root,
        // so return null.
        if (aPreviousNode.isNull())
					return result;

        // check if node passes filters and whatToShow.
        accepted = acceptNode(aPreviousNode);
        if (accepted) {
            // if accepted, update the current node, and return it.
            fCurrentNode = aPreviousNode;
            return fCurrentNode;
        }
    }
    // there are no nodes?
    return result;
}

/** The node is accepted if it passes the whatToShow and the filter. */
bool NodeIteratorImpl::acceptNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (fNodeFilter == 0) {
        return ((fWhatToShow & ((1 << node.getNodeType()) - 1)) != 0);
    } else {
        return ((fWhatToShow & ((1 << node.getNodeType()) - 1)) != 0 )
            && fNodeFilter->acceptNode(node) == DOM_NodeFilter::FILTER_ACCEPT;
    }
}

/** Return node, if matches or any parent if matches. */
DOM_Node NodeIteratorImpl::matchNodeOrParent (DOM_Node node) {
		DOM_Node result;

    for (DOM_Node n = node; n != fRoot; n = n.getParentNode()) {
        if (node == n) return n;
    }

    return result;
}

/** The method nextNode(DOM_Node, bool) returns the next node
 *  from the actual DOM tree.
 *
 *  The bool visitChildren determines whether to visit the children.
 *  The result is the nextNode.
 */

DOM_Node NodeIteratorImpl::nextNode (DOM_Node node, bool visitChildren) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (node.isNull()) return fRoot;

    DOM_Node result;
    // only check children if we visit children.
    if (visitChildren) {
        //if hasChildren, return 1st child.
        if (node.hasChildNodes()) {
            result = node.getFirstChild();
            return result;
        }
    }

    // if hasSibling, return sibling
    result = node.getNextSibling();
    if (! result.isNull()) return result;

    // return parent's 1st sibling.
    DOM_Node parent = node.getParentNode();
    while (!parent.isNull() && parent != fRoot) {
        result = parent.getNextSibling();
        if (!result.isNull()) {
            return result;
        } else {
            parent = parent.getParentNode();
        }

    } // while (parent != null && parent != fRoot) {

    // end of list, return null
		DOM_Node aNull;
    return aNull;
}

/** The method previousNode(DOM_Node) returns the previous node
 *  from the actual DOM tree.
 */

DOM_Node NodeIteratorImpl::previousNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    DOM_Node result;

    // if we're at the root, return null.
    if (node == fRoot)
			return result;

    // get sibling
    result = node.getPreviousSibling();
    if (result.isNull()) {
        //if 1st sibling, return parent
        result = node.getParentNode();
        return result;
    }

    // if sibling has children, keep getting last child of child.
    if (result.hasChildNodes()) {
        while (result.hasChildNodes()) {
            result = result.getLastChild();
        }
    }

    return result;
}

/** Fix-up the iterator on a remove. Called by DOM or otherwise,
 *  before an actual DOM remove.
 */

void NodeIteratorImpl::removeNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    // Implementation note: Fix-up means setting the current node properly
    // after a remove.

    if (node.isNull())
				return;

    DOM_Node deleted = matchNodeOrParent(node);

    if (deleted.isNull()) return;

    if (fForward) {
        fCurrentNode = previousNode(deleted);
    } else
    // if (!fForward)
    {
        DOM_Node next = nextNode(deleted, false);
        if (! next.isNull()) {
            // normal case: there _are_ nodes following this in the iterator.
            fCurrentNode = next;
        } else {
            // the last node in the iterator is to be removed,
            // so we set the current node to be the previous one.
            fCurrentNode = previousNode(deleted);
            fForward = true;
        }

    }

}

void NodeIteratorImpl::unreferenced()
{
    DOM_Document doc = fRoot.getOwnerDocument();
    DocumentImpl* impl;

    if (! doc.isNull()) {
        impl = (DocumentImpl *) doc.fImpl;
    }
    else
        impl = (DocumentImpl *) fRoot.fImpl;

    if (impl->iterators != 0L) {
        int i;
        int sz = impl->iterators->size();
        for (i = 0; i < sz; i++)
            if (impl->iterators->elementAt(i) == this) {
                impl->iterators->removeElementAt(i);
                break;
            }
    }

    delete this;
}
<commit_msg>nodeIterator previous tracking problem solved<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.7  2000/02/08 01:16:18  aruna1
 * nodeIterator previous tracking problem solved
 *
 * Revision 1.6  2000/02/06 07:47:33  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.5  2000/02/04 01:49:26  aruna1
 * TreeWalker and NodeIterator changes
 *
 * Revision 1.4  1999/11/30 21:16:25  roddey
 * Changes to add the transcode() method to DOMString, which returns a transcoded
 * version (to local code page) of the DOM string contents. And I changed all of the
 * exception 'throw by pointer' to 'throw by value' style.
 *
 * Revision 1.3  1999/11/23 01:48:16  rahulj
 * Changed 0L to 0. CC under HPUX is happy now.
 *
 * Revision 1.2  1999/11/20 00:56:39  rahulj
 * Source files must end with an un-escaped newline.
 *
 * Revision 1.1.1.1  1999/11/09 01:09:15  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:44:30  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// NodeIteratorImpl.cpp: implementation of the NodeIteratorImpl class.
//
//////////////////////////////////////////////////////////////////////

#include "NodeIteratorImpl.hpp"
#include "DOM_Document.hpp"
#include "DOM_DOMException.hpp"
#include "DocumentImpl.hpp"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

NodeIteratorImpl::NodeIteratorImpl ()
: fDetached(false),
    fNodeFilter(0)
{
}

NodeIteratorImpl::~NodeIteratorImpl ()
{
	fDetached = false;
}

void NodeIteratorImpl::detach ()
{
	fDetached = true;
}

NodeIteratorImpl::NodeIteratorImpl (
                                    DOM_Node root,
                                    unsigned long whatToShow,
                                    DOM_NodeFilter* nodeFilter,
                                    bool expandEntityRef)
:   fDetached(false),
    fRoot(root),
    fCurrentNode(0),
    fWhatToShow(whatToShow),
    fNodeFilter(nodeFilter),
    fForward(true),
    fExpandEntityReferences(expandEntityRef)
{

}

NodeIteratorImpl::NodeIteratorImpl ( const NodeIteratorImpl& toCopy)
    :   fDetached(toCopy.fDetached),
    fRoot(toCopy.fRoot),
    fCurrentNode(toCopy.fCurrentNode),
    fWhatToShow(toCopy.fWhatToShow),
    fNodeFilter(toCopy.fNodeFilter),
    fForward(toCopy.fForward),
    fExpandEntityReferences(toCopy.fExpandEntityReferences)
{
}

NodeIteratorImpl& NodeIteratorImpl::operator= (const NodeIteratorImpl& other) {
    fRoot                   = other.fRoot;
    fCurrentNode            = other.fRoot;
    fWhatToShow             = other.fWhatToShow;
    fNodeFilter             = other.fNodeFilter;
    fForward                = other.fForward;
	fDetached               = other.fDetached;
    fExpandEntityReferences = other.fExpandEntityReferences;
    return *this;
}

// Implementation Note: Note that the iterator looks at whatToShow
// and filter values at each call, and therefore one _could_ add
// setters for these values and alter them while iterating!

/** Return the whatToShow value */

unsigned long NodeIteratorImpl::getWhatToShow () {
    return fWhatToShow;
}

/** Return the filter */

DOM_NodeFilter* NodeIteratorImpl::getFilter () {
    return fNodeFilter;
}

/** Get the expandEntity reference flag. */
bool NodeIteratorImpl::getExpandEntityReferences()
{
    return fExpandEntityReferences;
}

/** Return the next DOM_Node in the Iterator. The node is the next node in
 *  depth-first order which also passes the filter, and whatToShow.
 *  A null return means either that
 */

DOM_Node NodeIteratorImpl::nextNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if root is null there is no next node.
    if (fRoot.isNull())
			return result;

    DOM_Node aNextNode = fCurrentNode;
    bool accepted = false; // the next node has not been accepted.

    while (!accepted) {

        // if last direction is not forward, repeat node.
        if (!fForward && !aNextNode.isNull()) {
            //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName());
            aNextNode = fCurrentNode;
        } else {
        // else get the next node via depth-first
            aNextNode = nextNode(aNextNode, true);
        }

        fForward = true; //REVIST: should direction be set forward before null check?

        // nothing in the list. return null.
        if (aNextNode.isNull())
					return result;

        // does node pass the filters and whatToShow?
        accepted = acceptNode(aNextNode);
        if (accepted) {
            // if so, then the node is the current node.
            fCurrentNode = aNextNode;
            return fCurrentNode;
				}

    }

    // no nodes, or no accepted nodes.
    return result;
}

/** Return the previous Node in the Iterator. The node is the next node in
 *  _backwards_ depth-first order which also passes the filter, and whatToShow.
 */

DOM_Node NodeIteratorImpl::previousNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if the root is null, or the current node is null, return null.
    if (fRoot.isNull() || fCurrentNode.isNull())
			return result;

    DOM_Node aPreviousNode = fCurrentNode;
    bool accepted = false;

    while (!accepted) {
        // we are going backwards
        fForward = false;

        if (fForward && ! aPreviousNode.isNull()) {
            //repeat last node.
            aPreviousNode = fCurrentNode;
        } else {
            // get previous node in backwards depth first order.
            aPreviousNode = previousNode(aPreviousNode);
        }

        // if the new previous node is null, we're at head or past the root,
        // so return null.
        if (aPreviousNode.isNull())
					return result;

        // check if node passes filters and whatToShow.
        accepted = acceptNode(aPreviousNode);
        if (accepted) {
            // if accepted, update the current node, and return it.
            fCurrentNode = aPreviousNode;
            return fCurrentNode;
        }
    }
    // there are no nodes?
    return result;
}

/** The node is accepted if it passes the whatToShow and the filter. */
bool NodeIteratorImpl::acceptNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (fNodeFilter == 0) {
        return ((fWhatToShow & ((1 << node.getNodeType()) - 1)) != 0);
    } else {
        return ((fWhatToShow & ((1 << node.getNodeType()) - 1)) != 0 )
            && fNodeFilter->acceptNode(node) == DOM_NodeFilter::FILTER_ACCEPT;
    }
}

/** Return node, if matches or any parent if matches. */
DOM_Node NodeIteratorImpl::matchNodeOrParent (DOM_Node node) {
		DOM_Node result;

    for (DOM_Node n = node; n != fRoot; n = n.getParentNode()) {
        if (node == n) return n;
    }

    return result;
}

/** The method nextNode(DOM_Node, bool) returns the next node
 *  from the actual DOM tree.
 *
 *  The bool visitChildren determines whether to visit the children.
 *  The result is the nextNode.
 */

DOM_Node NodeIteratorImpl::nextNode (DOM_Node node, bool visitChildren) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (node.isNull()) return fRoot;

    DOM_Node result;
    // only check children if we visit children.
    if (visitChildren) {
        //if hasChildren, return 1st child.
        if (node.hasChildNodes()) {
            result = node.getFirstChild();
            return result;
        }
    }

    // if hasSibling, return sibling
    result = node.getNextSibling();
    if (! result.isNull()) return result;

    // return parent's 1st sibling.
    DOM_Node parent = node.getParentNode();
    while (!parent.isNull() && parent != fRoot) {
        result = parent.getNextSibling();
        if (!result.isNull()) {
            return result;
        } else {
            parent = parent.getParentNode();
        }

    } // while (parent != null && parent != fRoot) {

    // end of list, return null
		DOM_Node aNull;
    return aNull;
}

/** The method previousNode(DOM_Node) returns the previous node
 *  from the actual DOM tree.
 */

DOM_Node NodeIteratorImpl::previousNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    DOM_Node result;

    // if we're at the root, return null.
    if (node == fRoot)
			return result;

    // get sibling
    result = node.getPreviousSibling();
    if (result.isNull()) {
        //if 1st sibling, return parent
        result = node.getParentNode();
        return result;
    }

    // if sibling has children, keep getting last child of child.
    if (result.hasChildNodes()) {
        while (result.hasChildNodes()) {
            result = result.getLastChild();
        }
    }

    return result;
}

/** Fix-up the iterator on a remove. Called by DOM or otherwise,
 *  before an actual DOM remove.
 */

void NodeIteratorImpl::removeNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    // Implementation note: Fix-up means setting the current node properly
    // after a remove.

    if (node.isNull())
				return;

    DOM_Node deleted = matchNodeOrParent(node);

    if (deleted.isNull()) return;

    if (fForward) {
        fCurrentNode = previousNode(deleted);
    } else
    // if (!fForward)
    {
        DOM_Node next = nextNode(deleted, false);
        if (! next.isNull()) {
            // normal case: there _are_ nodes following this in the iterator.
            fCurrentNode = next;
        } else {
            // the last node in the iterator is to be removed,
            // so we set the current node to be the previous one.
            fCurrentNode = previousNode(deleted);
            fForward = true;
        }

    }

}

void NodeIteratorImpl::unreferenced()
{
    DOM_Document doc = fRoot.getOwnerDocument();
    DocumentImpl* impl;

    if (! doc.isNull()) {
        impl = (DocumentImpl *) doc.fImpl;
    }
    else
        impl = (DocumentImpl *) fRoot.fImpl;

    if (impl->iterators != 0L) {
        int i;
        int sz = impl->iterators->size();
        for (i = 0; i < sz; i++)
            if (impl->iterators->elementAt(i) == this) {
                impl->iterators->removeElementAt(i);
                break;
            }
    }

    delete this;
}
<|endoftext|>


<commit_before>#include "domain/mesh_cartesian.h"

#include <algorithm>
#include <cmath>
#include <vector>

#include <deal.II/base/point.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/base/tensor.h>
#include <deal.II/base/utilities.h>

#include "problem/parameter_types.h"

namespace bart {

namespace domain {

template <int dim>
MeshCartesian<dim>::MeshCartesian(const std::vector<double> spatial_max,
                                  const std::vector<int> n_cells,
                                  const std::string material_mapping)
    : MeshCartesian(spatial_max, n_cells) {
  ParseMaterialMap(material_mapping);
}

template <int dim>
MeshCartesian<dim>::MeshCartesian(const std::vector<double> spatial_max,
                                  const std::vector<int> n_cells) {

  // Check lengths of spatial max and n_cells
  AssertThrow(spatial_max.size() == dim,
              dealii::ExcMessage("MeshCartesian argument error, incorrect spatial vector size"));
  AssertThrow(n_cells.size() == dim,
              dealii::ExcMessage("MeshCartesian argument error, incorrect number of cells vector size"));

  std::copy(n_cells.begin(), n_cells.end(), n_cells_.begin());
  std::copy(spatial_max.begin(), spatial_max.end(), spatial_max_.begin());
}

template <int dim>
void MeshCartesian<dim>::FillTriangulation(dealii::Triangulation<dim> &to_fill) {

  dealii::Point<dim> diagonal;
  dealii::Point<dim> origin;

  for (int i = 0; i < dim; ++i)
    diagonal[i] = spatial_max_[i];

  std::vector<unsigned int> number_of_cells{n_cells_.begin(), n_cells_.end()};
  dealii::GridGenerator::subdivided_hyper_rectangle(to_fill, number_of_cells,
                                                    origin, diagonal);
}

template <int dim>
void MeshCartesian<dim>::ParseMaterialMap(std::string material_mapping) {
  using dealii::Utilities::split_string_list;
  using dealii::Utilities::string_to_int;
  using StringVector = std::vector<std::string>;

  StringVector z_blocks = split_string_list(material_mapping, "\n\n");

  std::reverse(z_blocks.begin(), z_blocks.end());

  for (unsigned k = 0; k < z_blocks.size(); ++k) {
    StringVector y_line = split_string_list(z_blocks.at(k), "\n");
    std::reverse(y_line.begin(), y_line.end());
    for (unsigned j = 0; j < y_line.size(); ++j) {
      StringVector x_positions = split_string_list(y_line.at(j), " ");
      for (unsigned i = 0; i < x_positions.size(); ++i) {
        std::array<unsigned, 3> index{i, j, k};
        std::array<int, dim> location;
        for (int dir = 0; dir < dim; ++dir)
          location.at(dir) = index.at(dir);
        material_mapping_[location] = string_to_int(x_positions.at(i));
      }
      n_material_cells_.at(0) = x_positions.size();
    }
    if (dim > 1)
      n_material_cells_.at(1) = y_line.size();
  }

  if (dim > 2)
    n_material_cells_.at(2) = z_blocks.size();
}

template <int dim>
void MeshCartesian<dim>::FillMaterialID(dealii::Triangulation<dim> &to_fill) {
  for (auto cell = to_fill.begin_active(); cell != to_fill.end(); ++cell) {
    if (cell->is_locally_owned()) {
      int material_id = GetMaterialID(cell->center());
      cell->set_material_id(material_id);
    }
  }
}

template <int dim>
void MeshCartesian<dim>::FillBoundaryID(dealii::Triangulation<dim> &to_fill) {
  using Boundary = bart::problem::Boundary;
  int faces_per_cell = dealii::GeometryInfo<dim>::faces_per_cell;
  double zero_tol = 1.0e-14;

  for (auto cell = to_fill.begin_active(); cell != to_fill.end(); ++cell) {
    if (cell->is_locally_owned()) {
      for (int face_id = 0; face_id < faces_per_cell; ++face_id) {
        auto face = cell->face(face_id);
        dealii::Point<dim> face_center = face->center();
        //TODO(Josh) add 3D support
        switch (dim) {
          case 2: {
            if (std::fabs(face_center[1]) < zero_tol) {
              face->set_boundary_id(static_cast<int>(Boundary::kYMin));
              break;
            } else if (std::fabs(face_center[1] - spatial_max_[1]) < zero_tol) {
              face->set_boundary_id(static_cast<int>(Boundary::kYMax));
              break;
            }
            [[fallthrough]];
          }
            // Fall through to check x-direction
          case 1: {
            if (std::fabs(face_center[0]) < zero_tol) {
              face->set_boundary_id(static_cast<int>(Boundary::kXMin));
              break;
            } else if (std::fabs(face_center[0] - spatial_max_[0]) < zero_tol) {
              face->set_boundary_id(static_cast<int>(Boundary::kXMax));
              break;
            }
            break;
          }
          default: {
            AssertThrow(false,
                        dealii::ExcMessage("Unsupported number of dimensions in FillBoundaryID"));
          }
        }
      }
    }
  }
}

template <int dim>
int MeshCartesian<dim>::GetMaterialID(dealii::Point<dim> location) {
  std::array<double, dim> array_location;
  for (int i = 0; i < dim; ++i)
    array_location[i] = location[i];
  return GetMaterialID(array_location);
}

template <int dim>
int MeshCartesian<dim>::GetMaterialID(std::array<double, dim> location) {
  std::array<int, dim> relative_location;

  for (int i = 0; i < dim; ++i) {
    double cell_size = spatial_max_.at(i)/n_material_cells_.at(i);
    double cell_location = location.at(i) / cell_size;
    int cell_index = std::floor(cell_location);

    if (static_cast<double>(cell_index) == cell_location && cell_index != 0) {
      relative_location.at(i) = cell_index - 1;
    } else {
      relative_location.at(i) = cell_index;
    }
  }

  return material_mapping_[relative_location];
}

template class MeshCartesian<1>;
template class MeshCartesian<2>;
template class MeshCartesian<3>;

} // namespace domain

} // namespace bart
<commit_msg>added support for filling boundary material ID in 3D<commit_after>#include "domain/mesh_cartesian.h"

#include <algorithm>
#include <cmath>
#include <vector>

#include <deal.II/base/point.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/base/tensor.h>
#include <deal.II/base/utilities.h>

#include "problem/parameter_types.h"

namespace bart {

namespace domain {

template <int dim>
MeshCartesian<dim>::MeshCartesian(const std::vector<double> spatial_max,
                                  const std::vector<int> n_cells,
                                  const std::string material_mapping)
    : MeshCartesian(spatial_max, n_cells) {
  ParseMaterialMap(material_mapping);
}

template <int dim>
MeshCartesian<dim>::MeshCartesian(const std::vector<double> spatial_max,
                                  const std::vector<int> n_cells) {

  // Check lengths of spatial max and n_cells
  AssertThrow(spatial_max.size() == dim,
              dealii::ExcMessage("MeshCartesian argument error, incorrect spatial vector size"));
  AssertThrow(n_cells.size() == dim,
              dealii::ExcMessage("MeshCartesian argument error, incorrect number of cells vector size"));

  std::copy(n_cells.begin(), n_cells.end(), n_cells_.begin());
  std::copy(spatial_max.begin(), spatial_max.end(), spatial_max_.begin());
}

template <int dim>
void MeshCartesian<dim>::FillTriangulation(dealii::Triangulation<dim> &to_fill) {

  dealii::Point<dim> diagonal;
  dealii::Point<dim> origin;

  for (int i = 0; i < dim; ++i)
    diagonal[i] = spatial_max_[i];

  std::vector<unsigned int> number_of_cells{n_cells_.begin(), n_cells_.end()};
  dealii::GridGenerator::subdivided_hyper_rectangle(to_fill, number_of_cells,
                                                    origin, diagonal);
}

template <int dim>
void MeshCartesian<dim>::ParseMaterialMap(std::string material_mapping) {
  using dealii::Utilities::split_string_list;
  using dealii::Utilities::string_to_int;
  using StringVector = std::vector<std::string>;

  StringVector z_blocks = split_string_list(material_mapping, "\n\n");

  std::reverse(z_blocks.begin(), z_blocks.end());

  for (unsigned k = 0; k < z_blocks.size(); ++k) {
    StringVector y_line = split_string_list(z_blocks.at(k), "\n");
    std::reverse(y_line.begin(), y_line.end());
    for (unsigned j = 0; j < y_line.size(); ++j) {
      StringVector x_positions = split_string_list(y_line.at(j), " ");
      for (unsigned i = 0; i < x_positions.size(); ++i) {
        std::array<unsigned, 3> index{i, j, k};
        std::array<int, dim> location;
        for (int dir = 0; dir < dim; ++dir)
          location.at(dir) = index.at(dir);
        material_mapping_[location] = string_to_int(x_positions.at(i));
      }
      n_material_cells_.at(0) = x_positions.size();
    }
    if (dim > 1)
      n_material_cells_.at(1) = y_line.size();
  }

  if (dim > 2)
    n_material_cells_.at(2) = z_blocks.size();
}

template <int dim>
void MeshCartesian<dim>::FillMaterialID(dealii::Triangulation<dim> &to_fill) {
  for (auto cell = to_fill.begin_active(); cell != to_fill.end(); ++cell) {
    if (cell->is_locally_owned()) {
      int material_id = GetMaterialID(cell->center());
      cell->set_material_id(material_id);
    }
  }
}

template <int dim>
void MeshCartesian<dim>::FillBoundaryID(dealii::Triangulation<dim> &to_fill) {
  using Boundary = bart::problem::Boundary;
  int faces_per_cell = dealii::GeometryInfo<dim>::faces_per_cell;
  double zero_tol = 1.0e-14;

  for (auto cell = to_fill.begin_active(); cell != to_fill.end(); ++cell) {
    if (cell->is_locally_owned()) {
      for (int face_id = 0; face_id < faces_per_cell; ++face_id) {
        auto face = cell->face(face_id);
        dealii::Point<dim> face_center = face->center();
        switch (dim) {
          case 3: {
            if (std::fabs(face_center[2]) < zero_tol) {
              face->set_boundary_id(static_cast<int>(Boundary::kZMin));
              break;
            } else if (std::fabs(face_center[2] - spatial_max_.at(2) < zero_tol)) {
              face->set_boundary_id(static_cast<int>(Boundary::kZMax));
              break;
            }
            [[fallthrough]];
          }
          case 2: {
            if (std::fabs(face_center[1]) < zero_tol) {
              face->set_boundary_id(static_cast<int>(Boundary::kYMin));
              break;
            } else if (std::fabs(face_center[1] - spatial_max_[1]) < zero_tol) {
              face->set_boundary_id(static_cast<int>(Boundary::kYMax));
              break;
            }
            [[fallthrough]];
          }
            // Fall through to check x-direction
          case 1: {
            if (std::fabs(face_center[0]) < zero_tol) {
              face->set_boundary_id(static_cast<int>(Boundary::kXMin));
              break;
            } else if (std::fabs(face_center[0] - spatial_max_[0]) < zero_tol) {
              face->set_boundary_id(static_cast<int>(Boundary::kXMax));
              break;
            }
            break;
          }
          default: {
            AssertThrow(false,
                        dealii::ExcMessage("Unsupported number of dimensions in FillBoundaryID"));
          }
        }
      }
    }
  }
}

template <int dim>
int MeshCartesian<dim>::GetMaterialID(dealii::Point<dim> location) {
  std::array<double, dim> array_location;
  for (int i = 0; i < dim; ++i)
    array_location[i] = location[i];
  return GetMaterialID(array_location);
}

template <int dim>
int MeshCartesian<dim>::GetMaterialID(std::array<double, dim> location) {
  std::array<int, dim> relative_location;

  for (int i = 0; i < dim; ++i) {
    double cell_size = spatial_max_.at(i)/n_material_cells_.at(i);
    double cell_location = location.at(i) / cell_size;
    int cell_index = std::floor(cell_location);

    if (static_cast<double>(cell_index) == cell_location && cell_index != 0) {
      relative_location.at(i) = cell_index - 1;
    } else {
      relative_location.at(i) = cell_index;
    }
  }

  return material_mapping_[relative_location];
}

template class MeshCartesian<1>;
template class MeshCartesian<2>;
template class MeshCartesian<3>;

} // namespace domain

} // namespace bart
<|endoftext|>