<commit_before>/*++
Copyright (c) 2006 Microsoft Corporation

Module Name:

    dl_mk_filter_rules.cpp

Abstract:

    <abstract>

Author:

    Leonardo de Moura (leonardo) 2010-05-18.

Revision History:

--*/

#include"dl_mk_filter_rules.h"
#include"dl_context.h"
#include"for_each_expr.h"
#include"ast_pp.h"

namespace datalog {

    mk_filter_rules::mk_filter_rules(context & ctx):
            plugin(2000),
            m_context(ctx),
            m(ctx.get_manager()),
            rm(ctx.get_rule_manager()),
            m_result(0),
            m_pinned(m) {
    }

    mk_filter_rules::~mk_filter_rules() {
        ptr_vector<filter_key> to_dealloc;
        filter_cache::iterator it = m_tail2filter.begin();
        filter_cache::iterator end = m_tail2filter.end();
        for(; it!=end; ++it) {
            to_dealloc.push_back(it->m_key);
        }
        m_tail2filter.reset();
        ptr_vector<filter_key>::iterator dit = to_dealloc.begin();
        ptr_vector<filter_key>::iterator dend = to_dealloc.end();
        for(; dit!=dend; ++dit) {
            dealloc(*dit);
        }
    }

    /**
       \brief Return true if \c pred is a cadidate for a "filter" rule.
    */
    bool mk_filter_rules::is_candidate(app * pred) {
        if (!m_context.is_predicate(pred)) {
            TRACE("mk_filter_rules", tout << mk_pp(pred, m) << "\nis not a candidate because it is interpreted.\n";);
            return false;
        }
        var_idx_set used_vars;
        unsigned n  = pred->get_num_args();
        for (unsigned i = 0; i < n; i++) {
            expr * arg = pred->get_arg(i);
            if (m.is_value(arg))
                return true;
            SASSERT(is_var(arg));
            unsigned vidx = to_var(arg)->get_idx();
            if (used_vars.contains(vidx))
                return true;
            used_vars.insert(vidx);
        }
        return false;
    }

    /**
       \brief Create a "filter" (if it doesn't exist already) for the given predicate.
    */
    func_decl *  mk_filter_rules::mk_filter_decl(app * pred, var_idx_set const & non_local_vars) {
        sort_ref_buffer filter_domain(m);

        filter_key * key = alloc(filter_key, m);
        mk_new_rule_tail(m, pred, non_local_vars, filter_domain, key->filter_args, key->new_pred);
        filter_cache::obj_map_entry *entry = m_tail2filter.insert_if_not_there2(key, 0);
        func_decl*& filter_decl = entry->get_data().m_value;
        if (!filter_decl) {
            filter_decl = m_context.mk_fresh_head_predicate(pred->get_decl()->get_name(), symbol("filter"),
                filter_domain.size(), filter_domain.c_ptr(), pred->get_decl());

            m_pinned.push_back(filter_decl);
            app_ref filter_head(m);
            filter_head = m.mk_app(filter_decl, key->filter_args.size(), key->filter_args.c_ptr());
            app * filter_tail = key->new_pred;
            rule * filter_rule = m_context.get_rule_manager().mk(filter_head, 1, &filter_tail, (const bool *)0);
            filter_rule->set_accounting_parent_object(m_context, m_current);
            m_result->add_rule(filter_rule);
            m_context.get_rule_manager().mk_rule_asserted_proof(*filter_rule);
        }
        else {
            dealloc(key);
        }
        SASSERT(filter_decl != 0);
        SASSERT(filter_decl->get_arity()==filter_domain.size());
        return filter_decl;
    }

    void mk_filter_rules::process(rule * r) {
        m_current = r;
        app * new_head = r->get_head();
        app_ref_vector new_tail(m);
        svector<bool>  new_is_negated;
        unsigned sz = r->get_tail_size();
        bool rule_modified = false;
        for (unsigned i = 0; i < sz; i++) {
            app * tail = r->get_tail(i);
            if (is_candidate(tail)) {
                TRACE("mk_filter_rules", tout << "is_candidate: " << mk_pp(tail, m) << "\n";);
                var_idx_set non_local_vars = rm.collect_rule_vars_ex(r, tail);
                func_decl * filter_decl = mk_filter_decl(tail, non_local_vars);
                ptr_buffer<expr> new_args;
                var_idx_set used_vars;
                unsigned num_args = tail->get_num_args();
                for (unsigned i = 0; i < num_args; i++) {
                    expr * arg = tail->get_arg(i);
                    if (is_var(arg)) {
                        unsigned vidx = to_var(arg)->get_idx();
                        if (non_local_vars.contains(vidx) && !used_vars.contains(vidx)) {
                            new_args.push_back(arg);
                            used_vars.insert(vidx);
                        }
                    }
                }
                SASSERT(new_args.size() == filter_decl->get_arity());
                new_tail.push_back(m.mk_app(filter_decl, new_args.size(), new_args.c_ptr()));
                rule_modified = true;
            }
            else {
                new_tail.push_back(tail);
            }
            new_is_negated.push_back(r->is_neg_tail(i));
        }
        if (rule_modified) {
            remove_duplicate_tails(new_tail, new_is_negated);
            SASSERT(new_tail.size() == new_is_negated.size());
            rule * new_rule = m_context.get_rule_manager().mk(new_head, new_tail.size(), new_tail.c_ptr(), new_is_negated.c_ptr());
            new_rule->set_accounting_parent_object(m_context, m_current);
            m_result->add_rule(new_rule);
            m_context.get_rule_manager().mk_rule_rewrite_proof(*r, *new_rule);
            m_modified = true;
        }
        else {
            m_result->add_rule(r);
        }
    }

    rule_set * mk_filter_rules::operator()(rule_set const & source) {
        m_tail2filter.reset();
        m_result           = alloc(rule_set, m_context);
        m_modified         = false;
        unsigned num_rules = source.get_num_rules();
        for (unsigned i = 0; i < num_rules; i++) {
            process(source.get_rule(i));
        }
        if(!m_modified) {
            dealloc(m_result);
            return static_cast<rule_set *>(0);
        }
        m_result->inherit_predicates(source);
        return m_result;
    }

};
<commit_msg>disable filtering on negated tails. Issue #634<commit_after>/*++
Copyright (c) 2006 Microsoft Corporation

Module Name:

    dl_mk_filter_rules.cpp

Abstract:

    <abstract>

Author:

    Leonardo de Moura (leonardo) 2010-05-18.

Revision History:

--*/

#include"dl_mk_filter_rules.h"
#include"dl_context.h"
#include"for_each_expr.h"
#include"ast_pp.h"

namespace datalog {

    mk_filter_rules::mk_filter_rules(context & ctx):
            plugin(2000),
            m_context(ctx),
            m(ctx.get_manager()),
            rm(ctx.get_rule_manager()),
            m_result(0),
            m_pinned(m) {
    }

    mk_filter_rules::~mk_filter_rules() {
        ptr_vector<filter_key> to_dealloc;
        filter_cache::iterator it = m_tail2filter.begin();
        filter_cache::iterator end = m_tail2filter.end();
        for(; it!=end; ++it) {
            to_dealloc.push_back(it->m_key);
        }
        m_tail2filter.reset();
        ptr_vector<filter_key>::iterator dit = to_dealloc.begin();
        ptr_vector<filter_key>::iterator dend = to_dealloc.end();
        for(; dit!=dend; ++dit) {
            dealloc(*dit);
        }
    }

    /**
       \brief Return true if \c pred is a cadidate for a "filter" rule.
    */
    bool mk_filter_rules::is_candidate(app * pred) {
        if (!m_context.is_predicate(pred)) {
            TRACE("mk_filter_rules", tout << mk_pp(pred, m) << "\nis not a candidate because it is interpreted.\n";);
            return false;
        }
        var_idx_set used_vars;
        unsigned n  = pred->get_num_args();
        for (unsigned i = 0; i < n; i++) {
            expr * arg = pred->get_arg(i);
            if (m.is_value(arg))
                return true;
            SASSERT(is_var(arg));
            unsigned vidx = to_var(arg)->get_idx();
            if (used_vars.contains(vidx))
                return true;
            used_vars.insert(vidx);
        }
        return false;
    }

