<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include <Ogre.h>
#include "OgreRenderingModule.h"
#include "ComponentRegistrarInterface.h"
#include "ServiceManager.h"
#include "EC_OgrePlaceable.h"
#include "EC_OgreMesh.h"
#include "EC_OgreLight.h"
#include "EC_OgreSky.h"
#include "EC_OgreCustomObject.h"
#include "EC_OgreConsoleOverlay.h"

#pragma warning( push )
#pragma warning( disable : 4250 )
#include <gtkmm/window.h>
#include "OgreWidget.h"
#pragma warning( pop )

#ifdef WIN32
#include <gdkwin32.h>
#else
#include <gdk/gdkx.h>
#endif

namespace OgreRenderer
{
    OgreRenderingModule::OgreRenderingModule() : ModuleInterfaceImpl(type_static_),
        assetcategory_id_(0),
        resourcecategory_id_(0),
        ogre_widget_(NULL),
        ogre_window_(NULL)
    {
    }

    OgreRenderingModule::~OgreRenderingModule()
    {
    }

    // virtual
    void OgreRenderingModule::Load()
    {
        using namespace OgreRenderer;

        LogInfo("Module " + Name() + " loaded.");

        DECLARE_MODULE_EC(EC_OgrePlaceable);
        DECLARE_MODULE_EC(EC_OgreMesh);
        DECLARE_MODULE_EC(EC_OgreLight);
        DECLARE_MODULE_EC(EC_OgreSky);
        DECLARE_MODULE_EC(EC_OgreCustomObject);
        DECLARE_MODULE_EC(EC_OgreConsoleOverlay);
    }

    // virtual
    void OgreRenderingModule::Unload()
    {
        LogInfo("Module " + Name() + " unloaded.");
    }

    // virtual
    void OgreRenderingModule::PreInitialize()
    {
        // create renderer here, so it can be accessed in uninitialized state by other module's PreInitialize()
        renderer_ = OgreRenderer::RendererPtr(new OgreRenderer::Renderer(framework_));
    }

    // virtual
    void OgreRenderingModule::Initialize()
    {
        assert (renderer_);

        bool embed = framework_->GetDefaultConfig().DeclareSetting("OgreRenderer", "EmbedOgreIntoGtk", false);

        if (!embed)
        {
            renderer_->Initialize();
        }
        else
        {
            ogre_window_ = new Gtk::Window();
            ogre_widget_ = new OgreWidget(renderer_);
            ogre_window_->set_border_width(10);
            ogre_window_->add(*ogre_widget_);
            ogre_widget_->show();
            ogre_window_->show();
            ogre_window_->signal_hide().connect(sigc::mem_fun(*this, &OgreRenderingModule::OnOgreGtkWindowClosed));

#ifdef _WINDOWS
            // Must be after ogre_window_->show(), the window is not properly created until then.
            Core::uint handle = 0;
            Glib::RefPtr<Gdk::Window> main_gdk_win = ogre_window_->get_window();
            handle = (Core::uint)(GDK_WINDOW_HWND(main_gdk_win->gobj()));
            renderer_->SetMainWindowHandle(handle);
#endif

            assert (renderer_->IsInitialized());
        }

        framework_->GetServiceManager()->RegisterService(Foundation::Service::ST_Renderer, renderer_.get());

        LogInfo("Module " + Name() + " initialized.");
    }

    // virtual
    void OgreRenderingModule::PostInitialize()
    {
        Foundation::EventManagerPtr event_manager = framework_->GetEventManager();

        assetcategory_id_ = event_manager->QueryEventCategory("Asset");

        if (assetcategory_id_ == 0 )
            LogWarning("Unable to find event category for Asset events!");

        resourcecategory_id_ = event_manager->QueryEventCategory("Resource");
        if (!resourcecategory_id_)
        {
            resourcecategory_id_ = event_manager->RegisterEventCategory("Resource");
            event_manager->RegisterEvent(resourcecategory_id_, Resource::Events::RESOURCE_READY, "ResourceReady");
        }

        renderer_->PostInitialize();

        // Hackish way to register renderer debug console commands
        if (framework_->GetServiceManager()->IsRegistered(Foundation::Service::ST_ConsoleCommand))
        {
            Console::CommandService *console = framework_->GetService<Console::CommandService>(Foundation::Service::ST_ConsoleCommand);
            console->RegisterCommand(Console::CreateCommand(
                "RequestTexture", "Download, decode & create Ogre texture. Usage: RequestTexture(uuid)",
                Console::Bind(this, &OgreRenderingModule::ConsoleRequestTexture)));
            console->RegisterCommand(Console::CreateCommand(
                "RequestMesh", "Download & create Ogre mesh. Usage: RequestMesh(uuid)",
                Console::Bind(this, &OgreRenderingModule::ConsoleRequestMesh)));
        }
    }

    // virtual
    bool OgreRenderingModule::HandleEvent(
        Core::event_category_id_t category_id,
        Core::event_id_t event_id,
        Foundation::EventDataInterface* data)
    {
        if (!renderer_)
            return false;

        if (category_id == assetcategory_id_)
        {
            return renderer_->HandleAssetEvent(event_id, data);
        }

        if (category_id == resourcecategory_id_)
        {
            return renderer_->HandleResourceEvent(event_id, data);
        }

        return false;
    }

    // virtual
    void OgreRenderingModule::Uninitialize()
    {
        if (framework_->GetServiceManager()->IsRegistered(Foundation::Service::ST_ConsoleCommand))
        {
            // Unregister debug commands
            Console::CommandService *console = framework_->GetService<Console::CommandService>(Foundation::Service::ST_ConsoleCommand);
            console->UnregisterCommand("RequestTexture");
            console->UnregisterCommand("RequestMesh");
        }

        framework_->GetServiceManager()->UnregisterService(renderer_.get());

        delete ogre_window_;
        delete ogre_widget_;
        renderer_.reset();

        LogInfo("Module " + Name() + " uninitialized.");
    }

    // virtual
    void OgreRenderingModule::Update(Core::f64 frametime)
    {
        renderer_->Update(frametime);
    }

    Console::CommandResult OgreRenderingModule::ConsoleRequestTexture(const Core::StringVector &params)
    {
        if (params.size() < 1)
            return Console::ResultFailure("Usage: RequestTexture(uuid)");

        if (renderer_)
            renderer_->RequestTexture(params[0]);

        return Console::ResultSuccess();
    }

    Console::CommandResult OgreRenderingModule::ConsoleRequestMesh(const Core::StringVector &params)
    {
        if (params.size() < 1)
            return Console::ResultFailure("Usage: RequestMesh(uuid)");

        if (renderer_)
            renderer_->RequestMesh(params[0]);

        return Console::ResultSuccess();
    }

    void OgreRenderingModule::OnOgreGtkWindowClosed()
    {
        if (renderer_)
            renderer_->OnWindowClosed();
    }
}

using namespace OgreRenderer;

POCO_BEGIN_MANIFEST(Foundation::ModuleInterface)
   POCO_EXPORT_CLASS(OgreRenderingModule)
POCO_END_MANIFEST

<commit_msg>Added todo item about r583.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include <Ogre.h>
#include "OgreRenderingModule.h"
#include "ComponentRegistrarInterface.h"
#include "ServiceManager.h"
#include "EC_OgrePlaceable.h"
#include "EC_OgreMesh.h"
#include "EC_OgreLight.h"
#include "EC_OgreSky.h"
#include "EC_OgreCustomObject.h"
#include "EC_OgreConsoleOverlay.h"

#pragma warning( push )
#pragma warning( disable : 4250 )
#include <gtkmm/window.h>
#include "OgreWidget.h"
#pragma warning( pop )

#ifdef WIN32
#include <gdkwin32.h>
#else
#include <gdk/gdkx.h>
#endif

namespace OgreRenderer
{
    OgreRenderingModule::OgreRenderingModule() : ModuleInterfaceImpl(type_static_),
        assetcategory_id_(0),
        resourcecategory_id_(0),
        ogre_widget_(NULL),
        ogre_window_(NULL)
    {
    }

    OgreRenderingModule::~OgreRenderingModule()
    {
    }

    // virtual
    void OgreRenderingModule::Load()
    {
        using namespace OgreRenderer;

        LogInfo("Module " + Name() + " loaded.");

        DECLARE_MODULE_EC(EC_OgrePlaceable);
        DECLARE_MODULE_EC(EC_OgreMesh);
        DECLARE_MODULE_EC(EC_OgreLight);
        DECLARE_MODULE_EC(EC_OgreSky);
        DECLARE_MODULE_EC(EC_OgreCustomObject);
        DECLARE_MODULE_EC(EC_OgreConsoleOverlay);
    }

    // virtual
    void OgreRenderingModule::Unload()
    {
        LogInfo("Module " + Name() + " unloaded.");
    }

    // virtual
    void OgreRenderingModule::PreInitialize()
    {
        // create renderer here, so it can be accessed in uninitialized state by other module's PreInitialize()
        renderer_ = OgreRenderer::RendererPtr(new OgreRenderer::Renderer(framework_));
    }

    // virtual
    void OgreRenderingModule::Initialize()
    {
        assert (renderer_);

        bool embed = framework_->GetDefaultConfig().DeclareSetting("OgreRenderer", "EmbedOgreIntoGtk", false);

        if (!embed)
        {
            renderer_->Initialize();
        }
        else
        {
            ogre_window_ = new Gtk::Window();
            ogre_widget_ = new OgreWidget(renderer_);
            ogre_window_->set_border_width(10);
            ogre_window_->add(*ogre_widget_);
            ogre_widget_->show();
            ogre_window_->show();
            ogre_window_->signal_hide().connect(sigc::mem_fun(*this, &OgreRenderingModule::OnOgreGtkWindowClosed));

#ifdef _WINDOWS
            // Must be after ogre_window_->show(), the window is not properly created until then.
            Core::uint handle = 0;
            Glib::RefPtr<Gdk::Window> main_gdk_win = ogre_window_->get_window();
            handle = (Core::uint)(GDK_WINDOW_HWND(main_gdk_win->gobj()));
            renderer_->SetMainWindowHandle(handle);
#endif
            //! \todo Retrieve main Gtk window handle for other platforms.

            assert (renderer_->IsInitialized());
        }

        framework_->GetServiceManager()->RegisterService(Foundation::Service::ST_Renderer, renderer_.get());

        LogInfo("Module " + Name() + " initialized.");
    }

    // virtual
    void OgreRenderingModule::PostInitialize()
    {
        Foundation::EventManagerPtr event_manager = framework_->GetEventManager();

        assetcategory_id_ = event_manager->QueryEventCategory("Asset");

        if (assetcategory_id_ == 0 )
            LogWarning("Unable to find event category for Asset events!");

        resourcecategory_id_ = event_manager->QueryEventCategory("Resource");
        if (!resourcecategory_id_)
        {
            resourcecategory_id_ = event_manager->RegisterEventCategory("Resource");
            event_manager->RegisterEvent(resourcecategory_id_, Resource::Events::RESOURCE_READY, "ResourceReady");
        }

        renderer_->PostInitialize();

        // Hackish way to register renderer debug console commands
        if (framework_->GetServiceManager()->IsRegistered(Foundation::Service::ST_ConsoleCommand))
        {
            Console::CommandService *console = framework_->GetService<Console::CommandService>(Foundation::Service::ST_ConsoleCommand);
            console->RegisterCommand(Console::CreateCommand(
                "RequestTexture", "Download, decode & create Ogre texture. Usage: RequestTexture(uuid)",
                Console::Bind(this, &OgreRenderingModule::ConsoleRequestTexture)));
            console->RegisterCommand(Console::CreateCommand(
                "RequestMesh", "Download & create Ogre mesh. Usage: RequestMesh(uuid)",
                Console::Bind(this, &OgreRenderingModule::ConsoleRequestMesh)));
        }
    }

    // virtual
    bool OgreRenderingModule::HandleEvent(
        Core::event_category_id_t category_id,
        Core::event_id_t event_id,
        Foundation::EventDataInterface* data)
    {
        if (!renderer_)
            return false;

        if (category_id == assetcategory_id_)
        {
            return renderer_->HandleAssetEvent(event_id, data);
        }

        if (category_id == resourcecategory_id_)
        {
            return renderer_->HandleResourceEvent(event_id, data);
        }

        return false;
    }

    // virtual
    void OgreRenderingModule::Uninitialize()
    {
        if (framework_->GetServiceManager()->IsRegistered(Foundation::Service::ST_ConsoleCommand))
        {
            // Unregister debug commands
            Console::CommandService *console = framework_->GetService<Console::CommandService>(Foundation::Service::ST_ConsoleCommand);
            console->UnregisterCommand("RequestTexture");
            console->UnregisterCommand("RequestMesh");
        }

        framework_->GetServiceManager()->UnregisterService(renderer_.get());

        delete ogre_window_;
        delete ogre_widget_;
        renderer_.reset();

        LogInfo("Module " + Name() + " uninitialized.");
    }

    // virtual
    void OgreRenderingModule::Update(Core::f64 frametime)
    {
        renderer_->Update(frametime);
    }

    Console::CommandResult OgreRenderingModule::ConsoleRequestTexture(const Core::StringVector &params)
    {
        if (params.size() < 1)
            return Console::ResultFailure("Usage: RequestTexture(uuid)");

        if (renderer_)
            renderer_->RequestTexture(params[0]);

        return Console::ResultSuccess();
    }

    Console::CommandResult OgreRenderingModule::ConsoleRequestMesh(const Core::StringVector &params)
    {
        if (params.size() < 1)
            return Console::ResultFailure("Usage: RequestMesh(uuid)");

        if (renderer_)
            renderer_->RequestMesh(params[0]);

        return Console::ResultSuccess();
    }

    void OgreRenderingModule::OnOgreGtkWindowClosed()
    {
        if (renderer_)
            renderer_->OnWindowClosed();
    }
}

