<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2012 Francois Beaune, Jupiter Jazz Limited
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "entitybrowser.h"

// appleseed.renderer headers.
#include "renderer/api/bsdf.h"
#include "renderer/api/color.h"
#include "renderer/api/edf.h"
#include "renderer/api/environmentedf.h"
#include "renderer/api/environmentshader.h"
#include "renderer/api/material.h"
#include "renderer/api/scene.h"
#include "renderer/api/surfaceshader.h"

// appleseed.foundation headers.
#include "foundation/utility/containers/dictionary.h"
#include "foundation/utility/foreach.h"

using namespace foundation;
using namespace renderer;
using namespace std;

namespace appleseed {
namespace studio {

namespace
{
    template <typename EntityContainer>
    StringDictionary build_entity_dictionary(const EntityContainer& entities)
    {
        StringDictionary result;

        for (const_each<EntityContainer> i = entities; i; ++i)
            result.insert(i->get_name(), i->get_name());

        return result;
    }

    void merge_dictionary(StringDictionary& dest, const StringDictionary& other)
    {
        for (const_each<StringDictionary> i = other; i; ++i)
            dest.insert(i->name(), i->value());
    }
}

//
// EntityBrowser<BaseGroup> class implementation.
//

EntityBrowser<BaseGroup>::EntityBrowser(const BaseGroup& base_group)
  : m_base_group(base_group)
{
}

StringDictionary EntityBrowser<BaseGroup>::get_entities(const string& type) const
{
    if (type == "color")
    {
        return build_entity_dictionary(m_base_group.colors());
    }
    else if (type == "texture_instance")
    {
        return build_entity_dictionary(m_base_group.texture_instances());
    }
    else
    {
        return StringDictionary();
    }
}

//
// EntityBrowser<Scene> class implementation.
//

EntityBrowser<Scene>::EntityBrowser(const Scene& scene)
  : EntityBrowser<BaseGroup>(scene)
  , m_scene(scene)
{
}

StringDictionary EntityBrowser<Scene>::get_entities(const string& type) const
{
    if (type == "environment_edf")
    {
        return build_entity_dictionary(m_scene.environment_edfs());
    }
    else if (type == "environment_shader")
    {
        return build_entity_dictionary(m_scene.environment_shaders());
    }
    else
    {
        return EntityBrowser<BaseGroup>::get_entities(type);
    }
}

//
// EntityBrowser<Assembly> class implementation.
//

EntityBrowser<Assembly>::EntityBrowser(const Assembly& assembly)
  : EntityBrowser<BaseGroup>(assembly)
  , m_assembly(assembly)
{
}

StringDictionary EntityBrowser<Assembly>::get_entities(const string& type) const
{
    return get_entities(m_assembly, type);
}

StringDictionary EntityBrowser<Assembly>::get_entities(const Assembly& assembly, const string& type) const
{
    StringDictionary entities;

    if (type == "bsdf")
    {
        entities = build_entity_dictionary(assembly.bsdfs());
    }
    else if (type == "edf")
    {
        entities = build_entity_dictionary(assembly.edfs());
    }
    else if (type == "material")
    {
        entities = build_entity_dictionary(assembly.materials());
    }
    else if (type == "surface_shader")
    {
        entities = build_entity_dictionary(assembly.surface_shaders());
    }
    else
    {
        return EntityBrowser<BaseGroup>::get_entities(type);
    }

    if (assembly.get_parent())
    {
        const Assembly& parent = *static_cast<Assembly*>(assembly.get_parent());
        merge_dictionary(entities, get_entities(parent, type));
    }

    return entities;
}

}   // namespace studio
}   // namespace appleseed
<commit_msg>fixed regression introduced with support for nested assemblies: appleseed.studio would crash when browsing for an entity (e.g. a BSDF) during the edition of another entity (e.g. a material).<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2012 Francois Beaune, Jupiter Jazz Limited
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "entitybrowser.h"

// appleseed.renderer headers.
#include "renderer/api/bsdf.h"
#include "renderer/api/color.h"
#include "renderer/api/edf.h"
#include "renderer/api/environmentedf.h"
#include "renderer/api/environmentshader.h"
#include "renderer/api/material.h"
#include "renderer/api/scene.h"
#include "renderer/api/surfaceshader.h"

// appleseed.foundation headers.
#include "foundation/utility/containers/dictionary.h"
#include "foundation/utility/foreach.h"

using namespace foundation;
using namespace renderer;
using namespace std;

namespace appleseed {
namespace studio {

namespace
{
    template <typename EntityContainer>
    StringDictionary build_entity_dictionary(const EntityContainer& entities)
    {
        StringDictionary result;

        for (const_each<EntityContainer> i = entities; i; ++i)
            result.insert(i->get_name(), i->get_name());

        return result;
    }

    void merge_dictionary(StringDictionary& dest, const StringDictionary& other)
    {
        for (const_each<StringDictionary> i = other; i; ++i)
            dest.insert(i->name(), i->value());
    }
}

//
// EntityBrowser<BaseGroup> class implementation.
//

EntityBrowser<BaseGroup>::EntityBrowser(const BaseGroup& base_group)
  : m_base_group(base_group)
{
}

StringDictionary EntityBrowser<BaseGroup>::get_entities(const string& type) const
{
    if (type == "color")
    {
        return build_entity_dictionary(m_base_group.colors());
    }
    else if (type == "texture_instance")
    {
        return build_entity_dictionary(m_base_group.texture_instances());
    }
    else
    {
        return StringDictionary();
    }
}

//
// EntityBrowser<Scene> class implementation.
//

EntityBrowser<Scene>::EntityBrowser(const Scene& scene)
  : EntityBrowser<BaseGroup>(scene)
  , m_scene(scene)
{
}

StringDictionary EntityBrowser<Scene>::get_entities(const string& type) const
{
    if (type == "environment_edf")
    {
        return build_entity_dictionary(m_scene.environment_edfs());
    }
    else if (type == "environment_shader")
    {
        return build_entity_dictionary(m_scene.environment_shaders());
    }
    else
    {
        return EntityBrowser<BaseGroup>::get_entities(type);
    }
}

//
// EntityBrowser<Assembly> class implementation.
//

EntityBrowser<Assembly>::EntityBrowser(const Assembly& assembly)
  : EntityBrowser<BaseGroup>(assembly)
  , m_assembly(assembly)
{
}

StringDictionary EntityBrowser<Assembly>::get_entities(const string& type) const
{
    return get_entities(m_assembly, type);
}

StringDictionary EntityBrowser<Assembly>::get_entities(const Assembly& assembly, const string& type) const
{
    StringDictionary entities;

    if (type == "bsdf")
    {
        entities = build_entity_dictionary(assembly.bsdfs());
    }
    else if (type == "edf")
    {
        entities = build_entity_dictionary(assembly.edfs());
    }
    else if (type == "material")
    {
        entities = build_entity_dictionary(assembly.materials());
    }
    else if (type == "surface_shader")
    {
        entities = build_entity_dictionary(assembly.surface_shaders());
    }
    else
    {
        return EntityBrowser<BaseGroup>::get_entities(type);
    }

    if (assembly.get_parent())
    {
        const Assembly* parent = dynamic_cast<const Assembly*>(assembly.get_parent());

        if (parent)
            merge_dictionary(entities, get_entities(*parent, type));
    }

    return entities;
}

}   // namespace studio
}   // namespace appleseed
<|endoftext|>


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

#include "client/windows/crash_generation/minidump_generator.h"
#include <cassert>
#include "client/windows/common/auto_critical_section.h"
#include "common/windows/guid_string.h"

using std::wstring;

namespace google_breakpad {

MinidumpGenerator::MinidumpGenerator(const wstring& dump_path)
    : dbghelp_module_(NULL),
      rpcrt4_module_(NULL),
      dump_path_(dump_path),
      write_dump_(NULL),
      create_uuid_(NULL) {
  InitializeCriticalSection(&module_load_sync_);
  InitializeCriticalSection(&get_proc_address_sync_);
}

MinidumpGenerator::~MinidumpGenerator() {
  if (dbghelp_module_) {
    FreeLibrary(dbghelp_module_);
  }

  if (rpcrt4_module_) {
    FreeLibrary(rpcrt4_module_);
  }

  DeleteCriticalSection(&get_proc_address_sync_);
  DeleteCriticalSection(&module_load_sync_);
}

bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
                                      DWORD process_id,
                                      DWORD thread_id,
                                      DWORD requesting_thread_id,
                                      EXCEPTION_POINTERS* exception_pointers,
                                      MDRawAssertionInfo* assert_info,
                                      MINIDUMP_TYPE dump_type,
                                      bool is_client_pointers,
                                      wstring* dump_path) {
  MiniDumpWriteDumpType write_dump = GetWriteDump();
  if (!write_dump) {
    return false;
  }

  wstring dump_file_path;
  if (!GenerateDumpFilePath(&dump_file_path)) {
    return false;
  }

  HANDLE dump_file = CreateFile(dump_file_path.c_str(),
                                GENERIC_WRITE,
                                0,
                                NULL,
                                CREATE_NEW,
                                FILE_ATTRIBUTE_NORMAL,
                                NULL);

  if (dump_file == INVALID_HANDLE_VALUE) {
    return false;
  }

  MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL;
  MINIDUMP_EXCEPTION_INFORMATION dump_exception_info;

  // Setup the exception information object only if it's a dump
  // due to an exception.
  if (exception_pointers) {
    dump_exception_pointers = &dump_exception_info;
    dump_exception_info.ThreadId = thread_id;
    dump_exception_info.ExceptionPointers = exception_pointers;
    dump_exception_info.ClientPointers = is_client_pointers;
  }

  // Add an MDRawBreakpadInfo stream to the minidump, to provide additional
  // information about the exception handler to the Breakpad processor.
  // The information will help the processor determine which threads are
  // relevant. The Breakpad processor does not require this information but
  // can function better with Breakpad-generated dumps when it is present.
  // The native debugger is not harmed by the presence of this information.
  MDRawBreakpadInfo breakpad_info;
  breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
                           MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
  breakpad_info.dump_thread_id = thread_id;
  breakpad_info.requesting_thread_id = requesting_thread_id;

  // Leave room in user_stream_array for a possible assertion info stream.
  MINIDUMP_USER_STREAM user_stream_array[2];
  user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
  user_stream_array[0].BufferSize = sizeof(breakpad_info);
  user_stream_array[0].Buffer = &breakpad_info;

  MINIDUMP_USER_STREAM_INFORMATION user_streams;
  user_streams.UserStreamCount = 1;
  user_streams.UserStreamArray = user_stream_array;

  MDRawAssertionInfo* actual_assert_info = assert_info;
  MDRawAssertionInfo client_assert_info = {0};

  if (assert_info) {
    // If the assertion info object lives in the client process,
    // read the memory of the client process.
    if (is_client_pointers) {
      SIZE_T bytes_read = 0;
      if (!ReadProcessMemory(process_handle,
                             assert_info,
                             &client_assert_info,
                             sizeof(client_assert_info),
                             &bytes_read)) {
        CloseHandle(dump_file);
        return false;
      }

      if (bytes_read != sizeof(client_assert_info)) {
        CloseHandle(dump_file);
        return false;
      }

      actual_assert_info  = &client_assert_info;
    }

    user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
    user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
    user_stream_array[1].Buffer = actual_assert_info;
    ++user_streams.UserStreamCount;
  }

  bool result = write_dump(process_handle,
                           process_id,
                           dump_file,
                           dump_type,
                           exception_pointers ? &dump_exception_info : NULL,
                           &user_streams,
                           NULL) != FALSE;

  CloseHandle(dump_file);

  // Store the path of the dump file in the out parameter if dump generation
  // succeeded.
  if (result && dump_path) {
    *dump_path = dump_file_path;
  }

  return result;
}

