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

#include "chrome/browser/gtk/options/customize_sync_window_gtk.h"

#include <gtk/gtk.h>

#include <string>

#include "app/gtk_signal.h"
#include "app/l10n_util.h"
#include "base/message_loop.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/gtk/accessible_widget_helper_gtk.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/options_window.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"

///////////////////////////////////////////////////////////////////////////////
// CustomizeSyncWindowGtk
//
// The contents of the Customize Sync dialog window.

class CustomizeSyncWindowGtk {
 public:
  explicit CustomizeSyncWindowGtk(Profile* profile);
  ~CustomizeSyncWindowGtk();

  void Show();
  bool ClickOk();
  void ClickCancel();

 private:
  // The pixel width we wrap labels at.
  static const int kWrapWidth = 475;

  GtkWidget* AddCheckbox(GtkWidget* parent, int label_id, bool checked);
  bool Accept();

  static void OnWindowDestroy(GtkWidget* widget,
                              CustomizeSyncWindowGtk* window);

  static void OnResponse(GtkDialog* dialog, gint response_id,
                         CustomizeSyncWindowGtk* customize_sync_window);

  CHROMEGTK_CALLBACK_0(CustomizeSyncWindowGtk, void, OnCheckboxClicked);

  // The customize sync dialog.
  GtkWidget *dialog_;

  Profile* profile_;

  GtkWidget* description_label_;
  GtkWidget* bookmarks_check_box_;
  GtkWidget* preferences_check_box_;
  GtkWidget* themes_check_box_;
  GtkWidget* autofill_check_box_;

  // Helper object to manage accessibility metadata.
  scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_;

  DISALLOW_COPY_AND_ASSIGN(CustomizeSyncWindowGtk);
};

// The singleton customize sync window object.
static CustomizeSyncWindowGtk* customize_sync_window = NULL;

///////////////////////////////////////////////////////////////////////////////
// CustomizeSyncWindowGtk, public:

CustomizeSyncWindowGtk::CustomizeSyncWindowGtk(Profile* profile)
    : profile_(profile),
      description_label_(NULL),
      bookmarks_check_box_(NULL),
      preferences_check_box_(NULL),
      themes_check_box_(NULL),
      autofill_check_box_(NULL) {
  syncable::ModelTypeSet registered_types;
  profile_->GetProfileSyncService()->GetRegisteredDataTypes(&registered_types);
  syncable::ModelTypeSet preferred_types;
  profile_->GetProfileSyncService()->GetPreferredDataTypes(&preferred_types);

  std::string dialog_name = l10n_util::GetStringUTF8(
      IDS_CUSTOMIZE_SYNC_WINDOW_TITLE);
  dialog_ = gtk_dialog_new_with_buttons(
      dialog_name.c_str(),
      // Customize sync window is shared between all browser windows.
      NULL,
      // Non-modal.
      GTK_DIALOG_NO_SEPARATOR,
      GTK_STOCK_OK,
      GTK_RESPONSE_OK,
      GTK_STOCK_CANCEL,
      GTK_RESPONSE_CANCEL,
      NULL);
  gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox),
                      gtk_util::kContentAreaSpacing);

  accessible_widget_helper_.reset(new AccessibleWidgetHelper(
      dialog_, profile));
  accessible_widget_helper_->SendOpenWindowNotification(dialog_name);

  GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);

  description_label_ = gtk_label_new(l10n_util::GetStringUTF8(
      IDS_CUSTOMIZE_SYNC_DESCRIPTION).c_str());
  gtk_label_set_line_wrap(GTK_LABEL(description_label_), TRUE);
  gtk_widget_set_size_request(description_label_, kWrapWidth, -1);
  gtk_box_pack_start(GTK_BOX(vbox), description_label_, FALSE, FALSE, 0);

  accessible_widget_helper_->SetWidgetName(description_label_,
      IDS_CUSTOMIZE_SYNC_DESCRIPTION);

  DCHECK(registered_types.count(syncable::BOOKMARKS));
  bool bookmarks_checked = preferred_types.count(syncable::BOOKMARKS) != 0;
  bookmarks_check_box_ = AddCheckbox(vbox, IDS_SYNC_DATATYPE_BOOKMARKS,
                                     bookmarks_checked);

  if (registered_types.count(syncable::PREFERENCES)) {
    bool prefs_checked = preferred_types.count(syncable::PREFERENCES) != 0;
    preferences_check_box_ = AddCheckbox(vbox, IDS_SYNC_DATATYPE_PREFERENCES,
                                         prefs_checked);
  }

  if (registered_types.count(syncable::THEMES)) {
    bool themes_checked = preferred_types.count(syncable::THEMES) != 0;
    themes_check_box_ = AddCheckbox(vbox, IDS_SYNC_DATATYPE_THEMES,
                                    themes_checked);
  }

  if (registered_types.count(syncable::AUTOFILL)) {
    bool autofill_checked = preferred_types.count(syncable::AUTOFILL) != 0;
    autofill_check_box_ = AddCheckbox(vbox, IDS_SYNC_DATATYPE_AUTOFILL,
      autofill_checked);
  }

  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), vbox, FALSE, FALSE, 0);

  gtk_widget_realize(dialog_);
  gtk_util::SetWindowSizeFromResources(GTK_WINDOW(dialog_),
                                       IDS_CUSTOMIZE_SYNC_DIALOG_WIDTH_CHARS,
                                       IDS_CUSTOMIZE_SYNC_DIALOG_HEIGHT_LINES,
                                       true);

  g_signal_connect(dialog_, "response", G_CALLBACK(OnResponse), this);
  g_signal_connect(dialog_, "destroy", G_CALLBACK(OnWindowDestroy), this);

  gtk_widget_show_all(dialog_);
}

CustomizeSyncWindowGtk::~CustomizeSyncWindowGtk() {
}

void CustomizeSyncWindowGtk::Show() {
  // Bring options window to front if it already existed and isn't already
  // in front
  gtk_window_present(GTK_WINDOW(dialog_));
}

bool CustomizeSyncWindowGtk::ClickOk() {

  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(bookmarks_check_box_)) ||
      (preferences_check_box_ &&
       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
           preferences_check_box_))) ||
      (themes_check_box_ &&
       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(themes_check_box_))) ||
      (autofill_check_box_ &&
       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(autofill_check_box_)))) {
    Accept();
    gtk_widget_destroy(GTK_WIDGET(dialog_));
    return true;
  } else {
    // show the user that something's wrong with this dialog (not perfect, but
    // a temporary fix)
    gtk_window_present(GTK_WINDOW(dialog_));
    return false;
  }
}

void CustomizeSyncWindowGtk::ClickCancel() {
  gtk_widget_destroy(GTK_WIDGET(dialog_));
}

///////////////////////////////////////////////////////////////////////////////
// CustomizeSyncWindowGtk, private:

GtkWidget* CustomizeSyncWindowGtk::AddCheckbox(GtkWidget* parent, int label_id,
                                               bool checked) {

  GtkWidget* checkbox = gtk_check_button_new_with_label(
      l10n_util::GetStringUTF8(label_id).c_str());

  gtk_box_pack_start(GTK_BOX(parent), checkbox, FALSE, FALSE, 0);
  accessible_widget_helper_->SetWidgetName(checkbox, label_id);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox), checked);

  g_signal_connect(checkbox, "clicked", G_CALLBACK(OnCheckboxClickedThunk),
                   this);

  return checkbox;
}

bool CustomizeSyncWindowGtk::Accept() {
  syncable::ModelTypeSet preferred_types;

  bool bookmarks_enabled = gtk_toggle_button_get_active(
      GTK_TOGGLE_BUTTON(bookmarks_check_box_));
  if (bookmarks_enabled) {
    preferred_types.insert(syncable::BOOKMARKS);
  }

  if (preferences_check_box_) {
    bool preferences_enabled = gtk_toggle_button_get_active(
        GTK_TOGGLE_BUTTON(preferences_check_box_));
    if (preferences_enabled) {
      preferred_types.insert(syncable::PREFERENCES);
    }
  }
  if (themes_check_box_) {
    bool themes_enabled = gtk_toggle_button_get_active(
        GTK_TOGGLE_BUTTON(themes_check_box_));
    if (themes_enabled) {
      preferred_types.insert(syncable::THEMES);
    }
  }
  if (autofill_check_box_) {
    bool autofill_enabled = gtk_toggle_button_get_active(
      GTK_TOGGLE_BUTTON(autofill_check_box_));
    if (autofill_enabled) {
      preferred_types.insert(syncable::AUTOFILL);
    }
  }

  profile_->GetProfileSyncService()->ChangePreferredDataTypes(preferred_types);
  return true;
}

// static
void CustomizeSyncWindowGtk::OnWindowDestroy(GtkWidget* widget,
                                             CustomizeSyncWindowGtk* window) {
  customize_sync_window = NULL;
  MessageLoop::current()->DeleteSoon(FROM_HERE, window);
}

// static
void CustomizeSyncWindowGtk::OnResponse(
    GtkDialog* dialog, gint response_id,
    CustomizeSyncWindowGtk* customize_sync_window) {
  if (response_id == GTK_RESPONSE_OK) {
    customize_sync_window->ClickOk();
  } else if (response_id == GTK_RESPONSE_CANCEL) {
    customize_sync_window->ClickCancel();
  }
}

// Deactivate the "OK" button if you uncheck all the data types.
void CustomizeSyncWindowGtk::OnCheckboxClicked(GtkWidget* widget) {
  bool any_datatypes_selected =
      gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(bookmarks_check_box_)) ||
      (preferences_check_box_ &&
       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
           preferences_check_box_))) ||
      (themes_check_box_ &&
       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(themes_check_box_))) ||
      (autofill_check_box_ &&
       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(autofill_check_box_)));
  if (any_datatypes_selected) {
    gtk_dialog_set_response_sensitive(
        GTK_DIALOG(customize_sync_window->dialog_), GTK_RESPONSE_OK, TRUE);
  } else {
    gtk_dialog_set_response_sensitive(
        GTK_DIALOG(customize_sync_window->dialog_), GTK_RESPONSE_OK, FALSE);
  }
}

///////////////////////////////////////////////////////////////////////////////
// Factory/finder method:

void ShowCustomizeSyncWindow(Profile* profile) {
  DCHECK(profile);
  // If there's already an existing window, use it.
  if (!customize_sync_window) {
    customize_sync_window = new CustomizeSyncWindowGtk(profile);
  }
  customize_sync_window->Show();
}

bool CustomizeSyncWindowOk() {
  if (customize_sync_window) {
    return customize_sync_window->ClickOk();
  } else {
    return true;
  }
}

void CustomizeSyncWindowCancel() {
  if (customize_sync_window) {
    customize_sync_window->ClickCancel();
  }
}
<commit_msg>Put CustomizeSyncWindowGtk in NativeDialogHost for ChromeOS.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/gtk/options/customize_sync_window_gtk.h"

#include <gtk/gtk.h>

#include <string>

#include "app/gtk_signal.h"
#include "app/l10n_util.h"
#include "base/message_loop.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/gtk/accessible_widget_helper_gtk.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/options_window.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/sync/glue/data_type_controller.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/common/pref_names.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"

///////////////////////////////////////////////////////////////////////////////
// CustomizeSyncWindowGtk
//
// The contents of the Customize Sync dialog window.

class CustomizeSyncWindowGtk {
 public:
  explicit CustomizeSyncWindowGtk(Profile* profile);
  ~CustomizeSyncWindowGtk();

  void Show();
  bool ClickOk();
  void ClickCancel();

 private:
  // The pixel width we wrap labels at.
  static const int kWrapWidth = 475;

  GtkWidget* AddCheckbox(GtkWidget* parent, int label_id, bool checked);
  bool Accept();

  static void OnWindowDestroy(GtkWidget* widget,
                              CustomizeSyncWindowGtk* window);

  static void OnResponse(GtkDialog* dialog, gint response_id,
                         CustomizeSyncWindowGtk* customize_sync_window);

  CHROMEGTK_CALLBACK_0(CustomizeSyncWindowGtk, void, OnCheckboxClicked);

  // The customize sync dialog.
  GtkWidget *dialog_;

  Profile* profile_;

  GtkWidget* description_label_;
  GtkWidget* bookmarks_check_box_;
  GtkWidget* preferences_check_box_;
  GtkWidget* themes_check_box_;
  GtkWidget* autofill_check_box_;

  // Helper object to manage accessibility metadata.
  scoped_ptr<AccessibleWidgetHelper> accessible_widget_helper_;

  DISALLOW_COPY_AND_ASSIGN(CustomizeSyncWindowGtk);
};

