<commit_before>/*
 * Copyright 2011, Google Inc.
 *
 * 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 "common.h"

#include <string.h>
#include <android/bitmap.h>

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */

/************
 * ReadFile *
 ************/

jlong Java_com_googlecode_leptonica_android_ReadFile_nativeReadMem(JNIEnv *env, jclass clazz,
                                                                   jbyteArray image, jint length) {
  jbyte *image_buffer = env->GetByteArrayElements(image, NULL);
  int buffer_length = env->GetArrayLength(image);

  PIX *pix = pixReadMem((const l_uint8 *) image_buffer, buffer_length);

  env->ReleaseByteArrayElements(image, image_buffer, JNI_ABORT);

  return (jlong) pix;
}

jlong Java_com_googlecode_leptonica_android_ReadFile_nativeReadBytes8(JNIEnv *env, jclass clazz,
                                                                      jbyteArray data, jint w,
                                                                      jint h) {
  PIX *pix = pixCreateNoInit((l_int32) w, (l_int32) h, 8);
  l_uint8 **lineptrs = pixSetupByteProcessing(pix, NULL, NULL);
  jbyte *data_buffer = env->GetByteArrayElements(data, NULL);
  l_uint8 *byte_buffer = (l_uint8 *) data_buffer;

  for (int i = 0; i < h; i++) {
    memcpy(lineptrs[i], (byte_buffer + (i * w)), w);
  }

  env->ReleaseByteArrayElements(data, data_buffer, JNI_ABORT);
  pixCleanupByteProcessing(pix, lineptrs);

  l_int32 d;

  pixGetDimensions(pix, &w, &h, &d);

  LOGE("Created image width w=%d, h=%d, d=%d", w, h, d);

  return (jlong) pix;
}

jboolean Java_com_googlecode_leptonica_android_ReadFile_nativeReplaceBytes8(JNIEnv *env,
                                                                            jclass clazz,
                                                                            jlong nativePix,
                                                                            jbyteArray data,
                                                                            jint srcw, jint srch) {
  PIX *pix = (PIX *) nativePix;
  l_int32 w, h, d;

  pixGetDimensions(pix, &w, &h, &d);

  if (d != 8 || (l_int32) srcw != w || (l_int32) srch != h) {
    LOGE("Failed to replace bytes at w=%d, h=%d, d=%d with w=%d, h=%d", w, h, d, srcw, srch);

    return JNI_FALSE;
  }

  l_uint8 **lineptrs = pixSetupByteProcessing(pix, NULL, NULL);
  jbyte *data_buffer = env->GetByteArrayElements(data, NULL);
  l_uint8 *byte_buffer = (l_uint8 *) data_buffer;

  for (int i = 0; i < h; i++) {
    memcpy(lineptrs[i], (byte_buffer + (i * w)), w);
  }

  env->ReleaseByteArrayElements(data, data_buffer, JNI_ABORT);
  pixCleanupByteProcessing(pix, lineptrs);

  return JNI_TRUE;
}

jlong Java_com_googlecode_leptonica_android_ReadFile_nativeReadFiles(JNIEnv *env, jclass clazz,
                                                                     jstring dirName, jstring prefix) {
  PIXA *pixad = NULL;

  const char *c_dirName = env->GetStringUTFChars(dirName, NULL);
  if (c_dirName == NULL) {
    LOGE("could not extract dirName string!");
    return JNI_FALSE;
  }

  const char *c_prefix = env->GetStringUTFChars(prefix, NULL);
  if (c_prefix == NULL) {
    LOGE("could not extract prefix string!");
    return JNI_FALSE;
  }

  pixad = pixaReadFiles(c_dirName, c_prefix);

  env->ReleaseStringUTFChars(dirName, c_dirName);
  env->ReleaseStringUTFChars(prefix, c_prefix);

  return (jlong) pixad;
}

jlong Java_com_googlecode_leptonica_android_ReadFile_nativeReadFile(JNIEnv *env, jclass clazz,
                                                                    jstring fileName) {
  PIX *pixd = NULL;

  const char *c_fileName = env->GetStringUTFChars(fileName, NULL);
  if (c_fileName == NULL) {
    LOGE("could not extract fileName string!");
    return JNI_FALSE;
  }

  pixd = pixRead(c_fileName);

  env->ReleaseStringUTFChars(fileName, c_fileName);

  return (jlong) pixd;
}

jlong Java_com_googlecode_leptonica_android_ReadFile_nativeReadBitmap(JNIEnv *env, jclass clazz,
                                                                      jobject bitmap) {
  l_int32 w, h, d;
  AndroidBitmapInfo info;
  void* pixels;
  int ret;

  if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
    LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
    return JNI_FALSE;
  }

  if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
    LOGE("Bitmap format is not RGBA_8888 !");
    return JNI_FALSE;
  }

  if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
    LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
    return JNI_FALSE;
  }

  PIX *pixd = pixCreate(info.width, info.height, 8);

  l_uint32 *src = (l_uint32 *) pixels;
  l_int32 srcWpl = (info.stride / 4);
  l_uint32 *dst = pixGetData(pixd);
  l_int32 dstWpl = pixGetWpl(pixd);
  l_uint8 a, r, g, b, pixel8;

  for (int y = 0; y < info.height; y++) {
    l_uint32 *dst_line = dst + (y * dstWpl);
    l_uint32 *src_line = src + (y * srcWpl);

    for (int x = 0; x < info.width; x++) {
      // Get pixel from RGBA_8888
      r = *src_line >> SK_R32_SHIFT;
      g = *src_line >> SK_G32_SHIFT;
      b = *src_line >> SK_B32_SHIFT;
      a = *src_line >> SK_A32_SHIFT;
      pixel8 = (l_uint8)((r + g + b) / 3);

      // Set pixel to LUMA_8
      SET_DATA_BYTE(dst_line, x, pixel8);

      // Move to the next pixel
      src_line++;
    }
  }

  AndroidBitmap_unlockPixels(env, bitmap);

  return (jlong) pixd;
}

#ifdef __cplusplus
}
#endif  /* __cplusplus */
<commit_msg>Fix return type<commit_after>/*
 * Copyright 2011, Google Inc.
 *
 * 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 "common.h"

#include <string.h>
#include <android/bitmap.h>

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */

/************
 * ReadFile *
 ************/

jlong Java_com_googlecode_leptonica_android_ReadFile_nativeReadMem(JNIEnv *env, jclass clazz,
                                                                   jbyteArray image, jint length) {
  jbyte *image_buffer = env->GetByteArrayElements(image, NULL);
  int buffer_length = env->GetArrayLength(image);

  PIX *pix = pixReadMem((const l_uint8 *) image_buffer, buffer_length);

  env->ReleaseByteArrayElements(image, image_buffer, JNI_ABORT);

  return (jlong) pix;
}

jlong Java_com_googlecode_leptonica_android_ReadFile_nativeReadBytes8(JNIEnv *env, jclass clazz,
                                                                      jbyteArray data, jint w,
                                                                      jint h) {
  PIX *pix = pixCreateNoInit((l_int32) w, (l_int32) h, 8);
  l_uint8 **lineptrs = pixSetupByteProcessing(pix, NULL, NULL);
  jbyte *data_buffer = env->GetByteArrayElements(data, NULL);
  l_uint8 *byte_buffer = (l_uint8 *) data_buffer;

  for (int i = 0; i < h; i++) {
    memcpy(lineptrs[i], (byte_buffer + (i * w)), w);
  }

  env->ReleaseByteArrayElements(data, data_buffer, JNI_ABORT);
  pixCleanupByteProcessing(pix, lineptrs);

  l_int32 d;

  pixGetDimensions(pix, &w, &h, &d);

  LOGE("Created image width w=%d, h=%d, d=%d", w, h, d);

  return (jlong) pix;
}

jboolean Java_com_googlecode_leptonica_android_ReadFile_nativeReplaceBytes8(JNIEnv *env,
                                                                            jclass clazz,
                                                                            jlong nativePix,
                                                                            jbyteArray data,
                                                                            jint srcw, jint srch) {
  PIX *pix = (PIX *) nativePix;
  l_int32 w, h, d;

  pixGetDimensions(pix, &w, &h, &d);

  if (d != 8 || (l_int32) srcw != w || (l_int32) srch != h) {
    LOGE("Failed to replace bytes at w=%d, h=%d, d=%d with w=%d, h=%d", w, h, d, srcw, srch);

    return JNI_FALSE;
  }

  l_uint8 **lineptrs = pixSetupByteProcessing(pix, NULL, NULL);
  jbyte *data_buffer = env->GetByteArrayElements(data, NULL);
  l_uint8 *byte_buffer = (l_uint8 *) data_buffer;

  for (int i = 0; i < h; i++) {
    memcpy(lineptrs[i], (byte_buffer + (i * w)), w);
  }

  env->ReleaseByteArrayElements(data, data_buffer, JNI_ABORT);
  pixCleanupByteProcessing(pix, lineptrs);

  return JNI_TRUE;
}

jlong Java_com_googlecode_leptonica_android_ReadFile_nativeReadFiles(JNIEnv *env, jclass clazz,
                                                                     jstring dirName, jstring prefix) {
  PIXA *pixad = NULL;

  const char *c_dirName = env->GetStringUTFChars(dirName, NULL);
  if (c_dirName == NULL) {
    LOGE("could not extract dirName string!");
    return (jlong) NULL;
  }

  const char *c_prefix = env->GetStringUTFChars(prefix, NULL);
  if (c_prefix == NULL) {
    LOGE("could not extract prefix string!");
    return (jlong) NULL;
  }

  pixad = pixaReadFiles(c_dirName, c_prefix);

  env->ReleaseStringUTFChars(dirName, c_dirName);
  env->ReleaseStringUTFChars(prefix, c_prefix);

  return (jlong) pixad;
}

jlong Java_com_googlecode_leptonica_android_ReadFile_nativeReadFile(JNIEnv *env, jclass clazz,
                                                                    jstring fileName) {
  PIX *pixd = NULL;

  const char *c_fileName = env->GetStringUTFChars(fileName, NULL);
  if (c_fileName == NULL) {
    LOGE("could not extract fileName string!");
    return (jlong) NULL;
  }

  pixd = pixRead(c_fileName);

  env->ReleaseStringUTFChars(fileName, c_fileName);

  return (jlong) pixd;
}

jlong Java_com_googlecode_leptonica_android_ReadFile_nativeReadBitmap(JNIEnv *env, jclass clazz,
                                                                      jobject bitmap) {
  l_int32 w, h, d;
  AndroidBitmapInfo info;
  void* pixels;
  int ret;

  if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
    LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
    return (jlong) NULL;
  }

  if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
    LOGE("Bitmap format is not RGBA_8888 !");
    return (jlong) NULL;
  }

  if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
    LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
    return (jlong) NULL;
  }

  PIX *pixd = pixCreate(info.width, info.height, 8);

  l_uint32 *src = (l_uint32 *) pixels;
  l_int32 srcWpl = (info.stride / 4);
  l_uint32 *dst = pixGetData(pixd);
  l_int32 dstWpl = pixGetWpl(pixd);
  l_uint8 a, r, g, b, pixel8;

  for (int y = 0; y < info.height; y++) {
    l_uint32 *dst_line = dst + (y * dstWpl);
    l_uint32 *src_line = src + (y * srcWpl);

    for (int x = 0; x < info.width; x++) {
      // Get pixel from RGBA_8888
      r = *src_line >> SK_R32_SHIFT;
      g = *src_line >> SK_G32_SHIFT;
      b = *src_line >> SK_B32_SHIFT;
      a = *src_line >> SK_A32_SHIFT;
      pixel8 = (l_uint8)((r + g + b) / 3);

      // Set pixel to LUMA_8
      SET_DATA_BYTE(dst_line, x, pixel8);

      // Move to the next pixel
      src_line++;
    }
  }

  AndroidBitmap_unlockPixels(env, bitmap);

  return (jlong) pixd;
}