HMODULE MinidumpGenerator::GetDbghelpModule() {
  AutoCriticalSection lock(&module_load_sync_);
  if (!dbghelp_module_) {
    dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll"));
  }

  return dbghelp_module_;
}

MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() {
  AutoCriticalSection lock(&get_proc_address_sync_);
  if (!write_dump_) {
    HMODULE module = GetDbghelpModule();
    if (module) {
      FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump");
      write_dump_ = reinterpret_cast<MiniDumpWriteDumpType>(proc);
    }
  }

  return write_dump_;
}

HMODULE MinidumpGenerator::GetRpcrt4Module() {
  AutoCriticalSection lock(&module_load_sync_);
  if (!rpcrt4_module_) {
    rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll"));
  }

  return rpcrt4_module_;
}

MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() {
  AutoCriticalSection lock(&module_load_sync_);
  if (!create_uuid_) {
    HMODULE module = GetRpcrt4Module();
    if (module) {
      FARPROC proc = GetProcAddress(module, "UuidCreate");
      create_uuid_ = reinterpret_cast<UuidCreateType>(proc);
    }
  }

  return create_uuid_;
}

bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) {
  UUID id = {0};

  UuidCreateType create_uuid = GetCreateUuid();
  if(!create_uuid) {
    return false;
  }

  create_uuid(&id);
  wstring id_str = GUIDString::GUIDToWString(&id);

  *file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp");
  return true;
}

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

#include "client/windows/crash_generation/minidump_generator.h"
#include <cassert>
#include "client/windows/common/auto_critical_section.h"
#include "common/windows/guid_string.h"

using std::wstring;

namespace google_breakpad {

MinidumpGenerator::MinidumpGenerator(const wstring& dump_path)
    : dbghelp_module_(NULL),
      rpcrt4_module_(NULL),
      dump_path_(dump_path),
      write_dump_(NULL),
      create_uuid_(NULL) {
  InitializeCriticalSection(&module_load_sync_);
  InitializeCriticalSection(&get_proc_address_sync_);
}

MinidumpGenerator::~MinidumpGenerator() {
  if (dbghelp_module_) {
    FreeLibrary(dbghelp_module_);
  }

  if (rpcrt4_module_) {
    FreeLibrary(rpcrt4_module_);
  }

  DeleteCriticalSection(&get_proc_address_sync_);
  DeleteCriticalSection(&module_load_sync_);
}

bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
                                      DWORD process_id,
                                      DWORD thread_id,
                                      DWORD requesting_thread_id,
                                      EXCEPTION_POINTERS* exception_pointers,
                                      MDRawAssertionInfo* assert_info,
                                      MINIDUMP_TYPE dump_type,
                                      bool is_client_pointers,
                                      wstring* dump_path) {
  MiniDumpWriteDumpType write_dump = GetWriteDump();
  if (!write_dump) {
    return false;
  }

  wstring dump_file_path;
  if (!GenerateDumpFilePath(&dump_file_path)) {
    return false;
  }

  HANDLE dump_file = CreateFile(dump_file_path.c_str(),
                                GENERIC_WRITE,
                                0,
                                NULL,
                                CREATE_NEW,
                                FILE_ATTRIBUTE_NORMAL,
                                NULL);

  if (dump_file == INVALID_HANDLE_VALUE) {
    return false;
  }

  MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL;
  MINIDUMP_EXCEPTION_INFORMATION dump_exception_info;

  // Setup the exception information object only if it's a dump
  // due to an exception.
  if (exception_pointers) {
    dump_exception_pointers = &dump_exception_info;
    dump_exception_info.ThreadId = thread_id;
    dump_exception_info.ExceptionPointers = exception_pointers;
    dump_exception_info.ClientPointers = is_client_pointers;
  }

  // Add an MDRawBreakpadInfo stream to the minidump, to provide additional
  // information about the exception handler to the Breakpad processor.
  // The information will help the processor determine which threads are
  // relevant. The Breakpad processor does not require this information but
  // can function better with Breakpad-generated dumps when it is present.
  // The native debugger is not harmed by the presence of this information.
  MDRawBreakpadInfo breakpad_info = {0};
  if (!is_client_pointers) {
    // Set the dump thread id and requesting thread id only in case of
    // in-process dump generation.
    breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
                             MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
    breakpad_info.dump_thread_id = thread_id;
    breakpad_info.requesting_thread_id = requesting_thread_id;
  }

  // Leave room in user_stream_array for a possible assertion info stream.
  MINIDUMP_USER_STREAM user_stream_array[2];
  user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
  user_stream_array[0].BufferSize = sizeof(breakpad_info);
  user_stream_array[0].Buffer = &breakpad_info;

  MINIDUMP_USER_STREAM_INFORMATION user_streams;
  user_streams.UserStreamCount = 1;
  user_streams.UserStreamArray = user_stream_array;

  MDRawAssertionInfo* actual_assert_info = assert_info;
  MDRawAssertionInfo client_assert_info = {0};

  if (assert_info) {
    // If the assertion info object lives in the client process,
    // read the memory of the client process.
    if (is_client_pointers) {
      SIZE_T bytes_read = 0;
      if (!ReadProcessMemory(process_handle,
                             assert_info,
                             &client_assert_info,
                             sizeof(client_assert_info),
                             &bytes_read)) {
        CloseHandle(dump_file);
        return false;
      }

      if (bytes_read != sizeof(client_assert_info)) {
        CloseHandle(dump_file);
        return false;
      }

      actual_assert_info  = &client_assert_info;
    }

    user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
    user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
    user_stream_array[1].Buffer = actual_assert_info;
    ++user_streams.UserStreamCount;
  }

  bool result = write_dump(process_handle,
                           process_id,
                           dump_file,
                           dump_type,
                           exception_pointers ? &dump_exception_info : NULL,
                           &user_streams,
                           NULL) != FALSE;

  CloseHandle(dump_file);

  // Store the path of the dump file in the out parameter if dump generation
  // succeeded.
  if (result && dump_path) {
    *dump_path = dump_file_path;
  }

  return result;
}

HMODULE MinidumpGenerator::GetDbghelpModule() {
  AutoCriticalSection lock(&module_load_sync_);
  if (!dbghelp_module_) {
    dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll"));
  }

  return dbghelp_module_;
}

MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() {
  AutoCriticalSection lock(&get_proc_address_sync_);
  if (!write_dump_) {
    HMODULE module = GetDbghelpModule();
    if (module) {
      FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump");
      write_dump_ = reinterpret_cast<MiniDumpWriteDumpType>(proc);
    }
  }

  return write_dump_;
}

HMODULE MinidumpGenerator::GetRpcrt4Module() {
  AutoCriticalSection lock(&module_load_sync_);
  if (!rpcrt4_module_) {
    rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll"));
  }

  return rpcrt4_module_;
}

MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() {
  AutoCriticalSection lock(&module_load_sync_);
  if (!create_uuid_) {
    HMODULE module = GetRpcrt4Module();
    if (module) {
      FARPROC proc = GetProcAddress(module, "UuidCreate");
      create_uuid_ = reinterpret_cast<UuidCreateType>(proc);
    }
  }

  return create_uuid_;
}

bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) {
  UUID id = {0};

  UuidCreateType create_uuid = GetCreateUuid();
  if(!create_uuid) {
    return false;
  }

  create_uuid(&id);
  wstring id_str = GUIDString::GUIDToWString(&id);

  *file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp");
  return true;
}

}  // namespace google_breakpad
<|endoftext|>


<commit_before>#include <gtest/gtest.h>

#include "Communicator.h"
#include "Message.h"
#include "Resource.h"
#include "GenericResource.h"
#include "CycException.h"

#include <string>
#include <vector>

using namespace std;

class TrackerMessage : public Message {
  public:
    TrackerMessage(Communicator* originator) : Message(originator) { }