    /**
       \brief Create a "filter" (if it doesn't exist already) for the given predicate.
    */
    func_decl *  mk_filter_rules::mk_filter_decl(app * pred, var_idx_set const & non_local_vars) {
        sort_ref_buffer filter_domain(m);

        filter_key * key = alloc(filter_key, m);
        mk_new_rule_tail(m, pred, non_local_vars, filter_domain, key->filter_args, key->new_pred);
        filter_cache::obj_map_entry *entry = m_tail2filter.insert_if_not_there2(key, 0);
        func_decl*& filter_decl = entry->get_data().m_value;
        if (!filter_decl) {
            filter_decl = m_context.mk_fresh_head_predicate(pred->get_decl()->get_name(), symbol("filter"),
                filter_domain.size(), filter_domain.c_ptr(), pred->get_decl());

            m_pinned.push_back(filter_decl);
            app_ref filter_head(m);
            filter_head = m.mk_app(filter_decl, key->filter_args.size(), key->filter_args.c_ptr());
            app * filter_tail = key->new_pred;
            rule * filter_rule = m_context.get_rule_manager().mk(filter_head, 1, &filter_tail, (const bool *)0);
            filter_rule->set_accounting_parent_object(m_context, m_current);
            m_result->add_rule(filter_rule);
            m_context.get_rule_manager().mk_rule_asserted_proof(*filter_rule);
        }
        else {
            dealloc(key);
        }
        SASSERT(filter_decl != 0);
        SASSERT(filter_decl->get_arity()==filter_domain.size());
        return filter_decl;
    }

    void mk_filter_rules::process(rule * r) {
        m_current = r;
        app * new_head = r->get_head();
        app_ref_vector new_tail(m);
        svector<bool>  new_is_negated;
        unsigned sz = r->get_tail_size();
        bool rule_modified = false;
        for (unsigned i = 0; i < sz; i++) {
            app * tail = r->get_tail(i);
            if (is_candidate(tail) && !r->is_neg_tail(i)) {
                TRACE("mk_filter_rules", tout << "is_candidate: " << mk_pp(tail, m) << "\n";);
                var_idx_set non_local_vars = rm.collect_rule_vars_ex(r, tail);
                func_decl * filter_decl = mk_filter_decl(tail, non_local_vars);
                ptr_buffer<expr> new_args;
                var_idx_set used_vars;
                unsigned num_args = tail->get_num_args();
                for (unsigned i = 0; i < num_args; i++) {
                    expr * arg = tail->get_arg(i);
                    if (is_var(arg)) {
                        unsigned vidx = to_var(arg)->get_idx();
                        if (non_local_vars.contains(vidx) && !used_vars.contains(vidx)) {
                            new_args.push_back(arg);
                            used_vars.insert(vidx);
                        }
                    }
                }
                SASSERT(new_args.size() == filter_decl->get_arity());
                new_tail.push_back(m.mk_app(filter_decl, new_args.size(), new_args.c_ptr()));
                rule_modified = true;
            }
            else {
                new_tail.push_back(tail);
            }
            new_is_negated.push_back(r->is_neg_tail(i));
        }
        if (rule_modified) {
            remove_duplicate_tails(new_tail, new_is_negated);
            SASSERT(new_tail.size() == new_is_negated.size());
            rule * new_rule = m_context.get_rule_manager().mk(new_head, new_tail.size(), new_tail.c_ptr(), new_is_negated.c_ptr());
            new_rule->set_accounting_parent_object(m_context, m_current);
            m_result->add_rule(new_rule);
            m_context.get_rule_manager().mk_rule_rewrite_proof(*r, *new_rule);
            m_modified = true;
        }
        else {
            m_result->add_rule(r);
        }
    }

    rule_set * mk_filter_rules::operator()(rule_set const & source) {
        m_tail2filter.reset();
        m_result           = alloc(rule_set, m_context);
        m_modified         = false;
        unsigned num_rules = source.get_num_rules();
        for (unsigned i = 0; i < num_rules; i++) {
            process(source.get_rule(i));
        }
        if(!m_modified) {
            dealloc(m_result);
            return static_cast<rule_set *>(0);
        }
        m_result->inherit_predicates(source);
        return m_result;
    }

};
<|endoftext|>


<commit_before>/* The Channel class, provides a simple, Ruby thread safe communication
 * mechanism. */

#include "vm.hpp"
#include "vm/object_utils.hpp"
#include "objectmemory.hpp"

#include "builtin/object.hpp"
#include "builtin/channel.hpp"
#include "builtin/thread.hpp"
#include "builtin/list.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/float.hpp"
#include "builtin/io.hpp"

#include "arguments.hpp"
#include "dispatch.hpp"
#include "call_frame.hpp"

#include "on_stack.hpp"

#include "ontology.hpp"

#include <sys/time.h>

namespace rubinius {

  void Channel::init(STATE) {
    GO(channel).set(ontology::new_class(state, "Channel",
                      G(object), G(rubinius)));
    G(channel)->set_object_type(state, Channel::type);
    G(channel)->name(state, state->symbol("Rubinius::Channel"));
  }

  Channel* Channel::create(STATE) {
    Channel* chan = state->vm()->new_object_mature<Channel>(G(channel));
    chan->waiters_ = 0;
    chan->semaphore_count_ = 0;

    // Using placement new to call the constructor of condition_
    new(&chan->condition_) thread::Condition();
    new(&chan->mutex_) thread::Mutex();

    chan->value(state, List::create(state));

    return chan;
  }

  Channel* Channel::create_primed(STATE) {
    Channel* chan = state->vm()->new_object_mature<Channel>(G(channel));
    chan->waiters_ = 0;
    chan->semaphore_count_ = 1;

    // Using placement new to call the constructor of condition_
    new(&chan->condition_) thread::Condition();
    new(&chan->mutex_) thread::Mutex();

    chan->value(state, List::create(state));

    return chan;
  }

  /** @todo Remove the event too? Should not affect code, but no need for it either. --rue */
  void Channel::cancel_waiter(STATE, const Thread* waiter) {
    // waiting_->remove(state, waiter);
  }

  Object* Channel::send(STATE, GCToken gct, Object* val) {
    Channel* self = this;

    OnStack<2> os(state, val, self);

    GCLockGuard lg(state, gct, mutex_);

    if(val->nil_p()) {
      self->semaphore_count_++;
    } else {
      if(self->semaphore_count_ > 0) {
        for(int i = 0; i < self->semaphore_count_; i++) {
          self->value_->append(state, cNil);
        }
        self->semaphore_count_ = 0;
      }

      self->value_->append(state, val);
    }

    if(self->waiters_ > 0) {
      self->condition_.signal();
    }

    return cNil;
  }

  Object* Channel::try_receive(STATE, GCToken gct) {
    Channel* self = this;
    OnStack<1> os(state, self);

    GCLockGuard lg(state, gct, mutex_);

    if(self->semaphore_count_ > 0) {
      self->semaphore_count_--;
      return cNil;
    }

    if(self->value_->empty_p()) return cNil;
    return self->value_->shift(state);
  }

  Object* Channel::receive(STATE, GCToken gct, CallFrame* call_frame) {
    return receive_timeout(state, gct, cNil, call_frame);
  }

#define NANOSECONDS 1000000000
  Object* Channel::receive_timeout(STATE, GCToken gct, Object* duration, CallFrame* call_frame) {
    // Passing control away means that the GC might run. So we need
    // to stash this into a root, and read it back out again after
    // control is returned.
    //
    // DO NOT USE this AFTER wait().

    // We have to do this because we can't pass this to OnStack, since C++
    // won't let us reassign it.

    Channel* self = this;
    OnStack<2> os(state, self, duration);

    GCLockGuard lg(state, gct, mutex_);

    if(self->semaphore_count_ > 0) {
      self->semaphore_count_--;
      return cNil;
    }

    if(!self->value_->empty_p()) return self->value_->shift(state);

    // Otherwise, we need to wait for a value.
    struct timespec ts = {0,0};
    bool use_timed_wait = true;

    if(Fixnum* fix = try_as<Fixnum>(duration)) {
      ts.tv_sec = fix->to_native();
    } else if(Float* flt = try_as<Float>(duration)) {
      uint64_t nano = (uint64_t)(flt->val * NANOSECONDS);
      ts.tv_sec  =  (time_t)(nano / NANOSECONDS);
      ts.tv_nsec =    (long)(nano % NANOSECONDS);
    } else if(duration->nil_p()) {
      use_timed_wait = false;
    } else {
      return Primitives::failure();
    }

    // We pin this so we can pass condition_ out without worrying about
    // us moving it.
    if(!self->pin()) {
      rubinius::bug("unable to pin Channel");
    }

    struct timeval tv = {0,0};
    if(use_timed_wait) {
      gettimeofday(&tv, 0);
      uint64_t nano = ts.tv_nsec + tv.tv_usec * 1000;
      ts.tv_sec  += tv.tv_sec + nano / NANOSECONDS;
      ts.tv_nsec  = nano % NANOSECONDS;
    }

    // We lock to manipulate the wait condition on the VM* so that
    // we can sync up properly with another thread trying to wake us
    // up right as we're trying to go to sleep.
    state->lock(gct);

    if(!state->check_async(call_frame)) {
      state->unlock();
      return NULL;
    }

    state->vm()->wait_on_channel(self);

    state->unlock();

    self->waiters_++;

    for(;;) {
      {
        GCIndependent gc_guard(state, call_frame);

        if(use_timed_wait) {
          if(self->condition_.wait_until(mutex_, &ts) == thread::cTimedOut) break;
        } else {
          self->condition_.wait(mutex_);
        }
      }

      // or there are values available.
      if(self->semaphore_count_ > 0 || !self->value()->empty_p()) break;
    }

    state->vm()->clear_waiter();
    state->vm()->thread->sleep(state, cFalse);

    self->unpin();
    self->waiters_--;

    if(!state->check_async(call_frame)) return NULL;

    if(self->semaphore_count_ > 0) {
      self->semaphore_count_--;
      return cNil;
    }

    // We were awoken, but there is no value to use. Return false.
    if(self->value()->empty_p()) return cFalse;

    return self->value()->shift(state);
  }