// The singleton customize sync window object.
static CustomizeSyncWindowGtk* customize_sync_window = NULL;

///////////////////////////////////////////////////////////////////////////////
// CustomizeSyncWindowGtk, public:

CustomizeSyncWindowGtk::CustomizeSyncWindowGtk(Profile* profile)
    : profile_(profile),
      description_label_(NULL),
      bookmarks_check_box_(NULL),
      preferences_check_box_(NULL),
      themes_check_box_(NULL),
      autofill_check_box_(NULL) {
  syncable::ModelTypeSet registered_types;
  profile_->GetProfileSyncService()->GetRegisteredDataTypes(&registered_types);
  syncable::ModelTypeSet preferred_types;
  profile_->GetProfileSyncService()->GetPreferredDataTypes(&preferred_types);

  std::string dialog_name = l10n_util::GetStringUTF8(
      IDS_CUSTOMIZE_SYNC_WINDOW_TITLE);
  dialog_ = gtk_dialog_new_with_buttons(
      dialog_name.c_str(),
      // Customize sync window is shared between all browser windows.
      NULL,
      // Non-modal.
      GTK_DIALOG_NO_SEPARATOR,
      GTK_STOCK_OK,
      GTK_RESPONSE_OK,
      GTK_STOCK_CANCEL,
      GTK_RESPONSE_CANCEL,
      NULL);
  gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox),
                      gtk_util::kContentAreaSpacing);

  accessible_widget_helper_.reset(new AccessibleWidgetHelper(
      dialog_, profile));
  accessible_widget_helper_->SendOpenWindowNotification(dialog_name);

  GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);

  description_label_ = gtk_label_new(l10n_util::GetStringUTF8(
      IDS_CUSTOMIZE_SYNC_DESCRIPTION).c_str());
  gtk_label_set_line_wrap(GTK_LABEL(description_label_), TRUE);
  gtk_widget_set_size_request(description_label_, kWrapWidth, -1);
  gtk_box_pack_start(GTK_BOX(vbox), description_label_, FALSE, FALSE, 0);

  accessible_widget_helper_->SetWidgetName(description_label_,
      IDS_CUSTOMIZE_SYNC_DESCRIPTION);

  DCHECK(registered_types.count(syncable::BOOKMARKS));
  bool bookmarks_checked = preferred_types.count(syncable::BOOKMARKS) != 0;
  bookmarks_check_box_ = AddCheckbox(vbox, IDS_SYNC_DATATYPE_BOOKMARKS,
                                     bookmarks_checked);

  if (registered_types.count(syncable::PREFERENCES)) {
    bool prefs_checked = preferred_types.count(syncable::PREFERENCES) != 0;
    preferences_check_box_ = AddCheckbox(vbox, IDS_SYNC_DATATYPE_PREFERENCES,
                                         prefs_checked);
  }

  if (registered_types.count(syncable::THEMES)) {
    bool themes_checked = preferred_types.count(syncable::THEMES) != 0;
    themes_check_box_ = AddCheckbox(vbox, IDS_SYNC_DATATYPE_THEMES,
                                    themes_checked);
  }

  if (registered_types.count(syncable::AUTOFILL)) {
    bool autofill_checked = preferred_types.count(syncable::AUTOFILL) != 0;
    autofill_check_box_ = AddCheckbox(vbox, IDS_SYNC_DATATYPE_AUTOFILL,
      autofill_checked);
  }

  gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), vbox, FALSE, FALSE, 0);

  gtk_widget_realize(dialog_);
  gtk_util::SetWindowSizeFromResources(GTK_WINDOW(dialog_),
                                       IDS_CUSTOMIZE_SYNC_DIALOG_WIDTH_CHARS,
                                       IDS_CUSTOMIZE_SYNC_DIALOG_HEIGHT_LINES,
                                       true);

  g_signal_connect(dialog_, "response", G_CALLBACK(OnResponse), this);
  g_signal_connect(dialog_, "destroy", G_CALLBACK(OnWindowDestroy), this);

  gtk_util::ShowDialog(dialog_);
}

CustomizeSyncWindowGtk::~CustomizeSyncWindowGtk() {
}

void CustomizeSyncWindowGtk::Show() {
  // Bring options window to front if it already existed and isn't already
  // in front
  gtk_util::PresentWindow(dialog_, 0);
}

bool CustomizeSyncWindowGtk::ClickOk() {

  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(bookmarks_check_box_)) ||
      (preferences_check_box_ &&
       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
           preferences_check_box_))) ||
      (themes_check_box_ &&
       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(themes_check_box_))) ||
      (autofill_check_box_ &&
       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(autofill_check_box_)))) {
    Accept();
    gtk_widget_destroy(GTK_WIDGET(dialog_));
    return true;
  } else {
    // show the user that something's wrong with this dialog (not perfect, but
    // a temporary fix)
    gtk_util::PresentWindow(dialog_, 0);
    return false;
  }
}

void CustomizeSyncWindowGtk::ClickCancel() {
  gtk_widget_destroy(GTK_WIDGET(dialog_));
}

///////////////////////////////////////////////////////////////////////////////
// CustomizeSyncWindowGtk, private:

GtkWidget* CustomizeSyncWindowGtk::AddCheckbox(GtkWidget* parent, int label_id,
                                               bool checked) {

  GtkWidget* checkbox = gtk_check_button_new_with_label(
      l10n_util::GetStringUTF8(label_id).c_str());

  gtk_box_pack_start(GTK_BOX(parent), checkbox, FALSE, FALSE, 0);
  accessible_widget_helper_->SetWidgetName(checkbox, label_id);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox), checked);

  g_signal_connect(checkbox, "clicked", G_CALLBACK(OnCheckboxClickedThunk),
                   this);

  return checkbox;
}

bool CustomizeSyncWindowGtk::Accept() {
  syncable::ModelTypeSet preferred_types;

  bool bookmarks_enabled = gtk_toggle_button_get_active(
      GTK_TOGGLE_BUTTON(bookmarks_check_box_));
  if (bookmarks_enabled) {
    preferred_types.insert(syncable::BOOKMARKS);
  }

  if (preferences_check_box_) {
    bool preferences_enabled = gtk_toggle_button_get_active(
        GTK_TOGGLE_BUTTON(preferences_check_box_));
    if (preferences_enabled) {
      preferred_types.insert(syncable::PREFERENCES);
    }
  }
  if (themes_check_box_) {
    bool themes_enabled = gtk_toggle_button_get_active(
        GTK_TOGGLE_BUTTON(themes_check_box_));
    if (themes_enabled) {
      preferred_types.insert(syncable::THEMES);
    }
  }
  if (autofill_check_box_) {
    bool autofill_enabled = gtk_toggle_button_get_active(
      GTK_TOGGLE_BUTTON(autofill_check_box_));
    if (autofill_enabled) {
      preferred_types.insert(syncable::AUTOFILL);
    }
  }

  profile_->GetProfileSyncService()->ChangePreferredDataTypes(preferred_types);
  return true;
}

// static
void CustomizeSyncWindowGtk::OnWindowDestroy(GtkWidget* widget,
                                             CustomizeSyncWindowGtk* window) {
  customize_sync_window = NULL;
  MessageLoop::current()->DeleteSoon(FROM_HERE, window);
}

// static
void CustomizeSyncWindowGtk::OnResponse(
    GtkDialog* dialog, gint response_id,
    CustomizeSyncWindowGtk* customize_sync_window) {
  if (response_id == GTK_RESPONSE_OK) {
    customize_sync_window->ClickOk();
  } else if (response_id == GTK_RESPONSE_CANCEL) {
    customize_sync_window->ClickCancel();
  }
}

// Deactivate the "OK" button if you uncheck all the data types.
void CustomizeSyncWindowGtk::OnCheckboxClicked(GtkWidget* widget) {
  bool any_datatypes_selected =
      gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(bookmarks_check_box_)) ||
      (preferences_check_box_ &&
       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
           preferences_check_box_))) ||
      (themes_check_box_ &&
       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(themes_check_box_))) ||
      (autofill_check_box_ &&
       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(autofill_check_box_)));
  if (any_datatypes_selected) {
    gtk_dialog_set_response_sensitive(
        GTK_DIALOG(customize_sync_window->dialog_), GTK_RESPONSE_OK, TRUE);
  } else {
    gtk_dialog_set_response_sensitive(
        GTK_DIALOG(customize_sync_window->dialog_), GTK_RESPONSE_OK, FALSE);
  }
}

///////////////////////////////////////////////////////////////////////////////
// Factory/finder method:

void ShowCustomizeSyncWindow(Profile* profile) {
  DCHECK(profile);
  // If there's already an existing window, use it.
  if (!customize_sync_window) {
    customize_sync_window = new CustomizeSyncWindowGtk(profile);
  }
  customize_sync_window->Show();
}

bool CustomizeSyncWindowOk() {
  if (customize_sync_window) {
    return customize_sync_window->ClickOk();
  } else {
    return true;
  }
}

void CustomizeSyncWindowCancel() {
  if (customize_sync_window) {
    customize_sync_window->ClickCancel();
  }
}
<|endoftext|>


