<commit_before>// Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
#ifndef __RAPICORN_PIXMAP_HH__
#define __RAPICORN_PIXMAP_HH__

#include <rcore/blobres.hh>

namespace Rapicorn {

/** Pixmap (PixmapT) is a Pixbuf wrapper template which provides various pixel operations.
 * A Pixmap really is defined as PixmapT<Pixbuf>, a template class around Pixbuf which
 * provides automatic memory management, pixel operations and IO functions.
 * This class stores ARGB pixels of size @a width * @a height. The pixels are stored as unsigned
 * 32-bit values in native endian format with premultiplied alpha (compatible with libcairo).
 * The @a comment attribute is preserved during saving and loading by some file formats, such as PNG.
 */
template<class Pixbuf>
class PixmapT {
  std::shared_ptr<Pixbuf> m_pixbuf;
public:
  explicit      PixmapT         ();                     ///< Construct Pixmap with 0x0 pixesl.
  explicit      PixmapT         (uint w, uint h);       ///< Construct Pixmap at given width and height.
  explicit      PixmapT         (const Pixbuf &source); ///< Copy-construct Pixmap from a Pixbuf structure.
  explicit      PixmapT         (Blob &png_blob);       ///< Construct Pixmap from a PNG resource blob.
  explicit      PixmapT         (const String &res_png); ///< Construct Pixmap from a PNG resource blob.
  PixmapT&      operator=       (const Pixbuf &source); ///< Re-initialize the Pixmap from a Pixbuf structure.
  int           width           () const { return m_pixbuf->width(); }  ///< Get the width of the Pixmap.
  int           height          () const { return m_pixbuf->height(); } ///< Get the height of the Pixmap.
  void          resize          (uint w, uint h);   ///< Reset width and height and resize pixel sequence.
  bool          try_resize      (uint w, uint h);   ///< Resize unless width and height are too big.
  const uint32* row             (uint y) const { return m_pixbuf->row (y); } ///< Access row read-only.
  uint32*       row             (uint y) { return m_pixbuf->row (y); } ///< Access row as endian dependant ARGB integers.
  uint32&       pixel           (uint x, uint y) { return m_pixbuf->row (y)[x]; }       ///< Retrieve an ARGB pixel value reference.
  uint32        pixel           (uint x, uint y) const { return m_pixbuf->row (y)[x]; } ///< Retrieve an ARGB pixel value.
  bool          load_png        (const String &filename, bool tryrepair = false); ///< Load from PNG file, assigns errno on failure.
  bool          load_png        (size_t nbytes, const char *bytes, bool tryrepair = false); ///< Load PNG data, sets errno.
  bool          save_png        (const String &filename); ///< Save to PNG, assigns errno on failure.
  bool          load_pixstream  (const uint8 *pixstream); ///< Decode and load from pixel stream, assigns errno on failure.
  void          set_attribute   (const String &name, const String &value); ///< Set string attribute, e.g. "comment".
  String        get_attribute   (const String &name) const;                ///< Get string attribute, e.g. "comment".
  void          copy            (const Pixbuf &source, uint sx, uint sy,
                                 int swidth, int sheight, uint tx, uint ty); ///< Copy a Pixbuf area into this pximap.
  bool          compare         (const Pixbuf &source, uint sx, uint sy, int swidth, int sheight,
                                 uint tx, uint ty, double *averrp = NULL, double *maxerrp = NULL, double *nerrp = NULL,
                                 double *npixp = NULL) const; ///< Compare area and calculate difference metrics.
  operator const Pixbuf& () const { return *m_pixbuf; } ///< Allow automatic conversion of a Pixmap into a Pixbuf.
};

// RAPICORN_PIXBUF_TYPE is defined in <rcore/clientapi.hh> and <rcore/serverapi.hh>
typedef PixmapT<RAPICORN_PIXBUF_TYPE> Pixmap; ///< Pixmap is a convenience alias for PixmapT<Pixbuf>.

} // Rapicorn

#endif /* __RAPICORN_PIXMAP_HH__ */
<commit_msg>UI: fixed file references in a comment<commit_after>// Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
#ifndef __RAPICORN_PIXMAP_HH__
#define __RAPICORN_PIXMAP_HH__

#include <rcore/blobres.hh>

namespace Rapicorn {

/** Pixmap (PixmapT) is a Pixbuf wrapper template which provides various pixel operations.
 * A Pixmap really is defined as PixmapT<Pixbuf>, a template class around Pixbuf which
 * provides automatic memory management, pixel operations and IO functions.
 * This class stores ARGB pixels of size @a width * @a height. The pixels are stored as unsigned
 * 32-bit values in native endian format with premultiplied alpha (compatible with libcairo).
 * The @a comment attribute is preserved during saving and loading by some file formats, such as PNG.
 */
template<class Pixbuf>
class PixmapT {
  std::shared_ptr<Pixbuf> m_pixbuf;
public:
  explicit      PixmapT         ();                     ///< Construct Pixmap with 0x0 pixesl.
  explicit      PixmapT         (uint w, uint h);       ///< Construct Pixmap at given width and height.
  explicit      PixmapT         (const Pixbuf &source); ///< Copy-construct Pixmap from a Pixbuf structure.
  explicit      PixmapT         (Blob &png_blob);       ///< Construct Pixmap from a PNG resource blob.
  explicit      PixmapT         (const String &res_png); ///< Construct Pixmap from a PNG resource blob.
  PixmapT&      operator=       (const Pixbuf &source); ///< Re-initialize the Pixmap from a Pixbuf structure.
  int           width           () const { return m_pixbuf->width(); }  ///< Get the width of the Pixmap.
  int           height          () const { return m_pixbuf->height(); } ///< Get the height of the Pixmap.
  void          resize          (uint w, uint h);   ///< Reset width and height and resize pixel sequence.
  bool          try_resize      (uint w, uint h);   ///< Resize unless width and height are too big.
  const uint32* row             (uint y) const { return m_pixbuf->row (y); } ///< Access row read-only.
  uint32*       row             (uint y) { return m_pixbuf->row (y); } ///< Access row as endian dependant ARGB integers.
  uint32&       pixel           (uint x, uint y) { return m_pixbuf->row (y)[x]; }       ///< Retrieve an ARGB pixel value reference.
  uint32        pixel           (uint x, uint y) const { return m_pixbuf->row (y)[x]; } ///< Retrieve an ARGB pixel value.
  bool          load_png        (const String &filename, bool tryrepair = false); ///< Load from PNG file, assigns errno on failure.
  bool          load_png        (size_t nbytes, const char *bytes, bool tryrepair = false); ///< Load PNG data, sets errno.
  bool          save_png        (const String &filename); ///< Save to PNG, assigns errno on failure.
  bool          load_pixstream  (const uint8 *pixstream); ///< Decode and load from pixel stream, assigns errno on failure.
  void          set_attribute   (const String &name, const String &value); ///< Set string attribute, e.g. "comment".
  String        get_attribute   (const String &name) const;                ///< Get string attribute, e.g. "comment".
  void          copy            (const Pixbuf &source, uint sx, uint sy,
                                 int swidth, int sheight, uint tx, uint ty); ///< Copy a Pixbuf area into this pximap.
  bool          compare         (const Pixbuf &source, uint sx, uint sy, int swidth, int sheight,
                                 uint tx, uint ty, double *averrp = NULL, double *maxerrp = NULL, double *nerrp = NULL,
                                 double *npixp = NULL) const; ///< Compare area and calculate difference metrics.
  operator const Pixbuf& () const { return *m_pixbuf; } ///< Allow automatic conversion of a Pixmap into a Pixbuf.
};

// RAPICORN_PIXBUF_TYPE is defined in <clientapi.hh> and <serverapi.hh>
typedef PixmapT<RAPICORN_PIXBUF_TYPE> Pixmap; ///< Pixmap is a convenience alias for PixmapT<Pixbuf>.

} // Rapicorn

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


<commit_before>// This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
#include "window.hh"
#include "factory.hh"
#include "application.hh"
#include "uithread.hh"
#include <algorithm>

namespace Rapicorn {

WindowImpl&
WindowIface::impl ()
{
  WindowImpl *wimpl = dynamic_cast<WindowImpl*> (this);
  if (!wimpl)
    throw std::bad_cast();
  return *wimpl;
}

namespace WindowTrail {
static Mutex               wmutex;
static vector<WindowImpl*> windows;
static vector<WindowImpl*> wlist  ()               { ScopedLock<Mutex> slock (wmutex); return windows; }
static void wenter (WindowImpl *wi) { ScopedLock<Mutex> slock (wmutex); windows.push_back (wi); }
static void wleave (WindowImpl *wi)
{
  ScopedLock<Mutex> slock (wmutex);
  auto it = find (windows.begin(), windows.end(), wi);
  assert_return (it != windows.end());
  windows.erase (it);
};
} // WindowTrail

WindowImpl::WindowImpl () :
  loop_ (uithread_main_loop()->create_slave()),
  commands_emission_ (NULL)
{
  // create event loop (auto-starts)
  loop_->exec_dispatcher (Aida::slot (*this, &WindowImpl::command_dispatcher), EventLoop::PRIORITY_NOW);
  loop_->flag_primary (false);
}

void
WindowImpl::construct()
{
  ViewportImpl::construct();
  assert_return (has_children() == false);      // must be anchored before becoming parent
  assert_return (get_window() && get_viewport());
  WindowTrail::wenter (this);
  ApplicationImpl::WindowImplFriend::add_window (*this);
  assert_return (anchored() == false);
  sig_hierarchy_changed.emit (NULL);
  assert_return (anchored() == true);
}

void
WindowImpl::dispose()
{
  assert_return (anchored() == true);
  const bool was_listed = ApplicationImpl::WindowImplFriend::remove_window (*this);
  assert_return (was_listed);
  sig_hierarchy_changed.emit (this);
  assert_return (anchored() == false);
}

WindowImpl::~WindowImpl ()
{
  WindowTrail::wleave (this);
  assert_return (anchored() == false);
  // shutdown event loop
  loop_->destroy_loop();
  /* make sure all children are removed while this is still of type ViewportImpl.
   * necessary because C++ alters the object type during constructors and destructors
   */
  if (has_children())
    remove (get_child());
  AncestryCache *ancestry_cache = const_cast<AncestryCache*> (ViewportImpl::fetch_ancestry_cache());
  ancestry_cache->window = NULL;
}

const WidgetImpl::AncestryCache*
WindowImpl::fetch_ancestry_cache ()
{
  AncestryCache *ancestry_cache = const_cast<AncestryCache*> (ViewportImpl::fetch_ancestry_cache());
  ancestry_cache->window = this;
  return ancestry_cache;
}

void
WindowImpl::set_parent (ContainerImpl *parent)
{
  if (parent)
    critical ("setting parent on toplevel Window widget to: %p (%s)", parent, parent->typeid_name().c_str());
  return ContainerImpl::set_parent (parent);
}

void
WindowImpl::create_display_window ()
{
  ViewportImpl::create_display_window();
  if (has_display_window())
    loop_->flag_primary (true);
}

void
WindowImpl::destroy_display_window ()
{
  ViewportImpl::destroy_display_window();
  loop_->flag_primary (false);
}

void
WindowImpl::forcefully_close_all()
{
  vector<WindowImpl*> wl = WindowTrail::wlist();
  for (auto it : wl)
    it->close();
}

bool
WindowImpl::widget_is_anchored (WidgetImpl &widget, Internal)
{
  if (widget.parent() && widget.parent()->anchored())
    return true;
  WindowImpl *window = widget.as_window_impl(); // fast cast
  if (window && ApplicationImpl::WindowImplFriend::has_window (*window))
    return true;
  return false;
}

bool
WindowImpl::custom_command (const String &command_name, const StringSeq &command_args)
{
  assert_return (commands_emission_ == NULL, false);
  last_command_ = command_name;
  commands_emission_ = sig_commands.emission (command_name, command_args);
  return true;
}

bool
WindowImpl::command_dispatcher (const LoopState &state)
{
  if (state.phase == state.PREPARE || state.phase == state.CHECK)
    return commands_emission_ && commands_emission_->pending();
  else if (state.phase == state.DISPATCH)
    {
      WindowImplP guard_this = shared_ptr_cast<WindowImpl> (this);
      commands_emission_->dispatch();                   // invoke signal handlers
      bool handled = false;
      if (commands_emission_->has_value())
        handled = commands_emission_->get_value();      // value returned from signal handler
      if (handled || commands_emission_->done())
        {
          if (!handled)                                 // all handlers returned false
            critical ("Command unhandled: %s", last_command_.c_str());
          Signal_commands::Emission *emi = commands_emission_;
          commands_emission_ = NULL;
          delete emi;
          last_command_ = "";
        }
      return true;
    }
  else if (state.phase == state.DESTROY)
    {
      if (commands_emission_)
        {
          Signal_commands::Emission *emi = commands_emission_;
          commands_emission_ = NULL;
          delete emi;
          last_command_ = "";
        }
    }
  return false;
}

bool
WindowImpl::synthesize_enter (double xalign, double yalign)
{
  if (!has_display_window())
    return false;
  const Allocation &area = allocation();
  Point p (area.x + xalign * (max (1, area.width) - 1),
           area.y + yalign * (max (1, area.height) - 1));
  p = point_to_viewport (p);
  EventContext ec;
  ec.x = p.x;
  ec.y = p.y;
  push_immediate_event (create_event_mouse (MOUSE_ENTER, ec));
  return true;
}

bool
WindowImpl::synthesize_leave ()
{
  if (!has_display_window())
    return false;
  EventContext ec;
  push_immediate_event (create_event_mouse (MOUSE_LEAVE, ec));
  return true;
}

bool
WindowImpl::synthesize_click (WidgetIface &widgeti, int button, double xalign, double yalign)
{
  WidgetImpl &widget = *dynamic_cast<WidgetImpl*> (&widgeti);
  if (!has_display_window() || !&widget)
    return false;
  const Allocation &area = widget.allocation();
  Point p (area.x + xalign * (max (1, area.width) - 1),
           area.y + yalign * (max (1, area.height) - 1));
  p = widget.point_to_viewport (p);
  EventContext ec;
  ec.x = p.x;
  ec.y = p.y;
  push_immediate_event (create_event_button (BUTTON_RELEASE, ec, button));
  push_immediate_event (create_event_button (BUTTON_PRESS, ec, button));
  return true;
}

bool
WindowImpl::synthesize_delete ()
{
  if (!has_display_window())
    return false;
  EventContext ec;
  push_immediate_event (create_event_win_delete (ec));
  return true;
}

static const WidgetFactory<WindowImpl> window_factory ("Rapicorn::Window");

} // Rapicorn
<commit_msg>UI: WindowImpl: properly chain from dispose()<commit_after>// This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
#include "window.hh"
#include "factory.hh"
#include "application.hh"
#include "uithread.hh"
#include <algorithm>