    vector<string> dest_list_;
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class TestCommunicator : public Communicator {
  public:

    TestCommunicator(string name) {
      msg_ = new TrackerMessage(this);

      name_ = name;
      stop_at_return_ = true;
      flip_at_receive_ = false;
      flip_down_to_up_ = false;
      forget_set_dest_ = false;
      down_up_count_ = 0;
    }

    ~TestCommunicator() {
      delete msg_;
    }

    Communicator* parent_;
    TrackerMessage* msg_;

    string name_;
    bool stop_at_return_, flip_at_receive_, forget_set_dest_;
    bool flip_down_to_up_;
    int down_up_count_;

    void startMessage() {
      msg_->dest_list_.push_back(name_);
      msg_->setNextDest(parent_);
      msg_->sendOn();
    }

  private:

    void receiveMessage(msg_ptr msg) {
      boost::intrusive_ptr<TrackerMessage> ptr;
      ptr = boost::intrusive_ptr<TrackerMessage>(dynamic_cast<TrackerMessage*>(msg.get()));
      ptr->dest_list_.push_back(name_);
      if (stop_at_return_ && this == msg->sender()) {
        return;
      } else if (flip_at_receive_) {
        msg->setDir(DOWN_MSG);
      } else if (flip_down_to_up_) {
        int max_num_flips = 2;
        if (msg->dir() == DOWN_MSG && down_up_count_ < max_num_flips) {
          msg->setDir(UP_MSG);
          down_up_count_++;
        }
      }

      if ( !forget_set_dest_ ) {
        msg->setNextDest(parent_);
      }

      msg->sendOn();
    }
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class MessagePassingTest : public ::testing::Test {
  protected:
    TestCommunicator* comm1;
    TestCommunicator* comm2;
    TestCommunicator* comm3;
    TestCommunicator* comm4;

    virtual void SetUp(){
      comm1 = new TestCommunicator("comm1");
      comm2 = new TestCommunicator("comm2");
      comm3 = new TestCommunicator("comm3");
      comm4 = new TestCommunicator("comm4");

      comm1->parent_ = comm2;
      comm2->parent_ = comm3;
      comm3->parent_ = comm4;
      comm4->flip_at_receive_ = true;
    };

    virtual void TearDown() {
      delete comm1;
      delete comm2;
      delete comm3;
      delete comm4;
    }
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePassingTest, CleanThrough) {
  ASSERT_NO_THROW(comm1->startMessage());

  vector<string> stops = comm1->msg_->dest_list_;
  int num_stops = stops.size();
  int expected_num_stops = 7;

  ASSERT_EQ(num_stops, expected_num_stops);

  EXPECT_EQ(stops[0], "comm1");
  EXPECT_EQ(stops[1], "comm2");
  EXPECT_EQ(stops[2], "comm3");
  EXPECT_EQ(stops[3], "comm4");
  EXPECT_EQ(stops[4], "comm3");
  EXPECT_EQ(stops[5], "comm2");
  EXPECT_EQ(stops[6], "comm1");
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePassingTest, PassBeyondOrigin) {
  comm1->stop_at_return_ = false;

  ASSERT_THROW(comm1->startMessage(), CycException);

  vector<string> stops = comm1->msg_->dest_list_;
  int num_stops = stops.size();
  int expected_num_stops = 7;

  ASSERT_EQ(num_stops, expected_num_stops);

  EXPECT_EQ(stops[0], "comm1");
  EXPECT_EQ(stops[1], "comm2");
  EXPECT_EQ(stops[2], "comm3");
  EXPECT_EQ(stops[3], "comm4");
  EXPECT_EQ(stops[4], "comm3");
  EXPECT_EQ(stops[5], "comm2");
  EXPECT_EQ(stops[6], "comm1");
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePassingTest, ForgetToSetDest) {
  comm3->forget_set_dest_ = true;

  ASSERT_THROW(comm1->startMessage(), CycException);

  vector<string> stops = comm1->msg_->dest_list_;
  int num_stops = stops.size();
  int expected_num_stops = 3;

  ASSERT_EQ(num_stops, expected_num_stops);

  EXPECT_EQ(stops[0], "comm1");
  EXPECT_EQ(stops[1], "comm2");
  EXPECT_EQ(stops[2], "comm3");
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePassingTest, SendToSelf) {
  comm3->parent_ = comm3;

  ASSERT_THROW(comm1->startMessage(), CycException);

  vector<string> stops = comm1->msg_->dest_list_;
  int num_stops = stops.size();
  int expected_num_stops = 3;

  ASSERT_EQ(num_stops, expected_num_stops);

  EXPECT_EQ(stops[0], "comm1");
  EXPECT_EQ(stops[1], "comm2");
  EXPECT_EQ(stops[2], "comm3");
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePassingTest, YoYo) {
  comm2->flip_down_to_up_ = true;

  ASSERT_NO_THROW(comm1->startMessage());

  vector<string> stops = comm1->msg_->dest_list_;
  int num_stops = stops.size();
  int expected_num_stops = 15;

  ASSERT_EQ(num_stops, expected_num_stops);

  EXPECT_EQ(stops[0], "comm1");
  EXPECT_EQ(stops[1], "comm2");
  EXPECT_EQ(stops[2], "comm3");
  EXPECT_EQ(stops[3], "comm4");
  EXPECT_EQ(stops[4], "comm3");
  EXPECT_EQ(stops[5], "comm2");
  EXPECT_EQ(stops[6], "comm3");
  EXPECT_EQ(stops[7], "comm4");
  EXPECT_EQ(stops[8], "comm3");
  EXPECT_EQ(stops[9], "comm2");
  EXPECT_EQ(stops[10], "comm3");
  EXPECT_EQ(stops[11], "comm4");
  EXPECT_EQ(stops[12], "comm3");
  EXPECT_EQ(stops[13], "comm2");
  EXPECT_EQ(stops[14], "comm1");
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//- - - - - - - - -Message Public Interface Testing - - - - - - - - - - - -
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class MessagePublicInterfaceTest : public ::testing::Test {
  protected:

    Resource* resource;
    double quantity1, quantity2;

    TestCommunicator* comm1;
    msg_ptr msg1;

    virtual void SetUp(){
      quantity1 = 1.0;
      quantity2 = 2.0;
      resource = new GenericResource("kg", "bananas", quantity1);

      comm1 = new TestCommunicator("comm1");
      msg1 = msg_ptr(new Message(comm1));
    };

    virtual void TearDown() {
      delete comm1;
      delete resource;
    }
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//- - - - - - - - -Constructors and Cloning - - - - - - - - - - - - - - - -
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePublicInterfaceTest, DISABLED_ConstructorOne) {

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePublicInterfaceTest, DISABLED_ConstructorTwo) {

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePublicInterfaceTest, DISABLED_ConstructorThree) {

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePublicInterfaceTest, Cloning) {
  msg1->setResource(resource);
  msg_ptr msg2 = msg1->clone();

  // check proper cloning of message members
  EXPECT_EQ(msg1->sender(), msg2->sender());

  // check proper cloning of message's resource
  Resource* resource2 = msg2->resource();
  resource2->setQuantity(quantity2);

  ASSERT_DOUBLE_EQ(msg2->resource()->quantity(), quantity2);
  ASSERT_DOUBLE_EQ(msg2->resource()->quantity(), quantity2);
  ASSERT_NE(resource, msg1->resource());
  ASSERT_NE(resource, resource2);

  EXPECT_DOUBLE_EQ(resource->quantity(), quantity1);
  EXPECT_DOUBLE_EQ(resource2->quantity(), quantity2);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//- - - - - - - - - Getters and Setters - - - - - - - - - - - - - - - - - -
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

TEST_F(MessagePublicInterfaceTest, GetSetResource) {
  ASSERT_DOUBLE_EQ(resource->quantity(), quantity1);

  msg1->setResource(resource);

  ASSERT_NE(resource, msg1->resource());

  msg1->resource()->setQuantity(quantity2);

  ASSERT_DOUBLE_EQ(resource->quantity(), quantity1);
  ASSERT_DOUBLE_EQ(msg1->resource()->quantity(), quantity2);
}

<commit_msg>fixed Message tests to use the new intrusive pointer paradigm (closes #6).<commit_after>#include <gtest/gtest.h>

#include "Communicator.h"
#include "Message.h"
#include "Resource.h"
#include "GenericResource.h"
#include "CycException.h"

#include <string>
#include <vector>

using namespace std;

class TrackerMessage : public Message {
  public:
    TrackerMessage(Communicator* originator) : Message(originator) { }

    vector<string> dest_list_;
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class TestCommunicator : public Communicator {
  public:

    TestCommunicator(string name) {
      msg_ = msg_ptr(new TrackerMessage(this));

      name_ = name;
      stop_at_return_ = true;
      flip_at_receive_ = false;
      flip_down_to_up_ = false;
      forget_set_dest_ = false;
      down_up_count_ = 0;
    }

    ~TestCommunicator() { }

    Communicator* parent_;
    msg_ptr msg_;

    string name_;
    bool stop_at_return_, flip_at_receive_, forget_set_dest_;
    bool flip_down_to_up_;
    int down_up_count_;

    void startMessage() {
      dynamic_cast<TrackerMessage*>(msg_.get())->dest_list_.push_back(name_);
      msg_->setNextDest(parent_);
      msg_->sendOn();
    }

  private:

    void receiveMessage(msg_ptr msg) {
      boost::intrusive_ptr<TrackerMessage> ptr;
      ptr = boost::intrusive_ptr<TrackerMessage>(dynamic_cast<TrackerMessage*>(msg.get()));
      ptr->dest_list_.push_back(name_);
      if (stop_at_return_ && this == msg->sender()) {
        return;
      } else if (flip_at_receive_) {
        msg->setDir(DOWN_MSG);
      } else if (flip_down_to_up_) {
        int max_num_flips = 2;
        if (msg->dir() == DOWN_MSG && down_up_count_ < max_num_flips) {
          msg->setDir(UP_MSG);
          down_up_count_++;
        }
      }

      if ( !forget_set_dest_ ) {
        msg->setNextDest(parent_);
      }

      msg->sendOn();
    }
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class MessagePassingTest : public ::testing::Test {
  protected:
    TestCommunicator* comm1;
    TestCommunicator* comm2;
    TestCommunicator* comm3;
    TestCommunicator* comm4;

    virtual void SetUp(){
      comm1 = new TestCommunicator("comm1");
      comm2 = new TestCommunicator("comm2");
      comm3 = new TestCommunicator("comm3");
      comm4 = new TestCommunicator("comm4");

      comm1->parent_ = comm2;
      comm2->parent_ = comm3;
      comm3->parent_ = comm4;
      comm4->flip_at_receive_ = true;
    };

    virtual void TearDown() {
      delete comm1;
      delete comm2;
      delete comm3;
      delete comm4;
    }
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePassingTest, CleanThrough) {
  ASSERT_NO_THROW(comm1->startMessage());

  vector<string> stops = dynamic_cast<TrackerMessage*>(comm1->msg_.get())->dest_list_;
  int num_stops = stops.size();
  int expected_num_stops = 7;

  ASSERT_EQ(num_stops, expected_num_stops);

  EXPECT_EQ(stops[0], "comm1");
  EXPECT_EQ(stops[1], "comm2");
  EXPECT_EQ(stops[2], "comm3");
  EXPECT_EQ(stops[3], "comm4");
  EXPECT_EQ(stops[4], "comm3");
  EXPECT_EQ(stops[5], "comm2");
  EXPECT_EQ(stops[6], "comm1");
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePassingTest, PassBeyondOrigin) {
  comm1->stop_at_return_ = false;

  ASSERT_THROW(comm1->startMessage(), CycException);

  vector<string> stops = dynamic_cast<TrackerMessage*>(comm1->msg_.get())->dest_list_;
  int num_stops = stops.size();
  int expected_num_stops = 7;

  ASSERT_EQ(num_stops, expected_num_stops);

  EXPECT_EQ(stops[0], "comm1");
  EXPECT_EQ(stops[1], "comm2");
  EXPECT_EQ(stops[2], "comm3");
  EXPECT_EQ(stops[3], "comm4");
  EXPECT_EQ(stops[4], "comm3");
  EXPECT_EQ(stops[5], "comm2");
  EXPECT_EQ(stops[6], "comm1");
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePassingTest, ForgetToSetDest) {
  comm3->forget_set_dest_ = true;

  ASSERT_THROW(comm1->startMessage(), CycException);

  vector<string> stops = dynamic_cast<TrackerMessage*>(comm1->msg_.get())->dest_list_;
  int num_stops = stops.size();
  int expected_num_stops = 3;

  ASSERT_EQ(num_stops, expected_num_stops);

  EXPECT_EQ(stops[0], "comm1");
  EXPECT_EQ(stops[1], "comm2");
  EXPECT_EQ(stops[2], "comm3");
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePassingTest, SendToSelf) {
  comm3->parent_ = comm3;

  ASSERT_THROW(comm1->startMessage(), CycException);

  vector<string> stops = dynamic_cast<TrackerMessage*>(comm1->msg_.get())->dest_list_;
  int num_stops = stops.size();
  int expected_num_stops = 3;

  ASSERT_EQ(num_stops, expected_num_stops);

  EXPECT_EQ(stops[0], "comm1");
  EXPECT_EQ(stops[1], "comm2");
  EXPECT_EQ(stops[2], "comm3");
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePassingTest, YoYo) {
  comm2->flip_down_to_up_ = true;

  ASSERT_NO_THROW(comm1->startMessage());

  vector<string> stops = dynamic_cast<TrackerMessage*>(comm1->msg_.get())->dest_list_;
  int num_stops = stops.size();
  int expected_num_stops = 15;

  ASSERT_EQ(num_stops, expected_num_stops);

  EXPECT_EQ(stops[0], "comm1");
  EXPECT_EQ(stops[1], "comm2");
  EXPECT_EQ(stops[2], "comm3");
  EXPECT_EQ(stops[3], "comm4");
  EXPECT_EQ(stops[4], "comm3");
  EXPECT_EQ(stops[5], "comm2");
  EXPECT_EQ(stops[6], "comm3");
  EXPECT_EQ(stops[7], "comm4");
  EXPECT_EQ(stops[8], "comm3");
  EXPECT_EQ(stops[9], "comm2");
  EXPECT_EQ(stops[10], "comm3");
  EXPECT_EQ(stops[11], "comm4");
  EXPECT_EQ(stops[12], "comm3");
  EXPECT_EQ(stops[13], "comm2");
  EXPECT_EQ(stops[14], "comm1");
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//- - - - - - - - -Message Public Interface Testing - - - - - - - - - - - -
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class MessagePublicInterfaceTest : public ::testing::Test {
  protected:

    Resource* resource;
    double quantity1, quantity2;

    TestCommunicator* comm1;
    msg_ptr msg1;

    virtual void SetUp(){
      quantity1 = 1.0;
      quantity2 = 2.0;
      resource = new GenericResource("kg", "bananas", quantity1);

      comm1 = new TestCommunicator("comm1");
      msg1 = msg_ptr(new Message(comm1));
    };

    virtual void TearDown() {
      delete comm1;
      delete resource;
    }
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//- - - - - - - - -Constructors and Cloning - - - - - - - - - - - - - - - -
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePublicInterfaceTest, DISABLED_ConstructorOne) {

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePublicInterfaceTest, DISABLED_ConstructorTwo) {

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePublicInterfaceTest, DISABLED_ConstructorThree) {

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TEST_F(MessagePublicInterfaceTest, Cloning) {
  msg1->setResource(resource);
  msg_ptr msg2 = msg1->clone();

  // check proper cloning of message members
  EXPECT_EQ(msg1->sender(), msg2->sender());

  // check proper cloning of message's resource
  Resource* resource2 = msg2->resource();
  resource2->setQuantity(quantity2);

  ASSERT_DOUBLE_EQ(msg2->resource()->quantity(), quantity2);
  ASSERT_DOUBLE_EQ(msg2->resource()->quantity(), quantity2);
  ASSERT_NE(resource, msg1->resource());
  ASSERT_NE(resource, resource2);

  EXPECT_DOUBLE_EQ(resource->quantity(), quantity1);
  EXPECT_DOUBLE_EQ(resource2->quantity(), quantity2);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//- - - - - - - - - Getters and Setters - - - - - - - - - - - - - - - - - -
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

TEST_F(MessagePublicInterfaceTest, GetSetResource) {
  ASSERT_DOUBLE_EQ(resource->quantity(), quantity1);

  msg1->setResource(resource);

  ASSERT_NE(resource, msg1->resource());

  msg1->resource()->setQuantity(quantity2);

  ASSERT_DOUBLE_EQ(resource->quantity(), quantity1);
  ASSERT_DOUBLE_EQ(msg1->resource()->quantity(), quantity2);
}

<|endoftext|>


<commit_before>#include "BetaRand.h"
#include "../discrete/BernoulliRand.h"

BetaRand::BetaRand(double shape1, double shape2)
{
    setParameters(shape1, shape2);
}

std::string BetaRand::name()
{
    return "Beta(" + toStringWithPrecision(getAlpha()) + ", " + toStringWithPrecision(getBeta()) + ")";
}

void BetaRand::setParameters(double shape1, double shape2)
{
    alpha = shape1;
    if (alpha <= 0)
        alpha = 1.0;
    X.setParameters(alpha, 1);

    beta = shape2;
    if (beta <= 0)
        beta = 1.0;
    Y.setParameters(beta, 1);

    if (alpha + beta > 30)
    {
        /// we use log(Gamma(x)) in order to avoid too big numbers
        double logGammaX = std::log(X.getInverseGammaFunction());
        double logGammaY = std::log(Y.getInverseGammaFunction());
        pdfCoef = std::lgamma(alpha + beta) + logGammaX + logGammaY;
        pdfCoef = std::exp(pdfCoef);
    }
    else {
        pdfCoef = std::tgamma(alpha + beta) * X.getInverseGammaFunction() * Y.getInverseGammaFunction();
    }
    setVariateConstants();
}

void BetaRand::setAlpha(double shape1)
{
    alpha = shape1;
    if (alpha <= 0)
        alpha = 1.0;
    X.setParameters(alpha, 1);
    pdfCoef = std::tgamma(alpha + Y.getShape()) * X.getInverseGammaFunction() * Y.getInverseGammaFunction();
    setVariateConstants();
}

void BetaRand::setBeta(double shape2)
{
    beta = shape2;
    if (beta <= 0)
        beta = 1.0;
    Y.setParameters(beta, 1);
    pdfCoef = std::tgamma(X.getShape() + beta) * X.getInverseGammaFunction() * Y.getInverseGammaFunction();
    setVariateConstants();
}

double BetaRand::f(double x) const
{
    if (x < 0 || x > 1)
        return 0;
    if (RandMath::areEqual(alpha, beta))
        return pdfCoef * std::pow(x - x * x, alpha - 1);
    double rv = std::pow(x, alpha - 1);
    rv *= std::pow(1 - x, beta - 1);
    return pdfCoef * rv;
}

double BetaRand::F(double x) const
{
    if (x <= 0)
        return 0;
    if (x >= 1)
        return 1;
    return pdfCoef * RandMath::incompleteBetaFun(x, alpha, beta);
}

double BetaRand::variateArcsine() const
{
    double x = std::sin(UniformRand::variate(-M_PI, M_PI));
    return x * x;
}

double BetaRand::variateForSmallEqualParameters() const
{
    int iter = 0;
    do {
        double u1 = UniformRand::standardVariate();
        double u2 = UniformRand::standardVariate();
        if (u2 <= std::pow(4 * u1 * (1 - u1), alpha - 1))
            return u1;
    } while (++iter <= 1e9); /// one billion should be enough
    return NAN; /// fail
}

double BetaRand::variateForLargeEqualParameters() const
{
    int iter = 0;
    do {
        double n = N.variate();
        if (n < 0 || n > 1)
            continue;
        double u = UniformRand::standardVariate();
        if (u < N.f(n) / (variateCoef * f(n)))
            return n;
    } while (++iter <= 1e9); /// one billion should be enough
    return NAN; /// fail
}

double BetaRand::variateForDifferentParameters() const
{
    double x = X.variate();
    return x / (x + Y.variate());
}

void BetaRand::setVariateConstants()
{
    /// We need to storage variate coefficient only if alpha = beta and large enough
    if (alpha > edgeForGenerators && RandMath::areEqual(alpha, beta))
    {
        double t = 1.0 / (alpha + alpha + 1);
        variateCoef = M_E * std::sqrt(0.5 * M_PI * M_E * t);
        variateCoef *= std::pow(0.25 - 0.75 * t, alpha - 1);
        variateCoef *= pdfCoef; /// /= Beta(alpha, alpha)

        N.setMean(0.5);
        N.setVariance(0.25 * t);
    }
}

double BetaRand::variate() const
{
    if (RandMath::areEqual(alpha, beta) && alpha == 0.5)
        return variateArcsine();
    if (!RandMath::areEqual(alpha, beta) || alpha < 1)
        return variateForDifferentParameters();
    if (alpha == 1)
        return UniformRand::standardVariate();
    if (alpha <= edgeForGenerators)
        return variateForSmallEqualParameters();
    return variateForLargeEqualParameters();
}

void BetaRand::sample(QVector<double> &outputData) const
{
    if (RandMath::areEqual(alpha, beta) && alpha == 0.5) {
        for (double &var : outputData)
            var = variateArcsine();
    }
    else if (!RandMath::areEqual(alpha, beta) || alpha < 1) {
        for (double &var : outputData)
            var = variateForDifferentParameters();
    }
    else if (alpha == 1) {
        for (double &var : outputData)
            var = UniformRand::standardVariate();
    }
    else if (alpha <= edgeForGenerators) {
        for (double &var : outputData)
            var = variateForSmallEqualParameters();
    }
    else {
        for (double &var : outputData)
            var = variateForLargeEqualParameters();
    }
}

double BetaRand::Mean() const
{
    return alpha / (alpha + beta);
}

double BetaRand::Variance() const
{
    double denominator = alpha + beta;
    denominator *= denominator * (denominator + 1);
    return alpha * beta / denominator;
}

double BetaRand::Quantile(double p) const
{
    if (p < 0 || p > 1)
        return NAN;
    double root = p;
    if (RandMath::findRoot([this, p] (double x)
    {
        return BetaRand::F(x) - p;
    },
    0, 1, root))
        return root;
    return NAN;
}

double BetaRand::Median() const
{
    if (RandMath::areEqual(alpha, beta))
        return 0.5;
    return Quantile(0.5);
}

double BetaRand::Mode() const
{
    if (alpha > 1)
    {
        if (beta > 1)
            return (alpha - 1) / (alpha + beta - 2);
        return 1.0;
    }
    if (beta > 1)
        return 0.0;
    return BernoulliRand::standardVariate();
}

double BetaRand::Skewness() const
{
    double skewness = (alpha + beta + 1) / (alpha * beta);
    skewness = std::sqrt(skewness);
    skewness *= (alpha - beta);
    skewness /= (alpha + beta + 2);
    return skewness + skewness;
}

double BetaRand::ExcessKurtosis() const
{
    double sum = alpha + beta;
    double kurtosis = alpha - beta;
    kurtosis *= kurtosis;
    kurtosis *= (sum + 1);
    kurtosis /= (alpha * beta * (sum + 2));
    --kurtosis;
    kurtosis /= (sum + 3);
    return 6 * kurtosis;
}

BaldingNicholsRand::BaldingNicholsRand(double fixatingIndex, double frequency)
{
    setParameters(fixatingIndex, frequency);
}

std::string BaldingNicholsRand::name()
{
    return "Balding-Nichols(" + toStringWithPrecision(getFixatingIndex()) + ", " + toStringWithPrecision(getFrequency()) + ")";
}

void BaldingNicholsRand::setParameters(double fixatingIndex, double frequency)
{
    F = fixatingIndex;
    if (F <= 0 || F >= 1)
        F = 0.5;

    p = frequency;
    if (p <= 0 || p >= 1)
        p = 0.5;

    double frac = (1.0 - F) / F;
    BetaRand::setParameters(frac * p, frac * (1 - p));
}
<commit_msg>Update BetaRand.cpp<commit_after>#include "BetaRand.h"
#include "../discrete/BernoulliRand.h"

BetaRand::BetaRand(double shape1, double shape2)
{
    setParameters(shape1, shape2);
}

std::string BetaRand::name()
{
    return "Beta(" + toStringWithPrecision(getAlpha()) + ", " + toStringWithPrecision(getBeta()) + ")";
}

void BetaRand::setParameters(double shape1, double shape2)
{
    alpha = shape1;
    if (alpha <= 0)
        alpha = 1.0;
    X.setParameters(alpha, 1);

    beta = shape2;
    if (beta <= 0)
        beta = 1.0;
    Y.setParameters(beta, 1);

    if (alpha + beta > 30)
    {
        /// we use log(Gamma(x)) in order to avoid too big numbers
        double logGammaX = std::log(X.getInverseGammaFunction());
        double logGammaY = std::log(Y.getInverseGammaFunction());
        pdfCoef = std::lgamma(alpha + beta) + logGammaX + logGammaY;
        pdfCoef = std::exp(pdfCoef);
    }
    else {
        pdfCoef = std::tgamma(alpha + beta) * X.getInverseGammaFunction() * Y.getInverseGammaFunction();
    }
    setVariateConstants();
}

void BetaRand::setAlpha(double shape1)
{
    alpha = shape1;
    if (alpha <= 0)
        alpha = 1.0;
    X.setParameters(alpha, 1);
    pdfCoef = std::tgamma(alpha + Y.getShape()) * X.getInverseGammaFunction() * Y.getInverseGammaFunction();
    setVariateConstants();
}

void BetaRand::setBeta(double shape2)
{
    beta = shape2;
    if (beta <= 0)
        beta = 1.0;
    Y.setParameters(beta, 1);
    pdfCoef = std::tgamma(X.getShape() + beta) * X.getInverseGammaFunction() * Y.getInverseGammaFunction();
    setVariateConstants();
}

double BetaRand::f(double x) const
{
    if (x < 0 || x > 1)
        return 0;
    if (RandMath::areEqual(alpha, beta))
        return pdfCoef * std::pow(x - x * x, alpha - 1);
    double rv = std::pow(x, alpha - 1);
    rv *= std::pow(1 - x, beta - 1);
    return pdfCoef * rv;
}

double BetaRand::F(double x) const
{
    if (x <= 0)
        return 0;
    if (x >= 1)
        return 1;
    return pdfCoef * RandMath::incompleteBetaFun(x, alpha, beta);
}

double BetaRand::variateArcsine() const
{
    double x = std::sin(UniformRand::variate(-M_PI, M_PI));
    return x * x;
}

double BetaRand::variateForSmallEqualParameters() const
{
    int iter = 0;
    do {
        double u1 = UniformRand::standardVariate();
        double u2 = UniformRand::standardVariate();
        if (u2 <= std::pow(4 * u1 * (1 - u1), alpha - 1))
            return u1;
    } while (++iter <= 1e9); /// one billion should be enough
    return NAN; /// fail
}

double BetaRand::variateForLargeEqualParameters() const
{
    int iter = 0;
    do {
        double n = N.variate();
        if (n < 0 || n > 1)
            continue;
        double u = UniformRand::standardVariate();
        if (u < N.f(n) / (variateCoef * f(n)))
            return n;
    } while (++iter <= 1e9); /// one billion should be enough
    return NAN; /// fail
}

double BetaRand::variateForDifferentParameters() const
{
    double x = X.variate();
    return x / (x + Y.variate());
}

void BetaRand::setVariateConstants()
{
    /// We need to storage variate coefficient only if alpha = beta and large enough
    if (alpha > edgeForGenerators && RandMath::areEqual(alpha, beta))
    {
        double t = 1.0 / (alpha + alpha + 1);
        variateCoef = M_E * std::sqrt(0.5 * M_PI * M_E * t);
        variateCoef *= std::pow(0.25 - 0.75 * t, alpha - 1);
        variateCoef *= pdfCoef; /// /= Beta(alpha, alpha)

        N.setMean(0.5);
        N.setVariance(0.25 * t);
    }
}

double BetaRand::variate() const
{
    if (RandMath::areEqual(alpha, beta) && alpha == 0.5)
        return variateArcsine();
    if (!RandMath::areEqual(alpha, beta) || alpha < 1)
        return variateForDifferentParameters();
    if (alpha == 1)
        return UniformRand::standardVariate();
    if (alpha <= edgeForGenerators)
        return variateForSmallEqualParameters();
    return variateForLargeEqualParameters();
}

void BetaRand::sample(QVector<double> &outputData) const
{
    if (RandMath::areEqual(alpha, beta) && alpha == 0.5) {
        for (double &var : outputData)
            var = variateArcsine();
    }
    else if (!RandMath::areEqual(alpha, beta) || alpha < 1) {
        for (double &var : outputData)
            var = variateForDifferentParameters();
    }
    else if (alpha == 1) {
        for (double &var : outputData)
            var = UniformRand::standardVariate();
    }
    else if (alpha <= edgeForGenerators) {
        for (double &var : outputData)
            var = variateForSmallEqualParameters();
    }
    else {
        for (double &var : outputData)
            var = variateForLargeEqualParameters();
    }
}

double BetaRand::Mean() const
{
    return alpha / (alpha + beta);
}

double BetaRand::Variance() const
{
    double denominator = alpha + beta;
    denominator *= denominator * (denominator + 1);
    return alpha * beta / denominator;
}

double BetaRand::Quantile(double p) const
{
    if (p < 0 || p > 1)
        return NAN;
    double root = p;
    if (RandMath::findRoot([this, p] (double x)
    {
        return BetaRand::F(x) - p;
    },
    0, 1, root))
        return root;
    return NAN;
}

double BetaRand::Median() const
{
    if (RandMath::areEqual(alpha, beta))
        return 0.5;
    return Quantile(0.5);
}

double BetaRand::Mode() const
{
    if (alpha > 1)
    {
        if (beta > 1)
            return (alpha - 1) / (alpha + beta - 2);
        return 1.0;
    }
    if (beta > 1)
        return 0.0;
    return BernoulliRand::standardVariate();
}

double BetaRand::Skewness() const
{
    double skewness = (alpha + beta + 1) / (alpha * beta);
    skewness = std::sqrt(skewness);
    skewness *= (alpha - beta);
    skewness /= (alpha + beta + 2);
    return skewness + skewness;
}

double BetaRand::ExcessKurtosis() const
{
    double sum = alpha + beta;
    double kurtosis = alpha - beta;
    kurtosis *= kurtosis;
    kurtosis *= (sum + 1);
    kurtosis /= (alpha * beta * (sum + 2));
    --kurtosis;
    kurtosis /= (sum + 3);
    return 6 * kurtosis;
}

BaldingNicholsRand::BaldingNicholsRand(double fixatingIndex, double frequency)
{
    setParameters(fixatingIndex, frequency);
}

std::string BaldingNicholsRand::name()
{
    return "Balding-Nichols(" + toStringWithPrecision(getFixatingIndex()) + ", " + toStringWithPrecision(getFrequency()) + ")";
}

void BaldingNicholsRand::setParameters(double fixatingIndex, double frequency)
{
    F = fixatingIndex;
    if (F <= 0 || F >= 1)
        F = 0.5;

    p = frequency;
    if (p <= 0 || p >= 1)
        p = 0.5;

    double frac = (1.0 - F) / F, fracP = frac * p;
    BetaRand::setParameters(fracP, frac - fracP);
}
<|endoftext|>


<commit_before>#include "ffmpeg_video_target.h"
#include "except.h"

#ifdef GENERATE_PERFORMANCE_OUTPUT
#include <boost/timer/timer.hpp>
#endif

namespace gg
{

VideoTargetFFmpeg::VideoTargetFFmpeg(const std::string codec) :
    _codec(NULL),
    _codec_name(""),
    _frame(NULL),
    _framerate(-1),
    _sws_context(NULL),
    _format_context(NULL),
    _stream(NULL),
    _frame_index(0)
{
    if (codec != "H265")
    {
        std::string msg;
        msg.append("Codec ")
           .append(codec)
           .append(" not recognised");
        throw VideoTargetError(msg);
    }
#ifdef FFMPEG_HWACCEL
    _codec_name = "nvenc_hevc";
#else
    _codec_name = "libx265";
#endif

    av_register_all();
}

void VideoTargetFFmpeg::init(const std::string filepath, const float framerate)
{
    if (framerate <= 0)
        throw VideoTargetError("Negative fps does not make sense");
    if (framerate - (int) framerate > 0)
        throw VideoTargetError("Only integer framerates are supported");
    _framerate = (int) framerate;

    check_filetype_support(filepath, "mp4");

    _filepath = filepath;

    /* allocate the output media context */
    avformat_alloc_output_context2(&_format_context, NULL, NULL, _filepath.c_str());
    if (_format_context == NULL)
        // Use MP4 as default if context cannot be deduced from file extension
        avformat_alloc_output_context2(&_format_context, NULL, "mp4", NULL);
    if (_format_context == NULL)
        throw VideoTargetError("Could not allocate output media context");

    _codec = avcodec_find_encoder_by_name(_codec_name.c_str());
    if (not _codec)
        throw VideoTargetError("Codec not found");

    _stream = avformat_new_stream(_format_context, _codec);
    if (_stream == NULL)
        throw VideoTargetError("Could not allocate stream");
    _stream->id = _format_context->nb_streams-1; // TODO isn't this wrong?
}

void VideoTargetFFmpeg::append(const VideoFrame_BGRA & frame)
{
    if (_framerate <= 0)
        throw VideoTargetError("Video target not initialised");

    // return value buffers
    int ret, got_output;

    // if first frame, initialise
    if (_frame == NULL)
    {
#ifdef GENERATE_PERFORMANCE_OUTPUT
#ifndef timer_format_str
#define timer_format_str \
        std::string(", %w, %u, %s, %t, %p" \
                    ", wall (s), user (s), system (s), user+system (s), CPU (\%)\n")
#endif
#ifndef this_class_str
#define this_class_str std::string("VideoTargetFFmpeg-")
#endif
        boost::timer::auto_cpu_timer t(this_class_str + "first-frame" + timer_format_str);
#endif
        // TODO - is _codec_context ever being modified after first frame?
        /* TODO: using default reduces filesize
         * but should we set it nonetheless?
         */
//        _stream->codec->bit_rate = 400000;
        _stream->codec->width = frame.cols();
        _stream->codec->height = frame.rows();
        _stream->time_base = (AVRational){ 1, _framerate };
        _stream->codec->time_base = _stream->time_base;
        _stream->codec->gop_size = 12;
        /* TODO emit one intra frame every twelve frames at most */
        _stream->codec->pix_fmt = AV_PIX_FMT_YUV420P;
        /* Some formats want stream headers to be separate. */
        if (_format_context->oformat->flags & AVFMT_GLOBALHEADER)
            _stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

        switch (_stream->codec->codec_id)
        {
        case AV_CODEC_ID_H264:
        case AV_CODEC_ID_HEVC:
#ifdef FFMPEG_HWACCEL
            // nop
            ret = 0;
#else
            /* TODO will this work in real-time with a framegrabber ?
             * "slow" produces 2x larger file compared to "ultrafast",
             * but with a substantial visual quality degradation
             * (judged using the coloured chessboard pattern)
             * "fast" is a trade-off: visual quality looks similar
             * while file size is reasonable
             */
            ret = av_opt_set(_stream->codec->priv_data, "preset", "fast", 0);
#endif
            if (ret != 0)
                throw VideoTargetError("Could not set codec-specific options");

            /* Resolution must be a multiple of two, as required
             * by H264 and H265. Introduce a one-pixel padding for
             * non-complying dimension(s).
             */
            _stream->codec->width +=
                    _stream->codec->width % 2 == 0 ? 0 : 1;
            _stream->codec->height +=
                    _stream->codec->height % 2 == 0 ? 0 : 1;
            break;
        default:
            // nop
            break;
        }

        /* open it */
        if (avcodec_open2(_stream->codec, _codec, NULL) < 0)
            throw VideoTargetError("Could not open codec");

        _frame = av_frame_alloc();
        if (not _frame)
            throw VideoTargetError("Could not allocate video frame");
        _frame->format = _stream->codec->pix_fmt;
        _frame->width  = _stream->codec->width;
        _frame->height = _stream->codec->height;
        /* allocate the buffers for the frame data */
        // TODO #25 what influence does 32 have on performance?
        ret = av_frame_get_buffer(_frame, 32);
        if (ret < 0)
            throw VideoTargetError("Could not allocate frame data");

        /* Now that all the parameters are set, we can open the audio and
         * video codecs and allocate the necessary encode buffers. */
        av_dump_format(_format_context, 0, _filepath.c_str(), 1);
        /* open the output file, if needed */
        if (!(_format_context->oformat->flags & AVFMT_NOFILE))
        {
            ret = avio_open(&_format_context->pb, _filepath.c_str(), AVIO_FLAG_WRITE);
            if (ret < 0)
            {
                std::string msg;
                msg.append("File ")
                   .append(_filepath)
                   .append(" could not be opened");
                throw VideoTargetError(msg);
            }
        }

        /* Write the stream header, if any. */
        ret = avformat_write_header(_format_context, NULL);
        if (ret < 0)
            throw VideoTargetError("Could not write header to file");

        /* Open context for converting BGRA pixels to YUV420p */
        _sws_context = sws_getContext(
                    frame.cols(), frame.rows(), AV_PIX_FMT_BGRA,
                    frame.cols(), frame.rows(), _stream->codec->pix_fmt,
                    0, NULL, NULL, NULL);
        if (_sws_context == NULL)
            throw VideoTargetError("Could not allocate Sws context");

        // To be incremented for each frame, used as pts
        _frame_index = 0;

        // Packet to be used when writing frames
        av_init_packet(&_packet);
        // TODO #25 data gets allocated each time?
        _packet.data = NULL;    // packet data will be allocated by the encoder
        _packet.size = 0;

        _bgra_stride[0] = 4*frame.cols();
    }

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "1-av_frame_make_writable" + timer_format_str);
#endif

    /* when we pass a frame to the encoder, it may keep a reference to it
     * internally;
     * make sure we do not overwrite it here
     */
    // TODO #25 why not only once?
    ret = av_frame_make_writable(_frame);
    if (ret < 0)
        throw VideoTargetError("Could not make frame writeable");

    } // END auto_cpu_timer scope

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "1-sws_scale" + timer_format_str);
#endif

    /* convert pixel format */
    _src_data_ptr[0] = frame.data();
    sws_scale(_sws_context,
              _src_data_ptr, _bgra_stride, // BGRA has one plane
              0, frame.rows(),
              _frame->data, _frame->linesize
              );

    _frame->pts = _frame_index++;

    } // END auto_cpu_timer scope

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "1-encode_and_write" + timer_format_str);
#endif

    /* encode the image */
    encode_and_write(_frame, got_output);

    } // END auto_cpu_timer scope
}

void VideoTargetFFmpeg::encode_and_write(AVFrame * frame, int & got_output)
{
    int ret;

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "2-avcodec_encode_video2" + timer_format_str);
#endif
    ret = avcodec_encode_video2(_stream->codec, &_packet, frame, &got_output);
    } // END auto_cpu_timer scope

    if (ret < 0)
        throw VideoTargetError("Error encoding frame");

    if (got_output)
    {
        { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
        boost::timer::auto_cpu_timer t(this_class_str + "2-av_packet_rescale_ts" + timer_format_str);
#endif
        /* rescale output packet timestamp values from codec to stream timebase */
        av_packet_rescale_ts(&_packet, _stream->codec->time_base, _stream->time_base);
        // TODO - above time bases are the same, or not?
        _packet.stream_index = _stream->index;
        } // END auto_cpu_timer scope

        { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
        boost::timer::auto_cpu_timer t(this_class_str + "2-av_interleaved_write_frame" + timer_format_str);
#endif
        /* Write the compressed frame to the media file. */
        int ret = av_interleaved_write_frame(_format_context, &_packet);
        }

        if (ret < 0)
            throw VideoTargetError("Could not interleaved write frame");
//        av_packet_unref(&packet); taken care of by av_interleaved_write_frame
    }
}

void VideoTargetFFmpeg::finalise()
{
    /* get the delayed frames */
    for (int got_output = 1; got_output; )
        encode_and_write(NULL, got_output);

    /* Write the trailer, if any. The trailer must be written before you
     * close the CodecContexts open when you wrote the header; otherwise
     * av_write_trailer() may try to use memory that was freed on
     * av_codec_close(). */
    av_write_trailer(_format_context);

    if (_stream->codec) avcodec_close(_stream->codec);
    if (_frame) av_frame_free(&_frame);
//  av_freep(&_frame->data[0]); no need for this because _frame never manages its own data
    if (_sws_context) sws_freeContext(_sws_context);

    if (!(_format_context->oformat->flags & AVFMT_NOFILE))
        /* Close the output file. */
        avio_closep(&_format_context->pb);
    /* free the stream */
    avformat_free_context(_format_context);

    // default values, for next init
    _codec = NULL;
    _frame = NULL;
    _framerate = -1;
    _sws_context = NULL;
    _format_context = NULL;
    _stream = NULL;
    _frame_index = 0;
}

}
<commit_msg>Issue #36: when finalising FFmpeg target, checking whether append has been called at least once<commit_after>#include "ffmpeg_video_target.h"
#include "except.h"

#ifdef GENERATE_PERFORMANCE_OUTPUT
#include <boost/timer/timer.hpp>
#endif

namespace gg
{

VideoTargetFFmpeg::VideoTargetFFmpeg(const std::string codec) :
    _codec(NULL),
    _codec_name(""),
    _frame(NULL),
    _framerate(-1),
    _sws_context(NULL),
    _format_context(NULL),
    _stream(NULL),
    _frame_index(0)
{
    if (codec != "H265")
    {
        std::string msg;
        msg.append("Codec ")
           .append(codec)
           .append(" not recognised");
        throw VideoTargetError(msg);
    }
#ifdef FFMPEG_HWACCEL
    _codec_name = "nvenc_hevc";
#else
    _codec_name = "libx265";
#endif

    av_register_all();
}

void VideoTargetFFmpeg::init(const std::string filepath, const float framerate)
{
    if (framerate <= 0)
        throw VideoTargetError("Negative fps does not make sense");
    if (framerate - (int) framerate > 0)
        throw VideoTargetError("Only integer framerates are supported");
    _framerate = (int) framerate;

    check_filetype_support(filepath, "mp4");

    _filepath = filepath;

    /* allocate the output media context */
    avformat_alloc_output_context2(&_format_context, NULL, NULL, _filepath.c_str());
    if (_format_context == NULL)
        // Use MP4 as default if context cannot be deduced from file extension
        avformat_alloc_output_context2(&_format_context, NULL, "mp4", NULL);
    if (_format_context == NULL)
        throw VideoTargetError("Could not allocate output media context");

    _codec = avcodec_find_encoder_by_name(_codec_name.c_str());
    if (not _codec)
        throw VideoTargetError("Codec not found");

    _stream = avformat_new_stream(_format_context, _codec);
    if (_stream == NULL)
        throw VideoTargetError("Could not allocate stream");
    _stream->id = _format_context->nb_streams-1; // TODO isn't this wrong?
}

void VideoTargetFFmpeg::append(const VideoFrame_BGRA & frame)
{
    if (_framerate <= 0)
        throw VideoTargetError("Video target not initialised");

    // return value buffers
    int ret, got_output;

    // if first frame, initialise
    if (_frame == NULL)
    {
#ifdef GENERATE_PERFORMANCE_OUTPUT
#ifndef timer_format_str
#define timer_format_str \
        std::string(", %w, %u, %s, %t, %p" \
                    ", wall (s), user (s), system (s), user+system (s), CPU (\%)\n")
#endif
#ifndef this_class_str
#define this_class_str std::string("VideoTargetFFmpeg-")
#endif
        boost::timer::auto_cpu_timer t(this_class_str + "first-frame" + timer_format_str);
#endif
        // TODO - is _codec_context ever being modified after first frame?
        /* TODO: using default reduces filesize
         * but should we set it nonetheless?
         */
//        _stream->codec->bit_rate = 400000;
        _stream->codec->width = frame.cols();
        _stream->codec->height = frame.rows();
        _stream->time_base = (AVRational){ 1, _framerate };
        _stream->codec->time_base = _stream->time_base;
        _stream->codec->gop_size = 12;
        /* TODO emit one intra frame every twelve frames at most */
        _stream->codec->pix_fmt = AV_PIX_FMT_YUV420P;
        /* Some formats want stream headers to be separate. */
        if (_format_context->oformat->flags & AVFMT_GLOBALHEADER)
            _stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

        switch (_stream->codec->codec_id)
        {
        case AV_CODEC_ID_H264:
        case AV_CODEC_ID_HEVC:
#ifdef FFMPEG_HWACCEL
            // nop
            ret = 0;
#else
            /* TODO will this work in real-time with a framegrabber ?
             * "slow" produces 2x larger file compared to "ultrafast",
             * but with a substantial visual quality degradation
             * (judged using the coloured chessboard pattern)
             * "fast" is a trade-off: visual quality looks similar
             * while file size is reasonable
             */
            ret = av_opt_set(_stream->codec->priv_data, "preset", "fast", 0);
#endif
            if (ret != 0)
                throw VideoTargetError("Could not set codec-specific options");

            /* Resolution must be a multiple of two, as required
             * by H264 and H265. Introduce a one-pixel padding for
             * non-complying dimension(s).
             */
            _stream->codec->width +=
                    _stream->codec->width % 2 == 0 ? 0 : 1;
            _stream->codec->height +=
                    _stream->codec->height % 2 == 0 ? 0 : 1;
            break;
        default:
            // nop
            break;
        }

        /* open it */
        if (avcodec_open2(_stream->codec, _codec, NULL) < 0)
            throw VideoTargetError("Could not open codec");

        _frame = av_frame_alloc();
        if (not _frame)
            throw VideoTargetError("Could not allocate video frame");
        _frame->format = _stream->codec->pix_fmt;
        _frame->width  = _stream->codec->width;
        _frame->height = _stream->codec->height;
        /* allocate the buffers for the frame data */
        // TODO #25 what influence does 32 have on performance?
        ret = av_frame_get_buffer(_frame, 32);
        if (ret < 0)
            throw VideoTargetError("Could not allocate frame data");

        /* Now that all the parameters are set, we can open the audio and
         * video codecs and allocate the necessary encode buffers. */
        av_dump_format(_format_context, 0, _filepath.c_str(), 1);
        /* open the output file, if needed */
        if (!(_format_context->oformat->flags & AVFMT_NOFILE))
        {
            ret = avio_open(&_format_context->pb, _filepath.c_str(), AVIO_FLAG_WRITE);
            if (ret < 0)
            {
                std::string msg;
                msg.append("File ")
                   .append(_filepath)
                   .append(" could not be opened");
                throw VideoTargetError(msg);
            }
        }

        /* Write the stream header, if any. */
        ret = avformat_write_header(_format_context, NULL);
        if (ret < 0)
            throw VideoTargetError("Could not write header to file");

        /* Open context for converting BGRA pixels to YUV420p */
        _sws_context = sws_getContext(
                    frame.cols(), frame.rows(), AV_PIX_FMT_BGRA,
                    frame.cols(), frame.rows(), _stream->codec->pix_fmt,
                    0, NULL, NULL, NULL);
        if (_sws_context == NULL)
            throw VideoTargetError("Could not allocate Sws context");

        // To be incremented for each frame, used as pts
        _frame_index = 0;

        // Packet to be used when writing frames
        av_init_packet(&_packet);
        // TODO #25 data gets allocated each time?
        _packet.data = NULL;    // packet data will be allocated by the encoder
        _packet.size = 0;

        _bgra_stride[0] = 4*frame.cols();
    }

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "1-av_frame_make_writable" + timer_format_str);
#endif

    /* when we pass a frame to the encoder, it may keep a reference to it
     * internally;
     * make sure we do not overwrite it here
     */
    // TODO #25 why not only once?
    ret = av_frame_make_writable(_frame);
    if (ret < 0)
        throw VideoTargetError("Could not make frame writeable");

    } // END auto_cpu_timer scope

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "1-sws_scale" + timer_format_str);
#endif