#ifdef __cplusplus
}
#endif  /* __cplusplus */
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2000, 2010 Oracle and/or its affiliates.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* 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.
*
************************************************************************/

#include "precompiled_sal.hxx"
#include "sal/config.h"
#include "sal/precppunit.hxx"

#ifdef WNT
#include <windows.h>
#endif

#include <cstdlib>
#include <iostream>
#include <limits>
#include <string>
#include "cppunittester/protectorfactory.hxx"
#include "osl/module.h"
#include "osl/module.hxx"
#include "osl/thread.h"
#include "rtl/process.h"
#include "rtl/string.h"
#include "rtl/string.hxx"
#include "rtl/textcvt.h"
#include "rtl/ustring.hxx"
#include "sal/main.h"
#include "sal/types.h"

#include "cppunit/CompilerOutputter.h"
#include "cppunit/TestResult.h"
#include "cppunit/TestResultCollector.h"
#include "cppunit/TestRunner.h"
#include "cppunit/extensions/TestFactoryRegistry.h"
#include "cppunit/plugin/PlugInManager.h"
#include "cppunit/portability/Stream.h"

#include "boost/noncopyable.hpp"

namespace {

void usageFailure() {
    std::cerr
        << ("Usage: cppunittester (--protector <shared-library-path>"
            " <function-symbol>)* <shared-library-path>")
        << std::endl;
    std::exit(EXIT_FAILURE);
}

rtl::OUString getArgument(sal_Int32 index) {
    rtl::OUString arg;
    rtl_getAppCommandArg(index, &arg.pData);
    return arg;
}

std::string convertLazy(rtl::OUString const & s16) {
    rtl::OString s8(rtl::OUStringToOString(s16, osl_getThreadTextEncoding()));
    return std::string(
        s8.getStr(),
        ((static_cast< sal_uInt32 >(s8.getLength())
          > (std::numeric_limits< std::string::size_type >::max)())
         ? (std::numeric_limits< std::string::size_type >::max)()
         : static_cast< std::string::size_type >(s8.getLength())));
}

//Output how long each test took
class TimingListener
    : public CppUnit::TestListener
    , private boost::noncopyable
{
public:
    void startTest( CppUnit::Test *)
    {
        m_nStartTime = osl_getGlobalTimer();
    }

    void endTest( CppUnit::Test *test )
    {
        sal_uInt32 nEndTime = osl_getGlobalTimer();
        std::cout << test->getName() << ": " << nEndTime-m_nStartTime
            << "ms" << std::endl;
    }

private:
    sal_uInt32 m_nStartTime;
};

//Allow the whole uniting testing framework to be run inside a "Protector"
//which knows about uno exceptions, so it can print the content of the
//exception before falling over and dying
class CPPUNIT_API ProtectedFixtureFunctor
    : public CppUnit::Functor
    , private boost::noncopyable
{
private:
    const std::string &testlib;
    const std::string &args;
    CppUnit::TestResult &result;
public:
    ProtectedFixtureFunctor(const std::string& testlib_, const std::string &args_, CppUnit::TestResult &result_)
        : testlib(testlib_)
        , args(args_)
        , result(result_)
    {
    }
    bool run() const
    {
        CppUnit::PlugInManager manager;
        manager.load(testlib, args);

        CppUnit::TestRunner runner;
        runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());

        CppUnit::TestResultCollector collector;
        result.addListener(&collector);

#ifdef TIMETESTS
        TimingListener timer;
        result.addListener(&timer);
#endif

        runner.run(result);

        CppUnit::CompilerOutputter(&collector, CppUnit::stdCErr()).write();
        return collector.wasSuccessful();
    }
    virtual bool operator()() const
    {
        return run();
    }
};

}

SAL_IMPLEMENT_MAIN() {
#ifdef WNT
    //Disable Dr-Watson in order to crash simply without popup dialogs under
    //windows
    DWORD dwMode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
    SetErrorMode(SEM_NOGPFAULTERRORBOX|dwMode);
#ifdef _DEBUG // These functions are present only in the debgging runtime
    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
    _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
    _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
#endif
#endif

    CppUnit::TestResult result;
    cppunittester::LibreOfficeProtector *throw_protector = 0;
    std::string args;
    std::string testlib;
    sal_uInt32 index = 0;
    while (index < rtl_getAppCommandArgCount())
    {
        rtl::OUString arg = getArgument(index);
        if (!arg.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("--protector")))
        {
            if (testlib.empty())
            {
                testlib = rtl::OUStringToOString(arg, osl_getThreadTextEncoding()).getStr();
                args += testlib;
            }
            else
            {
                args += ' ';
                args += rtl::OUStringToOString(arg, osl_getThreadTextEncoding()).getStr();
            }
            ++index;
            continue;
        }
        if (rtl_getAppCommandArgCount() - index < 3) {
            usageFailure();
        }
        rtl::OUString lib(getArgument(index + 1));
        rtl::OUString sym(getArgument(index + 2));
        oslGenericFunction fn = (new osl::Module(lib, SAL_LOADMODULE_GLOBAL))
            ->getFunctionSymbol(sym);
        throw_protector = fn == 0
            ? 0
            : (*reinterpret_cast< cppunittester::ProtectorFactory * >(fn))();
        if (throw_protector == 0) {
            std::cerr
                << "Failure instantiating protector \"" << convertLazy(lib)
                << "\", \"" << convertLazy(sym) << '"' << std::endl;
            std::exit(EXIT_FAILURE);
        }
        result.pushProtector(throw_protector);
        index+=3;
    }

    bool ok = false;
    ProtectedFixtureFunctor tests(testlib, args, result);
    //if the unoprotector was given on the command line, use it to catch
    //and report the error message of exceptions
    if (throw_protector)
        ok = throw_protector->protect(tests);
    else
        ok = tests.run();

    return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>easier to find leaks if the test harness doesn't leak<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2000, 2010 Oracle and/or its affiliates.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* 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.
*
************************************************************************/

#include "precompiled_sal.hxx"
#include "sal/config.h"
#include "sal/precppunit.hxx"

#ifdef WNT
#include <windows.h>
#endif

#include <cstdlib>
#include <iostream>
#include <limits>
#include <string>
#include "cppunittester/protectorfactory.hxx"
#include "osl/module.h"
#include "osl/module.hxx"
#include "osl/thread.h"
#include "rtl/process.h"
#include "rtl/string.h"
#include "rtl/string.hxx"
#include "rtl/textcvt.h"
#include "rtl/ustring.hxx"
#include "sal/main.h"
#include "sal/types.h"

#include "cppunit/CompilerOutputter.h"
#include "cppunit/TestResult.h"
#include "cppunit/TestResultCollector.h"
#include "cppunit/TestRunner.h"
#include "cppunit/extensions/TestFactoryRegistry.h"
#include "cppunit/plugin/PlugInManager.h"
#include "cppunit/portability/Stream.h"

#include "boost/noncopyable.hpp"
#include "boost/ptr_container/ptr_vector.hpp"

namespace {

void usageFailure() {
    std::cerr
        << ("Usage: cppunittester (--protector <shared-library-path>"
            " <function-symbol>)* <shared-library-path>")
        << std::endl;
    std::exit(EXIT_FAILURE);
}

rtl::OUString getArgument(sal_Int32 index) {
    rtl::OUString arg;
    rtl_getAppCommandArg(index, &arg.pData);
    return arg;
}

std::string convertLazy(rtl::OUString const & s16) {
    rtl::OString s8(rtl::OUStringToOString(s16, osl_getThreadTextEncoding()));
    return std::string(
        s8.getStr(),
        ((static_cast< sal_uInt32 >(s8.getLength())
          > (std::numeric_limits< std::string::size_type >::max)())
         ? (std::numeric_limits< std::string::size_type >::max)()
         : static_cast< std::string::size_type >(s8.getLength())));
}

//Output how long each test took
class TimingListener
    : public CppUnit::TestListener
    , private boost::noncopyable
{
public:
    void startTest( CppUnit::Test *)
    {
        m_nStartTime = osl_getGlobalTimer();
    }

    void endTest( CppUnit::Test *test )
    {
        sal_uInt32 nEndTime = osl_getGlobalTimer();
        std::cout << test->getName() << ": " << nEndTime-m_nStartTime
            << "ms" << std::endl;
    }

private:
    sal_uInt32 m_nStartTime;
};

//Allow the whole uniting testing framework to be run inside a "Protector"
//which knows about uno exceptions, so it can print the content of the
//exception before falling over and dying
class CPPUNIT_API ProtectedFixtureFunctor
    : public CppUnit::Functor
    , private boost::noncopyable
{
private:
    const std::string &testlib;
    const std::string &args;
    CppUnit::TestResult &result;
public:
    ProtectedFixtureFunctor(const std::string& testlib_, const std::string &args_, CppUnit::TestResult &result_)
        : testlib(testlib_)
        , args(args_)
        , result(result_)
    {
    }
    bool run() const
    {
        CppUnit::PlugInManager manager;
        manager.load(testlib, args);

        CppUnit::TestRunner runner;
        runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());

        CppUnit::TestResultCollector collector;
        result.addListener(&collector);

#ifdef TIMETESTS
        TimingListener timer;
        result.addListener(&timer);
#endif

        runner.run(result);

        CppUnit::CompilerOutputter(&collector, CppUnit::stdCErr()).write();
        return collector.wasSuccessful();
    }
    virtual bool operator()() const
    {
        return run();
    }
};

}

SAL_IMPLEMENT_MAIN() {
#ifdef WNT
    //Disable Dr-Watson in order to crash simply without popup dialogs under
    //windows
    DWORD dwMode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
    SetErrorMode(SEM_NOGPFAULTERRORBOX|dwMode);
#ifdef _DEBUG // These functions are present only in the debgging runtime
    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
    _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
    _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
#endif
#endif

    CppUnit::TestResult result;
    boost::ptr_vector<osl::Module> modules;
    cppunittester::LibreOfficeProtector *throw_protector = 0;
    std::string args;
    std::string testlib;
    sal_uInt32 index = 0;
    while (index < rtl_getAppCommandArgCount())
    {
        rtl::OUString arg = getArgument(index);
        if (!arg.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("--protector")))
        {
            if (testlib.empty())
            {
                testlib = rtl::OUStringToOString(arg, osl_getThreadTextEncoding()).getStr();
                args += testlib;
            }
            else
            {
                args += ' ';
                args += rtl::OUStringToOString(arg, osl_getThreadTextEncoding()).getStr();
            }
            ++index;
            continue;
        }
        if (rtl_getAppCommandArgCount() - index < 3) {
            usageFailure();
        }
        rtl::OUString lib(getArgument(index + 1));
        rtl::OUString sym(getArgument(index + 2));
        modules.push_back(new osl::Module(lib, SAL_LOADMODULE_GLOBAL));
        oslGenericFunction fn = modules.back().getFunctionSymbol(sym);
        throw_protector = fn == 0
            ? 0
            : (*reinterpret_cast< cppunittester::ProtectorFactory * >(fn))();
        if (throw_protector == 0) {
            std::cerr
                << "Failure instantiating protector \"" << convertLazy(lib)
                << "\", \"" << convertLazy(sym) << '"' << std::endl;
            std::exit(EXIT_FAILURE);
        }
        result.pushProtector(throw_protector);
        index+=3;
    }

    bool ok = false;
    ProtectedFixtureFunctor tests(testlib, args, result);
    //if the unoprotector was given on the command line, use it to catch
    //and report the error message of exceptions
    if (throw_protector)
        ok = throw_protector->protect(tests);
    else
        ok = tests.run();

    return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/*************************************************************************
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2010 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* 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.
************************************************************************/