namespace Rapicorn {

WindowImpl&
WindowIface::impl ()
{
  WindowImpl *wimpl = dynamic_cast<WindowImpl*> (this);
  if (!wimpl)
    throw std::bad_cast();
  return *wimpl;
}

namespace WindowTrail {
static Mutex               wmutex;
static vector<WindowImpl*> windows;
static vector<WindowImpl*> wlist  ()               { ScopedLock<Mutex> slock (wmutex); return windows; }
static void wenter (WindowImpl *wi) { ScopedLock<Mutex> slock (wmutex); windows.push_back (wi); }
static void wleave (WindowImpl *wi)
{
  ScopedLock<Mutex> slock (wmutex);
  auto it = find (windows.begin(), windows.end(), wi);
  assert_return (it != windows.end());
  windows.erase (it);
};
} // WindowTrail

WindowImpl::WindowImpl () :
  loop_ (uithread_main_loop()->create_slave()),
  commands_emission_ (NULL)
{
  // create event loop (auto-starts)
  loop_->exec_dispatcher (Aida::slot (*this, &WindowImpl::command_dispatcher), EventLoop::PRIORITY_NOW);
  loop_->flag_primary (false);
}

void
WindowImpl::construct()
{
  ViewportImpl::construct();
  assert_return (has_children() == false);      // must be anchored before becoming parent
  assert_return (get_window() && get_viewport());
  WindowTrail::wenter (this);
  ApplicationImpl::WindowImplFriend::add_window (*this);
  assert_return (anchored() == false);
  sig_hierarchy_changed.emit (NULL);
  assert_return (anchored() == true);
}

void
WindowImpl::dispose()
{
  assert_return (anchored() == true);
  const bool was_listed = ApplicationImpl::WindowImplFriend::remove_window (*this);
  assert_return (was_listed);
  sig_hierarchy_changed.emit (this);
  assert_return (anchored() == false);
  ViewportImpl::dispose();
}

WindowImpl::~WindowImpl ()
{
  WindowTrail::wleave (this);
  assert_return (anchored() == false);
  // shutdown event loop
  loop_->destroy_loop();
  /* make sure all children are removed while this is still of type ViewportImpl.
   * necessary because C++ alters the object type during constructors and destructors
   */
  if (has_children())
    remove (get_child());
  AncestryCache *ancestry_cache = const_cast<AncestryCache*> (ViewportImpl::fetch_ancestry_cache());
  ancestry_cache->window = NULL;
}

const WidgetImpl::AncestryCache*
WindowImpl::fetch_ancestry_cache ()
{
  AncestryCache *ancestry_cache = const_cast<AncestryCache*> (ViewportImpl::fetch_ancestry_cache());
  ancestry_cache->window = this;
  return ancestry_cache;
}

void
WindowImpl::set_parent (ContainerImpl *parent)
{
  if (parent)
    critical ("setting parent on toplevel Window widget to: %p (%s)", parent, parent->typeid_name().c_str());
  return ContainerImpl::set_parent (parent);
}

void
WindowImpl::create_display_window ()
{
  ViewportImpl::create_display_window();
  if (has_display_window())
    loop_->flag_primary (true);
}

void
WindowImpl::destroy_display_window ()
{
  ViewportImpl::destroy_display_window();
  loop_->flag_primary (false);
}

void
WindowImpl::forcefully_close_all()
{
  vector<WindowImpl*> wl = WindowTrail::wlist();
  for (auto it : wl)
    it->close();
}

bool
WindowImpl::widget_is_anchored (WidgetImpl &widget, Internal)
{
  if (widget.parent() && widget.parent()->anchored())
    return true;
  WindowImpl *window = widget.as_window_impl(); // fast cast
  if (window && ApplicationImpl::WindowImplFriend::has_window (*window))
    return true;
  return false;
}

bool
WindowImpl::custom_command (const String &command_name, const StringSeq &command_args)
{
  assert_return (commands_emission_ == NULL, false);
  last_command_ = command_name;
  commands_emission_ = sig_commands.emission (command_name, command_args);
  return true;
}

bool
WindowImpl::command_dispatcher (const LoopState &state)
{
  if (state.phase == state.PREPARE || state.phase == state.CHECK)
    return commands_emission_ && commands_emission_->pending();
  else if (state.phase == state.DISPATCH)
    {
      WindowImplP guard_this = shared_ptr_cast<WindowImpl> (this);
      commands_emission_->dispatch();                   // invoke signal handlers
      bool handled = false;
      if (commands_emission_->has_value())
        handled = commands_emission_->get_value();      // value returned from signal handler
      if (handled || commands_emission_->done())
        {
          if (!handled)                                 // all handlers returned false
            critical ("Command unhandled: %s", last_command_.c_str());
          Signal_commands::Emission *emi = commands_emission_;
          commands_emission_ = NULL;
          delete emi;
          last_command_ = "";
        }
      return true;
    }
  else if (state.phase == state.DESTROY)
    {
      if (commands_emission_)
        {
          Signal_commands::Emission *emi = commands_emission_;
          commands_emission_ = NULL;
          delete emi;
          last_command_ = "";
        }
    }
  return false;
}

bool
WindowImpl::synthesize_enter (double xalign, double yalign)
{
  if (!has_display_window())
    return false;
  const Allocation &area = allocation();
  Point p (area.x + xalign * (max (1, area.width) - 1),
           area.y + yalign * (max (1, area.height) - 1));
  p = point_to_viewport (p);
  EventContext ec;
  ec.x = p.x;
  ec.y = p.y;
  push_immediate_event (create_event_mouse (MOUSE_ENTER, ec));
  return true;
}

bool
WindowImpl::synthesize_leave ()
{
  if (!has_display_window())
    return false;
  EventContext ec;
  push_immediate_event (create_event_mouse (MOUSE_LEAVE, ec));
  return true;
}

bool
WindowImpl::synthesize_click (WidgetIface &widgeti, int button, double xalign, double yalign)
{
  WidgetImpl &widget = *dynamic_cast<WidgetImpl*> (&widgeti);
  if (!has_display_window() || !&widget)
    return false;
  const Allocation &area = widget.allocation();
  Point p (area.x + xalign * (max (1, area.width) - 1),
           area.y + yalign * (max (1, area.height) - 1));
  p = widget.point_to_viewport (p);
  EventContext ec;
  ec.x = p.x;
  ec.y = p.y;
  push_immediate_event (create_event_button (BUTTON_RELEASE, ec, button));
  push_immediate_event (create_event_button (BUTTON_PRESS, ec, button));
  return true;
}

bool
WindowImpl::synthesize_delete ()
{
  if (!has_display_window())
    return false;
  EventContext ec;
  push_immediate_event (create_event_win_delete (ec));
  return true;
}

static const WidgetFactory<WindowImpl> window_factory ("Rapicorn::Window");

} // Rapicorn
<|endoftext|>