using namespace OgreRenderer;

POCO_BEGIN_MANIFEST(Foundation::ModuleInterface)
   POCO_EXPORT_CLASS(OgreRenderingModule)
POCO_END_MANIFEST

<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/directory_lister.h"

#include <algorithm>
#include <vector>

#include "base/file_util.h"
#include "base/i18n/file_util_icu.h"
#include "base/message_loop.h"
#include "base/platform_thread.h"
#include "net/base/net_errors.h"

namespace net {

static const int kFilesPerEvent = 8;

// A task which is used to signal the delegate asynchronously.
class DirectoryDataEvent : public Task {
public:
  explicit DirectoryDataEvent(DirectoryLister* d) : lister(d), error(0) {
    // Allocations of the FindInfo aren't super cheap, so reserve space.
    data.reserve(64);
  }

  void Run() {
    if (data.empty()) {
      lister->OnDone(error);
      return;
    }
    lister->OnReceivedData(&data[0], static_cast<int>(data.size()));
  }

  scoped_refptr<DirectoryLister> lister;
  std::vector<DirectoryLister::DirectoryListerData> data;
  int error;
};

// Comparator for sorting lister results. This uses the locale aware filename
// comparison function on the filenames for sorting in the user's locale.
// Static.
bool DirectoryLister::CompareAlphaDirsFirst(const DirectoryListerData& a,
                                            const DirectoryListerData& b) {
  // Parent directory before all else.
  if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(a.info)))
    return true;
  if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(b.info)))
    return false;

  // Directories before regular files.
  bool a_is_directory = file_util::FileEnumerator::IsDirectory(a.info);
  bool b_is_directory = file_util::FileEnumerator::IsDirectory(b.info);
  if (a_is_directory != b_is_directory)
    return a_is_directory;

  return file_util::LocaleAwareCompareFilenames(
      file_util::FileEnumerator::GetFilename(a.info),
      file_util::FileEnumerator::GetFilename(b.info));
}

// Static.
bool DirectoryLister::CompareDate(const DirectoryListerData& a,
                                  const DirectoryListerData& b) {
  // Parent directory before all else.
  if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(a.info)))
    return true;
  if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(b.info)))
    return false;

  // Directories before regular files.
  bool a_is_directory = file_util::FileEnumerator::IsDirectory(a.info);
  bool b_is_directory = file_util::FileEnumerator::IsDirectory(b.info);
  if (a_is_directory != b_is_directory)
    return a_is_directory;
#if defined(OS_POSIX)
  return a.info.stat.st_mtime > b.info.stat.st_mtime;
#elif defined(OS_WIN)
  if (a.info.ftLastWriteTime.dwHighDateTime ==
      b.info.ftLastWriteTime.dwHighDateTime) {
    return a.info.ftLastWriteTime.dwLowDateTime >
           b.info.ftLastWriteTime.dwLowDateTime;
  } else {
    return a.info.ftLastWriteTime.dwHighDateTime >
           b.info.ftLastWriteTime.dwHighDateTime;
  }
#endif
}

// Comparator for sorting find result by paths. This uses the locale-aware
// comparison function on the filenames for sorting in the user's locale.
// Static.
bool DirectoryLister::CompareFullPath(const DirectoryListerData& a,
                                      const DirectoryListerData& b) {
  return file_util::LocaleAwareCompareFilenames(a.path, b.path);
}

DirectoryLister::DirectoryLister(const FilePath& dir,
                                 DirectoryListerDelegate* delegate)
    : dir_(dir),
      recursive_(false),
      delegate_(delegate),
      sort_(ALPHA_DIRS_FIRST),
      message_loop_(NULL),
      thread_(kNullThreadHandle) {
  DCHECK(!dir.value().empty());
}

DirectoryLister::DirectoryLister(const FilePath& dir,
                                 bool recursive,
                                 SORT_TYPE sort,
                                 DirectoryListerDelegate* delegate)
    : dir_(dir),
      recursive_(recursive),
      delegate_(delegate),
      sort_(sort),
      message_loop_(NULL),
      thread_(kNullThreadHandle) {
  DCHECK(!dir.value().empty());
}

DirectoryLister::~DirectoryLister() {
  if (thread_) {
    PlatformThread::Join(thread_);
  }
}

bool DirectoryLister::Start() {
  // spawn a thread to enumerate the specified directory

  // pass events back to the current thread
  message_loop_ = MessageLoop::current();
  DCHECK(message_loop_) << "calling thread must have a message loop";

  AddRef();  // the thread will release us when it is done

  if (!PlatformThread::Create(0, this, &thread_)) {
    Release();
    return false;
  }

  return true;
}

void DirectoryLister::Cancel() {
  canceled_.Set();

  if (thread_) {
    PlatformThread::Join(thread_);
    thread_ = kNullThreadHandle;
  }
}

void DirectoryLister::ThreadMain() {
  DirectoryDataEvent* e = new DirectoryDataEvent(this);

  if (!file_util::DirectoryExists(dir_)) {
    e->error = net::ERR_FILE_NOT_FOUND;
    message_loop_->PostTask(FROM_HERE, e);
    Release();
    return;
  }

  int types = file_util::FileEnumerator::FILES |
              file_util::FileEnumerator::DIRECTORIES;
  if (!recursive_)
    types |= file_util::FileEnumerator::INCLUDE_DOT_DOT;

  file_util::FileEnumerator file_enum(dir_, recursive_,
      static_cast<file_util::FileEnumerator::FILE_TYPE>(types));

  FilePath path;
  while (!canceled_.IsSet() && !(path = file_enum.Next()).empty()) {
    DirectoryListerData data;
    file_enum.GetFindInfo(&data.info);
    data.path = path;
    e->data.push_back(data);

    /* TODO(brettw) bug 24107: It would be nice to send incremental updates.
       We gather them all so they can be sorted, but eventually the sorting
       should be done from JS to give more flexibility in the page. When we do
       that, we can uncomment this to send incremental updates to the page.
    if (++e->count == kFilesPerEvent) {
      message_loop_->PostTask(FROM_HERE, e);
      e = new DirectoryDataEvent(this);
    }
    */
  }

  if (!e->data.empty()) {
    // Sort the results. See the TODO above (this sort should be removed and we
    // should do it from JS).
    if (sort_ == DATE)
      std::sort(e->data.begin(), e->data.end(), CompareDate);
    else if (sort_ == FULL_PATH)
      std::sort(e->data.begin(), e->data.end(), CompareFullPath);
    else if (sort_ == ALPHA_DIRS_FIRST)
      std::sort(e->data.begin(), e->data.end(), CompareAlphaDirsFirst);
    else
      DCHECK_EQ(NO_SORT, sort_);

    message_loop_->PostTask(FROM_HERE, e);
    e = new DirectoryDataEvent(this);
  }

  // Notify done
  Release();
  message_loop_->PostTask(FROM_HERE, e);
}

void DirectoryLister::OnReceivedData(const DirectoryListerData* data,
                                     int count) {
  // Since the delegate can clear itself during the OnListFile callback, we
  // need to null check it during each iteration of the loop.  Similarly, it is
  // necessary to check the canceled_ flag to avoid sending data to a delegate
  // who doesn't want anymore.
  for (int i = 0; !canceled_.IsSet() && delegate_ && i < count; ++i)
    delegate_->OnListFile(data[i]);
}

void DirectoryLister::OnDone(int error) {
  // If canceled is set, we need to report some kind of error,
  // but don't overwrite the error condition if it is already set.
  if (!error && canceled_.IsSet())
    error = net::ERR_ABORTED;

  if (delegate_)
    delegate_->OnListDone(error);
}

}  // namespace net
<commit_msg>Temporarily whitelist DirectoryLister, which is blocking the IO thread.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/directory_lister.h"

#include <algorithm>
#include <vector>

#include "base/file_util.h"
#include "base/i18n/file_util_icu.h"
#include "base/message_loop.h"
#include "base/platform_thread.h"
#include "base/thread_restrictions.h"
#include "net/base/net_errors.h"

namespace net {

static const int kFilesPerEvent = 8;

// A task which is used to signal the delegate asynchronously.
class DirectoryDataEvent : public Task {
public:
  explicit DirectoryDataEvent(DirectoryLister* d) : lister(d), error(0) {
    // Allocations of the FindInfo aren't super cheap, so reserve space.
    data.reserve(64);
  }

  void Run() {
    if (data.empty()) {
      lister->OnDone(error);
      return;
    }
    lister->OnReceivedData(&data[0], static_cast<int>(data.size()));
  }

  scoped_refptr<DirectoryLister> lister;
  std::vector<DirectoryLister::DirectoryListerData> data;
  int error;
};

// Comparator for sorting lister results. This uses the locale aware filename
// comparison function on the filenames for sorting in the user's locale.
// Static.
bool DirectoryLister::CompareAlphaDirsFirst(const DirectoryListerData& a,
                                            const DirectoryListerData& b) {
  // Parent directory before all else.
  if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(a.info)))
    return true;
  if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(b.info)))
    return false;

  // Directories before regular files.
  bool a_is_directory = file_util::FileEnumerator::IsDirectory(a.info);
  bool b_is_directory = file_util::FileEnumerator::IsDirectory(b.info);
  if (a_is_directory != b_is_directory)
    return a_is_directory;

  return file_util::LocaleAwareCompareFilenames(
      file_util::FileEnumerator::GetFilename(a.info),
      file_util::FileEnumerator::GetFilename(b.info));
}

// Static.
bool DirectoryLister::CompareDate(const DirectoryListerData& a,
                                  const DirectoryListerData& b) {
  // Parent directory before all else.
  if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(a.info)))
    return true;
  if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(b.info)))
    return false;

  // Directories before regular files.
  bool a_is_directory = file_util::FileEnumerator::IsDirectory(a.info);
  bool b_is_directory = file_util::FileEnumerator::IsDirectory(b.info);
  if (a_is_directory != b_is_directory)
    return a_is_directory;
#if defined(OS_POSIX)
  return a.info.stat.st_mtime > b.info.stat.st_mtime;
#elif defined(OS_WIN)
  if (a.info.ftLastWriteTime.dwHighDateTime ==
      b.info.ftLastWriteTime.dwHighDateTime) {
    return a.info.ftLastWriteTime.dwLowDateTime >
           b.info.ftLastWriteTime.dwLowDateTime;
  } else {
    return a.info.ftLastWriteTime.dwHighDateTime >
           b.info.ftLastWriteTime.dwHighDateTime;
  }
#endif
}

// Comparator for sorting find result by paths. This uses the locale-aware
// comparison function on the filenames for sorting in the user's locale.
// Static.
bool DirectoryLister::CompareFullPath(const DirectoryListerData& a,
                                      const DirectoryListerData& b) {
  return file_util::LocaleAwareCompareFilenames(a.path, b.path);
}

DirectoryLister::DirectoryLister(const FilePath& dir,
                                 DirectoryListerDelegate* delegate)
    : dir_(dir),
      recursive_(false),
      delegate_(delegate),
      sort_(ALPHA_DIRS_FIRST),
      message_loop_(NULL),
      thread_(kNullThreadHandle) {
  DCHECK(!dir.value().empty());
}

DirectoryLister::DirectoryLister(const FilePath& dir,
                                 bool recursive,
                                 SORT_TYPE sort,
                                 DirectoryListerDelegate* delegate)
    : dir_(dir),
      recursive_(recursive),
      delegate_(delegate),
      sort_(sort),
      message_loop_(NULL),
      thread_(kNullThreadHandle) {
  DCHECK(!dir.value().empty());
}

DirectoryLister::~DirectoryLister() {
  if (thread_) {
    // This is a bug and we should stop joining this thread.
    // http://crbug.com/65331
    base::ThreadRestrictions::ScopedAllowIO allow_io;
    PlatformThread::Join(thread_);
  }
}

bool DirectoryLister::Start() {
  // spawn a thread to enumerate the specified directory

  // pass events back to the current thread
  message_loop_ = MessageLoop::current();
  DCHECK(message_loop_) << "calling thread must have a message loop";

  AddRef();  // the thread will release us when it is done

  if (!PlatformThread::Create(0, this, &thread_)) {
    Release();
    return false;
  }

  return true;
}

void DirectoryLister::Cancel() {
  canceled_.Set();

  if (thread_) {
    PlatformThread::Join(thread_);
    thread_ = kNullThreadHandle;
  }
}

void DirectoryLister::ThreadMain() {
  DirectoryDataEvent* e = new DirectoryDataEvent(this);

  if (!file_util::DirectoryExists(dir_)) {
    e->error = net::ERR_FILE_NOT_FOUND;
    message_loop_->PostTask(FROM_HERE, e);
    Release();
    return;
  }

  int types = file_util::FileEnumerator::FILES |
              file_util::FileEnumerator::DIRECTORIES;
  if (!recursive_)
    types |= file_util::FileEnumerator::INCLUDE_DOT_DOT;

  file_util::FileEnumerator file_enum(dir_, recursive_,
      static_cast<file_util::FileEnumerator::FILE_TYPE>(types));

  FilePath path;
  while (!canceled_.IsSet() && !(path = file_enum.Next()).empty()) {
    DirectoryListerData data;
    file_enum.GetFindInfo(&data.info);
    data.path = path;
    e->data.push_back(data);

    /* TODO(brettw) bug 24107: It would be nice to send incremental updates.
       We gather them all so they can be sorted, but eventually the sorting
       should be done from JS to give more flexibility in the page. When we do
       that, we can uncomment this to send incremental updates to the page.
    if (++e->count == kFilesPerEvent) {
      message_loop_->PostTask(FROM_HERE, e);
      e = new DirectoryDataEvent(this);
    }
    */
  }

  if (!e->data.empty()) {
    // Sort the results. See the TODO above (this sort should be removed and we
    // should do it from JS).
    if (sort_ == DATE)
      std::sort(e->data.begin(), e->data.end(), CompareDate);
    else if (sort_ == FULL_PATH)
      std::sort(e->data.begin(), e->data.end(), CompareFullPath);
    else if (sort_ == ALPHA_DIRS_FIRST)
      std::sort(e->data.begin(), e->data.end(), CompareAlphaDirsFirst);
    else
      DCHECK_EQ(NO_SORT, sort_);

    message_loop_->PostTask(FROM_HERE, e);
    e = new DirectoryDataEvent(this);
  }

  // Notify done
  Release();
  message_loop_->PostTask(FROM_HERE, e);
}