  bool Channel::has_readers_p() {
    return waiters_ > 0;
  }

  class SendToChannel : public ObjectCallback {
  public:
    TypedRoot<Channel*> chan;

    SendToChannel(STATE, Channel* chan) : ObjectCallback(state), chan(state, chan) { }

    virtual Object* object() {
      return chan.get();
    }

    virtual void call(Object* obj) {
      GCTokenImpl gct;
      chan->send(state, gct, obj);
    }
  };

/* ChannelCallback */

  ChannelCallback::ChannelCallback(STATE, Channel* chan) : ObjectCallback(state) {
    channel.set(chan, &GO(roots));
  }

  void ChannelCallback::call(Object* obj) {
    GCTokenImpl gct;
    channel->send(state, gct, obj);
  }
}
<commit_msg>Use self->mutex_ instead of this->mutex_ for safety<commit_after>/* The Channel class, provides a simple, Ruby thread safe communication
 * mechanism. */

#include "vm.hpp"
#include "vm/object_utils.hpp"
#include "objectmemory.hpp"

#include "builtin/object.hpp"
#include "builtin/channel.hpp"
#include "builtin/thread.hpp"
#include "builtin/list.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/float.hpp"
#include "builtin/io.hpp"

#include "arguments.hpp"
#include "dispatch.hpp"
#include "call_frame.hpp"

#include "on_stack.hpp"

#include "ontology.hpp"

#include <sys/time.h>

namespace rubinius {

  void Channel::init(STATE) {
    GO(channel).set(ontology::new_class(state, "Channel",
                      G(object), G(rubinius)));
    G(channel)->set_object_type(state, Channel::type);
    G(channel)->name(state, state->symbol("Rubinius::Channel"));
  }

  Channel* Channel::create(STATE) {
    Channel* chan = state->vm()->new_object_mature<Channel>(G(channel));
    chan->waiters_ = 0;
    chan->semaphore_count_ = 0;

    // Using placement new to call the constructor of condition_
    new(&chan->condition_) thread::Condition();
    new(&chan->mutex_) thread::Mutex();

    chan->value(state, List::create(state));

    return chan;
  }

  Channel* Channel::create_primed(STATE) {
    Channel* chan = state->vm()->new_object_mature<Channel>(G(channel));
    chan->waiters_ = 0;
    chan->semaphore_count_ = 1;

    // Using placement new to call the constructor of condition_
    new(&chan->condition_) thread::Condition();
    new(&chan->mutex_) thread::Mutex();

    chan->value(state, List::create(state));

    return chan;
  }

  /** @todo Remove the event too? Should not affect code, but no need for it either. --rue */
  void Channel::cancel_waiter(STATE, const Thread* waiter) {
    // waiting_->remove(state, waiter);
  }

  Object* Channel::send(STATE, GCToken gct, Object* val) {
    Channel* self = this;

    OnStack<2> os(state, val, self);

    GCLockGuard lg(state, gct, mutex_);

    if(val->nil_p()) {
      self->semaphore_count_++;
    } else {
      if(self->semaphore_count_ > 0) {
        for(int i = 0; i < self->semaphore_count_; i++) {
          self->value_->append(state, cNil);
        }
        self->semaphore_count_ = 0;
      }

      self->value_->append(state, val);
    }

    if(self->waiters_ > 0) {
      self->condition_.signal();
    }

    return cNil;
  }

  Object* Channel::try_receive(STATE, GCToken gct) {
    Channel* self = this;
    OnStack<1> os(state, self);

    GCLockGuard lg(state, gct, mutex_);

    if(self->semaphore_count_ > 0) {
      self->semaphore_count_--;
      return cNil;
    }

    if(self->value_->empty_p()) return cNil;
    return self->value_->shift(state);
  }

  Object* Channel::receive(STATE, GCToken gct, CallFrame* call_frame) {
    return receive_timeout(state, gct, cNil, call_frame);
  }

#define NANOSECONDS 1000000000
  Object* Channel::receive_timeout(STATE, GCToken gct, Object* duration, CallFrame* call_frame) {
    // Passing control away means that the GC might run. So we need
    // to stash this into a root, and read it back out again after
    // control is returned.
    //
    // DO NOT USE this AFTER wait().

    // We have to do this because we can't pass this to OnStack, since C++
    // won't let us reassign it.

    Channel* self = this;
    OnStack<2> os(state, self, duration);

    GCLockGuard lg(state, gct, mutex_);

    if(self->semaphore_count_ > 0) {
      self->semaphore_count_--;
      return cNil;
    }

    if(!self->value_->empty_p()) return self->value_->shift(state);

    // Otherwise, we need to wait for a value.
    struct timespec ts = {0,0};
    bool use_timed_wait = true;

    if(Fixnum* fix = try_as<Fixnum>(duration)) {
      ts.tv_sec = fix->to_native();
    } else if(Float* flt = try_as<Float>(duration)) {
      uint64_t nano = (uint64_t)(flt->val * NANOSECONDS);
      ts.tv_sec  =  (time_t)(nano / NANOSECONDS);
      ts.tv_nsec =    (long)(nano % NANOSECONDS);
    } else if(duration->nil_p()) {
      use_timed_wait = false;
    } else {
      return Primitives::failure();
    }

    // We pin this so we can pass condition_ out without worrying about
    // us moving it.
    if(!self->pin()) {
      rubinius::bug("unable to pin Channel");
    }

    struct timeval tv = {0,0};
    if(use_timed_wait) {
      gettimeofday(&tv, 0);
      uint64_t nano = ts.tv_nsec + tv.tv_usec * 1000;
      ts.tv_sec  += tv.tv_sec + nano / NANOSECONDS;
      ts.tv_nsec  = nano % NANOSECONDS;
    }

    // We lock to manipulate the wait condition on the VM* so that
    // we can sync up properly with another thread trying to wake us
    // up right as we're trying to go to sleep.
    state->lock(gct);

    if(!state->check_async(call_frame)) {
      state->unlock();
      return NULL;
    }

    state->vm()->wait_on_channel(self);

    state->unlock();

    self->waiters_++;

    for(;;) {
      {
        GCIndependent gc_guard(state, call_frame);

        if(use_timed_wait) {
          if(self->condition_.wait_until(self->mutex_, &ts) == thread::cTimedOut) break;
        } else {
          self->condition_.wait(self->mutex_);
        }
      }

      // or there are values available.
      if(self->semaphore_count_ > 0 || !self->value()->empty_p()) break;
    }

    state->vm()->clear_waiter();
    state->vm()->thread->sleep(state, cFalse);

    self->unpin();
    self->waiters_--;

    if(!state->check_async(call_frame)) return NULL;

    if(self->semaphore_count_ > 0) {
      self->semaphore_count_--;
      return cNil;
    }

    // We were awoken, but there is no value to use. Return false.
    if(self->value()->empty_p()) return cFalse;

    return self->value()->shift(state);
  }

  bool Channel::has_readers_p() {
    return waiters_ > 0;
  }

  class SendToChannel : public ObjectCallback {
  public:
    TypedRoot<Channel*> chan;

    SendToChannel(STATE, Channel* chan) : ObjectCallback(state), chan(state, chan) { }

    virtual Object* object() {
      return chan.get();
    }

    virtual void call(Object* obj) {
      GCTokenImpl gct;
      chan->send(state, gct, obj);
    }
  };

/* ChannelCallback */

  ChannelCallback::ChannelCallback(STATE, Channel* chan) : ObjectCallback(state) {
    channel.set(chan, &GO(roots));
  }

