<commit_before>// Filename: geomParticleRenderer.cxx
// Created by:  charles (05Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

#include "geomParticleRenderer.h"
#include "baseParticle.h"

#include "transformState.h"
#include "colorAttrib.h"

////////////////////////////////////////////////////////////////////
//    Function : GeomParticleRenderer
//      Access : public
// Description : constructor
////////////////////////////////////////////////////////////////////

GeomParticleRenderer::
GeomParticleRenderer(ParticleRendererAlphaMode am, PandaNode *geom_node) :
  BaseParticleRenderer(am),  _geom_node(geom_node), _pool_size(0) {

  if (_geom_node.is_null())
    _geom_node = new PandaNode("empty");
}

////////////////////////////////////////////////////////////////////
//    Function : GeomParticleRenderer
//      Access : public
// Description : copy constructor
////////////////////////////////////////////////////////////////////

GeomParticleRenderer::
GeomParticleRenderer(const GeomParticleRenderer& copy) :
  BaseParticleRenderer(copy), _pool_size(0) {
  _geom_node = copy._geom_node;
}

////////////////////////////////////////////////////////////////////
//    Function : ~GeomParticleRenderer
//      Access : public
// Description : destructor
////////////////////////////////////////////////////////////////////

GeomParticleRenderer::
~GeomParticleRenderer() {
  kill_nodes();
}

////////////////////////////////////////////////////////////////////
//    Function : make_copy
//      Access : public
// Description : dynamic copying
////////////////////////////////////////////////////////////////////

BaseParticleRenderer *GeomParticleRenderer::
make_copy() {
  return new GeomParticleRenderer(*this);
}

////////////////////////////////////////////////////////////////////
//    Function : init_geoms
//      Access : private
// Description : links the child nodes to the parent stuff
////////////////////////////////////////////////////////////////////

void GeomParticleRenderer::
init_geoms() {
}

////////////////////////////////////////////////////////////////////
//    Function : resize_pool
//      Access : private
// Description : handles renderer-size resizing.
////////////////////////////////////////////////////////////////////

void GeomParticleRenderer::
resize_pool(int new_size) {
  kill_nodes();

  // now repopulate the vector with a bunch of NULLS, representing
  // potential instances of the _geom_node.

  int i;
  for (i = 0; i < new_size; i++) {
    _node_vector.push_back(NULL);
  }

  _pool_size = new_size;
}

////////////////////////////////////////////////////////////////////
//  Function : kill_nodes
//    Access : private
////////////////////////////////////////////////////////////////////

void GeomParticleRenderer::
kill_nodes() {
  pvector< PT(PandaNode) >::iterator vec_iter = _node_vector.begin();

  PandaNode *render_node = get_render_node();
  for (; vec_iter != _node_vector.end(); vec_iter++) {
    PandaNode *node = *vec_iter;
    if (node != (PandaNode *)NULL) {
      render_node->remove_child(node);
    }
  }

  _node_vector.erase(_node_vector.begin(), _node_vector.end());
}

////////////////////////////////////////////////////////////////////
//    Function : birth_particle
//      Access : Private, virtual
// Description : child birth
////////////////////////////////////////////////////////////////////

void GeomParticleRenderer::
birth_particle(int index) {
  if (_node_vector[index] == (PandaNode *)NULL) {
    PandaNode *node = new PandaNode("");
    get_render_node()->add_child(node);
    node->add_child(_geom_node);
    _node_vector[index] = node;
  }
}

////////////////////////////////////////////////////////////////////
//    Function : kill_particle
//      Access : Private, virtual
// Description : child kill
////////////////////////////////////////////////////////////////////

void GeomParticleRenderer::
kill_particle(int index) {
  if (_node_vector[index] != (PandaNode *)NULL) {
    get_render_node()->remove_child(_node_vector[index]);
    _node_vector[index] = (PandaNode *)NULL;
  }
}

////////////////////////////////////////////////////////////////////
//    Function : render
//      Access : private
// Description : sets the transitions on each arc
////////////////////////////////////////////////////////////////////

void GeomParticleRenderer::
render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
  BaseParticle *cur_particle;
  int i, remaining_particles = ttl_particles;

  pvector< PT(PandaNode) >::iterator cur_node_iter = _node_vector.begin();

  // run through the particle vector

  for (i = 0; i < (int)po_vector.size(); i++) {
    PandaNode *cur_node;

    cur_particle = (BaseParticle *) po_vector[i].p();
    cur_node = *cur_node_iter;

    if (cur_particle->get_alive()) {
      // living particle
      if (cur_node == (PandaNode *)NULL) {
        birth_particle(i);
        cur_node = *cur_node_iter;
      }
      nassertv(cur_node != (PandaNode *)NULL);

      cur_node->set_state(_render_state);

      if ((_alpha_mode != PR_ALPHA_NONE)) {
        float alpha_scalar;

        if(_alpha_mode == PR_ALPHA_USER) {
          alpha_scalar = get_user_alpha();
        } else {
          alpha_scalar = cur_particle->get_parameterized_age();
          if (_alpha_mode == PR_ALPHA_OUT)
            alpha_scalar = 1.0f - alpha_scalar;
          alpha_scalar *= get_user_alpha();
        }

        cur_node->set_attrib(ColorAttrib::make_flat
                             (Colorf(1.0f, 1.0f, 1.0f, alpha_scalar)));
      }

      cur_node->set_transform(TransformState::make_pos_quat_scale
                              (cur_particle->get_position(),
                               cur_particle->get_orientation(),
                               LVecBase3f(1.0f, 1.0f, 1.0f)));

      // maybe get out early if possible.

      remaining_particles--;

      if (remaining_particles == 0)
        break;
    }

    cur_node_iter++;
  }
}

////////////////////////////////////////////////////////////////////
//     Function : output
//       Access : Public
//  Description : Write a string representation of this instance to
//                <out>.
////////////////////////////////////////////////////////////////////
void GeomParticleRenderer::
output(ostream &out) const {
  #ifndef NDEBUG //[
  out<<"GeomParticleRenderer";
  #endif //] NDEBUG
}

////////////////////////////////////////////////////////////////////
//     Function : write_linear_forces
//       Access : Public
//  Description : Write a string representation of this instance to
//                <out>.
////////////////////////////////////////////////////////////////////
void GeomParticleRenderer::
write_linear_forces(ostream &out, int indent) const {
  #ifndef NDEBUG //[
  out.width(indent);
  out<<""<<"_node_vector ("<<_node_vector.size()<<" forces)\n";
  for (pvector< PT(PandaNode) >::const_iterator i=_node_vector.begin();
       i != _node_vector.end();
       ++i) {
    (*i)->write(out, indent+2);
  }
  #endif //] NDEBUG
}

////////////////////////////////////////////////////////////////////
//     Function : write
//       Access : Public
//  Description : Write a string representation of this instance to
//                <out>.
////////////////////////////////////////////////////////////////////
void GeomParticleRenderer::
write(ostream &out, int indent) const {
  #ifndef NDEBUG //[
  out.width(indent); out<<""; out<<"GeomParticleRenderer:\n";
  out.width(indent+2); out<<""; out<<"_geom_node "<<_geom_node<<"\n";
  out.width(indent+2); out<<""; out<<"_pool_size "<<_pool_size<<"\n";
  write_linear_forces(out, indent+2);
  BaseParticleRenderer::write(out, indent+2);
  #endif //] NDEBUG
}
<commit_msg>should use set_color_scale(), not set_color(), to fade out geom particles<commit_after>// Filename: geomParticleRenderer.cxx
// Created by:  charles (05Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

#include "geomParticleRenderer.h"
#include "baseParticle.h"

#include "transformState.h"
#include "colorScaleAttrib.h"

////////////////////////////////////////////////////////////////////
//    Function : GeomParticleRenderer
//      Access : public
// Description : constructor
////////////////////////////////////////////////////////////////////

GeomParticleRenderer::
GeomParticleRenderer(ParticleRendererAlphaMode am, PandaNode *geom_node) :
  BaseParticleRenderer(am),  _geom_node(geom_node), _pool_size(0) {

  if (_geom_node.is_null())
    _geom_node = new PandaNode("empty");
}

////////////////////////////////////////////////////////////////////
//    Function : GeomParticleRenderer
//      Access : public
// Description : copy constructor
////////////////////////////////////////////////////////////////////

GeomParticleRenderer::
GeomParticleRenderer(const GeomParticleRenderer& copy) :
  BaseParticleRenderer(copy), _pool_size(0) {
  _geom_node = copy._geom_node;
}

////////////////////////////////////////////////////////////////////
//    Function : ~GeomParticleRenderer
//      Access : public
// Description : destructor
////////////////////////////////////////////////////////////////////

GeomParticleRenderer::
~GeomParticleRenderer() {
  kill_nodes();
}

////////////////////////////////////////////////////////////////////
//    Function : make_copy
//      Access : public
// Description : dynamic copying
////////////////////////////////////////////////////////////////////

BaseParticleRenderer *GeomParticleRenderer::
make_copy() {
  return new GeomParticleRenderer(*this);
}

////////////////////////////////////////////////////////////////////
//    Function : init_geoms
//      Access : private
// Description : links the child nodes to the parent stuff
////////////////////////////////////////////////////////////////////

void GeomParticleRenderer::
init_geoms() {
}

////////////////////////////////////////////////////////////////////
//    Function : resize_pool
//      Access : private
// Description : handles renderer-size resizing.
////////////////////////////////////////////////////////////////////

void GeomParticleRenderer::
resize_pool(int new_size) {
  kill_nodes();

  // now repopulate the vector with a bunch of NULLS, representing
  // potential instances of the _geom_node.

  int i;
  for (i = 0; i < new_size; i++) {
    _node_vector.push_back(NULL);
  }

  _pool_size = new_size;
}

////////////////////////////////////////////////////////////////////
//  Function : kill_nodes
//    Access : private
////////////////////////////////////////////////////////////////////

void GeomParticleRenderer::
kill_nodes() {
  pvector< PT(PandaNode) >::iterator vec_iter = _node_vector.begin();

  PandaNode *render_node = get_render_node();
  for (; vec_iter != _node_vector.end(); vec_iter++) {
    PandaNode *node = *vec_iter;
    if (node != (PandaNode *)NULL) {
      render_node->remove_child(node);
    }
  }

  _node_vector.erase(_node_vector.begin(), _node_vector.end());
}

////////////////////////////////////////////////////////////////////
//    Function : birth_particle
//      Access : Private, virtual
// Description : child birth
////////////////////////////////////////////////////////////////////

void GeomParticleRenderer::
birth_particle(int index) {
  if (_node_vector[index] == (PandaNode *)NULL) {
    PandaNode *node = new PandaNode("");
    get_render_node()->add_child(node);
    node->add_child(_geom_node);
    _node_vector[index] = node;
  }
}

////////////////////////////////////////////////////////////////////
//    Function : kill_particle
//      Access : Private, virtual
// Description : child kill
////////////////////////////////////////////////////////////////////

void GeomParticleRenderer::
kill_particle(int index) {
  if (_node_vector[index] != (PandaNode *)NULL) {
    get_render_node()->remove_child(_node_vector[index]);
    _node_vector[index] = (PandaNode *)NULL;
  }
}