void DirectoryLister::OnReceivedData(const DirectoryListerData* data,
                                     int count) {
  // Since the delegate can clear itself during the OnListFile callback, we
  // need to null check it during each iteration of the loop.  Similarly, it is
  // necessary to check the canceled_ flag to avoid sending data to a delegate
  // who doesn't want anymore.
  for (int i = 0; !canceled_.IsSet() && delegate_ && i < count; ++i)
    delegate_->OnListFile(data[i]);
}

void DirectoryLister::OnDone(int error) {
  // If canceled is set, we need to report some kind of error,
  // but don't overwrite the error condition if it is already set.
  if (!error && canceled_.IsSet())
    error = net::ERR_ABORTED;

  if (delegate_)
    delegate_->OnListDone(error);
}

}  // namespace net
<|endoftext|>


<commit_before>#include "chrono_parallel/lcp/ChLcpSolverParallel.h"
#include "chrono_parallel/math/ChThrustLinearAlgebra.h"
#include "core/ChSpmatrix.h"
#include "physics/ChBody.h"
using namespace chrono;

ChLcpSolverParallel::ChLcpSolverParallel(ChParallelDataManager* dc)
: data_container(dc)
{
  tolerance = 1e-7;
  record_violation_history = true;
  warm_start = false;
  residual = 0;
  solver = new ChSolverAPGD();
}

ChLcpSolverParallel::~ChLcpSolverParallel()
{
  delete solver;
}

void ChLcpSolverParallel::ComputeMassMatrix()
{
  uint num_bodies = data_container->num_bodies;
  uint num_shafts = data_container->num_shafts;
  uint num_dof = data_container->num_dof;

  const custom_vector<real>& shaft_inr = data_container->host_data.shaft_inr;

  const std::vector<ChBody*> *body_list = data_container->body_list;
  const std::vector<ChLink*> *link_list= data_container->link_list;
  const std::vector<ChPhysicsItem*> *other_physics_list= data_container->other_physics_list;

  const DynamicVector<real>& hf = data_container->host_data.hf;
  const DynamicVector<real>& v = data_container->host_data.v;

  DynamicVector<real>& M_invk = data_container->host_data.M_invk;
  CompressedMatrix<real>& M_inv = data_container->host_data.M_inv;

  clear(M_inv);

  // Each rigid object has 3 mass entries and 9 inertia entries
  // Each shaft has one inertia entry
  M_inv.reserve(num_bodies * 12 + num_shafts * 1);
  // The mass matrix is square and each rigid body has 6 DOF
  // Shafts have one DOF
  M_inv.resize(num_dof, num_dof);

  for (int i = 0; i < num_bodies; i++) {

    if (data_container->host_data.active_data[i]) {
      real inv_mass = 1.0/body_list->at(i)->GetMass();
      ChMatrix33<>&   body_inv_inr = body_list->at(i)->VariablesBody().GetBodyInvInertia();

      M_inv.append(i * 6 + 0, i * 6 + 0, inv_mass);
      M_inv.finalize(i * 6 + 0);
      M_inv.append(i * 6 + 1, i * 6 + 1, inv_mass);
      M_inv.finalize(i * 6 + 1);
      M_inv.append(i * 6 + 2, i * 6 + 2, inv_mass);
      M_inv.finalize(i * 6 + 2);

      M_inv.append(i * 6 + 3, i * 6 + 3, body_inv_inr.GetElement(0, 0));
      M_inv.append(i * 6 + 3, i * 6 + 4, body_inv_inr.GetElement(0, 1));
      M_inv.append(i * 6 + 3, i * 6 + 5, body_inv_inr.GetElement(0, 2));
      M_inv.finalize(i * 6 + 3);
      M_inv.append(i * 6 + 4, i * 6 + 3, body_inv_inr.GetElement(1, 0));
      M_inv.append(i * 6 + 4, i * 6 + 4, body_inv_inr.GetElement(1, 1));
      M_inv.append(i * 6 + 4, i * 6 + 5, body_inv_inr.GetElement(1, 2));
      M_inv.finalize(i * 6 + 4);
      M_inv.append(i * 6 + 5, i * 6 + 3, body_inv_inr.GetElement(2, 0));
      M_inv.append(i * 6 + 5, i * 6 + 4, body_inv_inr.GetElement(2, 1));
      M_inv.append(i * 6 + 5, i * 6 + 5, body_inv_inr.GetElement(2, 2));
      M_inv.finalize(i * 6 + 5);
    }
  }

  for (int i = 0; i < num_shafts; i++) {
    M_inv.append(num_bodies * 6 + i, num_bodies * 6 + i, shaft_inr[i]);
    M_inv.finalize(num_bodies * 6 + i);
  }
  //If this experimental feature is requested compute the real mass matrix
  if(data_container->settings.solver.scale_mass_matrix){

    CompressedMatrix<real>& M = data_container->host_data.M;
    clear(M);

      // Each rigid object has 3 mass entries and 9 inertia entries
      // Each shaft has one inertia entry
      M.reserve(num_bodies * 12 + num_shafts * 1);
      // The mass matrix is square and each rigid body has 6 DOF
      // Shafts have one DOF
      M.resize(num_dof, num_dof);

      for (int i = 0; i < num_bodies; i++) {
        if (data_container->host_data.active_data[i]) {

          real mass = body_list->at(i)->GetMass();
          ChMatrix33<>&   body_inr = body_list->at(i)->VariablesBody().GetBodyInertia();

          M.append(i * 6 + 0, i * 6 + 0, mass);
          M.finalize(i * 6 + 0);
          M.append(i * 6 + 1, i * 6 + 1, mass);
          M.finalize(i * 6 + 1);
          M.append(i * 6 + 2, i * 6 + 2, mass);
          M.finalize(i * 6 + 2);

          M.append(i * 6 + 3, i * 6 + 3, body_inr.GetElement(0, 0));
          M.append(i * 6 + 3, i * 6 + 4, body_inr.GetElement(0, 1));
          M.append(i * 6 + 3, i * 6 + 5, body_inr.GetElement(0, 2));
          M.finalize(i * 6 + 3);
          M.append(i * 6 + 4, i * 6 + 3, body_inr.GetElement(1, 0));
          M.append(i * 6 + 4, i * 6 + 4, body_inr.GetElement(1, 1));
          M.append(i * 6 + 4, i * 6 + 5, body_inr.GetElement(1, 2));
          M.finalize(i * 6 + 4);
          M.append(i * 6 + 5, i * 6 + 3, body_inr.GetElement(2, 0));
          M.append(i * 6 + 5, i * 6 + 4, body_inr.GetElement(2, 1));
          M.append(i * 6 + 5, i * 6 + 5, body_inr.GetElement(2, 2));
          M.finalize(i * 6 + 5);
        }
      }
      for (int i = 0; i < num_shafts; i++) {
        M.append(num_bodies * 6 + i, num_bodies * 6 + i, 1.0/shaft_inr[i]);
        M.finalize(num_bodies * 6 + i);
      }
  }

  M_invk = v + M_inv * hf;
}

void ChLcpSolverParallel::ComputeImpulses() {
  if (data_container->num_constraints > 0) {
	  //Compute new velocity based on the lagrange multipliers
    data_container->host_data.v = data_container->host_data.M_invk + data_container->host_data.M_invD * data_container->host_data.gamma;
  } else {
	  //When there are no constraints we need to still apply gravity and other
    //body forces!
    data_container->host_data.v = data_container->host_data.M_invk;
  }
}

void ChLcpSolverParallel::PerformStabilization() {
  DynamicVector<real>& R = data_container->host_data.R;
  DynamicVector<real>& gamma = data_container->host_data.gamma;
  uint& num_unilaterals = data_container->num_unilaterals;
  uint& num_bilaterals = data_container->num_bilaterals;

  if (data_container->settings.solver.max_iteration_bilateral <= 0 || data_container->num_bilaterals <= 0) {
    return;
  }
  blaze::DenseSubvector<DynamicVector<real> > bilateral_rhs = blaze::subvector(R, num_unilaterals, num_bilaterals);
  blaze::DenseSubvector<DynamicVector<real> > bilateral_gamma = blaze::subvector(gamma, num_unilaterals, num_bilaterals);

  data_container->system_timer.start("ChLcpSolverParallel_Stab");
  solver->SolveStab(data_container->settings.solver.max_iteration_bilateral, num_bilaterals, bilateral_rhs, bilateral_gamma);
  data_container->system_timer.stop("ChLcpSolverParallel_Stab");
}
<commit_msg>re-write the compute impulses function using the new split jacobians<commit_after>#include "chrono_parallel/lcp/ChLcpSolverParallel.h"
#include "chrono_parallel/math/ChThrustLinearAlgebra.h"
#include "core/ChSpmatrix.h"
#include "physics/ChBody.h"
using namespace chrono;

ChLcpSolverParallel::ChLcpSolverParallel(ChParallelDataManager* dc)
: data_container(dc)
{
  tolerance = 1e-7;
  record_violation_history = true;
  warm_start = false;
  residual = 0;
  solver = new ChSolverAPGD();
}

ChLcpSolverParallel::~ChLcpSolverParallel()
{
  delete solver;
}

void ChLcpSolverParallel::ComputeMassMatrix()
{
  uint num_bodies = data_container->num_bodies;
  uint num_shafts = data_container->num_shafts;
  uint num_dof = data_container->num_dof;

  const custom_vector<real>& shaft_inr = data_container->host_data.shaft_inr;

  const std::vector<ChBody*> *body_list = data_container->body_list;
  const std::vector<ChLink*> *link_list= data_container->link_list;
  const std::vector<ChPhysicsItem*> *other_physics_list= data_container->other_physics_list;

  const DynamicVector<real>& hf = data_container->host_data.hf;
  const DynamicVector<real>& v = data_container->host_data.v;

  DynamicVector<real>& M_invk = data_container->host_data.M_invk;
  CompressedMatrix<real>& M_inv = data_container->host_data.M_inv;

  clear(M_inv);

  // Each rigid object has 3 mass entries and 9 inertia entries
  // Each shaft has one inertia entry
  M_inv.reserve(num_bodies * 12 + num_shafts * 1);
  // The mass matrix is square and each rigid body has 6 DOF
  // Shafts have one DOF
  M_inv.resize(num_dof, num_dof);

  for (int i = 0; i < num_bodies; i++) {

    if (data_container->host_data.active_data[i]) {
      real inv_mass = 1.0/body_list->at(i)->GetMass();
      ChMatrix33<>&   body_inv_inr = body_list->at(i)->VariablesBody().GetBodyInvInertia();

      M_inv.append(i * 6 + 0, i * 6 + 0, inv_mass);
      M_inv.finalize(i * 6 + 0);
      M_inv.append(i * 6 + 1, i * 6 + 1, inv_mass);
      M_inv.finalize(i * 6 + 1);
      M_inv.append(i * 6 + 2, i * 6 + 2, inv_mass);
      M_inv.finalize(i * 6 + 2);

      M_inv.append(i * 6 + 3, i * 6 + 3, body_inv_inr.GetElement(0, 0));
      M_inv.append(i * 6 + 3, i * 6 + 4, body_inv_inr.GetElement(0, 1));
      M_inv.append(i * 6 + 3, i * 6 + 5, body_inv_inr.GetElement(0, 2));
      M_inv.finalize(i * 6 + 3);
      M_inv.append(i * 6 + 4, i * 6 + 3, body_inv_inr.GetElement(1, 0));
      M_inv.append(i * 6 + 4, i * 6 + 4, body_inv_inr.GetElement(1, 1));
      M_inv.append(i * 6 + 4, i * 6 + 5, body_inv_inr.GetElement(1, 2));
      M_inv.finalize(i * 6 + 4);
      M_inv.append(i * 6 + 5, i * 6 + 3, body_inv_inr.GetElement(2, 0));
      M_inv.append(i * 6 + 5, i * 6 + 4, body_inv_inr.GetElement(2, 1));
      M_inv.append(i * 6 + 5, i * 6 + 5, body_inv_inr.GetElement(2, 2));
      M_inv.finalize(i * 6 + 5);
    }
  }

  for (int i = 0; i < num_shafts; i++) {
    M_inv.append(num_bodies * 6 + i, num_bodies * 6 + i, shaft_inr[i]);
    M_inv.finalize(num_bodies * 6 + i);
  }
  //If this experimental feature is requested compute the real mass matrix
  if(data_container->settings.solver.scale_mass_matrix){

    CompressedMatrix<real>& M = data_container->host_data.M;
    clear(M);

      // Each rigid object has 3 mass entries and 9 inertia entries
      // Each shaft has one inertia entry
      M.reserve(num_bodies * 12 + num_shafts * 1);
      // The mass matrix is square and each rigid body has 6 DOF
      // Shafts have one DOF
      M.resize(num_dof, num_dof);

      for (int i = 0; i < num_bodies; i++) {
        if (data_container->host_data.active_data[i]) {

          real mass = body_list->at(i)->GetMass();
          ChMatrix33<>&   body_inr = body_list->at(i)->VariablesBody().GetBodyInertia();

          M.append(i * 6 + 0, i * 6 + 0, mass);
          M.finalize(i * 6 + 0);
          M.append(i * 6 + 1, i * 6 + 1, mass);
          M.finalize(i * 6 + 1);
          M.append(i * 6 + 2, i * 6 + 2, mass);
          M.finalize(i * 6 + 2);

          M.append(i * 6 + 3, i * 6 + 3, body_inr.GetElement(0, 0));
          M.append(i * 6 + 3, i * 6 + 4, body_inr.GetElement(0, 1));
          M.append(i * 6 + 3, i * 6 + 5, body_inr.GetElement(0, 2));
          M.finalize(i * 6 + 3);
          M.append(i * 6 + 4, i * 6 + 3, body_inr.GetElement(1, 0));
          M.append(i * 6 + 4, i * 6 + 4, body_inr.GetElement(1, 1));
          M.append(i * 6 + 4, i * 6 + 5, body_inr.GetElement(1, 2));
          M.finalize(i * 6 + 4);
          M.append(i * 6 + 5, i * 6 + 3, body_inr.GetElement(2, 0));
          M.append(i * 6 + 5, i * 6 + 4, body_inr.GetElement(2, 1));
          M.append(i * 6 + 5, i * 6 + 5, body_inr.GetElement(2, 2));
          M.finalize(i * 6 + 5);
        }
      }
      for (int i = 0; i < num_shafts; i++) {
        M.append(num_bodies * 6 + i, num_bodies * 6 + i, 1.0/shaft_inr[i]);
        M.finalize(num_bodies * 6 + i);
      }
  }

  M_invk = v + M_inv * hf;
}