    /* convert pixel format */
    _src_data_ptr[0] = frame.data();
    sws_scale(_sws_context,
              _src_data_ptr, _bgra_stride, // BGRA has one plane
              0, frame.rows(),
              _frame->data, _frame->linesize
              );

    _frame->pts = _frame_index++;

    } // END auto_cpu_timer scope

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "1-encode_and_write" + timer_format_str);
#endif

    /* encode the image */
    encode_and_write(_frame, got_output);

    } // END auto_cpu_timer scope
}

void VideoTargetFFmpeg::encode_and_write(AVFrame * frame, int & got_output)
{
    int ret;

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "2-avcodec_encode_video2" + timer_format_str);
#endif
    ret = avcodec_encode_video2(_stream->codec, &_packet, frame, &got_output);
    } // END auto_cpu_timer scope

    if (ret < 0)
        throw VideoTargetError("Error encoding frame");

    if (got_output)
    {
        { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
        boost::timer::auto_cpu_timer t(this_class_str + "2-av_packet_rescale_ts" + timer_format_str);
#endif
        /* rescale output packet timestamp values from codec to stream timebase */
        av_packet_rescale_ts(&_packet, _stream->codec->time_base, _stream->time_base);
        // TODO - above time bases are the same, or not?
        _packet.stream_index = _stream->index;
        } // END auto_cpu_timer scope

        { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
        boost::timer::auto_cpu_timer t(this_class_str + "2-av_interleaved_write_frame" + timer_format_str);
#endif
        /* Write the compressed frame to the media file. */
        int ret = av_interleaved_write_frame(_format_context, &_packet);
        }

        if (ret < 0)
            throw VideoTargetError("Could not interleaved write frame");
//        av_packet_unref(&packet); taken care of by av_interleaved_write_frame
    }
}