////////////////////////////////////////////////////////////////////
//    Function : render
//      Access : private
// Description : sets the transitions on each arc
////////////////////////////////////////////////////////////////////

void GeomParticleRenderer::
render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
  BaseParticle *cur_particle;
  int i, remaining_particles = ttl_particles;

  pvector< PT(PandaNode) >::iterator cur_node_iter = _node_vector.begin();

  // run through the particle vector

  for (i = 0; i < (int)po_vector.size(); i++) {
    PandaNode *cur_node;

    cur_particle = (BaseParticle *) po_vector[i].p();
    cur_node = *cur_node_iter;

    if (cur_particle->get_alive()) {
      // living particle
      if (cur_node == (PandaNode *)NULL) {
        birth_particle(i);
        cur_node = *cur_node_iter;
      }
      nassertv(cur_node != (PandaNode *)NULL);

      cur_node->set_state(_render_state);

      if ((_alpha_mode != PR_ALPHA_NONE)) {
        float alpha_scalar;

        if(_alpha_mode == PR_ALPHA_USER) {
          alpha_scalar = get_user_alpha();
        } else {
          alpha_scalar = cur_particle->get_parameterized_age();
          if (_alpha_mode == PR_ALPHA_OUT)
            alpha_scalar = 1.0f - alpha_scalar;
          alpha_scalar *= get_user_alpha();
        }

        cur_node->set_attrib(ColorScaleAttrib::make
                             (Colorf(1.0f, 1.0f, 1.0f, alpha_scalar)));
      }

      cur_node->set_transform(TransformState::make_pos_quat_scale
                              (cur_particle->get_position(),
                               cur_particle->get_orientation(),
                               LVecBase3f(1.0f, 1.0f, 1.0f)));

      // maybe get out early if possible.

      remaining_particles--;

      if (remaining_particles == 0)
        break;
    }

    cur_node_iter++;
  }
}

////////////////////////////////////////////////////////////////////
//     Function : output
//       Access : Public
//  Description : Write a string representation of this instance to
//                <out>.
////////////////////////////////////////////////////////////////////
void GeomParticleRenderer::
output(ostream &out) const {
  #ifndef NDEBUG //[
  out<<"GeomParticleRenderer";
  #endif //] NDEBUG
}

////////////////////////////////////////////////////////////////////
//     Function : write_linear_forces
//       Access : Public
//  Description : Write a string representation of this instance to
//                <out>.
////////////////////////////////////////////////////////////////////
void GeomParticleRenderer::
write_linear_forces(ostream &out, int indent) const {
  #ifndef NDEBUG //[
  out.width(indent);
  out<<""<<"_node_vector ("<<_node_vector.size()<<" forces)\n";
  for (pvector< PT(PandaNode) >::const_iterator i=_node_vector.begin();
       i != _node_vector.end();
       ++i) {
    (*i)->write(out, indent+2);
  }
  #endif //] NDEBUG
}

////////////////////////////////////////////////////////////////////
//     Function : write
//       Access : Public
//  Description : Write a string representation of this instance to
//                <out>.
////////////////////////////////////////////////////////////////////
void GeomParticleRenderer::
write(ostream &out, int indent) const {
  #ifndef NDEBUG //[
  out.width(indent); out<<""; out<<"GeomParticleRenderer:\n";
  out.width(indent+2); out<<""; out<<"_geom_node "<<_geom_node<<"\n";
  out.width(indent+2); out<<""; out<<"_pool_size "<<_pool_size<<"\n";
  write_linear_forces(out, indent+2);
  BaseParticleRenderer::write(out, indent+2);
  #endif //] NDEBUG
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 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 "app/l10n_util.h"
#include "base/file_path.h"
#include "base/gfx/native_widget_types.h"
#include "base/string_util.h"
#include "base/sys_info.h"
#include "base/values.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/platform_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "net/url_request/url_request_unittest.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"

namespace {

// Given a page title, returns the expected window caption string.
std::wstring WindowCaptionFromPageTitle(std::wstring page_title) {
#if defined(OS_WIN) || defined(OS_LINUX)
  if (page_title.empty())
    return l10n_util::GetString(IDS_PRODUCT_NAME);

  return l10n_util::GetStringF(IDS_BROWSER_WINDOW_TITLE_FORMAT, page_title);
#elif defined(OS_MACOSX)
  // On Mac, we don't want to suffix the page title with the application name.
  if (page_title.empty())
    return l10n_util::GetString(IDS_BROWSER_WINDOW_MAC_TAB_UNTITLED);
  return page_title;
#endif
}

class BrowserTest : public UITest {
 protected:
#if defined(OS_WIN)
  HWND GetMainWindow() {
    scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
    scoped_refptr<WindowProxy> window(browser->GetWindow());

    HWND window_handle;
    EXPECT_TRUE(window->GetHWND(&window_handle));
    return window_handle;
  }
#endif

  std::wstring GetWindowTitle() {
    scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
    scoped_refptr<WindowProxy> window(browser->GetWindow());

    string16 title;
    EXPECT_TRUE(window->GetWindowTitle(&title));
    return UTF16ToWide(title);
  }
};

class VisibleBrowserTest : public UITest {
 protected:
  VisibleBrowserTest() : UITest() {
    show_window_ = true;
  }
};

// Launch the app on a page with no title, check that the app title was set
// correctly.
TEST_F(BrowserTest, NoTitle) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title1.html");

  NavigateToURL(net::FilePathToFileURL(test_file));
  // The browser lazily updates the title.
  PlatformThread::Sleep(sleep_timeout_ms());
  EXPECT_EQ(WindowCaptionFromPageTitle(L"title1.html"), GetWindowTitle());
  EXPECT_EQ(L"title1.html", GetActiveTabTitle());
}

// Launch the app, navigate to a page with a title, check that the app title
// was set correctly.
TEST_F(BrowserTest, Title) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title2.html");

  NavigateToURL(net::FilePathToFileURL(test_file));
  // The browser lazily updates the title.
  PlatformThread::Sleep(sleep_timeout_ms());

  const std::wstring test_title(L"Title Of Awesomeness");
  EXPECT_EQ(WindowCaptionFromPageTitle(test_title), GetWindowTitle());
  EXPECT_EQ(test_title, GetActiveTabTitle());
}

// Create 34 tabs and verify that a lot of processes have been created. The
// exact number of processes depends on the amount of memory. Previously we
// had a hard limit of 31 processes and this test is mainly directed at
// verifying that we don't crash when we pass this limit.
TEST_F(BrowserTest, ThirtyFourTabs) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title2.html");
  GURL url(net::FilePathToFileURL(test_file));
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  // There is one initial tab.
  for (int ix = 0; ix != 33; ++ix) {
    EXPECT_TRUE(window->AppendTab(url));
  }
  int tab_count = 0;
  EXPECT_TRUE(window->GetTabCount(&tab_count));
  EXPECT_EQ(34, tab_count);
  // Do not test the rest in single process mode.
  if (in_process_renderer())
    return;
  // See browser\renderer_host\render_process_host.cc for the algorithm to
  // decide how many processes to create.
  int process_count = GetBrowserProcessCount();
  if (base::SysInfo::AmountOfPhysicalMemoryMB() >= 2048) {
    EXPECT_GE(process_count, 24);
  } else {
    EXPECT_LE(process_count, 23);
  }
}

#if defined(OS_WIN)
// The browser should quit quickly if it receives a WM_ENDSESSION message.
TEST_F(BrowserTest, WindowsSessionEnd) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title1.html");

  NavigateToURL(net::FilePathToFileURL(test_file));
  PlatformThread::Sleep(action_timeout_ms());

  // Simulate an end of session. Normally this happens when the user
  // shuts down the pc or logs off.
  HWND window_handle = GetMainWindow();
  ASSERT_TRUE(::PostMessageW(window_handle, WM_ENDSESSION, 0, 0));

  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_FALSE(IsBrowserRunning());

  // Make sure the UMA metrics say we didn't crash.
  scoped_ptr<DictionaryValue> local_prefs(GetLocalState());
  bool exited_cleanly;
  ASSERT_TRUE(local_prefs.get());
  ASSERT_TRUE(local_prefs->GetBoolean(prefs::kStabilityExitedCleanly,
                                      &exited_cleanly));
  ASSERT_TRUE(exited_cleanly);

  // And that session end was successful.
  bool session_end_completed;
  ASSERT_TRUE(local_prefs->GetBoolean(prefs::kStabilitySessionEndCompleted,
                                      &session_end_completed));
  ASSERT_TRUE(session_end_completed);

  // Make sure session restore says we didn't crash.
  scoped_ptr<DictionaryValue> profile_prefs(GetDefaultProfilePreferences());
  ASSERT_TRUE(profile_prefs.get());
  ASSERT_TRUE(profile_prefs->GetBoolean(prefs::kSessionExitedCleanly,
                                        &exited_cleanly));
  ASSERT_TRUE(exited_cleanly);
}
#endif

// This test is flakey, see bug 5668 for details.
TEST_F(BrowserTest, DISABLED_JavascriptAlertActivatesTab) {
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  int start_index;
  ASSERT_TRUE(window->GetActiveTabIndex(&start_index));
  ASSERT_TRUE(window->AppendTab(GURL("about:blank")));
  int javascript_tab_index;
  ASSERT_TRUE(window->GetActiveTabIndex(&javascript_tab_index));
  scoped_refptr<TabProxy> javascript_tab = window->GetActiveTab();
  // Switch back to the starting tab, then send the second tab a javascript
  // alert, which should force it to become active.
  ASSERT_TRUE(window->ActivateTab(start_index));
  ASSERT_TRUE(
      javascript_tab->NavigateToURLAsync(GURL("javascript:alert('Alert!')")));
  ASSERT_TRUE(window->WaitForTabToBecomeActive(javascript_tab_index,
                                               action_max_timeout_ms()));
}

// Test that scripts can fork a new renderer process for a tab in a particular
// case (which matches following a link in Gmail).  The script must open a new
// tab, set its window.opener to null, and redirect it to a cross-site URL.
// (Bug 1115708)
// This test can only run if V8 is in use, and not KJS, because KJS will not
// set window.opener to null properly.
#ifdef CHROME_V8
TEST_F(BrowserTest, NullOpenerRedirectForksProcess) {
  // This test only works in multi-process mode
  if (in_process_renderer())
    return;

  const wchar_t kDocRoot[] = L"chrome/test/data";
  scoped_refptr<HTTPTestServer> server =
      HTTPTestServer::CreateServer(kDocRoot, NULL);
  ASSERT_TRUE(NULL != server.get());
  FilePath test_file(test_data_directory_);
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  scoped_refptr<TabProxy> tab(window->GetActiveTab());

  // Start with a file:// url
  test_file = test_file.AppendASCII("title2.html");
  tab->NavigateToURL(net::FilePathToFileURL(test_file));
  int orig_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&orig_tab_count));
  int orig_process_count = GetBrowserProcessCount();
  ASSERT_GE(orig_process_count, 1);

  // Use JavaScript URL to "fork" a new tab, just like Gmail.  (Open tab to a
  // blank page, set its opener to null, and redirect it cross-site.)
  std::wstring url_prefix(L"javascript:(function(){w=window.open();");
  GURL fork_url(url_prefix +
      L"w.opener=null;w.document.location=\"http://localhost:1337\";})()");

  // Make sure that a new tab has been created and that we have a new renderer
  // process for it.
  tab->NavigateToURLAsync(fork_url);
  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_EQ(orig_process_count + 1, GetBrowserProcessCount());
  int new_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&new_tab_count));
  ASSERT_EQ(orig_tab_count + 1, new_tab_count);
}
#endif