void ChLcpSolverParallel::ComputeImpulses() {

  DynamicVector<real>& v = data_container->host_data.v;

  const DynamicVector<real>& M_invk = data_container->host_data.M_invk;
  const DynamicVector<real>& gamma = data_container->host_data.gamma;

  const CompressedMatrix<real>& M_invD_n = data_container->host_data.M_invD_n;
  const CompressedMatrix<real>& M_invD_t = data_container->host_data.M_invD_t;
  const CompressedMatrix<real>& M_invD_r = data_container->host_data.M_invD_r;
  const CompressedMatrix<real>& M_invD_b = data_container->host_data.M_invD_b;

  uint num_contacts = data_container->num_contacts;
  uint num_unilaterals = data_container->num_unilaterals;
  uint num_bilaterals = data_container->num_bilaterals;

  if (data_container->num_constraints > 0) {

    blaze::DenseSubvector<DynamicVector<real> > gamma_b = blaze::subvector(gamma, num_unilaterals, num_bilaterals);
    blaze::DenseSubvector<DynamicVector<real> > gamma_n = blaze::subvector(gamma, 0, num_contacts);

    //Compute new velocity based on the lagrange multipliers
    switch (data_container->settings.solver.solver_mode) {
      case NORMAL: {
        v = M_invk + M_invD_n * gamma_n + M_invD_b * gamma_b;
      } break;

      case SLIDING: {
        blaze::DenseSubvector<DynamicVector<real> > gamma_t = blaze::subvector(gamma, num_contacts, num_contacts * 2);

        v = M_invk + M_invD_n * gamma_n + M_invD_t * gamma_t + M_invD_b * gamma_b;

      } break;

      case SPINNING: {
        blaze::DenseSubvector<DynamicVector<real> > gamma_t = blaze::subvector(gamma, num_contacts, num_contacts * 2);
        blaze::DenseSubvector<DynamicVector<real> > gamma_r = blaze::subvector(gamma, num_contacts * 3, num_contacts * 3);

        v = M_invk + M_invD_n * gamma_n + M_invD_t * gamma_t + M_invD_r * gamma_r + M_invD_b * gamma_b;

      } break;
    }
  } else {
	  //When there are no constraints we need to still apply gravity and other
    //body forces!
    v = M_invk;
  }
}

void ChLcpSolverParallel::PerformStabilization() {
  DynamicVector<real>& R = data_container->host_data.R;
  DynamicVector<real>& gamma = data_container->host_data.gamma;
  uint& num_unilaterals = data_container->num_unilaterals;
  uint& num_bilaterals = data_container->num_bilaterals;

  if (data_container->settings.solver.max_iteration_bilateral <= 0 || data_container->num_bilaterals <= 0) {
    return;
  }
  blaze::DenseSubvector<DynamicVector<real> > bilateral_rhs = blaze::subvector(R, num_unilaterals, num_bilaterals);
  blaze::DenseSubvector<DynamicVector<real> > bilateral_gamma = blaze::subvector(gamma, num_unilaterals, num_bilaterals);

  data_container->system_timer.start("ChLcpSolverParallel_Stab");
  solver->SolveStab(data_container->settings.solver.max_iteration_bilateral, num_bilaterals, bilateral_rhs, bilateral_gamma);
  data_container->system_timer.stop("ChLcpSolverParallel_Stab");
}
<|endoftext|>


<commit_before>#include "jstreamsconfig.h"
#include "textutils.h"

// http://www.w3.org/TR/REC-xml/#charsets
bool
jstreams::checkUtf8(const char* p, int32_t length) {
    const char* end = p + length;
    // check if the text is valid UTF-8
    char nb = 0;
    while (p < end) {
        char c = *p;
        if (nb) {
            if ((0xC0 & c) != 0x80) {
                return false;
            }
            nb--;
        } else if ((0xE0 & c) == 0xC0) {
            nb = 1;
        } else if ((0xF0 & c) == 0xE0) {
            nb = 2;
        } else if ((0xF8 & c) == 0xF0) {
            nb = 3;
        } else if (c < 0x20 && !(c == 0x9 || c == 0xA || c == 0xD)) {
            return false;
        }
        p++;
    }
    return true;
}

bool
jstreams::checkUtf8(const std::string& p) {
    return checkUtf8(p.c_str(), p.size());
}

/**
 * convert the \r and \n in utf8 strings into spaces
 **/
void
jstreams::convertNewLines(char* p) {
    int32_t len = strlen(p);
    bool ok = checkUtf8(p, len);
    if (!ok) fprintf(stderr, "string is not valid utf8\n");

    const char* end = p+len;
    char nb = 0;
    while (p < end) {
        char c = *p;
        if (nb) {
            if ((0xC0 & c) != 0x80) {
                return;
            }
            nb--;
        } else if ((0xE0 & c) == 0xC0) {
            nb = 1;
        } else if ((0xF0 & c) == 0xE0) {
            nb = 2;
        } else if ((0xF8 & c) == 0xF0) {
            nb = 3;
        } else if (c == '\n' || c == '\r') {
            *p = ' ';
        }
        p++;
    }
}

<commit_msg>Check whether a utf8 value does end on an incomplete character.<commit_after>#include "jstreamsconfig.h"
#include "textutils.h"

// http://www.w3.org/TR/REC-xml/#charsets
bool
jstreams::checkUtf8(const char* p, int32_t length) {
    const char* end = p + length;
    // check if the text is valid UTF-8
    char nb = 0;
    while (p < end) {
        char c = *p;
        if (nb) {
            if ((0xC0 & c) != 0x80) {
                return false;
            }
            nb--;
        } else if ((0xE0 & c) == 0xC0) {
            nb = 1;
        } else if ((0xF0 & c) == 0xE0) {
            nb = 2;
        } else if ((0xF8 & c) == 0xF0) {
            nb = 3;
        } else if (c < 0x20 && !(c == 0x9 || c == 0xA || c == 0xD)) {
            return false;
        }
        p++;
    }
    // the string is only valid utf8 if it contains only complete characters
    return nb == 0;
}

bool
jstreams::checkUtf8(const std::string& p) {
    return checkUtf8(p.c_str(), p.size());
}

/**
 * convert the \r and \n in utf8 strings into spaces
 **/
void
jstreams::convertNewLines(char* p) {
    int32_t len = strlen(p);
    bool ok = checkUtf8(p, len);
    if (!ok) fprintf(stderr, "string is not valid utf8\n");

    const char* end = p+len;
    char nb = 0;
    while (p < end) {
        char c = *p;
        if (nb) {
            if ((0xC0 & c) != 0x80) {
                return;
            }
            nb--;
        } else if ((0xE0 & c) == 0xC0) {
            nb = 1;
        } else if ((0xF0 & c) == 0xE0) {
            nb = 2;
        } else if ((0xF8 & c) == 0xF0) {
            nb = 3;
        } else if (c == '\n' || c == '\r') {
            *p = ' ';
        }
        p++;
    }
}

<|endoftext|>


<commit_before><commit_msg>[http] fix files reading on Windows<commit_after><|endoftext|>


<commit_before>// -----------------------------------------------------------------------------
//
// Copyright (C) 2021 CERN & Newcastle University for the benefit of the
// BioDynaMo collaboration. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
//
// See the LICENSE file distributed with this work for details.
// See the NOTICE file distributed with this work for additional information
// regarding copyright ownership.
//
// -----------------------------------------------------------------------------

#include "core/execution_context/in_place_exec_ctxt.h"

#include <algorithm>
#include <mutex>
#include <utility>

#include "core/agent/agent.h"
#include "core/environment/environment.h"
#include "core/resource_manager.h"
#include "core/scheduler.h"

namespace bdm {

InPlaceExecutionContext::ThreadSafeAgentUidMap::ThreadSafeAgentUidMap()
    : batches_(nullptr) {
  Resize(kBatchSize);
}

InPlaceExecutionContext::ThreadSafeAgentUidMap::~ThreadSafeAgentUidMap() {
  DeleteOldCopies();
  auto* non_atomic_batches = batches_.load();
  if (non_atomic_batches != nullptr) {
    for (uint64_t i = 0; i < num_batches_; ++i) {
      delete non_atomic_batches[i];
    }
    delete[] non_atomic_batches;
  }
}

void InPlaceExecutionContext::ThreadSafeAgentUidMap::Insert(
    const AgentUid& uid,
    const typename InPlaceExecutionContext::ThreadSafeAgentUidMap::value_type&
        value) {
  auto index = uid.GetIndex();
  auto bidx = index / kBatchSize;
  if (bidx >= num_batches_) {
    auto new_size =
        std::max(index, static_cast<uint32_t>(num_batches_ * kBatchSize * 1.1));
    Resize(new_size);
  }

  auto el_idx = index % kBatchSize;
  (*batches_.load()[bidx])[el_idx] = value;
}

const typename InPlaceExecutionContext::ThreadSafeAgentUidMap::value_type&
InPlaceExecutionContext::ThreadSafeAgentUidMap::operator[](
    const AgentUid& uid) {
  static InPlaceExecutionContext::ThreadSafeAgentUidMap::value_type kDefault;
  auto index = uid.GetIndex();
  auto bidx = index / kBatchSize;
  if (bidx >= num_batches_) {
    Log::Fatal("ThreadSafeAgentUidMap::operator[]",
               Concat("AgentUid out of range access: AgentUid: ", uid,
                      ", ThreadSafeAgentUidMap max index ",
                      num_batches_ * kBatchSize));
    return kDefault;
  }

  auto el_idx = index % kBatchSize;
  return (*batches_.load()[bidx])[el_idx];
}

uint64_t InPlaceExecutionContext::ThreadSafeAgentUidMap::Size() const {
  return num_batches_ * kBatchSize;
}

void InPlaceExecutionContext::ThreadSafeAgentUidMap::Resize(uint64_t new_size) {
  using Batch = InPlaceExecutionContext::ThreadSafeAgentUidMap::Batch;
  auto new_num_batches = new_size / kBatchSize + 1;
  std::lock_guard<Spinlock> guard(lock_);
  if (new_num_batches >= num_batches_) {
    auto bcopy = new Batch*[new_num_batches];
    auto** non_atomic_batches = batches_.load();
    for (uint64_t i = 0; i < new_num_batches; ++i) {
      if (i < num_batches_) {
        bcopy[i] = non_atomic_batches[i];
      } else {
        bcopy[i] = new Batch();
        bcopy[i]->reserve(kBatchSize);
      }
    }
    batches_.exchange(bcopy);
    old_copies_.push_back(non_atomic_batches);
    num_batches_ = new_num_batches;
  }
}

void InPlaceExecutionContext::ThreadSafeAgentUidMap::DeleteOldCopies() {
  for (auto& entry : old_copies_) {
    if (entry != nullptr) {
      delete[] entry;
    }
  }
  old_copies_.clear();
}

InPlaceExecutionContext::InPlaceExecutionContext(
    const std::shared_ptr<ThreadSafeAgentUidMap>& map)
    : new_agent_map_(map), tinfo_(ThreadInfo::GetInstance()) {
  new_agents_.reserve(1e3);
}

InPlaceExecutionContext::~InPlaceExecutionContext() {
  for (auto* agent : new_agents_) {
    delete agent;
  }
}

void InPlaceExecutionContext::SetupIterationAll(
    const std::vector<InPlaceExecutionContext*>& all_exec_ctxts) const {
  // first iteration might have uncommited changes
  TearDownIterationAll(all_exec_ctxts);
}

void InPlaceExecutionContext::TearDownIterationAll(
    const std::vector<InPlaceExecutionContext*>& all_exec_ctxts) const {
  // group execution contexts by numa domain
  std::vector<uint64_t> new_agent_per_numa(tinfo_->GetNumaNodes());
  std::vector<uint64_t> thread_offsets(tinfo_->GetMaxThreads());

  for (int tid = 0; tid < tinfo_->GetMaxThreads(); ++tid) {
    auto* ctxt = all_exec_ctxts[tid];
    int nid = tinfo_->GetNumaNode(tid);
    thread_offsets[tid] = new_agent_per_numa[nid];
    new_agent_per_numa[nid] += ctxt->new_agents_.size();
  }

  // reserve enough memory in ResourceManager
  std::vector<uint64_t> numa_offsets(tinfo_->GetNumaNodes());
  auto* rm = Simulation::GetActive()->GetResourceManager();
  rm->ResizeAgentUidMap();
  for (unsigned n = 0; n < new_agent_per_numa.size(); n++) {
    numa_offsets[n] = rm->GrowAgentContainer(new_agent_per_numa[n], n);
  }

// add new_agents_ to the ResourceManager in parallel
#pragma omp parallel for schedule(static, 1)
  for (int i = 0; i < tinfo_->GetMaxThreads(); i++) {
    auto* ctxt = all_exec_ctxts[i];
    int nid = tinfo_->GetNumaNode(i);
    uint64_t offset = thread_offsets[i] + numa_offsets[nid];
    rm->AddAgents(nid, offset, ctxt->new_agents_);
    ctxt->new_agents_.clear();
  }

  // remove
  for (int i = 0; i < tinfo_->GetMaxThreads(); i++) {
    auto* ctxt = all_exec_ctxts[i];
    // removed agents
    // remove them after adding new ones (maybe one has been removed
    // that was in new_agents_)
    for (auto& uid : ctxt->remove_) {
      rm->RemoveAgent(uid);
    }
    ctxt->remove_.clear();
  }

  rm->EndOfIteration();

  new_agent_map_->DeleteOldCopies();
  if (rm->GetNumAgents() > new_agent_map_->Size()) {
    new_agent_map_->Resize(rm->GetNumAgents() * 1.5);
  }
}

void InPlaceExecutionContext::Execute(
    Agent* agent, const std::vector<Operation*>& operations) {
  auto* env = Simulation::GetActive()->GetEnvironment();
  auto* param = Simulation::GetActive()->GetParam();

  if (param->thread_safety_mechanism ==
      Param::ThreadSafetyMechanism::kUserSpecified) {
    while (true) {
      critical_region_.clear();
      critical_region_2_.clear();
      locks_.clear();
      agent->CriticalRegion(&critical_region_);
      std::sort(critical_region_.begin(), critical_region_.end());
      for (auto uid : critical_region_) {
        locks_.push_back(GetAgent(uid)->GetLock());
      }
      for (auto* l : locks_) {
        l->lock();
      }
      agent->CriticalRegion(&critical_region_2_);
      std::sort(critical_region_2_.begin(), critical_region_2_.end());
      bool same = true;
      if (critical_region_.size() == critical_region_2_.size()) {
        for (int i = 0; i < critical_region_.size(); ++i) {
          if (critical_region_[i] != critical_region_2_[i]) {
            same = false;
            break;
          }
        }
      } else {
        same = false;
      }
      if (same) {
        break;
      }
      for (auto* l : locks_) {
        l->unlock();
      }
    }
    neighbor_cache_.clear();
    for (auto& op : operations) {
      (*op)(agent);
    }
    for (auto* l : locks_) {
      l->unlock();
    }
  } else if (param->thread_safety_mechanism ==
             Param::ThreadSafetyMechanism::kAutomatic) {
    auto* nb_mutex_builder = env->GetNeighborMutexBuilder();
    auto* mutex = nb_mutex_builder->GetMutex(agent->GetBoxIdx());
    std::lock_guard<decltype(*mutex)> guard(*mutex);
    neighbor_cache_.clear();
    for (auto* op : operations) {
      (*op)(agent);
    }
  } else if (param->thread_safety_mechanism ==
             Param::ThreadSafetyMechanism::kNone) {
    neighbor_cache_.clear();
    for (auto* op : operations) {
      (*op)(agent);
    }
  } else {
    Log::Fatal("InPlaceExecutionContext::Execute",
               "Invalid value for parameter thread_safety_mechanism: ",
               param->thread_safety_mechanism);
  }
}

void InPlaceExecutionContext::AddAgent(Agent* new_agent) {
  new_agents_.push_back(new_agent);
  auto timesteps = Simulation::GetActive()->GetScheduler()->GetSimulatedSteps();
  new_agent_map_->Insert(new_agent->GetUid(), {new_agent, timesteps});
}

struct ForEachNeighborFunctor : public Functor<void, const Agent*, double> {
  const Param* param = Simulation::GetActive()->GetParam();
  Functor<void, const Agent*, double>& function_;
  std::vector<std::pair<const Agent*, double>>& neighbor_cache_;