void VideoTargetFFmpeg::finalise()
{
    /* This condition means that append
     * has been called at least once
     * successfully (see Issue#36)
     */
    if (_frame)
    {
        /* get the delayed frames */
        for (int got_output = 1; got_output; )
            encode_and_write(NULL, got_output);

        /* Write the trailer, if any. The trailer must be written before you
         * close the CodecContexts open when you wrote the header; otherwise
         * av_write_trailer() may try to use memory that was freed on
         * av_codec_close(). */
        av_write_trailer(_format_context);
    }

    if (_stream->codec) avcodec_close(_stream->codec);
    if (_frame) av_frame_free(&_frame);
//  av_freep(&_frame->data[0]); no need for this because _frame never manages its own data
    if (_sws_context) sws_freeContext(_sws_context);

    if (!(_format_context->oformat->flags & AVFMT_NOFILE))
        if (_format_context->pb)
            /* Close the output file. */
            avio_closep(&_format_context->pb);
    /* free the stream */
    avformat_free_context(_format_context);

    // default values, for next init
    _codec = NULL;
    _frame = NULL;
    _framerate = -1;
    _sws_context = NULL;
    _format_context = NULL;
    _stream = NULL;
    _frame_index = 0;
}

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: salobj.cxx,v $
 * $Revision: 1.14 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

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