#if !defined(OS_LINUX)
// TODO(port): This passes on linux locally, but fails on the try bot.
// Tests that non-Gmail-like script redirects (i.e., non-null window.opener) or
// a same-page-redirect) will not fork a new process.
TEST_F(BrowserTest, OtherRedirectsDontForkProcess) {
  // This test only works in multi-process mode
  if (in_process_renderer())
    return;

  const wchar_t kDocRoot[] = L"chrome/test/data";
  scoped_refptr<HTTPTestServer> server =
      HTTPTestServer::CreateServer(kDocRoot, NULL);
  ASSERT_TRUE(NULL != server.get());
  FilePath test_file(test_data_directory_);
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  scoped_refptr<TabProxy> tab(window->GetActiveTab());

  // Start with a file:// url
  test_file = test_file.AppendASCII("title2.html");
  tab->NavigateToURL(net::FilePathToFileURL(test_file));
  int orig_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&orig_tab_count));
  int orig_process_count = GetBrowserProcessCount();
  ASSERT_GE(orig_process_count, 1);

  // Use JavaScript URL to almost fork a new tab, but not quite.  (Leave the
  // opener non-null.)  Should not fork a process.
  std::string url_prefix("javascript:(function(){w=window.open();");
  GURL dont_fork_url(url_prefix +
      "w.document.location=\"http://localhost:1337\";})()");

  // Make sure that a new tab but not new process has been created.
  tab->NavigateToURLAsync(dont_fork_url);
  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_EQ(orig_process_count, GetBrowserProcessCount());
  int new_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&new_tab_count));
  ASSERT_EQ(orig_tab_count + 1, new_tab_count);

  // Same thing if the current tab tries to redirect itself.
  GURL dont_fork_url2(url_prefix +
      "document.location=\"http://localhost:1337\";})()");

  // Make sure that no new process has been created.
  tab->NavigateToURLAsync(dont_fork_url2);
  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_EQ(orig_process_count, GetBrowserProcessCount());
}
#endif

#if defined(OS_WIN)
// TODO(estade): need to port GetActiveTabTitle().
TEST_F(VisibleBrowserTest, WindowOpenClose) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("window.close.html");

  NavigateToURL(net::FilePathToFileURL(test_file));

  int i;
  for (i = 0; i < 10; ++i) {
    PlatformThread::Sleep(action_max_timeout_ms() / 10);
    std::wstring title = GetActiveTabTitle();
    if (title == L"PASSED") {
      // Success, bail out.
      break;
    }
  }

  if (i == 10)
    FAIL() << "failed to get error page title";
}
#endif

}  // namespace
<commit_msg>Coverity underground warfare: check return code - Check return code consistently - CID 4171<commit_after>// Copyright (c) 2006-2008 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 "app/l10n_util.h"
#include "base/file_path.h"
#include "base/gfx/native_widget_types.h"
#include "base/string_util.h"
#include "base/sys_info.h"
#include "base/values.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/platform_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "net/url_request/url_request_unittest.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"

namespace {

// Given a page title, returns the expected window caption string.
std::wstring WindowCaptionFromPageTitle(std::wstring page_title) {
#if defined(OS_WIN) || defined(OS_LINUX)
  if (page_title.empty())
    return l10n_util::GetString(IDS_PRODUCT_NAME);

  return l10n_util::GetStringF(IDS_BROWSER_WINDOW_TITLE_FORMAT, page_title);
#elif defined(OS_MACOSX)
  // On Mac, we don't want to suffix the page title with the application name.
  if (page_title.empty())
    return l10n_util::GetString(IDS_BROWSER_WINDOW_MAC_TAB_UNTITLED);
  return page_title;
#endif
}

class BrowserTest : public UITest {
 protected:
#if defined(OS_WIN)
  HWND GetMainWindow() {
    scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
    scoped_refptr<WindowProxy> window(browser->GetWindow());

    HWND window_handle;
    EXPECT_TRUE(window->GetHWND(&window_handle));
    return window_handle;
  }
#endif

  std::wstring GetWindowTitle() {
    scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
    scoped_refptr<WindowProxy> window(browser->GetWindow());

    string16 title;
    EXPECT_TRUE(window->GetWindowTitle(&title));
    return UTF16ToWide(title);
  }
};

class VisibleBrowserTest : public UITest {
 protected:
  VisibleBrowserTest() : UITest() {
    show_window_ = true;
  }
};

// Launch the app on a page with no title, check that the app title was set
// correctly.
TEST_F(BrowserTest, NoTitle) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title1.html");

  NavigateToURL(net::FilePathToFileURL(test_file));
  // The browser lazily updates the title.
  PlatformThread::Sleep(sleep_timeout_ms());
  EXPECT_EQ(WindowCaptionFromPageTitle(L"title1.html"), GetWindowTitle());
  EXPECT_EQ(L"title1.html", GetActiveTabTitle());
}

// Launch the app, navigate to a page with a title, check that the app title
// was set correctly.
TEST_F(BrowserTest, Title) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title2.html");

  NavigateToURL(net::FilePathToFileURL(test_file));
  // The browser lazily updates the title.
  PlatformThread::Sleep(sleep_timeout_ms());

  const std::wstring test_title(L"Title Of Awesomeness");
  EXPECT_EQ(WindowCaptionFromPageTitle(test_title), GetWindowTitle());
  EXPECT_EQ(test_title, GetActiveTabTitle());
}

// Create 34 tabs and verify that a lot of processes have been created. The
// exact number of processes depends on the amount of memory. Previously we
// had a hard limit of 31 processes and this test is mainly directed at
// verifying that we don't crash when we pass this limit.
TEST_F(BrowserTest, ThirtyFourTabs) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title2.html");
  GURL url(net::FilePathToFileURL(test_file));
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  // There is one initial tab.
  for (int ix = 0; ix != 33; ++ix) {
    EXPECT_TRUE(window->AppendTab(url));
  }
  int tab_count = 0;
  EXPECT_TRUE(window->GetTabCount(&tab_count));
  EXPECT_EQ(34, tab_count);
  // Do not test the rest in single process mode.
  if (in_process_renderer())
    return;
  // See browser\renderer_host\render_process_host.cc for the algorithm to
  // decide how many processes to create.
  int process_count = GetBrowserProcessCount();
  if (base::SysInfo::AmountOfPhysicalMemoryMB() >= 2048) {
    EXPECT_GE(process_count, 24);
  } else {
    EXPECT_LE(process_count, 23);
  }
}

#if defined(OS_WIN)
// The browser should quit quickly if it receives a WM_ENDSESSION message.
TEST_F(BrowserTest, WindowsSessionEnd) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title1.html");

  NavigateToURL(net::FilePathToFileURL(test_file));
  PlatformThread::Sleep(action_timeout_ms());

  // Simulate an end of session. Normally this happens when the user
  // shuts down the pc or logs off.
  HWND window_handle = GetMainWindow();
  ASSERT_TRUE(::PostMessageW(window_handle, WM_ENDSESSION, 0, 0));

  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_FALSE(IsBrowserRunning());

  // Make sure the UMA metrics say we didn't crash.
  scoped_ptr<DictionaryValue> local_prefs(GetLocalState());
  bool exited_cleanly;
  ASSERT_TRUE(local_prefs.get());
  ASSERT_TRUE(local_prefs->GetBoolean(prefs::kStabilityExitedCleanly,
                                      &exited_cleanly));
  ASSERT_TRUE(exited_cleanly);

  // And that session end was successful.
  bool session_end_completed;
  ASSERT_TRUE(local_prefs->GetBoolean(prefs::kStabilitySessionEndCompleted,
                                      &session_end_completed));
  ASSERT_TRUE(session_end_completed);

  // Make sure session restore says we didn't crash.
  scoped_ptr<DictionaryValue> profile_prefs(GetDefaultProfilePreferences());
  ASSERT_TRUE(profile_prefs.get());
  ASSERT_TRUE(profile_prefs->GetBoolean(prefs::kSessionExitedCleanly,
                                        &exited_cleanly));
  ASSERT_TRUE(exited_cleanly);
}
#endif

// This test is flakey, see bug 5668 for details.
TEST_F(BrowserTest, DISABLED_JavascriptAlertActivatesTab) {
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  int start_index;
  ASSERT_TRUE(window->GetActiveTabIndex(&start_index));
  ASSERT_TRUE(window->AppendTab(GURL("about:blank")));
  int javascript_tab_index;
  ASSERT_TRUE(window->GetActiveTabIndex(&javascript_tab_index));
  scoped_refptr<TabProxy> javascript_tab = window->GetActiveTab();
  // Switch back to the starting tab, then send the second tab a javascript
  // alert, which should force it to become active.
  ASSERT_TRUE(window->ActivateTab(start_index));
  ASSERT_TRUE(
      javascript_tab->NavigateToURLAsync(GURL("javascript:alert('Alert!')")));
  ASSERT_TRUE(window->WaitForTabToBecomeActive(javascript_tab_index,
                                               action_max_timeout_ms()));
}

// Test that scripts can fork a new renderer process for a tab in a particular
// case (which matches following a link in Gmail).  The script must open a new
// tab, set its window.opener to null, and redirect it to a cross-site URL.
// (Bug 1115708)
// This test can only run if V8 is in use, and not KJS, because KJS will not
// set window.opener to null properly.
#ifdef CHROME_V8
TEST_F(BrowserTest, NullOpenerRedirectForksProcess) {
  // This test only works in multi-process mode
  if (in_process_renderer())
    return;

  const wchar_t kDocRoot[] = L"chrome/test/data";
  scoped_refptr<HTTPTestServer> server =
      HTTPTestServer::CreateServer(kDocRoot, NULL);
  ASSERT_TRUE(NULL != server.get());
  FilePath test_file(test_data_directory_);
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  scoped_refptr<TabProxy> tab(window->GetActiveTab());

  // Start with a file:// url
  test_file = test_file.AppendASCII("title2.html");
  tab->NavigateToURL(net::FilePathToFileURL(test_file));
  int orig_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&orig_tab_count));
  int orig_process_count = GetBrowserProcessCount();
  ASSERT_GE(orig_process_count, 1);

  // Use JavaScript URL to "fork" a new tab, just like Gmail.  (Open tab to a
  // blank page, set its opener to null, and redirect it cross-site.)
  std::wstring url_prefix(L"javascript:(function(){w=window.open();");
  GURL fork_url(url_prefix +
      L"w.opener=null;w.document.location=\"http://localhost:1337\";})()");

  // Make sure that a new tab has been created and that we have a new renderer
  // process for it.
  ASSERT_TRUE(tab->NavigateToURLAsync(fork_url));
  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_EQ(orig_process_count + 1, GetBrowserProcessCount());
  int new_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&new_tab_count));
  ASSERT_EQ(orig_tab_count + 1, new_tab_count);
}
#endif