<commit_before>// Copyright (c) 2017 Pieter Wuille
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bech32.h>
#include <test/util/setup_common.h>
#include <test/util/str.h>

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(bech32_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(bip173_testvectors_valid)
{
    static const std::string CASES[] = {
        "A12UEL5L",
        "a12uel5l",
        "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
        "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
        "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
        "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
        "?1ezyfcl",
    };
    for (const std::string& str : CASES) {
        const auto dec = bech32::Decode(str);
        BOOST_CHECK(dec.encoding == bech32::Encoding::BECH32);
        std::string recode = bech32::Encode(bech32::Encoding::BECH32, dec.hrp, dec.data);
        BOOST_CHECK(!recode.empty());
        BOOST_CHECK(CaseInsensitiveEqual(str, recode));
    }
}

BOOST_AUTO_TEST_CASE(bip173_testvectors_invalid)
{
    static const std::string CASES[] = {
        " 1nwldj5",
        "\x7f""1axkwrx",
        "\x80""1eym55h",
        "an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx",
        "pzry9x0s0muk",
        "1pzry9x0s0muk",
        "x1b4n0q5v",
        "li1dgmt3",
        "de1lg7wt\xff",
        "A1G7SGD8",
        "10a06t8",
        "1qzzfhee",
        "a12UEL5L",
        "A12uEL5L",
    };
    for (const std::string& str : CASES) {
        const auto dec = bech32::Decode(str);
        BOOST_CHECK(dec.encoding != bech32::Encoding::BECH32);
    }
}

BOOST_AUTO_TEST_CASE(bech32_polymod_sanity)
{
    std::vector<unsigned char> data(40);
    // GetRandBytes only allows 32 bytes at a time
    GetRandBytes(data.data(), 32);
    GetRandBytes(data.data() + 32, data.size() - 32);

    std::vector<unsigned char> base32;
    ConvertBits<8, 5, true>([&](unsigned char c) { base32.push_back(c); }, data.begin(), data.end());
    uint64_t plm1 = bech32::PolyMod(base32);

    // Now add 1023 zeros.
    for (auto i = 0; i < 1023; i++) {
        base32.push_back(0);
    }
    uint64_t plm2 = bech32::PolyMod(base32);

    BOOST_CHECK_EQUAL(plm1, plm2);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Add Bech32m test vectors<commit_after>// Copyright (c) 2017 Pieter Wuille
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bech32.h>
#include <test/util/setup_common.h>
#include <test/util/str.h>

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(bech32_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(bech32_testvectors_valid)
{
    static const std::string CASES[] = {
        "A12UEL5L",
        "a12uel5l",
        "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
        "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
        "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
        "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
        "?1ezyfcl",
    };
    for (const std::string& str : CASES) {
        const auto dec = bech32::Decode(str);
        BOOST_CHECK(dec.encoding == bech32::Encoding::BECH32);
        std::string recode = bech32::Encode(bech32::Encoding::BECH32, dec.hrp, dec.data);
        BOOST_CHECK(!recode.empty());
        BOOST_CHECK(CaseInsensitiveEqual(str, recode));
    }
}

BOOST_AUTO_TEST_CASE(bech32m_testvectors_valid)
{
    static const std::string CASES[] = {
        "A1LQFN3A",
        "a1lqfn3a",
        "an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6",
        "abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx",
        "11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8",
        "split1checkupstagehandshakeupstreamerranterredcaperredlc445v",
        "?1v759aa"
    };
    for (const std::string& str : CASES) {
        const auto dec = bech32::Decode(str);
        BOOST_CHECK(dec.encoding == bech32::Encoding::BECH32M);
        std::string recode = bech32::Encode(bech32::Encoding::BECH32M, dec.hrp, dec.data);
        BOOST_CHECK(!recode.empty());
        BOOST_CHECK(CaseInsensitiveEqual(str, recode));
    }
}

BOOST_AUTO_TEST_CASE(bech32_testvectors_invalid)
{
    static const std::string CASES[] = {
        " 1nwldj5",
        "\x7f""1axkwrx",
        "\x80""1eym55h",
        "an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx",
        "pzry9x0s0muk",
        "1pzry9x0s0muk",
        "x1b4n0q5v",
        "li1dgmt3",
        "de1lg7wt\xff",
        "A1G7SGD8",
        "10a06t8",
        "1qzzfhee",
        "a12UEL5L",
        "A12uEL5L",
    };
    for (const std::string& str : CASES) {
        const auto dec = bech32::Decode(str);
        BOOST_CHECK(dec.encoding == bech32::Encoding::INVALID);
    }
}

BOOST_AUTO_TEST_CASE(bech32m_testvectors_invalid)
{
    static const std::string CASES[] = {
        " 1xj0phk",
        "\x7f""1g6xzxy",
        "\x80""1vctc34",
        "an84characterslonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11d6pts4",
        "qyrz8wqd2c9m",
        "1qyrz8wqd2c9m",
        "y1b0jsk6g",
        "lt1igcx5c0",
        "in1muywd",
        "mm1crxm3i",
        "au1s5cgom",
        "M1VUXWEZ",
        "16plkw9",
        "1p2gdwpf"
    };
    for (const std::string& str : CASES) {
        const auto dec = bech32::Decode(str);
        BOOST_CHECK(dec.encoding == bech32::Encoding::INVALID);
    }
}

BOOST_AUTO_TEST_CASE(bech32_polymod_sanity)
{
    std::vector<unsigned char> data(40);
    // GetRandBytes only allows 32 bytes at a time
    GetRandBytes(data.data(), 32);
    GetRandBytes(data.data() + 32, data.size() - 32);

    std::vector<unsigned char> base32;
    ConvertBits<8, 5, true>([&](unsigned char c) { base32.push_back(c); }, data.begin(), data.end());
    uint64_t plm1 = bech32::PolyMod(base32);

    // Now add 1023 zeros.
    for (auto i = 0; i < 1023; i++) {
        base32.push_back(0);
    }
    uint64_t plm2 = bech32::PolyMod(base32);

    BOOST_CHECK_EQUAL(plm1, plm2);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include <amino.h>
#include <amino/rx.h>

#include "amino/rx/scene_win.h"
#include "amino/rx/scene_gl.h"
#include "amino/rx/octree_geom.hpp"
#include "amino/rx/scene_plugin.h"

#include <stdio.h>

static const int SCREEN_WIDTH = 1000;
static const int SCREEN_HEIGHT = 1000;

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

  struct aa_rx_octree* oCloud = aa_rx_geom_read_octree_from_file("/home/mschack/simple_tree.bt.ot");

  std::cout << "Octree created" << std::endl;

  struct aa_rx_sg *sg = aa_rx_sg_create();

  std::cout << "scenegraph created" << std::endl;

  static const double q[4] = {0, 0, 0, 1};
  static const double v[3] = {0, 0, 0};

  // aa_rx_sg_add_frame_fixed(sg, "", "oct", q, v);

  // std::cout << "frame added" << std::endl;

  // struct aa_rx_geom *geom;
  struct aa_rx_geom_opt *opt = aa_rx_geom_opt_create();
  std::cout << "options created" << std::endl;
  aa_rx_geom_opt_set_color3(opt, 0.0, 0.0, 1.0);
  aa_rx_geom_opt_set_alpha(opt, 1.0);
  aa_rx_geom_opt_set_specular3(opt, 0, 0, 0);
  aa_rx_geom_opt_set_visual(opt, 1);
  aa_rx_geom_opt_set_collision(opt, 1);
  aa_rx_geom_opt_set_no_shadow(opt, 0);

  // geom = aa_rx_geom_octree(opt, oCloud);
  aa_rx_sg_add_octree(sg, "", oCloud, opt);
  std::cout << "octree added" << std::endl;
  // aa_rx_geom_attach(sg, "oct", geom);
  aa_rx_geom_opt_destroy(opt);

  struct aa_rx_win * win =
    aa_rx_win_default_create ( "Octree", SCREEN_WIDTH, SCREEN_HEIGHT );

  printf("OpenGL Version: %s\n", glGetString(GL_VERSION));

  // setup scene graph
  aa_rx_sg_init(sg); /* initialize scene graph internal structures */
  aa_rx_win_sg_gl_init(win, sg); /* Initialize scene graph GL-rendering objects */
  aa_rx_win_set_sg(win, sg); /* Set the scenegraph for the window */

  // start display
  aa_rx_win_run();

  // Cleanup
  aa_rx_sg_destroy(sg);
  aa_rx_win_destroy(win);
  SDL_Quit();

  return (0);
}
<commit_msg>Removed local test<commit_after><|endoftext|>


<commit_before>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#pragma once
#include "ork/ork.hpp"

#define ORK_STL_INC_FILE <type_traits>
#include "ork/core/stl_include.inl"

namespace ork {

} // namespace ork
<commit_msg>Added signature traits<commit_after>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#pragma once
#include "ork/ork.hpp"

#define ORK_STL_INC_FILE <type_traits>
#include "ork/core/stl_include.inl"

namespace ork {

/*
These are optimal types for function signatures
*/
template<typename T>
struct signature_traits {
private:
    static_assert(
        std::is_enum<T>::value || std::is_arithmetic<T>::value || std::is_class<T>::value,
        "Yeah, this trait is not general");
    using non_cv_type = typename std::remove_cv<T>::type;
    using val_t = non_cv_type;
    using cval_t = typename std::add_const<val_t>::type;
    using ref_t = typename std::add_lvalue_reference<val_t>::type;
    using cref_t = typename std::add_lvalue_reference<cval_t>::type;
    static const auto fund_t = std::is_enum<T>::value || std::is_arithmetic<T>::value;

public:
    // Trivial given the limitations above
    using value_type = val_t;
    // Trivial given the limitations above
    using reference_type = ref_t;
    // Parameter to a function
    using const_param_type = typename std::conditional<fund_t, cval_t, cref_t>::type;
    // Wrapper return type
    using const_wrap_type = typename std::conditional<fund_t, val_t, cref_t>::type;
};

// For use in templates
#define ORK_VAL_T typename ork::signature_traits<T>::value_type
#define ORK_REF_T typename ork::signature_traits<T>::reference_type
#define ORK_CPARAM_T typename ork::signature_traits<T>::const_param_type
#define ORK_CWRAP_T typename ork::signature_traits<T>::const_wrap_type

// For use in macros
#define ORK_VAL(TYPE) ork::signature_traits<TYPE>::value_type
#define ORK_REF(TYPE) ork::signature_traits<TYPE>::reference_type
#define ORK_CPARAM(TYPE) ork::signature_traits<TYPE>::const_param_type
#define ORK_CWRAP(TYPE) ork::signature_traits<TYPE>::const_wrap_type

} // namespace ork
<|endoftext|>


<commit_before>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include "CombineIndexedArrays.h"

#include <cstring>
#include <unordered_map>
#include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/MurmurHash2.h>

#include "Magnum/Magnum.h"

namespace Magnum { namespace MeshTools {

namespace Implementation {

std::pair<std::vector<UnsignedInt>, std::vector<UnsignedInt>> interleaveAndCombineIndexArrays(const std::reference_wrapper<const std::vector<UnsignedInt>>* begin, const std::reference_wrapper<const std::vector<UnsignedInt>>* end) {
    /* Array stride and size */
    const UnsignedInt stride = end - begin;
    const UnsignedInt inputSize = begin->get().size();
    #ifndef CORRADE_NO_ASSERT
    for(auto it = begin; it != end; ++it)
        CORRADE_ASSERT(it->get().size() == inputSize, "MeshTools::combineIndexArrays(): the arrays don't have the same size", {});
    #endif

    /* Interleave the arrays */
    std::vector<UnsignedInt> interleavedArrays;
    interleavedArrays.resize(inputSize*stride);
    for(UnsignedInt offset = 0; offset != stride; ++offset) {
        const auto& array = (begin+offset)->get();
        for(UnsignedInt i = 0; i != inputSize; ++i)
            interleavedArrays[offset + i*stride] = array[i];
    }

    /* Combine them */
    std::vector<UnsignedInt> combinedIndices;
    std::tie(combinedIndices, interleavedArrays) = MeshTools::combineIndexArrays(interleavedArrays, stride);
    return {combinedIndices, interleavedArrays};
}

std::vector<UnsignedInt> combineIndexArrays(const std::reference_wrapper<std::vector<UnsignedInt>>* const begin, const std::reference_wrapper<std::vector<UnsignedInt>>* const end) {
    /* Interleave and combine the arrays */
    std::vector<UnsignedInt> combinedIndices;
    std::vector<UnsignedInt> interleavedCombinedArrays;
    std::tie(combinedIndices, interleavedCombinedArrays) = Implementation::interleaveAndCombineIndexArrays(
        /* This will bite me hard once. */
        reinterpret_cast<const std::reference_wrapper<const std::vector<UnsignedInt>>*>(begin),
        reinterpret_cast<const std::reference_wrapper<const std::vector<UnsignedInt>>*>(end));

    /* Update the original indices */
    const UnsignedInt stride = end - begin;
    const UnsignedInt outputSize = interleavedCombinedArrays.size()/stride;
    for(UnsignedInt offset = 0; offset != stride; ++offset) {
        auto& array = (begin+offset)->get();
        CORRADE_INTERNAL_ASSERT(array.size() >= outputSize);
        array.resize(outputSize);
        for(UnsignedInt i = 0; i != outputSize; ++i)
            array[i] = interleavedCombinedArrays[offset + i*stride];
    }

    return combinedIndices;
}

}

namespace {

class IndexHash {
    public:
        explicit IndexHash(const std::vector<UnsignedInt>& indices, UnsignedInt stride): indices(indices), stride(stride) {}

        std::size_t operator()(UnsignedInt key) const {
            return *reinterpret_cast<const std::size_t*>(Utility::MurmurHash2()(reinterpret_cast<const char*>(indices.data()+key*stride), sizeof(UnsignedInt)*stride).byteArray());
        }

    private:
        const std::vector<UnsignedInt>& indices;
        UnsignedInt stride;
};

class IndexEqual {
    public:
        explicit IndexEqual(const std::vector<UnsignedInt>& indices, UnsignedInt stride): indices(indices), stride(stride) {}

        bool operator()(UnsignedInt a, UnsignedInt b) const {
            return std::memcmp(indices.data()+a*stride, indices.data()+b*stride, sizeof(UnsignedInt)*stride) == 0;
        }

    private:
        const std::vector<UnsignedInt>& indices;
        UnsignedInt stride;
};

}

std::pair<std::vector<UnsignedInt>, std::vector<UnsignedInt>> combineIndexArrays(const std::vector<UnsignedInt>& interleavedArrays, const UnsignedInt stride) {
    CORRADE_ASSERT(stride != 0, "MeshTools::combineIndexArrays(): stride can't be zero", {});
    CORRADE_ASSERT(interleavedArrays.size() % stride == 0, "MeshTools::combineIndexArrays(): array size is not divisible by stride", {});

    /* Hash map with index combinations, containing just indices into
       interleavedArrays vector, hashing and comparison is done using IndexHash
       and IndexEqual functors. Reserving more buckets than necessary (i.e. as
       if each combination was unique). */
    std::unordered_map<UnsignedInt, UnsignedInt, IndexHash, IndexEqual> indexCombinations(
        interleavedArrays.size()/stride,
        IndexHash(interleavedArrays, stride),
        IndexEqual(interleavedArrays, stride));

    /* Make the index combinations unique. Original indices into original
       `interleavedArrays` array were 0, 1, 2, 3, ..., `combinedIndices`
       contains new ones into new (shorter) `newInterleavedArrays` array. */
    std::vector<UnsignedInt> combinedIndices;
    combinedIndices.reserve(interleavedArrays.size()/stride);
    std::vector<UnsignedInt> newInterleavedArrays;
    for(std::size_t oldIndex = 0, end = interleavedArrays.size()/stride; oldIndex != end; ++oldIndex) {
        /* Try to insert new index combination to the map */
        const auto result = indexCombinations.emplace(oldIndex, indexCombinations.size());

        /* Add the (either new or already existing) index to resulting index array */
        combinedIndices.push_back(result.first->second);

        /* If this is new combination, copy it to new interleaved arrays */
        if(result.second) newInterleavedArrays.insert(newInterleavedArrays.end(),
            interleavedArrays.begin()+oldIndex*stride,
            interleavedArrays.begin()+(oldIndex+1)*stride);
    }

    CORRADE_INTERNAL_ASSERT(combinedIndices.size() == interleavedArrays.size()/stride &&
                            newInterleavedArrays.size() <= interleavedArrays.size());

    return {std::move(combinedIndices), std::move(newInterleavedArrays)};
}

}}
<commit_msg>MeshTools: fix test on build without assertions.<commit_after>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include "CombineIndexedArrays.h"

#include <cstring>
#include <unordered_map>
#include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/MurmurHash2.h>

#include "Magnum/Magnum.h"

namespace Magnum { namespace MeshTools {

namespace Implementation {

std::pair<std::vector<UnsignedInt>, std::vector<UnsignedInt>> interleaveAndCombineIndexArrays(const std::reference_wrapper<const std::vector<UnsignedInt>>* begin, const std::reference_wrapper<const std::vector<UnsignedInt>>* end) {
    /* Array stride and size */
    const UnsignedInt stride = end - begin;
    const UnsignedInt inputSize = begin->get().size();
    #if !defined(CORRADE_NO_ASSERT) || defined(CORRADE_GRACEFUL_ASSERT)
    for(auto it = begin; it != end; ++it)
        CORRADE_ASSERT(it->get().size() == inputSize, "MeshTools::combineIndexArrays(): the arrays don't have the same size", {});
    #endif

    /* Interleave the arrays */
    std::vector<UnsignedInt> interleavedArrays;
    interleavedArrays.resize(inputSize*stride);
    for(UnsignedInt offset = 0; offset != stride; ++offset) {
        const auto& array = (begin+offset)->get();
        for(UnsignedInt i = 0; i != inputSize; ++i)
            interleavedArrays[offset + i*stride] = array[i];
    }

    /* Combine them */
    std::vector<UnsignedInt> combinedIndices;
    std::tie(combinedIndices, interleavedArrays) = MeshTools::combineIndexArrays(interleavedArrays, stride);
    return {combinedIndices, interleavedArrays};
}

std::vector<UnsignedInt> combineIndexArrays(const std::reference_wrapper<std::vector<UnsignedInt>>* const begin, const std::reference_wrapper<std::vector<UnsignedInt>>* const end) {
    /* Interleave and combine the arrays */
    std::vector<UnsignedInt> combinedIndices;
    std::vector<UnsignedInt> interleavedCombinedArrays;
    std::tie(combinedIndices, interleavedCombinedArrays) = Implementation::interleaveAndCombineIndexArrays(
        /* This will bite me hard once. */
        reinterpret_cast<const std::reference_wrapper<const std::vector<UnsignedInt>>*>(begin),
        reinterpret_cast<const std::reference_wrapper<const std::vector<UnsignedInt>>*>(end));

    /* Update the original indices */
    const UnsignedInt stride = end - begin;
    const UnsignedInt outputSize = interleavedCombinedArrays.size()/stride;
    for(UnsignedInt offset = 0; offset != stride; ++offset) {
        auto& array = (begin+offset)->get();
        CORRADE_INTERNAL_ASSERT(array.size() >= outputSize);
        array.resize(outputSize);
        for(UnsignedInt i = 0; i != outputSize; ++i)
            array[i] = interleavedCombinedArrays[offset + i*stride];
    }

    return combinedIndices;
}

}

namespace {

class IndexHash {
    public:
        explicit IndexHash(const std::vector<UnsignedInt>& indices, UnsignedInt stride): indices(indices), stride(stride) {}

        std::size_t operator()(UnsignedInt key) const {
            return *reinterpret_cast<const std::size_t*>(Utility::MurmurHash2()(reinterpret_cast<const char*>(indices.data()+key*stride), sizeof(UnsignedInt)*stride).byteArray());
        }

    private:
        const std::vector<UnsignedInt>& indices;
        UnsignedInt stride;
};

class IndexEqual {
    public:
        explicit IndexEqual(const std::vector<UnsignedInt>& indices, UnsignedInt stride): indices(indices), stride(stride) {}

        bool operator()(UnsignedInt a, UnsignedInt b) const {
            return std::memcmp(indices.data()+a*stride, indices.data()+b*stride, sizeof(UnsignedInt)*stride) == 0;
        }

    private:
        const std::vector<UnsignedInt>& indices;
        UnsignedInt stride;
};

}

std::pair<std::vector<UnsignedInt>, std::vector<UnsignedInt>> combineIndexArrays(const std::vector<UnsignedInt>& interleavedArrays, const UnsignedInt stride) {
    CORRADE_ASSERT(stride != 0, "MeshTools::combineIndexArrays(): stride can't be zero", {});
    CORRADE_ASSERT(interleavedArrays.size() % stride == 0, "MeshTools::combineIndexArrays(): array size is not divisible by stride", {});

    /* Hash map with index combinations, containing just indices into
       interleavedArrays vector, hashing and comparison is done using IndexHash
       and IndexEqual functors. Reserving more buckets than necessary (i.e. as
       if each combination was unique). */
    std::unordered_map<UnsignedInt, UnsignedInt, IndexHash, IndexEqual> indexCombinations(
        interleavedArrays.size()/stride,
        IndexHash(interleavedArrays, stride),
        IndexEqual(interleavedArrays, stride));

    /* Make the index combinations unique. Original indices into original
       `interleavedArrays` array were 0, 1, 2, 3, ..., `combinedIndices`
       contains new ones into new (shorter) `newInterleavedArrays` array. */
    std::vector<UnsignedInt> combinedIndices;
    combinedIndices.reserve(interleavedArrays.size()/stride);
    std::vector<UnsignedInt> newInterleavedArrays;
    for(std::size_t oldIndex = 0, end = interleavedArrays.size()/stride; oldIndex != end; ++oldIndex) {
        /* Try to insert new index combination to the map */
        const auto result = indexCombinations.emplace(oldIndex, indexCombinations.size());

        /* Add the (either new or already existing) index to resulting index array */
        combinedIndices.push_back(result.first->second);

        /* If this is new combination, copy it to new interleaved arrays */
        if(result.second) newInterleavedArrays.insert(newInterleavedArrays.end(),
            interleavedArrays.begin()+oldIndex*stride,
            interleavedArrays.begin()+(oldIndex+1)*stride);
    }

    CORRADE_INTERNAL_ASSERT(combinedIndices.size() == interleavedArrays.size()/stride &&
                            newInterleavedArrays.size() <= interleavedArrays.size());

    return {std::move(combinedIndices), std::move(newInterleavedArrays)};
}

}}
<|endoftext|>


<commit_before>// NullFacility.cpp
// Implements the NullFacility class

#include <iostream>
#include <sstream>

#include "NullFacility.h"

#include "GenericResource.h"
#include "Logger.h"
#include "MarketModel.h"
#include "CycException.h"
#include "InputXML.h"

using namespace std;

/**
  TICK
  send a request for your capacity minus your stocks.
  offer stocks + capacity

  TOCK
  process as much in stocks as your capacity will allow.
  send appropriate materials to fill ordersWaiting.

  RECIEVE MATERIAL
  put it in stocks

  SEND MATERIAL
  pull it from inventory, fill the transaction
 */

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::init(xmlNodePtr cur) {
  FacilityModel::init(cur);

  // move XML pointer to current model
  cur = XMLinput->get_xpath_element(cur,"model/NullFacility");

  // all facilities require commodities - possibly many
  in_commod_ = XMLinput->get_xpath_content(cur,"incommodity");
  out_commod_ = XMLinput->get_xpath_content(cur,"outcommodity");

  inventory_.setCapacity(strtod(XMLinput->get_xpath_content(cur,"inventorysize"), NULL));
  stocks_.setCapacity(strtod(XMLinput->get_xpath_content(cur,"inventorysize"), NULL));
  capacity_ = strtod(XMLinput->get_xpath_content(cur,"capacity"), NULL);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::copy(NullFacility* src) {

  FacilityModel::copy(src);

  in_commod_ = src->in_commod_;
  out_commod_ = src->out_commod_;
  inventory_.setCapacity(src->inventory_.capacity());
  stocks_.setCapacity(src->stocks_.capacity());
  capacity_ = src->capacity_;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::copyFreshModel(Model* src) {
  copy(dynamic_cast<NullFacility*>(src));
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::string NullFacility::str() {
  std::stringstream ss;
  ss << FacilityModel::str()
     << " converts commodity '"
     << in_commod_
     << "' into commodity '"
     << out_commod_
     << "', with inventory holding "
     << inventory_.capacity() << " materials"
     << ", and stock holding "
     << stocks_.capacity() << " materials";
  return ss.str();
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::receiveMessage(msg_ptr msg) {
  // is this a message from on high?
  if (msg->supplier()==this) {
    // file the order
    ordersWaiting_.push_front(msg);
  } else {
    throw CycException("NullFacility is not the supplier of this msg.");
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
vector<rsrc_ptr> NullFacility::removeResource(msg_ptr order) {
  Transaction trans = order->trans();
  if (trans.commod != out_commod_) {
    string err_msg = "NullFacility can only send '" + out_commod_ ;
    err_msg += + "' materials.";
    throw CycException(err_msg);
  }

  MatManifest mats;
  try {
    mats = inventory_.popQty(trans.resource->quantity());
  } catch(CycNegQtyException err) {
    LOG(LEV_ERROR, "NulFac") << "extraction of " << trans.resource->quantity()
                   << " kg failed. Inventory is only "
                   << inventory_.quantity() << " kg.";
  }

  return ResourceBuff::toRes(mats);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::addResource(msg_ptr msg, std::vector<rsrc_ptr> manifest) {
  try {
    stocks_.pushAll(ResourceBuff::toMat(manifest));
  } catch(CycOverCapException err) {
    LOG(LEV_ERROR, "NulFac") << "addition of resources"
                   << " to stocks failed. Stocks only has"
                   << stocks_.space() << " kg of space.";
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::handleTick(int time) {
  makeRequests();
  makeOffers();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::makeRequests() {
  double cantake = capacity_;
  if (cantake > inventory_.space()) {
    cantake = inventory_.space();
  } else if (cantake <= 0) {
    return;
  }
  LOG(LEV_INFO3, "NulFac") << name() << " ID=" << ID() << " requesting "
                           << cantake << "kg of " << in_commod_ <<".";

  // build the transaction and message
  MarketModel* market = MarketModel::marketForCommod(in_commod_);
  Communicator* recipient = dynamic_cast<Communicator*>(market);
  Transaction trans = buildRequestTrans(cantake);
  msg_ptr request(new Message(this, recipient, trans));
  request->setNextDest(facInst());
  request->sendOn();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Transaction NullFacility::buildRequestTrans(double amt) {
  Transaction trans;
  gen_rsrc_ptr res = gen_rsrc_ptr(new GenericResource(in_commod_,"kg",amt));
  trans.commod = in_commod_;
  trans.minfrac = 0;
  trans.is_offer = false;
  trans.price = 0;
  trans.resource = res;
  return trans;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::makeOffers() {
  // decide how much to offer
  double offer_amt = inventory_.quantity() + stocks_.quantity();
  if (capacity_ < stocks_.quantity()) {
    offer_amt = inventory_.quantity() + capacity_;
  }
  if (offer_amt >= inventory_.capacity()) {
    offer_amt = inventory_.capacity();
  }

  // there is no minimum amount a null facility may send
  double min_amt = 0;
  // and it's free
  double commod_price = 0;

  // create a Resource and build transaction
  gen_rsrc_ptr res = gen_rsrc_ptr(new GenericResource(out_commod_, "kg", offer_amt));
  Transaction trans;
  trans.commod = out_commod_;
  trans.minfrac = min_amt/offer_amt;
  trans.is_offer = true;
  trans.price = commod_price;
  trans.resource = res;

  // build and send the message
  MarketModel* market = MarketModel::marketForCommod(out_commod_);
  Communicator* recipient = dynamic_cast<Communicator*>(market);
  msg_ptr msg(new Message(this, recipient, trans));
  msg->setNextDest(facInst());
  msg->sendOn();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::handleTock(int time) {
  // at rate allowed by capacity, convert material in Stocks to out_commod_ type
  // move converted material into Inventory

  double tomake = capacity_;
  if (inventory_.space() < tomake) {
    tomake = inventory_.space();
  }
  if (stocks_.quantity() < tomake) {
    tomake = stocks_.quantity();
  }

  LOG(LEV_DEBUG1, "NulFac") << "Transferring " << tomake << " kg of material from "
                  << "stocks to inventory.";
  try {
    inventory_.pushAll(stocks_.popQty(tomake));
  } catch(CycNegQtyException err) {
    LOG(LEV_ERROR, "NulFac") << "extraction of " << tomake
                   << " kg from stocks failed. Stocks is only "
                   << stocks_.quantity() << " kg.";
  } catch(CycOverCapException err) {
    LOG(LEV_ERROR, "NulFac") << "addition of " << tomake
                   << " kg from stocks to inventory failed. Inventory only has"
                   << inventory_.space() << " kg of space.";
  }

  // check what orders are waiting,
  while(!ordersWaiting_.empty()) {
    msg_ptr order = ordersWaiting_.front();
    order->approveTransfer();
    ordersWaiting_.pop_front();
  }
}

/* --------------------
 * all MODEL classes have these members
 * --------------------
 */

extern "C" Model* constructNullFacility() {
    return new NullFacility();
}

/* ------------------- */

<commit_msg>null facility generates no offers if stocks+inventory are empty.<commit_after>// NullFacility.cpp
// Implements the NullFacility class

#include <iostream>
#include <sstream>

#include "NullFacility.h"

#include "GenericResource.h"
#include "Logger.h"
#include "MarketModel.h"
#include "CycException.h"
#include "InputXML.h"

using namespace std;

/**
  TICK
  send a request for your capacity minus your stocks.
  offer stocks + capacity

  TOCK
  process as much in stocks as your capacity will allow.
  send appropriate materials to fill ordersWaiting.

  RECIEVE MATERIAL
  put it in stocks

  SEND MATERIAL
  pull it from inventory, fill the transaction
 */

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::init(xmlNodePtr cur) {
  FacilityModel::init(cur);

  // move XML pointer to current model
  cur = XMLinput->get_xpath_element(cur,"model/NullFacility");

  // all facilities require commodities - possibly many
  in_commod_ = XMLinput->get_xpath_content(cur,"incommodity");
  out_commod_ = XMLinput->get_xpath_content(cur,"outcommodity");

  inventory_.setCapacity(strtod(XMLinput->get_xpath_content(cur,"inventorysize"), NULL));
  stocks_.setCapacity(strtod(XMLinput->get_xpath_content(cur,"inventorysize"), NULL));
  capacity_ = strtod(XMLinput->get_xpath_content(cur,"capacity"), NULL);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::copy(NullFacility* src) {

  FacilityModel::copy(src);

  in_commod_ = src->in_commod_;
  out_commod_ = src->out_commod_;
  inventory_.setCapacity(src->inventory_.capacity());
  stocks_.setCapacity(src->stocks_.capacity());
  capacity_ = src->capacity_;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::copyFreshModel(Model* src) {
  copy(dynamic_cast<NullFacility*>(src));
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::string NullFacility::str() {
  std::stringstream ss;
  ss << FacilityModel::str()
     << " converts commodity '"
     << in_commod_
     << "' into commodity '"
     << out_commod_
     << "', with inventory holding "
     << inventory_.capacity() << " materials"
     << ", and stock holding "
     << stocks_.capacity() << " materials";
  return ss.str();
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::receiveMessage(msg_ptr msg) {
  // is this a message from on high?
  if (msg->supplier()==this) {
    // file the order
    ordersWaiting_.push_front(msg);
  } else {
    throw CycException("NullFacility is not the supplier of this msg.");
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
vector<rsrc_ptr> NullFacility::removeResource(msg_ptr order) {
  Transaction trans = order->trans();
  if (trans.commod != out_commod_) {
    string err_msg = "NullFacility can only send '" + out_commod_ ;
    err_msg += + "' materials.";
    throw CycException(err_msg);
  }

  MatManifest mats;
  try {
    mats = inventory_.popQty(trans.resource->quantity());
  } catch(CycNegQtyException err) {
    LOG(LEV_ERROR, "NulFac") << "extraction of " << trans.resource->quantity()
                   << " kg failed. Inventory is only "
                   << inventory_.quantity() << " kg.";
  }

  return ResourceBuff::toRes(mats);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::addResource(msg_ptr msg, std::vector<rsrc_ptr> manifest) {
  try {
    stocks_.pushAll(ResourceBuff::toMat(manifest));
  } catch(CycOverCapException err) {
    LOG(LEV_ERROR, "NulFac") << "addition of resources"
                   << " to stocks failed. Stocks only has"
                   << stocks_.space() << " kg of space.";
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::handleTick(int time) {
  makeRequests();
  makeOffers();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::makeRequests() {
  double cantake = capacity_;
  if (cantake > inventory_.space()) {
    cantake = inventory_.space();
  } else if (cantake <= 0) {
    return;
  }
  LOG(LEV_INFO3, "NulFac") << name() << " ID=" << ID() << " requesting "
                           << cantake << "kg of " << in_commod_ <<".";

  // build the transaction and message
  MarketModel* market = MarketModel::marketForCommod(in_commod_);
  Communicator* recipient = dynamic_cast<Communicator*>(market);
  Transaction trans = buildRequestTrans(cantake);
  msg_ptr request(new Message(this, recipient, trans));
  request->setNextDest(facInst());
  request->sendOn();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Transaction NullFacility::buildRequestTrans(double amt) {
  Transaction trans;
  gen_rsrc_ptr res = gen_rsrc_ptr(new GenericResource(in_commod_,"kg",amt));
  trans.commod = in_commod_;
  trans.minfrac = 0;
  trans.is_offer = false;
  trans.price = 0;
  trans.resource = res;
  return trans;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::makeOffers() {
  // decide how much to offer
  double offer_amt = inventory_.quantity() + stocks_.quantity();
  if (capacity_ < stocks_.quantity()) {
    offer_amt = inventory_.quantity() + capacity_;
  }
  if (offer_amt >= inventory_.capacity()) {
    offer_amt = inventory_.capacity();
  }

  if (offer_amt < EPS_KG) {
    return;
  }

  // there is no minimum amount a null facility may send
  double min_amt = 0;
  // and it's free
  double commod_price = 0;

  // create a Resource and build transaction
  gen_rsrc_ptr res = gen_rsrc_ptr(new GenericResource(out_commod_, "kg", offer_amt));
  Transaction trans;
  trans.commod = out_commod_;
  trans.minfrac = min_amt/offer_amt;
  trans.is_offer = true;
  trans.price = commod_price;
  trans.resource = res;

  // build and send the message
  MarketModel* market = MarketModel::marketForCommod(out_commod_);
  Communicator* recipient = dynamic_cast<Communicator*>(market);
  msg_ptr msg(new Message(this, recipient, trans));
  msg->setNextDest(facInst());
  msg->sendOn();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullFacility::handleTock(int time) {
  // at rate allowed by capacity, convert material in Stocks to out_commod_ type
  // move converted material into Inventory

  double tomake = capacity_;
  if (inventory_.space() < tomake) {
    tomake = inventory_.space();
  }
  if (stocks_.quantity() < tomake) {
    tomake = stocks_.quantity();
  }

  LOG(LEV_DEBUG1, "NulFac") << "Transferring " << tomake << " kg of material from "
                  << "stocks to inventory.";
  try {
    inventory_.pushAll(stocks_.popQty(tomake));
  } catch(CycNegQtyException err) {
    LOG(LEV_ERROR, "NulFac") << "extraction of " << tomake
                   << " kg from stocks failed. Stocks is only "
                   << stocks_.quantity() << " kg.";
  } catch(CycOverCapException err) {
    LOG(LEV_ERROR, "NulFac") << "addition of " << tomake
                   << " kg from stocks to inventory failed. Inventory only has"
                   << inventory_.space() << " kg of space.";
  }

  // check what orders are waiting,
  while(!ordersWaiting_.empty()) {
    msg_ptr order = ordersWaiting_.front();
    order->approveTransfer();
    ordersWaiting_.pop_front();
  }
}

/* --------------------
 * all MODEL classes have these members
 * --------------------
 */

extern "C" Model* constructNullFacility() {
    return new NullFacility();
}

/* ------------------- */

<|endoftext|>


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

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE state/method access tests

#include <boost/test/unit_test.hpp>
#include <list>

#include "authenticate.h"
#include "eventloop.h"
#include "fetch.h"
#include "json/cJSON.h"
#include "parse.h"
#include "state.h"
#include "table.h"

#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))

enum event {
	UNKNOWN_EVENT,
	ADD_EVENT,
	CHANGE_EVENT,
	REMOVE_EVENT
};

static struct io_event *timer_ev;
static struct eventloop loop;

static const char users[] = "users";
static const char admins[] = "admin";

static cJSON *user_auth;

static struct peer fetch_peer;

static std::list<cJSON*> fetch_events;

extern "C" {
	const cJSON *credentials_ok(const char *user_name, char *passwd)
	{
		(void)passwd;

		if (::strcmp(user_name, "user") == 0) {
			return user_auth;
		}

		return NULL;
	}

	ssize_t socket_read(socket_type sock, void *buf, size_t count)
	{
		(void)sock;
		(void)count;
		uint64_t number_of_timeouts = 1;
		::memcpy(buf, &number_of_timeouts, sizeof(number_of_timeouts));
		return 8;
	}

	int socket_close(socket_type sock)
	{
		(void)sock;
		return 0;
	}
}

static cJSON *parse_send_buffer(const char *json)
{
	const char *end_parse;
	cJSON *root = cJSON_ParseWithOpts(json, &end_parse, 0);
	return root;
}

static int send_message(const struct peer *p, char *rendered, size_t len)
{
	(void)len;
	if (p == &fetch_peer) {
		cJSON *fetch_event = parse_send_buffer(rendered);
		fetch_events.push_back(fetch_event);
	}

	return 0;
}

static enum eventloop_return fake_add(const void *this_ptr, const struct io_event *ev)
{
	(void)this_ptr;
	timer_ev = (struct io_event *)ev;
	return EL_CONTINUE_LOOP;
}

static void fake_remove(const void *this_ptr, const struct io_event *ev)
{
	(void)this_ptr;
	(void)ev;
	timer_ev = NULL;
	return;
}

static cJSON *create_fetch_params(const char *path_equals_string)
{
	cJSON *root = cJSON_CreateObject();
	BOOST_REQUIRE(root != NULL);
	cJSON_AddStringToObject(root, "id", "fetch_id_1");
	cJSON *path = cJSON_CreateObject();
	BOOST_REQUIRE(path != NULL);
	cJSON_AddItemToObject(root, "path", path);
	if (strlen(path_equals_string)) {
		cJSON_AddStringToObject(path, "equals", path_equals_string);
	}
	return root;
}

static enum event get_event_from_json(cJSON *json)
{
	cJSON *params = cJSON_GetObjectItem(json, "params");
	if (params == NULL) return UNKNOWN_EVENT;
	cJSON *event = cJSON_GetObjectItem(params, "event");
	if (event == NULL) return UNKNOWN_EVENT;
	if (event->type != cJSON_String) return UNKNOWN_EVENT;
	if (strcmp(event->valuestring, "add") == 0) return ADD_EVENT;
	if (strcmp(event->valuestring, "change") == 0) return CHANGE_EVENT;
	if (strcmp(event->valuestring, "remove") == 0) return REMOVE_EVENT;
	return UNKNOWN_EVENT;
}

struct F {
	F()
	{
		timer_ev = NULL;
		loop.this_ptr = NULL;
		loop.init = NULL;
		loop.destroy = NULL;
		loop.run = NULL;
		loop.add = fake_add;
		loop.remove = fake_remove;

		init_parser();
		state_hashtable_create();
		init_peer(&owner_peer, false, &loop);
		owner_peer.send_message = send_message;
		init_peer(&set_peer, false, &loop);
		set_peer.send_message = send_message;
		init_peer(&fetch_peer, false, &loop);
		fetch_peer.send_message = send_message;

		cJSON *groups = cJSON_CreateArray();
		cJSON_AddItemToArray(groups, cJSON_CreateString(admins));
		cJSON_AddItemToArray(groups, cJSON_CreateString(users));
		cJSON_AddItemToArray(groups, cJSON_CreateString("operators"));
		cJSON_AddItemToArray(groups, cJSON_CreateString("viewers"));
		create_groups();
		add_groups(groups);
		cJSON_Delete(groups);

		user_auth = cJSON_CreateObject();
		cJSON *fetch_groups = cJSON_CreateArray();
		cJSON_AddItemToArray(fetch_groups, cJSON_CreateString(users));
		cJSON_AddItemToObject(user_auth, "fetchGroups", fetch_groups);
		cJSON *set_groups = cJSON_CreateArray();
		cJSON_AddItemToArray(set_groups, cJSON_CreateString(users));
		cJSON_AddItemToObject(user_auth, "setGroups", set_groups);
		cJSON *call_groups = cJSON_CreateArray();
		cJSON_AddItemToArray(call_groups, cJSON_CreateString(users));
		cJSON_AddItemToObject(user_auth, "callGroups", call_groups);
	}

	~F()
	{
		while (!fetch_events.empty()) {
			cJSON *ptr = fetch_events.front();
			fetch_events.pop_front();
			cJSON_Delete(ptr);
		}
		cJSON_Delete(user_auth);
		free_groups();
		free_peer_resources(&fetch_peer);
		free_peer_resources(&set_peer);
		free_peer_resources(&owner_peer);
		state_hashtable_delete();
	}

	struct peer owner_peer;
	struct peer set_peer;
};

BOOST_FIXTURE_TEST_CASE(fetch_state_allowed, F)
{
	const char path[] = "/foo/bar/";
	cJSON *value = cJSON_CreateNumber(1234);
	cJSON *access = cJSON_CreateObject();
	cJSON *fetch_groups = cJSON_CreateArray();
	cJSON_AddItemToArray(fetch_groups, cJSON_CreateString(admins));
	cJSON_AddItemToArray(fetch_groups, cJSON_CreateString(users));
	cJSON_AddItemToObject(access, "fetchGroups", fetch_groups);
	cJSON *set_groups = cJSON_CreateArray();
	cJSON_AddItemToArray(set_groups, cJSON_CreateString(admins));
	cJSON_AddItemToObject(access, "setGroups", set_groups);

	cJSON *error = add_state_or_method_to_peer(&owner_peer, path, value, access, 0x00, CONFIG_ROUTED_MESSAGES_TIMEOUT);
	BOOST_REQUIRE_MESSAGE(error == NULL, "add_state_or_method_to_peer() failed!");

	cJSON_Delete(value);
	cJSON_Delete(access);

	char password[] = "user_passwd";
	error = handle_authentication(&fetch_peer, "user", password);
	BOOST_CHECK_MESSAGE(error == NULL, "fetch peer authentication failed!");

	struct fetch *f = NULL;
	cJSON *params = create_fetch_params(path);
	error = add_fetch_to_peer(&fetch_peer, params, &f);
	cJSON_Delete(params);
	BOOST_REQUIRE_MESSAGE(error == NULL, "add_fetch_to_peer() failed!");
	error = add_fetch_to_states(f);
	BOOST_REQUIRE_MESSAGE(error == NULL, "add_fetch_to_states() failed!");

	BOOST_REQUIRE_MESSAGE(fetch_events.size() == 1, "Number of emitted events != 1!");
	cJSON *json = fetch_events.front();
	fetch_events.pop_front();
	event event = get_event_from_json(json);
	BOOST_CHECK_MESSAGE(event == ADD_EVENT, "Emitted event is not an ADD event!");
	cJSON_Delete(json);
	remove_all_fetchers_from_peer(&fetch_peer);

	int ret = remove_state_or_method_from_peer(&owner_peer, path);
	BOOST_CHECK_MESSAGE(ret == 0, "remove_state_or_method_from_peer() failed!");
}
<commit_msg>Ensure that fetch without access rights will not get an add event.<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) <2016> <Stephan Gatzka>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE state/method access tests

#include <boost/test/unit_test.hpp>
#include <list>

#include "authenticate.h"
#include "eventloop.h"
#include "fetch.h"
#include "json/cJSON.h"
#include "parse.h"
#include "state.h"
#include "table.h"

#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))

enum event {
	UNKNOWN_EVENT,
	ADD_EVENT,
	CHANGE_EVENT,
	REMOVE_EVENT
};

static struct io_event *timer_ev;
static struct eventloop loop;

const char path[] = "/foo/bar/";

static const char users[] = "users";
static const char admins[] = "admin";

static cJSON *user_auth;

static struct peer fetch_peer;

static std::list<cJSON*> fetch_events;

extern "C" {
	const cJSON *credentials_ok(const char *user_name, char *passwd)
	{
		(void)passwd;

		if (::strcmp(user_name, "user") == 0) {
			return user_auth;
		}

		return NULL;
	}

	ssize_t socket_read(socket_type sock, void *buf, size_t count)
	{
		(void)sock;
		(void)count;
		uint64_t number_of_timeouts = 1;
		::memcpy(buf, &number_of_timeouts, sizeof(number_of_timeouts));
		return 8;
	}

	int socket_close(socket_type sock)
	{
		(void)sock;
		return 0;
	}
}

static cJSON *parse_send_buffer(const char *json)
{
	const char *end_parse;
	cJSON *root = cJSON_ParseWithOpts(json, &end_parse, 0);
	return root;
}

static int send_message(const struct peer *p, char *rendered, size_t len)
{
	(void)len;
	if (p == &fetch_peer) {
		cJSON *fetch_event = parse_send_buffer(rendered);
		fetch_events.push_back(fetch_event);
	}

	return 0;
}

static enum eventloop_return fake_add(const void *this_ptr, const struct io_event *ev)
{
	(void)this_ptr;
	timer_ev = (struct io_event *)ev;
	return EL_CONTINUE_LOOP;
}

static void fake_remove(const void *this_ptr, const struct io_event *ev)
{
	(void)this_ptr;
	(void)ev;
	timer_ev = NULL;
	return;
}

static cJSON *create_fetch_params(const char *path_equals_string)
{
	cJSON *root = cJSON_CreateObject();
	BOOST_REQUIRE(root != NULL);
	cJSON_AddStringToObject(root, "id", "fetch_id_1");
	cJSON *path = cJSON_CreateObject();
	BOOST_REQUIRE(path != NULL);
	cJSON_AddItemToObject(root, "path", path);
	if (strlen(path_equals_string)) {
		cJSON_AddStringToObject(path, "equals", path_equals_string);
	}
	return root;
}

static enum event get_event_from_json(cJSON *json)
{
	cJSON *params = cJSON_GetObjectItem(json, "params");
	if (params == NULL) return UNKNOWN_EVENT;
	cJSON *event = cJSON_GetObjectItem(params, "event");
	if (event == NULL) return UNKNOWN_EVENT;
	if (event->type != cJSON_String) return UNKNOWN_EVENT;
	if (strcmp(event->valuestring, "add") == 0) return ADD_EVENT;
	if (strcmp(event->valuestring, "change") == 0) return CHANGE_EVENT;
	if (strcmp(event->valuestring, "remove") == 0) return REMOVE_EVENT;
	return UNKNOWN_EVENT;
}

static void perform_fetch(const char *path)
{
	struct fetch *f = NULL;
	cJSON *params = create_fetch_params(path);
	cJSON *error = add_fetch_to_peer(&fetch_peer, params, &f);
	cJSON_Delete(params);
	BOOST_REQUIRE_MESSAGE(error == NULL, "add_fetch_to_peer() failed!");
	error = add_fetch_to_states(f);
	BOOST_REQUIRE_MESSAGE(error == NULL, "add_fetch_to_states() failed!");
}

struct F {
	F()
	{
		timer_ev = NULL;
		loop.this_ptr = NULL;
		loop.init = NULL;
		loop.destroy = NULL;
		loop.run = NULL;
		loop.add = fake_add;
		loop.remove = fake_remove;

		init_parser();
		state_hashtable_create();
		init_peer(&owner_peer, false, &loop);
		owner_peer.send_message = send_message;
		init_peer(&set_peer, false, &loop);
		set_peer.send_message = send_message;
		init_peer(&fetch_peer, false, &loop);
		fetch_peer.send_message = send_message;

		cJSON *groups = cJSON_CreateArray();
		cJSON_AddItemToArray(groups, cJSON_CreateString(admins));
		cJSON_AddItemToArray(groups, cJSON_CreateString(users));
		cJSON_AddItemToArray(groups, cJSON_CreateString("operators"));
		cJSON_AddItemToArray(groups, cJSON_CreateString("viewers"));
		create_groups();
		add_groups(groups);
		cJSON_Delete(groups);

		user_auth = cJSON_CreateObject();
		cJSON *fetch_groups = cJSON_CreateArray();
		cJSON_AddItemToArray(fetch_groups, cJSON_CreateString(users));
		cJSON_AddItemToObject(user_auth, "fetchGroups", fetch_groups);
		cJSON *set_groups = cJSON_CreateArray();
		cJSON_AddItemToArray(set_groups, cJSON_CreateString(users));
		cJSON_AddItemToObject(user_auth, "setGroups", set_groups);
		cJSON *call_groups = cJSON_CreateArray();
		cJSON_AddItemToArray(call_groups, cJSON_CreateString(users));
		cJSON_AddItemToObject(user_auth, "callGroups", call_groups);

		value = cJSON_CreateNumber(1234);
		password = ::strdup("password");
	}

	~F()
	{
		::free(password);
		cJSON_Delete(value);

		while (!fetch_events.empty()) {
			cJSON *ptr = fetch_events.front();
			fetch_events.pop_front();
			cJSON_Delete(ptr);
		}
		cJSON_Delete(user_auth);
		free_groups();
		free_peer_resources(&fetch_peer);
		free_peer_resources(&set_peer);
		free_peer_resources(&owner_peer);
		state_hashtable_delete();
	}

	cJSON *value;
	char *password;
	struct peer owner_peer;
	struct peer set_peer;
};

BOOST_FIXTURE_TEST_CASE(fetch_state_allowed, F)
{
	cJSON *access = cJSON_CreateObject();
	cJSON *fetch_groups = cJSON_CreateArray();
	cJSON_AddItemToArray(fetch_groups, cJSON_CreateString(users));
	cJSON_AddItemToObject(access, "fetchGroups", fetch_groups);

	cJSON *error = add_state_or_method_to_peer(&owner_peer, path, value, access, 0x00, CONFIG_ROUTED_MESSAGES_TIMEOUT);
	BOOST_REQUIRE_MESSAGE(error == NULL, "add_state_or_method_to_peer() failed!");
	cJSON_Delete(access);

	error = handle_authentication(&fetch_peer, "user", password);
	BOOST_CHECK_MESSAGE(error == NULL, "fetch peer authentication failed!");

	perform_fetch(path);
	BOOST_REQUIRE_MESSAGE(fetch_events.size() == 1, "Number of emitted events != 1!");
	cJSON *json = fetch_events.front();
	fetch_events.pop_front();
	event event = get_event_from_json(json);
	BOOST_CHECK_MESSAGE(event == ADD_EVENT, "Emitted event is not an ADD event!");
	cJSON_Delete(json);
	remove_all_fetchers_from_peer(&fetch_peer);
}

BOOST_FIXTURE_TEST_CASE(fetch_state_not_allowed, F)
{
	cJSON *access = cJSON_CreateObject();
	cJSON *fetch_groups = cJSON_CreateArray();
	cJSON_AddItemToArray(fetch_groups, cJSON_CreateString(admins));
	cJSON_AddItemToObject(access, "fetchGroups", fetch_groups);

	cJSON *error = add_state_or_method_to_peer(&owner_peer, path, value, access, 0x00, CONFIG_ROUTED_MESSAGES_TIMEOUT);
	BOOST_REQUIRE_MESSAGE(error == NULL, "add_state_or_method_to_peer() failed!");
	cJSON_Delete(access);

	error = handle_authentication(&fetch_peer, "user", password);
	BOOST_CHECK_MESSAGE(error == NULL, "fetch peer authentication failed!");

	perform_fetch(path);
	BOOST_REQUIRE_MESSAGE(fetch_events.size() == 0, "Number of emitted events != 0!");
	remove_all_fetchers_from_peer(&fetch_peer);
}
<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2012 Scientific Computing and Imaging Institute,
   University of Utah.

   License for the specific language governing rights and limitations under
   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <Testing/ModuleTestBase/ModuleTestBase.h>
#include <Modules/Visualization/ShowField.h>
#include <Core/Datatypes/Legacy/Field/Field.h>
#include <Core/Algorithms/Base/AlgorithmVariableNames.h>
#include <Core/Utils/Exception.h>
#include <Core/Logging/Log.h>

using namespace SCIRun::Testing;
using namespace SCIRun::Core::Datatypes;
using namespace SCIRun::Dataflow::Networks;
using namespace SCIRun::Core::Algorithms;
using namespace SCIRun::Core;
using namespace SCIRun;
using namespace SCIRun::Core::Logging;
using ::testing::Values;
using ::testing::Combine;
using ::testing::Range;

class ShowFieldScalingTest : public ParameterizedModuleTest<int>
{
protected:
  virtual void SetUp()
  {
    Log::get().setVerbose(false);
    showField = makeModule("ShowField");
    showField->setStateDefaults();
    auto size = GetParam();
    latVol = CreateEmptyLatVol(size, size, size);
    stubPortNWithThisData(showField, 0, latVol);
    Log::get() << INFO << "Setting up ShowField with size " << size << "^3 latvol" << std::endl;
  }

  UseRealModuleStateFactory f;
  ModuleHandle showField;
  FieldHandle latVol;
};

TEST_P(ShowFieldScalingTest, ConstructLatVolGeometry)
{
  Log::get() << INFO << "Start ShowField::execute" << std::endl;
  showField->execute();
  Log::get() << INFO << "End ShowField::execute" << std::endl;
}

INSTANTIATE_TEST_CASE_P(
  ConstructLatVolGeometry,
  ShowFieldScalingTest,
  Values(20, 40, 60, 80
  //, 100, 120, 150  //too slow already
  )
  );<commit_msg>Extend test for Mac<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2012 Scientific Computing and Imaging Institute,
   University of Utah.

   License for the specific language governing rights and limitations under
   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <Testing/ModuleTestBase/ModuleTestBase.h>
#include <Modules/Visualization/ShowField.h>
#include <Core/Datatypes/Legacy/Field/Field.h>
#include <Core/Algorithms/Base/AlgorithmVariableNames.h>
#include <Core/Utils/Exception.h>
#include <Core/Logging/Log.h>

using namespace SCIRun::Testing;
using namespace SCIRun::Core::Datatypes;
using namespace SCIRun::Dataflow::Networks;
using namespace SCIRun::Core::Algorithms;
using namespace SCIRun::Core;
using namespace SCIRun;
using namespace SCIRun::Core::Logging;
using ::testing::Values;
using ::testing::Combine;
using ::testing::Range;

class ShowFieldScalingTest : public ParameterizedModuleTest<int>
{
protected:
  virtual void SetUp()
  {
    Log::get().setVerbose(false);
    showField = makeModule("ShowField");
    showField->setStateDefaults();
    auto size = GetParam();
    latVol = CreateEmptyLatVol(size, size, size);
    stubPortNWithThisData(showField, 0, latVol);
    Log::get() << INFO << "Setting up ShowField with size " << size << "^3 latvol" << std::endl;
  }

  UseRealModuleStateFactory f;
  ModuleHandle showField;
  FieldHandle latVol;
};

TEST_P(ShowFieldScalingTest, ConstructLatVolGeometry)
{
  Log::get() << INFO << "Start ShowField::execute" << std::endl;
  showField->execute();
  Log::get() << INFO << "End ShowField::execute" << std::endl;
}

INSTANTIATE_TEST_CASE_P(
  ConstructLatVolGeometry,
  ShowFieldScalingTest,
  Values(20, 40, 60, 80
  #ifndef WIN32   //too slow already
  , 100, 120, 150, 200, 256
  #endif
  )
  );
<|endoftext|>


<commit_before>#include <climits>
#include "splitter.hpp"

question_data splitter::operator() (question_raw_data const& raw)
{
    question_data formed = {
        raw.split_num,
        raw.selectable_num,
        raw.cost.first,
        raw.cost.second,
        std::vector<std::vector<int>>(raw.split_num.second, std::vector<int>(raw.split_num.first, INT_MAX) )
    };

    auto& block = formed.block;

    //
    // Sub Algorithm
    // 正しい位置に並べた時に左上から，1~nまでの番号をふり，それが今どこにあるのかという情報をblockに格納
    //

    // Sub Algorithm End

    return formed;
}
<commit_msg>split_image function impled.<commit_after>#include <climits>
#include "splitter.hpp"

// 気持ち悪いが，[i][j]の位置に分割された画像が入っている．更に[j][k]へのアクセスによって画素にアクセス
typedef std::vector<std::vector<std::vector<std::vector<std::tuple<char,char,char>>>>> split_image_type;

void recursive_operation(std::pair<int,int> const now, split_image_type const& split_image, std::vector<std::vector<int>>& output)
{
    //// nowの上下左右に隣接するブロックを探して，それに再帰する
    //{
    //    auto const target = std::make_pair(now.first + 1, now.second);
    //    for(
    //}

    return;
}

split_image_type split_image(question_raw_data const& raw)
{
    int const parts_width = raw.size.first / raw.split_num.first;
    int const parts_height = raw.size.second / raw.split_num.second;

    std::vector<std::vector<std::vector<std::vector<std::tuple<char,char,char>>>>> split_pixels(
        raw.split_num.second,
        std::vector<std::vector<std::vector<std::tuple<char,char,char>>>>(
            raw.split_num.first,
            std::vector<std::vector<std::tuple<char,char,char>>>(
                parts_height,
                std::vector<std::tuple<char,char,char>>(
                    parts_width,
                    std::make_tuple(0,0,0)
                )
            )
        )
    );

    for(int i=0; i<raw.split_num.second; ++i) for(int j=0; j<raw.split_num.first; ++j)
    {
        int const splitting_pos = i * raw.split_num.first + j;
        for(int k=0; k<parts_height; ++k) for(int l=0; l<parts_width; ++l)
        {
            split_pixels[i][j][k][l] = raw.pixels[parts_height * i + k][parts_width * j + l];
        }
    }

    return split_pixels;
}

question_data splitter::operator() (question_raw_data const& raw)
{
    question_data formed = {
        raw.split_num,
        raw.selectable_num,
        raw.cost.first,
        raw.cost.second,
        std::vector<std::vector<int>>(raw.split_num.second, std::vector<int>(raw.split_num.first, INT_MAX) )
    };

    auto& block = formed.block;

    //
    // Sub Algorithm
    // 正しい位置に並べた時に左上から，1~nまでの番号をふり，それが今どこにあるのかという情報をblockに格納
    //

    auto const split_pixels = split_image(raw);

    // Sub Algorithm End

    return formed;
}
<|endoftext|>


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

#include <string>
#include <vector>

#include "ComputeParser.h"

// stdout configuration
bool g_PrintHeader = true;
bool g_PrintHelp = false;
bool g_Verbose = false;

std::string g_InputFilename;
std::string g_OutputFilename;

#define LOG if (g_Verbose) printf

#ifndef _MSC_VER
#include <cstring>
#include <strings.h>
#include <cstdio>
#define strcmpi strcasecmp
#endif

const char* ParseArguments(int argc, const char* argv[])
{
	int i;

	for (i = 1; i < argc; i++)
	{
		const char* arg = argv[i];

		// Is this an option?
		if (arg[0] == '-')
		{
			if (!strcmpi(arg, "-h"))
			{
				g_PrintHelp = true;
			}

			else if (!strcmpi(arg, "-noheader"))
			{
				g_PrintHeader = false;
			}

			else if (!strcmpi(arg, "-verbose"))
			{
				g_Verbose = true;
			}

			else if (!strcmpi(arg, "-output") && i < argc - 1)
			{
				g_OutputFilename = argv[i + 1];
				i++;
			}
		}

		else
		{
			// Must be a filename
			g_InputFilename = arg;
		}
	}

	if (g_InputFilename[0] == 0)
		return "No input filename specified";

	return 0;
}

void PrintHeader()
{
	printf("cbpp Compute Bridge Preprocessor Copyright 2014 Celtoys Ltd\n");
	printf("Licensed under the Apache License, Version 2.0 \n");
}

void PrintUsage()
{
	printf("Usage: cbpp [options] filename\n");

	if (g_PrintHelp)
	{
		printf("\nOptions are:\n\n");
		printf("   -noheader          Supress header\n");
		printf("   -verbose           Print logs detailing what cbpp is doing behind the scenes\n");
	}
}

class ComputeProcessor
{
public:
	ComputeProcessor()
		: m_MemoryFile(0)
		, m_LexerCursor(0)
		, m_ParserCursor(0)
	{
	}

	bool Parse(const char* filename)
	{
		// Open the input file
		LOG("Opening file '%s'\n", filename);
		if (cmpError error = cmpMemoryFile_Create(&m_MemoryFile, filename))
		{
			printf("Error opening input file: %s\n\n", cmpError_Text(&error));
			return false;
		}

		// Build a list of tokens
		LOG("Running lexer\n");
		if (cmpError error = cmpLexerCursor_Create(&m_LexerCursor, cmpMemoryFile_Data(m_MemoryFile), cmpMemoryFile_Size(m_MemoryFile)))
		{
			printf("Error creating lexer cursor: %s\n\n", cmpError_Text(&error));
			return false;
		}
		while (cmpToken token = cmpLexer_ConsumeToken(m_LexerCursor))
		{
			m_Tokens.push_back(token);
			LOG("[0x%2x] %s %d\n", token.type, cmpTokenType_Name(token.type), token.length);
		}

		// Print any lexer errors
		if (cmpError error = cmpLexerCursor_Error(m_LexerCursor))
		{
			printf("%s(%d): %s\n", filename, cmpLexerCursor_Line(m_LexerCursor), cmpError_Text(&error));
			return false;
		}

		// Build a list of parser nodes
		LOG("Running parser\n");
		if (cmpError error = cmpParserCursor_Create(&m_ParserCursor, m_Tokens.data(), m_Tokens.size()))
		{
			printf("Error creating parser cursor: %s\n\n", cmpError_Text(&error));
			return false;
		}
		while (cmpNode* node = cmpParser_ConsumeNode(m_ParserCursor))
			m_Nodes.push_back(node);

		if (g_Verbose)
		{
			for (size_t i = 0; i < m_Nodes.size(); i++)
				cmpParser_LogNodes(m_Nodes[i], 0);
		}

		// Print any parser errors
		if (cmpError error = cmpParserCursor_Error(m_ParserCursor))
		{
			printf("%s(%d): %s\n",filename, cmpParserCursor_Line(m_ParserCursor), cmpError_Text(&error));
			return false;
		}

		return true;
	}

	bool EmitFile(const char* filename)
	{
		FILE* fp = fopen(filename, "wb");
		if (fp == NULL)
			return false;

		for (size_t i = 0; i < m_Nodes.size(); i++)
			EmitNode(fp, m_Nodes[i]);

		fclose(fp);
		return true;
	}

	~ComputeProcessor()
	{
		for (std::size_t i = 0; i < m_Nodes.size(); i++)
			cmpNode_Destroy(m_Nodes[i]);

		if (m_ParserCursor != 0)
			cmpParserCursor_Destroy(m_ParserCursor);

		if (m_LexerCursor != 0)
			cmpLexerCursor_Destroy(m_LexerCursor);

		if (m_MemoryFile != 0)
			cmpMemoryFile_Destroy(m_MemoryFile);
	}

private:
	void EmitNode(FILE* fp, const cmpNode* node)
	{
		for (cmpU32 i = 0; i < node->nb_tokens; i++)
		{
			const cmpToken& token = node->start_token[i];
			fprintf(fp, "%.*s", token.length, token.start);
		}

		for (const cmpNode* child = node->first_child; child != 0; child = child->next_sibling)
			EmitNode(fp, child);
	}

	// Parser runtime
	cmpMemoryFile* m_MemoryFile;
	cmpLexerCursor* m_LexerCursor;
	cmpParserCursor* m_ParserCursor;

	// Generated tokens and AST
	std::vector<cmpToken> m_Tokens;
	std::vector<cmpNode*> m_Nodes;
};

int main(int argc, const char* argv[])
{
	// Attempt to parse arguments
	if (const char* error = ParseArguments(argc, argv))
	{
		PrintHeader();
		printf("\nError parsing arguments: %s\n\n", error);
		PrintUsage();
		return 1;
	}

	// Print program information
	if (g_PrintHeader)
		PrintHeader();
	if (g_PrintHelp)
		PrintUsage();

	ComputeProcessor processor;
	if (!processor.Parse(g_InputFilename.c_str()))
		return 1;

	if (!g_OutputFilename.empty())
	{
		if (!processor.EmitFile(g_OutputFilename.c_str()))
		{
			printf("Couldn't write to output file %s\n", g_OutputFilename.c_str());
			return 1;
		}
	}

	return 0;
}
<commit_msg>Add  node visiting to the compute processor.<commit_after>
//
// Copyright 2014 Celtoys Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include <string>
#include <vector>
#include <cassert>

#include "ComputeParser.h"

// stdout configuration
bool g_PrintHeader = true;
bool g_PrintHelp = false;
bool g_Verbose = false;

std::string g_InputFilename;
std::string g_OutputFilename;

#define LOG if (g_Verbose) printf

#ifndef _MSC_VER
#include <cstring>
#include <strings.h>
#include <cstdio>
#define strcmpi strcasecmp
#endif

const char* ParseArguments(int argc, const char* argv[])
{
	int i;

	for (i = 1; i < argc; i++)
	{
		const char* arg = argv[i];

		// Is this an option?
		if (arg[0] == '-')
		{
			if (!strcmpi(arg, "-h"))
			{
				g_PrintHelp = true;
			}

			else if (!strcmpi(arg, "-noheader"))
			{
				g_PrintHeader = false;
			}

			else if (!strcmpi(arg, "-verbose"))
			{
				g_Verbose = true;
			}

			else if (!strcmpi(arg, "-output") && i < argc - 1)
			{
				g_OutputFilename = argv[i + 1];
				i++;
			}
		}

		else
		{
			// Must be a filename
			g_InputFilename = arg;
		}
	}

	if (g_InputFilename[0] == 0)
		return "No input filename specified";

	return 0;
}

void PrintHeader()
{
	printf("cbpp Compute Bridge Preprocessor Copyright 2014 Celtoys Ltd\n");
	printf("Licensed under the Apache License, Version 2.0 \n");
}

void PrintUsage()
{
	printf("Usage: cbpp [options] filename\n");

	if (g_PrintHelp)
	{
		printf("\nOptions are:\n\n");
		printf("   -noheader          Supress header\n");
		printf("   -verbose           Print logs detailing what cbpp is doing behind the scenes\n");
	}
}

struct INodeVisitor
{
	virtual void Visit(cmpNode& node) = 0;
};

struct EmitFile : public INodeVisitor
{
	EmitFile(const char* filename)
		: fp(0)
	{
		fp = fopen(filename, "wb");
	}

	~EmitFile()
	{
		if (fp != 0)
			fclose(fp);
	}

	void Visit(cmpNode& node)
	{
		for (cmpU32 i = 0; i < node.nb_tokens; i++)
		{
			const cmpToken& token = node.start_token[i];
			fprintf(fp, "%.*s", token.length, token.start);
		}
	}

	FILE* fp;
};

class ComputeProcessor
{
public:
	ComputeProcessor()
		: m_MemoryFile(0)
		, m_LexerCursor(0)
		, m_ParserCursor(0)
	{
	}

	~ComputeProcessor()
	{
		for (std::size_t i = 0; i < m_Nodes.size(); i++)
			cmpNode_Destroy(m_Nodes[i]);

		if (m_ParserCursor != 0)
			cmpParserCursor_Destroy(m_ParserCursor);

		if (m_LexerCursor != 0)
			cmpLexerCursor_Destroy(m_LexerCursor);

		if (m_MemoryFile != 0)
			cmpMemoryFile_Destroy(m_MemoryFile);
	}

	bool Parse(const char* filename)
	{
		// Open the input file
		LOG("Opening file '%s'\n", filename);
		if (cmpError error = cmpMemoryFile_Create(&m_MemoryFile, filename))
		{
			printf("Error opening input file: %s\n\n", cmpError_Text(&error));
			return false;
		}

		// Build a list of tokens
		LOG("Running lexer\n");
		if (cmpError error = cmpLexerCursor_Create(&m_LexerCursor, cmpMemoryFile_Data(m_MemoryFile), cmpMemoryFile_Size(m_MemoryFile)))
		{
			printf("Error creating lexer cursor: %s\n\n", cmpError_Text(&error));
			return false;
		}
		while (cmpToken token = cmpLexer_ConsumeToken(m_LexerCursor))
		{
			m_Tokens.push_back(token);
			LOG("[0x%2x] %s %d\n", token.type, cmpTokenType_Name(token.type), token.length);
		}

		// Print any lexer errors
		if (cmpError error = cmpLexerCursor_Error(m_LexerCursor))
		{
			printf("%s(%d): %s\n", filename, cmpLexerCursor_Line(m_LexerCursor), cmpError_Text(&error));
			return false;
		}

		// Build a list of parser nodes
		LOG("Running parser\n");
		if (cmpError error = cmpParserCursor_Create(&m_ParserCursor, m_Tokens.data(), m_Tokens.size()))
		{
			printf("Error creating parser cursor: %s\n\n", cmpError_Text(&error));
			return false;
		}
		while (cmpNode* node = cmpParser_ConsumeNode(m_ParserCursor))
			m_Nodes.push_back(node);

		if (g_Verbose)
		{
			for (size_t i = 0; i < m_Nodes.size(); i++)
				cmpParser_LogNodes(m_Nodes[i], 0);
		}

		// Print any parser errors
		if (cmpError error = cmpParserCursor_Error(m_ParserCursor))
		{
			printf("%s(%d): %s\n",filename, cmpParserCursor_Line(m_ParserCursor), cmpError_Text(&error));
			return false;
		}

		return true;
	}

	void VisitNodes(INodeVisitor* visitor)
	{
		assert(visitor != 0);
		for (size_t i = 0; i < m_Nodes.size(); i++)
			VisitNode(m_Nodes[i], visitor);
	}

private:
	void VisitNode(cmpNode* node, INodeVisitor* visitor)
	{
		assert(visitor != 0);
		assert(node != 0);
		visitor->Visit(*node);

		for (cmpNode* child = node->first_child; child != 0; child = child->next_sibling)
			VisitNode(child, visitor);
	}

	// Parser runtime
	cmpMemoryFile* m_MemoryFile;
	cmpLexerCursor* m_LexerCursor;
	cmpParserCursor* m_ParserCursor;

	// Generated tokens and AST
	std::vector<cmpToken> m_Tokens;
	std::vector<cmpNode*> m_Nodes;
};

int main(int argc, const char* argv[])
{
	// Attempt to parse arguments
	if (const char* error = ParseArguments(argc, argv))
	{
		PrintHeader();
		printf("\nError parsing arguments: %s\n\n", error);
		PrintUsage();
		return 1;
	}

	// Print program information
	if (g_PrintHeader)
		PrintHeader();
	if (g_PrintHelp)
		PrintUsage();

	ComputeProcessor processor;
	if (!processor.Parse(g_InputFilename.c_str()))
		return 1;

	if (!g_OutputFilename.empty())
	{
		EmitFile emitter(g_OutputFilename.c_str());
		if (emitter.fp == 0)
		{
			printf("Couldn't write to output file %s\n", g_OutputFilename.c_str());
			return 1;
		}
		processor.VisitNodes(&emitter);
	}

	return 0;
}
<|endoftext|>