<commit_before>/* -*- Mode:C++; c-file-style:"gnu" -*- */
/*
 * Copyright 2014 Waseda University, Sato Laboratory
 *   Author: Takahiro Miyamoto <mt3.mos@gmail.com>
 *           Jairo Eduardo Lopez <jairo@ruri.waseda.jp>
 *
 *  nnn-nnpt.cc is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  nnn-nnpt.cc 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 Affero Public License for more details.
 *
 *  You should have received a copy of the GNU Affero Public License
 *  along with nnn-nnpt.cc.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "nnn-nnpt.h"

#include <ns3-dev/ns3/log.h>

NS_LOG_COMPONENT_DEFINE ("nnn.nnpt");

namespace ns3
{
  namespace nnn
  {
    NS_OBJECT_ENSURE_REGISTERED (NNPT);

    TypeId
    NNPT::GetTypeId (void)
    {
      static TypeId tid = TypeId ("ns3::nnn::NNPT") // cheating ns3 object system
	  .SetParent<Object> ()
	  .SetGroupName ("Nnn")
	  .AddConstructor<NNPT> ()
	  ;
      return tid;
    }

    NNPT::NNPT() {
    }

    NNPT::~NNPT() {
    }

    void
    NNPT::addEntry (Ptr<const NNNAddress> oldName, Ptr<const NNNAddress> newName, Time lease_expire)
    {
      NS_LOG_FUNCTION (this);

      if (!foundOldName(oldName) && !foundOldName(newName))
        {
	  // We assume that the lease time gives us the absolute expiry time
	  // We need to calculate the relative time for the Schedule function
	  Time relativeExpireTime = lease_expire - Simulator::Now ();
          container.insert(nnpt::Entry(oldName, newName, lease_expire));

          // If the relative expire time is above 0, we can save it
          if (relativeExpireTime.IsStrictlyPositive())
            {
              Simulator::Schedule(lease_expire, &NNPT::cleanExpired, this);
            }
        }
      else
        {
          NS_LOG_INFO("Found either " << *oldName << " or " << *newName << " already in NNPT");
        }
    }

    void
    NNPT::deleteEntry (Ptr<const NNNAddress> oldName)
    {
      NS_LOG_FUNCTION (this);
      nnpt::Entry tmp = findEntry (oldName);
      container.erase(tmp);
    }

    void
    NNPT::deleteEntry (nnpt::Entry nnptEntry)
    {
      NS_LOG_FUNCTION (this);
      container.erase(nnptEntry);
    }

    bool
    NNPT::foundOldName (Ptr<const NNNAddress> name)
    {
      NS_LOG_FUNCTION (this);
      pair_set_by_oldname& names_index = container.get<oldname> ();
      pair_set_by_oldname::iterator it = names_index.find(name);

      if (it == names_index.end())
	return false;
      else
	return true;
    }

    bool
    NNPT::foundNewName (Ptr<const NNNAddress> name)
    {
      NS_LOG_FUNCTION (this);
      pair_set_by_newname& names_index = container.get<newname> ();
      pair_set_by_newname::iterator it = names_index.find(name);

      if (it == names_index.end())
	return false;
      else
	return true;
    }

    const NNNAddress&
    NNPT::findPairedName (Ptr<const NNNAddress> oldName)
    {
      NS_LOG_FUNCTION (this);

      return *findPairedNamePtr(oldName);
    }

    const NNNAddress&
    NNPT::findPairedOldName (Ptr<const NNNAddress> newName)
    {
      NS_LOG_FUNCTION (this);

      return *findPairedOldNamePtr(newName);
    }

    Ptr<const NNNAddress>
    NNPT::findPairedNamePtr (Ptr<const NNNAddress> oldName)
    {
      NS_LOG_FUNCTION (this);
      pair_set_by_oldname& pair_index = container.get<oldname> ();
      pair_set_by_oldname::iterator it = pair_index.find(oldName);

      if (it != pair_index.end())
	{
	  nnpt::Entry tmp;
	  // Check if there is a newer entry
	  while (true)
	    {
	      tmp = *it;
	      it = pair_index.find(tmp.m_newName);
	      if (it == pair_index.end())
		break;
	    }
	  return tmp.m_newName;
	}
      else
	{
	  return oldName;
	}
    }

    Ptr<const NNNAddress>
    NNPT::findPairedOldNamePtr (Ptr<const NNNAddress> newName)
    {
      NS_LOG_FUNCTION (this);
      pair_set_by_newname& pair_index = container.get<newname> ();
      pair_set_by_newname::iterator it = pair_index.find(newName);

      if (it != pair_index.end ())
	{
	  nnpt::Entry tmp;
	  // Check if there is a newer entry
	  while (true)
	    {
	      tmp = *it;
	      it = pair_index.find (tmp.m_oldName);
	      if (it == pair_index.end ())
		break;
	    }
	  return tmp.m_oldName;
	}
      else
	{
	  return newName;
	}
    }

    nnpt::Entry
    NNPT::findEntry (Ptr<const NNNAddress> name)
    {
      NS_LOG_FUNCTION (this);
      pair_set_by_oldname& pair_index = container.get<oldname> ();
      pair_set_by_oldname::iterator it = pair_index.find(name);

      if (it != pair_index.end())
	{
	  return *it;
	}
      else
	{
	  return nnpt::Entry ();
	}
    }

    void
    NNPT::updateLeaseTime (Ptr<const NNNAddress> oldName, Time lease_expire)
    {
      NS_LOG_FUNCTION (this);
      pair_set_by_oldname& pair_index = container.get<oldname> ();
      pair_set_by_oldname::iterator it = pair_index.find(oldName);

      if (it != pair_index.end())
	{
	  nnpt::Entry tmp = *it;

	  tmp.m_lease_expire = lease_expire;

	  if (pair_index.replace(it, tmp))
	    {
	      Time relativeExpireTime = lease_expire - Simulator::Now ();

	      // If the relative expire time is above 0, schedule the next clean
	      if (relativeExpireTime.IsStrictlyPositive())
		{
		  Simulator::Schedule(relativeExpireTime, &NNPT::cleanExpired, this);
		}
	    }
	}
    }

    uint32_t
    NNPT::size ()
    {
      NS_LOG_FUNCTION (this);
      return container.size();
    }

    bool
    NNPT::isEmpty ()
    {
      NS_LOG_FUNCTION (this);
      return (container.size() == 0);
    }

    Time
    NNPT::findNameExpireTime (Ptr<const NNNAddress> name)
    {
      NS_LOG_FUNCTION (this);
      nnpt::Entry tmp = findEntry(name);

      return tmp.m_lease_expire;
    }

    Time
    NNPT::findNameExpireTime (nnpt::Entry nnptEntry)
    {
      NS_LOG_FUNCTION (this);
      return nnptEntry.m_lease_expire;
    }

    void
    NNPT::cleanExpired ()
    {
      NS_LOG_FUNCTION (this);
      pair_set_by_lease& lease_index = container.get<st_lease> ();
      Time now = Simulator::Now();

      //std::cout << "Deleting expired entries at " << now << std::endl;

      pair_set_by_lease::iterator it = lease_index.begin();

      while (! isEmpty())
	{
	  if (it->m_lease_expire <= now)
	    {
	      deleteEntry(*it);
	      break;
	    }
	  ++it;
	}
    }

    void
    NNPT::printByAddress ()
    {
      pair_set_by_oldname& pair_index = container.get<oldname> ();
      pair_set_by_oldname::iterator it = pair_index.begin();

      std::cout << "Old Address\t| New Address\t| Lease Expire" << std::endl;
      std::cout << "-------------------------------------------------" << std::endl;

      while (it != pair_index.end())
	{
	  std::cout << *it;
	  ++it;
	}
    }

    void
    NNPT::printByLease ()
    {
      pair_set_by_lease& lease_index = container.get<st_lease> ();
      pair_set_by_lease::iterator it = lease_index.begin();

      std::cout << "NNN Address\t| New Address\t| Lease Expire" << std::endl;
      std::cout << "-------------------------------------------------" << std::endl;

      while (it != lease_index.end ())
	{
	  std::cout << *it;
	  ++it;
	}
    }

    std::ostream&
    operator<< (std::ostream& os, const NNPT &nnpt)
    {
      return os;
    }

  } /* namespace nnn */
} /* namespace ns3 */
<commit_msg>Realized relative time being strictly positive is a precondition<commit_after>/* -*- Mode:C++; c-file-style:"gnu" -*- */
/*
 * Copyright 2014 Waseda University, Sato Laboratory
 *   Author: Takahiro Miyamoto <mt3.mos@gmail.com>
 *           Jairo Eduardo Lopez <jairo@ruri.waseda.jp>
 *
 *  nnn-nnpt.cc is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  nnn-nnpt.cc 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 Affero Public License for more details.
 *
 *  You should have received a copy of the GNU Affero Public License
 *  along with nnn-nnpt.cc.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "nnn-nnpt.h"

#include <ns3-dev/ns3/log.h>

NS_LOG_COMPONENT_DEFINE ("nnn.nnpt");

namespace ns3
{
  namespace nnn
  {
    NS_OBJECT_ENSURE_REGISTERED (NNPT);

    TypeId
    NNPT::GetTypeId (void)
    {
      static TypeId tid = TypeId ("ns3::nnn::NNPT") // cheating ns3 object system
	  .SetParent<Object> ()
	  .SetGroupName ("Nnn")
	  .AddConstructor<NNPT> ()
	  ;
      return tid;
    }

    NNPT::NNPT() {
    }

    NNPT::~NNPT() {
    }

    void
    NNPT::addEntry (Ptr<const NNNAddress> oldName, Ptr<const NNNAddress> newName, Time lease_expire)
    {
      NS_LOG_FUNCTION (this);

      if (!foundOldName(oldName) && !foundOldName(newName))
        {
	  // We assume that the lease time gives us the absolute expiry time
	  // We need to calculate the relative time for the Schedule function
	  Time now = Simulator::Now ();
	  Time relativeExpireTime = lease_expire - now;

	  NS_LOG_INFO ("Checking remaining lease time " << relativeExpireTime << " for (" << *newName << ") at " << now);

          // If the relative expire time is above 0, we can save it
          if (relativeExpireTime.IsStrictlyPositive())
            {
              container.insert(nnpt::Entry(oldName, newName, lease_expire));
              Simulator::Schedule(lease_expire, &NNPT::cleanExpired, this);
            }
        }
      else
        {
          NS_LOG_INFO("Found either " << *oldName << " or " << *newName << " already in NNPT");
        }
    }

    void
    NNPT::deleteEntry (Ptr<const NNNAddress> oldName)
    {
      NS_LOG_FUNCTION (this);
      nnpt::Entry tmp = findEntry (oldName);
      container.erase(tmp);
    }

    void
    NNPT::deleteEntry (nnpt::Entry nnptEntry)
    {
      NS_LOG_FUNCTION (this);
      container.erase(nnptEntry);
    }

    bool
    NNPT::foundOldName (Ptr<const NNNAddress> name)
    {
      NS_LOG_FUNCTION (this);
      pair_set_by_oldname& names_index = container.get<oldname> ();
      pair_set_by_oldname::iterator it = names_index.find(name);

      if (it == names_index.end())
	return false;
      else
	return true;
    }

    bool
    NNPT::foundNewName (Ptr<const NNNAddress> name)
    {
      NS_LOG_FUNCTION (this);
      pair_set_by_newname& names_index = container.get<newname> ();
      pair_set_by_newname::iterator it = names_index.find(name);

      if (it == names_index.end())
	return false;
      else
	return true;
    }

    const NNNAddress&
    NNPT::findPairedName (Ptr<const NNNAddress> oldName)
    {
      NS_LOG_FUNCTION (this);

      return *findPairedNamePtr(oldName);
    }

    const NNNAddress&
    NNPT::findPairedOldName (Ptr<const NNNAddress> newName)
    {
      NS_LOG_FUNCTION (this);

      return *findPairedOldNamePtr(newName);
    }

    Ptr<const NNNAddress>
    NNPT::findPairedNamePtr (Ptr<const NNNAddress> oldName)
    {
      NS_LOG_FUNCTION (this);
      pair_set_by_oldname& pair_index = container.get<oldname> ();
      pair_set_by_oldname::iterator it = pair_index.find(oldName);

      if (it != pair_index.end())
	{
	  nnpt::Entry tmp;
	  // Check if there is a newer entry
	  while (true)
	    {
	      tmp = *it;
	      it = pair_index.find(tmp.m_newName);
	      if (it == pair_index.end())
		break;
	    }
	  return tmp.m_newName;
	}
      else
	{
	  return oldName;
	}
    }

    Ptr<const NNNAddress>
    NNPT::findPairedOldNamePtr (Ptr<const NNNAddress> newName)
    {
      NS_LOG_FUNCTION (this);
      pair_set_by_newname& pair_index = container.get<newname> ();
      pair_set_by_newname::iterator it = pair_index.find(newName);

      if (it != pair_index.end ())
	{
	  nnpt::Entry tmp;
	  // Check if there is a newer entry
	  while (true)
	    {
	      tmp = *it;
	      it = pair_index.find (tmp.m_oldName);
	      if (it == pair_index.end ())
		break;
	    }
	  return tmp.m_oldName;
	}
      else
	{
	  return newName;
	}
    }

    nnpt::Entry
    NNPT::findEntry (Ptr<const NNNAddress> name)
    {
      NS_LOG_FUNCTION (this);
      pair_set_by_oldname& pair_index = container.get<oldname> ();
      pair_set_by_oldname::iterator it = pair_index.find(name);

      if (it != pair_index.end())
	{
	  return *it;
	}
      else
	{
	  return nnpt::Entry ();
	}
    }

    void
    NNPT::updateLeaseTime (Ptr<const NNNAddress> oldName, Time lease_expire)
    {
      NS_LOG_FUNCTION (this);
      pair_set_by_oldname& pair_index = container.get<oldname> ();
      pair_set_by_oldname::iterator it = pair_index.find(oldName);

      Time relativeExpireTime = lease_expire - Simulator::Now ();

      // If the relative expire time is above 0, schedule the next clean
      if (relativeExpireTime.IsStrictlyPositive())
	{
	  if (it != pair_index.end())
	    {
	      nnpt::Entry tmp = *it;

	      tmp.m_lease_expire = lease_expire;

	      if (pair_index.replace(it, tmp))
		{
		  Simulator::Schedule(relativeExpireTime, &NNPT::cleanExpired, this);
		}
	    }
	}
    }

    uint32_t
    NNPT::size ()
    {
      NS_LOG_FUNCTION (this);
      return container.size();
    }

    bool
    NNPT::isEmpty ()
    {
      NS_LOG_FUNCTION (this);
      return (container.size() == 0);
    }

    Time
    NNPT::findNameExpireTime (Ptr<const NNNAddress> name)
    {
      NS_LOG_FUNCTION (this);
      nnpt::Entry tmp = findEntry(name);

      return tmp.m_lease_expire;
    }

    Time
    NNPT::findNameExpireTime (nnpt::Entry nnptEntry)
    {
      NS_LOG_FUNCTION (this);
      return nnptEntry.m_lease_expire;
    }

    void
    NNPT::cleanExpired ()
    {
      NS_LOG_FUNCTION (this);
      pair_set_by_lease& lease_index = container.get<st_lease> ();
      Time now = Simulator::Now();

      //std::cout << "Deleting expired entries at " << now << std::endl;

      pair_set_by_lease::iterator it = lease_index.begin();

      while (! isEmpty())
	{
	  if (it->m_lease_expire <= now)
	    {
	      deleteEntry(*it);
	      break;
	    }
	  ++it;
	}
    }

    void
    NNPT::printByAddress ()
    {
      pair_set_by_oldname& pair_index = container.get<oldname> ();
      pair_set_by_oldname::iterator it = pair_index.begin();

      std::cout << "Old Address\t| New Address\t| Lease Expire" << std::endl;
      std::cout << "-------------------------------------------------" << std::endl;

      while (it != pair_index.end())
	{
	  std::cout << *it;
	  ++it;
	}
    }

    void
    NNPT::printByLease ()
    {
      pair_set_by_lease& lease_index = container.get<st_lease> ();
      pair_set_by_lease::iterator it = lease_index.begin();

      std::cout << "NNN Address\t| New Address\t| Lease Expire" << std::endl;
      std::cout << "-------------------------------------------------" << std::endl;

      while (it != lease_index.end ())
	{
	  std::cout << *it;
	  ++it;
	}
    }

    std::ostream&
    operator<< (std::ostream& os, const NNPT &nnpt)
    {
      return os;
    }

  } /* namespace nnn */
} /* namespace ns3 */
<|endoftext|>