#if !defined(OS_LINUX)
// TODO(port): This passes on linux locally, but fails on the try bot.
// Tests that non-Gmail-like script redirects (i.e., non-null window.opener) or
// a same-page-redirect) will not fork a new process.
TEST_F(BrowserTest, OtherRedirectsDontForkProcess) {
  // This test only works in multi-process mode
  if (in_process_renderer())
    return;

  const wchar_t kDocRoot[] = L"chrome/test/data";
  scoped_refptr<HTTPTestServer> server =
      HTTPTestServer::CreateServer(kDocRoot, NULL);
  ASSERT_TRUE(NULL != server.get());
  FilePath test_file(test_data_directory_);
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  scoped_refptr<TabProxy> tab(window->GetActiveTab());

  // Start with a file:// url
  test_file = test_file.AppendASCII("title2.html");
  tab->NavigateToURL(net::FilePathToFileURL(test_file));
  int orig_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&orig_tab_count));
  int orig_process_count = GetBrowserProcessCount();
  ASSERT_GE(orig_process_count, 1);

  // Use JavaScript URL to almost fork a new tab, but not quite.  (Leave the
  // opener non-null.)  Should not fork a process.
  std::string url_prefix("javascript:(function(){w=window.open();");
  GURL dont_fork_url(url_prefix +
      "w.document.location=\"http://localhost:1337\";})()");

  // Make sure that a new tab but not new process has been created.
  ASSERT_TRUE(tab->NavigateToURLAsync(dont_fork_url));
  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_EQ(orig_process_count, GetBrowserProcessCount());
  int new_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&new_tab_count));
  ASSERT_EQ(orig_tab_count + 1, new_tab_count);

  // Same thing if the current tab tries to redirect itself.
  GURL dont_fork_url2(url_prefix +
      "document.location=\"http://localhost:1337\";})()");

  // Make sure that no new process has been created.
  ASSERT_TRUE(tab->NavigateToURLAsync(dont_fork_url2));
  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_EQ(orig_process_count, GetBrowserProcessCount());
}
#endif

#if defined(OS_WIN)
// TODO(estade): need to port GetActiveTabTitle().
TEST_F(VisibleBrowserTest, WindowOpenClose) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("window.close.html");

  NavigateToURL(net::FilePathToFileURL(test_file));

  int i;
  for (i = 0; i < 10; ++i) {
    PlatformThread::Sleep(action_max_timeout_ms() / 10);
    std::wstring title = GetActiveTabTitle();
    if (title == L"PASSED") {
      // Success, bail out.
      break;
    }
  }

  if (i == 10)
    FAIL() << "failed to get error page title";
}
#endif

}  // namespace
<|endoftext|>


<commit_before>/*
 * replay.cpp
 *
 * eXploration module for Autonomous Robotic Embedded Systems
 *
 * xares replay : replay dump from xares (and xares-genom)
 *
 * author:  Cyril Robin <cyril.robin@laas.fr>
 * created: 2013-09-19
 * license: BSD
 */

#include <ostream>
#include <fstream>
#include <sys/time.h>

#include "xares/xares.hpp"
#include "gladys/point.hpp"
#include "gladys/weight_map.hpp"