#include "precompiled_sal.hxx"
#include "sal/config.h"

#include <cstdlib>
#include <iostream>

#include "cppunit/CompilerOutputter.h"
#include "cppunit/TestResult.h"
#include "cppunit/TestResultCollector.h"
#include "cppunit/TestRunner.h"
#include "cppunit/extensions/TestFactoryRegistry.h"
#include "cppunit/plugin/PlugInManager.h"
#include "cppunit/portability/Stream.h"
#include "osl/thread.h"
#include "rtl/process.h"
#include "rtl/string.hxx"
#include "rtl/ustring.hxx"
#include "sal/main.h"

SAL_IMPLEMENT_MAIN() {
    if (rtl_getAppCommandArgCount() != 1) {
        std::cerr << "Usage: cppunittest <shared-library-path>" << std::endl;
        return EXIT_FAILURE;
    }
    rtl::OUString path;
    rtl_getAppCommandArg(0, &path.pData);
    CppUnit::PlugInManager manager;
    manager.load(
        rtl::OUStringToOString(path, osl_getThreadTextEncoding()).getStr());
    CppUnit::TestRunner runner;
    runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
    CppUnit::TestResult result;
    CppUnit::TestResultCollector collector;
    result.addListener(&collector);
    runner.run(result);
    CppUnit::CompilerOutputter(&collector, CppUnit::stdCErr()).write();
    return collector.wasSuccessful() ? EXIT_SUCCESS : EXIT_FAILURE;
}
<commit_msg>sb118: typo<commit_after>/*************************************************************************
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2010 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* 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.
************************************************************************/

#include "precompiled_sal.hxx"
#include "sal/config.h"

#include <cstdlib>
#include <iostream>

#include "cppunit/CompilerOutputter.h"
#include "cppunit/TestResult.h"
#include "cppunit/TestResultCollector.h"
#include "cppunit/TestRunner.h"
#include "cppunit/extensions/TestFactoryRegistry.h"
#include "cppunit/plugin/PlugInManager.h"
#include "cppunit/portability/Stream.h"
#include "osl/thread.h"
#include "rtl/process.h"
#include "rtl/string.hxx"
#include "rtl/ustring.hxx"
#include "sal/main.h"

SAL_IMPLEMENT_MAIN() {
    if (rtl_getAppCommandArgCount() != 1) {
        std::cerr << "Usage: cppunittester <shared-library-path>" << std::endl;
        return EXIT_FAILURE;
    }
    rtl::OUString path;
    rtl_getAppCommandArg(0, &path.pData);
    CppUnit::PlugInManager manager;
    manager.load(
        rtl::OUStringToOString(path, osl_getThreadTextEncoding()).getStr());
    CppUnit::TestRunner runner;
    runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
    CppUnit::TestResult result;
    CppUnit::TestResultCollector collector;
    result.addListener(&collector);
    runner.run(result);
    CppUnit::CompilerOutputter(&collector, CppUnit::stdCErr()).write();
    return collector.wasSuccessful() ? EXIT_SUCCESS : EXIT_FAILURE;
}
<|endoftext|>