#include <string.h>

#include "saldata.hxx"
#include "salobj.h"
#include "salframe.h"

// get QTMovieView
#include "premac.h"
#include <QTKit/QTMovieView.h>
#include "postmac.h"

// =======================================================================

AquaSalObject::AquaSalObject( AquaSalFrame* pFrame ) :
    mpFrame( pFrame ),
    mnClipX( -1 ),
    mnClipY( -1 ),
    mnClipWidth( -1 ),
    mnClipHeight( -1 ),
    mbClip( false ),
    mnX( 0 ),
    mnY( 0 ),
    mnWidth( 20 ),
    mnHeight( 20 )
{
    maSysData.nSize = sizeof( maSysData );
    maSysData.pView = NULL;

    NSRect aInitFrame = { { 0, 0 }, { 20, 20 } };
    mpClipView = [[NSClipView alloc] initWithFrame: aInitFrame ];
    if( mpClipView )
    {
        [mpFrame->getView() addSubview: mpClipView];
        [mpClipView setHidden: YES];
    }
    maSysData.pView = [[QTMovieView alloc] initWithFrame: aInitFrame];
    if( maSysData.pView )
    {
        if( mpClipView )
            [mpClipView setDocumentView: maSysData.pView];
    }
}

// -----------------------------------------------------------------------