  ForEachNeighborFunctor(
      Functor<void, const Agent*, double>& function,
      std::vector<std::pair<const Agent*, double>>& neigbor_cache)
      : function_(function), neighbor_cache_(neigbor_cache) {}

  void operator()(const Agent* agent, double squared_distance) override {
    if (param->cache_neighbors) {
      neighbor_cache_.push_back(std::make_pair(agent, squared_distance));
    }
    function_(agent, squared_distance);
  }
};

void InPlaceExecutionContext::ForEachNeighbor(
    Functor<void, const Agent*, double>& lambda, const Agent& query) {
  // use values in cache
  if (neighbor_cache_.size() != 0) {
    for (auto& pair : neighbor_cache_) {
      lambda(pair.first, pair.second);
    }
    return;
  }

  // forward call to env and populate cache
  auto* env = Simulation::GetActive()->GetEnvironment();
  ForEachNeighborFunctor for_each(lambda, neighbor_cache_);
  env->ForEachNeighbor(for_each, query);
}

struct ForEachNeighborWithinRadiusFunctor
    : public Functor<void, const Agent*, double> {
  const Param* param = Simulation::GetActive()->GetParam();
  Functor<void, const Agent*, double>& function_;
  std::vector<std::pair<const Agent*, double>>& neighbor_cache_;
  double squared_radius_ = 0;

  ForEachNeighborWithinRadiusFunctor(
      Functor<void, const Agent*, double>& function,
      std::vector<std::pair<const Agent*, double>>& neigbor_cache,
      double squared_radius)
      : function_(function),
        neighbor_cache_(neigbor_cache),
        squared_radius_(squared_radius) {}

  void operator()(const Agent* agent, double squared_distance) override {
    if (param->cache_neighbors) {
      neighbor_cache_.push_back(std::make_pair(agent, squared_distance));
    }
    if (squared_distance < squared_radius_) {
      function_(agent, 0);
    }
  }
};

void InPlaceExecutionContext::ForEachNeighborWithinRadius(
    Functor<void, const Agent*, double>& lambda, const Agent& query,
    double squared_radius) {
  // use values in cache
  if (neighbor_cache_.size() != 0) {
    for (auto& pair : neighbor_cache_) {
      if (pair.second < squared_radius) {
        lambda(pair.first, 0);
      }
    }
    return;
  }

  // forward call to env and populate cache
  auto* env = Simulation::GetActive()->GetEnvironment();

  ForEachNeighborWithinRadiusFunctor for_each(lambda, neighbor_cache_,
                                              squared_radius);
  env->ForEachNeighbor(for_each, query);
}

Agent* InPlaceExecutionContext::GetAgent(const AgentUid& uid) {
  auto* sim = Simulation::GetActive();
  auto* rm = sim->GetResourceManager();
  auto* agent = rm->GetAgent(uid);
  if (agent != nullptr) {
    return agent;
  }

  // returns nullptr if the object is not found
  return (*new_agent_map_)[uid].first;
}

const Agent* InPlaceExecutionContext::GetConstAgent(const AgentUid& uid) {
  return GetAgent(uid);
}

void InPlaceExecutionContext::RemoveFromSimulation(const AgentUid& uid) {
  remove_.push_back(uid);
}

// TODO(lukas) Add tests for caching mechanism in ForEachNeighbor*

}  // namespace bdm
<commit_msg>Fix warning of integer expression of different signedness<commit_after>// -----------------------------------------------------------------------------
//
// Copyright (C) 2021 CERN & Newcastle University for the benefit of the
// BioDynaMo collaboration. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
//
// See the LICENSE file distributed with this work for details.
// See the NOTICE file distributed with this work for additional information
// regarding copyright ownership.
//
// -----------------------------------------------------------------------------

#include "core/execution_context/in_place_exec_ctxt.h"

#include <algorithm>
#include <mutex>
#include <utility>

#include "core/agent/agent.h"
#include "core/environment/environment.h"
#include "core/resource_manager.h"
#include "core/scheduler.h"

namespace bdm {

InPlaceExecutionContext::ThreadSafeAgentUidMap::ThreadSafeAgentUidMap()
    : batches_(nullptr) {
  Resize(kBatchSize);
}

InPlaceExecutionContext::ThreadSafeAgentUidMap::~ThreadSafeAgentUidMap() {
  DeleteOldCopies();
  auto* non_atomic_batches = batches_.load();
  if (non_atomic_batches != nullptr) {
    for (uint64_t i = 0; i < num_batches_; ++i) {
      delete non_atomic_batches[i];
    }
    delete[] non_atomic_batches;
  }
}

void InPlaceExecutionContext::ThreadSafeAgentUidMap::Insert(
    const AgentUid& uid,
    const typename InPlaceExecutionContext::ThreadSafeAgentUidMap::value_type&
        value) {
  auto index = uid.GetIndex();
  auto bidx = index / kBatchSize;
  if (bidx >= num_batches_) {
    auto new_size =
        std::max(index, static_cast<uint32_t>(num_batches_ * kBatchSize * 1.1));
    Resize(new_size);
  }

  auto el_idx = index % kBatchSize;
  (*batches_.load()[bidx])[el_idx] = value;
}

const typename InPlaceExecutionContext::ThreadSafeAgentUidMap::value_type&
InPlaceExecutionContext::ThreadSafeAgentUidMap::operator[](
    const AgentUid& uid) {
  static InPlaceExecutionContext::ThreadSafeAgentUidMap::value_type kDefault;
  auto index = uid.GetIndex();
  auto bidx = index / kBatchSize;
  if (bidx >= num_batches_) {
    Log::Fatal("ThreadSafeAgentUidMap::operator[]",
               Concat("AgentUid out of range access: AgentUid: ", uid,
                      ", ThreadSafeAgentUidMap max index ",
                      num_batches_ * kBatchSize));
    return kDefault;
  }

  auto el_idx = index % kBatchSize;
  return (*batches_.load()[bidx])[el_idx];
}

uint64_t InPlaceExecutionContext::ThreadSafeAgentUidMap::Size() const {
  return num_batches_ * kBatchSize;
}

void InPlaceExecutionContext::ThreadSafeAgentUidMap::Resize(uint64_t new_size) {
  using Batch = InPlaceExecutionContext::ThreadSafeAgentUidMap::Batch;
  auto new_num_batches = new_size / kBatchSize + 1;
  std::lock_guard<Spinlock> guard(lock_);
  if (new_num_batches >= num_batches_) {
    auto bcopy = new Batch*[new_num_batches];
    auto** non_atomic_batches = batches_.load();
    for (uint64_t i = 0; i < new_num_batches; ++i) {
      if (i < num_batches_) {
        bcopy[i] = non_atomic_batches[i];
      } else {
        bcopy[i] = new Batch();
        bcopy[i]->reserve(kBatchSize);
      }
    }
    batches_.exchange(bcopy);
    old_copies_.push_back(non_atomic_batches);
    num_batches_ = new_num_batches;
  }
}

void InPlaceExecutionContext::ThreadSafeAgentUidMap::DeleteOldCopies() {
  for (auto& entry : old_copies_) {
    if (entry != nullptr) {
      delete[] entry;
    }
  }
  old_copies_.clear();
}

InPlaceExecutionContext::InPlaceExecutionContext(
    const std::shared_ptr<ThreadSafeAgentUidMap>& map)
    : new_agent_map_(map), tinfo_(ThreadInfo::GetInstance()) {
  new_agents_.reserve(1e3);
}

InPlaceExecutionContext::~InPlaceExecutionContext() {
  for (auto* agent : new_agents_) {
    delete agent;
  }
}

void InPlaceExecutionContext::SetupIterationAll(
    const std::vector<InPlaceExecutionContext*>& all_exec_ctxts) const {
  // first iteration might have uncommited changes
  TearDownIterationAll(all_exec_ctxts);
}

void InPlaceExecutionContext::TearDownIterationAll(
    const std::vector<InPlaceExecutionContext*>& all_exec_ctxts) const {
  // group execution contexts by numa domain
  std::vector<uint64_t> new_agent_per_numa(tinfo_->GetNumaNodes());
  std::vector<uint64_t> thread_offsets(tinfo_->GetMaxThreads());

  for (int tid = 0; tid < tinfo_->GetMaxThreads(); ++tid) {
    auto* ctxt = all_exec_ctxts[tid];
    int nid = tinfo_->GetNumaNode(tid);
    thread_offsets[tid] = new_agent_per_numa[nid];
    new_agent_per_numa[nid] += ctxt->new_agents_.size();
  }

  // reserve enough memory in ResourceManager
  std::vector<uint64_t> numa_offsets(tinfo_->GetNumaNodes());
  auto* rm = Simulation::GetActive()->GetResourceManager();
  rm->ResizeAgentUidMap();
  for (unsigned n = 0; n < new_agent_per_numa.size(); n++) {
    numa_offsets[n] = rm->GrowAgentContainer(new_agent_per_numa[n], n);
  }

// add new_agents_ to the ResourceManager in parallel
#pragma omp parallel for schedule(static, 1)
  for (int i = 0; i < tinfo_->GetMaxThreads(); i++) {
    auto* ctxt = all_exec_ctxts[i];
    int nid = tinfo_->GetNumaNode(i);
    uint64_t offset = thread_offsets[i] + numa_offsets[nid];
    rm->AddAgents(nid, offset, ctxt->new_agents_);
    ctxt->new_agents_.clear();
  }

  // remove
  for (int i = 0; i < tinfo_->GetMaxThreads(); i++) {
    auto* ctxt = all_exec_ctxts[i];
    // removed agents
    // remove them after adding new ones (maybe one has been removed
    // that was in new_agents_)
    for (auto& uid : ctxt->remove_) {
      rm->RemoveAgent(uid);
    }
    ctxt->remove_.clear();
  }

  rm->EndOfIteration();

  new_agent_map_->DeleteOldCopies();
  if (rm->GetNumAgents() > new_agent_map_->Size()) {
    new_agent_map_->Resize(rm->GetNumAgents() * 1.5);
  }
}

void InPlaceExecutionContext::Execute(
    Agent* agent, const std::vector<Operation*>& operations) {
  auto* env = Simulation::GetActive()->GetEnvironment();
  auto* param = Simulation::GetActive()->GetParam();

  if (param->thread_safety_mechanism ==
      Param::ThreadSafetyMechanism::kUserSpecified) {
    while (true) {
      critical_region_.clear();
      critical_region_2_.clear();
      locks_.clear();
      agent->CriticalRegion(&critical_region_);
      std::sort(critical_region_.begin(), critical_region_.end());
      for (auto uid : critical_region_) {
        locks_.push_back(GetAgent(uid)->GetLock());
      }
      for (auto* l : locks_) {
        l->lock();
      }
      agent->CriticalRegion(&critical_region_2_);
      std::sort(critical_region_2_.begin(), critical_region_2_.end());
      bool same = true;
      if (critical_region_.size() == critical_region_2_.size()) {
        for (size_t i = 0; i < critical_region_.size(); ++i) {
          if (critical_region_[i] != critical_region_2_[i]) {
            same = false;
            break;
          }
        }
      } else {
        same = false;
      }
      if (same) {
        break;
      }
      for (auto* l : locks_) {
        l->unlock();
      }
    }
    neighbor_cache_.clear();
    for (auto& op : operations) {
      (*op)(agent);
    }
    for (auto* l : locks_) {
      l->unlock();
    }
  } else if (param->thread_safety_mechanism ==
             Param::ThreadSafetyMechanism::kAutomatic) {
    auto* nb_mutex_builder = env->GetNeighborMutexBuilder();
    auto* mutex = nb_mutex_builder->GetMutex(agent->GetBoxIdx());
    std::lock_guard<decltype(*mutex)> guard(*mutex);
    neighbor_cache_.clear();
    for (auto* op : operations) {
      (*op)(agent);
    }
  } else if (param->thread_safety_mechanism ==
             Param::ThreadSafetyMechanism::kNone) {
    neighbor_cache_.clear();
    for (auto* op : operations) {
      (*op)(agent);
    }
  } else {
    Log::Fatal("InPlaceExecutionContext::Execute",
               "Invalid value for parameter thread_safety_mechanism: ",
               param->thread_safety_mechanism);
  }
}

void InPlaceExecutionContext::AddAgent(Agent* new_agent) {
  new_agents_.push_back(new_agent);
  auto timesteps = Simulation::GetActive()->GetScheduler()->GetSimulatedSteps();
  new_agent_map_->Insert(new_agent->GetUid(), {new_agent, timesteps});
}

struct ForEachNeighborFunctor : public Functor<void, const Agent*, double> {
  const Param* param = Simulation::GetActive()->GetParam();
  Functor<void, const Agent*, double>& function_;
  std::vector<std::pair<const Agent*, double>>& neighbor_cache_;