<commit_before>/*
 * main.cpp -- irccd main file
 *
 * Copyright (c) 2013, 2014, 2015 David Demelier <markand@malikania.fr>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <iostream>
#include <chrono>

#include <js/Js.h>

using namespace std::chrono_literals;

std::atomic<bool> g_running{true};

void quit(int)
{
	g_running = false;
}

int main(void)
{
	duk_context *ctx = duk_create_heap_default();
	duk_push_c_function(ctx, dukopen_filesystem, 0);
	duk_call(ctx, 0);
	duk_put_global_string(ctx, "fs");
	irccd::ServerSettings settings;

	if (duk_peval_file(ctx, "test.js") != 0) {
		printf("%s\n", duk_safe_to_string(ctx, -1));
	info.port = 6667;

	settings.recotimeout = 3;
	settings.channels = {
		{ "#staff", "" },
		{ "#test", "" }
	};

	smanager.add(std::move(info), irccd::Identity(), std::move(settings));

	while (g_running) {
	}

	duk_destroy_heap(ctx);

	printf("Quitting...\n");

	return 0;
}

#if 0
#include <cstdlib>
#include <cstring>

#include <signal.h>

#include <Logger.h>

#include "Irccd.h"
#include "Test.h"
#include "PluginManager.h"

using namespace irccd;
using namespace std;

namespace {

void quit(int)
{
	Irccd::instance().shutdown();
	Irccd::instance().stop();
}

void usage()
{
	Logger::warn("usage: %s [-fv] [-c config] [-p pluginpath] [-P plugin]", getprogname());
	Logger::fatal(1, "       %s test plugin.lua [command] [parameters...]", getprogname());
}

} // !namespace

int main(int argc, char **argv)
{
	Irccd &irccd = Irccd::instance();
	int ch;

	setprogname("irccd");
	atexit([] () {
		quit(0);
	});

	irccd.initialize();

	while ((ch = getopt(argc, argv, "fc:p:P:v")) != -1) {
		switch (ch) {
		case 'c':
			irccd.setConfigPath(string(optarg));
			irccd.override(Options::Config);
			break;
		case 'f':
			irccd.setForeground(true);
			irccd.override(Options::Foreground);
			break;
		case 'p':
#if defined(WITH_LUA)
			PluginManager::instance().addPath(string(optarg));
#endif
			break;
		case 'P':
			irccd.deferPlugin(string(optarg));
			break;
		case 'v':
			Logger::setVerbose(true);
			irccd.override(Options::Verbose);
			break;
		case '?':
		default:
			usage();
			// NOTREACHED
		}
	}
	argc -= optind;
	argv += optind;

	if (argc > 0) {
		if (strcmp(argv[0], "test") == 0) {
#if defined(WITH_LUA)
			test(argc, argv);
			// NOTREACHED
#else
			Logger::fatal(1, "irccd: Lua support is disabled");
#endif
		}

		if (strcmp(argv[0], "version") == 0) {
			Logger::setVerbose(true);
			Logger::log("irccd version %s", VERSION);
			Logger::log("Copyright (c) 2013, 2014, 2015 David Demelier <markand@malikania.fr>");
			Logger::log("");
			Logger::log("Irccd is a customizable IRC bot daemon compatible with Lua plugins");
			Logger::log("to fit your needs.");
			Logger::log("");

#if defined(WITH_LUA)
			auto enabled = "enabled";
#else
			auto enabled = "disabled";
#endif
			Logger::log("* Lua support is %s", enabled);
			std::exit(0);
		}
	}

	signal(SIGINT, quit);
	signal(SIGTERM, quit);

#if defined(SIGQUIT)
	signal(SIGQUIT, quit);
#endif

	return irccd.run();
}

#endif
<commit_msg>Update main.<commit_after>/*
 * main.cpp -- irccd main file
 *
 * Copyright (c) 2013, 2014, 2015 David Demelier <markand@malikania.fr>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <iostream>
#include <chrono>

#include <js/Js.h>

int main(void)
{
	duk_context *ctx = duk_create_heap_default();
	duk_push_c_function(ctx, dukopen_filesystem, 0);
	duk_call(ctx, 0);
	duk_put_global_string(ctx, "fs");

	if (duk_peval_file(ctx, "test.js") != 0) {
		printf("%s\n", duk_safe_to_string(ctx, -1));

	duk_destroy_heap(ctx);

	return 0;
}

#if 0
#include <cstdlib>
#include <cstring>

#include <signal.h>

#include <Logger.h>

#include "Irccd.h"
#include "Test.h"
#include "PluginManager.h"

using namespace irccd;
using namespace std;

namespace {

void quit(int)
{
	Irccd::instance().shutdown();
	Irccd::instance().stop();
}

void usage()
{
	Logger::warn("usage: %s [-fv] [-c config] [-p pluginpath] [-P plugin]", getprogname());
	Logger::fatal(1, "       %s test plugin.lua [command] [parameters...]", getprogname());
}

} // !namespace

int main(int argc, char **argv)
{
	Irccd &irccd = Irccd::instance();
	int ch;

	setprogname("irccd");
	atexit([] () {
		quit(0);
	});

	irccd.initialize();

	while ((ch = getopt(argc, argv, "fc:p:P:v")) != -1) {
		switch (ch) {
		case 'c':
			irccd.setConfigPath(string(optarg));
			irccd.override(Options::Config);
			break;
		case 'f':
			irccd.setForeground(true);
			irccd.override(Options::Foreground);
			break;
		case 'p':
#if defined(WITH_LUA)
			PluginManager::instance().addPath(string(optarg));
#endif
			break;
		case 'P':
			irccd.deferPlugin(string(optarg));
			break;
		case 'v':
			Logger::setVerbose(true);
			irccd.override(Options::Verbose);
			break;
		case '?':
		default:
			usage();
			// NOTREACHED
		}
	}
	argc -= optind;
	argv += optind;

	if (argc > 0) {
		if (strcmp(argv[0], "test") == 0) {
#if defined(WITH_LUA)
			test(argc, argv);
			// NOTREACHED
#else
			Logger::fatal(1, "irccd: Lua support is disabled");
#endif
		}

		if (strcmp(argv[0], "version") == 0) {
			Logger::setVerbose(true);
			Logger::log("irccd version %s", VERSION);
			Logger::log("Copyright (c) 2013, 2014, 2015 David Demelier <markand@malikania.fr>");
			Logger::log("");
			Logger::log("Irccd is a customizable IRC bot daemon compatible with Lua plugins");
			Logger::log("to fit your needs.");
			Logger::log("");

#if defined(WITH_LUA)
			auto enabled = "enabled";
#else
			auto enabled = "disabled";
#endif
			Logger::log("* Lua support is %s", enabled);
			std::exit(0);
		}
	}

	signal(SIGINT, quit);
	signal(SIGTERM, quit);

#if defined(SIGQUIT)
	signal(SIGQUIT, quit);
#endif

	return irccd.run();
}

#endif
<|endoftext|>


<commit_before>#ifndef MANIFOLDS_FUNCTIONS_IS_FUNCTION_HH
#define MANIFOLDS_FUNCTIONS_IS_FUNCTION_HH

#include "function.hh"
#include <type_traits>
#include <utility>
#include <tuple>

namespace manifolds {
  //For now just test whether first function is a function
  template <class Func>
  struct is_function
  {

    typedef typename std::remove_cv<
      typename std::remove_reference<
	Func>::type
      >::type F;
    typedef std::integral_constant<
      bool,
      std::is_base_of<
	Function, F>::value ||
      std::is_base_of<
	MultiFunction, F>::value> type;

    static const bool value = type::value;
  };

  template <class T>
  struct is_tuple: std::false_type{};

  template <class ... Args>
  struct is_tuple<std::tuple<Args...>>:
    std::true_type{};
}

#endif
<commit_msg>Changed meta-function to accomodate new Function format, namely that function is now a template<commit_after>#ifndef MANIFOLDS_FUNCTIONS_IS_FUNCTION_HH
#define MANIFOLDS_FUNCTIONS_IS_FUNCTION_HH

#include "function.hh"
#include <type_traits>
#include <utility>
#include <tuple>

namespace manifolds {
  //For now just test whether first function is a function
  template <class F>
  std::true_type is_function_helper(int,int_<F::input_dim> =
				    int_<F::input_dim>(),
				    int_<F::output_dim> =
				    int_<F::output_dim>(),
				    bool_<F::stateless> =
				    bool_<F::stateless>(),
				    bool_<F::abelian_arithmetic> =
				    bool_<F::abelian_arithmetic>());
  template <class>
  std::false_type is_function_helper(long);

  template <class F>
  using is_function =
    decltype(is_function_helper<F>(0));

  template <class T>
  struct is_tuple: std::false_type{};

  template <class ... Args>
  struct is_tuple<std::tuple<Args...>>:
    std::true_type{};
}

#endif
<|endoftext|>


<commit_before>// Copyright 2013 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ozone/wayland/dispatcher.h"

#include "ozone/wayland/display.h"
#include "ozone/wayland/input/kbd_conversion.h"
#include "base/bind.h"
#include "base/message_loop/message_pump_ozone.h"
#include "content/child/child_thread.h"
#include "content/child/child_process.h"

#include <errno.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <wayland-client.h>

namespace {

content::ChildThread* GetProcessMainThread()
{
  content::ChildProcess* process = content::ChildProcess::current();
  DCHECK(process);
  DCHECK(process->main_thread());
  return process ? process->main_thread() : NULL;
}

}

namespace ozonewayland {
WaylandDispatcher* WaylandDispatcher::instance_ = NULL;

// os-compatibility
extern "C" {
int osEpollCreateCloExec(void);

static int setCloExecOrClose(int fd)
{
  long flags;

  if (fd == -1)
    return -1;

  flags = fcntl(fd, F_GETFD);
  if (flags == -1)
    goto err;

  if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
    goto err;

  return fd;

err:
  close(fd);
  return -1;
}

int osEpollCreateCloExec(void)
{
  int fd;

#ifdef EPOLL_CLOEXEC
  fd = epoll_create1(EPOLL_CLOEXEC);
  if (fd >= 0)
    return fd;
  if (errno != EINVAL)
    return -1;
#endif

  fd = epoll_create(1);
  return setCloExecOrClose(fd);
}

} // os-compatibility

void WaylandDispatcher::MotionNotify(float x, float y)
{
  if (epoll_fd_) {
    if (!running)
      return;
    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::SendMotionNotify, x, y));
  } else {
    scoped_ptr<ui::MouseEvent> mouseev(
        new ui::MouseEvent(ui::ET_MOUSE_MOVED,
                           gfx::Point(x, y),
                           gfx::Point(x, y),
                           0));

    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::DispatchEventHelper, base::Passed(
                                              mouseev.PassAs<ui::Event>())));
  }
}

void WaylandDispatcher::ButtonNotify(unsigned handle,
                                     int state,
                                     int flags,
                                     float x,
                                     float y)
{
  if (epoll_fd_) {
    if (!running)
      return;
    PostTaskOnMainLoop(FROM_HERE, base::Bind(&WaylandDispatcher::SendButtonNotify,
                                             handle, state, flags, x, y));
  } else {
    ui::EventType type;
    if (state == 1)
      type = ui::ET_MOUSE_PRESSED;
    else
      type = ui::ET_MOUSE_RELEASED;

    scoped_ptr<ui::MouseEvent> mouseev(
        new ui::MouseEvent(type,
                           gfx::Point(x, y),
                           gfx::Point(x, y),
                           flags));
    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::NotifyButtonPress, this, handle));

    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::DispatchEventHelper, base::Passed(
                                              mouseev.PassAs<ui::Event>())));
  }
}

void WaylandDispatcher::AxisNotify(float x, float y, float xoffset, float yoffset)
{
  if (epoll_fd_) {
    if (!running)
      return;

    PostTaskOnMainLoop(FROM_HERE, base::Bind(&WaylandDispatcher::SendAxisNotify,
                                             x, y, xoffset, yoffset));
  } else {
    ui::MouseEvent mouseev(
        ui::ET_MOUSEWHEEL,
        gfx::Point(x,y),
        gfx::Point(x,y),
        0);

    scoped_ptr<ui::MouseWheelEvent> wheelev(
        new ui::MouseWheelEvent(mouseev,
                                xoffset,
                                yoffset));

    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::DispatchEventHelper, base::Passed(
                                              wheelev.PassAs<ui::Event>())));
  }
}

void WaylandDispatcher::PointerEnter(unsigned handle, float x, float y)
{
  if (epoll_fd_) {
    if (!running)
      return;
    PostTaskOnMainLoop(FROM_HERE, base::Bind(&WaylandDispatcher::SendPointerEnter,
                                             handle, x, y));
  } else {
    scoped_ptr<ui::MouseEvent> mouseev(
        new ui::MouseEvent(ui::ET_MOUSE_ENTERED,
                           gfx::Point(x, y),
                           gfx::Point(x, y),
                           handle));
    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::NotifyPointerEnter, this, handle));

    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::DispatchEventHelper, base::Passed(
                                              mouseev.PassAs<ui::Event>())));
  }
}

void WaylandDispatcher::PointerLeave(unsigned handle, float x, float y)
{
  if (epoll_fd_) {
    if (!running)
      return;
    PostTaskOnMainLoop(FROM_HERE, base::Bind(&WaylandDispatcher::SendPointerLeave,
                                             handle, x, y));
  } else {
    scoped_ptr<ui::MouseEvent> mouseev(
        new ui::MouseEvent(ui::ET_MOUSE_EXITED,
                           gfx::Point(x, y),
                           gfx::Point(x, y),
                           0));

    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::NotifyPointerLeave, this, handle));

    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::DispatchEventHelper, base::Passed(
                                              mouseev.PassAs<ui::Event>())));
  }
}

void WaylandDispatcher::KeyNotify(unsigned state, unsigned code,
                                  unsigned modifiers)
{
  if (epoll_fd_) {
    if (!running)
      return;
    PostTaskOnMainLoop(FROM_HERE, base::Bind(&WaylandDispatcher::SendKeyNotify,
                                             state, code, modifiers));
  } else {
    ui::EventType type;
    if (state)
      type = ui::ET_KEY_PRESSED;
    else
      type = ui::ET_KEY_RELEASED;

    scoped_ptr<ui::KeyEvent> keyev(
        new ui::KeyEvent(type,
                         KeyboardCodeFromXKeysym(code),
                         0,
                         true));

    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::DispatchEventHelper, base::Passed(
                                              keyev.PassAs<ui::Event>())));
  }
}

void WaylandDispatcher::OutputSizeChanged(unsigned width, unsigned height)
{
  if (!running || !epoll_fd_)
    return;

  PostTaskOnMainLoop(FROM_HERE, base::Bind(
                      &WaylandDispatcher::SendOutputSizeChanged, width, height));
}

void WaylandDispatcher::PostTask(Task type)
{
  if (!IsRunning() || ignore_task_)
    return;

  switch (type) {
    case (Flush):
      message_loop_proxy()->PostTask(
                  FROM_HERE, base::Bind(&WaylandDispatcher::HandleFlush));
      break;
    case (Poll):
      if (epoll_fd_) {
        loop_ = base::MessageLoop::current();
        if (!running)
          message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
                                          &WaylandDispatcher::DisplayRun, this));
      }
  default:
    break;
  }
}

void WaylandDispatcher::DispatchEvent(scoped_ptr<ui::Event> event) {
  PostTaskOnMainLoop(FROM_HERE, base::Bind(&WaylandDispatcher::DispatchEventHelper,
                                           base::Passed(&event)));
}

void WaylandDispatcher::PostTaskOnMainLoop(
        const tracked_objects::Location& from_here, const base::Closure& task)
{
  if (ignore_task_ || !IsRunning() || !loop_)
    return;

  loop_->message_loop_proxy()->PostTask(from_here, task);
}

WaylandDispatcher::WaylandDispatcher(int fd)
    : Thread("WaylandDispatcher"),
      ignore_task_(false),
      running(false),
      epoll_fd_(0),
      display_fd_(fd),
      observer_(NULL)
{
  instance_ = this;
  if (display_fd_) {
    epoll_fd_ = osEpollCreateCloExec();
    struct epoll_event ep;
    ep.events = EPOLLIN | EPOLLOUT;
    ep.data.ptr = 0;
    epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, display_fd_, &ep);
  }

  loop_ = base::MessageLoop::current();
  Options options;
  options.message_loop_type = base::MessageLoop::TYPE_IO;
  StartWithOptions(options);
  SetPriority(base::kThreadPriority_Background);
}

WaylandDispatcher::~WaylandDispatcher()
{
  ignore_task_ = true;
  loop_ = NULL;
  running = false;
  Stop();

  if (epoll_fd_) {
    close(epoll_fd_);
    epoll_fd_ = 0;
  }

  instance_ = NULL;
}

void WaylandDispatcher::HandleFlush()
{
  wl_display* waylandDisp = WaylandDisplay::GetInstance()->display();

  while (wl_display_prepare_read(waylandDisp) != 0)
    wl_display_dispatch_pending(waylandDisp);

  wl_display_flush(waylandDisp);
  wl_display_read_events(waylandDisp);
  wl_display_dispatch_pending(waylandDisp);
}

void  WaylandDispatcher::DisplayRun(WaylandDispatcher* data)
{
  struct epoll_event ep[16];
  int i, count, ret;

  data->running = 1;
  // Adopted from:
  // http://cgit.freedesktop.org/wayland/weston/tree/clients/window.c#n5531.
  while (1) {
    wl_display* waylandDisp = WaylandDisplay::GetInstance()->display();
    wl_display_dispatch_pending(waylandDisp);

    if (!data->running)
      break;

    ret = wl_display_flush(waylandDisp);
    if (ret < 0 && errno == EAGAIN) {
      ep[0].events = EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP;
      epoll_ctl(data->epoll_fd_, EPOLL_CTL_MOD, data->display_fd_, &ep[0]);
    } else if (ret < 0) {
      break;
    }

    count = epoll_wait(data->epoll_fd_, ep, 16, -1);
    for (i = 0; i < count; i++) {
      int ret;
      uint32_t event = ep[i].events;

      if (event & EPOLLERR || event & EPOLLHUP)
        return;

      if (event & EPOLLIN) {
        ret = wl_display_dispatch(waylandDisp);
        if (ret == -1)
          return;
      }

      if (event & EPOLLOUT) {
        ret = wl_display_flush(waylandDisp);
        if (ret == 0) {
          struct epoll_event eps;
          memset(&eps, 0, sizeof(eps));

          eps.events = EPOLLIN | EPOLLERR | EPOLLHUP;
          epoll_ctl(data->epoll_fd_, EPOLL_CTL_MOD, data->display_fd_, &eps);
        } else if (ret == -1 && errno != EAGAIN) {
          return;
        }
      }
    }
  }
}

void WaylandDispatcher::NotifyPointerEnter(WaylandDispatcher* data,
                                           unsigned handle) {
  if (data->observer_)
    data->observer_->OnWindowEnter(handle);
}

void WaylandDispatcher::NotifyPointerLeave(WaylandDispatcher* data,
                                           unsigned handle) {
  if (data->observer_)
    data->observer_->OnWindowLeave(handle);
}

void WaylandDispatcher::NotifyButtonPress(WaylandDispatcher* data,
                                          unsigned handle) {
  if (data->observer_)
    data->observer_->OnWindowFocused(handle);
}

void WaylandDispatcher::DispatchEventHelper(scoped_ptr<ui::Event> key) {
  base::MessagePumpOzone::Current()->Dispatch(key.get());
}

void WaylandDispatcher::SendMotionNotify(float x, float y)
{
  content::ChildThread* thread = GetProcessMainThread();
  thread->Send(new WaylandInput_MotionNotify(x, y));
}

void WaylandDispatcher::SendButtonNotify(unsigned handle,
                                         int state,
                                         int flags,
                                         float x,
                                         float y)
{
  content::ChildThread* thread = GetProcessMainThread();
  thread->Send(new WaylandInput_ButtonNotify(handle, state, flags, x, y));
}

void WaylandDispatcher::SendAxisNotify(float x, float y, float xoffset,
                                       float yoffset)
{
  content::ChildThread* thread = GetProcessMainThread();
  thread->Send(new WaylandInput_AxisNotify(x, y, xoffset, yoffset));
}

void WaylandDispatcher::SendPointerEnter(unsigned handle, float x, float y)
{
  content::ChildThread* thread = GetProcessMainThread();
  thread->Send(new WaylandInput_PointerEnter(handle, x, y));
}

void WaylandDispatcher::SendPointerLeave(unsigned handle, float x, float y)
{
  content::ChildThread* thread = GetProcessMainThread();
  thread->Send(new WaylandInput_PointerLeave(handle, x, y));
}

void WaylandDispatcher::SendKeyNotify(unsigned type, unsigned code,
                                      unsigned modifiers)
{
  content::ChildThread* thread = GetProcessMainThread();
  thread->Send(new WaylandInput_KeyNotify(type, code, modifiers));
}

void WaylandDispatcher::SendOutputSizeChanged(unsigned width, unsigned height)
{
  content::ChildThread* thread = GetProcessMainThread();
  thread->Send(new WaylandInput_OutputSize(width, height));
}

void WaylandDispatcher::MessageLoopDestroyed()
{
  if (!IsRunning())
    return;

  ignore_task_ = true;
  loop_ = NULL;
  running = false;
  Stop();
}

}  // namespace ozonewayland
<commit_msg>Pass keyboard modifiers correctly.<commit_after>// Copyright 2013 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ozone/wayland/dispatcher.h"

#include "ozone/wayland/display.h"
#include "ozone/wayland/input/kbd_conversion.h"
#include "base/bind.h"
#include "base/message_loop/message_pump_ozone.h"
#include "content/child/child_thread.h"
#include "content/child/child_process.h"

#include <errno.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <wayland-client.h>

namespace {

content::ChildThread* GetProcessMainThread()
{
  content::ChildProcess* process = content::ChildProcess::current();
  DCHECK(process);
  DCHECK(process->main_thread());
  return process ? process->main_thread() : NULL;
}

}

namespace ozonewayland {
WaylandDispatcher* WaylandDispatcher::instance_ = NULL;

// os-compatibility
extern "C" {
int osEpollCreateCloExec(void);

static int setCloExecOrClose(int fd)
{
  long flags;

  if (fd == -1)
    return -1;

  flags = fcntl(fd, F_GETFD);
  if (flags == -1)
    goto err;

  if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
    goto err;

  return fd;

err:
  close(fd);
  return -1;
}

int osEpollCreateCloExec(void)
{
  int fd;

#ifdef EPOLL_CLOEXEC
  fd = epoll_create1(EPOLL_CLOEXEC);
  if (fd >= 0)
    return fd;
  if (errno != EINVAL)
    return -1;
#endif

  fd = epoll_create(1);
  return setCloExecOrClose(fd);
}

} // os-compatibility

void WaylandDispatcher::MotionNotify(float x, float y)
{
  if (epoll_fd_) {
    if (!running)
      return;
    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::SendMotionNotify, x, y));
  } else {
    scoped_ptr<ui::MouseEvent> mouseev(
        new ui::MouseEvent(ui::ET_MOUSE_MOVED,
                           gfx::Point(x, y),
                           gfx::Point(x, y),
                           0));

    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::DispatchEventHelper, base::Passed(
                                              mouseev.PassAs<ui::Event>())));
  }
}

void WaylandDispatcher::ButtonNotify(unsigned handle,
                                     int state,
                                     int flags,
                                     float x,
                                     float y)
{
  if (epoll_fd_) {
    if (!running)
      return;
    PostTaskOnMainLoop(FROM_HERE, base::Bind(&WaylandDispatcher::SendButtonNotify,
                                             handle, state, flags, x, y));
  } else {
    ui::EventType type;
    if (state == 1)
      type = ui::ET_MOUSE_PRESSED;
    else
      type = ui::ET_MOUSE_RELEASED;

    scoped_ptr<ui::MouseEvent> mouseev(
        new ui::MouseEvent(type,
                           gfx::Point(x, y),
                           gfx::Point(x, y),
                           flags));
    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::NotifyButtonPress, this, handle));

    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::DispatchEventHelper, base::Passed(
                                              mouseev.PassAs<ui::Event>())));
  }
}

void WaylandDispatcher::AxisNotify(float x, float y, float xoffset, float yoffset)
{
  if (epoll_fd_) {
    if (!running)
      return;

    PostTaskOnMainLoop(FROM_HERE, base::Bind(&WaylandDispatcher::SendAxisNotify,
                                             x, y, xoffset, yoffset));
  } else {
    ui::MouseEvent mouseev(
        ui::ET_MOUSEWHEEL,
        gfx::Point(x,y),
        gfx::Point(x,y),
        0);

    scoped_ptr<ui::MouseWheelEvent> wheelev(
        new ui::MouseWheelEvent(mouseev,
                                xoffset,
                                yoffset));

    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::DispatchEventHelper, base::Passed(
                                              wheelev.PassAs<ui::Event>())));
  }
}

void WaylandDispatcher::PointerEnter(unsigned handle, float x, float y)
{
  if (epoll_fd_) {
    if (!running)
      return;
    PostTaskOnMainLoop(FROM_HERE, base::Bind(&WaylandDispatcher::SendPointerEnter,
                                             handle, x, y));
  } else {
    scoped_ptr<ui::MouseEvent> mouseev(
        new ui::MouseEvent(ui::ET_MOUSE_ENTERED,
                           gfx::Point(x, y),
                           gfx::Point(x, y),
                           handle));
    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::NotifyPointerEnter, this, handle));

    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::DispatchEventHelper, base::Passed(
                                              mouseev.PassAs<ui::Event>())));
  }
}

void WaylandDispatcher::PointerLeave(unsigned handle, float x, float y)
{
  if (epoll_fd_) {
    if (!running)
      return;
    PostTaskOnMainLoop(FROM_HERE, base::Bind(&WaylandDispatcher::SendPointerLeave,
                                             handle, x, y));
  } else {
    scoped_ptr<ui::MouseEvent> mouseev(
        new ui::MouseEvent(ui::ET_MOUSE_EXITED,
                           gfx::Point(x, y),
                           gfx::Point(x, y),
                           0));

    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::NotifyPointerLeave, this, handle));

    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::DispatchEventHelper, base::Passed(
                                              mouseev.PassAs<ui::Event>())));
  }
}

void WaylandDispatcher::KeyNotify(unsigned state, unsigned code,
                                  unsigned modifiers)
{
  if (epoll_fd_) {
    if (!running)
      return;
    PostTaskOnMainLoop(FROM_HERE, base::Bind(&WaylandDispatcher::SendKeyNotify,
                                             state, code, modifiers));
  } else {
    ui::EventType type;
    if (state)
      type = ui::ET_KEY_PRESSED;
    else
      type = ui::ET_KEY_RELEASED;

    scoped_ptr<ui::KeyEvent> keyev(
        new ui::KeyEvent(type,
                         KeyboardCodeFromXKeysym(code),
                         modifiers,
                         true));

    PostTaskOnMainLoop(FROM_HERE, base::Bind(
                        &WaylandDispatcher::DispatchEventHelper, base::Passed(
                                              keyev.PassAs<ui::Event>())));
  }
}

void WaylandDispatcher::OutputSizeChanged(unsigned width, unsigned height)
{
  if (!running || !epoll_fd_)
    return;

  PostTaskOnMainLoop(FROM_HERE, base::Bind(
                      &WaylandDispatcher::SendOutputSizeChanged, width, height));
}

void WaylandDispatcher::PostTask(Task type)
{
  if (!IsRunning() || ignore_task_)
    return;

  switch (type) {
    case (Flush):
      message_loop_proxy()->PostTask(
                  FROM_HERE, base::Bind(&WaylandDispatcher::HandleFlush));
      break;
    case (Poll):
      if (epoll_fd_) {
        loop_ = base::MessageLoop::current();
        if (!running)
          message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
                                          &WaylandDispatcher::DisplayRun, this));
      }
  default:
    break;
  }
}

void WaylandDispatcher::DispatchEvent(scoped_ptr<ui::Event> event) {
  PostTaskOnMainLoop(FROM_HERE, base::Bind(&WaylandDispatcher::DispatchEventHelper,
                                           base::Passed(&event)));
}

void WaylandDispatcher::PostTaskOnMainLoop(
        const tracked_objects::Location& from_here, const base::Closure& task)
{
  if (ignore_task_ || !IsRunning() || !loop_)
    return;

  loop_->message_loop_proxy()->PostTask(from_here, task);
}

WaylandDispatcher::WaylandDispatcher(int fd)
    : Thread("WaylandDispatcher"),
      ignore_task_(false),
      running(false),
      epoll_fd_(0),
      display_fd_(fd),
      observer_(NULL)
{
  instance_ = this;
  if (display_fd_) {
    epoll_fd_ = osEpollCreateCloExec();
    struct epoll_event ep;
    ep.events = EPOLLIN | EPOLLOUT;
    ep.data.ptr = 0;
    epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, display_fd_, &ep);
  }

  loop_ = base::MessageLoop::current();
  Options options;
  options.message_loop_type = base::MessageLoop::TYPE_IO;
  StartWithOptions(options);
  SetPriority(base::kThreadPriority_Background);
}

WaylandDispatcher::~WaylandDispatcher()
{
  ignore_task_ = true;
  loop_ = NULL;
  running = false;
  Stop();

  if (epoll_fd_) {
    close(epoll_fd_);
    epoll_fd_ = 0;
  }

  instance_ = NULL;
}

void WaylandDispatcher::HandleFlush()
{
  wl_display* waylandDisp = WaylandDisplay::GetInstance()->display();

  while (wl_display_prepare_read(waylandDisp) != 0)
    wl_display_dispatch_pending(waylandDisp);

  wl_display_flush(waylandDisp);
  wl_display_read_events(waylandDisp);
  wl_display_dispatch_pending(waylandDisp);
}

void  WaylandDispatcher::DisplayRun(WaylandDispatcher* data)
{
  struct epoll_event ep[16];
  int i, count, ret;

  data->running = 1;
  // Adopted from:
  // http://cgit.freedesktop.org/wayland/weston/tree/clients/window.c#n5531.
  while (1) {
    wl_display* waylandDisp = WaylandDisplay::GetInstance()->display();
    wl_display_dispatch_pending(waylandDisp);

    if (!data->running)
      break;

    ret = wl_display_flush(waylandDisp);
    if (ret < 0 && errno == EAGAIN) {
      ep[0].events = EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP;
      epoll_ctl(data->epoll_fd_, EPOLL_CTL_MOD, data->display_fd_, &ep[0]);
    } else if (ret < 0) {
      break;
    }

    count = epoll_wait(data->epoll_fd_, ep, 16, -1);
    for (i = 0; i < count; i++) {
      int ret;
      uint32_t event = ep[i].events;

      if (event & EPOLLERR || event & EPOLLHUP)
        return;

      if (event & EPOLLIN) {
        ret = wl_display_dispatch(waylandDisp);
        if (ret == -1)
          return;
      }

      if (event & EPOLLOUT) {
        ret = wl_display_flush(waylandDisp);
        if (ret == 0) {
          struct epoll_event eps;
          memset(&eps, 0, sizeof(eps));

          eps.events = EPOLLIN | EPOLLERR | EPOLLHUP;
          epoll_ctl(data->epoll_fd_, EPOLL_CTL_MOD, data->display_fd_, &eps);
        } else if (ret == -1 && errno != EAGAIN) {
          return;
        }
      }
    }
  }
}

void WaylandDispatcher::NotifyPointerEnter(WaylandDispatcher* data,
                                           unsigned handle) {
  if (data->observer_)
    data->observer_->OnWindowEnter(handle);
}

void WaylandDispatcher::NotifyPointerLeave(WaylandDispatcher* data,
                                           unsigned handle) {
  if (data->observer_)
    data->observer_->OnWindowLeave(handle);
}

void WaylandDispatcher::NotifyButtonPress(WaylandDispatcher* data,
                                          unsigned handle) {
  if (data->observer_)
    data->observer_->OnWindowFocused(handle);
}

void WaylandDispatcher::DispatchEventHelper(scoped_ptr<ui::Event> key) {
  base::MessagePumpOzone::Current()->Dispatch(key.get());
}

void WaylandDispatcher::SendMotionNotify(float x, float y)
{
  content::ChildThread* thread = GetProcessMainThread();
  thread->Send(new WaylandInput_MotionNotify(x, y));
}

void WaylandDispatcher::SendButtonNotify(unsigned handle,
                                         int state,
                                         int flags,
                                         float x,
                                         float y)
{
  content::ChildThread* thread = GetProcessMainThread();
  thread->Send(new WaylandInput_ButtonNotify(handle, state, flags, x, y));
}

void WaylandDispatcher::SendAxisNotify(float x, float y, float xoffset,
                                       float yoffset)
{
  content::ChildThread* thread = GetProcessMainThread();
  thread->Send(new WaylandInput_AxisNotify(x, y, xoffset, yoffset));
}

void WaylandDispatcher::SendPointerEnter(unsigned handle, float x, float y)
{
  content::ChildThread* thread = GetProcessMainThread();
  thread->Send(new WaylandInput_PointerEnter(handle, x, y));
}

void WaylandDispatcher::SendPointerLeave(unsigned handle, float x, float y)
{
  content::ChildThread* thread = GetProcessMainThread();
  thread->Send(new WaylandInput_PointerLeave(handle, x, y));
}

void WaylandDispatcher::SendKeyNotify(unsigned type, unsigned code,
                                      unsigned modifiers)
{
  content::ChildThread* thread = GetProcessMainThread();
  thread->Send(new WaylandInput_KeyNotify(type, code, modifiers));
}

void WaylandDispatcher::SendOutputSizeChanged(unsigned width, unsigned height)
{
  content::ChildThread* thread = GetProcessMainThread();
  thread->Send(new WaylandInput_OutputSize(width, height));
}

void WaylandDispatcher::MessageLoopDestroyed()
{
  if (!IsRunning())
    return;

  ignore_task_ = true;
  loop_ = NULL;
  running = false;
  Stop();
}

}  // namespace ozonewayland
<|endoftext|>


<commit_before>#include <map>
#include <string>
#include <vector>
#include <cmath>

#include "defs.hh"
#include "msfgtest.hh"

#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>

using namespace std;

CPPUNIT_TEST_SUITE_REGISTRATION (msfgtest);

void msfgtest :: setUp (void)
{
    start_end.assign("*");
}

void msfgtest :: tearDown (void)
{
}

void msfgtest :: MultiStringFactorGraphTest1 (void)
{
    MultiStringFactorGraph msfg(start_end);

    map<string, flt_type> vocab;
    vocab["k"] = 0.0;
    vocab["i"] = 0.0;
    vocab["s"] = 0.0;
    vocab["a"] = 0.0;
    vocab["sa"] = 0.0;
    vocab["ki"] = 0.0;
    vocab["kis"] = 0.0;
    vocab["kissa"] = 0.0;
    vocab["lle"] = 0.0;
    vocab["kin"] = 0.0;
    vocab["kala"] = 0.0;

    string sentence("kissa");
    FactorGraph fg(sentence, start_end, vocab, 5);
    string sentence2("kissallekin");
    FactorGraph fg2(sentence2, start_end, vocab, 5);
    string sentence3("kissakala");
    FactorGraph fg3(sentence3, start_end, vocab, 5);
    msfg.add(fg);
    CPPUNIT_ASSERT_EQUAL( 1, (int)msfg.string_end_nodes.size() );
    CPPUNIT_ASSERT_EQUAL( 7, (int)msfg.num_paths(sentence) );
    msfg.add(fg2);
    CPPUNIT_ASSERT_EQUAL( 2, (int)msfg.string_end_nodes.size() );
    CPPUNIT_ASSERT_EQUAL( 7, (int)msfg.num_paths(sentence2) );
    msfg.add(fg3);
    CPPUNIT_ASSERT_EQUAL( 3, (int)msfg.string_end_nodes.size() );
    CPPUNIT_ASSERT_EQUAL( 7, (int)msfg.num_paths(sentence3) );
}

void msfgtest :: MultiStringFactorGraphTest2 (void)
{
    MultiStringFactorGraph msfg(start_end);

    map<string, flt_type> vocab;
    vocab["k"] = 0.0;
    vocab["i"] = 0.0;
    vocab["s"] = 0.0;
    vocab["a"] = 0.0;
    vocab["sa"] = 0.0;
    vocab["ki"] = 0.0;
    vocab["la"] = 0.0;
    vocab["kis"] = 0.0;
    vocab["kissa"] = 0.0;
    vocab["lle"] = 0.0;
    vocab["kin"] = 0.0;
    vocab["kala"] = 0.0;

    string sentence("kissa");
    FactorGraph fg(sentence, start_end, vocab, 5);
    string sentence2("kala");
    FactorGraph fg2(sentence2, start_end, vocab, 5);
    string sentence3("kissakala");
    FactorGraph fg3(sentence3, start_end, vocab, 5);
    msfg.add(fg);
    msfg.add(fg2);
    msfg.add(fg3);
}

// No possible segmentation
void msfgtest :: MultiStringFactorGraphTest3 (void)
{
    CPPUNIT_ASSERT (false);
}
<commit_msg>Failing test case for path counting.<commit_after>#include <map>
#include <string>
#include <vector>
#include <cmath>

#include "defs.hh"
#include "msfgtest.hh"

#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>

using namespace std;

CPPUNIT_TEST_SUITE_REGISTRATION (msfgtest);

void msfgtest :: setUp (void)
{
    start_end.assign("*");
}

void msfgtest :: tearDown (void)
{
}

void msfgtest :: MultiStringFactorGraphTest1 (void)
{
    MultiStringFactorGraph msfg(start_end);

    map<string, flt_type> vocab;
    vocab["k"] = 0.0;
    vocab["i"] = 0.0;
    vocab["s"] = 0.0;
    vocab["a"] = 0.0;
    vocab["sa"] = 0.0;
    vocab["ki"] = 0.0;
    vocab["kis"] = 0.0;
    vocab["kissa"] = 0.0;
    vocab["lle"] = 0.0;
    vocab["kin"] = 0.0;
    vocab["kala"] = 0.0;

    string sentence("kissa");
    FactorGraph fg(sentence, start_end, vocab, 5);
    string sentence2("kissallekin");
    FactorGraph fg2(sentence2, start_end, vocab, 5);
    string sentence3("kissakala");
    FactorGraph fg3(sentence3, start_end, vocab, 5);
    msfg.add(fg);
    CPPUNIT_ASSERT_EQUAL( 1, (int)msfg.string_end_nodes.size() );
    CPPUNIT_ASSERT_EQUAL( 7, (int)msfg.num_paths(sentence) );
    msfg.add(fg2);
    CPPUNIT_ASSERT_EQUAL( 2, (int)msfg.string_end_nodes.size() );
    CPPUNIT_ASSERT_EQUAL( 7, (int)msfg.num_paths(sentence2) );
    msfg.add(fg3);
    CPPUNIT_ASSERT_EQUAL( 3, (int)msfg.string_end_nodes.size() );
    CPPUNIT_ASSERT_EQUAL( 7, (int)msfg.num_paths(sentence3) );
}

void msfgtest :: MultiStringFactorGraphTest2 (void)
{
    MultiStringFactorGraph msfg(start_end);

    map<string, flt_type> vocab;
    vocab["k"] = 0.0;
    vocab["i"] = 0.0;
    vocab["s"] = 0.0;
    vocab["a"] = 0.0;
    vocab["sa"] = 0.0;
    vocab["ki"] = 0.0;
    vocab["la"] = 0.0;
    vocab["kis"] = 0.0;
    vocab["kissa"] = 0.0;
    vocab["lle"] = 0.0;
    vocab["kin"] = 0.0;
    vocab["kala"] = 0.0;

    string sentence("kissa");
    FactorGraph fg(sentence, start_end, vocab, 5);
    string sentence2("kala");
    FactorGraph fg2(sentence2, start_end, vocab, 5);
    string sentence3("kissakala");
    FactorGraph fg3(sentence3, start_end, vocab, 5);
    msfg.add(fg);
    msfg.add(fg2);
    msfg.add(fg3);
}

// No possible segmentation
void msfgtest :: MultiStringFactorGraphTest3 (void)
{
    MultiStringFactorGraph msfg(start_end);

    map<string, flt_type> vocab;
    vocab["aarian"] = 0.0;
    vocab["aari"] = 0.0;
    vocab["an"] = 0.0;
    vocab["a"] = 0.0;
    vocab["ari"] = 0.0;
    vocab["ri"] = 0.0;
    vocab["ar"] = 0.0;
    vocab["i"] = 0.0;
    vocab["n"] = 0.0;
    vocab["r"] = 0.0;

    string word("aarian");
    FactorGraph fg(word, start_end, vocab, 6);
    msfg.add(fg);
    vector<vector<string> > paths;
    msfg.get_paths(word, paths);
    CPPUNIT_ASSERT_EQUAL( 11, (int)paths.size() );
    CPPUNIT_ASSERT_EQUAL( 11, msfg.num_paths(word) );
}
<|endoftext|>


<commit_before>#include <aikido/constraint/dart.hpp>
#include <aikido/constraint/DifferentiableSubSpace.hpp>
#include <aikido/constraint/StackedConstraint.hpp>
#include <dart/common/StlHelpers.h>

namespace aikido {
namespace constraint {

//=============================================================================
std::unique_ptr<Differentiable> createDifferentiableBounds(
  std::shared_ptr<statespace::JointStateSpace> _stateSpace)
{
  return detail::ForOneOf<
      detail::createDifferentiableFor_impl,
      statespace::JointStateSpace,
      detail::JointStateSpaceTypeList
    >::create(std::move(_stateSpace));
}

//=============================================================================
std::unique_ptr<Differentiable> createDifferentiableBounds(
  statespace::MetaSkeletonStateSpacePtr _metaSkeleton)
{
  const auto n = _metaSkeleton->getNumStates();

  std::vector<std::shared_ptr<Differentiable>> constraints;
  constraints.reserve(n);

  // TODO: Filter out trivial constraints for efficiency.
  for (size_t i = 0; i < n; ++i)
  {
    auto subspace = _metaSkeleton->getSubSpace<statespace::JointStateSpace>(i);
    auto subSpaceConstraint = createDifferentiableBounds(std::move(subspace));
    auto constraint = std::make_shared<DifferentiableSubSpace>(
      _metaSkeleton, std::move(subSpaceConstraint), i);
    constraints.emplace_back(std::move(constraint));
  }

  // TODO: We should std::move constraints here, but we can't because
  // StackedConstraint does not take by value.
  return dart::common::make_unique<StackedConstraint>(
    constraints, _metaSkeleton);
}

//=============================================================================
std::unique_ptr<Projectable> createProjectableBounds(
  std::shared_ptr<statespace::JointStateSpace> _stateSpace)
{
  return detail::ForOneOf<
      detail::createProjectableFor_impl,
      statespace::JointStateSpace,
      detail::JointStateSpaceTypeList
    >::create(std::move(_stateSpace));
}

//=============================================================================
std::unique_ptr<Projectable> createProjectableBounds(
  statespace::MetaSkeletonStateSpacePtr _metaSkeleton)
{
  const auto n = _metaSkeleton->getNumStates();

  std::vector<std::shared_ptr<Projectable>> constraints;
  constraints.reserve(n);

  for (size_t i = 0; i < n; ++i)
  {
    auto subspace = _metaSkeleton->getSubSpace<statespace::JointStateSpace>(i);
    auto constraint = createProjectableBounds(std::move(subspace));
    constraints.emplace_back(constraint.release());
  }

  // TODO: Apply a separate constraint to each dimension.

  throw std::runtime_error("not implemented");
}

//=============================================================================
std::unique_ptr<TestableConstraint> createTestableBounds(
  std::shared_ptr<statespace::JointStateSpace> _stateSpace)
{
  return detail::ForOneOf<
      detail::createTestableFor_impl,
      statespace::JointStateSpace,
      detail::JointStateSpaceTypeList
    >::create(std::move(_stateSpace));
}

//=============================================================================
std::unique_ptr<TestableConstraint> createTestableBounds(
  statespace::MetaSkeletonStateSpacePtr _metaSkeleton)
{
  const auto n = _metaSkeleton->getNumStates();

  std::vector<std::shared_ptr<TestableConstraint>> constraints;
  constraints.reserve(n);

  for (size_t i = 0; i < n; ++i)
  {
    auto subspace = _metaSkeleton->getSubSpace<statespace::JointStateSpace>(i);
    auto constraint = createTestableBounds(std::move(subspace));
    constraints.emplace_back(constraint.release());
  }

  // TODO: Apply a separate constraint to each dimension.

  throw std::runtime_error("not implemented");
}

//=============================================================================
std::unique_ptr<SampleableConstraint> createSampleableBounds(
  std::shared_ptr<statespace::JointStateSpace> _stateSpace,
  std::unique_ptr<util::RNG> _rng)
{
  return detail::ForOneOf<
      detail::createSampleableFor_impl,
      statespace::JointStateSpace,
      detail::JointStateSpaceTypeList
    >::create(std::move(_stateSpace), std::move(_rng));
}

//=============================================================================
std::unique_ptr<SampleableConstraint> createSampleableBounds(
  statespace::MetaSkeletonStateSpacePtr _metaSkeleton,
  std::unique_ptr<util::RNG> _rng)
{
  // TODO: Create N random number generators.
  throw std::runtime_error("not implemented");
}

} // namespace constraint
} // namespace aikido
<commit_msg>Added an error check<commit_after>#include <aikido/constraint/dart.hpp>
#include <aikido/constraint/DifferentiableSubSpace.hpp>
#include <aikido/constraint/StackedConstraint.hpp>
#include <dart/common/StlHelpers.h>

namespace aikido {
namespace constraint {

//=============================================================================
std::unique_ptr<Differentiable> createDifferentiableBounds(
  std::shared_ptr<statespace::JointStateSpace> _stateSpace)
{
  return detail::ForOneOf<
      detail::createDifferentiableFor_impl,
      statespace::JointStateSpace,
      detail::JointStateSpaceTypeList
    >::create(std::move(_stateSpace));
}

//=============================================================================
std::unique_ptr<Differentiable> createDifferentiableBounds(
  statespace::MetaSkeletonStateSpacePtr _metaSkeleton)
{
  if (!_metaSkeleton)
    throw std::invalid_argument("MetaSkeletonStateSpace is nullptr.");

  const auto n = _metaSkeleton->getNumStates();

  std::vector<std::shared_ptr<Differentiable>> constraints;
  constraints.reserve(n);

  // TODO: Filter out trivial constraints for efficiency.
  for (size_t i = 0; i < n; ++i)
  {
    auto subspace = _metaSkeleton->getSubSpace<statespace::JointStateSpace>(i);
    auto subSpaceConstraint = createDifferentiableBounds(std::move(subspace));
    auto constraint = std::make_shared<DifferentiableSubSpace>(
      _metaSkeleton, std::move(subSpaceConstraint), i);
    constraints.emplace_back(std::move(constraint));
  }

  // TODO: We should std::move constraints here, but we can't because
  // StackedConstraint does not take by value.
  return dart::common::make_unique<StackedConstraint>(
    constraints, _metaSkeleton);
}

//=============================================================================
std::unique_ptr<Projectable> createProjectableBounds(
  std::shared_ptr<statespace::JointStateSpace> _stateSpace)
{
  return detail::ForOneOf<
      detail::createProjectableFor_impl,
      statespace::JointStateSpace,
      detail::JointStateSpaceTypeList
    >::create(std::move(_stateSpace));
}

//=============================================================================
std::unique_ptr<Projectable> createProjectableBounds(
  statespace::MetaSkeletonStateSpacePtr _metaSkeleton)
{
  const auto n = _metaSkeleton->getNumStates();

  std::vector<std::shared_ptr<Projectable>> constraints;
  constraints.reserve(n);

  for (size_t i = 0; i < n; ++i)
  {
    auto subspace = _metaSkeleton->getSubSpace<statespace::JointStateSpace>(i);
    auto constraint = createProjectableBounds(std::move(subspace));
    constraints.emplace_back(constraint.release());
  }

  // TODO: Apply a separate constraint to each dimension.

  throw std::runtime_error("not implemented");
}

//=============================================================================
std::unique_ptr<TestableConstraint> createTestableBounds(
  std::shared_ptr<statespace::JointStateSpace> _stateSpace)
{
  return detail::ForOneOf<
      detail::createTestableFor_impl,
      statespace::JointStateSpace,
      detail::JointStateSpaceTypeList
    >::create(std::move(_stateSpace));
}

//=============================================================================
std::unique_ptr<TestableConstraint> createTestableBounds(
  statespace::MetaSkeletonStateSpacePtr _metaSkeleton)
{
  const auto n = _metaSkeleton->getNumStates();

  std::vector<std::shared_ptr<TestableConstraint>> constraints;
  constraints.reserve(n);

  for (size_t i = 0; i < n; ++i)
  {
    auto subspace = _metaSkeleton->getSubSpace<statespace::JointStateSpace>(i);
    auto constraint = createTestableBounds(std::move(subspace));
    constraints.emplace_back(constraint.release());
  }

  // TODO: Apply a separate constraint to each dimension.

  throw std::runtime_error("not implemented");
}

//=============================================================================
std::unique_ptr<SampleableConstraint> createSampleableBounds(
  std::shared_ptr<statespace::JointStateSpace> _stateSpace,
  std::unique_ptr<util::RNG> _rng)
{
  return detail::ForOneOf<
      detail::createSampleableFor_impl,
      statespace::JointStateSpace,
      detail::JointStateSpaceTypeList
    >::create(std::move(_stateSpace), std::move(_rng));
}

//=============================================================================
std::unique_ptr<SampleableConstraint> createSampleableBounds(
  statespace::MetaSkeletonStateSpacePtr _metaSkeleton,
  std::unique_ptr<util::RNG> _rng)
{
  // TODO: Create N random number generators.
  throw std::runtime_error("not implemented");
}

} // namespace constraint
} // namespace aikido
<|endoftext|>


<commit_before>/*

Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TINY_COMPONENTS_HPP
#define TINY_COMPONENTS_HPP

#include "../typedefs.h"
#include "../data_structures/deallocating_vector.hpp"
#include "../data_structures/import_edge.hpp"
#include "../data_structures/query_node.hpp"
#include "../data_structures/percent.hpp"
#include "../data_structures/restriction.hpp"
#include "../data_structures/restriction_map.hpp"
#include "../data_structures/turn_instructions.hpp"

#include "../Util/integer_range.hpp"
#include "../Util/OSRMException.h"
#include "../Util/simple_logger.hpp"
#include "../Util/std_hash.hpp"
#include "../Util/timing_util.hpp"

#include <osrm/Coordinate.h>

#include <boost/assert.hpp>

#include <tbb/parallel_sort.h>

#include <cstdint>

#include <memory>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>

template <typename GraphT>
class TarjanSCC
{
    struct TarjanStackFrame
    {
        explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {}
        NodeID v;
        NodeID parent;
    };

    struct TarjanNode
    {
        TarjanNode() : index(SPECIAL_NODEID), low_link(SPECIAL_NODEID), on_stack(false) {}
        unsigned index;
        unsigned low_link;
        bool on_stack;
    };

    std::vector<unsigned> components_index;
    std::vector<NodeID> component_size_vector;
    std::shared_ptr<GraphT> m_node_based_graph;
    std::unordered_set<NodeID> barrier_node_set;
    RestrictionMap m_restriction_map;
    unsigned size_one_counter;

  public:
    template<class ContainerT>
    TarjanSCC(std::shared_ptr<GraphT> graph,
              const RestrictionMap &restrictions,
              const ContainerT &barrier_node_list)
        : components_index(graph->GetNumberOfNodes(), SPECIAL_NODEID),
          m_node_based_graph(graph), m_restriction_map(restrictions),
          size_one_counter(0)
    {
        barrier_node_set.insert(std::begin(barrier_node_list), std::end(barrier_node_list));
        BOOST_ASSERT(m_node_based_graph->GetNumberOfNodes() > 0);
    }

    void run()
    {
        TIMER_START(SCC_RUN);
        // The following is a hack to distinguish between stuff that happens
        // before the recursive call and stuff that happens after
        std::stack<TarjanStackFrame> recursion_stack;
        // true = stuff before, false = stuff after call
        std::stack<NodeID> tarjan_stack;
        std::vector<TarjanNode> tarjan_node_list(m_node_based_graph->GetNumberOfNodes());
        unsigned component_index = 0, size_of_current_component = 0;
        int index = 0;
        const NodeID last_node = m_node_based_graph->GetNumberOfNodes();
        std::vector<bool> processing_node_before_recursion(m_node_based_graph->GetNumberOfNodes(), true);
        for(const NodeID node : osrm::irange(0u, last_node))
        {
            if (SPECIAL_NODEID == components_index[node])
            {
                recursion_stack.emplace(TarjanStackFrame(node, node));
            }

            while (!recursion_stack.empty())
            {
                TarjanStackFrame currentFrame = recursion_stack.top();
                const NodeID u = currentFrame.parent;
                const NodeID v = currentFrame.v;
                recursion_stack.pop();

                const bool before_recursion = processing_node_before_recursion[v];

                if (before_recursion && tarjan_node_list[v].index != UINT_MAX)
                {
                    continue;
                }

                if (before_recursion)
                {
                    // Mark frame to handle tail of recursion
                    recursion_stack.emplace(currentFrame);
                    processing_node_before_recursion[v] = false;

                    // Mark essential information for SCC
                    tarjan_node_list[v].index = index;
                    tarjan_node_list[v].low_link = index;
                    tarjan_stack.push(v);
                    tarjan_node_list[v].on_stack = true;
                    ++index;

                    // Traverse outgoing edges
                    if (barrier_node_set.find(v) != barrier_node_set.end())
                    {
                        continue;
                    }

                    const NodeID to_node_of_only_restriction =
                        m_restriction_map.CheckForEmanatingIsOnlyTurn(u, v);

                    for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(v))
                    {
                        const auto vprime = m_node_based_graph->GetTarget(current_edge);
                        if (to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&
                            vprime == to_node_of_only_restriction)
                        {
                            // At an only_-restriction but not at the right turn
                            // continue;
                        }

                        if (m_restriction_map.CheckIfTurnIsRestricted(u, v, vprime))
                        {
                            // continue;
                        }

                        if (SPECIAL_NODEID == tarjan_node_list[vprime].index)
                        {
                            recursion_stack.emplace(TarjanStackFrame(vprime, v));
                        }
                        else
                        {
                            if (tarjan_node_list[vprime].on_stack &&
                                tarjan_node_list[vprime].index < tarjan_node_list[v].low_link)
                            {
                                tarjan_node_list[v].low_link = tarjan_node_list[vprime].index;
                            }
                        }
                    }
                }
                else
                {
                    processing_node_before_recursion[v] = true;
                    tarjan_node_list[currentFrame.parent].low_link =
                        std::min(tarjan_node_list[currentFrame.parent].low_link,
                                 tarjan_node_list[v].low_link);
                    // after recursion, lets do cycle checking
                    // Check if we found a cycle. This is the bottom part of the recursion
                    if (tarjan_node_list[v].low_link == tarjan_node_list[v].index)
                    {
                        NodeID vprime;
                        do
                        {
                            vprime = tarjan_stack.top();
                            tarjan_stack.pop();
                            tarjan_node_list[vprime].on_stack = false;
                            components_index[vprime] = component_index;
                            ++size_of_current_component;
                        } while (v != vprime);

                        component_size_vector.emplace_back(size_of_current_component);

                        if (size_of_current_component > 1000)
                        {
                            SimpleLogger().Write() << "large component [" << component_index
                                                   << "]=" << size_of_current_component;
                        }

                        ++component_index;
                        size_of_current_component = 0;
                    }
                }
            }
        }

        TIMER_STOP(SCC_RUN);
        SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN)/1000. << "s";
        SimpleLogger().Write() << "identified: " << component_size_vector.size() << " many components";

        size_one_counter = std::count_if(component_size_vector.begin(),
                                         component_size_vector.end(),
                                         [](unsigned value)
                                         {
            return 1 == value;
        });

        SimpleLogger().Write() << "identified " << size_one_counter << " SCCs of size 1";

    }

    std::size_t get_number_of_components() const
    {
        return component_size_vector.size();
    }

    unsigned get_component_size(const NodeID node) const
    {
        return component_size_vector[components_index[node]];
    }
};

#endif /* TINY_COMPONENTS_HPP */
<commit_msg>move SCC stats output out of algo implementation<commit_after>/*

Copyright (c) 2014, Project OSRM, Dennis Luxen, others
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TINY_COMPONENTS_HPP
#define TINY_COMPONENTS_HPP

#include "../typedefs.h"
#include "../data_structures/deallocating_vector.hpp"
#include "../data_structures/import_edge.hpp"
#include "../data_structures/query_node.hpp"
#include "../data_structures/percent.hpp"
#include "../data_structures/restriction.hpp"
#include "../data_structures/restriction_map.hpp"
#include "../data_structures/turn_instructions.hpp"

#include "../Util/integer_range.hpp"
#include "../Util/OSRMException.h"
#include "../Util/simple_logger.hpp"
#include "../Util/std_hash.hpp"
#include "../Util/timing_util.hpp"

#include <osrm/Coordinate.h>

#include <boost/assert.hpp>

#include <tbb/parallel_sort.h>

#include <cstdint>

#include <memory>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>

template <typename GraphT>
class TarjanSCC
{
    struct TarjanStackFrame
    {
        explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {}
        NodeID v;
        NodeID parent;
    };

    struct TarjanNode
    {
        TarjanNode() : index(SPECIAL_NODEID), low_link(SPECIAL_NODEID), on_stack(false) {}
        unsigned index;
        unsigned low_link;
        bool on_stack;
    };

    std::vector<unsigned> components_index;
    std::vector<NodeID> component_size_vector;
    std::shared_ptr<GraphT> m_node_based_graph;
    std::unordered_set<NodeID> barrier_node_set;
    RestrictionMap m_restriction_map;
    unsigned size_one_counter;

  public:
    template<class ContainerT>
    TarjanSCC(std::shared_ptr<GraphT> graph,
              const RestrictionMap &restrictions,
              const ContainerT &barrier_node_list)
        : components_index(graph->GetNumberOfNodes(), SPECIAL_NODEID),
          m_node_based_graph(graph), m_restriction_map(restrictions),
          size_one_counter(0)
    {
        barrier_node_set.insert(std::begin(barrier_node_list), std::end(barrier_node_list));
        BOOST_ASSERT(m_node_based_graph->GetNumberOfNodes() > 0);
    }

    void run()
    {
        TIMER_START(SCC_RUN);
        // The following is a hack to distinguish between stuff that happens
        // before the recursive call and stuff that happens after
        std::stack<TarjanStackFrame> recursion_stack;
        // true = stuff before, false = stuff after call
        std::stack<NodeID> tarjan_stack;
        std::vector<TarjanNode> tarjan_node_list(m_node_based_graph->GetNumberOfNodes());
        unsigned component_index = 0, size_of_current_component = 0;
        int index = 0;
        const NodeID last_node = m_node_based_graph->GetNumberOfNodes();
        std::vector<bool> processing_node_before_recursion(m_node_based_graph->GetNumberOfNodes(), true);
        for(const NodeID node : osrm::irange(0u, last_node))
        {
            if (SPECIAL_NODEID == components_index[node])
            {
                recursion_stack.emplace(TarjanStackFrame(node, node));
            }

            while (!recursion_stack.empty())
            {
                TarjanStackFrame currentFrame = recursion_stack.top();
                const NodeID u = currentFrame.parent;
                const NodeID v = currentFrame.v;
                recursion_stack.pop();

                const bool before_recursion = processing_node_before_recursion[v];

                if (before_recursion && tarjan_node_list[v].index != UINT_MAX)
                {
                    continue;
                }

                if (before_recursion)
                {
                    // Mark frame to handle tail of recursion
                    recursion_stack.emplace(currentFrame);
                    processing_node_before_recursion[v] = false;

                    // Mark essential information for SCC
                    tarjan_node_list[v].index = index;
                    tarjan_node_list[v].low_link = index;
                    tarjan_stack.push(v);
                    tarjan_node_list[v].on_stack = true;
                    ++index;

                    // Traverse outgoing edges
                    if (barrier_node_set.find(v) != barrier_node_set.end())
                    {
                        continue;
                    }

                    const NodeID to_node_of_only_restriction =
                        m_restriction_map.CheckForEmanatingIsOnlyTurn(u, v);

                    for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(v))
                    {
                        const auto vprime = m_node_based_graph->GetTarget(current_edge);
                        if (to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&
                            vprime == to_node_of_only_restriction)
                        {
                            // At an only_-restriction but not at the right turn
                            // continue;
                        }

                        if (m_restriction_map.CheckIfTurnIsRestricted(u, v, vprime))
                        {
                            // continue;
                        }

                        if (SPECIAL_NODEID == tarjan_node_list[vprime].index)
                        {
                            recursion_stack.emplace(TarjanStackFrame(vprime, v));
                        }
                        else
                        {
                            if (tarjan_node_list[vprime].on_stack &&
                                tarjan_node_list[vprime].index < tarjan_node_list[v].low_link)
                            {
                                tarjan_node_list[v].low_link = tarjan_node_list[vprime].index;
                            }
                        }
                    }
                }
                else
                {
                    processing_node_before_recursion[v] = true;
                    tarjan_node_list[currentFrame.parent].low_link =
                        std::min(tarjan_node_list[currentFrame.parent].low_link,
                                 tarjan_node_list[v].low_link);
                    // after recursion, lets do cycle checking
                    // Check if we found a cycle. This is the bottom part of the recursion
                    if (tarjan_node_list[v].low_link == tarjan_node_list[v].index)
                    {
                        NodeID vprime;
                        do
                        {
                            vprime = tarjan_stack.top();
                            tarjan_stack.pop();
                            tarjan_node_list[vprime].on_stack = false;
                            components_index[vprime] = component_index;
                            ++size_of_current_component;
                        } while (v != vprime);

                        component_size_vector.emplace_back(size_of_current_component);

                        if (size_of_current_component > 1000)
                        {
                            SimpleLogger().Write() << "large component [" << component_index
                                                   << "]=" << size_of_current_component;
                        }

                        ++component_index;
                        size_of_current_component = 0;
                    }
                }
            }
        }

        TIMER_STOP(SCC_RUN);
        SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN)/1000. << "s";

        size_one_counter = std::count_if(component_size_vector.begin(),
                                         component_size_vector.end(),
                                         [](unsigned value)
                                         {
            return 1 == value;
        });
    }

    std::size_t get_number_of_components() const
    {
        return component_size_vector.size();
    }

    unsigned get_size_one_count() const
    {
        return size_one_counter;
    }

    unsigned get_component_size(const NodeID node) const
    {
        return component_size_vector[components_index[node]];
    }
};

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