<commit_before><commit_msg>Limit and simplify variable lifetimes used in the IME code. From johnsonj and Neil.<commit_after><|endoftext|>


<commit_before>/*
**
* BEGIN_COPYRIGHT
*
* load_tools is a plugin for SciDB.  Copyright (C) 2008-2014 SciDB, Inc.
*
* load_tools is free software: you can redistribute it and/or modify
* it under the terms of the AFFERO GNU General Public License as published by
* the Free Software Foundation.
*
* load_tools is distributed "AS-IS" AND WITHOUT ANY WARRANTY OF ANY KIND,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* NON-INFRINGEMENT, OR FITNESS FOR A PARTICULAR PURPOSE. See
* the AFFERO GNU General Public License for the complete license terms.
*
* You should have received a copy of the AFFERO GNU General Public License
* along with load_tools.  If not, see <http://www.gnu.org/licenses/agpl-3.0.html>
*
* END_COPYRIGHT
*/

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <vector>

#include <boost/lexical_cast.hpp>
#include <boost/assign.hpp>
#include <boost/algorithm/string.hpp>

#include "query/FunctionLibrary.h"
#include "query/FunctionDescription.h"
#include "system/ErrorsLibrary.h"

using namespace std;
using namespace boost;
using namespace boost::assign;
using namespace scidb;

/**
 * DCAST: cast with default, does not throw an error. Tries to cast input to the appropriate type. If the cast fails,
 * returns the supplied default.
 */
template <typename T>
static void dcast(const Value** args, Value *res, void*)
{
  if(args[0]->isNull())
  {
      res->setNull(args[0]->getMissingReason());
      return;
  }
  const char* s = args[0]->getString();
  try
  {
      T result = lexical_cast<T>(s);
      res->set<T>(result);
  }
  catch(...)
  {
      Value const* def = args[1];
      if(def->isNull())
      {
          res->setNull( def->getMissingReason());
      }
      else
      {
          res->set<T>(def->get<T>());
      }
  }
}

static scidb::UserDefinedFunction dcast_double (scidb::FunctionDescription("dcast", list_of("string")("double"), "double", &dcast<double> ));
static scidb::UserDefinedFunction dcast_float (scidb::FunctionDescription("dcast", list_of("string")("float"), "float", &dcast<float> ));
static scidb::UserDefinedFunction dcast_bool (scidb::FunctionDescription("dcast", list_of("string")("bool"), "bool", &dcast<bool> ));
static scidb::UserDefinedFunction dcast_int64  (scidb::FunctionDescription("dcast", list_of("string")("int64"),  "int64" , &dcast<int64_t>));
static scidb::UserDefinedFunction dcast_int32 (scidb::FunctionDescription("dcast", list_of("string")("int32"), "int32", &dcast<int32_t> ));
static scidb::UserDefinedFunction dcast_int16 (scidb::FunctionDescription("dcast", list_of("string")("int16"), "int16", &dcast<int16_t> ));
static scidb::UserDefinedFunction dcast_int8 (scidb::FunctionDescription("dcast", list_of("string")("int8"), "int8", &dcast<int8_t> ));
static scidb::UserDefinedFunction dcast_uint64 (scidb::FunctionDescription("dcast", list_of("string")("uint64"), "uint64", &dcast<uint64_t> ));
static scidb::UserDefinedFunction dcast_uint32 (scidb::FunctionDescription("dcast", list_of("string")("uint32"), "uint32", &dcast<uint32_t> ));
static scidb::UserDefinedFunction dcast_uint16 (scidb::FunctionDescription("dcast", list_of("string")("uint16"), "uint16", &dcast<uint16_t> ));
static scidb::UserDefinedFunction dcast_uint8 (scidb::FunctionDescription("dcast", list_of("string")("uint8"), "uint8", &dcast<uint8_t> ));

// XXX How to add datetime conversion here? The naive approach:
//static scidb::UserDefinedFunction dcast_datetimetz (scidb::FunctionDescription("dcast", list_of("string")("datetimetz"), "datetimetz", &dcast<datetimetz> ));
// doesn't work!

/**
 * first argument: the string to trim
 * second argument: a set of characters to trim, represented as another string {S}
 * returns: the first argument with all occurrences of any of the characters in S removed from the beginning or end of the string
 */
static void trim (const Value** args, Value *res, void*)
{
    if(args[0]->isNull())
    {
      res->setNull(args[0]->getMissingReason());
      return;
    }
    const char* input = args[0]->getString();
    size_t inputLen = args[0]->size();
    const char* chars = args[1]->getString();
    size_t charsLen = args[1]->size();
    if (charsLen == 0 || (charsLen ==1 && chars[0]==0))
    {
        res->setSize(inputLen);
        memcpy(res->data(), input, inputLen);
        return;
    }
    const char* start = input;
    for(size_t i=0; i<inputLen; ++i)
    {
        char ch = input[i];
        if(ch==0)
        {
            break;
        }
        bool match = false;
        for(size_t j=0; j<charsLen; ++j)
        {
            if(ch == chars[j])
            {
                match =true;
                break;
            }
        }
        if(!match)
        {
            break;
        }
        ++start;
    }
    const char* end = input + inputLen - 1;
    for(ssize_t i = inputLen-1; i>=0; --i)
    {
        char ch = input[i];
        if(ch==0)
        {
            continue;
        }
        bool match = false;
        for(size_t j=0; j<charsLen; ++j)
        {
            if(ch == chars[j])
            {
                match =true;
                break;
            }
        }
        if(!match)
        {
            break;
        }
        --end;
    }
    if (inputLen == 0 || (inputLen ==1 && input[0]==0) || start >= end)
    {
        res->setSize(1);
        ((char *) res->data())[0]=0;
        return;
    }
    size_t size = end - start + 1;
    res->setSize(size);
    memcpy(res->data(), start, (end-start));
    ((char*)res->data())[size-1]=0;
}

static scidb::UserDefinedFunction trim_str (scidb::FunctionDescription("trim", list_of("string")("string"), "string", &trim ));

static void int_to_char (const Value** args, Value *res, void*)
{
    if(args[0]->isNull())
    {
      res->setNull(args[0]->getMissingReason());
      return;
    }
    uint8_t input = args[0]->getUint8();
    res->setChar(input);
}

static scidb::UserDefinedFunction int_to_c (scidb::FunctionDescription("int_to_char", list_of("uint8"), "char", &int_to_char ));
static scidb::UserDefinedFunction c_to_int (scidb::FunctionDescription("char_to_int", list_of("char"), "uint8", &int_to_char ));

static void codify (const Value** args, Value *res, void*)
{
    if(args[0]->isNull())
    {
      res->setNull(args[0]->getMissingReason());
      return;
    }
    const char* input = args[0]->getString();
    size_t inputLen = args[0]->size();
    ostringstream out;
    for (size_t i=0; i< inputLen; ++i)
    {
        char c = input[i];
        int32_t res = c;
        out<<res<<"|";
    }
    res->setString(out.str().c_str());
}

static scidb::UserDefinedFunction asciify_str (scidb::FunctionDescription("codify", list_of("string"), "string", &codify ));

//in some rare cases, on older versions, string values are not null-terminated; we aim to be nice
string get_null_terminated_string(char const* input, size_t const size)
{
    if(size == 0)
    {
        return string("");
    }
    else if (input[size-1] != 0)
    {
        return string(input, size);
    }
    else
    {
        return string(input);
    }
}

static void keyed_value( const Value** args, Value *res, void* )
{
    if(args[0]->isNull())
    {
        res->setNull(args[0]->getMissingReason());
        return;
    }
    else if (args[1]->isNull())
    {
        res->setNull(1);
        return;
    }
    string cell =        get_null_terminated_string(args[0]->getString(), args[0]->size());
    string info_field =  get_null_terminated_string(args[1]->getString(), args[1]->size());
    vector<string> values;
    split(values, cell, is_from_range(';', ';'));
    for(size_t i=0, n=values.size(); i<n; ++i)
    {
        vector<string> pair;
        split(pair, values[i], is_from_range('=','='));
        if(pair.size()!=2)
        {
            res->setNull(2);
            return;
        }
        if(pair[0]==info_field)
        {
            res->setString(pair[1]);
            return;
        }
    }
    (*res) = (*args[2]);
}
static scidb::UserDefinedFunction key_value_extract( scidb::FunctionDescription("keyed_value", list_of("string")("string")("string"), "string", &keyed_value));

/**
 * Loosely based on https://github.com/slottad/scidb-genotypes/
 * Thanks to Douglas Slotta.
 * We find we are repeating some of the work and it might make sense to merge in more of that functionality
 */
void num_csv(const scidb::Value** args, scidb::Value* res, void*)
{
    if (args[0]->isNull())
    {
        res->setNull(args[0]->getMissingReason());
        return;
    }
    string cell = get_null_terminated_string(args[0]->getString(), args[0]->size());
    uint32_t count = 0;
    if (!cell.empty())
    {
        count = 1 + std::count(cell.begin(), cell.end(), ',');
    }
    res->setUint32(count);
}
static scidb::UserDefinedFunction ncsv( scidb::FunctionDescription("num_csv", list_of("string"), "uint32", &num_csv));

void nth_csv(const scidb::Value** args, scidb::Value* res, void*)
{
    if (args[0]->isNull())
    {
        res->setNull(args[0]->getMissingReason());
        return;
    }
    if (args[1]->isNull())
    {
        res->setNull(0);
        return;
    }
    uint32_t n = args[1]->getUint32();
    string cell = get_null_terminated_string(args[0]->getString(), args[0]->size());
    vector<string> values;
    split(values, cell, is_from_range(',', ','));
    if (values.size() <= n)
    {
        res->setNull(0);
        return;
    }
    res->setString(values[n]);
}

static scidb::UserDefinedFunction ntcsv( scidb::FunctionDescription("nth_csv", list_of("string")("uint32"), "string", &nth_csv));

void maxlen_csv(const scidb::Value** args, scidb::Value* res, void*)
{
    if (args[0]->isNull())
    {
        res->setNull(args[0]->getMissingReason());
        return;
    }
    string cell = get_null_terminated_string(args[0]->getString(), args[0]->size());
    vector<string> values;
    split(values, cell, is_from_range(',', ','));
    uint32_t maxSize =0;
    for(size_t i=0, n=values.size(); i<n; ++i)
    {
        if(values[i].size()> maxSize)
            maxSize=values[i].size();
    }
    res->setUint32(maxSize);
}

static scidb::UserDefinedFunction mlcsv( scidb::FunctionDescription("maxlen_csv", list_of("string"), "uint32", &maxlen_csv));

/**
 * arg0: FORMAT FIELD
 * arg1: sample FIELD
 * arg2: attribute name
 */
static void extract_format_field( const Value **args, Value* res, void*) {
    for(int i = 0; i < 3; i++) {
        if(args[i]->isNull()) {
            res->setNull(args[i]->getMissingReason());
            return;
        }
    }

    const char* formatField = args[0]->getString();
    size_t formatLen = args[0]->size();
    const char* sampleField = args[1]->getString();
    size_t sampleLen = args[1]->size();
    const char* attrName = args[2]->getString();
    size_t attrLen = args[2]->size();

    size_t index = 0;
    size_t j = 0, k = 0;
    bool match = false;
    for(; j < formatLen && !match; j += k) {
      if(formatField[j] == ':') { index++; j++; }
      match = true;
      for(k = 0; j+k < formatLen && formatField[j+k] != ':'; k++) {
        if(k >= attrLen || formatField[j+k] != attrName[k]) { match = false; }
      }
    }

    if(!match) {
      res->setNull(0);
      return;
    }

    size_t start = 0;
    size_t indexi = 0;
    for(; start < sampleLen && indexi < index; start++) {
        if(sampleField[start] == ':') {
            indexi += 1;
        }
    }

    size_t end = start+1;
    for(; end < sampleLen && sampleField[end] != ':'; end += 1)
        {}

    size_t size = end - start + 1;
    res->setSize(size);
    memcpy(res->data(), &sampleField[start], (end-start));
    ((char*)res->data())[size-1]=0;
}