  ForEachNeighborFunctor(
      Functor<void, const Agent*, double>& function,
      std::vector<std::pair<const Agent*, double>>& neigbor_cache)
      : function_(function), neighbor_cache_(neigbor_cache) {}

  void operator()(const Agent* agent, double squared_distance) override {
    if (param->cache_neighbors) {
      neighbor_cache_.push_back(std::make_pair(agent, squared_distance));
    }
    function_(agent, squared_distance);
  }
};

void InPlaceExecutionContext::ForEachNeighbor(
    Functor<void, const Agent*, double>& lambda, const Agent& query) {
  // use values in cache
  if (neighbor_cache_.size() != 0) {
    for (auto& pair : neighbor_cache_) {
      lambda(pair.first, pair.second);
    }
    return;
  }

  // forward call to env and populate cache
  auto* env = Simulation::GetActive()->GetEnvironment();
  ForEachNeighborFunctor for_each(lambda, neighbor_cache_);
  env->ForEachNeighbor(for_each, query);
}

struct ForEachNeighborWithinRadiusFunctor
    : public Functor<void, const Agent*, double> {
  const Param* param = Simulation::GetActive()->GetParam();
  Functor<void, const Agent*, double>& function_;
  std::vector<std::pair<const Agent*, double>>& neighbor_cache_;
  double squared_radius_ = 0;

  ForEachNeighborWithinRadiusFunctor(
      Functor<void, const Agent*, double>& function,
      std::vector<std::pair<const Agent*, double>>& neigbor_cache,
      double squared_radius)
      : function_(function),
        neighbor_cache_(neigbor_cache),
        squared_radius_(squared_radius) {}

  void operator()(const Agent* agent, double squared_distance) override {
    if (param->cache_neighbors) {
      neighbor_cache_.push_back(std::make_pair(agent, squared_distance));
    }
    if (squared_distance < squared_radius_) {
      function_(agent, 0);
    }
  }
};

void InPlaceExecutionContext::ForEachNeighborWithinRadius(
    Functor<void, const Agent*, double>& lambda, const Agent& query,
    double squared_radius) {
  // use values in cache
  if (neighbor_cache_.size() != 0) {
    for (auto& pair : neighbor_cache_) {
      if (pair.second < squared_radius) {
        lambda(pair.first, 0);
      }
    }
    return;
  }

  // forward call to env and populate cache
  auto* env = Simulation::GetActive()->GetEnvironment();

  ForEachNeighborWithinRadiusFunctor for_each(lambda, neighbor_cache_,
                                              squared_radius);
  env->ForEachNeighbor(for_each, query);
}

Agent* InPlaceExecutionContext::GetAgent(const AgentUid& uid) {
  auto* sim = Simulation::GetActive();
  auto* rm = sim->GetResourceManager();
  auto* agent = rm->GetAgent(uid);
  if (agent != nullptr) {
    return agent;
  }

  // returns nullptr if the object is not found
  return (*new_agent_map_)[uid].first;
}

const Agent* InPlaceExecutionContext::GetConstAgent(const AgentUid& uid) {
  return GetAgent(uid);
}

void InPlaceExecutionContext::RemoveFromSimulation(const AgentUid& uid) {
  remove_.push_back(uid);
}

// TODO(lukas) Add tests for caching mechanism in ForEachNeighbor*

}  // namespace bdm
<|endoftext|>


<commit_before>#include "scene_view.h"
#include "core/crc32.h"
#include "core/profiler.h"
#include "core/resource_manager.h"
#include "editor/gizmo.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "ocornut-imgui/imgui.h"
#include "renderer/frame_buffer.h"
#include "renderer/pipeline.h"
#include "renderer/render_scene.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

static const char* WINDOW_NAME = "Scene view";

SceneView::SceneView()
{
	m_pipeline = nullptr;
	m_editor = nullptr;
	m_camera_speed = 0.1f;
}

SceneView::~SceneView()
{
}

void SceneView::setWireframe(bool wireframe)
{
	m_pipeline->setWireframe(wireframe);
}

void SceneView::setScene(Lumix::RenderScene* scene)
{
	m_pipeline->setScene(scene);
}

void SceneView::shutdown()
{
	Lumix::PipelineInstance::destroy(m_pipeline);
	auto* pipeline_manager =
		m_pipeline_source->getResourceManager().get(Lumix::ResourceManager::PIPELINE);
	pipeline_manager->unload(*m_pipeline_source);
}

void SceneView::onUniverseCreated()
{
	auto* scene = m_editor->getScene(Lumix::crc32("renderer"));
	m_pipeline->setScene(static_cast<Lumix::RenderScene*>(scene));
}

void SceneView::onUniverseDestroyed()
{
	m_pipeline->setScene(nullptr);
}

bool SceneView::init(Lumix::WorldEditor& editor, Lumix::Array<Action*>& actions)
{
	m_editor = &editor;
	auto& engine = editor.getEngine();
	auto& allocator = engine.getAllocator();
	auto* pipeline_manager = engine.getResourceManager().get(Lumix::ResourceManager::PIPELINE);

	m_pipeline_source =
		static_cast<Lumix::Pipeline*>(pipeline_manager->load(Lumix::Path("pipelines/main.lua")));
	m_pipeline = Lumix::PipelineInstance::create(*m_pipeline_source, allocator);
	m_pipeline->addCustomCommandHandler("render_gizmos")
		.bind<SceneView, &SceneView::renderGizmos>(this);

	editor.universeCreated().bind<SceneView, &SceneView::onUniverseCreated>(this);
	editor.universeDestroyed().bind<SceneView, &SceneView::onUniverseDestroyed>(this);
	onUniverseCreated();

	m_toggle_gizmo_step_action =
		LUMIX_NEW(editor.getAllocator(), Action)("Enable/disable gizmo step", "toggleGizmoStep");
	m_toggle_gizmo_step_action->is_global = false;

	actions.push(m_toggle_gizmo_step_action);

	return true;
}

void SceneView::update()
{
	PROFILE_FUNCTION();
	if (ImGui::IsAnyItemActive()) return;
	if (!m_is_opened) return;
	if (ImGui::GetIO().KeysDown[VK_CONTROL]) return;

	m_camera_speed =
		Lumix::Math::maxValue(0.01f, m_camera_speed + ImGui::GetIO().MouseWheel / 20.0f);

	int screen_x = int(ImGui::GetIO().MousePos.x);
	int screen_y = int(ImGui::GetIO().MousePos.y);
	bool is_inside = screen_x >= m_screen_x && screen_y >= m_screen_y &&
					 screen_x <= m_screen_x + m_width && screen_y <= m_screen_y + m_height;
	if (!is_inside) return;

	float speed = m_camera_speed;
	if (ImGui::GetIO().KeysDown[VK_SHIFT])
	{
		speed *= 10;
	}
	if (ImGui::GetIO().KeysDown['W'])
	{
		m_editor->navigate(1.0f, 0, speed);
	}
	if (ImGui::GetIO().KeysDown['S'])
	{
		m_editor->navigate(-1.0f, 0, speed);
	}
	if (ImGui::GetIO().KeysDown['A'])
	{
		m_editor->navigate(0.0f, -1.0f, speed);
	}
	if (ImGui::GetIO().KeysDown['D'])
	{
		m_editor->navigate(0.0f, 1.0f, speed);
	}
}

void SceneView::renderGizmos()
{
	m_editor->renderIcons(*m_pipeline);
	m_editor->getGizmo().updateScale(m_editor->getEditCamera().index);
	m_editor->getGizmo().render(*m_pipeline);
}

void SceneView::onMouseUp(Lumix::MouseButton::Value button)
{
	auto pos = ImGui::GetIO().MousePos;
	m_editor->onMouseUp(int(pos.x) - m_screen_x, int(pos.y) - m_screen_y, button);
}

bool SceneView::onMouseDown(int screen_x, int screen_y, Lumix::MouseButton::Value button)
{
	if (!m_is_mouse_hovering_window) return false;

	bool is_inside = screen_x >= m_screen_x && screen_y >= m_screen_y &&
					 screen_x <= m_screen_x + m_width && screen_y <= m_screen_y + m_height;

	if (!is_inside) return false;

	ImGui::ResetActiveID();
	ImGui::SetWindowFocus(WINDOW_NAME);
	m_editor->onMouseDown(screen_x - m_screen_x, screen_y - m_screen_y, button);

	return true;
}

void SceneView::onMouseMove(int mouse_screen_x, int mouse_screen_y, int rel_x, int rel_y)
{
	m_editor->setGizmoUseStep(m_toggle_gizmo_step_action->isActive());
	m_editor->onMouseMove(mouse_screen_x - m_screen_x, mouse_screen_y - m_screen_y, rel_x, rel_y);
}

void SceneView::onGUI()
{
	PROFILE_FUNCTION();
	m_is_opened = false;
	m_is_mouse_hovering_window = false;
	if (ImGui::Begin(WINDOW_NAME))
	{
		m_is_mouse_hovering_window = ImGui::IsMouseHoveringWindow();
		m_is_opened = true;
		auto size = ImGui::GetContentRegionAvail();
		size.y -= ImGui::GetTextLineHeightWithSpacing();
		if (size.x > 0 && size.y > 0)
		{
			auto pos = ImGui::GetWindowPos();
			auto cp = ImGui::GetCursorPos();
			m_pipeline->setViewport(0, 0, int(size.x), int(size.y));
			auto* fb = m_pipeline->getFramebuffer("default");
			m_texture_handle = fb->getRenderbufferHandle(0);
			auto cursor_pos = ImGui::GetCursorScreenPos();
			m_screen_x = int(cursor_pos.x);
			m_screen_y = int(cursor_pos.y);
			m_width = int(size.x);
			m_height = int(size.y);
			ImGui::Image(&m_texture_handle, size);

			m_pipeline->render();
		}
	}

	ImGui::PushItemWidth(60);
	ImGui::DragFloat("Camera speed", &m_camera_speed, 0.1f, 0.01f, 999.0f, "%.2f");
	ImGui::SameLine();
	if (m_editor->isMeasureToolActive())
	{
		ImGui::Text("| Measured distance: %f", m_editor->getMeasuredDistance());
	}

	ImGui::SameLine();
	int step = m_editor->getGizmo().getStep();
	if (ImGui::DragInt("Gizmo step", &step, 1.0f, 0, 200))
	{
		m_editor->getGizmo().setStep(step);
	}

	ImGui::End();
}<commit_msg>refactor<commit_after>#include "scene_view.h"
#include "core/crc32.h"
#include "core/profiler.h"
#include "core/resource_manager.h"
#include "editor/gizmo.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "ocornut-imgui/imgui.h"
#include "renderer/frame_buffer.h"
#include "renderer/pipeline.h"
#include "renderer/render_scene.h"

static const char* WINDOW_NAME = "Scene view";

SceneView::SceneView()
{
	m_pipeline = nullptr;
	m_editor = nullptr;
	m_camera_speed = 0.1f;
}

SceneView::~SceneView()
{
}

void SceneView::setWireframe(bool wireframe)
{
	m_pipeline->setWireframe(wireframe);
}

void SceneView::setScene(Lumix::RenderScene* scene)
{
	m_pipeline->setScene(scene);
}

