<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: controlaccess.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 23:41:11 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _CONTROLACCESS_HXX_
#define _CONTROLACCESS_HXX_

//------------------------------------------------------------------------
// includes
//------------------------------------------------------------------------

#ifndef _SAL_TYPES_H_
#include <sal/types.h>
#endif

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring>
#endif

#include <windows.h>

#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif

//------------------------------------------------------------------------
// deklarations
//------------------------------------------------------------------------

typedef void ( SAL_CALL *CTRL_SETVALUE_FUNCTION_T)( HWND, const ::com::sun::star::uno::Any&, const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >&, sal_Int16 );
typedef ::com::sun::star::uno::Any ( SAL_CALL *CTRL_GETVALUE_FUNCTION_T )( HWND );

// the currently supported control classes
enum CTRL_CLASS
{
    UNKNOWN = 0,
    CHECKBOX,
    LISTBOX,
    PUSHBUTTON
};

// returns the class of a control
CTRL_CLASS SAL_CALL GetCtrlClass( HWND hwndCtrl );

// returns a pointer to a setValue function based on the control class
// and the control action, if no function was found NULL will be returned
CTRL_SETVALUE_FUNCTION_T SAL_CALL GetCtrlSetValueFunction( CTRL_CLASS aCtrlClass, sal_Int16 aCtrlAction );

// returns a pointer to a getValue function based on the control class
// and the control action, if no function was found NULL will be returned
CTRL_GETVALUE_FUNCTION_T SAL_CALL GetCtrlGetValueFunction( CTRL_CLASS aCtrlClass, sal_Int16 aCtrlAction );

// translates a CommonFilePickerElementId as defined in CommonFilePickerElementIds.idl
// to a control id that is valid for the FileOpen dialog under windows as defined
// in dlgs.h in the Windows Platform SDK
int SAL_CALL CommonFilePickerCtrlIdToWinFileOpenCtrlId( sal_Int16 aControlId );

#endif
<commit_msg>INTEGRATION: CWS warnings01 (1.2.18); FILE MERGED 2006/05/15 12:09:02 sb 1.2.18.1: #i53898# Made code warning-free and/or compile at all after resync to SRC680m162.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: controlaccess.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 00:14:21 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _CONTROLACCESS_HXX_
#define _CONTROLACCESS_HXX_

//------------------------------------------------------------------------
// includes
//------------------------------------------------------------------------

#ifndef _SAL_TYPES_H_
#include <sal/types.h>
#endif

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#include <windows.h>

#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif

//------------------------------------------------------------------------
// deklarations
//------------------------------------------------------------------------

typedef void ( SAL_CALL *CTRL_SETVALUE_FUNCTION_T)( HWND, const ::com::sun::star::uno::Any&, const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >&, sal_Int16 );
typedef ::com::sun::star::uno::Any ( SAL_CALL *CTRL_GETVALUE_FUNCTION_T )( HWND );

// the currently supported control classes
enum CTRL_CLASS
{
    UNKNOWN = 0,
    CHECKBOX,
    LISTBOX,
    PUSHBUTTON
};

// returns the class of a control
CTRL_CLASS SAL_CALL GetCtrlClass( HWND hwndCtrl );

// returns a pointer to a setValue function based on the control class
// and the control action, if no function was found NULL will be returned
CTRL_SETVALUE_FUNCTION_T SAL_CALL GetCtrlSetValueFunction( CTRL_CLASS aCtrlClass, sal_Int16 aCtrlAction );

// returns a pointer to a getValue function based on the control class
// and the control action, if no function was found NULL will be returned
CTRL_GETVALUE_FUNCTION_T SAL_CALL GetCtrlGetValueFunction( CTRL_CLASS aCtrlClass, sal_Int16 aCtrlAction );

// translates a CommonFilePickerElementId as defined in CommonFilePickerElementIds.idl
// to a control id that is valid for the FileOpen dialog under windows as defined
// in dlgs.h in the Windows Platform SDK
int SAL_CALL CommonFilePickerCtrlIdToWinFileOpenCtrlId( sal_Int16 aControlId );

#endif
<|endoftext|>


<commit_before>#ifndef DEAMORTIZED_HASH_SET
#define DEAMORTIZED_HASH_SET

#include <cstdint>
#include <functional>
#include <cstdlib>
#include <cassert>
#include <cstddef>
#include <memory>
#include <vector>

using std::vector;
using std::pair;
using std::make_pair;

#include "tlsf_allocator.hpp"

template<typename Key,
         typename Hash = std::hash<Key>,
         typename Equal = std::equal_to<Key>,
         typename Allocate = TlsfAllocator<Key> >
class LimitedHashSet {
  typedef std::size_t size_t;
public:

  LimitedHashSet& operator=(const LimitedHashSet&) = delete;
  LimitedHashSet(const LimitedHashSet&) = delete;
  LimitedHashSet(LimitedHashSet&&) = delete;
  LimitedHashSet& operator=(LimitedHashSet&&) = delete;

public:

  struct Slot {
    bool occupied;
    Key key;
  };
  Hash hasher;
  Equal equaler;
  typedef typename Allocate::template rebind<Slot>::other A;
  A allocator;
  size_t capacity, size;
  Slot * data;
  size_t progress;
  enum ACT : char {
    CLEAR, INIT, RESET, FILL
  } state;

public:

  // TODO: overload for std::swap
  // TODO: copy and move and assignment constructors
  void swap(LimitedHashSet & that) {
    std::swap(allocator, that.allocator);
    std::swap(capacity, that.capacity);
    std::swap(size, that.size);
    std::swap(data, that.data);
    std::swap(progress, that.progress);
    std::swap(state, that.state);
  }

  explicit LimitedHashSet(const Allocate& a, const size_t capacity)
    : hasher(), equaler(), allocator(a), capacity(capacity), size(0),
      data(allocator.allocate(capacity)), progress(0), state(INIT)
  {}

  // TODO: this need to take state into account
  ~LimitedHashSet() {
    switch (state) {
    case CLEAR:
      while (progress < capacity) {
        allocator.destroy(&data[progress++]);
      }
      break;
    case INIT: // no data - still initializing
      break;
    case RESET: // no data - not even initialized yet
      break;
    case FILL:
      for (size_t i = 0; i < capacity; ++i) {
        if (data[i].occupied) {
          allocator.destroy(&data[i]);
        }
      }
    }
    allocator.deallocate(data, capacity);
  }

  void clear(const size_t left) {
    assert ((state == FILL) || (state == CLEAR));
    if (state == FILL) {
      progress = 0;
    }
    state = CLEAR;
    const size_t many = (capacity - progress + left - 1)/left;
    for (size_t i = 0; i < many; ++i) {
      allocator.destroy(&data[progress]);
      ++progress;
    }
  }

  void init(const size_t left) {
    assert ((state == RESET) || (state == INIT));
    if (RESET == state) {
      progress = 0;
    }
    state = INIT;
    const size_t many = (capacity - progress + left - 1)/left;
    for (size_t i = 0; i < many; ++i) {
      data[progress].occupied = false;
      ++progress;
    }
  }

  void reset(const size_t new_capacity) {
    assert (state == CLEAR);
    state = RESET;
    size = 0;
    allocator.deallocate(data, capacity);
    capacity = new_capacity;
    data = allocator.allocate(capacity);
    progress = 0;
  }

  void fill(const size_t left, const LimitedHashSet& that) {
    assert ((state == FILL) || (state == INIT));
    if (INIT == state) {
      progress = 0;
    }
    state = FILL;
    // don't care about *my* progress
    const size_t many = (that.capacity - progress + left - 1)/left;
    for (size_t i = 0; i < many; ++i) {
      insert(that.data[progress].key);
      ++progress;
    }
  }

  void catch_up(const vector<pair<Key *, pair<size_t, size_t> > > & moved_back) {
    for (const auto & kft : moved_back) {
      if ((kft.second.first >= progress)
          and (kft.second.second < progress)) {
        insert(kft.first);
      }
    }
  }

private:

  // find a key. capacity must be > 0. if key is not present, returns
  // location where it would be if it were newly placed.
  size_t locate(const Key& k) const {
    const size_t cap_mask = capacity-1;
    auto h = hasher(k) & cap_mask;
    while (true) {
      if (not data[h].occupied)    return h;
      if (equaler(data[h].key, k)) return h;
      h = (h+1) & cap_mask;
    }
  }

  // i < j <= k, mod capacity
  static bool cyclic_between(const size_t& i, const size_t& j, const size_t& k) {
    return (((i < j) and (j <= k))
            or ((i < j) and (k < i))
            or ((j <= k) and (k < i)));
  }

public:
  Key* find(const Key& k) {
    if (NULL == data) return nullptr;
    const size_t i = locate(k);
    if (data[i].occupied && equaler(data[i].key, k)) {
      return &data[i].key;
    }
    return nullptr;
  }

public:

  vector<pair<Key *, pair<size_t, size_t> > > erase(const Key& k) {
    vector<pair<Key *, pair<size_t, size_t> > > ans;
    const size_t cap_mask = capacity-1;
    size_t start = locate(k); // the empty location
    if (not data[start].occupied) return;
    data[start].occupied = false;
    data[start].key.~Key();
    --size;
    size_t i = (start + 1) & cap_mask;
    while (data[i].occupied) {
      const size_t h = hasher(data[i].key) & cap_mask;
      if (not cyclic_between(start,h,i)) {
        data[start].occupied = true;
        new (&data[start].key) Key(std::move(data[i].key));
        start = i;
        data[i].occupied = false;
        ans.push_back(make_pair(&data[start].key, make_pair(i, start)));
        //data[i].key.~Key(); // no : already moved it?
      }
      i = (i+1) & cap_mask;
    }
  }

  bool insert(const Key& k) {
    const size_t i = locate(k);
    if (data[i].occupied) return false;
    new (&data[i].key) Key(k);
    ++size;
    return true;
  }

};

// IDEA: store hash values, ones means "empty"

template<typename Key,
         typename Hash = std::hash<Key>,
         typename Equal = std::equal_to<Key>,
         typename Allocate = TlsfAllocator<Key> >
struct DeamortizedHashSet {

  DeamortizedHashSet() :
    allocator(), far(allocator,0), near(allocator,32) {
    near.init(1);
  }

  Allocate allocator;
  LimitedHashSet<Key, Hash, Equal, Allocate> far, near;
  // 1/4: clear old
  // 1/4: init new
  // 1/2: fill new

  enum ACT : char {
    CLEAR, BIGGER, SMALLER, FILL, SWAP, RELAX
  };

  // how much time you have to do this
  pair<ACT, size_t> get_act_help() const {
    if (near.size < near.capacity/8) return make_pair(SWAP, 1);
    if (near.size < 3*(near.capacity/16)) return make_pair(FILL, near.size - near.capacity/8);
    if (near.size < 7*(near.capacity/32)) return make_pair(SMALLER, near.size - 3*(near.capacity/16));
    if (near.size < near.capacity/4) return make_pair(CLEAR, near.size - 7*(near.capacity/32));
    if (near.size < 5*(near.capacity/16)) return make_pair(CLEAR, 5*(near.capacity/16) - near.size);
    if (near.size < 3*(near.capacity/8)) return make_pair(BIGGER, 3*(near.capacity/8) - near.size);
    if (near.size < near.capacity/2) return make_pair(FILL, near.capacity/2 - near.size);
    return make_pair(SWAP, 1);
  }

  pair<ACT, size_t> get_act() const {
    if ((near.capacity <= 32) and (near.size < 7)) return make_pair(RELAX, 0);
    return get_act_help();
  }

  void erase(const Key& k) {
    vector<pair<Key *, pair<size_t, size_t> > >  moved_back = near.erase(k);
    const auto act = get_act();
    switch (act.first) {
    case RELAX:
      break;
    case CLEAR:
      far.clear(act.second);
      break;
    case BIGGER:
      if (far.capacity <= near.capacity) far.reset(near.capacity*2);
      far.init(act.second);
      break;
    case SMALLER:
      if (far.capacity >= near.capacity) far.reset(near.capacity/2);
      far.init(act.second);
      break;
    case FILL:
      far.fill(act.second, near);
      far.erase(k);
      far.catch_up(moved_back);
      break;
    default: // SWAP
      far.swap(near);
      far.erase(k);
    }
  }

  bool insert(const Key& k) {
    const bool ans = near.insert(k);
    const auto act = get_act();
    switch (act.first) {
    case RELAX:
      break;
    case CLEAR:
      far.clear(act.second);
      break;
    case BIGGER:
      if (far.capacity <= near.capacity) far.reset(near.capacity*2);
      far.init(act.second);
      break;
    case SMALLER:
      if (far.capacity >= near.capacity) far.reset(near.capacity/2);
      far.init(act.second);
      break;
    case FILL:
      far.fill(act.second, near);
      far.insert(k);
      break;
    default: // SWAP
      far.swap(near);
      near.insert(k);
    }
    return ans;
  }
};