static scidb::UserDefinedFunction format_extract(scidb::FunctionDescription("format_extract", list_of("string")("string")("string"), "string", &extract_format_field));
<commit_msg>Add a default trim call and cleanup trim code significantly. Fix a bug whereby casts to uint8 or int8 would return an incorrect result<commit_after>/*
**
* BEGIN_COPYRIGHT
*
* load_tools is a plugin for SciDB.  Copyright (C) 2008-2014 SciDB, Inc.
*
* load_tools is free software: you can redistribute it and/or modify
* it under the terms of the AFFERO GNU General Public License as published by
* the Free Software Foundation.
*
* load_tools is distributed "AS-IS" AND WITHOUT ANY WARRANTY OF ANY KIND,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* NON-INFRINGEMENT, OR FITNESS FOR A PARTICULAR PURPOSE. See
* the AFFERO GNU General Public License for the complete license terms.
*
* You should have received a copy of the AFFERO GNU General Public License
* along with load_tools.  If not, see <http://www.gnu.org/licenses/agpl-3.0.html>
*
* END_COPYRIGHT
*/

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <vector>

#include <boost/lexical_cast.hpp>
#include <boost/assign.hpp>
#include <boost/algorithm/string.hpp>

#include "query/FunctionLibrary.h"
#include "query/FunctionDescription.h"
#include "system/ErrorsLibrary.h"

using namespace std;
using namespace boost;
using namespace boost::assign;
using namespace scidb;

/**
 * DCAST: cast with default, does not throw an error. Tries to cast input to the appropriate type. If the cast fails,
 * returns the supplied default.
 */
template <typename T, bool eight_bit>
static void dcast(const Value** args, Value *res, void*)
{
  if(args[0]->isNull())
  {
      res->setNull(args[0]->getMissingReason());
      return;
  }
  const char* s = args[0]->getString();
  try
  {
      T result;
      if (!eight_bit)
      {
          result = lexical_cast<T>(s);
      }
      else
      {
          result = numeric_cast <T> (lexical_cast<int32_t> (s));
      }
      res->set<T>(result);
  }
  catch(...)
  {
      Value const* def = args[1];
      if(def->isNull())
      {
          res->setNull( def->getMissingReason());
      }
      else
      {
          res->set<T>(def->get<T>());
      }
  }
}

static scidb::UserDefinedFunction dcast_double (scidb::FunctionDescription("dcast", list_of("string")("double"),  "double", &dcast<double,   false> ));
static scidb::UserDefinedFunction dcast_float  (scidb::FunctionDescription("dcast", list_of("string")("float"),   "float",  &dcast<float,    false> ));
static scidb::UserDefinedFunction dcast_bool   (scidb::FunctionDescription("dcast", list_of("string")("bool"),    "bool",   &dcast<bool,     false> ));
static scidb::UserDefinedFunction dcast_int64  (scidb::FunctionDescription("dcast", list_of("string")("int64"),   "int64" , &dcast<int64_t,  false> ));
static scidb::UserDefinedFunction dcast_int32  (scidb::FunctionDescription("dcast", list_of("string")("int32"),   "int32",  &dcast<int32_t,  false> ));
static scidb::UserDefinedFunction dcast_int16  (scidb::FunctionDescription("dcast", list_of("string")("int16"),   "int16",  &dcast<int16_t,  false> ));
static scidb::UserDefinedFunction dcast_uint64 (scidb::FunctionDescription("dcast", list_of("string")("uint64"),  "uint64", &dcast<uint64_t, false> ));
static scidb::UserDefinedFunction dcast_uint32 (scidb::FunctionDescription("dcast", list_of("string")("uint32"),  "uint32", &dcast<uint32_t, false> ));
static scidb::UserDefinedFunction dcast_uint16 (scidb::FunctionDescription("dcast", list_of("string")("uint16"),  "uint16", &dcast<uint16_t, false> ));
static scidb::UserDefinedFunction dcast_uint8  (scidb::FunctionDescription("dcast", list_of("string")("uint8"),   "uint8",  &dcast<uint8_t,  true>  ));
static scidb::UserDefinedFunction dcast_int8   (scidb::FunctionDescription("dcast", list_of("string")("int8"),    "int8",   &dcast<int8_t,   true>  ));

// XXX this gives a wrong result when

// XXX How to add datetime conversion here? The naive approach:
//static scidb::UserDefinedFunction dcast_datetimetz (scidb::FunctionDescription("dcast", list_of("string")("datetimetz"), "datetimetz", &dcast<datetimetz> ));
// doesn't work!

//in some rare cases, on older versions, string values are not null-terminated; we aim to be nice
string get_null_terminated_string(char const* input, size_t const size)
{
    if(size == 0)
    {
        return string("");
    }
    else if (input[size-1] != 0)
    {
        return string(input, size);
    }
    else
    {
        return string(input);
    }
}

static void trim_inner(string& input, string const& characters, Value* res)
{
    trim_if(input, is_any_of(characters));
    res->setString(input);
}

template <bool two_arg>
static void trim (const Value** args, Value *res, void*)
{
    if(args[0]->isNull())
    {
        res->setNull(args[0]->getMissingReason());
        return;
    }
    string characters = " ";
    if(two_arg)
    {
        if(args[1]->isNull())
        {
            res->setNull(0);
            return;
        }
        characters = get_null_terminated_string(args[1]->getString(), args[1]->size());
    }
    string input = get_null_terminated_string(args[0]->getString(), args[0]->size());
    trim_inner(input, characters, res);
}

static scidb::UserDefinedFunction trim_space (scidb::FunctionDescription("trim", list_of("string"),           "string", &trim<false> ));
static scidb::UserDefinedFunction trim_str   (scidb::FunctionDescription("trim", list_of("string")("string"), "string", &trim<true> ));

static void int_to_char (const Value** args, Value *res, void*)
{
    if(args[0]->isNull())
    {
      res->setNull(args[0]->getMissingReason());
      return;
    }
    uint8_t input = args[0]->getUint8();
    res->setChar(input);
}

static scidb::UserDefinedFunction int_to_c (scidb::FunctionDescription("int_to_char", list_of("uint8"), "char", &int_to_char ));
static scidb::UserDefinedFunction c_to_int (scidb::FunctionDescription("char_to_int", list_of("char"), "uint8", &int_to_char ));

static void codify (const Value** args, Value *res, void*)
{
    if(args[0]->isNull())
    {
      res->setNull(args[0]->getMissingReason());
      return;
    }
    const char* input = args[0]->getString();
    size_t inputLen = args[0]->size();
    ostringstream out;
    for (size_t i=0; i< inputLen; ++i)
    {
        char c = input[i];
        int32_t res = c;
        out<<res<<"|";
    }
    res->setString(out.str().c_str());
}

static scidb::UserDefinedFunction asciify_str (scidb::FunctionDescription("codify", list_of("string"), "string", &codify ));

static void keyed_value( const Value** args, Value *res, void* )
{
    if(args[0]->isNull())
    {
        res->setNull(args[0]->getMissingReason());
        return;
    }
    else if (args[1]->isNull())
    {
        res->setNull(1);
        return;
    }
    string cell =        get_null_terminated_string(args[0]->getString(), args[0]->size());
    string info_field =  get_null_terminated_string(args[1]->getString(), args[1]->size());
    vector<string> values;
    split(values, cell, is_from_range(';', ';'));
    for(size_t i=0, n=values.size(); i<n; ++i)
    {
        vector<string> pair;
        split(pair, values[i], is_from_range('=','='));
        if(pair.size()!=2)
        {
            res->setNull(2);
            return;
        }
        if(pair[0]==info_field)
        {
            res->setString(pair[1]);
            return;
        }
    }
    (*res) = (*args[2]);
}
static scidb::UserDefinedFunction key_value_extract( scidb::FunctionDescription("keyed_value", list_of("string")("string")("string"), "string", &keyed_value));

/**
 * Loosely based on https://github.com/slottad/scidb-genotypes/
 * Thanks to Douglas Slotta.
 * We find we are repeating some of the work and it might make sense to merge in more of that functionality
 */
void num_csv(const scidb::Value** args, scidb::Value* res, void*)
{
    if (args[0]->isNull())
    {
        res->setNull(args[0]->getMissingReason());
        return;
    }
    string cell = get_null_terminated_string(args[0]->getString(), args[0]->size());
    uint32_t count = 0;
    if (!cell.empty())
    {
        count = 1 + std::count(cell.begin(), cell.end(), ',');
    }
    res->setUint32(count);
}
static scidb::UserDefinedFunction ncsv( scidb::FunctionDescription("num_csv", list_of("string"), "uint32", &num_csv));

void nth_csv(const scidb::Value** args, scidb::Value* res, void*)
{
    if (args[0]->isNull())
    {
        res->setNull(args[0]->getMissingReason());
        return;
    }
    if (args[1]->isNull())
    {
        res->setNull(0);
        return;
    }
    uint32_t n = args[1]->getUint32();
    string cell = get_null_terminated_string(args[0]->getString(), args[0]->size());
    vector<string> values;
    split(values, cell, is_from_range(',', ','));
    if (values.size() <= n)
    {
        res->setNull(0);
        return;
    }
    res->setString(values[n]);
}

static scidb::UserDefinedFunction ntcsv( scidb::FunctionDescription("nth_csv", list_of("string")("uint32"), "string", &nth_csv));

void maxlen_csv(const scidb::Value** args, scidb::Value* res, void*)
{
    if (args[0]->isNull())
    {
        res->setNull(args[0]->getMissingReason());
        return;
    }
    string cell = get_null_terminated_string(args[0]->getString(), args[0]->size());
    vector<string> values;
    split(values, cell, is_from_range(',', ','));
    uint32_t maxSize =0;
    for(size_t i=0, n=values.size(); i<n; ++i)
    {
        if(values[i].size()> maxSize)
            maxSize=values[i].size();
    }
    res->setUint32(maxSize);
}

static scidb::UserDefinedFunction mlcsv( scidb::FunctionDescription("maxlen_csv", list_of("string"), "uint32", &maxlen_csv));

/**
 * arg0: FORMAT FIELD
 * arg1: sample FIELD
 * arg2: attribute name
 */
static void extract_format_field( const Value **args, Value* res, void*) {
    for(int i = 0; i < 3; i++) {
        if(args[i]->isNull()) {
            res->setNull(args[i]->getMissingReason());
            return;
        }
    }

    const char* formatField = args[0]->getString();
    size_t formatLen = args[0]->size();
    const char* sampleField = args[1]->getString();
    size_t sampleLen = args[1]->size();
    const char* attrName = args[2]->getString();
    size_t attrLen = args[2]->size();

    size_t index = 0;
    size_t j = 0, k = 0;
    bool match = false;
    for(; j < formatLen && !match; j += k) {
      if(formatField[j] == ':') { index++; j++; }
      match = true;
      for(k = 0; j+k < formatLen && formatField[j+k] != ':'; k++) {
        if(k >= attrLen || formatField[j+k] != attrName[k]) { match = false; }
      }
    }

    if(!match) {
      res->setNull(0);
      return;
    }

    size_t start = 0;
    size_t indexi = 0;
    for(; start < sampleLen && indexi < index; start++) {
        if(sampleField[start] == ':') {
            indexi += 1;
        }
    }

    size_t end = start+1;
    for(; end < sampleLen && sampleField[end] != ':'; end += 1)
        {}

    size_t size = end - start + 1;
    res->setSize(size);
    memcpy(res->data(), &sampleField[start], (end-start));
    ((char*)res->data())[size-1]=0;
}

static scidb::UserDefinedFunction format_extract(scidb::FunctionDescription("format_extract", list_of("string")("string")("string"), "string", &extract_format_field));
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen 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 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <Eigen/Geometry>
#include <Eigen/LU>
#include <Eigen/QR>

#include<iostream>
using namespace std;