void SceneView::shutdown()
{
	Lumix::PipelineInstance::destroy(m_pipeline);
	auto* pipeline_manager =
		m_pipeline_source->getResourceManager().get(Lumix::ResourceManager::PIPELINE);
	pipeline_manager->unload(*m_pipeline_source);
}

void SceneView::onUniverseCreated()
{
	auto* scene = m_editor->getScene(Lumix::crc32("renderer"));
	m_pipeline->setScene(static_cast<Lumix::RenderScene*>(scene));
}

void SceneView::onUniverseDestroyed()
{
	m_pipeline->setScene(nullptr);
}

bool SceneView::init(Lumix::WorldEditor& editor, Lumix::Array<Action*>& actions)
{
	m_editor = &editor;
	auto& engine = editor.getEngine();
	auto& allocator = engine.getAllocator();
	auto* pipeline_manager = engine.getResourceManager().get(Lumix::ResourceManager::PIPELINE);

	m_pipeline_source =
		static_cast<Lumix::Pipeline*>(pipeline_manager->load(Lumix::Path("pipelines/main.lua")));
	m_pipeline = Lumix::PipelineInstance::create(*m_pipeline_source, allocator);
	m_pipeline->addCustomCommandHandler("render_gizmos")
		.bind<SceneView, &SceneView::renderGizmos>(this);

	editor.universeCreated().bind<SceneView, &SceneView::onUniverseCreated>(this);
	editor.universeDestroyed().bind<SceneView, &SceneView::onUniverseDestroyed>(this);
	onUniverseCreated();

	m_toggle_gizmo_step_action =
		LUMIX_NEW(editor.getAllocator(), Action)("Enable/disable gizmo step", "toggleGizmoStep");
	m_toggle_gizmo_step_action->is_global = false;

	actions.push(m_toggle_gizmo_step_action);

	return true;
}

void SceneView::update()
{
	PROFILE_FUNCTION();
	if (ImGui::IsAnyItemActive()) return;
	if (!m_is_opened) return;
	if (ImGui::GetIO().KeyCtrl) return;

	m_camera_speed =
		Lumix::Math::maxValue(0.01f, m_camera_speed + ImGui::GetIO().MouseWheel / 20.0f);

	int screen_x = int(ImGui::GetIO().MousePos.x);
	int screen_y = int(ImGui::GetIO().MousePos.y);
	bool is_inside = screen_x >= m_screen_x && screen_y >= m_screen_y &&
					 screen_x <= m_screen_x + m_width && screen_y <= m_screen_y + m_height;
	if (!is_inside) return;

	float speed = m_camera_speed;
	if (ImGui::GetIO().KeyShift)
	{
		speed *= 10;
	}
	if (ImGui::GetIO().KeysDown['W'])
	{
		m_editor->navigate(1.0f, 0, speed);
	}
	if (ImGui::GetIO().KeysDown['S'])
	{
		m_editor->navigate(-1.0f, 0, speed);
	}
	if (ImGui::GetIO().KeysDown['A'])
	{
		m_editor->navigate(0.0f, -1.0f, speed);
	}
	if (ImGui::GetIO().KeysDown['D'])
	{
		m_editor->navigate(0.0f, 1.0f, speed);
	}
}

void SceneView::renderGizmos()
{
	m_editor->renderIcons(*m_pipeline);
	m_editor->getGizmo().updateScale(m_editor->getEditCamera().index);
	m_editor->getGizmo().render(*m_pipeline);
}

void SceneView::onMouseUp(Lumix::MouseButton::Value button)
{
	auto pos = ImGui::GetIO().MousePos;
	m_editor->onMouseUp(int(pos.x) - m_screen_x, int(pos.y) - m_screen_y, button);
}

bool SceneView::onMouseDown(int screen_x, int screen_y, Lumix::MouseButton::Value button)
{
	if (!m_is_mouse_hovering_window) return false;

	bool is_inside = screen_x >= m_screen_x && screen_y >= m_screen_y &&
					 screen_x <= m_screen_x + m_width && screen_y <= m_screen_y + m_height;

	if (!is_inside) return false;

	ImGui::ResetActiveID();
	ImGui::SetWindowFocus(WINDOW_NAME);
	m_editor->onMouseDown(screen_x - m_screen_x, screen_y - m_screen_y, button);

	return true;
}

void SceneView::onMouseMove(int mouse_screen_x, int mouse_screen_y, int rel_x, int rel_y)
{
	m_editor->setGizmoUseStep(m_toggle_gizmo_step_action->isActive());
	m_editor->onMouseMove(mouse_screen_x - m_screen_x, mouse_screen_y - m_screen_y, rel_x, rel_y);
}

void SceneView::onGUI()
{
	PROFILE_FUNCTION();
	m_is_opened = false;
	m_is_mouse_hovering_window = false;
	if (ImGui::Begin(WINDOW_NAME))
	{
		m_is_mouse_hovering_window = ImGui::IsMouseHoveringWindow();
		m_is_opened = true;
		auto size = ImGui::GetContentRegionAvail();
		size.y -= ImGui::GetTextLineHeightWithSpacing();
		if (size.x > 0 && size.y > 0)
		{
			auto pos = ImGui::GetWindowPos();
			auto cp = ImGui::GetCursorPos();
			m_pipeline->setViewport(0, 0, int(size.x), int(size.y));
			auto* fb = m_pipeline->getFramebuffer("default");
			m_texture_handle = fb->getRenderbufferHandle(0);
			auto cursor_pos = ImGui::GetCursorScreenPos();
			m_screen_x = int(cursor_pos.x);
			m_screen_y = int(cursor_pos.y);
			m_width = int(size.x);
			m_height = int(size.y);
			ImGui::Image(&m_texture_handle, size);

			m_pipeline->render();
		}
	}

	ImGui::PushItemWidth(60);
	ImGui::DragFloat("Camera speed", &m_camera_speed, 0.1f, 0.01f, 999.0f, "%.2f");
	ImGui::SameLine();
	if (m_editor->isMeasureToolActive())
	{
		ImGui::Text("| Measured distance: %f", m_editor->getMeasuredDistance());
	}

	ImGui::SameLine();
	int step = m_editor->getGizmo().getStep();
	if (ImGui::DragInt("Gizmo step", &step, 1.0f, 0, 200))
	{
		m_editor->getGizmo().setStep(step);
	}

	ImGui::End();
}<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/dom_ui/system_settings_provider.h"

#include <string>

#include "app/l10n_util.h"
#include "base/i18n/rtl.h"
#include "base/lock.h"
#include "base/scoped_ptr.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros_settings.h"
#include "chrome/browser/chromeos/cros_settings_names.h"
#include "grit/generated_resources.h"
#include "unicode/calendar.h"
#include "unicode/timezone.h"
#include "unicode/ures.h"

namespace {

// TODO(jungshik): Using Enumerate method in ICU gives 600+ timezones.
// Even after filtering out duplicate entries with a strict identity check,
// we still have 400+ zones. Relaxing the criteria for the timezone
// identity is likely to cut down the number to < 100. Until we
// come up with a better list, we hard-code the following list as used by
// Android.
static const char* kTimeZones[] = {
    "Pacific/Majuro",
    "Pacific/Midway",
    "Pacific/Honolulu",
    "America/Anchorage",
    "America/Los_Angeles",
    "America/Tijuana",
    "America/Denver",
    "America/Phoenix",
    "America/Chihuahua",
    "America/Chicago",
    "America/Mexico_City",
    "America/Costa_Rica",
    "America/Regina",
    "America/New_York",
    "America/Bogota",
    "America/Caracas",
    "America/Barbados",
    "America/Manaus",
    "America/Santiago",
    "America/St_Johns",
    "America/Sao_Paulo",
    "America/Araguaina",
    "America/Argentina/Buenos_Aires",
    "America/Godthab",
    "America/Montevideo",
    "Atlantic/South_Georgia",
    "Atlantic/Azores",
    "Atlantic/Cape_Verde",
    "Africa/Casablanca",
    "Europe/London",
    "Europe/Amsterdam",
    "Europe/Belgrade",
    "Europe/Brussels",
    "Europe/Sarajevo",
    "Africa/Windhoek",
    "Africa/Brazzaville",
    "Asia/Amman",
    "Europe/Athens",
    "Asia/Beirut",
    "Africa/Cairo",
    "Europe/Helsinki",
    "Asia/Jerusalem",
    "Europe/Minsk",
    "Africa/Harare",
    "Asia/Baghdad",
    "Europe/Moscow",
    "Asia/Kuwait",
    "Africa/Nairobi",
    "Asia/Tehran",
    "Asia/Baku",
    "Asia/Tbilisi",
    "Asia/Yerevan",
    "Asia/Dubai",
    "Asia/Kabul",
    "Asia/Karachi",
    "Asia/Oral",
    "Asia/Yekaterinburg",
    "Asia/Calcutta",
    "Asia/Colombo",
    "Asia/Katmandu",
    "Asia/Almaty",
    "Asia/Rangoon",
    "Asia/Krasnoyarsk",
    "Asia/Bangkok",
    "Asia/Shanghai",
    "Asia/Hong_Kong",
    "Asia/Irkutsk",
    "Asia/Kuala_Lumpur",
    "Australia/Perth",
    "Asia/Taipei",
    "Asia/Seoul",
    "Asia/Tokyo",
    "Asia/Yakutsk",
    "Australia/Adelaide",
    "Australia/Darwin",
    "Australia/Brisbane",
    "Australia/Hobart",
    "Australia/Sydney",
    "Asia/Vladivostok",
    "Pacific/Guam",
    "Asia/Magadan",
    "Pacific/Auckland",
    "Pacific/Fiji",
    "Pacific/Tongatapu",
};

static Lock timezone_bundle_lock;

struct UResClose {
  inline void operator() (UResourceBundle* b) const {
    ures_close(b);
  }
};

string16 GetExemplarCity(const icu::TimeZone& zone) {
  // TODO(jungshik): After upgrading to ICU 4.6, use U_ICUDATA_ZONE
  static const char* zone_bundle_name = NULL;

  // These will be leaked at the end.
  static UResourceBundle *zone_bundle = NULL;
  static UResourceBundle *zone_strings = NULL;

  UErrorCode status = U_ZERO_ERROR;
  {
    AutoLock lock(timezone_bundle_lock);
    if (zone_bundle == NULL)
      zone_bundle = ures_open(zone_bundle_name, uloc_getDefault(), &status);

    if (zone_strings == NULL)
      zone_strings = ures_getByKey(zone_bundle, "zone_strings", NULL, &status);
  }

  UnicodeString zone_id;
  zone.getID(zone_id);
  std::string zone_id_str;
  zone_id.toUTF8String(zone_id_str);

  // resource keys for timezones use ':' in place of '/'.
  ReplaceSubstringsAfterOffset(&zone_id_str, 0, "/", ":");
  scoped_ptr_malloc<UResourceBundle, UResClose> zone_item(
      ures_getByKey(zone_strings, zone_id_str.c_str(), NULL, &status));
  UnicodeString city;
  if (U_FAILURE(status))
    goto fallback;
  city = ures_getUnicodeStringByKey(zone_item.get(), "ec", &status);
  if (U_SUCCESS(status))
    return string16(city.getBuffer(), city.length());

 fallback:
  ReplaceSubstringsAfterOffset(&zone_id_str, 0, ":", "/");
  // Take the last component of a timezone id (e.g. 'Baz' in 'Foo/Bar/Baz').
  // Depending on timezones, keeping all but the 1st component
  // (e.g. Bar/Baz) may be better, but our current list does not have
  // any timezone for which that's the case.
  std::string::size_type slash_pos = zone_id_str.rfind('/');
  if (slash_pos != std::string::npos && slash_pos < zone_id_str.size())
    zone_id_str.erase(0, slash_pos + 1);
  // zone id has '_' in place of ' '.
  ReplaceSubstringsAfterOffset(&zone_id_str, 0, "_", " ");
  return ASCIIToUTF16(zone_id_str);
}

}  // namespace anonymous