  void ChannelCallback::call(Object* obj) {
    GCTokenImpl gct;
    channel->send(state, gct, obj);
  }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: pdffilter.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2004-09-08 16:00:55 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef PDFFILTER_HXX
#define PDFFILTER_HXX

#ifndef _COM_SUN_STAR_DOCUMENT_XFILTER_HPP_
#include <com/sun/star/document/XFilter.hpp>
#endif
#ifndef _COM_SUN_STAR_DOCUMENT_XEXPORTER_HPP_
#include <com/sun/star/document/XExporter.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XINITIALIZATION_HPP_
#include <com/sun/star/lang/XInitialization.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif
#ifndef _CPPUHELPER_IMPLBASE1_HXX_
#include <cppuhelper/implbase1.hxx>
#endif
#ifndef _CPPUHELPER_IMPLBASE2_HXX_
#include <cppuhelper/implbase2.hxx>
#endif
#ifndef _CPPUHELPER_IMPLBASE3_HXX_
#include <cppuhelper/implbase3.hxx>
#endif
#ifndef _CPPUHELPER_IMPLBASE4_HXX_
#include <cppuhelper/implbase4.hxx>
#endif
#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYACCESS_HPP_
#include <com/sun/star/beans/XPropertyAccess.hpp>
#endif
#ifndef _COMPHELPER_PROPERTY_HXX_
#include <comphelper/property.hxx>
#endif
#ifndef _COM_SUN_STAR_TASK_XSTATUSINDICATOR_HPP_
#include <com/sun/star/task/XStatusIndicator.hpp>
#endif

#include <osl/diagnose.h>
#include <rtl/process.h>
#include <tools/debug.hxx>
#include <comphelper/processfactory.hxx>
#include <unotools/tempfile.hxx>
#include <unotools/localfilehelper.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <unotools/streamwrap.hxx>

using namespace ::rtl;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::document;
using namespace ::com::sun::star::io;

// -------------
// - PDFFilter -
// -------------

class PDFFilter : public cppu::WeakImplHelper4 < XFilter,
                                                 XExporter,
                                                 XInitialization,
                                                 XServiceInfo >
{
private:

    Reference< XMultiServiceFactory >   mxMSF;
    Reference< XComponent >             mxSrcDoc;

    sal_Bool                            implExport( const Sequence< PropertyValue >& rDescriptor );

protected:

    // XFilter
    virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& rDescriptor ) throw(RuntimeException);
    virtual void SAL_CALL cancel( ) throw (RuntimeException);

    // XExporter
    virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) throw(IllegalArgumentException, RuntimeException);

    // XInitialization
    virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw(Exception, RuntimeException);

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName() throw(RuntimeException);
    virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw(RuntimeException);
    virtual Sequence< OUString > SAL_CALL getSupportedServiceNames()  throw(RuntimeException);

public:

                PDFFilter( const Reference< XMultiServiceFactory >& rxMSF );
    virtual     ~PDFFilter();
};

// -----------------------------------------------------------------------------

OUString PDFFilter_getImplementationName ()
    throw ( RuntimeException );

// -----------------------------------------------------------------------------

sal_Bool SAL_CALL PDFFilter_supportsService( const OUString& ServiceName )
    throw ( RuntimeException );

// -----------------------------------------------------------------------------

Sequence< OUString > SAL_CALL PDFFilter_getSupportedServiceNames(  )
    throw ( RuntimeException );

// -----------------------------------------------------------------------------

Reference< XInterface >
SAL_CALL PDFFilter_createInstance( const Reference< XMultiServiceFactory > & rSMgr)
    throw ( Exception );

#endif // PDFFILTER_HXX

<commit_msg>INTEGRATION: CWS ooo19126 (1.5.242); FILE MERGED 2005/09/05 14:31:02 rt 1.5.242.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: pdffilter.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 21:50:36 $
 *
 *  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 PDFFILTER_HXX
#define PDFFILTER_HXX

#ifndef _COM_SUN_STAR_DOCUMENT_XFILTER_HPP_
#include <com/sun/star/document/XFilter.hpp>
#endif
#ifndef _COM_SUN_STAR_DOCUMENT_XEXPORTER_HPP_
#include <com/sun/star/document/XExporter.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XINITIALIZATION_HPP_
#include <com/sun/star/lang/XInitialization.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif
#ifndef _CPPUHELPER_IMPLBASE1_HXX_
#include <cppuhelper/implbase1.hxx>
#endif
#ifndef _CPPUHELPER_IMPLBASE2_HXX_
#include <cppuhelper/implbase2.hxx>
#endif
#ifndef _CPPUHELPER_IMPLBASE3_HXX_
#include <cppuhelper/implbase3.hxx>
#endif
#ifndef _CPPUHELPER_IMPLBASE4_HXX_
#include <cppuhelper/implbase4.hxx>
#endif
#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYACCESS_HPP_
#include <com/sun/star/beans/XPropertyAccess.hpp>
#endif
#ifndef _COMPHELPER_PROPERTY_HXX_
#include <comphelper/property.hxx>
#endif
#ifndef _COM_SUN_STAR_TASK_XSTATUSINDICATOR_HPP_
#include <com/sun/star/task/XStatusIndicator.hpp>
#endif

#include <osl/diagnose.h>
#include <rtl/process.h>
#include <tools/debug.hxx>
#include <comphelper/processfactory.hxx>
#include <unotools/tempfile.hxx>
#include <unotools/localfilehelper.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <unotools/streamwrap.hxx>

using namespace ::rtl;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::document;
using namespace ::com::sun::star::io;

// -------------
// - PDFFilter -
// -------------

class PDFFilter : public cppu::WeakImplHelper4 < XFilter,
                                                 XExporter,
                                                 XInitialization,
                                                 XServiceInfo >
{
private:

    Reference< XMultiServiceFactory >   mxMSF;
    Reference< XComponent >             mxSrcDoc;

    sal_Bool                            implExport( const Sequence< PropertyValue >& rDescriptor );

protected:

    // XFilter
    virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& rDescriptor ) throw(RuntimeException);
    virtual void SAL_CALL cancel( ) throw (RuntimeException);

    // XExporter
    virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) throw(IllegalArgumentException, RuntimeException);

    // XInitialization
    virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw(Exception, RuntimeException);

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName() throw(RuntimeException);
    virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw(RuntimeException);
    virtual Sequence< OUString > SAL_CALL getSupportedServiceNames()  throw(RuntimeException);

public:

                PDFFilter( const Reference< XMultiServiceFactory >& rxMSF );
    virtual     ~PDFFilter();
};

// -----------------------------------------------------------------------------

OUString PDFFilter_getImplementationName ()
    throw ( RuntimeException );

// -----------------------------------------------------------------------------

sal_Bool SAL_CALL PDFFilter_supportsService( const OUString& ServiceName )
    throw ( RuntimeException );

// -----------------------------------------------------------------------------

Sequence< OUString > SAL_CALL PDFFilter_getSupportedServiceNames(  )
    throw ( RuntimeException );

// -----------------------------------------------------------------------------

Reference< XInterface >
SAL_CALL PDFFilter_createInstance( const Reference< XMultiServiceFactory > & rSMgr)
    throw ( Exception );

#endif // PDFFILTER_HXX

<|endoftext|>


<commit_before><commit_msg>fdo#77268 SVG Import: fix null pointer dereference<commit_after><|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2012, Willow Garage, Inc.
 *  Copyright (c) 2012-, Open Perception, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the copyright holder(s) nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */

#include <pcl/filters/impl/extract_indices.hpp>

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::ExtractIndices<pcl::PCLPointCloud2>::applyFilter (PCLPointCloud2 &output)
{
  if (keep_organized_)
  {
    output = *input_;
    if (negative_)
    {
      // Prepare the output and copy the data
      for (size_t i = 0; i < indices_->size (); ++i)
        for (size_t j = 0; j < output.fields.size(); ++j)
          memcpy (&output.data[(*indices_)[i] * output.point_step + output.fields[j].offset],
                  &user_filter_value_, sizeof(float));
    }
    else
    {
      // Prepare a vector holding all indices
      std::vector<int> all_indices (input_->width * input_->height);
      for (int i = 0; i < static_cast<int>(all_indices.size ()); ++i)
        all_indices[i] = i;

      std::vector<int> indices = *indices_;
      std::sort (indices.begin (), indices.end ());

      // Get the diference
      std::vector<int> remaining_indices;
      set_difference (all_indices.begin (), all_indices.end (), indices.begin (), indices.end (),
                      inserter (remaining_indices, remaining_indices.begin ()));

      // Prepare the output and copy the data
      for (size_t i = 0; i < remaining_indices.size (); ++i)
        for (size_t j = 0; j < output.fields.size(); ++j)
          memcpy (&output.data[remaining_indices[i] * output.point_step + output.fields[j].offset],
                  &user_filter_value_, sizeof(float));
    }
    if (!pcl_isfinite (user_filter_value_))
      output.is_dense = false;
    return;
  }
  if (indices_->empty () || (input_->width * input_->height == 0))
  {
    output.width = output.height = 0;
    output.data.clear ();
    // If negative, copy all the data
    if (negative_)
      output = *input_;
    return;
  }
  if (indices_->size () == (input_->width * input_->height))
  {
    // If negative, then return an empty cloud
    if (negative_)
    {
      output.width = output.height = 0;
      output.data.clear ();
    }
    // else, we need to return all points
    else
      output = *input_;
    return;
  }

  // Copy the common fields (header and fields should have already been copied)
  output.is_bigendian = input_->is_bigendian;
  output.point_step   = input_->point_step;
  output.height       = 1;
  // TODO: check the output cloud and assign is_dense based on whether the points are valid or not
  output.is_dense     = false;

  if (negative_)
  {
    // Prepare a vector holding all indices
    std::vector<int> all_indices (input_->width * input_->height);
    for (int i = 0; i < static_cast<int>(all_indices.size ()); ++i)
      all_indices[i] = i;

    std::vector<int> indices = *indices_;
    std::sort (indices.begin (), indices.end ());

    // Get the diference
    std::vector<int> remaining_indices;
    set_difference (all_indices.begin (), all_indices.end (), indices.begin (), indices.end (),
                    inserter (remaining_indices, remaining_indices.begin ()));

    // Prepare the output and copy the data
    output.width = static_cast<uint32_t> (remaining_indices.size ());
    output.data.resize (remaining_indices.size () * output.point_step);
    for (size_t i = 0; i < remaining_indices.size (); ++i)
      memcpy (&output.data[i * output.point_step], &input_->data[remaining_indices[i] * output.point_step], output.point_step);
  }
  else
  {
    // Prepare the output and copy the data
    output.width = static_cast<uint32_t> (indices_->size ());
    output.data.resize (indices_->size () * output.point_step);
    for (size_t i = 0; i < indices_->size (); ++i)
      memcpy (&output.data[i * output.point_step], &input_->data[(*indices_)[i] * output.point_step], output.point_step);
  }
  output.row_step = output.point_step * output.width;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void
pcl::ExtractIndices<pcl::PCLPointCloud2>::applyFilter (std::vector<int> &indices)
{
  if (negative_)
  {
    // If the subset is the full set
    if (indices_->size () == (input_->width * input_->height))
    {
      // Empty set copy
      indices.clear ();
      return;
    }

    // Set up the full indices set
    std::vector<int> indices_fullset (input_->width * input_->height);
    for (int p_it = 0; p_it < static_cast<int> (indices_fullset.size ()); ++p_it)
      indices_fullset[p_it] = p_it;

    // If the subset is the empty set
    if (indices_->empty () || (input_->width * input_->height == 0))
    {
      // Full set copy
      indices = indices_fullset;
      return;
    }

    // If the subset is a proper subset
    // Set up the subset input indices
    std::vector<int> indices_subset = *indices_;
    std::sort (indices_subset.begin (), indices_subset.end ());

    // Get the difference
    set_difference (indices_fullset.begin (), indices_fullset.end (), indices_subset.begin (), indices_subset.end (), inserter (indices, indices.begin ()));
  }
  else
    indices = *indices_;
}

#ifndef PCL_NO_PRECOMPILE
#include <pcl/impl/instantiate.hpp>
#include <pcl/point_types.h>

#ifdef PCL_ONLY_CORE_POINT_TYPES
  PCL_INSTANTIATE(ExtractIndices, (pcl::PointXYZ)(pcl::PointXYZI)(pcl::PointXYZRGB)(pcl::PointXYZRGBA)(pcl::Normal)(pcl::PointXYZRGBNormal))
#else
  PCL_INSTANTIATE(ExtractIndices, PCL_POINT_TYPES)
#endif

#endif    // PCL_NO_PRECOMPILE

<commit_msg>Add PointNormal to ExtractIndices Instantiate Types<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2012, Willow Garage, Inc.
 *  Copyright (c) 2012-, Open Perception, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the copyright holder(s) nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */

#include <pcl/filters/impl/extract_indices.hpp>

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::ExtractIndices<pcl::PCLPointCloud2>::applyFilter (PCLPointCloud2 &output)
{
  if (keep_organized_)
  {
    output = *input_;
    if (negative_)
    {
      // Prepare the output and copy the data
      for (size_t i = 0; i < indices_->size (); ++i)
        for (size_t j = 0; j < output.fields.size(); ++j)
          memcpy (&output.data[(*indices_)[i] * output.point_step + output.fields[j].offset],
                  &user_filter_value_, sizeof(float));
    }
    else
    {
      // Prepare a vector holding all indices
      std::vector<int> all_indices (input_->width * input_->height);
      for (int i = 0; i < static_cast<int>(all_indices.size ()); ++i)
        all_indices[i] = i;

      std::vector<int> indices = *indices_;
      std::sort (indices.begin (), indices.end ());

      // Get the diference
      std::vector<int> remaining_indices;
      set_difference (all_indices.begin (), all_indices.end (), indices.begin (), indices.end (),
                      inserter (remaining_indices, remaining_indices.begin ()));

      // Prepare the output and copy the data
      for (size_t i = 0; i < remaining_indices.size (); ++i)
        for (size_t j = 0; j < output.fields.size(); ++j)
          memcpy (&output.data[remaining_indices[i] * output.point_step + output.fields[j].offset],
                  &user_filter_value_, sizeof(float));
    }
    if (!pcl_isfinite (user_filter_value_))
      output.is_dense = false;
    return;
  }
  if (indices_->empty () || (input_->width * input_->height == 0))
  {
    output.width = output.height = 0;
    output.data.clear ();
    // If negative, copy all the data
    if (negative_)
      output = *input_;
    return;
  }
  if (indices_->size () == (input_->width * input_->height))
  {
    // If negative, then return an empty cloud
    if (negative_)
    {
      output.width = output.height = 0;
      output.data.clear ();
    }
    // else, we need to return all points
    else
      output = *input_;
    return;
  }

  // Copy the common fields (header and fields should have already been copied)
  output.is_bigendian = input_->is_bigendian;
  output.point_step   = input_->point_step;
  output.height       = 1;
  // TODO: check the output cloud and assign is_dense based on whether the points are valid or not
  output.is_dense     = false;

  if (negative_)
  {
    // Prepare a vector holding all indices
    std::vector<int> all_indices (input_->width * input_->height);
    for (int i = 0; i < static_cast<int>(all_indices.size ()); ++i)
      all_indices[i] = i;

    std::vector<int> indices = *indices_;
    std::sort (indices.begin (), indices.end ());

    // Get the diference
    std::vector<int> remaining_indices;
    set_difference (all_indices.begin (), all_indices.end (), indices.begin (), indices.end (),
                    inserter (remaining_indices, remaining_indices.begin ()));

    // Prepare the output and copy the data
    output.width = static_cast<uint32_t> (remaining_indices.size ());
    output.data.resize (remaining_indices.size () * output.point_step);
    for (size_t i = 0; i < remaining_indices.size (); ++i)
      memcpy (&output.data[i * output.point_step], &input_->data[remaining_indices[i] * output.point_step], output.point_step);
  }
  else
  {
    // Prepare the output and copy the data
    output.width = static_cast<uint32_t> (indices_->size ());
    output.data.resize (indices_->size () * output.point_step);
    for (size_t i = 0; i < indices_->size (); ++i)
      memcpy (&output.data[i * output.point_step], &input_->data[(*indices_)[i] * output.point_step], output.point_step);
  }
  output.row_step = output.point_step * output.width;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void
pcl::ExtractIndices<pcl::PCLPointCloud2>::applyFilter (std::vector<int> &indices)
{
  if (negative_)
  {
    // If the subset is the full set
    if (indices_->size () == (input_->width * input_->height))
    {
      // Empty set copy
      indices.clear ();
      return;
    }

    // Set up the full indices set
    std::vector<int> indices_fullset (input_->width * input_->height);
    for (int p_it = 0; p_it < static_cast<int> (indices_fullset.size ()); ++p_it)
      indices_fullset[p_it] = p_it;

    // If the subset is the empty set
    if (indices_->empty () || (input_->width * input_->height == 0))
    {
      // Full set copy
      indices = indices_fullset;
      return;
    }

    // If the subset is a proper subset
    // Set up the subset input indices
    std::vector<int> indices_subset = *indices_;
    std::sort (indices_subset.begin (), indices_subset.end ());

    // Get the difference
    set_difference (indices_fullset.begin (), indices_fullset.end (), indices_subset.begin (), indices_subset.end (), inserter (indices, indices.begin ()));
  }
  else
    indices = *indices_;
}

#ifndef PCL_NO_PRECOMPILE
#include <pcl/impl/instantiate.hpp>
#include <pcl/point_types.h>

#ifdef PCL_ONLY_CORE_POINT_TYPES
  PCL_INSTANTIATE(ExtractIndices, (pcl::PointXYZ)(pcl::PointXYZI)(pcl::PointXYZRGB)(pcl::PointXYZRGBA)(pcl::Normal)(pcl::PointNormal)(pcl::PointXYZRGBNormal))
#else
  PCL_INSTANTIATE(ExtractIndices, PCL_POINT_TYPES)
#endif

#endif    // PCL_NO_PRECOMPILE

<|endoftext|>


<commit_before>/// @file
/// @author uentity
/// @date 23.04.2019
/// @brief BS kernel Python subsystem impl
/// @copyright
/// This Source Code Form is subject to the terms of the Mozilla Public License,
/// v. 2.0. If a copy of the MPL was not distributed with this file,
/// You can obtain one at https://mozilla.org/MPL/2.0/

#include <bs/python/common.h>
#include <bs/log.h>
#include <bs/kernel/errors.h>
#include <bs/tree/node.h>

#include "kimpl.h"
#include "python_subsyst_impl.h"
#include "plugins_subsyst.h"
#include "radio_subsyst.h"

#include <pybind11/functional.h>

#include <iostream>
#include <functional>

#define WITH_KMOD \
[[maybe_unused]] auto res = pykmod(this).map([&](auto kmod_ptr) { \
[[maybe_unused]] auto& kmod = *kmod_ptr;

#define END_WITH });

#define RETURN_WITH END_WITH return res.value();

#define RETURN_WITH_FAIL(err_val) END_WITH return res.value_or(err_val);

NAMESPACE_BEGIN(blue_sky::kernel::detail)
using namespace blue_sky::detail;
namespace py = pybind11;

NAMESPACE_BEGIN()

auto pykmod(const python_subsyst* v) -> result_or_err<pybind11::module*> {
	if(v) if(auto kmod = v->py_kmod())
		return { static_cast<pybind11::module*>(kmod) };
	return tl::unexpected{Error::BadPymod};
}

std::string extract_root_name(const std::string& full_name) {
	using namespace std;

	//extract user-friendly lib name from full name
	string pyl_name = full_name;
	//cut path
	string::size_type pos = pyl_name.rfind('/');
	if(pos != string::npos) pyl_name = pyl_name.substr(pos + 1, string::npos);
	pos = pyl_name.rfind('\\');
	if(pos != string::npos) pyl_name = pyl_name.substr(pos + 1, string::npos);
	//cut extension
	pyl_name = pyl_name.substr(0, pyl_name.find('.'));
	//cut "lib" prefix if exists
	if(pyl_name.compare(0, 3, string("lib")) == 0)
		pyl_name = pyl_name.substr(3, string::npos);

	return pyl_name;
}

NAMESPACE_END()

/*-----------------------------------------------------------------------------
 *  python_subsyst_impl
 *-----------------------------------------------------------------------------*/
python_subsyst_impl::python_subsyst_impl(void* kmod_ptr) :
	kmod_(nullptr)
{
	setup_py_kmod(kmod_ptr);
}

python_subsyst_impl::~python_subsyst_impl() {}

auto python_subsyst_impl::self() -> python_subsyst_impl& {
	// [NOTE] unconditional cast, because if self() is called, then instance MUST be self for sure
	return static_cast<python_subsyst_impl&>(singleton<python_subsyst>::Instance());
}

auto python_subsyst_impl::py_kmod() const -> void* { return kmod_; }

auto python_subsyst_impl::setup_py_kmod(void* kmod_ptr) -> void {
	if(!kmod_ptr) return;

	kmod_ = kmod_ptr;
	auto& kmod = *static_cast<pybind11::module*>(kmod_);

	auto& kpd = plugins_subsyst::kernel_pd();
	kmod.doc() = kpd.description;
	kpd.py_namespace = PyModule_GetName(kmod.ptr());

	// [IMPORTANT] we must clean up adapters & cache right BEFORE interpreter termination
	auto at_pyexit = py::module::import("atexit");
	at_pyexit.attr("register")(py::cpp_function{[this] {
		std::cout << "~~~ Python subsystem shutting down..." << std::endl;
		drop_adapted_cache();
		adapters_.clear();
		def_adapter_ = nullptr;

		// kick all event-based actors (normally wait until all actor handles wired into Python are released)
		{
			auto _ = py::gil_scoped_release{};
			const auto kradio = KIMPL.get_radio();
			kradio->kick_citizens();
			// stop queue while Python is still alive to gracefully finish all pending transactions
			kradio->stop_queue(true);
		}

		// force garbage collection
		auto gc = py::module::import("gc");
		gc.attr("collect")();
		gc.attr("collect")();

		std::cout << "~~~ Python subsystem down" << std::endl;
	}});
}

auto python_subsyst_impl::py_init_plugin(
	const blue_sky::detail::lib_descriptor& lib, plugin_descriptor& p_descr
) -> result_or_err<std::string> {
	return pykmod(this).and_then([&](auto kmod_ptr) -> result_or_err<std::string> {
		bs_init_py_fn init_py_fn;
		lib.load_sym("bs_init_py_subsystem", init_py_fn);
		if(!init_py_fn) return tl::make_unexpected(error{p_descr.name, kernel::Error::PythonDisabled});

		if(p_descr.py_namespace.empty())
			p_descr.py_namespace = extract_root_name(lib.fname_);

		// create submodule
		auto plugin_mod = kmod_ptr->def_submodule(p_descr.py_namespace.c_str(), p_descr.description.c_str());
		// invoke init function
		init_py_fn(&plugin_mod);

		return plugins_subsyst::kernel_pd().py_namespace + '.' + p_descr.py_namespace;
	});
}

auto python_subsyst_impl::py_add_error_closure() -> void {
WITH_KMOD
	auto err_class = (pybind11::class_<std::error_code>)kmod.attr("error_code");
	pybind11::init([](int ec) {
		return std::error_code(static_cast<Error>(ec));
	}).execute(err_class);
END_WITH
}

auto python_subsyst_impl::register_adapter(std::string obj_type_id, adapter_fn f) -> void {
	if(f)
		adapters_.insert_or_assign(std::move(obj_type_id), std::move(f));
	else {
		auto pa = adapters_.find(obj_type_id);
		if(pa != adapters_.end())
			adapters_.erase(pa);
	}
}

auto python_subsyst_impl::register_default_adapter(adapter_fn f) -> void {
	def_adapter_ = std::move(f);
}

auto python_subsyst_impl::clear_adapters() -> void {
	drop_adapted_cache();
	adapters_.clear();
	def_adapter_ = nullptr;
}

auto python_subsyst_impl::adapted_types() const -> std::vector<std::string> {
	std::vector<std::string> res(adapters_.size());
	std::transform(
		adapters_.begin(), adapters_.end(), res.begin(),
		[](const auto& A){ return A.first; }
	);
	if(def_adapter_) res.push_back("*");
	return res;
}

auto python_subsyst_impl::adapt(sp_obj source, const tree::link& L) -> py::object {
	if(!source) return py::none();

	// register link and return whether link is met for the first time
	const auto remember_link = [&](auto* data_ptr) {
		if(!lnk2obj_.try_emplace(L.id(), data_ptr).second) return false;
		// erase adapter on link delete
		L.subscribe([](const auto& ev) {
			const auto& [_, params, __] = ev;
			const auto* lid = prop::get_if<uuid>(&params, "link_id");
			if(!lid) return;

			auto& self = python_subsyst_impl::self();
			auto cached_L = self.lnk2obj_.find(*lid);
			if(cached_L == self.lnk2obj_.end()) return;

			// kill cache entry if ref counter reaches zero
			if(auto cached_A = self.acache_.find(cached_L->second); cached_A != self.acache_.end()) {
				if(--cached_A->second.second == 0) {
					auto py_guard = py::gil_scoped_acquire();
					self.acache_.erase(cached_A);
				}
			}
			self.lnk2obj_.erase(cached_L);
		}, tree::Event::LinkDeleted);
		return true;
	};

	// check if adapter already created for given object
	auto* data_ptr = source.get();
	if(auto cached_A = acache_.find(data_ptr); cached_A != acache_.end()) {
		// inc ref counter for new link
		auto& [pyobj, use_count] = cached_A->second;
		if(remember_link(data_ptr))
			++use_count;
		return pyobj;
	}

	// adapt or passthrough
	const auto adapt_and_cache = [&](auto&& afn) {
		// cache adapter with ref counter = 1
		return acache_.try_emplace(
			data_ptr, afn(std::move(source)), size_t{ remember_link(data_ptr) }
		).first->second.first;
	};

	auto pf = adapters_.find(source->type_id());
	return pf != adapters_.end() ?
		adapt_and_cache(pf->second) :
		( def_adapter_ ? adapt_and_cache(def_adapter_) : py::cast(source) );
}

auto python_subsyst_impl::get_cached_adapter(const sp_obj& obj) const -> pybind11::object {
	if(auto cached_A = acache_.find(obj.get()); cached_A != acache_.end())
		return cached_A->second.first;
	return py::none();
}

auto python_subsyst_impl::drop_adapted_cache(const sp_obj& obj) -> std::size_t {
	std::size_t res = 0;
	if(!obj) {
		res = acache_.size();
		acache_.clear();
		lnk2obj_.clear();
	}
	else if(auto cached_A = acache_.find(obj.get()); cached_A != acache_.end()) {
		// clean link -> obj ptr resolver
		auto* obj_ptr = cached_A->first;
		for(auto p_lnk = lnk2obj_.begin(); p_lnk != lnk2obj_.end();) {
			if(p_lnk->second == obj_ptr)
				p_lnk = lnk2obj_.erase(p_lnk);
			else
				++p_lnk;
		}
		// clean cached adapter
		acache_.erase(cached_A);
		res = 1;
	}
	return res;
}

NAMESPACE_END(blue_sky::kernel::detail)

NAMESPACE_BEGIN(blue_sky::python)

auto py_bind_adapters(py::module& m) -> void {
	using namespace kernel::detail;
	static auto py_kernel = &python_subsyst_impl::self;

	// export adapters manip functions
	using adapter_fn = kernel::detail::python_subsyst_impl::adapter_fn;

	m.def("register_adapter", [](std::string obj_type_id, adapter_fn f) {
			py_kernel().register_adapter(std::move(obj_type_id), std::move(f));
		}, "obj_type_id"_a, "adapter_fn"_a, "Register adapter for specified BS type"
	);
	m.def("register_default_adapter", [](adapter_fn f) {
			py_kernel().register_default_adapter(std::move(f));
		}, "adapter_fn"_a, "Register default adapter for all BS types with no adapter registered"
	);
	m.def("adapted_types", []() { return py_kernel().adapted_types(); },
		"Return list of types with registered adapters ('*' denotes default adapter)"
	);
	m.def("adapt", [](sp_obj source, const tree::link& L) {
			return py_kernel().adapt(std::move(source), L);
		}, "source"_a, "lnk"_a,
		"Make adapter for given object"
	);

	m.def("clear_adapters", []() { py_kernel().clear_adapters(); },
		"Remove all adapters (including default) for BS types"
	);
	m.def("drop_adapted_cache", [](const sp_obj& obj) {
			return py_kernel().drop_adapted_cache(obj);
		}, "obj"_a = nullptr,
		"Clear cached adapter for given object (or drop all cached adapters if object is None)"
	);
	m.def("get_cached_adapter", [](const sp_obj& obj) {
			return py_kernel().get_cached_adapter(obj);
		},
		"obj"_a, "Get cached adapter for given object (if created before, otherwise None)"
	);

	m.def("enqueue", [](py::function f) {
		KRADIO.enqueue(launch_async, [f = std::move(f)] {
			f();
			return perfect;
		});
	}, "f"_a, "Async run Python function in BS queue");
}

NAMESPACE_END(blue_sky::python)
<commit_msg>kernel/python: run adapter cleanup after link deletion in kernel's queue<commit_after>/// @file
/// @author uentity
/// @date 23.04.2019
/// @brief BS kernel Python subsystem impl
/// @copyright
/// This Source Code Form is subject to the terms of the Mozilla Public License,
/// v. 2.0. If a copy of the MPL was not distributed with this file,
/// You can obtain one at https://mozilla.org/MPL/2.0/

#include <bs/python/common.h>
#include <bs/log.h>
#include <bs/kernel/errors.h>
#include <bs/tree/node.h>

#include "kimpl.h"
#include "python_subsyst_impl.h"
#include "plugins_subsyst.h"
#include "radio_subsyst.h"

#include <pybind11/functional.h>

#include <iostream>
#include <functional>

#define WITH_KMOD \
[[maybe_unused]] auto res = pykmod(this).map([&](auto kmod_ptr) { \
[[maybe_unused]] auto& kmod = *kmod_ptr;

#define END_WITH });

#define RETURN_WITH END_WITH return res.value();

#define RETURN_WITH_FAIL(err_val) END_WITH return res.value_or(err_val);

NAMESPACE_BEGIN(blue_sky::kernel::detail)
using namespace blue_sky::detail;
namespace py = pybind11;

NAMESPACE_BEGIN()

auto pykmod(const python_subsyst* v) -> result_or_err<pybind11::module*> {
	if(v) if(auto kmod = v->py_kmod())
		return { static_cast<pybind11::module*>(kmod) };
	return tl::unexpected{Error::BadPymod};
}

std::string extract_root_name(const std::string& full_name) {
	using namespace std;

	//extract user-friendly lib name from full name
	string pyl_name = full_name;
	//cut path
	string::size_type pos = pyl_name.rfind('/');
	if(pos != string::npos) pyl_name = pyl_name.substr(pos + 1, string::npos);
	pos = pyl_name.rfind('\\');
	if(pos != string::npos) pyl_name = pyl_name.substr(pos + 1, string::npos);
	//cut extension
	pyl_name = pyl_name.substr(0, pyl_name.find('.'));
	//cut "lib" prefix if exists
	if(pyl_name.compare(0, 3, string("lib")) == 0)
		pyl_name = pyl_name.substr(3, string::npos);

	return pyl_name;
}

NAMESPACE_END()

/*-----------------------------------------------------------------------------
 *  python_subsyst_impl
 *-----------------------------------------------------------------------------*/
python_subsyst_impl::python_subsyst_impl(void* kmod_ptr) :
	kmod_(nullptr)
{
	setup_py_kmod(kmod_ptr);
}

python_subsyst_impl::~python_subsyst_impl() {}

auto python_subsyst_impl::self() -> python_subsyst_impl& {
	// [NOTE] unconditional cast, because if self() is called, then instance MUST be self for sure
	return static_cast<python_subsyst_impl&>(singleton<python_subsyst>::Instance());
}

auto python_subsyst_impl::py_kmod() const -> void* { return kmod_; }

auto python_subsyst_impl::setup_py_kmod(void* kmod_ptr) -> void {
	if(!kmod_ptr) return;

	kmod_ = kmod_ptr;
	auto& kmod = *static_cast<pybind11::module*>(kmod_);

	auto& kpd = plugins_subsyst::kernel_pd();
	kmod.doc() = kpd.description;
	kpd.py_namespace = PyModule_GetName(kmod.ptr());

	// [IMPORTANT] we must clean up adapters & cache right BEFORE interpreter termination
	auto at_pyexit = py::module::import("atexit");
	at_pyexit.attr("register")(py::cpp_function{[this] {
		std::cout << "~~~ Python subsystem shutting down..." << std::endl;
		drop_adapted_cache();
		adapters_.clear();
		def_adapter_ = nullptr;

		// kick all event-based actors (normally wait until all actor handles wired into Python are released)
		{
			auto _ = py::gil_scoped_release{};
			const auto kradio = KIMPL.get_radio();
			kradio->kick_citizens();
			// stop queue while Python is still alive to gracefully finish all pending transactions
			kradio->stop_queue(true);
		}

		// force garbage collection
		auto gc = py::module::import("gc");
		gc.attr("collect")();
		gc.attr("collect")();

		std::cout << "~~~ Python subsystem down" << std::endl;
	}});
}

auto python_subsyst_impl::py_init_plugin(
	const blue_sky::detail::lib_descriptor& lib, plugin_descriptor& p_descr
) -> result_or_err<std::string> {
	return pykmod(this).and_then([&](auto kmod_ptr) -> result_or_err<std::string> {
		bs_init_py_fn init_py_fn;
		lib.load_sym("bs_init_py_subsystem", init_py_fn);
		if(!init_py_fn) return tl::make_unexpected(error{p_descr.name, kernel::Error::PythonDisabled});

		if(p_descr.py_namespace.empty())
			p_descr.py_namespace = extract_root_name(lib.fname_);

		// create submodule
		auto plugin_mod = kmod_ptr->def_submodule(p_descr.py_namespace.c_str(), p_descr.description.c_str());
		// invoke init function
		init_py_fn(&plugin_mod);

		return plugins_subsyst::kernel_pd().py_namespace + '.' + p_descr.py_namespace;
	});
}

auto python_subsyst_impl::py_add_error_closure() -> void {
WITH_KMOD
	auto err_class = (pybind11::class_<std::error_code>)kmod.attr("error_code");
	pybind11::init([](int ec) {
		return std::error_code(static_cast<Error>(ec));
	}).execute(err_class);
END_WITH
}

auto python_subsyst_impl::register_adapter(std::string obj_type_id, adapter_fn f) -> void {
	if(f)
		adapters_.insert_or_assign(std::move(obj_type_id), std::move(f));
	else {
		auto pa = adapters_.find(obj_type_id);
		if(pa != adapters_.end())
			adapters_.erase(pa);
	}
}

auto python_subsyst_impl::register_default_adapter(adapter_fn f) -> void {
	def_adapter_ = std::move(f);
}

auto python_subsyst_impl::clear_adapters() -> void {
	drop_adapted_cache();
	adapters_.clear();
	def_adapter_ = nullptr;
}

auto python_subsyst_impl::adapted_types() const -> std::vector<std::string> {
	std::vector<std::string> res(adapters_.size());
	std::transform(
		adapters_.begin(), adapters_.end(), res.begin(),
		[](const auto& A){ return A.first; }
	);
	if(def_adapter_) res.push_back("*");
	return res;
}

auto python_subsyst_impl::adapt(sp_obj source, const tree::link& L) -> py::object {
	if(!source) return py::none();

	// register link and return whether link is met for the first time
	const auto remember_link = [&](auto* data_ptr) {
		if(!lnk2obj_.try_emplace(L.id(), data_ptr).second) return false;
		// erase adapter on link delete
		L.subscribe([](const auto& ev) {
			const auto& [_, params, __] = ev;
			const auto* lid = prop::get_if<uuid>(&params, "link_id");
			if(!lid) return;

			KRADIO.enqueue(launch_async, [lid = *lid] {
				auto py_guard = py::gil_scoped_acquire();
				auto& self = python_subsyst_impl::self();
				auto cached_L = self.lnk2obj_.find(lid);
				if(cached_L == self.lnk2obj_.end()) return perfect;

				// kill cache entry if ref counter reaches zero
				if(auto cached_A = self.acache_.find(cached_L->second); cached_A != self.acache_.end()) {
					if(--cached_A->second.second == 0)
						self.acache_.erase(cached_A);
				}
				self.lnk2obj_.erase(cached_L);
				return perfect;
			});
		}, tree::Event::LinkDeleted);
		return true;
	};

	// check if adapter already created for given object
	auto* data_ptr = source.get();
	if(auto cached_A = acache_.find(data_ptr); cached_A != acache_.end()) {
		// inc ref counter for new link
		auto& [pyobj, use_count] = cached_A->second;
		if(remember_link(data_ptr))
			++use_count;
		return pyobj;
	}

	// adapt or passthrough
	const auto adapt_and_cache = [&](auto&& afn) {
		// cache adapter with ref counter = 1
		return acache_.try_emplace(
			data_ptr, afn(std::move(source)), size_t{ remember_link(data_ptr) }
		).first->second.first;
	};

	auto pf = adapters_.find(source->type_id());
	return pf != adapters_.end() ?
		adapt_and_cache(pf->second) :
		( def_adapter_ ? adapt_and_cache(def_adapter_) : py::cast(source) );
}

auto python_subsyst_impl::get_cached_adapter(const sp_obj& obj) const -> pybind11::object {
	if(auto cached_A = acache_.find(obj.get()); cached_A != acache_.end())
		return cached_A->second.first;
	return py::none();
}

auto python_subsyst_impl::drop_adapted_cache(const sp_obj& obj) -> std::size_t {
	std::size_t res = 0;
	if(!obj) {
		res = acache_.size();
		acache_.clear();
		lnk2obj_.clear();
	}
	else if(auto cached_A = acache_.find(obj.get()); cached_A != acache_.end()) {
		// clean link -> obj ptr resolver
		auto* obj_ptr = cached_A->first;
		for(auto p_lnk = lnk2obj_.begin(); p_lnk != lnk2obj_.end();) {
			if(p_lnk->second == obj_ptr)
				p_lnk = lnk2obj_.erase(p_lnk);
			else
				++p_lnk;
		}
		// clean cached adapter
		acache_.erase(cached_A);
		res = 1;
	}
	return res;
}

NAMESPACE_END(blue_sky::kernel::detail)

NAMESPACE_BEGIN(blue_sky::python)

auto py_bind_adapters(py::module& m) -> void {
	using namespace kernel::detail;
	static auto py_kernel = &python_subsyst_impl::self;

	// export adapters manip functions
	using adapter_fn = kernel::detail::python_subsyst_impl::adapter_fn;

	m.def("register_adapter", [](std::string obj_type_id, adapter_fn f) {
			py_kernel().register_adapter(std::move(obj_type_id), std::move(f));
		}, "obj_type_id"_a, "adapter_fn"_a, "Register adapter for specified BS type"
	);
	m.def("register_default_adapter", [](adapter_fn f) {
			py_kernel().register_default_adapter(std::move(f));
		}, "adapter_fn"_a, "Register default adapter for all BS types with no adapter registered"
	);
	m.def("adapted_types", []() { return py_kernel().adapted_types(); },
		"Return list of types with registered adapters ('*' denotes default adapter)"
	);
	m.def("adapt", [](sp_obj source, const tree::link& L) {
			return py_kernel().adapt(std::move(source), L);
		}, "source"_a, "lnk"_a,
		"Make adapter for given object"
	);

	m.def("clear_adapters", []() { py_kernel().clear_adapters(); },
		"Remove all adapters (including default) for BS types"
	);
	m.def("drop_adapted_cache", [](const sp_obj& obj) {
			return py_kernel().drop_adapted_cache(obj);
		}, "obj"_a = nullptr,
		"Clear cached adapter for given object (or drop all cached adapters if object is None)"
	);
	m.def("get_cached_adapter", [](const sp_obj& obj) {
			return py_kernel().get_cached_adapter(obj);
		},
		"obj"_a, "Get cached adapter for given object (if created before, otherwise None)"
	);

	m.def("enqueue", [](py::function f) {
		KRADIO.enqueue(launch_async, [f = std::move(f)] {
			f();
			return perfect;
		});
	}, "f"_a, "Async run Python function in BS queue");
}

NAMESPACE_END(blue_sky::python)
<|endoftext|>


<commit_before>#include "follower.hpp"
using namespace cv;

const unsigned char minHue = 12;
const unsigned char maxHue = 37;
const unsigned char minSat = 60;
const unsigned char maxSat = 255;
const unsigned char minVal = 60;
const unsigned char maxVal = 255;

Follower::Follower()
    : m_st(Unknown)
{}

Follower::~Follower()
{}

void Follower::process(const cv::Mat& img)
{
    Mat binary(img.size(), CV_8UC1);
    /* Creating the binary picture. */
    for(int i = 0; i < img.rows; ++i) {
        for(int j = 0; j < img.cols; ++j) {
            auto vec = img.at<Vec<unsigned char,3>>(i,j);
            if(vec[0] >= minHue && vec[0] <= maxHue
                    && vec[1] >= minSat && vec[1] <= maxSat
                    && vec[2] >= minVal && vec[2] <= minVal)
                binary.at<unsigned char>(i,j) = 255;
            else
                binary.at<unsigned char>(i,j) = 0;
        }
    }
    imshow("Binary", binary);

    /* Getting contours. */
    std::vector<std::vector<Point>> contours;
    std::vector<Vec4i> hierarchy;
    findContours(binary, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, Point(0,0));

    /* Find center of biggest. */
    double maxArea = 0.0f;
    Point center;
    for(std::vector<Point> ctr : contours) {
        double area = contourArea(ctr);
        if(area > maxArea) {
            maxArea = area;
            Rect r = boundingRect(ctr);
            center.x = r.x + r.width / 2;
            center.y = r.y + r.height / 2;
        }
    }

    /* Set status depending on center. */
    if(maxArea < 100)
        m_st = Unknown;
    else if(center.x < img.size().width / 3)
        m_st = Left;
    else if(center.x < 2*img.size().width / 3)
        m_st = Center;
    else
        m_st = Right;
}

const char* Follower::status() const
{
    switch(m_st) {
        case Left:    return "left";
        case Right:   return "right";
        case Center:  return "center";
        case Unknown: return "unknown";
    }
    return "error";
}

Follower::Status Follower::pos() const
{
    return m_st;
}

<commit_msg>Fixed bugs in follower.cpp.<commit_after>#include "follower.hpp"
using namespace cv;

const unsigned char minHue = 75;
const unsigned char maxHue = 114;
const unsigned char minSat = 0;
const unsigned char maxSat = 255;
const unsigned char minVal = 0;
const unsigned char maxVal = 255;

Follower::Follower()
    : m_st(Unknown)
{}

Follower::~Follower()
{}

void Follower::process(const cv::Mat& img)
{
    Mat hsv;
    cvtColor(img, hsv, CV_BGR2HSV);

    Mat binary(img.size(), CV_8UC1);
    /* Creating the binary picture. */
    for(int i = 0; i < hsv.rows; ++i) {
        for(int j = 0; j < hsv.cols; ++j) {
            auto vec = hsv.at<Vec<unsigned char,3>>(i,j);
            if(vec[0] >= minHue && vec[0] <= maxHue
                    && vec[1] >= minSat && vec[1] <= maxSat
                    && vec[2] >= minVal && vec[2] <= maxVal)
                binary.at<unsigned char>(i,j) = 255;
            else
                binary.at<unsigned char>(i,j) = 0;
        }
    }

    /* Getting contours. */
    std::vector<std::vector<Point>> contours;
    std::vector<Vec4i> hierarchy;
    findContours(binary, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, Point(0,0));

    /* Find center of biggest. */
    double maxArea = 0.0f;
    Point center;
    for(std::vector<Point> ctr : contours) {
        double area = contourArea(ctr);
        if(area > maxArea) {
            maxArea = area;
            Rect r = boundingRect(ctr);
            center.x = r.x + r.width / 2;
            center.y = r.y + r.height / 2;
        }
    }

    Mat todraw;
    cvtColor(binary, todraw, CV_GRAY2BGR);
    if(maxArea >= 100)
        circle(todraw, center, 5, Scalar(0,0,255), 3);
    imshow("Result", todraw);
    waitKey(10);

    /* Set status depending on center. */
    if(maxArea < 100)
        m_st = Unknown;
    else if(center.x < img.size().width / 3)
        m_st = Left;
    else if(center.x < 2*img.size().width / 3)
        m_st = Center;
    else
        m_st = Right;
}

const char* Follower::status() const
{
    switch(m_st) {
        case Left:    return "left";
        case Right:   return "right";
        case Center:  return "center";
        case Unknown: return "unknown";
    }
    return "error";
}

Follower::Status Follower::pos() const
{
    return m_st;
}

<|endoftext|>