#endif // LINEAR_HASH_SET
<commit_msg>an empty hash table is in all states at once<commit_after>#ifndef DEAMORTIZED_HASH_SET
#define DEAMORTIZED_HASH_SET

#include <cstdint>
#include <functional>
#include <cstdlib>
#include <cassert>
#include <cstddef>
#include <memory>
#include <vector>

using std::vector;
using std::pair;
using std::make_pair;

#include "tlsf_allocator.hpp"

template<typename Key,
         typename Hash = std::hash<Key>,
         typename Equal = std::equal_to<Key>,
         typename Allocate = TlsfAllocator<Key> >
class LimitedHashSet {
  typedef std::size_t size_t;
public:

  LimitedHashSet& operator=(const LimitedHashSet&) = delete;
  LimitedHashSet(const LimitedHashSet&) = delete;
  LimitedHashSet(LimitedHashSet&&) = delete;
  LimitedHashSet& operator=(LimitedHashSet&&) = delete;

public:

  struct Slot {
    bool occupied;
    Key key;
  };
  Hash hasher;
  Equal equaler;
  typedef typename Allocate::template rebind<Slot>::other A;
  A allocator;
  size_t capacity, size;
  Slot * data;
  size_t progress;
  enum ACT : char {
    CLEAR, INIT, RESET, FILL
  } state;

public:

  // TODO: overload for std::swap
  // TODO: copy and move and assignment constructors
  void swap(LimitedHashSet & that) {
    std::swap(allocator, that.allocator);
    std::swap(capacity, that.capacity);
    std::swap(size, that.size);
    std::swap(data, that.data);
    std::swap(progress, that.progress);
    std::swap(state, that.state);
  }

  explicit LimitedHashSet(const Allocate& a, const size_t capacity)
    : hasher(), equaler(), allocator(a), capacity(capacity), size(0),
      data(allocator.allocate(capacity)), progress(0), state(INIT)
  {}

  // TODO: this need to take state into account
  ~LimitedHashSet() {
    switch (state) {
    case CLEAR:
      while (progress < capacity) {
        allocator.destroy(&data[progress++]);
      }
      break;
    case INIT: // no data - still initializing
      break;
    case RESET: // no data - not even initialized yet
      break;
    case FILL:
      for (size_t i = 0; i < capacity; ++i) {
        if (data[i].occupied) {
          allocator.destroy(&data[i]);
        }
      }
    }
    allocator.deallocate(data, capacity);
  }

  void clear(const size_t left) {
    assert ((0 == capacity) || (state == FILL) || (state == CLEAR));
    if (state == FILL) {
      progress = 0;
    }
    state = CLEAR;
    const size_t many = (capacity - progress + left - 1)/left;
    for (size_t i = 0; i < many; ++i) {
      allocator.destroy(&data[progress]);
      ++progress;
    }
  }

  void init(const size_t left) {
    assert ((0 == capacity) || (state == RESET) || (state == INIT));
    if (RESET == state) {
      progress = 0;
    }
    state = INIT;
    const size_t many = (capacity - progress + left - 1)/left;
    for (size_t i = 0; i < many; ++i) {
      data[progress].occupied = false;
      ++progress;
    }
  }

  void reset(const size_t new_capacity) {
    assert ((0 == capacity) || (state == CLEAR));
    state = RESET;
    size = 0;
    allocator.deallocate(data, capacity);
    capacity = new_capacity;
    data = allocator.allocate(capacity);
    progress = 0;
  }

  void fill(const size_t left, const LimitedHashSet& that) {
    assert ((0 == capacity) || (state == FILL) || (state == INIT));
    if (INIT == state) {
      progress = 0;
    }
    state = FILL;
    // don't care about *my* progress
    const size_t many = (that.capacity - progress + left - 1)/left;
    for (size_t i = 0; i < many; ++i) {
      insert(that.data[progress].key);
      ++progress;
    }
  }

  void catch_up(const vector<pair<Key *, pair<size_t, size_t> > > & moved_back) {
    for (const auto & kft : moved_back) {
      if ((kft.second.first >= progress)
          and (kft.second.second < progress)) {
        insert(kft.first);
      }
    }
  }

private:

  // find a key. capacity must be > 0. if key is not present, returns
  // location where it would be if it were newly placed.
  size_t locate(const Key& k) const {
    const size_t cap_mask = capacity-1;
    auto h = hasher(k) & cap_mask;
    while (true) {
      if (not data[h].occupied)    return h;
      if (equaler(data[h].key, k)) return h;
      h = (h+1) & cap_mask;
    }
  }

  // i < j <= k, mod capacity
  static bool cyclic_between(const size_t& i, const size_t& j, const size_t& k) {
    return (((i < j) and (j <= k))
            or ((i < j) and (k < i))
            or ((j <= k) and (k < i)));
  }

public:
  Key* find(const Key& k) {
    if (NULL == data) return nullptr;
    const size_t i = locate(k);
    if (data[i].occupied && equaler(data[i].key, k)) {
      return &data[i].key;
    }
    return nullptr;
  }

public:

  vector<pair<Key *, pair<size_t, size_t> > > erase(const Key& k) {
    vector<pair<Key *, pair<size_t, size_t> > > ans;
    const size_t cap_mask = capacity-1;
    size_t start = locate(k); // the empty location
    if (not data[start].occupied) return;
    data[start].occupied = false;
    data[start].key.~Key();
    --size;
    size_t i = (start + 1) & cap_mask;
    while (data[i].occupied) {
      const size_t h = hasher(data[i].key) & cap_mask;
      if (not cyclic_between(start,h,i)) {
        data[start].occupied = true;
        new (&data[start].key) Key(std::move(data[i].key));
        start = i;
        data[i].occupied = false;
        ans.push_back(make_pair(&data[start].key, make_pair(i, start)));
        //data[i].key.~Key(); // no : already moved it?
      }
      i = (i+1) & cap_mask;
    }
  }

  bool insert(const Key& k) {
    const size_t i = locate(k);
    if (data[i].occupied) return false;
    new (&data[i].key) Key(k);
    ++size;
    return true;
  }

};

// IDEA: store hash values, ones means "empty"

template<typename Key,
         typename Hash = std::hash<Key>,
         typename Equal = std::equal_to<Key>,
         typename Allocate = TlsfAllocator<Key> >
struct DeamortizedHashSet {

  DeamortizedHashSet() :
    allocator(), far(allocator,0), near(allocator,32) {
    near.init(1);
  }

  Allocate allocator;
  LimitedHashSet<Key, Hash, Equal, Allocate> far, near;
  // 1/4: clear old
  // 1/4: init new
  // 1/2: fill new

  enum ACT : char {
    CLEAR, BIGGER, SMALLER, FILL, SWAP, RELAX
  };

  // how much time you have to do this
  pair<ACT, size_t> get_act_help() const {
    if (near.size < near.capacity/8) return make_pair(SWAP, 1);
    if (near.size < 3*(near.capacity/16)) return make_pair(FILL, near.size - near.capacity/8);
    if (near.size < 7*(near.capacity/32)) return make_pair(SMALLER, near.size - 3*(near.capacity/16));
    if (near.size < near.capacity/4) return make_pair(CLEAR, near.size - 7*(near.capacity/32));
    if (near.size < 5*(near.capacity/16)) return make_pair(CLEAR, 5*(near.capacity/16) - near.size);
    if (near.size < 3*(near.capacity/8)) return make_pair(BIGGER, 3*(near.capacity/8) - near.size);
    if (near.size < near.capacity/2) return make_pair(FILL, near.capacity/2 - near.size);
    return make_pair(SWAP, 1);
  }

  pair<ACT, size_t> get_act() const {
    if ((near.capacity <= 32) and (near.size < 7)) return make_pair(RELAX, 0);
    return get_act_help();
  }

  void erase(const Key& k) {
    vector<pair<Key *, pair<size_t, size_t> > >  moved_back = near.erase(k);
    const auto act = get_act();
    switch (act.first) {
    case RELAX:
      break;
    case CLEAR:
      far.clear(act.second);
      break;
    case BIGGER:
      if (far.capacity <= near.capacity) far.reset(near.capacity*2);
      far.init(act.second);
      break;
    case SMALLER:
      if (far.capacity >= near.capacity) far.reset(near.capacity/2);
      far.init(act.second);
      break;
    case FILL:
      far.fill(act.second, near);
      far.erase(k);
      far.catch_up(moved_back);
      break;
    default: // SWAP
      far.swap(near);
      far.erase(k);
    }
  }

  bool insert(const Key& k) {
    const bool ans = near.insert(k);
    const auto act = get_act();
    switch (act.first) {
    case RELAX:
      break;
    case CLEAR:
      far.clear(act.second);
      break;
    case BIGGER:
      if (far.capacity <= near.capacity) far.reset(near.capacity*2);
      far.init(act.second);
      break;
    case SMALLER:
      if (far.capacity >= near.capacity) far.reset(near.capacity/2);
      far.init(act.second);
      break;
    case FILL:
      far.fill(act.second, near);
      far.insert(k);
      break;
    default: // SWAP
      far.swap(near);
      near.insert(k);
    }
    return ans;
  }
};

#endif // LINEAR_HASH_SET
<|endoftext|>


<commit_before><commit_msg>Planning: considered path reference as invalid when its length of stitching is too short.<commit_after><|endoftext|>


<commit_before>#ifndef LIGHTGBM_IO_DENSE_NBITS_BIN_HPP_
#define LIGHTGBM_IO_DENSE_NBITS_BIN_HPP_

#include <LightGBM/bin.h>

#include <vector>
#include <cstring>
#include <cstdint>

namespace LightGBM {

class Dense4bitsBin;

class Dense4bitsBinIterator: public BinIterator {
public:
  explicit Dense4bitsBinIterator(const Dense4bitsBin* bin_data, uint32_t min_bin, uint32_t max_bin, uint32_t default_bin)
    : bin_data_(bin_data), min_bin_(static_cast<uint8_t>(min_bin)),
    max_bin_(static_cast<uint8_t>(max_bin)),
    default_bin_(static_cast<uint8_t>(default_bin)) {
    if (default_bin_ == 0) {
      bias_ = 1;
    } else {
      bias_ = 0;
    }
  }
  inline uint32_t Get(data_size_t idx) override;
  inline void Reset(data_size_t) override { }
private:
  const Dense4bitsBin* bin_data_;
  uint8_t min_bin_;
  uint8_t max_bin_;
  uint8_t default_bin_;
  uint8_t bias_;
};

class Dense4bitsBin: public Bin {
public:
  friend Dense4bitsBinIterator;
  Dense4bitsBin(data_size_t num_data)
    : num_data_(num_data) {
    int len = (num_data_ + 1) / 2;
    data_ = std::vector<uint8_t>(len, static_cast<uint8_t>(0));
  }

  ~Dense4bitsBin() {

  }

  void Push(int, data_size_t idx, uint32_t value) override {
    if (buf_.empty()) {
#pragma omp critical
      {
        if (buf_.empty()) {
          int len = (num_data_ + 1) / 2;
          buf_ = std::vector<uint8_t>(len, static_cast<uint8_t>(0));
        }
      }
    }
    const int i1 = idx >> 1;
    const int i2 = (idx & 1) << 2;
    const uint8_t val = static_cast<uint8_t>(value) << i2;
    if (i2 == 0) {
      data_[i1] = val;
    } else {
      buf_[i1] = val;
    }
  }

  void ReSize(data_size_t num_data) override {
    if (num_data_ != num_data) {
      num_data_ = num_data;
      int len = (num_data_ + 1) / 2;
      data_.resize(len);
    }
  }

  BinIterator* GetIterator(uint32_t min_bin, uint32_t max_bin, uint32_t default_bin) const override;