namespace chromeos {

SystemSettingsProvider::SystemSettingsProvider() {
  for (size_t i = 0; i < arraysize(kTimeZones); i++) {
    timezones_.push_back(icu::TimeZone::createTimeZone(
        icu::UnicodeString(kTimeZones[i], -1, US_INV)));
  }
  CrosLibrary::Get()->GetSystemLibrary()->AddObserver(this);

}

SystemSettingsProvider::~SystemSettingsProvider() {
  CrosLibrary::Get()->GetSystemLibrary()->RemoveObserver(this);
  STLDeleteElements(&timezones_);
}

void SystemSettingsProvider::DoSet(const std::string& path, Value* in_value) {
  if (path == kSystemTimezone) {
    string16 value;
    if (!in_value || !in_value->IsType(Value::TYPE_STRING) ||
        !in_value->GetAsString(&value))
      return;
    const icu::TimeZone* timezone = GetTimezone(value);
    if (!timezone)
      return;
    CrosLibrary::Get()->GetSystemLibrary()->SetTimezone(timezone);
  }
}

bool SystemSettingsProvider::Get(const std::string& path,
                                 Value** out_value) const {
  if (path == kSystemTimezone) {
    *out_value = Value::CreateStringValue(
        GetTimezoneID(CrosLibrary::Get()->GetSystemLibrary()->GetTimezone()));
    return true;
  }
  return false;
}

bool SystemSettingsProvider::HandlesSetting(const std::string& path) {
  return ::StartsWithASCII(path, std::string("cros.system."), true);
}

void SystemSettingsProvider::TimezoneChanged(const icu::TimeZone& timezone) {
  // Fires system setting change notification.
  CrosSettings::Get()->FireObservers(kSystemTimezone);
}

ListValue* SystemSettingsProvider::GetTimezoneList() {
  ListValue* timezoneList = new ListValue();
  for (std::vector<icu::TimeZone*>::iterator iter = timezones_.begin();
       iter != timezones_.end(); ++iter) {
    const icu::TimeZone* timezone = *iter;
    ListValue* option = new ListValue();
    option->Append(Value::CreateStringValue(GetTimezoneID(*timezone)));
    option->Append(Value::CreateStringValue(GetTimezoneName(*timezone)));
    timezoneList->Append(option);
  }
  return timezoneList;
}

string16 SystemSettingsProvider::GetTimezoneName(
    const icu::TimeZone& timezone) {
  // Instead of using the raw_offset, use the offset in effect now.
  // For instance, US Pacific Time, the offset shown will be -7 in summer
  // while it'll be -8 in winter.
  int raw_offset, dst_offset;
  UDate now = icu::Calendar::getNow();
  UErrorCode status = U_ZERO_ERROR;
  timezone.getOffset(now, false, raw_offset, dst_offset, status);
  DCHECK(U_SUCCESS(status));
  int offset = raw_offset + dst_offset;
  // offset is in msec.
  int minute_offset = std::abs(offset) / 60000;
  int hour_offset = minute_offset / 60;
  int min_remainder = minute_offset % 60;
  // Some timezones have a non-integral hour offset. So, we need to
  // use hh:mm form.
  std::string  offset_str = base::StringPrintf(offset >= 0 ?
      "UTC+%d:%02d" : "UTC-%d:%02d", hour_offset, min_remainder);

  // TODO(jungshik): When coming up with a better list of timezones, we also
  // have to come up with better 'display' names. One possibility is to list
  // multiple cities (e.g. "Los Angeles, Vancouver .." in the order of
  // the population of a country the city belongs to.).
  // We can also think of using LONG_GENERIC or LOCATION once we upgrade
  // to ICU 4.6.
  // In the meantime, we use "LONG" name with "Exemplar City" to distinguish
  // multiple timezones with the same "LONG" name but with different
  // rules (e.g. US Mountain Time in Dever vs Phoneix).
  icu::UnicodeString name;
  timezone.getDisplayName(dst_offset != 0, icu::TimeZone::LONG, name);
  string16 result(l10n_util::GetStringFUTF16(
      IDS_OPTIONS_SETTINGS_TIMEZONE_DISPLAY_TEMPLATE, ASCIIToUTF16(offset_str),
      string16(name.getBuffer(), name.length()), GetExemplarCity(timezone)));
  string16 rtl_safe_result = result;
  base::i18n::AdjustStringForLocaleDirection(result, &rtl_safe_result);
  return rtl_safe_result;
}

string16 SystemSettingsProvider::GetTimezoneID(
    const icu::TimeZone& timezone) {
  icu::UnicodeString id;
  timezone.getID(id);
  return string16(id.getBuffer(), id.length());
}

const icu::TimeZone* SystemSettingsProvider::GetTimezone(
    const string16& timezone_id) {
  for (std::vector<icu::TimeZone*>::iterator iter = timezones_.begin();
       iter != timezones_.end(); ++iter) {
    const icu::TimeZone* timezone = *iter;
    if (GetTimezoneID(*timezone) == timezone_id) {
      return timezone;
    }
  }
  return NULL;
}

}  // namespace chromeos
<commit_msg>Fix 552d build break.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/dom_ui/system_settings_provider.h"

#include <string>

#include "app/l10n_util.h"
#include "base/i18n/rtl.h"
#include "base/lock.h"
#include "base/scoped_ptr.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros_settings.h"
#include "chrome/browser/chromeos/cros_settings_names.h"
#include "grit/generated_resources.h"
#include "unicode/calendar.h"
#include "unicode/timezone.h"
#include "unicode/ures.h"

namespace {

// TODO(jungshik): Using Enumerate method in ICU gives 600+ timezones.
// Even after filtering out duplicate entries with a strict identity check,
// we still have 400+ zones. Relaxing the criteria for the timezone
// identity is likely to cut down the number to < 100. Until we
// come up with a better list, we hard-code the following list as used by
// Android.
static const char* kTimeZones[] = {
    "Pacific/Majuro",
    "Pacific/Midway",
    "Pacific/Honolulu",
    "America/Anchorage",
    "America/Los_Angeles",
    "America/Tijuana",
    "America/Denver",
    "America/Phoenix",
    "America/Chihuahua",
    "America/Chicago",
    "America/Mexico_City",
    "America/Costa_Rica",
    "America/Regina",
    "America/New_York",
    "America/Bogota",
    "America/Caracas",
    "America/Barbados",
    "America/Manaus",
    "America/Santiago",
    "America/St_Johns",
    "America/Sao_Paulo",
    "America/Araguaina",
    "America/Argentina/Buenos_Aires",
    "America/Godthab",
    "America/Montevideo",
    "Atlantic/South_Georgia",
    "Atlantic/Azores",
    "Atlantic/Cape_Verde",
    "Africa/Casablanca",
    "Europe/London",
    "Europe/Amsterdam",
    "Europe/Belgrade",
    "Europe/Brussels",
    "Europe/Sarajevo",
    "Africa/Windhoek",
    "Africa/Brazzaville",
    "Asia/Amman",
    "Europe/Athens",
    "Asia/Beirut",
    "Africa/Cairo",
    "Europe/Helsinki",
    "Asia/Jerusalem",
    "Europe/Minsk",
    "Africa/Harare",
    "Asia/Baghdad",
    "Europe/Moscow",
    "Asia/Kuwait",
    "Africa/Nairobi",
    "Asia/Tehran",
    "Asia/Baku",
    "Asia/Tbilisi",
    "Asia/Yerevan",
    "Asia/Dubai",
    "Asia/Kabul",
    "Asia/Karachi",
    "Asia/Oral",
    "Asia/Yekaterinburg",
    "Asia/Calcutta",
    "Asia/Colombo",
    "Asia/Katmandu",
    "Asia/Almaty",
    "Asia/Rangoon",
    "Asia/Krasnoyarsk",
    "Asia/Bangkok",
    "Asia/Shanghai",
    "Asia/Hong_Kong",
    "Asia/Irkutsk",
    "Asia/Kuala_Lumpur",
    "Australia/Perth",
    "Asia/Taipei",
    "Asia/Seoul",
    "Asia/Tokyo",
    "Asia/Yakutsk",
    "Australia/Adelaide",
    "Australia/Darwin",
    "Australia/Brisbane",
    "Australia/Hobart",
    "Australia/Sydney",
    "Asia/Vladivostok",
    "Pacific/Guam",
    "Asia/Magadan",
    "Pacific/Auckland",
    "Pacific/Fiji",
    "Pacific/Tongatapu",
};

static Lock timezone_bundle_lock;

struct UResClose {
  inline void operator() (UResourceBundle* b) const {
    ures_close(b);
  }
};

string16 GetExemplarCity(const icu::TimeZone& zone) {
  // TODO(jungshik): After upgrading to ICU 4.6, use U_ICUDATA_ZONE
  static const char* zone_bundle_name = NULL;

  // These will be leaked at the end.
  static UResourceBundle *zone_bundle = NULL;
  static UResourceBundle *zone_strings = NULL;

  UErrorCode status = U_ZERO_ERROR;
  {
    AutoLock lock(timezone_bundle_lock);
    if (zone_bundle == NULL)
      zone_bundle = ures_open(zone_bundle_name, uloc_getDefault(), &status);

    if (zone_strings == NULL)
      zone_strings = ures_getByKey(zone_bundle, "zone_strings", NULL, &status);
  }

  icu::UnicodeString zone_id;
  zone.getID(zone_id);
  std::string zone_id_str;
  zone_id.toUTF8String(zone_id_str);

  // resource keys for timezones use ':' in place of '/'.
  ReplaceSubstringsAfterOffset(&zone_id_str, 0, "/", ":");
  scoped_ptr_malloc<UResourceBundle, UResClose> zone_item(
      ures_getByKey(zone_strings, zone_id_str.c_str(), NULL, &status));
  icu::UnicodeString city;
  if (U_FAILURE(status))
    goto fallback;
  city = icu::ures_getUnicodeStringByKey(zone_item.get(), "ec", &status);
  if (U_SUCCESS(status))
    return string16(city.getBuffer(), city.length());

 fallback:
  ReplaceSubstringsAfterOffset(&zone_id_str, 0, ":", "/");
  // Take the last component of a timezone id (e.g. 'Baz' in 'Foo/Bar/Baz').
  // Depending on timezones, keeping all but the 1st component
  // (e.g. Bar/Baz) may be better, but our current list does not have
  // any timezone for which that's the case.
  std::string::size_type slash_pos = zone_id_str.rfind('/');
  if (slash_pos != std::string::npos && slash_pos < zone_id_str.size())
    zone_id_str.erase(0, slash_pos + 1);
  // zone id has '_' in place of ' '.
  ReplaceSubstringsAfterOffset(&zone_id_str, 0, "_", " ");
  return ASCIIToUTF16(zone_id_str);
}

}  // namespace anonymous

namespace chromeos {

SystemSettingsProvider::SystemSettingsProvider() {
  for (size_t i = 0; i < arraysize(kTimeZones); i++) {
    timezones_.push_back(icu::TimeZone::createTimeZone(
        icu::UnicodeString(kTimeZones[i], -1, US_INV)));
  }
  CrosLibrary::Get()->GetSystemLibrary()->AddObserver(this);

}

SystemSettingsProvider::~SystemSettingsProvider() {
  CrosLibrary::Get()->GetSystemLibrary()->RemoveObserver(this);
  STLDeleteElements(&timezones_);
}

void SystemSettingsProvider::DoSet(const std::string& path, Value* in_value) {
  if (path == kSystemTimezone) {
    string16 value;
    if (!in_value || !in_value->IsType(Value::TYPE_STRING) ||
        !in_value->GetAsString(&value))
      return;
    const icu::TimeZone* timezone = GetTimezone(value);
    if (!timezone)
      return;
    CrosLibrary::Get()->GetSystemLibrary()->SetTimezone(timezone);
  }
}

bool SystemSettingsProvider::Get(const std::string& path,
                                 Value** out_value) const {
  if (path == kSystemTimezone) {
    *out_value = Value::CreateStringValue(
        GetTimezoneID(CrosLibrary::Get()->GetSystemLibrary()->GetTimezone()));
    return true;
  }
  return false;
}

bool SystemSettingsProvider::HandlesSetting(const std::string& path) {
  return ::StartsWithASCII(path, std::string("cros.system."), true);
}

void SystemSettingsProvider::TimezoneChanged(const icu::TimeZone& timezone) {
  // Fires system setting change notification.
  CrosSettings::Get()->FireObservers(kSystemTimezone);
}

ListValue* SystemSettingsProvider::GetTimezoneList() {
  ListValue* timezoneList = new ListValue();
  for (std::vector<icu::TimeZone*>::iterator iter = timezones_.begin();
       iter != timezones_.end(); ++iter) {
    const icu::TimeZone* timezone = *iter;
    ListValue* option = new ListValue();
    option->Append(Value::CreateStringValue(GetTimezoneID(*timezone)));
    option->Append(Value::CreateStringValue(GetTimezoneName(*timezone)));
    timezoneList->Append(option);
  }
  return timezoneList;
}

string16 SystemSettingsProvider::GetTimezoneName(
    const icu::TimeZone& timezone) {
  // Instead of using the raw_offset, use the offset in effect now.
  // For instance, US Pacific Time, the offset shown will be -7 in summer
  // while it'll be -8 in winter.
  int raw_offset, dst_offset;
  UDate now = icu::Calendar::getNow();
  UErrorCode status = U_ZERO_ERROR;
  timezone.getOffset(now, false, raw_offset, dst_offset, status);
  DCHECK(U_SUCCESS(status));
  int offset = raw_offset + dst_offset;
  // offset is in msec.
  int minute_offset = std::abs(offset) / 60000;
  int hour_offset = minute_offset / 60;
  int min_remainder = minute_offset % 60;
  // Some timezones have a non-integral hour offset. So, we need to
  // use hh:mm form.
  std::string  offset_str = base::StringPrintf(offset >= 0 ?
      "UTC+%d:%02d" : "UTC-%d:%02d", hour_offset, min_remainder);

  // TODO(jungshik): When coming up with a better list of timezones, we also
  // have to come up with better 'display' names. One possibility is to list
  // multiple cities (e.g. "Los Angeles, Vancouver .." in the order of
  // the population of a country the city belongs to.).
  // We can also think of using LONG_GENERIC or LOCATION once we upgrade
  // to ICU 4.6.
  // In the meantime, we use "LONG" name with "Exemplar City" to distinguish
  // multiple timezones with the same "LONG" name but with different
  // rules (e.g. US Mountain Time in Dever vs Phoneix).
  icu::UnicodeString name;
  timezone.getDisplayName(dst_offset != 0, icu::TimeZone::LONG, name);
  string16 result(l10n_util::GetStringFUTF16(
      IDS_OPTIONS_SETTINGS_TIMEZONE_DISPLAY_TEMPLATE, ASCIIToUTF16(offset_str),
      string16(name.getBuffer(), name.length()), GetExemplarCity(timezone)));
  string16 rtl_safe_result = result;
  base::i18n::AdjustStringForLocaleDirection(result, &rtl_safe_result);
  return rtl_safe_result;
}

string16 SystemSettingsProvider::GetTimezoneID(
    const icu::TimeZone& timezone) {
  icu::UnicodeString id;
  timezone.getID(id);
  return string16(id.getBuffer(), id.length());
}

const icu::TimeZone* SystemSettingsProvider::GetTimezone(
    const string16& timezone_id) {
  for (std::vector<icu::TimeZone*>::iterator iter = timezones_.begin();
       iter != timezones_.end(); ++iter) {
    const icu::TimeZone* timezone = *iter;
    if (GetTimezoneID(*timezone) == timezone_id) {
      return timezone;
    }
  }
  return NULL;
}

}  // namespace chromeos
<|endoftext|>