AquaSalObject::~AquaSalObject()
{
    if( maSysData.pView )
    {
        [maSysData.pView removeFromSuperview];
        [maSysData.pView release];
    }
    if( mpClipView )
    {
        [mpClipView removeFromSuperview];
        [mpClipView release];
    }
}

/*
   sadly there seems to be no way to impose clipping on a child view,
   especially a QTMovieView which seems to ignore the current context
   completely. Also there is no real way to shape a window; on Aqua a
   similar effect to non-rectangular windows is achieved by using a
   non-opaque window and not painting where one wants the background
   to shine through.

   With respect to SalObject this leaves us to having an NSClipView
   containing the child view. Even a QTMovieView respects the boundaries of
   that, which gives us a clip "region" consisting of one rectangle.
   This is gives us an 80% solution only, though.
*/

// -----------------------------------------------------------------------

void AquaSalObject::ResetClipRegion()
{
    mbClip = false;
    setClippedPosSize();
}

// -----------------------------------------------------------------------

USHORT AquaSalObject::GetClipRegionType()
{
    return SAL_OBJECT_CLIP_INCLUDERECTS;
}

// -----------------------------------------------------------------------

void AquaSalObject::BeginSetClipRegion( ULONG nRectCount )
{
    mbClip = false;
}

// -----------------------------------------------------------------------

void AquaSalObject::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
{
    if( mbClip )
    {
        if( nX < mnClipX )
        {
            mnClipWidth += mnClipX - nX;
            mnClipX = nX;
        }
        if( nX + nWidth > mnClipX + mnClipWidth )
            mnClipWidth = nX + nWidth - mnClipX;
        if( nY < mnClipY )
        {
            mnClipHeight += mnClipY - nY;
            mnClipY = nY;
        }
        if( nY + nHeight > mnClipY + mnClipHeight )
            mnClipHeight = nY + nHeight - mnClipY;
    }
    else
    {
        mnClipX = nX;
        mnClipY = nY;
        mnClipWidth = nWidth;
        mnClipHeight = nHeight;
        mbClip = true;
    }
}

// -----------------------------------------------------------------------

void AquaSalObject::EndSetClipRegion()
{
    setClippedPosSize();
}

// -----------------------------------------------------------------------

void AquaSalObject::SetPosSize( long nX, long nY, long nWidth, long nHeight )
{
    mnX = nX;
    mnY = nY;
    mnWidth = nWidth;
    mnHeight = nHeight;
    setClippedPosSize();
}

// -----------------------------------------------------------------------