  void ConstructHistogram(const data_size_t* data_indices, data_size_t num_data,
    const score_t* ordered_gradients, const score_t* ordered_hessians,
    HistogramBinEntry* out) const override {
    if (data_indices != nullptr) {  // if use part of data

      const data_size_t rest = num_data & 0x3;
      data_size_t i = 0;

      for (; i < num_data - rest; i += 4) {

        data_size_t idx = data_indices[i];
        const auto bin0 = (data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;

        idx = data_indices[i + 1];
        const auto bin1 = (data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;

        idx = data_indices[i + 2];
        const auto bin2 = (data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;

        idx = data_indices[i + 3];
        const auto bin3 = (data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;

        out[bin0].sum_gradients += ordered_gradients[i];
        out[bin1].sum_gradients += ordered_gradients[i + 1];
        out[bin2].sum_gradients += ordered_gradients[i + 2];
        out[bin3].sum_gradients += ordered_gradients[i + 3];

        out[bin0].sum_hessians += ordered_hessians[i];
        out[bin1].sum_hessians += ordered_hessians[i + 1];
        out[bin2].sum_hessians += ordered_hessians[i + 2];
        out[bin3].sum_hessians += ordered_hessians[i + 3];

        ++out[bin0].cnt;
        ++out[bin1].cnt;
        ++out[bin2].cnt;
        ++out[bin3].cnt;

      }

      for (; i < num_data; ++i) {
        const data_size_t idx = data_indices[i];
        const auto bin = (data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;
        out[bin].sum_gradients += ordered_gradients[i];
        out[bin].sum_hessians += ordered_hessians[i];
        ++out[bin].cnt;
      }
    } else {  // use full data
      const data_size_t rest = num_data & 0x3;
      data_size_t i = 0;
      for (; i < num_data - rest; i += 4) {
        int j = i >> 1;
        const auto bin0 = (data_[j]) & 0xf;
        const auto bin1 = (data_[j] >> 4) & 0xf;
        ++j;
        const auto bin2 = (data_[j]) & 0xf;
        const auto bin3 = (data_[j] >> 4) & 0xf;

        out[bin0].sum_gradients += ordered_gradients[i];
        out[bin1].sum_gradients += ordered_gradients[i + 1];
        out[bin2].sum_gradients += ordered_gradients[i + 2];
        out[bin3].sum_gradients += ordered_gradients[i + 3];

        out[bin0].sum_hessians += ordered_hessians[i];
        out[bin1].sum_hessians += ordered_hessians[i + 1];
        out[bin2].sum_hessians += ordered_hessians[i + 2];
        out[bin3].sum_hessians += ordered_hessians[i + 3];

        ++out[bin0].cnt;
        ++out[bin1].cnt;
        ++out[bin2].cnt;
        ++out[bin3].cnt;
      }
      for (; i < num_data; ++i) {
        const auto bin = (data_[i >> 1] >> ((i & 1) << 2)) & 0xf;
        out[bin].sum_gradients += ordered_gradients[i];
        out[bin].sum_hessians += ordered_hessians[i];
        ++out[bin].cnt;
      }
    }
  }

  virtual data_size_t Split(
    uint32_t min_bin, uint32_t max_bin, uint32_t default_bin,
    uint32_t threshold, data_size_t* data_indices, data_size_t num_data,
    data_size_t* lte_indices, data_size_t* gt_indices) const override {
    if (num_data <= 0) { return 0; }
    uint8_t th = static_cast<uint8_t>(threshold + min_bin);
    uint8_t minb = static_cast<uint8_t>(min_bin);
    uint8_t maxb = static_cast<uint8_t>(max_bin);
    if (default_bin == 0) {
      th -= 1;
    }
    data_size_t lte_count = 0;
    data_size_t gt_count = 0;
    data_size_t* default_indices = gt_indices;
    data_size_t* default_count = &gt_count;
    if (default_bin <= threshold) {
      default_indices = lte_indices;
      default_count = &lte_count;
    }
    for (data_size_t i = 0; i < num_data; ++i) {
      const data_size_t idx = data_indices[i];
      const auto bin = (data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;
      if (bin > maxb || bin < minb) {
        default_indices[(*default_count)++] = idx;
      } else if (bin > th) {
        gt_indices[gt_count++] = idx;
      } else {
        lte_indices[lte_count++] = idx;
      }
    }
    return lte_count;
  }
  data_size_t num_data() const override { return num_data_; }

  /*! \brief not ordered bin for dense feature */
  OrderedBin* CreateOrderedBin() const override { return nullptr; }

  void FinishLoad() override {
    int len = (num_data_ + 1) / 2;
    for (int i = 0; i < len; ++i) {
      data_[i] |= buf_[i];
    }
    buf_.clear();
  }

  void LoadFromMemory(const void* memory, const std::vector<data_size_t>& local_used_indices) override {
    const uint8_t* mem_data = reinterpret_cast<const uint8_t*>(memory);
    if (!local_used_indices.empty()) {
      for (int i = 0; i < num_data_; i += 2) {
        // get old bins
        data_size_t idx = local_used_indices[i];
        const auto bin1 = static_cast<uint8_t>((mem_data[idx >> 1] >> ((idx & 1) << 2)) & 0xf);
        idx = local_used_indices[i + 1];
        const auto bin2 = static_cast<uint8_t>((mem_data[idx >> 1] >> ((idx & 1) << 2)) & 0xf);
        // add
        const int i1 = i >> 1;
        data_[i1] = (bin1 | (bin2 << 4));
      }
      if ((num_data_ & 1) == 1) {
        data_size_t idx = local_used_indices[num_data_ - 1];
        data_[num_data_ / 2 + 1] = (mem_data[idx >> 1] >> ((idx & 1) << 2)) & 0xf;
      }
    } else {
      for (size_t i = 0; i < data_.size(); ++i) {
        data_[i] = mem_data[i];
      }
    }
  }

  void CopySubset(const Bin* full_bin, const data_size_t* used_indices, data_size_t num_used_indices) override {
    auto other_bin = reinterpret_cast<const Dense4bitsBin*>(full_bin);
    for (int i = 0; i < num_used_indices; i += 2) {
      data_size_t idx = used_indices[i];
      const auto bin1 = static_cast<uint8_t>((other_bin->data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf);
      idx = used_indices[i + 1];
      const auto bin2 = static_cast<uint8_t>((other_bin->data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf);
      const int i1 = i >> 1;
      data_[i1] = (bin1 | (bin2 << 4));
    }
    if ((num_used_indices & 1) == 1) {
      data_size_t idx = used_indices[num_used_indices - 1];
      data_[num_used_indices / 2 + 1] = (other_bin->data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;
    }
  }

  void SaveBinaryToFile(FILE* file) const override {
    fwrite(data_.data(), sizeof(uint8_t), data_.size(), file);
  }

  size_t SizesInByte() const override {
    return sizeof(uint8_t) * data_.size();
  }

protected:
  data_size_t num_data_;
  std::vector<uint8_t> data_;
  std::vector<uint8_t> buf_;
};

uint32_t Dense4bitsBinIterator::Get(data_size_t idx) {
  const auto bin = (bin_data_->data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;
  if (bin >= min_bin_ && bin <= max_bin_) {
    return bin - min_bin_ + bias_;
  } else {
    return default_bin_;
  }
}

BinIterator* Dense4bitsBin::GetIterator(uint32_t min_bin, uint32_t max_bin, uint32_t default_bin) const {
  return new Dense4bitsBinIterator(this, min_bin, max_bin, default_bin);
}

}  // namespace LightGBM
#endif   // LIGHTGBM_IO_DENSE_NBITS_BIN_HPP_
<commit_msg>fix index out of range bug.<commit_after>#ifndef LIGHTGBM_IO_DENSE_NBITS_BIN_HPP_
#define LIGHTGBM_IO_DENSE_NBITS_BIN_HPP_

#include <LightGBM/bin.h>

#include <vector>
#include <cstring>
#include <cstdint>

namespace LightGBM {

class Dense4bitsBin;

class Dense4bitsBinIterator: public BinIterator {
public:
  explicit Dense4bitsBinIterator(const Dense4bitsBin* bin_data, uint32_t min_bin, uint32_t max_bin, uint32_t default_bin)
    : bin_data_(bin_data), min_bin_(static_cast<uint8_t>(min_bin)),
    max_bin_(static_cast<uint8_t>(max_bin)),
    default_bin_(static_cast<uint8_t>(default_bin)) {
    if (default_bin_ == 0) {
      bias_ = 1;
    } else {
      bias_ = 0;
    }
  }
  inline uint32_t Get(data_size_t idx) override;
  inline void Reset(data_size_t) override { }
private:
  const Dense4bitsBin* bin_data_;
  uint8_t min_bin_;
  uint8_t max_bin_;
  uint8_t default_bin_;
  uint8_t bias_;
};

class Dense4bitsBin: public Bin {
public:
  friend Dense4bitsBinIterator;
  Dense4bitsBin(data_size_t num_data)
    : num_data_(num_data) {
    int len = (num_data_ + 1) / 2;
    data_ = std::vector<uint8_t>(len, static_cast<uint8_t>(0));
  }

  ~Dense4bitsBin() {

  }

  void Push(int, data_size_t idx, uint32_t value) override {
    if (buf_.empty()) {
#pragma omp critical
      {
        if (buf_.empty()) {
          int len = (num_data_ + 1) / 2;
          buf_ = std::vector<uint8_t>(len, static_cast<uint8_t>(0));
        }
      }
    }
    const int i1 = idx >> 1;
    const int i2 = (idx & 1) << 2;
    const uint8_t val = static_cast<uint8_t>(value) << i2;
    if (i2 == 0) {
      data_[i1] = val;
    } else {
      buf_[i1] = val;
    }
  }

  void ReSize(data_size_t num_data) override {
    if (num_data_ != num_data) {
      num_data_ = num_data;
      int len = (num_data_ + 1) / 2;
      data_.resize(len);
    }
  }

  BinIterator* GetIterator(uint32_t min_bin, uint32_t max_bin, uint32_t default_bin) const override;

  void ConstructHistogram(const data_size_t* data_indices, data_size_t num_data,
    const score_t* ordered_gradients, const score_t* ordered_hessians,
    HistogramBinEntry* out) const override {
    if (data_indices != nullptr) {  // if use part of data

      const data_size_t rest = num_data & 0x3;
      data_size_t i = 0;

      for (; i < num_data - rest; i += 4) {

        data_size_t idx = data_indices[i];
        const auto bin0 = (data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;

        idx = data_indices[i + 1];
        const auto bin1 = (data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;

        idx = data_indices[i + 2];
        const auto bin2 = (data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;

        idx = data_indices[i + 3];
        const auto bin3 = (data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;

        out[bin0].sum_gradients += ordered_gradients[i];
        out[bin1].sum_gradients += ordered_gradients[i + 1];
        out[bin2].sum_gradients += ordered_gradients[i + 2];
        out[bin3].sum_gradients += ordered_gradients[i + 3];

        out[bin0].sum_hessians += ordered_hessians[i];
        out[bin1].sum_hessians += ordered_hessians[i + 1];
        out[bin2].sum_hessians += ordered_hessians[i + 2];
        out[bin3].sum_hessians += ordered_hessians[i + 3];

        ++out[bin0].cnt;
        ++out[bin1].cnt;
        ++out[bin2].cnt;
        ++out[bin3].cnt;

      }

      for (; i < num_data; ++i) {
        const data_size_t idx = data_indices[i];
        const auto bin = (data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;
        out[bin].sum_gradients += ordered_gradients[i];
        out[bin].sum_hessians += ordered_hessians[i];
        ++out[bin].cnt;
      }
    } else {  // use full data
      const data_size_t rest = num_data & 0x3;
      data_size_t i = 0;
      for (; i < num_data - rest; i += 4) {
        int j = i >> 1;
        const auto bin0 = (data_[j]) & 0xf;
        const auto bin1 = (data_[j] >> 4) & 0xf;
        ++j;
        const auto bin2 = (data_[j]) & 0xf;
        const auto bin3 = (data_[j] >> 4) & 0xf;

        out[bin0].sum_gradients += ordered_gradients[i];
        out[bin1].sum_gradients += ordered_gradients[i + 1];
        out[bin2].sum_gradients += ordered_gradients[i + 2];
        out[bin3].sum_gradients += ordered_gradients[i + 3];

        out[bin0].sum_hessians += ordered_hessians[i];
        out[bin1].sum_hessians += ordered_hessians[i + 1];
        out[bin2].sum_hessians += ordered_hessians[i + 2];
        out[bin3].sum_hessians += ordered_hessians[i + 3];

        ++out[bin0].cnt;
        ++out[bin1].cnt;
        ++out[bin2].cnt;
        ++out[bin3].cnt;
      }
      for (; i < num_data; ++i) {
        const auto bin = (data_[i >> 1] >> ((i & 1) << 2)) & 0xf;
        out[bin].sum_gradients += ordered_gradients[i];
        out[bin].sum_hessians += ordered_hessians[i];
        ++out[bin].cnt;
      }
    }
  }

  virtual data_size_t Split(
    uint32_t min_bin, uint32_t max_bin, uint32_t default_bin,
    uint32_t threshold, data_size_t* data_indices, data_size_t num_data,
    data_size_t* lte_indices, data_size_t* gt_indices) const override {
    if (num_data <= 0) { return 0; }
    uint8_t th = static_cast<uint8_t>(threshold + min_bin);
    uint8_t minb = static_cast<uint8_t>(min_bin);
    uint8_t maxb = static_cast<uint8_t>(max_bin);
    if (default_bin == 0) {
      th -= 1;
    }
    data_size_t lte_count = 0;
    data_size_t gt_count = 0;
    data_size_t* default_indices = gt_indices;
    data_size_t* default_count = &gt_count;
    if (default_bin <= threshold) {
      default_indices = lte_indices;
      default_count = &lte_count;
    }
    for (data_size_t i = 0; i < num_data; ++i) {
      const data_size_t idx = data_indices[i];
      const auto bin = (data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;
      if (bin > maxb || bin < minb) {
        default_indices[(*default_count)++] = idx;
      } else if (bin > th) {
        gt_indices[gt_count++] = idx;
      } else {
        lte_indices[lte_count++] = idx;
      }
    }
    return lte_count;
  }
  data_size_t num_data() const override { return num_data_; }

  /*! \brief not ordered bin for dense feature */
  OrderedBin* CreateOrderedBin() const override { return nullptr; }

  void FinishLoad() override {
    int len = (num_data_ + 1) / 2;
    for (int i = 0; i < len; ++i) {
      data_[i] |= buf_[i];
    }
    buf_.clear();
  }

  void LoadFromMemory(const void* memory, const std::vector<data_size_t>& local_used_indices) override {
    const uint8_t* mem_data = reinterpret_cast<const uint8_t*>(memory);
    if (!local_used_indices.empty()) {
      const data_size_t rest = num_data_ & 1;
      for (int i = 0; i < num_data_ - rest; i += 2) {
        // get old bins
        data_size_t idx = local_used_indices[i];
        const auto bin1 = static_cast<uint8_t>((mem_data[idx >> 1] >> ((idx & 1) << 2)) & 0xf);
        idx = local_used_indices[i + 1];
        const auto bin2 = static_cast<uint8_t>((mem_data[idx >> 1] >> ((idx & 1) << 2)) & 0xf);
        // add
        const int i1 = i >> 1;
        data_[i1] = (bin1 | (bin2 << 4));
      }
      if (rest) {
        data_size_t idx = local_used_indices[num_data_ - 1];
        data_[num_data_ / 2 + 1] = (mem_data[idx >> 1] >> ((idx & 1) << 2)) & 0xf;
      }
    } else {
      for (size_t i = 0; i < data_.size(); ++i) {
        data_[i] = mem_data[i];
      }
    }
  }

  void CopySubset(const Bin* full_bin, const data_size_t* used_indices, data_size_t num_used_indices) override {
    auto other_bin = reinterpret_cast<const Dense4bitsBin*>(full_bin);
    const data_size_t rest = num_used_indices & 1;
    for (int i = 0; i < num_used_indices - rest; i += 2) {
      data_size_t idx = used_indices[i];
      const auto bin1 = static_cast<uint8_t>((other_bin->data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf);
      idx = used_indices[i + 1];
      const auto bin2 = static_cast<uint8_t>((other_bin->data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf);
      const int i1 = i >> 1;
      data_[i1] = (bin1 | (bin2 << 4));
    }
    if (rest) {
      data_size_t idx = used_indices[num_used_indices - 1];
      data_[num_used_indices / 2 + 1] = (other_bin->data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;
    }
  }

  void SaveBinaryToFile(FILE* file) const override {
    fwrite(data_.data(), sizeof(uint8_t), data_.size(), file);
  }

  size_t SizesInByte() const override {
    return sizeof(uint8_t) * data_.size();
  }

protected:
  data_size_t num_data_;
  std::vector<uint8_t> data_;
  std::vector<uint8_t> buf_;
};

uint32_t Dense4bitsBinIterator::Get(data_size_t idx) {
  const auto bin = (bin_data_->data_[idx >> 1] >> ((idx & 1) << 2)) & 0xf;
  if (bin >= min_bin_ && bin <= max_bin_) {
    return bin - min_bin_ + bias_;
  } else {
    return default_bin_;
  }
}

BinIterator* Dense4bitsBin::GetIterator(uint32_t min_bin, uint32_t max_bin, uint32_t default_bin) const {
  return new Dense4bitsBinIterator(this, min_bin, max_bin, default_bin);
}

}  // namespace LightGBM
#endif   // LIGHTGBM_IO_DENSE_NBITS_BIN_HPP_
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <jni.h>
#include <qi/type/dynamicobjectbuilder.hpp>
#include <qi/property.hpp>
#include <jnitools.hpp>
#include <jobjectconverter.hpp>
#include <object.hpp>
#include <objectbuilder.hpp>

qiLogCategory("qimessaging.jni.test");

int main(int argc, char** argv)
{
  // Avoid making a qi::Application. Real Java apps cannot do it.
  qi::log::addFilter("qimessaging.jni", qi::LogLevel_Debug);
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

class QiJNI: public ::testing::Test
{
protected:
  static void SetUpTestCase()
  {
    JavaVMOption options[1];
    JavaVMInitArgs vm_args;
    long status;

    char classPathDefinition[] = "-Djava.class.path=.";
    options[0].optionString = classPathDefinition;
    memset(&vm_args, 0, sizeof(vm_args));
    vm_args.version = JNI_VERSION_1_6;
    vm_args.nOptions = 1;
    vm_args.options = options;
    status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);

    if (status == JNI_ERR)
      throw std::runtime_error("Failed to set a JVM up");
    jvm->AttachCurrentThread((void**)&env, nullptr);

    // Real Java apps will always call this when loading the library.
    JNI_OnLoad(jvm, nullptr);

    Java_com_aldebaran_qi_EmbeddedTools_initTypeSystem(env, jclass{});
  }

  static void TearDownTestCase()
  {
    if (jvm)
      jvm->DestroyJavaVM();
  }

  static JNIEnv* env;
  static JavaVM* jvm;
};

JNIEnv* QiJNI::env = nullptr;
JavaVM* QiJNI::jvm = nullptr;

template <typename T>
qi::AnyObject makeObjectWithProperty(const std::string& propertyName, qi::Property<T>& property)
{
  qi::DynamicObjectBuilder objectBuilder;
  objectBuilder.advertiseProperty(propertyName, &property);
  return objectBuilder.object();
}

TEST_F(QiJNI, setProperty)
{
  const int initialValue = 12;
  const int newValue = 42;
  qi::Property<int> property{initialValue};

  const std::string propertyName = "serendipity";
  auto object = makeObjectWithProperty(propertyName, property);
  auto objectPtr = &object;

  qi::jni::JNIAttach attach{env};
  auto futureAddress = Java_com_aldebaran_qi_AnyObject_setProperty(
        env, jobject{},
        reinterpret_cast<jlong>(objectPtr),
        qi::jni::toJstring(propertyName),
        JObject_from_AnyValue(qi::AnyValue{newValue}.asReference()));

  auto future = reinterpret_cast<qi::Future<qi::AnyValue>*>(futureAddress);
  auto status = future->waitFor(qi::MilliSeconds{200});
  ASSERT_EQ(qi::FutureState_FinishedWithValue, status);
  ASSERT_EQ(newValue, object.property<int>(propertyName).value());
}

TEST_F(QiJNI, futureErrorIfSetPropertyThrows)
{
  using CustomException = std::exception;
  const int initialValue = 12;
  const int newValue = 42;
  qi::Property<int> property{initialValue, qi::Property<int>::Getter{}, [this](int&, const int&)->bool
  {
    throw CustomException{};
  }};

  const std::string propertyName = "serendipity";
  auto object = makeObjectWithProperty(propertyName, property);
  auto objectPtr = &object;

  qi::jni::JNIAttach attach{env};
  auto futureAddress = Java_com_aldebaran_qi_AnyObject_setProperty(
        env, jobject{},
        reinterpret_cast<jlong>(objectPtr),
        qi::jni::toJstring(propertyName),
        JObject_from_AnyValue(qi::AnyValue{newValue}.asReference()));

  auto future = reinterpret_cast<qi::Future<qi::AnyValue>*>(futureAddress);
  auto status = future->waitFor(qi::MilliSeconds{200});
  ASSERT_EQ(qi::FutureState_FinishedWithError, status);
  ASSERT_EQ(initialValue, object.property<int>(propertyName).value());
}

TEST_F(QiJNI, dynamicObjectBuilderAdvertiseMethodVoidVoid)
{
  // Object.notify() is a typical example of function taking and returning nothing.
  const auto javaObjectClassName = "java/lang/Object";
  const auto javaObjectClass = env->FindClass(javaObjectClassName);
  const auto javaObjectConstructor = env->GetMethodID(javaObjectClass, "<init>", "()V");
  const auto javaObject = env->NewObject(javaObjectClass, javaObjectConstructor);

  // Let's make a Qi Object calling that method.
  const auto objectBuilderAddress = Java_com_aldebaran_qi_DynamicObjectBuilder_create(env, nullptr);
  env->ExceptionClear();
  Java_com_aldebaran_qi_DynamicObjectBuilder_advertiseMethod(
        env, jobject{},
        objectBuilderAddress,
        qi::jni::toJstring("notify::v()"), javaObject, // 'v' stands for "void"
        qi::jni::toJstring(javaObjectClassName),
        qi::jni::toJstring("Whatever"));
  ASSERT_FALSE(env->ExceptionCheck());
}
<commit_msg>jni.tests: Refactors tests by using a global environment instead of a fixture.<commit_after>#include <gtest/gtest.h>
#include <jni.h>
#include <ka/errorhandling.hpp>
#include <qi/type/dynamicobjectbuilder.hpp>
#include <qi/property.hpp>
#include <jnitools.hpp>
#include <jobjectconverter.hpp>
#include <object.hpp>
#include <objectbuilder.hpp>

qiLogCategory("qimessaging.jni.test");

namespace qi { namespace jni { namespace test
{

namespace
{
  /// Procedure<jint()> Proc
  /// OStreamable O
  template<typename Proc, typename O = const char*>
  void assertSuccess(Proc&& p, O&& errorPrefix = {})
  {
    const auto status = std::forward<Proc>(p)();
    if (status != JNI_OK)
      FAIL() << std::forward<O>(errorPrefix) << "Status: " << errorToString(status);
  }
}

class Environment : public ::testing::Environment
{
  void SetUp() override
  {
    JavaVMOption options[1];
    JavaVMInitArgs vm_args;

    char classPathDefinition[] = "-Djava.class.path=.";
    options[0].optionString = classPathDefinition;
    memset(&vm_args, 0, sizeof(vm_args));
    vm_args.version = QI_JNI_MIN_VERSION;
    vm_args.nOptions = 1;
    vm_args.options = options;
    assertSuccess(
      [&]{ return JNI_CreateJavaVM(&javaVM, reinterpret_cast<void**>(&jniEnv), &vm_args); },
      "Failed to create the Java virtual machine.");
    assertSuccess(
      [&]{ return javaVM->AttachCurrentThread(reinterpret_cast<void**>(&jniEnv), nullptr); },
      "Failed to attach current thread.");

    // Real Java apps will always call this when loading the library.
    ASSERT_NO_THROW(EXPECT_EQ(QI_JNI_MIN_VERSION, JNI_OnLoad(javaVM, nullptr)));
    ASSERT_NO_THROW(Java_com_aldebaran_qi_EmbeddedTools_initTypeSystem(jniEnv));
  }

  void TearDown() override
  {
    ASSERT_NO_THROW(JNI_OnUnload(javaVM, nullptr));

    jniEnv = nullptr;
    if (const auto localJavaVM = ka::exchange(javaVM, nullptr))
    {
      assertSuccess([&]{ return localJavaVM->DetachCurrentThread(); },
                    "Failed to detach current thread.");
      assertSuccess([&]{ return localJavaVM->DestroyJavaVM(); },
                    "Failed to destroy the Java virtual machine.");
    }
  }

public:
  JavaVM* javaVM = nullptr;
  JNIEnv* jniEnv = nullptr;
};

Environment* environment = nullptr;

namespace
{

template <typename T>
AnyObject makeObjectWithProperty(const std::string& propertyName, Property<T>& property)
{
  DynamicObjectBuilder objectBuilder;
  objectBuilder.advertiseProperty(propertyName, &property);
  return objectBuilder.object();
}

} // anonymous namespace

}}} // namespace jni::test

using namespace qi;
using namespace qi::jni;

int main(int argc, char** argv)
{
  // Avoid making a qi::Application. Real Java apps cannot do it.
  log::addFilter("qimessaging.jni", LogLevel_Debug);
  ::testing::InitGoogleTest(&argc, argv);
  test::environment =
    static_cast<test::Environment*>(::testing::AddGlobalTestEnvironment(new test::Environment));
  return RUN_ALL_TESTS();
}

TEST(QiJNI, setProperty)
{
  const int initialValue = 12;
  const int newValue = 42;
  Property<int> property{initialValue};

  const std::string propertyName = "serendipity";
  auto object = test::makeObjectWithProperty(propertyName, property);
  auto objectPtr = &object;

  JNIAttach attach{test::environment->jniEnv};
  auto futureAddress = Java_com_aldebaran_qi_AnyObject_setProperty(
        test::environment->jniEnv, jobject{},
        reinterpret_cast<jlong>(objectPtr),
        toJstring(propertyName),
        JObject_from_AnyValue(AnyValue{newValue}.asReference()));

  auto future = reinterpret_cast<Future<AnyValue>*>(futureAddress);
  auto status = future->waitFor(MilliSeconds{200});
  ASSERT_EQ(FutureState_FinishedWithValue, status);
  ASSERT_EQ(newValue, object.property<int>(propertyName).value());
}

TEST(QiJNI, futureErrorIfSetPropertyThrows)
{
  using CustomException = std::exception;
  const int initialValue = 12;
  const int newValue = 42;
  Property<int> property{initialValue, Property<int>::Getter{}, [this](int&, const int&)->bool
  {
    throw CustomException{};
  }};

  const std::string propertyName = "serendipity";
  auto object = test::makeObjectWithProperty(propertyName, property);
  auto objectPtr = &object;

  JNIAttach attach{test::environment->jniEnv};
  auto futureAddress = Java_com_aldebaran_qi_AnyObject_setProperty(
        test::environment->jniEnv, jobject{},
        reinterpret_cast<jlong>(objectPtr),
        toJstring(propertyName),
        JObject_from_AnyValue(AnyValue{newValue}.asReference()));

  auto future = reinterpret_cast<Future<AnyValue>*>(futureAddress);
  auto status = future->wait();
  ASSERT_EQ(FutureState_FinishedWithError, status);
  ASSERT_EQ(initialValue, object.property<int>(propertyName).value());
}

TEST(QiJNI, dynamicObjectBuilderAdvertiseMethodVoidVoid)
{
  // Object.notify() is a typical example of function taking and returning nothing.
  const auto javaObjectClassName = "java/lang/Object";
  const auto javaObjectClass = test::environment->jniEnv->FindClass(javaObjectClassName);
  const auto javaObjectConstructor =
    test::environment->jniEnv->GetMethodID(javaObjectClass, "<init>", "()V");
  const auto javaObject = test::environment->jniEnv->NewObject(javaObjectClass, javaObjectConstructor);

  // Let's make a Qi Object calling that method.
  const auto objectBuilderAddress =
    Java_com_aldebaran_qi_DynamicObjectBuilder_create(test::environment->jniEnv, nullptr);
  test::environment->jniEnv->ExceptionClear();
  Java_com_aldebaran_qi_DynamicObjectBuilder_advertiseMethod(
        test::environment->jniEnv, jobject{},
        objectBuilderAddress,
        toJstring("notify::v()"), javaObject, // 'v' stands for "void"
        toJstring(javaObjectClassName),
        toJstring("Whatever"));
  ASSERT_FALSE(test::environment->jniEnv->ExceptionCheck());
}
<|endoftext|>


<commit_before>#include "perf_precomp.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/opencv_modules.hpp"

using namespace std;
using namespace cv;
using namespace perf;
using std::tr1::tuple;
using std::tr1::get;

#define SURF_MATCH_CONFIDENCE 0.65f
#define ORB_MATCH_CONFIDENCE  0.3f
#define WORK_MEGAPIX 0.6

typedef TestBaseWithParam<string> stitch;
typedef TestBaseWithParam<tuple<string, string> > stitchDatasets;

#ifdef HAVE_OPENCV_XFEATURES2D
#define TEST_DETECTORS testing::Values("surf", "orb")
#else
#define TEST_DETECTORS testing::Values<string>("orb")
#endif
#define AFFINE_DATASETS testing::Values("s", "budapest", "newspaper", "prague")

PERF_TEST_P(stitch, a123, TEST_DETECTORS)
{
    Mat pano;

    vector<Mat> imgs;
    imgs.push_back( imread( getDataPath("stitching/a1.png") ) );
    imgs.push_back( imread( getDataPath("stitching/a2.png") ) );
    imgs.push_back( imread( getDataPath("stitching/a3.png") ) );

    Ptr<detail::FeaturesFinder> featuresFinder = GetParam() == "orb"
            ? Ptr<detail::FeaturesFinder>(new detail::OrbFeaturesFinder())
            : Ptr<detail::FeaturesFinder>(new detail::SurfFeaturesFinder());

    Ptr<detail::FeaturesMatcher> featuresMatcher = GetParam() == "orb"
            ? makePtr<detail::BestOf2NearestMatcher>(false, ORB_MATCH_CONFIDENCE)
            : makePtr<detail::BestOf2NearestMatcher>(false, SURF_MATCH_CONFIDENCE);

    declare.time(30 * 20).iterations(20);

    while(next())
    {
        Stitcher stitcher = Stitcher::createDefault();
        stitcher.setFeaturesFinder(featuresFinder);
        stitcher.setFeaturesMatcher(featuresMatcher);
        stitcher.setWarper(makePtr<SphericalWarper>());
        stitcher.setRegistrationResol(WORK_MEGAPIX);

        startTimer();
        stitcher.stitch(imgs, pano);
        stopTimer();
    }

    EXPECT_NEAR(pano.size().width, 1182, 50);
    EXPECT_NEAR(pano.size().height, 682, 30);

    SANITY_CHECK_NOTHING();
}

PERF_TEST_P(stitch, b12, TEST_DETECTORS)
{
    Mat pano;

    vector<Mat> imgs;
    imgs.push_back( imread( getDataPath("stitching/b1.png") ) );
    imgs.push_back( imread( getDataPath("stitching/b2.png") ) );

    Ptr<detail::FeaturesFinder> featuresFinder = GetParam() == "orb"
            ? Ptr<detail::FeaturesFinder>(new detail::OrbFeaturesFinder())
            : Ptr<detail::FeaturesFinder>(new detail::SurfFeaturesFinder());

    Ptr<detail::FeaturesMatcher> featuresMatcher = GetParam() == "orb"
            ? makePtr<detail::BestOf2NearestMatcher>(false, ORB_MATCH_CONFIDENCE)
            : makePtr<detail::BestOf2NearestMatcher>(false, SURF_MATCH_CONFIDENCE);

    declare.time(30 * 20).iterations(20);

    while(next())
    {
        Stitcher stitcher = Stitcher::createDefault();
        stitcher.setFeaturesFinder(featuresFinder);
        stitcher.setFeaturesMatcher(featuresMatcher);
        stitcher.setWarper(makePtr<SphericalWarper>());
        stitcher.setRegistrationResol(WORK_MEGAPIX);

        startTimer();
        stitcher.stitch(imgs, pano);
        stopTimer();
    }

    EXPECT_NEAR(pano.size().width, 1117, 50);
    EXPECT_NEAR(pano.size().height, 642, 30);

    SANITY_CHECK_NOTHING();
}

PERF_TEST_P(stitchDatasets, affine, testing::Combine(AFFINE_DATASETS, TEST_DETECTORS))
{
    string dataset = get<0>(GetParam());
    string detector = get<1>(GetParam());

    Mat pano;
    vector<Mat> imgs;
    int width, height, allowed_diff = 10;
    Ptr<detail::FeaturesFinder> featuresFinder;

    if(detector == "orb")
        featuresFinder = makePtr<detail::OrbFeaturesFinder>();
    else
        featuresFinder = makePtr<detail::SurfFeaturesFinder>();

    if(dataset == "budapest")
    {
        imgs.push_back(imread(getDataPath("stitching/budapest1.jpg")));
        imgs.push_back(imread(getDataPath("stitching/budapest2.jpg")));
        imgs.push_back(imread(getDataPath("stitching/budapest3.jpg")));
        imgs.push_back(imread(getDataPath("stitching/budapest4.jpg")));
        imgs.push_back(imread(getDataPath("stitching/budapest5.jpg")));
        imgs.push_back(imread(getDataPath("stitching/budapest6.jpg")));
        width = 2313;
        height = 1158;
        // this dataset is big, the results between surf and orb differ slightly,
        // but both are still good
        allowed_diff = 27;
    }
    else if (dataset == "newspaper")
    {
        imgs.push_back(imread(getDataPath("stitching/newspaper1.jpg")));
        imgs.push_back(imread(getDataPath("stitching/newspaper2.jpg")));
        imgs.push_back(imread(getDataPath("stitching/newspaper3.jpg")));
        imgs.push_back(imread(getDataPath("stitching/newspaper4.jpg")));
        width = 1791;
        height = 1136;
        // we need to boost ORB number of features to be able to stitch this dataset
        // SURF works just fine with default settings
        if(detector == "orb")
            featuresFinder = makePtr<detail::OrbFeaturesFinder>(Size(3,1), 3000);
    }
    else if (dataset == "prague")
    {
        imgs.push_back(imread(getDataPath("stitching/prague1.jpg")));
        imgs.push_back(imread(getDataPath("stitching/prague2.jpg")));
        width = 983;
        height = 1759;
    }
    else // dataset == "s"
    {
        imgs.push_back(imread(getDataPath("stitching/s1.jpg")));
        imgs.push_back(imread(getDataPath("stitching/s2.jpg")));
        width = 1815;
        height = 700;
    }

    declare.time(30 * 20).iterations(20);

    while(next())
    {
        Ptr<Stitcher> stitcher = Stitcher::create(Stitcher::SCANS, false);
        stitcher->setFeaturesFinder(featuresFinder);

        startTimer();
        stitcher->stitch(imgs, pano);
        stopTimer();
    }

    EXPECT_NEAR(pano.size().width, width, allowed_diff);
    EXPECT_NEAR(pano.size().height, height, allowed_diff);

    SANITY_CHECK_NOTHING();
}
<commit_msg>stitching(perf): workaround test failures<commit_after>#include "perf_precomp.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/opencv_modules.hpp"

#include "opencv2/core/ocl.hpp"

using namespace std;
using namespace cv;
using namespace perf;
using std::tr1::tuple;
using std::tr1::get;

#define SURF_MATCH_CONFIDENCE 0.65f
#define ORB_MATCH_CONFIDENCE  0.3f
#define WORK_MEGAPIX 0.6

typedef TestBaseWithParam<string> stitch;
typedef TestBaseWithParam<tuple<string, string> > stitchDatasets;

#ifdef HAVE_OPENCV_XFEATURES2D
#define TEST_DETECTORS testing::Values("surf", "orb")
#else
#define TEST_DETECTORS testing::Values<string>("orb")
#endif
#define AFFINE_DATASETS testing::Values("s", "budapest", "newspaper", "prague")

PERF_TEST_P(stitch, a123, TEST_DETECTORS)
{
    Mat pano;

    vector<Mat> imgs;
    imgs.push_back( imread( getDataPath("stitching/a1.png") ) );
    imgs.push_back( imread( getDataPath("stitching/a2.png") ) );
    imgs.push_back( imread( getDataPath("stitching/a3.png") ) );

    Ptr<detail::FeaturesFinder> featuresFinder = GetParam() == "orb"
            ? Ptr<detail::FeaturesFinder>(new detail::OrbFeaturesFinder())
            : Ptr<detail::FeaturesFinder>(new detail::SurfFeaturesFinder());

    Ptr<detail::FeaturesMatcher> featuresMatcher = GetParam() == "orb"
            ? makePtr<detail::BestOf2NearestMatcher>(false, ORB_MATCH_CONFIDENCE)
            : makePtr<detail::BestOf2NearestMatcher>(false, SURF_MATCH_CONFIDENCE);

    declare.time(30 * 20).iterations(20);

    while(next())
    {
        Stitcher stitcher = Stitcher::createDefault();
        stitcher.setFeaturesFinder(featuresFinder);
        stitcher.setFeaturesMatcher(featuresMatcher);
        stitcher.setWarper(makePtr<SphericalWarper>());
        stitcher.setRegistrationResol(WORK_MEGAPIX);

        startTimer();
        stitcher.stitch(imgs, pano);
        stopTimer();
    }

    EXPECT_NEAR(pano.size().width, 1182, 50);
    EXPECT_NEAR(pano.size().height, 682, 30);

    SANITY_CHECK_NOTHING();
}

PERF_TEST_P(stitch, b12, TEST_DETECTORS)
{
    Mat pano;

    vector<Mat> imgs;
    imgs.push_back( imread( getDataPath("stitching/b1.png") ) );
    imgs.push_back( imread( getDataPath("stitching/b2.png") ) );

    Ptr<detail::FeaturesFinder> featuresFinder = GetParam() == "orb"
            ? Ptr<detail::FeaturesFinder>(new detail::OrbFeaturesFinder())
            : Ptr<detail::FeaturesFinder>(new detail::SurfFeaturesFinder());

    Ptr<detail::FeaturesMatcher> featuresMatcher = GetParam() == "orb"
            ? makePtr<detail::BestOf2NearestMatcher>(false, ORB_MATCH_CONFIDENCE)
            : makePtr<detail::BestOf2NearestMatcher>(false, SURF_MATCH_CONFIDENCE);

    declare.time(30 * 20).iterations(20);

    while(next())
    {
        Stitcher stitcher = Stitcher::createDefault();
        stitcher.setFeaturesFinder(featuresFinder);
        stitcher.setFeaturesMatcher(featuresMatcher);
        stitcher.setWarper(makePtr<SphericalWarper>());
        stitcher.setRegistrationResol(WORK_MEGAPIX);

        startTimer();
        stitcher.stitch(imgs, pano);
        stopTimer();
    }

    EXPECT_NEAR(pano.size().width, 1117, 50);
    EXPECT_NEAR(pano.size().height, 642, 30);

    SANITY_CHECK_NOTHING();
}

PERF_TEST_P(stitchDatasets, affine, testing::Combine(AFFINE_DATASETS, TEST_DETECTORS))
{
    string dataset = get<0>(GetParam());
    string detector = get<1>(GetParam());

    Mat pano;
    vector<Mat> imgs;
    int width, height, allowed_diff = 10;
    Ptr<detail::FeaturesFinder> featuresFinder;

    if(detector == "orb")
        featuresFinder = makePtr<detail::OrbFeaturesFinder>();
    else
        featuresFinder = makePtr<detail::SurfFeaturesFinder>();

    if(dataset == "budapest")
    {
        imgs.push_back(imread(getDataPath("stitching/budapest1.jpg")));
        imgs.push_back(imread(getDataPath("stitching/budapest2.jpg")));
        imgs.push_back(imread(getDataPath("stitching/budapest3.jpg")));
        imgs.push_back(imread(getDataPath("stitching/budapest4.jpg")));
        imgs.push_back(imread(getDataPath("stitching/budapest5.jpg")));
        imgs.push_back(imread(getDataPath("stitching/budapest6.jpg")));
        width = 2313;
        height = 1158;
        // this dataset is big, the results between surf and orb differ slightly,
        // but both are still good
        allowed_diff = 27;
    }
    else if (dataset == "newspaper")
    {
        imgs.push_back(imread(getDataPath("stitching/newspaper1.jpg")));
        imgs.push_back(imread(getDataPath("stitching/newspaper2.jpg")));
        imgs.push_back(imread(getDataPath("stitching/newspaper3.jpg")));
        imgs.push_back(imread(getDataPath("stitching/newspaper4.jpg")));
        width = 1791;
        height = 1136;
        // we need to boost ORB number of features to be able to stitch this dataset
        // SURF works just fine with default settings
        if(detector == "orb")
            featuresFinder = makePtr<detail::OrbFeaturesFinder>(Size(3,1), 3000);
    }
    else if (dataset == "prague")
    {
        imgs.push_back(imread(getDataPath("stitching/prague1.jpg")));
        imgs.push_back(imread(getDataPath("stitching/prague2.jpg")));
        width = 983;
        height = 1759;
    }
    else // dataset == "s"
    {
        imgs.push_back(imread(getDataPath("stitching/s1.jpg")));
        imgs.push_back(imread(getDataPath("stitching/s2.jpg")));
        width = 1815;
        height = 700;
    }

    declare.time(30 * 20).iterations(20);

    while(next())
    {
        Ptr<Stitcher> stitcher = Stitcher::create(Stitcher::SCANS, false);
        stitcher->setFeaturesFinder(featuresFinder);

        if (cv::ocl::useOpenCL())
            cv::theRNG() = cv::RNG(12345); // prevent fails of Windows OpenCL builds (see #8294)

        startTimer();
        stitcher->stitch(imgs, pano);
        stopTimer();
    }

    EXPECT_NEAR(pano.size().width, width, allowed_diff);
    EXPECT_NEAR(pano.size().height, height, allowed_diff);

    SANITY_CHECK_NOTHING();
}
<|endoftext|>


<commit_before>#include "jni.h"
#include "zip.h"
#include "ArgConverter.h"
#include "NativeScriptAssert.h"
#include <assert.h>
#include <libgen.h>
#include <time.h>
#include <utime.h>
#include <sys/stat.h>
#include "AssetExtractor.h"

using namespace tns;

std::string jstringToString(JNIEnv *env, jstring value);
void mkdir_rec(const char *dir);

void AssetExtractor::ExtractAssets(JNIEnv *env, jobject obj, jstring apk, jstring outputDir, jboolean _forceOverwrite)
{
	auto forceOverwrite = JNI_TRUE == _forceOverwrite;
	auto strApk = jstringToString(env, apk);
	auto baseDir = jstringToString(env, outputDir);
	int err = 0;
	auto z = zip_open(strApk.c_str(), 0, &err);
	assert(z != nullptr);
	zip_int64_t num = zip_get_num_entries(z, 0);
	struct zip_stat sb;
	struct zip_file *zf;
	char buf[65536];
	auto pathcopy = new char[1024];
	for (zip_int64_t i = 0; i < num; i++)
	{
		zip_stat_index(z, i, ZIP_STAT_MTIME, &sb);
		if (strstr(sb.name, "assets/") == sb.name)
		{
			auto name = sb.name + 7; // strlen("assets/") == 7

			std::string assetFullname(baseDir);
			assetFullname.append(name);

			struct stat attrib;
			auto shouldOverwrite = true;
			int ret = stat(assetFullname.c_str(), &attrib);
			if (ret == 0 /* file exists */)
			{
				auto diff = difftime(sb.mtime, attrib.st_mtime);
				shouldOverwrite = diff > 0;
			}

			if (shouldOverwrite || forceOverwrite)
			{
				//DEBUG_WRITE("write asset %s", assetFullname.c_str());
				strcpy(pathcopy, name);
				auto path = dirname(pathcopy);
				std::string dirFullname(baseDir);
				dirFullname.append(path);
				mkdir_rec(dirFullname.c_str());

				zf = zip_fopen_index(z, i, 0);
				assert(zf != nullptr);

				auto fd = fopen(assetFullname.c_str(), "w");

				zip_int64_t sum = 0;
				while (sum != sb.size)
				{
					zip_int64_t len = zip_fread(zf, buf, sizeof(buf));
					assert(len > 0);

					fwrite(buf, 1, len, fd);
					sum += len;
				}
				fclose(fd);
				utimbuf t;
				t.modtime = sb.mtime;
				ret = utime(assetFullname.c_str(), &t);
				zip_fclose(zf);
			}
		}
	}
	delete[] pathcopy;
	zip_close(z);
}

void AssetExtractor::mkdir_rec(const char *dir)
{
	char opath[256];
	snprintf(opath, sizeof(opath), "%s", dir);
	size_t len = strlen(opath);

	if (opath[len - 1] == '/')
		opath[len - 1] = 0;

	for (char *p = opath + 1; *p; p++)
	{
		if (*p == '/')
		{
			*p = 0;
			mkdir(opath, S_IRWXU);
			*p = '/';
		}
	}

	mkdir(opath, S_IRWXU);
}

std::string AssetExtractor::jstringToString(JNIEnv *env, jstring value)
{
	if (value == nullptr)
	{
		return std::string();
	}

	jboolean f = false;
	const char* chars = env->GetStringUTFChars(value, &f);
	std::string s(chars);
	env->ReleaseStringUTFChars(value, chars);

	return s;
}
<commit_msg>add error handling<commit_after>#include "jni.h"
#include "zip.h"
#include "ArgConverter.h"
#include "NativeScriptAssert.h"
#include <assert.h>
#include <libgen.h>
#include <time.h>
#include <utime.h>
#include <sys/stat.h>
#include "AssetExtractor.h"

using namespace tns;

std::string jstringToString(JNIEnv *env, jstring value);
void mkdir_rec(const char *dir);

void AssetExtractor::ExtractAssets(JNIEnv *env, jobject obj, jstring apk, jstring outputDir, jboolean _forceOverwrite)
{
	auto forceOverwrite = JNI_TRUE == _forceOverwrite;
	auto strApk = jstringToString(env, apk);
	auto baseDir = jstringToString(env, outputDir);
	int err = 0;
	auto z = zip_open(strApk.c_str(), 0, &err);
	assert(z != nullptr);
	zip_int64_t num = zip_get_num_entries(z, 0);
	struct zip_stat sb;
	struct zip_file *zf;
	char buf[65536];
	auto pathcopy = new char[1024];
	for (zip_int64_t i = 0; i < num; i++)
	{
		zip_stat_index(z, i, ZIP_STAT_MTIME, &sb);
		if (strstr(sb.name, "assets/") == sb.name)
		{
			auto name = sb.name + 7; // strlen("assets/") == 7

			std::string assetFullname(baseDir);
			assetFullname.append(name);

			struct stat attrib;
			auto shouldOverwrite = true;
			int ret = stat(assetFullname.c_str(), &attrib);
			if (ret == 0 /* file exists */)
			{
				auto diff = difftime(sb.mtime, attrib.st_mtime);
				shouldOverwrite = diff > 0;
			}

			if (shouldOverwrite || forceOverwrite)
			{
				strcpy(pathcopy, name);
				auto path = dirname(pathcopy);
				std::string dirFullname(baseDir);
				dirFullname.append(path);
				mkdir_rec(dirFullname.c_str());

				zf = zip_fopen_index(z, i, 0);
				assert(zf != nullptr);

				auto fd = fopen(assetFullname.c_str(), "w");

				if (fd != nullptr)
				{
					zip_int64_t sum = 0;
					while (sum != sb.size)
					{
						zip_int64_t len = zip_fread(zf, buf, sizeof(buf));
						assert(len > 0);

						fwrite(buf, 1, len, fd);
						sum += len;
					}
					fclose(fd);
					utimbuf t;
					t.modtime = sb.mtime;
					ret = utime(assetFullname.c_str(), &t);
				}

				zip_fclose(zf);
			}
		}
	}
	delete[] pathcopy;
	zip_close(z);
}

void AssetExtractor::mkdir_rec(const char *dir)
{
	char opath[256];
	snprintf(opath, sizeof(opath), "%s", dir);
	size_t len = strlen(opath);

	if (opath[len - 1] == '/')
		opath[len - 1] = 0;

	for (char *p = opath + 1; *p; p++)
	{
		if (*p == '/')
		{
			*p = 0;
			mkdir(opath, S_IRWXU);
			*p = '/';
		}
	}

	mkdir(opath, S_IRWXU);
}

std::string AssetExtractor::jstringToString(JNIEnv *env, jstring value)
{
	if (value == nullptr)
	{
		return std::string();
	}

	jboolean f = false;
	const char* chars = env->GetStringUTFChars(value, &f);
	std::string s(chars);
	env->ReleaseStringUTFChars(value, chars);

	return s;
}
<|endoftext|>


<commit_before>
#include "journal/player.hpp"

#include <list>
#include <string>
#include <thread>
#include <vector>

#include "benchmark/benchmark.h"
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "journal/method.hpp"
#include "journal/profiles.hpp"
#include "journal/recorder.hpp"
#include "ksp_plugin/interface.hpp"
#include "serialization/journal.pb.h"

namespace principia {
namespace journal {

// The benchmark is only run if --gtest_filter=PlayerTest.Benchmarks
void BM_PlayForReal(benchmark::State& state) {  // NOLINT(runtime/references)
  while (state.KeepRunning()) {
    Player player(
        R"(P:\Public Mockingbird\Principia\Journals\JOURNAL.20160626-143407)");
    int count = 0;
    while (player.Play()) {
      ++count;
      LOG_IF(ERROR, (count % 100'000) == 0)
          << count << " journal entries replayed";
    }
  }
}

BENCHMARK(BM_PlayForReal);

class PlayerTest : public ::testing::Test {
 protected:
  PlayerTest()
      : test_info_(testing::UnitTest::GetInstance()->current_test_info()),
        test_case_name_(test_info_->test_case_name()),
        test_name_(test_info_->name()),
        plugin_(interface::principia__NewPlugin("0 s", "0 s", 0)) {}

  template<typename Profile>
  bool RunIfAppropriate(serialization::Method const& method_in,
                        serialization::Method const& method_out_return,
                        Player& player) {
    return player.RunIfAppropriate<Profile>(method_in, method_out_return);
  }

  ::testing::TestInfo const* const test_info_;
  std::string const test_case_name_;
  std::string const test_name_;
  std::unique_ptr<ksp_plugin::Plugin> plugin_;
};

TEST_F(PlayerTest, PlayTiny) {
  // Do the recording in a separate thread to make sure that it activates using
  // a different static variable than the one in the plugin dynamic library.
  std::thread recorder([this]() {
    Recorder* const r(new Recorder(test_name_ + ".journal.hex"));
    Recorder::Activate(r);

    {
      Method<NewPlugin> m({"1 s", "2 s", 3});
      m.Return(plugin_.get());
    }
    {
      const ksp_plugin::Plugin* plugin = plugin_.get();
      Method<DeletePlugin> m({&plugin}, {&plugin});
      m.Return();
    }
    Recorder::Deactivate();
  });
  recorder.join();

  Player player(test_name_ + ".journal.hex");

  // Replay the journal.
  int count = 0;
  while (player.Play()) {
    ++count;
  }
  EXPECT_EQ(2, count);
}

// This test (a.k.a. benchmark) is only run if the --gtest_filter flag names it
// explicitly.
TEST_F(PlayerTest, Benchmarks) {
  if (testing::FLAGS_gtest_filter == test_case_name_ + "." + test_name_) {
    benchmark::RunSpecifiedBenchmarks();
  }
}

#if 0
// This test is only run if the --gtest_filter flag names it explicitly.
TEST_F(PlayerTest, Debug) {
  if (testing::FLAGS_gtest_filter == test_case_name_ + "." + test_name_) {
    // An example of how journalling may be used for debugging.  You must set
    // |path| and fill the |method_in| and |method_out_return| protocol buffers.
    std::string path =
        R"(C:\Users\robin\Projects\KSP_win64\glog\Principia\JOURNAL.20161226-193328)";
    Player player(path);
    int count = 0;
    while (player.Play()) {
      ++count;
      LOG_IF(ERROR, (count % 100'000) == 0) << count
                                            << " journal entries replayed";
    }
    LOG(ERROR) << count << " journal entries in total";
    LOG(ERROR) << "Last successful method in:\n"
               << player.last_method_in().DebugString();
    LOG(ERROR) << "Last successful method out/return: \n"
               << player.last_method_out_return().DebugString();

#if 0
    serialization::Method method_in;
    auto* extension = method_in.MutableExtension(
        serialization::ReportCollision::extension);
    auto* in = extension->mutable_in();
    in->set_plugin(355375312);
    in->set_vessel1_guid("14b05bd3-9707-4d49-a6be-a7de481f3e0a");
    in->set_vessel2_guid("3e6fcb7e-4761-48ed-829f-0adb035f457e");
    serialization::Method method_out_return;
    method_out_return.MutableExtension(
        serialization::ReportCollision::extension);
    LOG(ERROR) << "Running unpaired method:\n" << method_in.DebugString();
    CHECK(RunIfAppropriate<ReportCollision>(method_in,
                                            method_out_return,
                                            player));
#endif
  }
}
#endif

}  // namespace journal
}  // namespace principia
<commit_msg>journalling is broken<commit_after>
#include "journal/player.hpp"

#include <list>
#include <string>
#include <thread>
#include <vector>

#include "benchmark/benchmark.h"
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "journal/method.hpp"
#include "journal/profiles.hpp"
#include "journal/recorder.hpp"
#include "ksp_plugin/interface.hpp"
#include "serialization/journal.pb.h"

namespace principia {
namespace journal {

// The benchmark is only run if --gtest_filter=PlayerTest.Benchmarks
void BM_PlayForReal(benchmark::State& state) {  // NOLINT(runtime/references)
  while (state.KeepRunning()) {
    Player player(
        R"(P:\Public Mockingbird\Principia\Journals\JOURNAL.20160626-143407)");
    int count = 0;
    while (player.Play()) {
      ++count;
      LOG_IF(ERROR, (count % 100'000) == 0)
          << count << " journal entries replayed";
    }
  }
}

BENCHMARK(BM_PlayForReal);

class PlayerTest : public ::testing::Test {
 protected:
  PlayerTest()
      : test_info_(testing::UnitTest::GetInstance()->current_test_info()),
        test_case_name_(test_info_->test_case_name()),
        test_name_(test_info_->name()),
        plugin_(interface::principia__NewPlugin("0 s", "0 s", 0)) {}

  template<typename Profile>
  bool RunIfAppropriate(serialization::Method const& method_in,
                        serialization::Method const& method_out_return,
                        Player& player) {
    return player.RunIfAppropriate<Profile>(method_in, method_out_return);
  }

  ::testing::TestInfo const* const test_info_;
  std::string const test_case_name_;
  std::string const test_name_;
  std::unique_ptr<ksp_plugin::Plugin> plugin_;
};

TEST_F(PlayerTest, PlayTiny) {
  // Do the recording in a separate thread to make sure that it activates using
  // a different static variable than the one in the plugin dynamic library.
  std::thread recorder([this]() {
    Recorder* const r(new Recorder(test_name_ + ".journal.hex"));
    Recorder::Activate(r);

    {
      Method<NewPlugin> m({"1 s", "2 s", 3});
      m.Return(plugin_.get());
    }
    {
      const ksp_plugin::Plugin* plugin = plugin_.get();
      Method<DeletePlugin> m({&plugin}, {&plugin});
      m.Return();
    }
    Recorder::Deactivate();
  });
  recorder.join();

  Player player(test_name_ + ".journal.hex");

  // Replay the journal.
  int count = 0;
  while (player.Play()) {
    ++count;
  }
  EXPECT_EQ(2, count);
}

// This test (a.k.a. benchmark) is only run if the --gtest_filter flag names it
// explicitly.
TEST_F(PlayerTest, Benchmarks) {
  if (testing::FLAGS_gtest_filter == test_case_name_ + "." + test_name_) {
    benchmark::RunSpecifiedBenchmarks();
  }
}

#if 1
// This test is only run if the --gtest_filter flag names it explicitly.
TEST_F(PlayerTest, Debug) {
  if (testing::FLAGS_gtest_filter == test_case_name_ + "." + test_name_) {
    // An example of how journalling may be used for debugging.  You must set
    // |path| and fill the |method_in| and |method_out_return| protocol buffers.
    std::string path =
        R"(C:\Users\robin\Projects\Kerbal Space Program\KSP_win64 1.2.2\glog\Principia\JOURNAL.20170307-163451)";
    Player player(path);
    int count = 0;
    while (player.Play()) {
      ++count;
      LOG_IF(ERROR, (count % 100'000) == 0) << count
                                            << " journal entries replayed";
    }
    LOG(ERROR) << count << " journal entries in total";
    LOG(ERROR) << "Last successful method in:\n"
               << player.last_method_in().DebugString();
    LOG(ERROR) << "Last successful method out/return: \n"
               << player.last_method_out_return().DebugString();

#if 0
    serialization::Method method_in;
    auto* extension = method_in.MutableExtension(
        serialization::ReportCollision::extension);
    auto* in = extension->mutable_in();
    in->set_plugin(355375312);
    in->set_vessel1_guid("14b05bd3-9707-4d49-a6be-a7de481f3e0a");
    in->set_vessel2_guid("3e6fcb7e-4761-48ed-829f-0adb035f457e");
    serialization::Method method_out_return;
    method_out_return.MutableExtension(
        serialization::ReportCollision::extension);
    LOG(ERROR) << "Running unpaired method:\n" << method_in.DebugString();
    CHECK(RunIfAppropriate<ReportCollision>(method_in,
                                            method_out_return,
                                            player));
#endif
  }
}
#endif

}  // namespace journal
}  // namespace principia
<|endoftext|>


<commit_before>#include <SFML/Graphics.hpp>
#include <Astra/Astra.h>
#include <AstraUL/AstraUL.h>
#include "../../common/LitDepthVisualizer.h"
#include <chrono>
#include <iostream>
#include <iomanip>
#include <key_handler.h>
#include <sstream>

class DepthFrameListener : public astra::FrameReadyListener
{
public:
    DepthFrameListener()
    {
        m_lastTimepoint = clock_type::now();
        m_font.loadFromFile("Inconsolata.otf");
    }

    void init_texture(int width, int height)
    {
        if (m_displayBuffer == nullptr || width != m_displayWidth || height != m_displayHeight)
        {
            m_displayWidth = width;
            m_displayHeight = height;

            // texture is RGBA
            int byteLength = m_displayWidth * m_displayHeight * 4;

            m_displayBuffer = BufferPtr(new uint8_t[byteLength]);
            memset(m_displayBuffer.get(), 0, byteLength);

            m_texture.create(m_displayWidth, m_displayHeight);
            m_sprite.setTexture(m_texture);
            m_sprite.setPosition(0, 0);
        }
    }

    void check_fps()
    {
        const double frameWeight = 0.2;

        auto newTimepoint = clock_type::now();
        auto frameDuration = std::chrono::duration_cast<duration_type>(newTimepoint - m_lastTimepoint);

        m_frameDuration = frameDuration * frameWeight + m_frameDuration * (1 - frameWeight);
        m_lastTimepoint = newTimepoint;

        double fps = 1.0 / m_frameDuration.count();

        auto precision = std::cout.precision();
        std::cout << std::fixed
                  << std::setprecision(1)
                  << fps << " fps ("
                  << std::setprecision(2)
                  << frameDuration.count() * 1000 << " ms)"
                  << std::setprecision(precision)
                  << std::endl;
    }

    virtual void on_frame_ready(astra::StreamReader& reader,
                                astra::Frame& frame) override
    {
        astra::PointFrame pointFrame = frame.get<astra::PointFrame>();

        int width = pointFrame.resolutionX();
        int height = pointFrame.resolutionY();

        init_texture(width, height);

        update_mouse_overlay_from_depth(frame);
        check_fps();

        if (m_isPaused)
        {
            return;
        }
        m_visualizer.update(pointFrame);

        astra_rgb_pixel_t* vizBuffer = m_visualizer.get_output();
        for (int i = 0; i < width * height; i++)
        {
            int rgbaOffset = i * 4;
            m_displayBuffer[rgbaOffset] = vizBuffer[i].r;
            m_displayBuffer[rgbaOffset + 1] = vizBuffer[i].b;
            m_displayBuffer[rgbaOffset + 2] = vizBuffer[i].g;
            m_displayBuffer[rgbaOffset + 3] = 255;
        }
        m_texture.update(m_displayBuffer.get());
    }

    void update_mouse_overlay_from_depth(astra::Frame& frame)
    {
        astra::DepthFrame depthFrame = frame.get<astra::DepthFrame>();

        if (depthFrame.is_valid())
        {
            int with = depthFrame.resolutionX();
            int height = depthFrame.resolutionY();

            const int16_t* buffer = depthFrame.data();

            m_mouse_X = with * m_width_Scale;
            m_mouse_Y = height * m_height_Scale;

            size_t index = (with * m_mouse_Y + m_mouse_X);

            m_mouse_D = buffer[index];
        }
    }

    void set_Scale(sf::RenderWindow& window)
    {
        sf::Vector2i position = sf::Mouse::getPosition(window);
        astra::Vector2f normPosition;
        auto windowSize = window.getSize();

        normPosition.x = position.x / static_cast<float>(windowSize.x);
        normPosition.y = position.y / static_cast<float>(windowSize.y);

        m_width_Scale = normPosition.x;
        m_height_Scale = normPosition.y;
    }

    void drawMouseText(sf::RenderWindow& window, sf::Text& text, sf::Color color, int x, int y)
    {
        text.setColor(sf::Color::Black);
        text.setPosition(x + 5, y + 5);
        window.draw(text);

        text.setColor(color);
        text.setPosition(x, y);
        window.draw(text);
    }

    void drawMousePoints(sf::RenderWindow& window, float depthWScale, float depthHScale)
    {
        std::stringstream str;
        str << std::fixed << std::setprecision(0);
        str << "X:" << m_mouse_X << " " << "Y:" << m_mouse_Y << " " << "D:" << m_mouse_D;
        sf::Text text(str.str(), m_font);

        int characterSize = 40;
        text.setCharacterSize(characterSize);
        text.setStyle(sf::Text::Bold);

        float display_x = 100;
        float display_y = window.getView().getSize().y - 100;
        drawMouseText(window, text, sf::Color::White, display_x, display_y);
    }

    void drawTo(sf::RenderWindow& window)
    {
        if (m_displayBuffer != nullptr)
        {
            float depthWScale = window.getView().getSize().x / m_displayWidth;
            float depthHScale = window.getView().getSize().y / m_displayHeight;

            m_sprite.setScale(depthWScale, depthHScale);

            window.draw(m_sprite);
            drawMousePoints(window, depthWScale, depthHScale);
        }
    }

    void toggle_Paused()
    {
        m_isPaused = !m_isPaused;
    }

    bool get_isPaused() const
    {
        return m_isPaused;
    }

    void toggle_Display()
    {
        m_isDisplay = !m_isDisplay;
    }

    bool get_isDisplay() const
    {
        return m_isDisplay;
    }

private:
    samples::common::LitDepthVisualizer m_visualizer;

    using duration_type = std::chrono::duration<double>;
    duration_type m_frameDuration{0.0};

    using clock_type = std::chrono::system_clock;
    std::chrono::time_point<clock_type> m_lastTimepoint;
    sf::Texture m_texture;
    sf::Sprite m_sprite;
    sf::Font m_font;

    using BufferPtr = std::unique_ptr< uint8_t[] >;
    BufferPtr m_displayBuffer{ nullptr };
    int m_displayWidth{ 0 };
    int m_displayHeight{ 0 };

    int m_mouse_X{ 0 };
    int m_mouse_Y{ 0 };
    int m_mouse_D{ 0 };
    float m_width_Scale{ 0 };
    float m_height_Scale{ 0 };
    bool m_isPaused{ false };
    bool m_isDisplay{ false };
};

int main(int argc, char** argv)
{
    astra::Astra::initialize();

    set_key_handler();

    sf::RenderWindow window(sf::VideoMode(1280, 960), "Depth Viewer");

    #ifdef _WIN32
        auto fullscreenStyle = sf::Style::None;
    #else
        auto fullscreenStyle = sf::Style::Fullscreen;
    #endif

    sf::VideoMode fullscreen_mode = sf::VideoMode::getFullscreenModes()[0];
    sf::VideoMode windowed_mode(1280, 960);
    bool is_fullscreen = false;

    astra::StreamSet streamset;
    astra::StreamReader reader = streamset.create_reader();

    reader.stream<astra::PointStream>().start();
    auto depthStream = reader.stream<astra::DepthStream>();
    depthStream.start();

    DepthFrameListener listener;

    reader.addListener(listener);

    while (window.isOpen())
    {
        astra_temp_update();

        sf::Event event;
        while (window.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::Closed:
                window.close();
                break;
            case sf::Event::KeyPressed:
            {
                if (event.key.code == sf::Keyboard::C && event.key.control)
                {
                    window.close();
                }
                switch (event.key.code)
                {
                    case sf::Keyboard::Escape:
                        window.close();
                        break;
                    case sf::Keyboard::F:
                        if (is_fullscreen)
                        {
                            is_fullscreen = false;
                            window.create(windowed_mode, "Depth Viewer", sf::Style::Default);
                        }
                        else
                        {
                            is_fullscreen = true;
                            window.create(fullscreen_mode, "Depth Viewer", fullscreenStyle);
                        }
                        break;
                    case sf::Keyboard::R:
                        depthStream.enable_registration(!depthStream.registration_enabled());
                        break;
                    case sf::Keyboard::M:
                        depthStream.enable_mirroring(!depthStream.mirroring_enabled());
                        break;
                    case sf::Keyboard::P:
                        listener.toggle_Paused();
                        break;
                    case sf::Keyboard::Space:
                        listener.toggle_Display();
                        break;
                    default:
                        break;
                }
                break;
            }
            case sf::Event::MouseMoved:
            {
                if (listener.get_isDisplay())
                    listener.set_Scale(window);
                break;
            }
            default:
                break;
            }
        }

        // clear the window with black color
        window.clear(sf::Color::Black);

        listener.drawTo(window);
        window.display();

        if (!shouldContinue)
        {
            window.close();
        }
    }

    astra::Astra::terminate();
    return 0;
}

<commit_msg>Code cleanup<commit_after>#include <SFML/Graphics.hpp>
#include <Astra/Astra.h>
#include <AstraUL/AstraUL.h>
#include "../../common/LitDepthVisualizer.h"
#include <chrono>
#include <iostream>
#include <iomanip>
#include <key_handler.h>
#include <sstream>

class DepthFrameListener : public astra::FrameReadyListener
{
public:
    DepthFrameListener()
    {
        m_lastTimepoint = clock_type::now();
        m_font.loadFromFile("Inconsolata.otf");
    }

    void init_texture(int width, int height)
    {
        if (m_displayBuffer == nullptr || width != m_displayWidth || height != m_displayHeight)
        {
            m_displayWidth = width;
            m_displayHeight = height;

            // texture is RGBA
            int byteLength = m_displayWidth * m_displayHeight * 4;

            m_displayBuffer = BufferPtr(new uint8_t[byteLength]);
            memset(m_displayBuffer.get(), 0, byteLength);

            m_texture.create(m_displayWidth, m_displayHeight);
            m_sprite.setTexture(m_texture);
            m_sprite.setPosition(0, 0);
        }
    }

    void check_fps()
    {
        const double frameWeight = 0.2;

        auto newTimepoint = clock_type::now();
        auto frameDuration = std::chrono::duration_cast<duration_type>(newTimepoint - m_lastTimepoint);

        m_frameDuration = frameDuration * frameWeight + m_frameDuration * (1 - frameWeight);
        m_lastTimepoint = newTimepoint;

        double fps = 1.0 / m_frameDuration.count();

        auto precision = std::cout.precision();
        std::cout << std::fixed
                  << std::setprecision(1)
                  << fps << " fps ("
                  << std::setprecision(2)
                  << frameDuration.count() * 1000 << " ms)"
                  << std::setprecision(precision)
                  << std::endl;
    }

    virtual void on_frame_ready(astra::StreamReader& reader,
                                astra::Frame& frame) override
    {
        astra::PointFrame pointFrame = frame.get<astra::PointFrame>();

        int width = pointFrame.resolutionX();
        int height = pointFrame.resolutionY();

        init_texture(width, height);

        update_mouse_overlay_from_depth(frame);
        check_fps();

        if (m_isPaused)
        {
            return;
        }
        m_visualizer.update(pointFrame);

        astra_rgb_pixel_t* vizBuffer = m_visualizer.get_output();
        for (int i = 0; i < width * height; i++)
        {
            int rgbaOffset = i * 4;
            m_displayBuffer[rgbaOffset] = vizBuffer[i].r;
            m_displayBuffer[rgbaOffset + 1] = vizBuffer[i].b;
            m_displayBuffer[rgbaOffset + 2] = vizBuffer[i].g;
            m_displayBuffer[rgbaOffset + 3] = 255;
        }
        m_texture.update(m_displayBuffer.get());
    }

    void update_mouse_overlay_from_depth(astra::Frame& frame)
    {
        astra::DepthFrame depthFrame = frame.get<astra::DepthFrame>();

        if (depthFrame.is_valid())
        {
            int width = depthFrame.resolutionX();
            int height = depthFrame.resolutionY();

            const int16_t* buffer = depthFrame.data();

            m_mouse_X = width * m_mouseNormX;
            m_mouse_Y = height * m_mouseNormY;

            size_t index = (width * m_mouse_Y + m_mouse_X);

            m_mouse_Z = buffer[index];
        }
    }

    void update_mouse_position(sf::RenderWindow& window)
    {
        sf::Vector2i position = sf::Mouse::getPosition(window);
        auto windowSize = window.getSize();

        m_mouseNormX = position.x / static_cast<float>(windowSize.x);
        m_mouseNormY = position.y / static_cast<float>(windowSize.y);
    }

    void drawText(sf::RenderWindow& window, sf::Text& text, sf::Color color, int x, int y)
    {
        text.setColor(sf::Color::Black);
        text.setPosition(x + 5, y + 5);
        window.draw(text);

        text.setColor(color);
        text.setPosition(x, y);
        window.draw(text);
    }

    void drawMouseOverlay(sf::RenderWindow& window, float depthWScale, float depthHScale)
    {
        if (!m_isMouseOverlayEnabled)
        {
            return;
        }
        std::stringstream str;
        str << std::fixed << std::setprecision(0);
        str << "X:" << m_mouse_X << " " << "Y:" << m_mouse_Y << " " << "Z:" << m_mouse_Z;
        sf::Text text(str.str(), m_font);

        int characterSize = 40;
        text.setCharacterSize(characterSize);
        text.setStyle(sf::Text::Bold);

        float display_x = 10;
        float display_y = window.getView().getSize().y - 10 - characterSize;
        drawText(window, text, sf::Color::White, display_x, display_y);
    }

    void drawTo(sf::RenderWindow& window)
    {
        if (m_displayBuffer != nullptr)
        {
            float depthWScale = window.getView().getSize().x / m_displayWidth;
            float depthHScale = window.getView().getSize().y / m_displayHeight;

            m_sprite.setScale(depthWScale, depthHScale);

            window.draw(m_sprite);

            drawMouseOverlay(window, depthWScale, depthHScale);
        }
    }

    void toggle_isPaused()
    {
        m_isPaused = !m_isPaused;
    }

    bool get_isPaused() const
    {
        return m_isPaused;
    }

    void toggle_isMouseOverlayEnabled()
    {
        m_isMouseOverlayEnabled = !m_isMouseOverlayEnabled;
    }

    bool get_isMouseOverlayEnabled() const
    {
        return m_isMouseOverlayEnabled;
    }

private:
    samples::common::LitDepthVisualizer m_visualizer;

    using duration_type = std::chrono::duration<double>;
    duration_type m_frameDuration{0.0};

    using clock_type = std::chrono::system_clock;
    std::chrono::time_point<clock_type> m_lastTimepoint;
    sf::Texture m_texture;
    sf::Sprite m_sprite;
    sf::Font m_font;

    using BufferPtr = std::unique_ptr< uint8_t[] >;
    BufferPtr m_displayBuffer{ nullptr };
    int m_displayWidth{ 0 };
    int m_displayHeight{ 0 };

    int m_mouse_X{ 0 };
    int m_mouse_Y{ 0 };
    int m_mouse_Z{ 0 };
    float m_mouseNormX{ 0 };
    float m_mouseNormY{ 0 };
    bool m_isPaused{ false };
    bool m_isMouseOverlayEnabled{ false };
};

int main(int argc, char** argv)
{
    astra::Astra::initialize();

    set_key_handler();

    sf::RenderWindow window(sf::VideoMode(1280, 960), "Depth Viewer");

    #ifdef _WIN32
        auto fullscreenStyle = sf::Style::None;
    #else
        auto fullscreenStyle = sf::Style::Fullscreen;
    #endif

    sf::VideoMode fullscreen_mode = sf::VideoMode::getFullscreenModes()[0];
    sf::VideoMode windowed_mode(1280, 960);
    bool is_fullscreen = false;

    astra::StreamSet streamset;
    astra::StreamReader reader = streamset.create_reader();

    reader.stream<astra::PointStream>().start();
    auto depthStream = reader.stream<astra::DepthStream>();
    depthStream.start();

    DepthFrameListener listener;

    reader.addListener(listener);

    while (window.isOpen())
    {
        astra_temp_update();

        sf::Event event;
        while (window.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::Closed:
                window.close();
                break;
            case sf::Event::KeyPressed:
            {
                if (event.key.code == sf::Keyboard::C && event.key.control)
                {
                    window.close();
                }
                switch (event.key.code)
                {
                    case sf::Keyboard::Escape:
                        window.close();
                        break;
                    case sf::Keyboard::F:
                        if (is_fullscreen)
                        {
                            is_fullscreen = false;
                            window.create(windowed_mode, "Depth Viewer", sf::Style::Default);
                        }
                        else
                        {
                            is_fullscreen = true;
                            window.create(fullscreen_mode, "Depth Viewer", fullscreenStyle);
                        }
                        break;
                    case sf::Keyboard::R:
                        depthStream.enable_registration(!depthStream.registration_enabled());
                        break;
                    case sf::Keyboard::M:
                        depthStream.enable_mirroring(!depthStream.mirroring_enabled());
                        break;
                    case sf::Keyboard::P:
                        listener.toggle_isPaused();
                        break;
                    case sf::Keyboard::Space:
                        listener.toggle_isMouseOverlayEnabled();
                        break;
                    default:
                        break;
                }
                break;
            }
            case sf::Event::MouseMoved:
            {
                listener.update_mouse_position(window);
                break;
            }
            default:
                break;
            }
        }

        // clear the window with black color
        window.clear(sf::Color::Black);

        listener.drawTo(window);
        window.display();

        if (!shouldContinue)
        {
            window.close();
        }
    }

    astra::Astra::terminate();
    return 0;
}

<|endoftext|>