template<typename BoxType> void alignedbox(const BoxType& _box)
{
  /* this test covers the following files:
     AlignedBox.h
  */

  const int dim = _box.dim();
  typedef typename BoxType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, BoxType::AmbientDimAtCompileTime, 1> VectorType;

  VectorType p0 = VectorType::Random(dim);
  VectorType p1 = VectorType::Random(dim);
  while( p1 == p0 ){
      p1 =  VectorType::Random(dim); }
  RealScalar s1 = ei_random<RealScalar>(0,1);

  BoxType b0(dim);
  BoxType b1(VectorType::Random(dim),VectorType::Random(dim));
  BoxType b2;

  b0.extend(p0);
  b0.extend(p1);
  VERIFY(b0.contains(p0*s1+(Scalar(1)-s1)*p1));
  VERIFY(!b0.contains(p0 + (2+s1)*(p1-p0)));

  (b2 = b0).extend(b1);
  VERIFY(b2.contains(b0));
  VERIFY(b2.contains(b1));
  VERIFY_IS_APPROX(b2.clamp(b0), b0);

  // alignment -- make sure there is no memory alignment assertion
  BoxType *bp0 = new BoxType(dim);
  BoxType *bp1 = new BoxType(dim);
  bp0->extend(*bp1);
  delete bp0;
  delete bp1;

  // sampling
  for( int i=0; i<10; ++i )
  {
      VectorType r = b0.sample();
      VERIFY(b0.contains(r));
  }

}

template<typename BoxType>
void alignedboxCastTests(const BoxType& _box)
{
  // casting
  const int dim = _box.dim();
  typedef typename BoxType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, BoxType::AmbientDimAtCompileTime, 1> VectorType;

  VectorType p0 = VectorType::Random(dim);
  VectorType p1 = VectorType::Random(dim);

  BoxType b0(dim);

  b0.extend(p0);
  b0.extend(p1);

  const int Dim = BoxType::AmbientDimAtCompileTime;
  typedef typename GetDifferentType<Scalar>::type OtherScalar;
  AlignedBox<OtherScalar,Dim> hp1f = b0.template cast<OtherScalar>();
  VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),b0);
  AlignedBox<Scalar,Dim> hp1d = b0.template cast<Scalar>();
  VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),b0);
}

void specificTest1()
{
    Vector2f m; m << -1.0f, -2.0f;
    Vector2f M; M <<  1.0f,  5.0f;

    typedef AlignedBox<float,2>  BoxType;
    BoxType box( m, M );

    Vector2f sides = M-m;
    VERIFY_IS_APPROX(sides, box.sizes() );
    VERIFY_IS_APPROX(sides[1], box.sizes()[1] );
    VERIFY_IS_APPROX(sides[1], box.sizes().maxCoeff() );
    VERIFY_IS_APPROX(sides[0], box.sizes().minCoeff() );

    VERIFY_IS_APPROX( 14.0f, box.volume() );
    VERIFY_IS_APPROX( 53.0f, box.diagonal().squaredNorm() );
    VERIFY_IS_APPROX( ei_sqrt( 53.0f ), box.diagonal().norm() );

    VERIFY_IS_APPROX( m, box.corner( BoxType::BottomLeft ) );
    VERIFY_IS_APPROX( M, box.corner( BoxType::TopRight ) );
    Vector2f bottomRight; bottomRight << M[0], m[1];
    Vector2f topLeft; topLeft << m[0], M[1];
    VERIFY_IS_APPROX( bottomRight, box.corner( BoxType::BottomRight ) );
    VERIFY_IS_APPROX( topLeft, box.corner( BoxType::TopLeft ) );
}

void specificTest2()
{
    Vector3i m; m << -1, -2, 0;
    Vector3i M; M <<  1,  5, 3;

    typedef AlignedBox<int,3>  BoxType;
    BoxType box( m, M );

    Vector3i sides = M-m;
    VERIFY_IS_APPROX(sides, box.sizes() );
    VERIFY_IS_APPROX(sides[1], box.sizes()[1] );
    VERIFY_IS_APPROX(sides[1], box.sizes().maxCoeff() );
    VERIFY_IS_APPROX(sides[0], box.sizes().minCoeff() );

    VERIFY_IS_APPROX( 42, box.volume() );
    VERIFY_IS_APPROX( 62, box.diagonal().squaredNorm() );

    VERIFY_IS_APPROX( m, box.corner( BoxType::BottomLeftFloor ) );
    VERIFY_IS_APPROX( M, box.corner( BoxType::TopRightCeil ) );
    Vector3i bottomRightFloor; bottomRightFloor << M[0], m[1], m[2];
    Vector3i topLeftFloor; topLeftFloor << m[0], M[1], m[2];
    VERIFY_IS_APPROX( bottomRightFloor, box.corner( BoxType::BottomRightFloor ) );
    VERIFY_IS_APPROX( topLeftFloor, box.corner( BoxType::TopLeftFloor ) );
}

void test_geo_alignedbox()
{
  for(int i = 0; i < g_repeat; i++)
  {
    CALL_SUBTEST_1( alignedbox(AlignedBox<float,2>()) );
    CALL_SUBTEST_2( alignedboxCastTests(AlignedBox<float,2>()) );

    CALL_SUBTEST_3( alignedbox(AlignedBox<float,3>()) );
    CALL_SUBTEST_4( alignedboxCastTests(AlignedBox<float,3>()) );

    CALL_SUBTEST_5( alignedbox(AlignedBox<double,4>()) );
    CALL_SUBTEST_6( alignedboxCastTests(AlignedBox<double,4>()) );

    CALL_SUBTEST_7( alignedbox(AlignedBox<double,1>()) );
    CALL_SUBTEST_8( alignedboxCastTests(AlignedBox<double,1>()) );

    CALL_SUBTEST_9( alignedbox(AlignedBox<int,1>()) );
    CALL_SUBTEST_10( alignedbox(AlignedBox<int,2>()) );
    CALL_SUBTEST_11( alignedbox(AlignedBox<int,3>()) );
  }
  CALL_SUBTEST_12( specificTest1() );
  CALL_SUBTEST_13( specificTest2() );
}
<commit_msg>remove bogus test that was failing<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen 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 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <Eigen/Geometry>
#include <Eigen/LU>
#include <Eigen/QR>

#include<iostream>
using namespace std;

template<typename BoxType> void alignedbox(const BoxType& _box)
{
  /* this test covers the following files:
     AlignedBox.h
  */

  const int dim = _box.dim();
  typedef typename BoxType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, BoxType::AmbientDimAtCompileTime, 1> VectorType;

  VectorType p0 = VectorType::Random(dim);
  VectorType p1 = VectorType::Random(dim);
  while( p1 == p0 ){
      p1 =  VectorType::Random(dim); }
  RealScalar s1 = ei_random<RealScalar>(0,1);

  BoxType b0(dim);
  BoxType b1(VectorType::Random(dim),VectorType::Random(dim));
  BoxType b2;

  b0.extend(p0);
  b0.extend(p1);
  VERIFY(b0.contains(p0*s1+(Scalar(1)-s1)*p1));

  (b2 = b0).extend(b1);
  VERIFY(b2.contains(b0));
  VERIFY(b2.contains(b1));
  VERIFY_IS_APPROX(b2.clamp(b0), b0);

  // alignment -- make sure there is no memory alignment assertion
  BoxType *bp0 = new BoxType(dim);
  BoxType *bp1 = new BoxType(dim);
  bp0->extend(*bp1);
  delete bp0;
  delete bp1;

  // sampling
  for( int i=0; i<10; ++i )
  {
      VectorType r = b0.sample();
      VERIFY(b0.contains(r));
  }

}

template<typename BoxType>
void alignedboxCastTests(const BoxType& _box)
{
  // casting
  const int dim = _box.dim();
  typedef typename BoxType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, BoxType::AmbientDimAtCompileTime, 1> VectorType;

  VectorType p0 = VectorType::Random(dim);
  VectorType p1 = VectorType::Random(dim);

  BoxType b0(dim);

  b0.extend(p0);
  b0.extend(p1);

  const int Dim = BoxType::AmbientDimAtCompileTime;
  typedef typename GetDifferentType<Scalar>::type OtherScalar;
  AlignedBox<OtherScalar,Dim> hp1f = b0.template cast<OtherScalar>();
  VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),b0);
  AlignedBox<Scalar,Dim> hp1d = b0.template cast<Scalar>();
  VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),b0);
}

void specificTest1()
{
    Vector2f m; m << -1.0f, -2.0f;
    Vector2f M; M <<  1.0f,  5.0f;

    typedef AlignedBox<float,2>  BoxType;
    BoxType box( m, M );

    Vector2f sides = M-m;
    VERIFY_IS_APPROX(sides, box.sizes() );
    VERIFY_IS_APPROX(sides[1], box.sizes()[1] );
    VERIFY_IS_APPROX(sides[1], box.sizes().maxCoeff() );
    VERIFY_IS_APPROX(sides[0], box.sizes().minCoeff() );

    VERIFY_IS_APPROX( 14.0f, box.volume() );
    VERIFY_IS_APPROX( 53.0f, box.diagonal().squaredNorm() );
    VERIFY_IS_APPROX( ei_sqrt( 53.0f ), box.diagonal().norm() );

    VERIFY_IS_APPROX( m, box.corner( BoxType::BottomLeft ) );
    VERIFY_IS_APPROX( M, box.corner( BoxType::TopRight ) );
    Vector2f bottomRight; bottomRight << M[0], m[1];
    Vector2f topLeft; topLeft << m[0], M[1];
    VERIFY_IS_APPROX( bottomRight, box.corner( BoxType::BottomRight ) );
    VERIFY_IS_APPROX( topLeft, box.corner( BoxType::TopLeft ) );
}

void specificTest2()
{
    Vector3i m; m << -1, -2, 0;
    Vector3i M; M <<  1,  5, 3;

    typedef AlignedBox<int,3>  BoxType;
    BoxType box( m, M );

    Vector3i sides = M-m;
    VERIFY_IS_APPROX(sides, box.sizes() );
    VERIFY_IS_APPROX(sides[1], box.sizes()[1] );
    VERIFY_IS_APPROX(sides[1], box.sizes().maxCoeff() );
    VERIFY_IS_APPROX(sides[0], box.sizes().minCoeff() );

    VERIFY_IS_APPROX( 42, box.volume() );
    VERIFY_IS_APPROX( 62, box.diagonal().squaredNorm() );

    VERIFY_IS_APPROX( m, box.corner( BoxType::BottomLeftFloor ) );
    VERIFY_IS_APPROX( M, box.corner( BoxType::TopRightCeil ) );
    Vector3i bottomRightFloor; bottomRightFloor << M[0], m[1], m[2];
    Vector3i topLeftFloor; topLeftFloor << m[0], M[1], m[2];
    VERIFY_IS_APPROX( bottomRightFloor, box.corner( BoxType::BottomRightFloor ) );
    VERIFY_IS_APPROX( topLeftFloor, box.corner( BoxType::TopLeftFloor ) );
}

void test_geo_alignedbox()
{
  for(int i = 0; i < g_repeat; i++)
  {
    CALL_SUBTEST_1( alignedbox(AlignedBox<float,2>()) );
    CALL_SUBTEST_2( alignedboxCastTests(AlignedBox<float,2>()) );

    CALL_SUBTEST_3( alignedbox(AlignedBox<float,3>()) );
    CALL_SUBTEST_4( alignedboxCastTests(AlignedBox<float,3>()) );

    CALL_SUBTEST_5( alignedbox(AlignedBox<double,4>()) );
    CALL_SUBTEST_6( alignedboxCastTests(AlignedBox<double,4>()) );

    CALL_SUBTEST_7( alignedbox(AlignedBox<double,1>()) );
    CALL_SUBTEST_8( alignedboxCastTests(AlignedBox<double,1>()) );

    CALL_SUBTEST_9( alignedbox(AlignedBox<int,1>()) );
    CALL_SUBTEST_10( alignedbox(AlignedBox<int,2>()) );
    CALL_SUBTEST_11( alignedbox(AlignedBox<int,3>()) );
  }
  CALL_SUBTEST_12( specificTest1() );
  CALL_SUBTEST_13( specificTest2() );
}
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen 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 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <Eigen/Geometry>
#include <Eigen/LU>
#include <Eigen/QR>