void AquaSalObject::setClippedPosSize()
{
    NSRect aViewRect = { { 0, 0 }, { mnWidth, mnHeight } };
    if( maSysData.pView )
        [maSysData.pView setFrame: aViewRect];

    NSRect aClipViewRect = { { mnX, mnY }, { mnWidth, mnHeight } };
    NSPoint aClipPt = { 0, 0 };
    if( mbClip )
    {
        aClipViewRect.origin.x += mnClipX;
        aClipViewRect.origin.y += mnClipY;
        aClipViewRect.size.width = mnClipWidth;
        aClipViewRect.size.height = mnClipHeight;
        aClipPt.x = mnClipX;
        if( mnClipY == 0 )
            aClipPt.y = mnHeight - mnClipHeight;;
    }

    mpFrame->VCLToCocoa( aClipViewRect, false );
    [mpClipView setFrame: aClipViewRect];

    [mpClipView scrollToPoint: aClipPt];
}

// -----------------------------------------------------------------------

void AquaSalObject::Show( BOOL bVisible )
{
    if( mpClipView )
        [mpClipView setHidden: (bVisible ? NO : YES)];
}

// -----------------------------------------------------------------------

void AquaSalObject::Enable( BOOL bEnable )
{
}

// -----------------------------------------------------------------------

void AquaSalObject::GrabFocus()
{
}

// -----------------------------------------------------------------------

void AquaSalObject::SetBackground()
{
}

// -----------------------------------------------------------------------

void AquaSalObject::SetBackground( SalColor nSalColor )
{
}

// -----------------------------------------------------------------------

const SystemEnvData* AquaSalObject::GetSystemData() const
{
    return &maSysData;
}

<commit_msg>INTEGRATION: CWS canvas05 (1.13.60); FILE MERGED 2008/04/29 05:33:46 mox 1.13.60.3: Remove the now-unnecessary casts of (NSView*). 2008/04/21 07:47:27 thb 1.13.60.2: RESYNC: (1.13-1.14); FILE MERGED 2008/04/06 19:35:18 mox 1.13.60.1: Change headers to GetGraphicsData() const, Build fixes for VCL aqua<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: salobj.cxx,v $
 * $Revision: 1.15 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

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

#include <string.h>

#include "saldata.hxx"
#include "salobj.h"
#include "salframe.h"

// get QTMovieView
#include "premac.h"
#include <QTKit/QTMovieView.h>
#include "postmac.h"

// =======================================================================

AquaSalObject::AquaSalObject( AquaSalFrame* pFrame ) :
    mpFrame( pFrame ),
    mnClipX( -1 ),
    mnClipY( -1 ),
    mnClipWidth( -1 ),
    mnClipHeight( -1 ),
    mbClip( false ),
    mnX( 0 ),
    mnY( 0 ),
    mnWidth( 20 ),
    mnHeight( 20 )
{
    maSysData.nSize = sizeof( maSysData );
    maSysData.pView = NULL;

    NSRect aInitFrame = { { 0, 0 }, { 20, 20 } };
    mpClipView = [[NSClipView alloc] initWithFrame: aInitFrame ];
    if( mpClipView )
    {
        [mpFrame->getView() addSubview: mpClipView];
        [mpClipView setHidden: YES];
    }
    maSysData.pView = [[QTMovieView alloc] initWithFrame: aInitFrame];
    if( maSysData.pView )
    {
        if( mpClipView )
            [mpClipView setDocumentView: maSysData.pView];
    }
}

// -----------------------------------------------------------------------

AquaSalObject::~AquaSalObject()
{
    if( maSysData.pView )
    {
        NSView *pView = maSysData.pView;
        [pView removeFromSuperview];
        [pView release];
    }
    if( mpClipView )
    {
        [mpClipView removeFromSuperview];
        [mpClipView release];
    }
}

/*
   sadly there seems to be no way to impose clipping on a child view,
   especially a QTMovieView which seems to ignore the current context
   completely. Also there is no real way to shape a window; on Aqua a
   similar effect to non-rectangular windows is achieved by using a
   non-opaque window and not painting where one wants the background
   to shine through.

   With respect to SalObject this leaves us to having an NSClipView
   containing the child view. Even a QTMovieView respects the boundaries of
   that, which gives us a clip "region" consisting of one rectangle.
   This is gives us an 80% solution only, though.
*/

// -----------------------------------------------------------------------

void AquaSalObject::ResetClipRegion()
{
    mbClip = false;
    setClippedPosSize();
}

// -----------------------------------------------------------------------

USHORT AquaSalObject::GetClipRegionType()
{
    return SAL_OBJECT_CLIP_INCLUDERECTS;
}

// -----------------------------------------------------------------------

void AquaSalObject::BeginSetClipRegion( ULONG nRectCount )
{
    mbClip = false;
}

// -----------------------------------------------------------------------

void AquaSalObject::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
{
    if( mbClip )
    {
        if( nX < mnClipX )
        {
            mnClipWidth += mnClipX - nX;
            mnClipX = nX;
        }
        if( nX + nWidth > mnClipX + mnClipWidth )
            mnClipWidth = nX + nWidth - mnClipX;
        if( nY < mnClipY )
        {
            mnClipHeight += mnClipY - nY;
            mnClipY = nY;
        }
        if( nY + nHeight > mnClipY + mnClipHeight )
            mnClipHeight = nY + nHeight - mnClipY;
    }
    else
    {
        mnClipX = nX;
        mnClipY = nY;
        mnClipWidth = nWidth;
        mnClipHeight = nHeight;
        mbClip = true;
    }
}

// -----------------------------------------------------------------------

void AquaSalObject::EndSetClipRegion()
{
    setClippedPosSize();
}

// -----------------------------------------------------------------------

void AquaSalObject::SetPosSize( long nX, long nY, long nWidth, long nHeight )
{
    mnX = nX;
    mnY = nY;
    mnWidth = nWidth;
    mnHeight = nHeight;
    setClippedPosSize();
}

// -----------------------------------------------------------------------

void AquaSalObject::setClippedPosSize()
{
    NSRect aViewRect = { { 0, 0 }, { mnWidth, mnHeight } };
    if( maSysData.pView )
    {
        NSView *pView = maSysData.pView;
        [pView setFrame: aViewRect];
    }

    NSRect aClipViewRect = { { mnX, mnY }, { mnWidth, mnHeight } };
    NSPoint aClipPt = { 0, 0 };
    if( mbClip )
    {
        aClipViewRect.origin.x += mnClipX;
        aClipViewRect.origin.y += mnClipY;
        aClipViewRect.size.width = mnClipWidth;
        aClipViewRect.size.height = mnClipHeight;
        aClipPt.x = mnClipX;
        if( mnClipY == 0 )
            aClipPt.y = mnHeight - mnClipHeight;;
    }

    mpFrame->VCLToCocoa( aClipViewRect, false );
    [mpClipView setFrame: aClipViewRect];

    [mpClipView scrollToPoint: aClipPt];
}

// -----------------------------------------------------------------------

void AquaSalObject::Show( BOOL bVisible )
{
    if( mpClipView )
        [mpClipView setHidden: (bVisible ? NO : YES)];
}

// -----------------------------------------------------------------------

void AquaSalObject::Enable( BOOL bEnable )
{
}

// -----------------------------------------------------------------------

void AquaSalObject::GrabFocus()
{
}

// -----------------------------------------------------------------------

void AquaSalObject::SetBackground()
{
}

// -----------------------------------------------------------------------

void AquaSalObject::SetBackground( SalColor nSalColor )
{
}

// -----------------------------------------------------------------------

const SystemEnvData* AquaSalObject::GetSystemData() const
{
    return &maSysData;
}

<|endoftext|>


<commit_before>/*===-- int128_builtins.cpp - Implement __muloti4 --------------------------===
 *
 * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 * See https://llvm.org/LICENSE.txt for license information.
 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 *
 * ===----------------------------------------------------------------------===
 *
 * This file implements __muloti4, and is stolen from the compiler_rt library.
 *
 * FIXME: we steal and re-compile it into filesystem, which uses __int128_t,
 * and requires this builtin when sanitized. See llvm.org/PR30643
 *
 * ===----------------------------------------------------------------------===
 */
#include "__config"
#include "climits"

#if !defined(_LIBCPP_HAS_NO_INT128)

extern "C" __attribute__((no_sanitize("undefined")))
__int128_t __muloti4(__int128_t a, __int128_t b, int* overflow) {
  const int N = (int)(sizeof(__int128_t) * CHAR_BIT);
  const __int128_t MIN = (__int128_t)1 << (N - 1);
  const __int128_t MAX = ~MIN;
  *overflow = 0;
  __int128_t result = a * b;
  if (a == MIN) {
    if (b != 0 && b != 1)
      *overflow = 1;
    return result;
  }
  if (b == MIN) {
    if (a != 0 && a != 1)
      *overflow = 1;
    return result;
  }
  __int128_t sa = a >> (N - 1);
  __int128_t abs_a = (a ^ sa) - sa;
  __int128_t sb = b >> (N - 1);
  __int128_t abs_b = (b ^ sb) - sb;
  if (abs_a < 2 || abs_b < 2)
    return result;
  if (sa == sb) {
    if (abs_a > MAX / abs_b)
      *overflow = 1;
  } else {
    if (abs_a > MIN / -abs_b)
      *overflow = 1;
  }
  return result;
}

#endif
<commit_msg>Fix missing __muloti4 function with UBSAN<commit_after>/*===-- int128_builtins.cpp - Implement __muloti4 --------------------------===
 *
 * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 * See https://llvm.org/LICENSE.txt for license information.
 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 *
 * ===----------------------------------------------------------------------===
 *
 * This file implements __muloti4, and is stolen from the compiler_rt library.
 *
 * FIXME: we steal and re-compile it into filesystem, which uses __int128_t,
 * and requires this builtin when sanitized. See llvm.org/PR30643
 *
 * ===----------------------------------------------------------------------===
 */
#include "__config"
#include "climits"

#if !defined(_LIBCPP_HAS_NO_INT128)

extern "C" __attribute__((no_sanitize("undefined"))) _LIBCPP_FUNC_VIS
__int128_t __muloti4(__int128_t a, __int128_t b, int* overflow) {
  const int N = (int)(sizeof(__int128_t) * CHAR_BIT);
  const __int128_t MIN = (__int128_t)1 << (N - 1);
  const __int128_t MAX = ~MIN;
  *overflow = 0;
  __int128_t result = a * b;
  if (a == MIN) {
    if (b != 0 && b != 1)
      *overflow = 1;
    return result;
  }
  if (b == MIN) {
    if (a != 0 && a != 1)
      *overflow = 1;
    return result;
  }
  __int128_t sa = a >> (N - 1);
  __int128_t abs_a = (a ^ sa) - sa;
  __int128_t sb = b >> (N - 1);
  __int128_t abs_b = (b ^ sb) - sb;
  if (abs_a < 2 || abs_b < 2)
    return result;
  if (sa == sb) {
    if (abs_a > MAX / abs_b)
      *overflow = 1;
  } else {
    if (abs_a > MIN / -abs_b)
      *overflow = 1;
  }
  return result;
}

#endif
<|endoftext|>