int replay_genom_dump( const std::string& path_to_dump_file) {//{{{

  std::ifstream dump_file;
  dump_file.open (path_to_dump_file) ;

  if ( dump_file.is_open () ) {
    // init
    struct timeval tv0, tv1;

    std::string line, name ;
    gladys::points_t r_pos;
    int n, max_nf, x_origin, y_origin ;
    size_t min_size, height_max, width_max ;
    double x, y, yaw, min_dist, max_dist ;

    //read data
    getline (dump_file,line) ;
    std::istringstream iss1(line);
    iss1 >> name >> n ;
    std::cerr << "[Xares replay] r_pos ["<< n << "] =";
    while ( n-- > 0) {
      iss1 >> x >> y ;
      r_pos.push_back( gladys::point_xy_t {x,y} );
      std::cerr << " ("<< x << "," << y << ")";
    }
    std::cerr << std::endl;

    getline (dump_file,line) ;
    std::istringstream iss2(line);
    iss2 >> name >> yaw ;
    std::cerr << "[Xares replay] yaw = " << yaw << std::endl;

    // load and display internal params
    getline (dump_file,line) ;
    std::istringstream iss3(line);
    iss3 >> name >> max_nf >> min_size >> min_dist >> max_dist ;
    std::cerr << "[Xares replay] internal params "
              << "(max_nf,min_size,min_dist,max_dist) = ("
              << max_nf << "," << min_size << "," << min_dist << "," << max_dist
              << ")" << std::endl;

    std::cerr << "[Xares replay] max nbr of frontiers = " << max_nf << std::endl;
    getline (dump_file,line) ;
    gladys::weight_map wm ( line );

    // weightmap : origin, size, scale
    std::cerr << "[Xares repay] weight map: (x0,y0,xSc,ySc,W,H) = ("
              << wm.get_utm_pose_x()<< ","
              << wm.get_utm_pose_y()<< ","
              << wm.get_scale_x()   << ","
              << wm.get_scale_y()   << ","
              << wm.get_height()    << ","
              << wm.get_width()     << ")"
              << std::endl;

    // bounded area to explore
    getline (dump_file,line) ;
    std::istringstream iss4(line);
    iss4 >> name >> x_origin >> y_origin >> height_max >> width_max ;
    std::cerr << "[Xares replay] bounded area : (x0,y0,W,H) "
              << x_origin << "," << y_origin << ","
              << height_max << "," << width_max
              << ")" << std::endl;

    dump_file.close();

    // load the planner
    gettimeofday(&tv0, NULL);
    xares::xares xp( wm, x_origin, y_origin, height_max, width_max );
    gettimeofday(&tv1, NULL);

    std::cerr << "[Xares replay] planner loaded ("
              << (tv1.tv_sec -  tv0.tv_sec) * 1000 +
              (tv1.tv_usec - tv0.tv_usec) / 1000 << " ms)." << std::endl;

    // Set internal parameters for xares
    xp.set_params( max_nf, min_size, min_dist, max_dist );
    std::cerr << "[Xares replay] parameters settled. Let's plan !" << std::endl;

    //plan (=replay !)
    gettimeofday(&tv0, NULL);
    xares::xares::return_value rv = xp.plan( r_pos, yaw );
    gettimeofday(&tv1, NULL);

    // parse results
    if ( rv == xares::xares::XARES_FAILURE ) {
      std::cerr << "[Xares replay] #EEE# xares : unexpected data ; unable to compute frontiers :'( " << std::endl;
      return EXIT_SUCCESS;
    }

    if ( rv == xares::xares::XARES_NO_FRONTIER ) {
      std::cerr << "[Xares replay] #EEE# xares : no valuable frontier detected." << std::endl;
      return EXIT_SUCCESS;
    }

    // From here, there should be a valid plan
    std::cerr << "[Xares replay] Plan computed ("
              << (tv1.tv_sec -  tv0.tv_sec) * 1000 +
              (tv1.tv_usec - tv0.tv_usec) / 1000 << " ms)" << std::endl;

    //get planned path
    const gladys::path_t& path = xp.get_goal().path ;

    for (unsigned int i = 0 ; i < path.size() ; i++)
      std::cerr   << "[Xares replay ] ----waypoint #" << i
                  << " = (" << path[i][0]<< "," << path[i][1]
                  <<")"<<std::endl;

    // get poster path
    gladys::path_t::const_iterator it;
    double dist = 0.0;

    gladys::point_xy_t curr = path.front() ;

    unsigned int pt = 0 ;
    for ( it = path.begin(); it != path.end() ; ++it)
    {
      dist += gladys::distance( curr, *it );
      curr = *it;

      if ( dist > 6.0 ) {
        std::cerr   << "[Xares replay ] ---- poster waypoint #" << pt++
                    << " = (" << (*it)[0]<< "," << (*it)[1]
                    <<")"<<std::endl;
      }
    }

    std::cerr   << "[Xares replay ] ---- poster waypoint #" << pt
                << " = (" << curr[0]<< "," << curr[1]
                <<")"<<std::endl;

    // ASCII plot of weightmap, seed & goal
    std::cerr   << "[Xares replay ] ASCII weight map : " << std::endl;
    // foreach from (origin) to (dim+origin)
    for (int j = wm.get_utm_pose_y(); j < wm.get_width()  + wm.get_utm_pose_y(); j++)
    {
      //if ( j < -21 || j > 19 ) continue; //cropping
      for (int i = wm.get_utm_pose_x(); i < wm.get_height() + wm.get_utm_pose_x(); i++)
      {
        //if ( i < 0 || i > 60 ) continue; //cropping
        // Special points
        // O = origin
        // S = Seed
        // G = Goal
        if ( i == 0 && j == 0 ) { // origin
            std::cerr << "O"; continue; }
        if ( i == r_pos[0][0] && j == r_pos[0][1] ) { // seed
            std::cerr << "S"; continue; }
        if ( i == curr[0] && j == curr[1] ) { // goal
            std::cerr << "G"; continue;}

        // Common points
        // u = unknown
        // . = known
        // # = obstacle
        double w = wm.get_weight_band()[ wm.index_utm( gladys::point_xy_t {(double)i,(double)j} )];
        if        (w < 0)  std::cerr << "u"; //unknonwn
        else if   (w > 100 )  std::cerr << "#"; //obstacle
        else                  std::cerr << ".";

      }
      std::cerr << std::endl;
    }
  }
  else {
    std::cerr << "[Xares replay] Cannot open provided dump file. :-(" << std::endl;
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}//}}}

int replay_lib_dump(char dumpFile[]) {//{{{

  std::cerr << "Not yet implemented..." << std::endl;

  return EXIT_SUCCESS;

}//}}}

int main(int argc, char **argv) {//{{{

  int return_value ;
  return_value = replay_genom_dump( argv[1] ) ;

  std::cerr << "[Xares replay] Done." << std::endl;

  return return_value;

}//}}}

<commit_msg>[replay] Fix the display of the map<commit_after>/*
 * replay.cpp
 *
 * eXploration module for Autonomous Robotic Embedded Systems
 *
 * xares replay : replay dump from xares (and xares-genom)
 *
 * author:  Cyril Robin <cyril.robin@laas.fr>
 * created: 2013-09-19
 * license: BSD
 */

#include <ostream>
#include <fstream>
#include <sys/time.h>

#include "xares/xares.hpp"
#include "gladys/point.hpp"
#include "gladys/weight_map.hpp"

int replay_genom_dump( const std::string& path_to_dump_file) {//{{{

  std::ifstream dump_file;
  dump_file.open (path_to_dump_file) ;

  if ( dump_file.is_open () ) {
    // init
    struct timeval tv0, tv1;

    std::string line, name ;
    gladys::points_t r_pos;
    int n, max_nf ;
    double min_size, x_origin, y_origin, height_max, width_max ;
    double x, y, yaw, min_dist, max_dist ;

    //read data
    getline (dump_file,line) ;
    std::istringstream iss1(line);
    iss1 >> name >> n ;
    std::cerr << "[Xares replay] r_pos ["<< n << "] =";
    while ( n-- > 0) {
      iss1 >> x >> y ;
      r_pos.push_back( gladys::point_xy_t {x,y} );
      std::cerr << " ("<< x << "," << y << ")";
    }
    std::cerr << std::endl;

    getline (dump_file,line) ;
    std::istringstream iss2(line);
    iss2 >> name >> yaw ;
    std::cerr << "[Xares replay] yaw = " << yaw << std::endl;

    // load and display internal params
    getline (dump_file,line) ;
    std::istringstream iss3(line);
    iss3 >> name >> max_nf >> min_size >> min_dist >> max_dist ;
    std::cerr << "[Xares replay] internal params "
              << "(max_nf,min_size,min_dist,max_dist) = ("
              << max_nf << "," << min_size << "," << min_dist << "," << max_dist
              << ")" << std::endl;

    std::cerr << "[Xares replay] max nbr of frontiers = " << max_nf << std::endl;
    getline (dump_file,line) ;
    gladys::weight_map wm ( line );

    // weightmap : origin, size, scale
    std::cerr << "[Xares repay] weight map: (x0,y0,xSc,ySc,W,H) = ("
              << wm.get_utm_pose_x()<< ","
              << wm.get_utm_pose_y()<< ","
              << wm.get_scale_x()   << ","
              << wm.get_scale_y()   << ","
              << wm.get_height()    << ","
              << wm.get_width()     << ")"
              << std::endl;

    // bounded area to explore
    getline (dump_file,line) ;
    std::istringstream iss4(line);
    iss4 >> name >> x_origin >> y_origin >> height_max >> width_max ;
    std::cerr << "[Xares replay] bounded area : (x0,y0,W,H) "
              << x_origin << "," << y_origin << ","
              << height_max << "," << width_max
              << ")" << std::endl;

    dump_file.close();

    // load the planner
    gettimeofday(&tv0, NULL);
    xares::xares xp( wm, x_origin, y_origin, height_max, width_max );
    gettimeofday(&tv1, NULL);

    std::cerr << "[Xares replay] planner loaded ("
              << (tv1.tv_sec -  tv0.tv_sec) * 1000 +
              (tv1.tv_usec - tv0.tv_usec) / 1000 << " ms)." << std::endl;

    // Set internal parameters for xares
    xp.set_params( max_nf, min_size, min_dist, max_dist );
    std::cerr << "[Xares replay] parameters settled. Let's plan !" << std::endl;

    //plan (=replay !)
    gettimeofday(&tv0, NULL);
    xares::xares::return_value rv = xp.plan( r_pos, yaw );
    gettimeofday(&tv1, NULL);

    // parse results
    if ( rv == xares::xares::XARES_FAILURE ) {
      std::cerr << "[Xares replay] #EEE# xares : unexpected data ; unable to compute frontiers :'( " << std::endl;
      return EXIT_SUCCESS;
    }

    if ( rv == xares::xares::XARES_NO_FRONTIER ) {
      std::cerr << "[Xares replay] #EEE# xares : no valuable frontier detected." << std::endl;
      return EXIT_SUCCESS;
    }

    // From here, there should be a valid plan
    std::cerr << "[Xares replay] Plan computed ("
              << (tv1.tv_sec -  tv0.tv_sec) * 1000 +
              (tv1.tv_usec - tv0.tv_usec) / 1000 << " ms)" << std::endl;

    //get planned path
    const gladys::path_t& path = xp.get_goal().path ;

    for (unsigned int i = 0 ; i < path.size() ; i++)
      std::cerr   << "[Xares replay ] ----waypoint #" << i
                  << " = (" << path[i][0]<< "," << path[i][1]
                  <<")"<<std::endl;

    // get poster path
    gladys::path_t::const_iterator it;
    double dist = 0.0;

    gladys::point_xy_t curr = path.front() ;

    unsigned int pt = 0 ;
    for ( it = path.begin(); it != path.end() ; ++it)
    {
      dist += gladys::distance( curr, *it );
      curr = *it;

      if ( dist > 6.0 ) {
        std::cerr   << "[Xares replay ] ---- poster waypoint #" << pt++
                    << " = (" << (*it)[0]<< "," << (*it)[1]
                    <<")"<<std::endl;
      }
    }

    std::cerr   << "[Xares replay ] ---- poster waypoint #" << pt
                << " = (" << curr[0]<< "," << curr[1]
                <<")"<<std::endl;

    // ASCII plot of weightmap, seed & goal
    std::cerr   << "[Xares replay ] ASCII weight map : " << std::endl;
    // foreach from (origin) to (dim+origin)
    for ( double j = wm.get_utm_pose_y(); j < wm.get_width()*wm.get_scale_y() + wm.get_utm_pose_y(); j+= wm.get_scale_y() )
    {
      //if ( j < -21 || j > 19 ) continue; //cropping
      for (double i = wm.get_utm_pose_x(); i < wm.get_height()*wm.get_scale_x() + wm.get_utm_pose_x(); i+= wm.get_scale_x() )
      {

        //if ( i < 0 || i > 60 ) continue; //cropping
        // Special points
        // O = origin
        // S = Seed
        // G = Goal
        if ( i == 0 && j == 0 ) { // origin
            std::cerr << "O"; continue; }
        if ( i == r_pos[0][0] && j == r_pos[0][1] ) { // seed
            std::cerr << "S"; continue; }
        if ( i == curr[0] && j == curr[1] ) { // goal
            std::cerr << "G"; continue;}

        // Common points
        // u = unknown
        // . = known
        // # = obstacle
        double w = wm.get_weight_band()[ wm.index_utm( gladys::point_xy_t {(double)i,(double)j} )];
        if        (w < 0)  std::cerr << "u"; //unknonwn
        else if   (w > 100 )  std::cerr << "#"; //obstacle
        else                  std::cerr << ".";

      }
      std::cerr << std::endl;
    }
  }
  else {
    std::cerr << "[Xares replay] Cannot open provided dump file. :-(" << std::endl;
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}//}}}

int replay_lib_dump(char dumpFile[]) {//{{{

  std::cerr << "Not yet implemented..." << std::endl;

  return EXIT_SUCCESS;

}//}}}

int main(int argc, char **argv) {//{{{

  int return_value ;
  return_value = replay_genom_dump( argv[1] ) ;

  std::cerr << "[Xares replay] Done." << std::endl;

  return return_value;

}//}}}

<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/** Common utilities for internetworking */

#ifndef NET_INET_COMMON_HPP
#define NET_INET_COMMON_HPP

#include <delegate>
#include <net/packet.hpp>
#include <hw/mac_addr.hpp>
#include <net/ethernet/ethertype.hpp>
#include <net/ip4/icmp4_common.hpp>

namespace net {
  // Packet must be forward declared to avoid circular dependency
  // i.e. IP uses Packet, and Packet uses IP headers
  class Packet;
  class Ethernet;

  using LinkLayer = Ethernet;

  using Packet_ptr = std::unique_ptr<Packet>;
  using Frame_ptr = std::unique_ptr<Packet>;

  // Downstream / upstream delegates
  using downstream = delegate<void(Packet_ptr)>;
  using downstream_link = delegate<void(Packet_ptr, MAC::Addr, Ethertype)>;
  using upstream = downstream;

  // Delegate for signalling available buffers in device transmit queue
  using transmit_avail_delg = delegate<void(size_t)>;

  // Compute internet checksum with partial @sum provided
  uint16_t checksum(uint32_t sum, const void* data, size_t len) noexcept;

  // Compute the internet checksum for the buffer / buffer part provided
  inline uint16_t checksum(const void* data, size_t len) noexcept {
    return checksum(0, data, len);
  }

  // View a packet differently based on context
  template <typename T, typename Packet>
  inline auto view_packet_as(Packet packet) noexcept {
    return std::static_pointer_cast<T>(packet);
  }

  template<typename Derived, typename Base>
  auto static_unique_ptr_cast( std::unique_ptr<Base>&& p )
  {
      auto* d = static_cast<Derived *>(p.release());
      return std::unique_ptr<Derived>(d);
  }

  class Error {
  public:
    enum class Type : uint8_t {
      no_error,
      general_IO,
      ifdown,
      ICMP
      // Add more as needed
     };

    virtual Type type()
    { return t_;  }

    virtual const char* what()
    { return msg_; }

    virtual ~Error() = default;

    Error() = default;

    Error(Type t, const char* msg)
      : t_{t}, msg_{msg}
    {};

    operator bool()
    { return t_ != Type::no_error; }

  private:
    Type t_ = Type::no_error;
    const char* msg_ = "No error";
  };

  /* RFC 6335 - IANA */
  namespace port_ranges
  {
    static constexpr uint16_t SYSTEM_START  {0};
    static constexpr uint16_t SYSTEM_END    {1023};
    static constexpr uint16_t USER_START    {1024};
    static constexpr uint16_t USER_END      {49151};
    static constexpr uint16_t DYNAMIC_START {49152};
    static constexpr uint16_t DYNAMIC_END   {65534}; // 65535 never assigned
  }

  /**
   * Known transport layer protocols. Shared between IPv4 and IPv6.
   * Full list:
   * http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
   */
  enum class Protocol : uint8_t {
    HOPOPT  =  0,
    ICMPv4  =  1,
    IPv4    =  4,  // IPv4 encapsulation
    TCP     =  6,
    UDP     = 17,
    IPv6    = 41,  // IPv6 encapsulation
    ICMPv6  = 58
  };

  /**
   * Explicit Congestion Notification (ECN) values for IPv4 and IPv6
   * Defined in RFC3168
   **/
  enum class ECN : uint8_t {
    NOT_ECT = 0b00,   // Non-ECN transport
    ECT_0   = 0b01,   // ECN-enabled transport 1
    ECT_1   = 0b10,   // ECN-enabled transport 2
    CE      = 0b11    // Congestion encountered
  };

  /**
   * Differentiated Services Code Points, for IPv4 and IPv6
   * Defined in RFC2474
   * NOTE: Replaces IPv4 TOS field
   *
   * IANA list:
   * https://www.iana.org/assignments/dscp-registry/dscp-registry.xhtml
   *
   * 6 DSCP bits together with 2 ECN bits form one octet
   **/
  enum class DSCP : uint8_t {
    CS0 = 0b000000,
    CS1 = 0b001000,
    CS2 = 0b010000,
    CS3 = 0b011000,
    CS4 = 0b100000,
    CS5 = 0b101000,
    CS6 = 0b110000,
    CS7 = 0b111000,
    AF11 = 0b001010,
    AF12 = 0b001100,
    AF13 = 0b001110,
    AF21 = 0b010010,
    AF22 = 0b010100,
    AF23 = 0b010110,
    AF31 = 0b011010,
    AF32 = 0b011100,
    AF33 = 0b011110,
    AF41 = 0b100010,
    AF42 = 0b100100,
    AF43 = 0b100110,
    EF_PHB = 0b101110,
    VOICE_ADMIT = 0b101100
  };

  inline uint16_t new_ephemeral_port() noexcept
  { return port_ranges::DYNAMIC_START + rand() % (port_ranges::DYNAMIC_END - port_ranges::DYNAMIC_START); }

} //< namespace net

#endif //< NET_INET_COMMON_HPP
<commit_msg>ICMP_error created, inheriting from Error<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/** Common utilities for internetworking */

#ifndef NET_INET_COMMON_HPP
#define NET_INET_COMMON_HPP

#include <delegate>
#include <net/packet.hpp>
#include <hw/mac_addr.hpp>
#include <net/ethernet/ethertype.hpp>
#include <net/ip4/icmp4_common.hpp>

namespace net {
  // Packet must be forward declared to avoid circular dependency
  // i.e. IP uses Packet, and Packet uses IP headers
  class Packet;
  class Ethernet;

  using LinkLayer = Ethernet;

  using Packet_ptr = std::unique_ptr<Packet>;
  using Frame_ptr = std::unique_ptr<Packet>;

  // Downstream / upstream delegates
  using downstream = delegate<void(Packet_ptr)>;
  using downstream_link = delegate<void(Packet_ptr, MAC::Addr, Ethertype)>;
  using upstream = downstream;

  // Delegate for signalling available buffers in device transmit queue
  using transmit_avail_delg = delegate<void(size_t)>;

  // Compute internet checksum with partial @sum provided
  uint16_t checksum(uint32_t sum, const void* data, size_t len) noexcept;

  // Compute the internet checksum for the buffer / buffer part provided
  inline uint16_t checksum(const void* data, size_t len) noexcept {
    return checksum(0, data, len);
  }

  // View a packet differently based on context
  template <typename T, typename Packet>
  inline auto view_packet_as(Packet packet) noexcept {
    return std::static_pointer_cast<T>(packet);
  }

  template<typename Derived, typename Base>
  auto static_unique_ptr_cast( std::unique_ptr<Base>&& p )
  {
      auto* d = static_cast<Derived *>(p.release());
      return std::unique_ptr<Derived>(d);
  }

  /**
   *  General Error class for the OS
   *  ICMP_error in icmp4_common.hpp f.ex. inherits from this class
   */
  class Error {
  public:

    enum class Type : uint8_t {
      no_error,
      general_IO,
      ifdown,
      ICMP
      // Add more as needed
    };

    virtual Type type()
    { return t_; }

    virtual const char* what()
    { return msg_; }

    virtual ~Error() = default;

    Error() = default;

    Error(Type t, const char* msg)
      : t_{t}, msg_{msg}
    {}

    operator bool() const noexcept
    { return t_ != Type::no_error; }

  private:
    Type t_{Type::no_error};
    const char* msg_{"No error"};

  };  // < class Error

  /**
   *  An object of this error class is sent to UDP and TCP (via Inet) when an ICMP error message
   *  is received in ICMPv4::receive
   *
   *  Inherits from the Error class in inet_common.hpp
   */
  class ICMP_error : public Error {

  public:
    using ICMP_type = icmp4::Type;
    using ICMP_code = uint8_t;    // Codes in icmp4_common.hpp in namespace icmp4::code
                                  // icmp4::code::Dest_unreachable::PORT f.ex.

    ICMP_error(Type t, const char* msg, ICMP_type icmp_type, ICMP_code icmp_code)
      : Error{t, msg}, icmp_type_{icmp_type}, icmp_code_{icmp_code}
    {}

    ICMP_type icmp_type() const noexcept
    { return icmp_type_; }

    std::string icmp_type_str() const
    { return icmp4::get_type_string(icmp_type_); }

    void set_icmp_type(ICMP_type icmp_type)
    { icmp_type_ = icmp_type; }

    ICMP_code icmp_code() const noexcept
    { return icmp_code_; }

    std::string icmp_code_str() const
    { return icmp4::get_code_string(icmp_type_, icmp_code_); }

    void set_icmp_code(ICMP_code icmp_code)
    { icmp_code_ = icmp_code; }

  private:
    ICMP_type icmp_type_{ICMP_type::NO_REPLY};
    ICMP_code icmp_code_{0};

  };  // < class ICMP_error

  /* RFC 6335 - IANA */
  namespace port_ranges
  {
    static constexpr uint16_t SYSTEM_START  {0};
    static constexpr uint16_t SYSTEM_END    {1023};
    static constexpr uint16_t USER_START    {1024};
    static constexpr uint16_t USER_END      {49151};
    static constexpr uint16_t DYNAMIC_START {49152};
    static constexpr uint16_t DYNAMIC_END   {65534}; // 65535 never assigned
  }

  /**
   * Known transport layer protocols. Shared between IPv4 and IPv6.
   * Full list:
   * http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
   */
  enum class Protocol : uint8_t {
    HOPOPT  =  0,
    ICMPv4  =  1,
    IPv4    =  4,  // IPv4 encapsulation
    TCP     =  6,
    UDP     = 17,
    IPv6    = 41,  // IPv6 encapsulation
    ICMPv6  = 58
  };

  /**
   * Explicit Congestion Notification (ECN) values for IPv4 and IPv6
   * Defined in RFC3168
   **/
  enum class ECN : uint8_t {
    NOT_ECT = 0b00,   // Non-ECN transport
    ECT_0   = 0b01,   // ECN-enabled transport 1
    ECT_1   = 0b10,   // ECN-enabled transport 2
    CE      = 0b11    // Congestion encountered
  };

  /**
   * Differentiated Services Code Points, for IPv4 and IPv6
   * Defined in RFC2474
   * NOTE: Replaces IPv4 TOS field
   *
   * IANA list:
   * https://www.iana.org/assignments/dscp-registry/dscp-registry.xhtml
   *
   * 6 DSCP bits together with 2 ECN bits form one octet
   **/
  enum class DSCP : uint8_t {
    CS0 = 0b000000,
    CS1 = 0b001000,
    CS2 = 0b010000,
    CS3 = 0b011000,
    CS4 = 0b100000,
    CS5 = 0b101000,
    CS6 = 0b110000,
    CS7 = 0b111000,
    AF11 = 0b001010,
    AF12 = 0b001100,
    AF13 = 0b001110,
    AF21 = 0b010010,
    AF22 = 0b010100,
    AF23 = 0b010110,
    AF31 = 0b011010,
    AF32 = 0b011100,
    AF33 = 0b011110,
    AF41 = 0b100010,
    AF42 = 0b100100,
    AF43 = 0b100110,
    EF_PHB = 0b101110,
    VOICE_ADMIT = 0b101100
  };

  inline uint16_t new_ephemeral_port() noexcept
  { return port_ranges::DYNAMIC_START + rand() % (port_ranges::DYNAMIC_END - port_ranges::DYNAMIC_START); }

} //< namespace net

#endif //< NET_INET_COMMON_HPP
<|endoftext|>


<commit_before>#ifndef MAP_THREAD_SAFE
#define MAP_THREAD_SAFE

#include <map>
#include <thread>
#include <mutex>
#include <shared_mutex>

namespace std
{
    namespace threadsafe
    {
        /*
        Concurrent Map prototype, it allows concurrent reads and safe writes.

        */
        template<class K,class V>
        class map
        {
            std::map<K,V> internal_map;

            std::shared_mutex mutex;

            public:
                map(){}
                map(const std::map<K,V> &m) : internal_map(m){}
                map(const std::threadsafe::map &m) = delete;

                V get(const K& key)
                {
                    std::shared_lock<std::shared_mutex> lock(mutex);
                    auto it = internal_map.find(key);
                    if (it == internal_map.end())
                    {
                        return nullptr;
                    }
                    else{
                        return V(it->second);
                    }
                }

                bool insert(const K & key,V & value){
                    std::unique_lock<std::shared_mutex> lock(mutex);
                    return internal_map.insert(std::make_pair(key,value)).second;
                }

                size_t erase(const K & key){
                    std::unique_lock<std::shared_mutex> lock(mutex);
                    return internal_map.erase(key);
                }

                size_t size(){
                    std::shared_lock<std::shared_mutex> lock(mutex);
                    return internal_map.size();
                }

                bool contains(const K& key){
                    std::shared_lock<std::shared_mutex> lock(mutex);
                    auto it = internal_map.find(key);
                    return it == internal_map.end();
                }

                V putIfAbsent(const K& key,const V& value){
			std::unique_lock<std::shared_mutex> lock(mutex);
			auto it = internal_map.find(key);
			if (it == internal_map.end()){
				internal_map.insert(std::make_pair(key,value));
				return value;
			}
			else
				return it->second;
		}

		bool remove(const K& key,const V& value){
			std::unique_lock<std::shared_mutex> lock(mutex);
			auto it = internal_map.find(key);
			if (it == internal_map.end() || it->second != value)
				return false
			else
			{
				internal_map.erase(it);
				return true;
			}
		}

		bool replace(const K& key,const V& value){
			std::unique_lock<std::shared_mutex> lock(mutex);

			auto it = internal_map.find(key);
			if (it != internal_map.end()){
				it->second = value;
				return true;
			}
			return false;
		}

		bool replace(const K& key,V& oldValue,V& newValue){
			std::unique_lock<std::shared_mutex> lock(mutex);

			auto it = internal_map.find(key);
			if (it != internal_map.end() && it->second == oldValue){
				it->second = newValue;
				return true;
			}
			return false;
		}
        };
    }
}

#endif
<commit_msg>Implemented [] operator in map<commit_after>#ifndef MAP_THREAD_SAFE
#define MAP_THREAD_SAFE

#include <map>
#include <thread>
#include <mutex>
#include <shared_mutex>

namespace std
{
    namespace threadsafe
    {
        /*
        Concurrent Map prototype, it allows concurrent reads and safe writes.

        */
        template<class K,class V>
        class map
        {
            std::map<K,V> internal_map;

            std::shared_mutex mutex;

            public:
                map(){}
                map(const std::map<K,V> &m) : internal_map(m){}
                map(const std::threadsafe::map &m) = delete;

                V get(const K& key)
                {
                    std::shared_lock<std::shared_mutex> lock(mutex);
                    auto it = internal_map.find(key);
                    if (it == internal_map.end())
                    {
                        return nullptr;
                    }
                    else{
                        return V(it->second);
                    }
                }

		V operator[](const K& key){
			return get(key);
		}

                bool insert(const K & key,V & value){
                    std::unique_lock<std::shared_mutex> lock(mutex);
                    return internal_map.insert(std::make_pair(key,value)).second;
                }

                size_t erase(const K & key){
                    std::unique_lock<std::shared_mutex> lock(mutex);
                    return internal_map.erase(key);
                }

                size_t size(){
                    std::shared_lock<std::shared_mutex> lock(mutex);
                    return internal_map.size();
                }

                bool contains(const K& key){
                    std::shared_lock<std::shared_mutex> lock(mutex);
                    auto it = internal_map.find(key);
                    return it == internal_map.end();
                }

                V putIfAbsent(const K& key,const V& value){
			std::unique_lock<std::shared_mutex> lock(mutex);
			auto it = internal_map.find(key);
			if (it == internal_map.end()){
				internal_map.insert(std::make_pair(key,value));
				return value;
			}
			else
				return it->second;
		}

		bool remove(const K& key,const V& value){
			std::unique_lock<std::shared_mutex> lock(mutex);
			auto it = internal_map.find(key);
			if (it == internal_map.end() || it->second != value)
				return false
			else
			{
				internal_map.erase(it);
				return true;
			}
		}

		bool replace(const K& key,const V& value){
			std::unique_lock<std::shared_mutex> lock(mutex);

			auto it = internal_map.find(key);
			if (it != internal_map.end()){
				it->second = value;
				return true;
			}
			return false;
		}

		bool replace(const K& key,V& oldValue,V& newValue){
			std::unique_lock<std::shared_mutex> lock(mutex);

			auto it = internal_map.find(key);
			if (it != internal_map.end() && it->second == oldValue){
				it->second = newValue;
				return true;
			}
			return false;
		}
        };
    }
}

#endif
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_FEATURE_HPP
#define MAPNIK_FEATURE_HPP

// mapnik
#include <mapnik/config.hpp>
#include <mapnik/value.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/raster.hpp>
#include <mapnik/feature_kv_iterator.hpp>
#include <mapnik/noncopyable.hpp>

// boost
#include <boost/version.hpp>
#if BOOST_VERSION >= 104000
#include <boost/property_map/property_map.hpp>
#else
#include <boost/property_map.hpp>
#endif

#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>

// stl
#include <vector>
#include <map>
#include <stdexcept>

namespace mapnik {

typedef boost::shared_ptr<raster> raster_ptr;

class feature_impl;

template <typename T>
class context : private mapnik::noncopyable,
                public boost::associative_property_map<T>

{
    friend class feature_impl;
public:
    typedef T map_type;
    typedef typename boost::associative_property_map<map_type> base_type;
    typedef typename map_type::value_type value_type;
    typedef typename map_type::key_type key_type;
    typedef typename map_type::size_type size_type;
    typedef typename map_type::difference_type difference_type;
    typedef typename map_type::iterator iterator;
    typedef typename map_type::const_iterator const_iterator;

    context()
        : base_type(mapping_) {}

    size_type push(key_type const& name)
    {
        size_type index = mapping_.size();
        mapping_.insert(std::make_pair(name, index));
        return index;
    }

    void add(key_type const& name, size_type index)
    {
        mapping_.insert(std::make_pair(name, index));
    }

    size_type size() const { return mapping_.size(); }
    const_iterator begin() const { return mapping_.begin();}
    const_iterator end() const { return mapping_.end();}

private:
    map_type mapping_;
};

typedef MAPNIK_DECL context<std::map<std::string,std::size_t> > context_type;
typedef MAPNIK_DECL boost::shared_ptr<context_type> context_ptr;

static const value default_value;

class MAPNIK_DECL feature_impl : private mapnik::noncopyable
{
    friend class feature_kv_iterator;
public:

    typedef mapnik::value value_type;
    typedef std::vector<value_type> cont_type;
    typedef feature_kv_iterator iterator;

    feature_impl(context_ptr const& ctx, mapnik::value_integer id)
        : id_(id),
        ctx_(ctx),
        data_(ctx_->mapping_.size()),
        geom_cont_(),
        raster_()
        {}

    inline mapnik::value_integer id() const { return id_;}

    inline void set_id(mapnik::value_integer id) { id_ = id;}

    template <typename T>
    void put(context_type::key_type const& key, T const& val)
    {
        put(key,value(val));
    }

    template <typename T>
    void put_new(context_type::key_type const& key, T const& val)
    {
        put_new(key,value(val));
    }

    void put(context_type::key_type const& key, value const& val)
    {
        context_type::map_type::const_iterator itr = ctx_->mapping_.find(key);
        if (itr != ctx_->mapping_.end()
            && itr->second < data_.size())
        {
            data_[itr->second] = val;
        }
        else
        {
            throw std::out_of_range(std::string("Key does not exist: '") + key + "'");
        }
    }

    void put_new(context_type::key_type const& key, value const& val)
    {
        context_type::map_type::const_iterator itr = ctx_->mapping_.find(key);
        if (itr != ctx_->mapping_.end()
            && itr->second < data_.size())
        {
            data_[itr->second] = val;
        }
        else
        {
            cont_type::size_type index = ctx_->push(key);
            if (index == data_.size())
                data_.push_back(val);
        }
    }

    bool has_key(context_type::key_type const& key) const
    {
        return (ctx_->mapping_.find(key) != ctx_->mapping_.end());
    }

    value_type const& get(context_type::key_type const& key) const
    {
        context_type::map_type::const_iterator itr = ctx_->mapping_.find(key);
        if (itr != ctx_->mapping_.end())
            return get(itr->second);
        else
            return default_value;
    }

    value_type const& get(std::size_t index) const
    {
        if (index < data_.size())
            return data_[index];
        return default_value;
    }

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

    cont_type const& get_data() const
    {
        return data_;
    }

    void set_data(cont_type const& data)
    {
        data_ = data;
    }

    context_ptr context()
    {
        return ctx_;
    }

    boost::ptr_vector<geometry_type> const& paths() const
    {
        return geom_cont_;
    }

    boost::ptr_vector<geometry_type> & paths()
    {
        return geom_cont_;
    }

    void add_geometry(geometry_type * geom)
    {
        geom_cont_.push_back(geom);
    }

    unsigned num_geometries() const
    {
        return geom_cont_.size();
    }

    geometry_type const& get_geometry(unsigned index) const
    {
        return geom_cont_[index];
    }

    geometry_type& get_geometry(unsigned index)
    {
        return geom_cont_[index];
    }

    box2d<double> envelope() const
    {
        // TODO - cache this
        box2d<double> result;
        for (unsigned i=0;i<num_geometries();++i)
        {
            geometry_type const& geom = get_geometry(i);
            if (i==0)
            {
                box2d<double> const& box = geom.envelope();
                result.init(box.minx(),box.miny(),box.maxx(),box.maxy());
            }
            else
            {
                result.expand_to_include(geom.envelope());
            }
        }
        return result;
    }

    raster_ptr const& get_raster() const
    {
        return raster_;
    }

    void set_raster(raster_ptr const& raster)
    {
        raster_ = raster;
    }

    feature_kv_iterator begin() const
    {
        return feature_kv_iterator(*this,true);
    }

    feature_kv_iterator end() const
    {
        return feature_kv_iterator(*this);
    }

    std::string to_string() const
    {
        std::stringstream ss;
        ss << "Feature ( id=" << id_ << std::endl;
        context_type::map_type::const_iterator itr = ctx_->mapping_.begin();
        context_type::map_type::const_iterator end = ctx_->mapping_.end();
        for ( ;itr!=end; ++itr)
        {
            std::size_t index = itr->second;
            if (index < data_.size())
            {
                if (data_[itr->second] == mapnik::value_null())
                {
                    ss << "  " << itr->first  << ":null" << std::endl;
                }
                else
                {
                    ss << "  " << itr->first  << ":" <<  data_[itr->second] << std::endl;
                }
            }
        }
        ss << ")" << std::endl;
        return ss.str();
    }

private:
    mapnik::value_integer id_;
    context_ptr ctx_;
    cont_type data_;
    boost::ptr_vector<geometry_type> geom_cont_;
    raster_ptr raster_;
};

inline std::ostream& operator<< (std::ostream & out,feature_impl const& f)
{
    out << f.to_string();
    return out;
}

typedef feature_impl Feature;

typedef MAPNIK_DECL boost::shared_ptr<Feature> feature_ptr;

}

#endif // MAPNIK_FEATURE_HPP
<commit_msg>remove boost::property_map, which is unneeded in new context interface<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_FEATURE_HPP
#define MAPNIK_FEATURE_HPP

// mapnik
#include <mapnik/config.hpp>
#include <mapnik/value_types.hpp>
#include <mapnik/value.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/feature_kv_iterator.hpp>
#include <mapnik/noncopyable.hpp>

// boost
#include <boost/shared_ptr.hpp>
#include <boost/ptr_container/ptr_vector.hpp>

// stl
#include <vector>
#include <map>
#include <ostream>                      // for basic_ostream, operator<<, etc
#include <sstream>                      // for basic_stringstream
#include <stdexcept>                    // for out_of_range

namespace mapnik {

class raster;
class feature_impl;

typedef boost::shared_ptr<raster> raster_ptr;

template <typename T>
class context : private mapnik::noncopyable

{
    friend class feature_impl;
public:
    typedef T map_type;
    typedef typename map_type::value_type value_type;
    typedef typename map_type::key_type key_type;
    typedef typename map_type::size_type size_type;
    typedef typename map_type::difference_type difference_type;
    typedef typename map_type::iterator iterator;
    typedef typename map_type::const_iterator const_iterator;

    context()
        : mapping_() {}

    size_type push(key_type const& name)
    {
        size_type index = mapping_.size();
        mapping_.insert(std::make_pair(name, index));
        return index;
    }

    void add(key_type const& name, size_type index)
    {
        mapping_.insert(std::make_pair(name, index));
    }

    size_type size() const { return mapping_.size(); }
    const_iterator begin() const { return mapping_.begin();}
    const_iterator end() const { return mapping_.end();}

private:
    map_type mapping_;
};

typedef MAPNIK_DECL context<std::map<std::string,std::size_t> > context_type;
typedef MAPNIK_DECL boost::shared_ptr<context_type> context_ptr;

static const value default_value;

class MAPNIK_DECL feature_impl : private mapnik::noncopyable
{
    friend class feature_kv_iterator;
public:

    typedef mapnik::value value_type;
    typedef std::vector<value_type> cont_type;
    typedef feature_kv_iterator iterator;

    feature_impl(context_ptr const& ctx, mapnik::value_integer id)
        : id_(id),
        ctx_(ctx),
        data_(ctx_->mapping_.size()),
        geom_cont_(),
        raster_()
        {}

    inline mapnik::value_integer id() const { return id_;}

    inline void set_id(mapnik::value_integer id) { id_ = id;}

    template <typename T>
    void put(context_type::key_type const& key, T const& val)
    {
        put(key,value(val));
    }

    template <typename T>
    void put_new(context_type::key_type const& key, T const& val)
    {
        put_new(key,value(val));
    }

    void put(context_type::key_type const& key, value const& val)
    {
        context_type::map_type::const_iterator itr = ctx_->mapping_.find(key);
        if (itr != ctx_->mapping_.end()
            && itr->second < data_.size())
        {
            data_[itr->second] = val;
        }
        else
        {
            throw std::out_of_range(std::string("Key does not exist: '") + key + "'");
        }
    }

    void put_new(context_type::key_type const& key, value const& val)
    {
        context_type::map_type::const_iterator itr = ctx_->mapping_.find(key);
        if (itr != ctx_->mapping_.end()
            && itr->second < data_.size())
        {
            data_[itr->second] = val;
        }
        else
        {
            cont_type::size_type index = ctx_->push(key);
            if (index == data_.size())
                data_.push_back(val);
        }
    }

    bool has_key(context_type::key_type const& key) const
    {
        return (ctx_->mapping_.find(key) != ctx_->mapping_.end());
    }

    value_type const& get(context_type::key_type const& key) const
    {
        context_type::map_type::const_iterator itr = ctx_->mapping_.find(key);
        if (itr != ctx_->mapping_.end())
            return get(itr->second);
        else
            return default_value;
    }

    value_type const& get(std::size_t index) const
    {
        if (index < data_.size())
            return data_[index];
        return default_value;
    }

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

    cont_type const& get_data() const
    {
        return data_;
    }

    void set_data(cont_type const& data)
    {
        data_ = data;
    }

    context_ptr context()
    {
        return ctx_;
    }

    boost::ptr_vector<geometry_type> const& paths() const
    {
        return geom_cont_;
    }

    boost::ptr_vector<geometry_type> & paths()
    {
        return geom_cont_;
    }

    void add_geometry(geometry_type * geom)
    {
        geom_cont_.push_back(geom);
    }

    unsigned num_geometries() const
    {
        return geom_cont_.size();
    }

    geometry_type const& get_geometry(unsigned index) const
    {
        return geom_cont_[index];
    }

    geometry_type& get_geometry(unsigned index)
    {
        return geom_cont_[index];
    }

    box2d<double> envelope() const
    {
        // TODO - cache this
        box2d<double> result;
        for (unsigned i=0;i<num_geometries();++i)
        {
            geometry_type const& geom = get_geometry(i);
            if (i==0)
            {
                box2d<double> const& box = geom.envelope();
                result.init(box.minx(),box.miny(),box.maxx(),box.maxy());
            }
            else
            {
                result.expand_to_include(geom.envelope());
            }
        }
        return result;
    }

    raster_ptr const& get_raster() const
    {
        return raster_;
    }

    void set_raster(raster_ptr const& raster)
    {
        raster_ = raster;
    }

    feature_kv_iterator begin() const
    {
        return feature_kv_iterator(*this,true);
    }

    feature_kv_iterator end() const
    {
        return feature_kv_iterator(*this);
    }

    std::string to_string() const
    {
        std::stringstream ss;
        ss << "Feature ( id=" << id_ << std::endl;
        context_type::map_type::const_iterator itr = ctx_->mapping_.begin();
        context_type::map_type::const_iterator end = ctx_->mapping_.end();
        for ( ;itr!=end; ++itr)
        {
            std::size_t index = itr->second;
            if (index < data_.size())
            {
                if (data_[itr->second] == mapnik::value_null())
                {
                    ss << "  " << itr->first  << ":null" << std::endl;
                }
                else
                {
                    ss << "  " << itr->first  << ":" <<  data_[itr->second] << std::endl;
                }
            }
        }
        ss << ")" << std::endl;
        return ss.str();
    }

private:
    mapnik::value_integer id_;
    context_ptr ctx_;
    cont_type data_;
    boost::ptr_vector<geometry_type> geom_cont_;
    raster_ptr raster_;
};

inline std::ostream& operator<< (std::ostream & out,feature_impl const& f)
{
    out << f.to_string();
    return out;
}

typedef feature_impl Feature;

typedef MAPNIK_DECL boost::shared_ptr<Feature> feature_ptr;

}

#endif // MAPNIK_FEATURE_HPP
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id$
#ifndef UNICODE_HPP
#define UNICODE_HPP

#include <string>
#include <boost/utility.hpp>

#ifdef USE_FRIBIDI
#include <fribidi/fribidi.h>
#endif

#include <iconv.h>

namespace mapnik {

/*
** Use FRIBIDI to encode the string.
** The return value must be freed by the caller.
*/

#ifdef USE_FRIBIDI
    inline wchar_t* bidi_string(const wchar_t *logical)
    {
        FriBidiCharType base = FRIBIDI_TYPE_ON;
        size_t len;

        len = wcslen(logical);

        FriBidiChar *visual;

        FriBidiStrIndex *ltov, *vtol;
        FriBidiLevel *levels;
        FriBidiStrIndex new_len;
        fribidi_boolean log2vis;

        visual = (FriBidiChar *) malloc (sizeof (FriBidiChar) * (len + 1));
        ltov = 0;
        vtol = 0;
        levels = 0;

        /* Create a bidi string. */
        log2vis = fribidi_log2vis ((FriBidiChar *)logical, len, &base,
                /* output */
                visual, ltov, vtol, levels);

        if (!log2vis) {
            return 0;
        }

        new_len = len;

        return (wchar_t *)visual;
    }
#endif

    inline std::wstring to_unicode(std::string const& text)
    {
        std::wstring out;
        unsigned long code = 0;
        int expect = 0;
        std::string::const_iterator itr=text.begin();
        std::string::const_iterator end=text.end();
        while ( itr != end)
        {
            unsigned p = (*itr++) & 0xff;
            if ( p >= 0xc0)
            {
                if ( p < 0xe0)      // U+0080 - U+07ff
                {
                    expect = 1;
                    code = p & 0x1f;
                }
                else if ( p < 0xf0)  // U+0800 - U+ffff
                {
                    expect = 2;
                    code = p & 0x0f;
                }
                else if ( p  < 0xf8) // U+1000 - U+10ffff
                {
                    expect = 3;
                    code = p & 0x07;
                }
                continue;
            }
            else if (p >= 0x80)
            {
                --expect;
                if (expect >= 0)
                {
                    code <<= 6;
                    code += p & 0x3f;
                }
                if (expect > 0)
                    continue;
                expect = 0;
            }
            else
            {
                code = p;            // U+0000 - U+007f (ascii)
            }
            out.push_back(wchar_t(code));
        }
#ifdef USE_FRIBIDI
        wchar_t *bidi_text = bidi_string(out.c_str());
        out = bidi_text;
        free(bidi_text);
#endif

        return out;
    }

   inline std::wstring latin1_to_unicode(std::string const& text)
   {
      std::wstring out;
      std::string::const_iterator itr=text.begin();
      std::string::const_iterator end=text.end();
      while ( itr != end)
      {
         unsigned p = (*itr++) & 0xff;
         out.push_back(wchar_t(p));
      }
      return out;
   }

   inline std::string latin1_to_unicode2(std::string const& text)
   {
      std::string out;
      std::string::const_iterator itr=text.begin();
      std::string::const_iterator end=text.end();
      while ( itr != end)
      {
         out.push_back(0x00);
         out.push_back(*itr++);
      }
      return out;
   }

   class transcoder : private boost::noncopyable
   {
      public:
         explicit transcoder (std::string const& encoding)
         {
            desc_ = iconv_open("UCS-2",encoding.c_str());
         }

         std::wstring transcode(std::string const& input) const
         {
            std::string buf(input.size() * 2,0);
            size_t inleft = input.size();
            char * in  = const_cast<char*>(input.data());
            size_t outleft = buf.size();
            char * out = const_cast<char*>(buf.data());

            iconv(desc_,&in,&inleft,&out,&outleft);

            std::string::const_iterator itr = buf.begin();
            std::string::const_iterator end = buf.end();
            wchar_t wch = 0;
            bool state = false;
            std::wstring unicode;
            size_t num_char = buf.size() - outleft;
            for ( ; itr != end; ++itr)
            {
               if (!state)
               {
                  wch = (*itr & 0xff);
                  state = true;
               }
               else
               {
                  wch |= *itr << 8 ;
                  unicode.push_back(wchar_t(wch));
                  state = false;
               }
               if (!num_char--) break;
            }

#ifdef USE_FRIBIDI
            wchar_t *bidi_text = bidi_string(unicode.c_str());
            unicode = bidi_text;
            free(bidi_text);
#endif
            return unicode;
         }

         ~transcoder()
         {
            iconv_close(desc_);
         }

   private:
      iconv_t desc_;
   };
}

#endif // UNICODE_HPP
<commit_msg>check strings size before applying bidi.  <commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id$
#ifndef UNICODE_HPP
#define UNICODE_HPP

#include <string>
#include <boost/utility.hpp>

#ifdef USE_FRIBIDI
#include <fribidi/fribidi.h>
#endif

#include <iconv.h>

namespace mapnik {

/*
** Use FRIBIDI to encode the string.
** The return value must be freed by the caller.
*/

#ifdef USE_FRIBIDI
    inline wchar_t* bidi_string(const wchar_t *logical)
    {
        FriBidiCharType base = FRIBIDI_TYPE_ON;
        size_t len;

        len = wcslen(logical);

        FriBidiChar *visual;

        FriBidiStrIndex *ltov, *vtol;
        FriBidiLevel *levels;
        FriBidiStrIndex new_len;
        fribidi_boolean log2vis;

        visual = (FriBidiChar *) malloc (sizeof (FriBidiChar) * (len + 1));
        ltov = 0;
        vtol = 0;
        levels = 0;

        /* Create a bidi string. */
        log2vis = fribidi_log2vis ((FriBidiChar *)logical, len, &base,
                /* output */
                visual, ltov, vtol, levels);

        if (!log2vis) {
            return 0;
        }

        new_len = len;

        return (wchar_t *)visual;
    }
#endif

    inline std::wstring to_unicode(std::string const& text)
    {
        std::wstring out;
        unsigned long code = 0;
        int expect = 0;
        std::string::const_iterator itr=text.begin();
        std::string::const_iterator end=text.end();
        while ( itr != end)
        {
            unsigned p = (*itr++) & 0xff;
            if ( p >= 0xc0)
            {
                if ( p < 0xe0)      // U+0080 - U+07ff
                {
                    expect = 1;
                    code = p & 0x1f;
                }
                else if ( p < 0xf0)  // U+0800 - U+ffff
                {
                    expect = 2;
                    code = p & 0x0f;
                }
                else if ( p  < 0xf8) // U+1000 - U+10ffff
                {
                    expect = 3;
                    code = p & 0x07;
                }
                continue;
            }
            else if (p >= 0x80)
            {
                --expect;
                if (expect >= 0)
                {
                    code <<= 6;
                    code += p & 0x3f;
                }
                if (expect > 0)
                    continue;
                expect = 0;
            }
            else
            {
                code = p;            // U+0000 - U+007f (ascii)
            }
            out.push_back(wchar_t(code));
        }
#ifdef USE_FRIBIDI
        wchar_t *bidi_text = bidi_string(out.c_str());
        out = bidi_text;
        free(bidi_text);
#endif

        return out;
    }

   inline std::wstring latin1_to_unicode(std::string const& text)
   {
      std::wstring out;
      std::string::const_iterator itr=text.begin();
      std::string::const_iterator end=text.end();
      while ( itr != end)
      {
         unsigned p = (*itr++) & 0xff;
         out.push_back(wchar_t(p));
      }
      return out;
   }

   inline std::string latin1_to_unicode2(std::string const& text)
   {
      std::string out;
      std::string::const_iterator itr=text.begin();
      std::string::const_iterator end=text.end();
      while ( itr != end)
      {
         out.push_back(0x00);
         out.push_back(*itr++);
      }
      return out;
   }

   class transcoder : private boost::noncopyable
   {
      public:
         explicit transcoder (std::string const& encoding)
         {
            desc_ = iconv_open("UCS-2",encoding.c_str());
         }

         std::wstring transcode(std::string const& input) const
         {
            std::string buf(input.size() * 2,0);
            size_t inleft = input.size();
            char * in  = const_cast<char*>(input.data());
            size_t outleft = buf.size();
            char * out = const_cast<char*>(buf.data());

            iconv(desc_,&in,&inleft,&out,&outleft);

            std::string::const_iterator itr = buf.begin();
            std::string::const_iterator end = buf.end();
            wchar_t wch = 0;
            bool state = false;
            std::wstring unicode;
            size_t num_char = buf.size() - outleft;
            for ( ; itr != end; ++itr)
            {
               if (!state)
               {
                  wch = (*itr & 0xff);
                  state = true;
               }
               else
               {
                  wch |= *itr << 8 ;
                  unicode.push_back(wchar_t(wch));
                  state = false;
               }
               if (!num_char--) break;
            }

#ifdef USE_FRIBIDI
            if (unicode.length() > 0)
            {
               wchar_t *bidi_text = bidi_string(unicode.c_str());
               unicode = bidi_text;
               free(bidi_text);
            }
#endif
            return unicode;
         }

         ~transcoder()
         {
            iconv_close(desc_);
         }

   private:
      iconv_t desc_;
   };
}

#endif // UNICODE_HPP
<|endoftext|>