template<typename HyperplaneType> void hyperplane(const HyperplaneType& _plane)
{
  /* this test covers the following files:
     Hyperplane.h
  */

  const int dim = _plane.dim();
  typedef typename HyperplaneType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, HyperplaneType::AmbientDimAtCompileTime, 1> VectorType;
  typedef Matrix<Scalar, HyperplaneType::AmbientDimAtCompileTime,
                         HyperplaneType::AmbientDimAtCompileTime> MatrixType;

  VectorType p0 = VectorType::Random(dim);
  VectorType p1 = VectorType::Random(dim);

  VectorType n0 = VectorType::Random(dim).normalized();
  VectorType n1 = VectorType::Random(dim).normalized();

  HyperplaneType pl0(n0, p0);
  HyperplaneType pl1(n1, p1);
  HyperplaneType pl2 = pl1;

  Scalar s0 = ei_random<Scalar>();
  Scalar s1 = ei_random<Scalar>();

  VERIFY_IS_APPROX( n1.dot(n1), Scalar(1) );

  VERIFY_IS_MUCH_SMALLER_THAN( pl0.absDistance(p0), Scalar(1) );
  VERIFY_IS_APPROX( pl1.signedDistance(p1 + n1 * s0), s0 );
  VERIFY_IS_MUCH_SMALLER_THAN( pl1.signedDistance(pl1.projection(p0)), Scalar(1) );
  VERIFY_IS_MUCH_SMALLER_THAN( pl1.absDistance(p1 +  pl1.normal().unitOrthogonal() * s1), Scalar(1) );

  // transform
  if (!NumTraits<Scalar>::IsComplex)
  {
    MatrixType rot = MatrixType::Random(dim,dim).householderQr().householderQ();
    DiagonalMatrix<Scalar,HyperplaneType::AmbientDimAtCompileTime> scaling(VectorType::Random());
    Translation<Scalar,HyperplaneType::AmbientDimAtCompileTime> translation(VectorType::Random());

    pl2 = pl1;
    VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot).absDistance(rot * p1), Scalar(1) );
    pl2 = pl1;
    VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot,Isometry).absDistance(rot * p1), Scalar(1) );
    pl2 = pl1;
    VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling).absDistance((rot*scaling) * p1), Scalar(1) );
    pl2 = pl1;
    VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling*translation)
                                 .absDistance((rot*scaling*translation) * p1), Scalar(1) );
    pl2 = pl1;
    VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*translation,Isometry)
                                 .absDistance((rot*translation) * p1), Scalar(1) );
  }

  // casting
  const int Dim = HyperplaneType::AmbientDimAtCompileTime;
  typedef typename GetDifferentType<Scalar>::type OtherScalar;
  Hyperplane<OtherScalar,Dim> hp1f = pl1.template cast<OtherScalar>();
  VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),pl1);
  Hyperplane<Scalar,Dim> hp1d = pl1.template cast<Scalar>();
  VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),pl1);
}

template<typename Scalar> void lines()
{
  typedef Hyperplane<Scalar, 2> HLine;
  typedef ParametrizedLine<Scalar, 2> PLine;
  typedef Matrix<Scalar,2,1> Vector;
  typedef Matrix<Scalar,3,1> CoeffsType;

  for(int i = 0; i < 10; i++)
  {
    Vector center = Vector::Random();
    Vector u = Vector::Random();
    Vector v = Vector::Random();
    Scalar a = ei_random<Scalar>();
    while (ei_abs(a-1) < 1e-4) a = ei_random<Scalar>();
    while (u.norm() < 1e-4) u = Vector::Random();
    while (v.norm() < 1e-4) v = Vector::Random();

    HLine line_u = HLine::Through(center + u, center + a*u);
    HLine line_v = HLine::Through(center + v, center + a*v);

    // the line equations should be normalized so that a^2+b^2=1
    VERIFY_IS_APPROX(line_u.normal().norm(), Scalar(1));
    VERIFY_IS_APPROX(line_v.normal().norm(), Scalar(1));

    Vector result = line_u.intersection(line_v);

    // the lines should intersect at the point we called "center"
    VERIFY_IS_APPROX(result, center);

    // check conversions between two types of lines
    PLine pl(line_u); // gcc 3.3 will commit suicide if we don't name this variable
    CoeffsType converted_coeffs = HLine(pl).coeffs();
    converted_coeffs *= (line_u.coeffs()[0])/(converted_coeffs[0]);
    VERIFY(line_u.coeffs().isApprox(converted_coeffs));
  }
}

void test_geo_hyperplane()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( hyperplane(Hyperplane<float,2>()) );
    CALL_SUBTEST_2( hyperplane(Hyperplane<float,3>()) );
    CALL_SUBTEST_3( hyperplane(Hyperplane<double,4>()) );
    CALL_SUBTEST_4( hyperplane(Hyperplane<std::complex<double>,5>()) );
    CALL_SUBTEST_1( lines<float>() );
    CALL_SUBTEST_2( lines<double>() );
  }
}
<commit_msg>workaround weird gcc 4.0.1 compilation error<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen 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 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <Eigen/Geometry>
#include <Eigen/LU>
#include <Eigen/QR>

template<typename HyperplaneType> void hyperplane(const HyperplaneType& _plane)
{
  /* this test covers the following files:
     Hyperplane.h
  */

  const int dim = _plane.dim();
  typedef typename HyperplaneType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, HyperplaneType::AmbientDimAtCompileTime, 1> VectorType;
  typedef Matrix<Scalar, HyperplaneType::AmbientDimAtCompileTime,
                         HyperplaneType::AmbientDimAtCompileTime> MatrixType;

  VectorType p0 = VectorType::Random(dim);
  VectorType p1 = VectorType::Random(dim);

  VectorType n0 = VectorType::Random(dim).normalized();
  VectorType n1 = VectorType::Random(dim).normalized();

  HyperplaneType pl0(n0, p0);
  HyperplaneType pl1(n1, p1);
  HyperplaneType pl2 = pl1;

  Scalar s0 = ei_random<Scalar>();
  Scalar s1 = ei_random<Scalar>();

  VERIFY_IS_APPROX( n1.dot(n1), Scalar(1) );

  VERIFY_IS_MUCH_SMALLER_THAN( pl0.absDistance(p0), Scalar(1) );
  VERIFY_IS_APPROX( pl1.signedDistance(p1 + n1 * s0), s0 );
  VERIFY_IS_MUCH_SMALLER_THAN( pl1.signedDistance(pl1.projection(p0)), Scalar(1) );
  VERIFY_IS_MUCH_SMALLER_THAN( pl1.absDistance(p1 +  pl1.normal().unitOrthogonal() * s1), Scalar(1) );

  // transform
  if (!NumTraits<Scalar>::IsComplex)
  {
    MatrixType rot = MatrixType::Random(dim,dim).householderQr().householderQ();
    DiagonalMatrix<Scalar,HyperplaneType::AmbientDimAtCompileTime> scaling(VectorType::Random());
    Translation<Scalar,HyperplaneType::AmbientDimAtCompileTime> translation(VectorType::Random());

    pl2 = pl1;
    VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot).absDistance(rot * p1), Scalar(1) );
    pl2 = pl1;
    VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot,Isometry).absDistance(rot * p1), Scalar(1) );
    pl2 = pl1;
    VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling).absDistance((rot*scaling) * p1), Scalar(1) );
    pl2 = pl1;
    VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling*translation)
                                 .absDistance((rot*scaling*translation) * p1), Scalar(1) );
    pl2 = pl1;
    VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*translation,Isometry)
                                 .absDistance((rot*translation) * p1), Scalar(1) );
  }

  // casting
  const int Dim = HyperplaneType::AmbientDimAtCompileTime;
  typedef typename GetDifferentType<Scalar>::type OtherScalar;
  Hyperplane<OtherScalar,Dim> hp1f = pl1.template cast<OtherScalar>();
  VERIFY_IS_APPROX(hp1f.template cast<Scalar>(),pl1);
  Hyperplane<Scalar,Dim> hp1d = pl1.template cast<Scalar>();
  VERIFY_IS_APPROX(hp1d.template cast<Scalar>(),pl1);
}

template<typename Scalar> void lines()
{
  typedef Hyperplane<Scalar, 2> HLine;
  typedef ParametrizedLine<Scalar, 2> PLine;
  typedef Matrix<Scalar,2,1> Vector;
  typedef Matrix<Scalar,3,1> CoeffsType;

  for(int i = 0; i < 10; i++)
  {
    Vector center = Vector::Random();
    Vector u = Vector::Random();
    Vector v = Vector::Random();
    Scalar a = ei_random<Scalar>();
    while (ei_abs(a-1) < 1e-4) a = ei_random<Scalar>();
    while (u.norm() < 1e-4) u = Vector::Random();
    while (v.norm() < 1e-4) v = Vector::Random();

    HLine line_u = HLine::Through(center + u, center + a*u);
    HLine line_v = HLine::Through(center + v, center + a*v);

    // the line equations should be normalized so that a^2+b^2=1
    VERIFY_IS_APPROX(line_u.normal().norm(), Scalar(1));
    VERIFY_IS_APPROX(line_v.normal().norm(), Scalar(1));

    Vector result = line_u.intersection(line_v);

    // the lines should intersect at the point we called "center"
    VERIFY_IS_APPROX(result, center);

    // check conversions between two types of lines
    PLine pl(line_u); // gcc 3.3 will commit suicide if we don't name this variable
    CoeffsType converted_coeffs = HLine(pl).coeffs();
    converted_coeffs *= (line_u.coeffs()[0])/(converted_coeffs[0]);
    VERIFY(line_u.coeffs().isApprox(converted_coeffs));
  }
}

void test_geo_hyperplane()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( hyperplane(Hyperplane<float,2>()) );
    CALL_SUBTEST_2( hyperplane(Hyperplane<float,3>()) );
    CALL_SUBTEST_3( hyperplane(Hyperplane<double,4>()) );
    CALL_SUBTEST_4( hyperplane(Hyperplane<std::complex<double>,5>()) );
    CALL_SUBTEST_1( lines<float>() );
    CALL_SUBTEST_3( lines<double>() );
  }
}
<|endoftext|>


<commit_before>#include	<math.h>

#include	"FTExtrdGlyph.h"
#include	"FTVectoriser.h"
#ifdef FTGL_DEBUG
	#include "mmgr.h"
#endif

FTExtrdGlyph::FTExtrdGlyph( FT_Glyph glyph, float d)
:	FTGlyph(),
	vectoriser(0),
	numPoints(0),
	frontMesh(0),
	backMesh(0),
	sidemesh(0),
	glList(0),
	depth(d)
{
	if( ft_glyph_format_outline != glyph->format)
	{
		return;
	}

	vectoriser = new FTVectoriser( glyph);

	vectoriser->Process();

	// Make the front polygons
	vectoriser->MakeMesh( 1.0);

	bBox = FTBBox( glyph);
	bBox.z2 = -depth;
	advance = glyph->advance.x >> 16;

	numPoints = vectoriser->MeshPoints();
	if ( numPoints < 3)
	{
		delete vectoriser;
		return;
	}

	frontMesh = new FTGL_DOUBLE[ numPoints * 3];
	vectoriser->GetMesh( frontMesh);

	// Make the back polygons
	vectoriser->MakeMesh( -1.0);

	numPoints = vectoriser->MeshPoints();
	if ( numPoints < 3)
	{
		delete vectoriser;
		delete [] frontMesh;
		return;
	}

	backMesh =  new FTGL_DOUBLE[ numPoints * 3];
	vectoriser->GetMesh( backMesh);

	numPoints = vectoriser->points();
	int numContours = vectoriser->contours(); // FIXME

	if ( ( numContours < 1) || ( numPoints < 3))
	{
		delete vectoriser;
		delete [] frontMesh;
		delete [] backMesh;
		return;
	}

	// Build the edge polygons
	int* contourLength = new int[ numContours];
	for( int cn = 0; cn < numContours; ++cn)
	{
		contourLength[cn] = vectoriser->contourSize( cn);
	}

	sidemesh = new FTGL_DOUBLE[ numPoints * 3];
	vectoriser->GetOutline( sidemesh);

	delete vectoriser;

	// Draw the glyph
	int offset = 0;
	glList = glGenLists(1);
	glNewList( glList, GL_COMPILE);
		// Render Front Mesh
		int BEPairs = static_cast<int>(frontMesh[0]);
		for( int i = 0; i < BEPairs; ++i)
		{
			int polyType = (int)frontMesh[offset + 1];
			glBegin( polyType);
				glNormal3d(0.0, 0.0, 1.0);

				int verts = (int)frontMesh[offset+2];
				offset += 3;
				for( int x = 0; x < verts; ++x)
				{
					glVertex3dv( frontMesh + offset);
					offset += 3;
				}
			glEnd();
		}

		// Render Back Mesh
		offset = 0;
		BEPairs = static_cast<int>(backMesh[0]);
		for( int i = 0; i < BEPairs; ++i)
		{
			int polyType = (int)backMesh[offset + 1];
			glBegin( polyType);

				glNormal3d(0.0, 0.0, -1.0);
				int verts = (int)backMesh[offset+2];
				offset += 3;
				for( int x = 0; x < verts; ++x)
				{
					glVertex3d( backMesh[offset], backMesh[offset + 1], -depth); // FIXME
					offset += 3;
				}
			glEnd();
		}

		FT_OutlineGlyph outline = (FT_OutlineGlyph)glyph;
		FT_Outline ftOutline = outline->outline;
		int contourFlag = ftOutline.flags; // this is broken for winding direction in freetype so...

		// This assumes that the first contour is an outside contour!!!
		bool winding = Winding( contourLength[0], sidemesh);

		// Join them together.
		// Extrude each contour to make the sides.
		FTGL_DOUBLE* contour = sidemesh;
		for (int c=0; c<numContours; ++c)
		{
			// Make a quad strip using each successive
			// pair of points in this contour.
			int numPoints = contourLength[c];

			glBegin( GL_QUAD_STRIP);

				for( int j= 0; j <= numPoints; ++j)
				{
					int j1 = (j < numPoints) ? j : 0;
					int j0 = (j1 == 0) ? (numPoints-1) : (j1-1);

					FTGL_DOUBLE* p0 = contour + j0*3;
					FTGL_DOUBLE* p1 = contour + j1*3;

					// Compute normal for this quad.
					FTGL_DOUBLE vx = p1[0] - p0[0];
					FTGL_DOUBLE vy = p1[1] - p0[1];
					// Normalise
					FTGL_DOUBLE length = sqrt( ( ( vx * vx) + ( vy * vy)));
					vx /= length; vy /= length;
					glNormal3d(-vy, vx, 0.0);

					// Add vertices to the quad strip.
					// Winding order
//					if( contourFlag & ft_outline_reverse_fill) // this is broken in freetype so...
					if( winding)
					{
						glVertex3d(p0[0], p0[1], 0);
						glVertex3d(p0[0], p0[1], -depth);
					}
					else
					{
						glVertex3d(p0[0], p0[1], -depth);
						glVertex3d(p0[0], p0[1], 0);
					}
				} // for
			glEnd();
			contour += numPoints*3;
		} // for

	glEndList();

	delete [] sidemesh; // FIXME
	delete [] frontMesh;
	delete [] backMesh;
	delete [] contourLength;

	// discard glyph image (bitmap or not)
	FT_Done_Glyph( glyph); // Why does this have to be HERE
}

FTExtrdGlyph::~FTExtrdGlyph()
{
//	if( data)
//		delete [] data; // FIXME
}

bool FTExtrdGlyph::Winding( int numPoints, FTGL_DOUBLE *points)
{
	// Calculate the winding direction. use formula from redbook.
	FTGL_DOUBLE area = 0;

	for( int count = 0; count <= numPoints; ++count)
	{
		int j1 = (count < numPoints) ? count : 0;
		int j0 = (j1 == 0) ? ( numPoints - 1) : ( j1 - 1);

		FTGL_DOUBLE* p0 = points + j0 * 3;
		FTGL_DOUBLE* p1 = points + j1 * 3;

		area += ( p0[0] * p1[1]) - ( p1[0] * p0[1]);
	}

	return( area < 0 ? false: true);
}

float FTExtrdGlyph::Render( const FT_Vector& pen)
{
	if( glList)
	{
		glTranslatef( pen.x, pen.y, 0);
			glCallList( glList);
		glTranslatef( -pen.x, -pen.y, 0);
	}

	return advance;
}
<commit_msg>Removed the winding code. Reverted back to broken outline.flag.
Glyph winding still broken!!!<commit_after>#include	<math.h>

#include	"FTExtrdGlyph.h"
#include	"FTVectoriser.h"
#ifdef FTGL_DEBUG
	#include "mmgr.h"
#endif

FTExtrdGlyph::FTExtrdGlyph( FT_Glyph glyph, float d)
:	FTGlyph(),
	vectoriser(0),
	numPoints(0),
	frontMesh(0),
	backMesh(0),
	sidemesh(0),
	glList(0),
	depth(d)
{
	if( ft_glyph_format_outline != glyph->format)
	{
		return;
	}

	vectoriser = new FTVectoriser( glyph);

	vectoriser->Process();

	// Make the front polygons
	vectoriser->MakeMesh( 1.0);

	bBox = FTBBox( glyph);
	bBox.z2 = -depth;
	advance = glyph->advance.x >> 16;

	numPoints = vectoriser->MeshPoints();
	if ( numPoints < 3)
	{
		delete vectoriser;
		return;
	}

	frontMesh = new FTGL_DOUBLE[ numPoints * 3];
	vectoriser->GetMesh( frontMesh);

	// Make the back polygons
	vectoriser->MakeMesh( -1.0);

	numPoints = vectoriser->MeshPoints();
	if ( numPoints < 3)
	{
		delete vectoriser;
		delete [] frontMesh;
		return;
	}

	backMesh =  new FTGL_DOUBLE[ numPoints * 3];
	vectoriser->GetMesh( backMesh);

	numPoints = vectoriser->points();
	int numContours = vectoriser->contours(); // FIXME

	if ( ( numContours < 1) || ( numPoints < 3))
	{
		delete vectoriser;
		delete [] frontMesh;
		delete [] backMesh;
		return;
	}

	// Build the edge polygons
	int* contourLength = new int[ numContours];
	for( int cn = 0; cn < numContours; ++cn)
	{
		contourLength[cn] = vectoriser->contourSize( cn);
	}

	sidemesh = new FTGL_DOUBLE[ numPoints * 3];
	vectoriser->GetOutline( sidemesh);

	delete vectoriser;

	// Draw the glyph
	int offset = 0;
	glList = glGenLists(1);
	glNewList( glList, GL_COMPILE);
		// Render Front Mesh
		int BEPairs = static_cast<int>(frontMesh[0]);
		for( int i = 0; i < BEPairs; ++i)
		{
			int polyType = (int)frontMesh[offset + 1];
			glBegin( polyType);
				glNormal3d(0.0, 0.0, 1.0);

				int verts = (int)frontMesh[offset+2];
				offset += 3;
				for( int x = 0; x < verts; ++x)
				{
					glVertex3dv( frontMesh + offset);
					offset += 3;
				}
			glEnd();
		}

		// Render Back Mesh
		offset = 0;
		BEPairs = static_cast<int>(backMesh[0]);
		for( int i = 0; i < BEPairs; ++i)
		{
			int polyType = (int)backMesh[offset + 1];
			glBegin( polyType);

				glNormal3d(0.0, 0.0, -1.0);
				int verts = (int)backMesh[offset+2];
				offset += 3;
				for( int x = 0; x < verts; ++x)
				{
					glVertex3d( backMesh[offset], backMesh[offset + 1], -depth); // FIXME
					offset += 3;
				}
			glEnd();
		}

		FT_OutlineGlyph outline = (FT_OutlineGlyph)glyph;
		FT_Outline ftOutline = outline->outline;
		int contourFlag = ftOutline.flags; // this is broken for winding direction in freetype...
                // BUT THIS DOESN'T WORK EITHER!!!!!
//                bool winding = Winding( contourLength[0], sidemesh);

		// Join them together.
		// Extrude each contour to make the sides.
		FTGL_DOUBLE* contour = sidemesh;
		for (int c=0; c<numContours; ++c)
		{
			// Make a quad strip using each successive
			// pair of points in this contour.
			int numPoints = contourLength[c];

			glBegin( GL_QUAD_STRIP);

				for( int j= 0; j <= numPoints; ++j)
				{
					int j1 = (j < numPoints) ? j : 0;
					int j0 = (j1 == 0) ? (numPoints-1) : (j1-1);

					FTGL_DOUBLE* p0 = contour + j0*3;
					FTGL_DOUBLE* p1 = contour + j1*3;

					// Compute normal for this quad.
					FTGL_DOUBLE vx = p1[0] - p0[0];
					FTGL_DOUBLE vy = p1[1] - p0[1];
					// Normalise
					FTGL_DOUBLE length = sqrt( ( ( vx * vx) + ( vy * vy)));
					vx /= length; vy /= length;
					glNormal3d(-vy, vx, 0.0);

					// Add vertices to the quad strip.
					// Winding order
					if( contourFlag & ft_outline_reverse_fill)
//					if( winding)
					{
						glVertex3d(p0[0], p0[1], 0);
						glVertex3d(p0[0], p0[1], -depth);
					}
					else
					{
						glVertex3d(p0[0], p0[1], -depth);
						glVertex3d(p0[0], p0[1], 0);
					}
				} // for
			glEnd();
			contour += numPoints*3;
		} // for

	glEndList();

	delete [] sidemesh; // FIXME
	delete [] frontMesh;
	delete [] backMesh;
	delete [] contourLength;

	// discard glyph image (bitmap or not)
	FT_Done_Glyph( glyph); // Why does this have to be HERE
}

FTExtrdGlyph::~FTExtrdGlyph()
{
//	if( data)
//		delete [] data; // FIXME
}

bool FTExtrdGlyph::Winding( int numPoints, FTGL_DOUBLE *points)
{
	// Calculate the winding direction. use formula from redbook.
	FTGL_DOUBLE area = 0;

	for( int count = 0; count <= numPoints; ++count)
	{
		int j1 = (count < numPoints) ? count : 0;
		int j0 = (j1 == 0) ? ( numPoints - 1) : ( j1 - 1);

		FTGL_DOUBLE* p0 = points + j0 * 3;
		FTGL_DOUBLE* p1 = points + j1 * 3;

		area += ( p0[0] * p1[1]) - ( p1[0] * p0[1]);
	}

	return( area >= 0 );
}

float FTExtrdGlyph::Render( const FT_Vector& pen)
{
	if( glList)
	{
		glTranslatef( pen.x, pen.y, 0);
			glCallList( glList);
		glTranslatef( -pen.x, -pen.y, 0);
	}

	return advance;
}
<|endoftext|>


<commit_before>//
// Created by team_dev on 7/29/16.
//

#include <iostream>
#include <string>
#include "Poco/Net/HTTPServerRequestImpl.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Net/MediaType.h"
#include "Poco/URI.h"
#include "HttpHandlers.h"

void GetHandler(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
  response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_OK);
  response.setKeepAlive(true);

  response.setContentType(Poco::Net::MediaType("text/plain"));
  std::ostream& os = response.send();

  os << "GetHandler(): " << request.getURI() << std::endl;
  Poco::URI uri(request.getURI());
  std::string query = uri.getQuery();

  std::cout << uri.getQuery() << std::endl;

  os.flush();
}

void OtherGetHandler(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
  response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_OK);
  response.setKeepAlive(true);

  response.setContentType(Poco::Net::MediaType("text/plain"));
  std::ostream& os = response.send();

  os << "OtherGetHandler(): " << request.getURI() << std::endl;

  os.flush();
}

void PostHandler(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
  response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_OK);
  response.setKeepAlive(true);

  response.setContentType(Poco::Net::MediaType("text/plain"));
  std::ostream& os = response.send();

  os << "PostHandler()" << request.getURI() << std::endl;

  os.flush();
}

void HandlerClass::operator()(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
  response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_OK);
  response.setKeepAlive(true);

  response.setContentType(Poco::Net::MediaType("text/plain"));
  std::ostream& os = response.send();

  os << "HandlerClass::operator()" << request.getURI() << std::endl;

  os.flush();
}<commit_msg>fixed a warning<commit_after>//
// Created by team_dev on 7/29/16.
//

#include <iostream>
#include "Poco/Net/HTTPServerRequestImpl.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Net/MediaType.h"
#include "Poco/URI.h"
#include "HttpHandlers.h"

void GetHandler(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
  response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_OK);
  response.setKeepAlive(true);

  response.setContentType(Poco::Net::MediaType("text/plain"));
  std::ostream& os = response.send();

  os << "GetHandler(): " << request.getURI() << std::endl;
  Poco::URI uri(request.getURI());
  std::string query = uri.getQuery();

  std::cout << query << std::endl;

  os.flush();
}

void OtherGetHandler(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
  response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_OK);
  response.setKeepAlive(true);

  response.setContentType(Poco::Net::MediaType("text/plain"));
  std::ostream& os = response.send();

  os << "OtherGetHandler(): " << request.getURI() << std::endl;

  os.flush();
}

void PostHandler(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
  response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_OK);
  response.setKeepAlive(true);

  response.setContentType(Poco::Net::MediaType("text/plain"));
  std::ostream& os = response.send();

  os << "PostHandler()" << request.getURI() << std::endl;

  os.flush();
}

void HandlerClass::operator()(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
  response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_OK);
  response.setKeepAlive(true);

  response.setContentType(Poco::Net::MediaType("text/plain"));
  std::ostream& os = response.send();

  os << "HandlerClass::operator()" << request.getURI() << std::endl;

  os.flush();
}<|endoftext|>