<commit_before>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include "arch/io/disk/conflict_resolving.hpp"

#include <deque>
#include <map>

#include "containers/printf_buffer.hpp"
#include "perfmon/perfmon.hpp"

void debug_print(printf_buffer_t *buf,
                 const conflict_resolving_diskmgr_action_t &action) {
    buf->appendf("cr_diskmgr_action{conflict_count=%d}<", action.conflict_count);
    const accounting_diskmgr_action_t &parent_action = action;
    debug_print(buf, parent_action);
}

conflict_resolving_diskmgr_t::conflict_resolving_diskmgr_t(perfmon_collection_t *stats) :
    conflict_sampler(secs_to_ticks(1), true),
    conflict_sampler_membership(stats, &conflict_sampler, "conflict")
{ }

conflict_resolving_diskmgr_t::~conflict_resolving_diskmgr_t() {
#ifndef NDEBUG
    /* Make sure there are no requests still out. */
    for (std::map<fd_t, std::map<int64_t, std::deque<action_t *> > >::iterator
             fd_t_chunk_queues = all_chunk_queues.begin();
         fd_t_chunk_queues != all_chunk_queues.end();
         ++fd_t_chunk_queues) {
        rassert(fd_t_chunk_queues->second.empty());
    }
    for (auto it = resize_waiter_queues.begin();
         it != resize_waiter_queues.end();
         ++it) {
        rassert(it->second.empty());
    }
    for (auto it = resize_active.begin(); it != resize_active.end(); ++it) {
        rassert(it->second == 0);
    }
#endif
}

// Fills dest's bufs with data from source.  source's range is a superset of dest's.
void copy_full_action_buf(pool_diskmgr_action_t *dest, pool_diskmgr_action_t *source,
                          const size_t offset_into_source) {
    guarantee(source->get_offset() <= dest->get_offset()
              && source->get_offset() + source->get_count() >= dest->get_offset() + dest->get_count());

    iovec *dest_vecs;
    size_t dest_size;
    dest->get_bufs(&dest_vecs, &dest_size);
    iovec *source_vecs;
    size_t source_size;
    source->get_bufs(&source_vecs, &source_size);

    fill_bufs_from_source(dest_vecs, dest_size, source_vecs, source_size, offset_into_source);
};

void conflict_resolving_diskmgr_t::submit(action_t *action) {
    action->conflict_count = 0;

    if (resize_active[action->get_fd()] > 0) {
        /* There is a resizing operation going on. Get in line for it. */

        action->conflict_count += resize_active[action->get_fd()];
        resize_waiter_queues[action->get_fd()].push_back(action);
    }

    if (action->get_is_resize()) {
        /* Block out subsequent operations; reads, writes and resizes alike. */
        ++resize_active[action->get_fd()];
    } else {
        std::map<int64_t, std::deque<action_t *> > *chunk_queues = &all_chunk_queues[action->get_fd()];
        /* Determine the range of file-blocks that this action spans */
        int64_t start;
        int64_t end;
        get_range(action, &start, &end);

        /* If this is a read, we check whether there is a write from which we
        can "steal" data to satisfy the read immediately. We currently only
        do this if there is a single write operation that provides all the data
        that we need, we don't combine multiple writes that affect different parts
        of the read request. */
        if (action->get_is_read()) {
            /* The logic here is a bit tricky. What we do is the following:
            First we check the queue for the first chunk. If there is a write that
            can satisfy us, it must span all chunks and therefore be on the first
            chunk's queue. We pick the latest write that exists on that queue, so
            we get the most recent version of the data. We then check the other
            chunks and make sure that the same write is also the latest write on
            these queues. If there is another more recent write, we cannot take
            the data from our initial write, because a subrange of it will be
            overwritten by that other write. As an optimization, we could
            still use the data from the initial write and just replace that part of
            it, using the data from the other write. We leave this extension as an
            exercise to the reader. */

            action_t *latest_write = NULL;

            std::map<int64_t, std::deque<action_t*> >::iterator it;
            it = chunk_queues->find(start);
            if (it != chunk_queues->end()) {
                std::deque<action_t *> &queue = it->second;

                /* Locate the latest write on the queue */
                std::deque<action_t *>::reverse_iterator qrit;
                for (qrit = queue.rbegin(); qrit != queue.rend(); ++qrit) {
                    if ((*qrit)->get_is_write()) {
                        /* We found it! Check if it's of any use to us...
                        If the range it was supposed to write is a superrange of
                        our range, then it's a valid candidate. */
                        if ((*qrit)->get_offset() <= action->get_offset() &&
                                (*qrit)->get_offset() + (*qrit)->get_count() >= action->get_offset() + action->get_count() ) {

                            latest_write = *qrit;
                        }

                        /* No other write on the queue can be the latest one. Stop looking. */
                        break;
                    }
                }
            }

            /* Now check that latest_write is also latest for all other chunks.
            Keep on validating as long as we have a latest_write candidate. */
            for (int64_t block = start; latest_write && block < end; block++) {
                it = chunk_queues->find(start);
                rassert(it != chunk_queues->end()); // Note: At least latest_write should be there!
                std::deque<action_t *> &queue = it->second;

                /* Locate the latest write on the queue */
                std::deque<action_t *>::reverse_iterator qrit;
                for (qrit = queue.rbegin(); qrit != queue.rend(); ++qrit) {
                    if ((*qrit)->get_is_write()) {

                        if (*qrit != latest_write) {
                            /* This write is more recent than latest_write, so latest_write
                            isn't actually the latest one over the whole range,
                            This renders it unusable for us. */
                            latest_write = NULL;
                        }

                        /* No other write on the queue can be the latest one. Stop looking. */
                        break;
                    }
                }
            }

            if (latest_write) {
                copy_full_action_buf(action, latest_write, action->get_offset() - latest_write->get_offset());

                action->set_successful_due_to_conflict();
                done_fun(action);
                return;
            }
        }

        /* Determine if there are chunk conflicts and put ourself on the queues */
        for (int64_t block = start; block < end; block++) {
            std::map<int64_t, std::deque<action_t*> >::iterator it;
            it = chunk_queues->find(block);

            if (it != chunk_queues->end()) {
                /* We conflict on this block. */
                action->conflict_count++;
            }

            /* Put ourself on the queue for this chunk */
            if (it == chunk_queues->end()) {
                /* Start a queue because there isn't one already */
                it = chunk_queues->insert(it, std::make_pair(block, std::deque<action_t *>()));
            }
            rassert(it->first == block);
            it->second.push_back(action);
        }
    } // if (!action->get_is_resize())

    /* If there are no conflicts, we can start right away. */
    if (action->conflict_count == 0) {
        submit_action_downwards(action);
    } else {
        // TODO: Refine the perfmon such that it measures the actual time that ops spend
        // in a waiting state
        conflict_sampler.record(1);
    }
}

void conflict_resolving_diskmgr_t::submit_action_downwards(action_t *action) {
    accounting_diskmgr_action_t *action_payload =
        static_cast<accounting_diskmgr_action_t *>(action);
    submit_fun(action_payload);
}

void conflict_resolving_diskmgr_t::done(accounting_diskmgr_action_t *payload) {
    /* The only payloads we get back via done() should be payloads that we sent into
    submit_fun(), which means they should actually be action_t objects secretly. */
    action_t *action = static_cast<action_t *>(payload);

    if (action->get_is_resize()) {
        /* Mark the resize as done. */
        rassert(resize_active[action->get_fd()] > 0);
        --resize_active[action->get_fd()];

        /* Resume all operations that were waiting for us. */
        std::deque<action_t *> &waiter_queue = resize_waiter_queues[action->get_fd()];

        std::vector<action_t *> waiters_to_unblock;
        waiters_to_unblock.reserve(waiter_queue.size());

        while (!waiter_queue.empty()) {
            /* Decrease the conflict count for the oldest remaining waiter. */
            action_t *waiter = waiter_queue.front();
            waiter_queue.pop_front();

            rassert(waiter->conflict_count > 0);
            waiter->conflict_count--;

            /* Resizes only wait for other resizes. So if we get here, we must
            be the last thing that `waiter` has been waiting for. */
            rassert(!waiter->get_is_resize() || waiter->conflict_count == 0);

            if (waiter->conflict_count == 0) {
                /* The waiter isn't waiting on anything else. Unblock it. */
                waiters_to_unblock.push_back(waiter);

                if (waiter->get_is_resize()) {
                    /* We are about to submit another resize. waiters that come after
                    this must remain on the resize_waiter_queue, because they
                    are still waiting for that resize. Continue by
                    just decrementing the conflict_count, but not
                    popping the waiters off the queue nor unblocking them. */
                    for (auto it = waiter_queue.begin();
                         it != waiter_queue.end();
                         ++it) {
                        --(*it)->conflict_count;
                        /* The waiter must at least still be waiting for the
                        resize we are about to unblock. */
                        rassert((*it)->conflict_count > 0);
                    }

                    /* Sorry, the remaining waiters must wait for a little longer. */
                    break;
                }
            }
        }

        /* Now actually unblock some waiters. */
        for (size_t i = 0; i < waiters_to_unblock.size(); ++i) {
            submit_action_downwards(waiters_to_unblock[i]);
        }

    } else {
        std::map<int64_t, std::deque<action_t *> > *chunk_queues = &all_chunk_queues[action->get_fd()];

        int64_t start, end;
        get_range(action, &start, &end);

        /* Visit every block and see if anything is blocking on us. As we iterate
        over block indices, we iterate through the corresponding entries in the map. */

        std::map<int64_t, std::deque<action_t*> >::iterator it = chunk_queues->find(start);
        for (int64_t block = start; block < end; block++) {
            /* We can assert this because at least we must still be on the queue */
            rassert(it != chunk_queues->end() && it->first == block);

            std::deque<action_t *> &queue = it->second;

            /* Remove ourselves from the queue */
            rassert(queue.front() == action);
            queue.pop_front();

            if (!queue.empty()) {
                /* Continue with the next chunk queue.
                We have to move on now, because we might call done() recursively and that might
                invalidate the iterator. */
                ++it;

                /* Something was blocking on us for this block. Get the first waiter from the queue. */
                action_t *waiter = queue.front();

                rassert(waiter->conflict_count > 0);
                waiter->conflict_count--;

                if (waiter->conflict_count == 0) {
                    /* We were the last thing it was waiting on */

                    /* If the waiter is a read, and the range it was supposed to read is a subrange of
                    our range, then we can just fill its buffer directly instead of going to disk. */
                    if (waiter->get_is_read() &&
                            waiter->get_offset() >= action->get_offset() &&
                            waiter->get_offset() + waiter->get_count() <= action->get_offset() + action->get_count() ) {

                        copy_full_action_buf(waiter, action, waiter->get_offset() - action->get_offset());

                        waiter->set_successful_due_to_conflict();

                        /* Recursively calling done() is safe. "waiter" must end at or before
                        our current location, or else its conflict_count would still be nonzero.
                        Therefore it will not touch any part of the multimap that we have not
                        yet gotten to. If it touches the queue that we popped it from, that's
                        also safe, because we've already moved our iterator past it.
                        Note that we can potentially lose some short-circuit opportunities,
                        because we might be able to provide a larger range than the request
                        that we just provided a subset of our data to. So that request might
                        not be able to short-circuit another watier, while we might have
                        been able. This should be more of an academic concern though. */
                        done(waiter);

                    } else {
                        /* The shortcut didn't work out; do things the normal way */
                        submit_action_downwards(waiter);
                    }
                }
            } else {
                /* The queue is empty, erase it. */
                chunk_queues->erase(it++);
            }
        }
    }

    done_fun(action);
}
<commit_msg>Fix for #2500<commit_after>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include "arch/io/disk/conflict_resolving.hpp"

#include <deque>
#include <map>

#include "containers/printf_buffer.hpp"
#include "perfmon/perfmon.hpp"

void debug_print(printf_buffer_t *buf,
                 const conflict_resolving_diskmgr_action_t &action) {
    buf->appendf("cr_diskmgr_action{conflict_count=%d}<", action.conflict_count);
    const accounting_diskmgr_action_t &parent_action = action;
    debug_print(buf, parent_action);
}

conflict_resolving_diskmgr_t::conflict_resolving_diskmgr_t(perfmon_collection_t *stats) :
    conflict_sampler(secs_to_ticks(1), true),
    conflict_sampler_membership(stats, &conflict_sampler, "conflict")
{ }

conflict_resolving_diskmgr_t::~conflict_resolving_diskmgr_t() {
#ifndef NDEBUG
    /* Make sure there are no requests still out. */
    for (std::map<fd_t, std::map<int64_t, std::deque<action_t *> > >::iterator
             fd_t_chunk_queues = all_chunk_queues.begin();
         fd_t_chunk_queues != all_chunk_queues.end();
         ++fd_t_chunk_queues) {
        rassert(fd_t_chunk_queues->second.empty());
    }
    for (auto it = resize_waiter_queues.begin();
         it != resize_waiter_queues.end();
         ++it) {
        rassert(it->second.empty());
    }
    for (auto it = resize_active.begin(); it != resize_active.end(); ++it) {
        rassert(it->second == 0);
    }
#endif
}

// Fills dest's bufs with data from source.  source's range is a superset of dest's.
void copy_full_action_buf(pool_diskmgr_action_t *dest, pool_diskmgr_action_t *source,
                          const size_t offset_into_source) {
    guarantee(source->get_offset() <= dest->get_offset()
              && source->get_offset() + source->get_count() >= dest->get_offset() + dest->get_count());

    iovec *dest_vecs;
    size_t dest_size;
    dest->get_bufs(&dest_vecs, &dest_size);
    iovec *source_vecs;
    size_t source_size;
    source->get_bufs(&source_vecs, &source_size);

    fill_bufs_from_source(dest_vecs, dest_size, source_vecs, source_size, offset_into_source);
};

void conflict_resolving_diskmgr_t::submit(action_t *action) {
    action->conflict_count = 0;

    if (action->get_is_resize()) {
        /* Block out subsequent operations; reads, writes and resizes alike. */
        ++resize_active[action->get_fd()];
    } else {
        std::map<int64_t, std::deque<action_t *> > *chunk_queues = &all_chunk_queues[action->get_fd()];
        /* Determine the range of file-blocks that this action spans */
        int64_t start;
        int64_t end;
        get_range(action, &start, &end);

        /* If this is a read, we check whether there is a write from which we
        can "steal" data to satisfy the read immediately. We currently only
        do this if there is a single write operation that provides all the data
        that we need, we don't combine multiple writes that affect different parts
        of the read request. */
        if (action->get_is_read()) {
            /* The logic here is a bit tricky. What we do is the following:
            First we check the queue for the first chunk. If there is a write that
            can satisfy us, it must span all chunks and therefore be on the first
            chunk's queue. We pick the latest write that exists on that queue, so
            we get the most recent version of the data. We then check the other
            chunks and make sure that the same write is also the latest write on
            these queues. If there is another more recent write, we cannot take
            the data from our initial write, because a subrange of it will be
            overwritten by that other write. As an optimization, we could
            still use the data from the initial write and just replace that part of
            it, using the data from the other write. We leave this extension as an
            exercise to the reader. */

            action_t *latest_write = NULL;

            std::map<int64_t, std::deque<action_t*> >::iterator it;
            it = chunk_queues->find(start);
            if (it != chunk_queues->end()) {
                std::deque<action_t *> &queue = it->second;

                /* Locate the latest write on the queue */
                std::deque<action_t *>::reverse_iterator qrit;
                for (qrit = queue.rbegin(); qrit != queue.rend(); ++qrit) {
                    if ((*qrit)->get_is_write()) {
                        /* We found it! Check if it's of any use to us...
                        If the range it was supposed to write is a superrange of
                        our range, then it's a valid candidate. */
                        if ((*qrit)->get_offset() <= action->get_offset() &&
                                (*qrit)->get_offset() + (*qrit)->get_count() >= action->get_offset() + action->get_count() ) {

                            latest_write = *qrit;
                        }

                        /* No other write on the queue can be the latest one. Stop looking. */
                        break;
                    }
                }
            }

            /* Now check that latest_write is also latest for all other chunks.
            Keep on validating as long as we have a latest_write candidate. */
            for (int64_t block = start; latest_write && block < end; block++) {
                it = chunk_queues->find(start);
                rassert(it != chunk_queues->end()); // Note: At least latest_write should be there!
                std::deque<action_t *> &queue = it->second;

                /* Locate the latest write on the queue */
                std::deque<action_t *>::reverse_iterator qrit;
                for (qrit = queue.rbegin(); qrit != queue.rend(); ++qrit) {
                    if ((*qrit)->get_is_write()) {

                        if (*qrit != latest_write) {
                            /* This write is more recent than latest_write, so latest_write
                            isn't actually the latest one over the whole range,
                            This renders it unusable for us. */
                            latest_write = NULL;
                        }

                        /* No other write on the queue can be the latest one. Stop looking. */
                        break;
                    }
                }
            }

            if (latest_write) {
                guarantee(action->conflict_count == 0,
                          "Short-circuited a read despite it already being on a "
                          "waiter queue.");

                copy_full_action_buf(action, latest_write, action->get_offset() - latest_write->get_offset());

                action->set_successful_due_to_conflict();
                done_fun(action);
                return;
            }
        }

        /* Determine if there are chunk conflicts and put ourself on the queues */
        for (int64_t block = start; block < end; block++) {
            std::map<int64_t, std::deque<action_t*> >::iterator it;
            it = chunk_queues->find(block);

            if (it != chunk_queues->end()) {
                /* We conflict on this block. */
                action->conflict_count++;
            }

            /* Put ourself on the queue for this chunk */
            if (it == chunk_queues->end()) {
                /* Start a queue because there isn't one already */
                it = chunk_queues->insert(it, std::make_pair(block, std::deque<action_t *>()));
            }
            rassert(it->first == block);
            it->second.push_back(action);
        }
    } // if (!action->get_is_resize())

    if (resize_active[action->get_fd()] > 0) {
        /* There is a resizing operation going on. Get in line for it. */

        action->conflict_count += resize_active[action->get_fd()];
        resize_waiter_queues[action->get_fd()].push_back(action);
    }

    /* If there are no conflicts, we can start right away. */
    if (action->conflict_count == 0) {
        submit_action_downwards(action);
    } else {
        // TODO: Refine the perfmon such that it measures the actual time that ops spend
        // in a waiting state
        conflict_sampler.record(1);
    }
}

void conflict_resolving_diskmgr_t::submit_action_downwards(action_t *action) {
    accounting_diskmgr_action_t *action_payload =
        static_cast<accounting_diskmgr_action_t *>(action);
    submit_fun(action_payload);
}

void conflict_resolving_diskmgr_t::done(accounting_diskmgr_action_t *payload) {
    /* The only payloads we get back via done() should be payloads that we sent into
    submit_fun(), which means they should actually be action_t objects secretly. */
    action_t *action = static_cast<action_t *>(payload);

    if (action->get_is_resize()) {
        /* Mark the resize as done. */
        rassert(resize_active[action->get_fd()] > 0);
        --resize_active[action->get_fd()];

        /* Resume all operations that were waiting for us. */
        std::deque<action_t *> &waiter_queue = resize_waiter_queues[action->get_fd()];

        std::vector<action_t *> waiters_to_unblock;
        waiters_to_unblock.reserve(waiter_queue.size());

        while (!waiter_queue.empty()) {
            /* Decrease the conflict count for the oldest remaining waiter. */
            action_t *waiter = waiter_queue.front();
            waiter_queue.pop_front();

            rassert(waiter->conflict_count > 0);
            waiter->conflict_count--;

            /* Resizes only wait for other resizes. So if we get here, we must
            be the last thing that `waiter` has been waiting for. */
            rassert(!waiter->get_is_resize() || waiter->conflict_count == 0);

            if (waiter->conflict_count == 0) {
                /* The waiter isn't waiting on anything else. Unblock it. */
                waiters_to_unblock.push_back(waiter);

                if (waiter->get_is_resize()) {
                    /* We are about to submit another resize. waiters that come after
                    this must remain on the resize_waiter_queue, because they
                    are still waiting for that resize. Continue by
                    just decrementing the conflict_count, but not
                    popping the waiters off the queue nor unblocking them. */
                    for (auto it = waiter_queue.begin();
                         it != waiter_queue.end();
                         ++it) {
                        --(*it)->conflict_count;
                        /* The waiter must at least still be waiting for the
                        resize we are about to unblock. */
                        rassert((*it)->conflict_count > 0);
                    }

                    /* Sorry, the remaining waiters must wait for a little longer. */
                    break;
                }
            }
        }

        /* Now actually unblock some waiters. */
        for (size_t i = 0; i < waiters_to_unblock.size(); ++i) {
            submit_action_downwards(waiters_to_unblock[i]);
        }

    } else {
        std::map<int64_t, std::deque<action_t *> > *chunk_queues = &all_chunk_queues[action->get_fd()];

        int64_t start, end;
        get_range(action, &start, &end);

        /* Visit every block and see if anything is blocking on us. As we iterate
        over block indices, we iterate through the corresponding entries in the map. */

        std::map<int64_t, std::deque<action_t*> >::iterator it = chunk_queues->find(start);
        for (int64_t block = start; block < end; block++) {
            /* We can assert this because at least we must still be on the queue */
            rassert(it != chunk_queues->end() && it->first == block);

            std::deque<action_t *> &queue = it->second;

            /* Remove ourselves from the queue */
            rassert(queue.front() == action);
            queue.pop_front();

            if (!queue.empty()) {
                /* Continue with the next chunk queue.
                We have to move on now, because we might call done() recursively and that might
                invalidate the iterator. */
                ++it;

                /* Something was blocking on us for this block. Get the first waiter from the queue. */
                action_t *waiter = queue.front();

                rassert(waiter->conflict_count > 0);
                waiter->conflict_count--;

                if (waiter->conflict_count == 0) {
                    /* We were the last thing it was waiting on */

                    /* If the waiter is a read, and the range it was supposed to read is a subrange of
                    our range, then we can just fill its buffer directly instead of going to disk. */
                    if (waiter->get_is_read() &&
                            waiter->get_offset() >= action->get_offset() &&
                            waiter->get_offset() + waiter->get_count() <= action->get_offset() + action->get_count() ) {

                        copy_full_action_buf(waiter, action, waiter->get_offset() - action->get_offset());

                        waiter->set_successful_due_to_conflict();

                        /* Recursively calling done() is safe. "waiter" must end at or before
                        our current location, or else its conflict_count would still be nonzero.
                        Therefore it will not touch any part of the multimap that we have not
                        yet gotten to. If it touches the queue that we popped it from, that's
                        also safe, because we've already moved our iterator past it.
                        Note that we can potentially lose some short-circuit opportunities,
                        because we might be able to provide a larger range than the request
                        that we just provided a subset of our data to. So that request might
                        not be able to short-circuit another watier, while we might have
                        been able. This should be more of an academic concern though. */
                        done(waiter);

                    } else {
                        /* The shortcut didn't work out; do things the normal way */
                        submit_action_downwards(waiter);
                    }
                }
            } else {
                /* The queue is empty, erase it. */
                chunk_queues->erase(it++);
            }
        }
    }

    done_fun(action);
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
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 author 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.

*/

#ifdef TORRENT_DEBUG

#ifdef __GNUC__

#include <cxxabi.h>
#include <string>
#include <cstring>
#include <stdlib.h>

std::string demangle(char const* name)
{
// in case this string comes
	// this is needed on linux
	char const* start = strchr(name, '(');
	if (start != 0)
	{
		++start;
	}
	else
	{
		// this is needed on macos x
		start = strstr(name, "0x");
		if (start != 0)
		{
			start = strchr(start, ' ');
			if (start != 0) ++start;
			else start = name;
		}
		else start = name;
	}

	char const* end = strchr(start, '+');
	if (end) while (*(end-1) == ' ') --end;

	std::string in;
	if (end == 0) in.assign(start);
	else in.assign(start, end);

	size_t len;
	int status;
	char* unmangled = ::abi::__cxa_demangle(in.c_str(), 0, &len, &status);
	if (unmangled == 0) return in;
	std::string ret(unmangled);
	free(unmangled);
	return ret;
}

#endif

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>

// execinfo.h is available in the MacOS X 10.5 SDK. I
// don't know of a define to distiguish between SDKs, so
// for now, all Mac builds are assumed to be using 10.5
// for debug builds. If this fails for you, just remove
// the __APPLE__ check
#if (defined __linux__ || defined __APPLE__)
#include <execinfo.h>

void print_backtrace(char const* label)
{
	void* stack[50];
	int size = backtrace(stack, 50);
	char** symbols = backtrace_symbols(stack, size);

	fprintf(stderr, "%s\n", label);
	for (int i = 1; i < size; ++i)
	{
		fprintf(stderr, "%d: %s\n", i, demangle(symbols[i]).c_str());
	}

	free(symbols);
}
#else

void print_backtrace(char const* label) {}

#endif

void assert_fail(char const* expr, int line, char const* file, char const* function)
{

	fprintf(stderr, "assertion failed. Please file a bugreport at "
		"http://code.rasterbar.com/libtorrent/newticket\n"
		"Please include the following information:\n\n"
		"file: '%s'\n"
		"line: %d\n"
		"function: %s\n"
		"expression: %s\n", file, line, function, expr);

	print_backtrace("stack:");

 	// send SIGINT to the current process
 	// to break into the debugger
 	raise(SIGINT);
 	abort();
}

#else

void assert_fail(char const* expr, int line, char const* file, char const* function) {}

#endif

<commit_msg>fix assert.cpp mac build to take sdk version into account<commit_after>/*

Copyright (c) 2007, Arvid Norberg
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 author 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.

*/

#ifdef TORRENT_DEBUG

#ifdef __APPLE__
#include <AvailabilityMacros.h>
#endif

#ifdef __GNUC__

#include <cxxabi.h>
#include <string>
#include <cstring>
#include <stdlib.h>

std::string demangle(char const* name)
{
// in case this string comes
	// this is needed on linux
	char const* start = strchr(name, '(');
	if (start != 0)
	{
		++start;
	}
	else
	{
		// this is needed on macos x
		start = strstr(name, "0x");
		if (start != 0)
		{
			start = strchr(start, ' ');
			if (start != 0) ++start;
			else start = name;
		}
		else start = name;
	}

	char const* end = strchr(start, '+');
	if (end) while (*(end-1) == ' ') --end;

	std::string in;
	if (end == 0) in.assign(start);
	else in.assign(start, end);

	size_t len;
	int status;
	char* unmangled = ::abi::__cxa_demangle(in.c_str(), 0, &len, &status);
	if (unmangled == 0) return in;
	std::string ret(unmangled);
	free(unmangled);
	return ret;
}

#endif

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>

// execinfo.h is available in the MacOS X 10.5 SDK.
#if (defined __linux__ || (defined __APPLE__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050))
#include <execinfo.h>

void print_backtrace(char const* label)
{
	void* stack[50];
	int size = backtrace(stack, 50);
	char** symbols = backtrace_symbols(stack, size);

	fprintf(stderr, "%s\n", label);
	for (int i = 1; i < size; ++i)
	{
		fprintf(stderr, "%d: %s\n", i, demangle(symbols[i]).c_str());
	}

	free(symbols);
}
#else

void print_backtrace(char const* label) {}

#endif

void assert_fail(char const* expr, int line, char const* file, char const* function)
{

	fprintf(stderr, "assertion failed. Please file a bugreport at "
		"http://code.rasterbar.com/libtorrent/newticket\n"
		"Please include the following information:\n\n"
		"file: '%s'\n"
		"line: %d\n"
		"function: %s\n"
		"expression: %s\n", file, line, function, expr);

	print_backtrace("stack:");

 	// send SIGINT to the current process
 	// to break into the debugger
 	raise(SIGINT);
 	abort();
}

#else

void assert_fail(char const* expr, int line, char const* file, char const* function) {}

#endif

<|endoftext|>


<commit_before>#include <iostream>
#include <cstdlib>
#include <signal.h>

#include <libfreenect2/libfreenect2.hpp>
#include <libfreenect2/frame_listener_impl.h>
#include <libfreenect2/registration.h>
#include <libfreenect2/packet_pipeline.h>
#include <libfreenect2/logger.h>

#include "src/navirice.h"

using namespace std;
bool keep_alive = true;

#define PORT 29000

navirice::ImageDistributionServer* server;

void finish_program(int input){
	keep_alive = false;
}

class IOCW;

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

	// KINNECT CONFIG
	libfreenect2::setGlobalLogger(libfreenect2::createConsoleLogger(libfreenect2::Logger::Level::None));
	libfreenect2::Freenect2 freenect2;
	libfreenect2::Freenect2Device *kinect = 0;

	cout << navirice::ansi::green("---CONFIGURING---") << endl;

	cout << "  Finding devices: " << std::flush;
	if(freenect2.enumerateDevices() == 0){
		cout << navirice::ansi::red("FAILURE") << endl;
		cout << "0 connected devices" << endl;
		return 1;
	}
	cout << navirice::ansi::green("SUCCESS") << " found: " << freenect2.enumerateDevices() << " device(s)" << endl;

	cout << "  Opening device 0: " << std::flush;
	string serial = freenect2.getDeviceSerialNumber(0);
	kinect = freenect2.openDevice(serial);
	if(kinect == 0){
		cout << navirice::ansi::red("FAILURE") << endl;
		cout << "Cannot open device 0" << endl;
		return 1;
	}
	cout << navirice::ansi::green("SUCCESS") << " serial: " << serial << endl;

	libfreenect2::FrameMap frames;
	int types = 0;
	types |= libfreenect2::Frame::Color;
	types |= libfreenect2::Frame::Ir | libfreenect2::Frame::Depth;
	libfreenect2::SyncMultiFrameListener listener(types);

	kinect->setColorFrameListener(&listener);
  kinect->setIrAndDepthFrameListener(&listener);
	kinect->startStreams(true, true);

	server = new navirice::ImageDistributionServer(PORT);

	signal(SIGINT, finish_program);

	while(keep_alive) {
		auto start = std::chrono::steady_clock::now();
		// ACQUIRE COLOR FRAME FROM KINECT
		if(!listener.waitForNewFrame(frames, 10*1000)){
			cout << navirice::ansi::red("FAILED TO ACQUIRE FRAME\n");
		} else {

			libfreenect2::Frame *rgb_frame = frames[libfreenect2::Frame::Color];
			navirice::Image* rgb_image = new navirice::ImageImpl(
					rgb_frame->width,
					rgb_frame->height,
					rgb_frame->bytes_per_pixel,
					navirice::ImageDataType::UBYTE,
					rgb_frame->data,
					rgb_frame->bytes_per_pixel * rgb_frame->width * rgb_frame->height
					);

			libfreenect2::Frame *depth_frame = frames[libfreenect2::Frame::Depth];
			navirice::Image* depth_image = new navirice::ImageImpl(
					depth_frame->width,
					depth_frame->height,
					depth_frame->bytes_per_pixel,
					navirice::ImageDataType::FLOAT,
					depth_frame->data,
					depth_frame->bytes_per_pixel * depth_frame->width * depth_frame->height
					);

			libfreenect2::Frame *ir_frame = frames[libfreenect2::Frame::Ir];
			navirice::Image* ir_image = new navirice::ImageImpl(
					ir_frame->width,
					ir_frame->height,
					ir_frame->bytes_per_pixel,
					navirice::ImageDataType::FLOAT,
					ir_frame->data,
					ir_frame->bytes_per_pixel * ir_frame->width * ir_frame->height
					);

			server->set_new_images(rgb_image, ir_image, depth_image);

			delete rgb_image;
			delete ir_image;
			delete depth_image;

			listener.release(frames);
		}
		auto duration = std::chrono::steady_clock::now() - start;
		cout << "------- push duration: " + std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count()) + " milliseconds\n";
	}

	// CLEANUP
	delete server;

	cout << "SHUTTING DOWN KINECT!" << endl;
	kinect->stop();
	kinect->close();
	cout << navirice::ansi::green("DONE") << endl;

	return 0;
}

<commit_msg>Server code modified to send requested images, Need to fix capture speed...<commit_after>#include <iostream>
#include <cstdlib>
#include <signal.h>

#include <libfreenect2/libfreenect2.hpp>
#include <libfreenect2/frame_listener_impl.h>
#include <libfreenect2/registration.h>
#include <libfreenect2/packet_pipeline.h>
#include <libfreenect2/logger.h>

#include "src/navirice.h"

using namespace std;
bool keep_alive = true;

#define PORT 29000

navirice::ImageDistributionServer* server;

int program_exit_counter = 0;

void finish_program(int input){
	keep_alive = false;
	program_exit_counter++;
	if(program_exit_counter >=3){
		std::cout << "*****************************\nOVERRIDING FOR FORCED EXIT!" << std::endl;
		exit(3);
	}
}

class IOCW;

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

	// KINNECT CONFIG
	libfreenect2::setGlobalLogger(libfreenect2::createConsoleLogger(libfreenect2::Logger::Level::None));
	libfreenect2::Freenect2 freenect2;
	libfreenect2::Freenect2Device *kinect = 0;

	cout << navirice::ansi::green("---CONFIGURING---") << endl;

	cout << "  Finding devices: " << std::flush;
	if(freenect2.enumerateDevices() == 0){
		cout << navirice::ansi::red("FAILURE") << endl;
		cout << "0 connected devices" << endl;
		return 1;
	}
	cout << navirice::ansi::green("SUCCESS") << " found: " << freenect2.enumerateDevices() << " device(s)" << endl;

	cout << "  Opening device 0: " << std::flush;
	string serial = freenect2.getDeviceSerialNumber(0);
	kinect = freenect2.openDevice(serial);
	if(kinect == 0){
		cout << navirice::ansi::red("FAILURE") << endl;
		cout << "Cannot open device 0" << endl;
		return 1;
	}
	cout << navirice::ansi::green("SUCCESS") << " serial: " << serial << endl;

	libfreenect2::FrameMap frames;
	int types = 0;
	types |= libfreenect2::Frame::Color;
	types |= libfreenect2::Frame::Ir | libfreenect2::Frame::Depth;
	libfreenect2::SyncMultiFrameListener listener(types);

	kinect->setColorFrameListener(&listener);
	kinect->setIrAndDepthFrameListener(&listener);

	server = new navirice::ImageDistributionServer(PORT);
	auto settings = server->get_server_settings();
	auto r = kinect->startStreams(true, true);

	signal(SIGINT, finish_program);

	while(keep_alive) {

		auto new_settings = server->get_server_settings();
		if(!settings.is_equal(new_settings)){
			settings = new_settings;
			std::cout << "------------ SERVER SETTINGS CHANGED ----------------\n";
			std::cout << "IR: " << settings.IR << std::endl;
			std::cout << "RGB: " << settings.RGB << std::endl;
			std::cout << "Depth: " << settings.Depth << std::endl;
			std::cout << "-----------          END             ----------------\n";
//			kinect->stop();
			kinect->startStreams(settings.RGB, settings.IR || settings.Depth);
		}

		auto start = std::chrono::steady_clock::now();
		// ACQUIRE COLOR FRAME FROM KINECT
		//std::cout << "WAITING FOR NEW FRAME" << std::endl;
		if(!listener.waitForNewFrame(frames, 100)){
			cout << navirice::ansi::red("FAILED TO ACQUIRE FRAME\n");
		} else {
			//std::cout << "ACQUIRED NEW FRAME" << std::endl;

			libfreenect2::Frame *rgb_frame = NULL;
			libfreenect2::Frame *depth_frame = NULL;
			libfreenect2::Frame *ir_frame = NULL;
			navirice::Image* rgb_image = NULL;
			navirice::Image* depth_image = NULL;
			navirice::Image* ir_image = NULL;

			if(settings.RGB){
				rgb_frame = frames[libfreenect2::Frame::Color];
				if(rgb_frame) rgb_image = new navirice::ImageImpl(
						rgb_frame->width,
						rgb_frame->height,
						rgb_frame->bytes_per_pixel,
						navirice::ImageDataType::UBYTE,
						rgb_frame->data,
						rgb_frame->bytes_per_pixel * rgb_frame->width * rgb_frame->height
						);
			}

			//std::cout << "RGB SET" << std::endl;

			if(settings.IR || settings.RGB){
				depth_frame = frames[libfreenect2::Frame::Depth];
				if(depth_frame) depth_image = new navirice::ImageImpl(
						depth_frame->width,
						depth_frame->height,
						depth_frame->bytes_per_pixel,
						navirice::ImageDataType::FLOAT,
						depth_frame->data,
						depth_frame->bytes_per_pixel * depth_frame->width * depth_frame->height
						);

				ir_frame = frames[libfreenect2::Frame::Ir];
				if(ir_frame) ir_image = new navirice::ImageImpl(
						ir_frame->width,
						ir_frame->height,
						ir_frame->bytes_per_pixel,
						navirice::ImageDataType::FLOAT,
						ir_frame->data,
						ir_frame->bytes_per_pixel * ir_frame->width * ir_frame->height
						);
			}

			//std::cout << "IR DEPTH SET" << std::endl;

			server->set_new_images(rgb_image, ir_image, depth_image);

			//std::cout << "NEW IMAGES SET" << std::endl;

			if(rgb_image) delete rgb_image;
			if(ir_image) delete ir_image;
			if(depth_image) delete depth_image;

			listener.release(frames);
		}
		auto duration = std::chrono::steady_clock::now() - start;
		cout << "------- push duration: " + std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count()) + " milliseconds\n";
	}

	// CLEANUP
	delete server;

	cout << "SHUTTING DOWN KINECT!" << endl;
	kinect->stop();
	kinect->close();
	cout << navirice::ansi::green("DONE") << endl;

	return 0;
}

<|endoftext|>


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

#include "condor_common.h"
#include "condor_debug.h"
#include "condor_fix_setjmp.h"
#include "state_machine_driver.h"
#include "event_handler.unix.h"
#include "name_tab.h"

extern NameTable	StateNames;
extern NameTable	EventNames;
extern NameTable 	StateFuncNames;
extern NameTable	TransFuncNames;

static StateMachine	*CurFSA;
static sigjmp_buf		JmpBuf;

static const char	*TransFmt = "\t%-14s%-16s%-14s%-12s\n";

StateMachine::StateMachine(
	State *st, Transition *tr, const int sigs[], int start, int end
	) :
	start_state( start ),
	end_state( end ),
	StateTab( st ),
	TransitionTab( tr )
{
	int		i;

		// Calculate size of state table
	for( n_states=0; StateTab[n_states].id >= 0; n_states++ )
		;

		// Calculate size of transition table
	for( n_transitions=0; TransitionTab[n_transitions].from >= 0;
															n_transitions++)
		;

		// Package up set of signals into a sigset_t
	sigemptyset( &asynch_events );
	for( i=0; sigs[i]; i++ ) {
		sigaddset( &asynch_events, sigs[i] );
	}

		// Calculate signal mask for each state
	for( i=0; i<n_states; i++ ) {
		init_asynch_events( StateTab[i] );
	}
	no_print_tr = NULL;
	cur_state = -1;
}

/*
  Return TRUE if the given event is registered as an asynchronous event
  for this finite state machine, and FALSE otherwise.
*/
inline int
StateMachine::is_asynch_event( int event )
{
	return sigismember(&asynch_events,event) == 1;
}

/*
  Generate an individualized signal mask for a state.  The mask consists
  of those signals which the state machine has registered as an asynch
  event and for which this state has a transition.
*/
void
StateMachine::init_asynch_events( State &state )
{
	int		i;

	sigemptyset( &state.asynch_events );
	for( i=0; i<n_transitions; i++ ) {
		if( TransitionTab[i].from != state.id ) {
			continue;
		}
		if( is_asynch_event(TransitionTab[i].event) ) {
			sigaddset( &state.asynch_events, TransitionTab[i].event );
		}
	}
}

void
StateMachine::execute()
{
	State		*state_ptr;
	Transition	*transition = 0;
	int			next_state;
	int			event;
	EventHandler	h( fsa_sig_handler, asynch_events );

	CurFSA = this;
	cur_state = start_state;

	h.display();
	h.install();

	while( cur_state != end_state ) {
		if ( transition != no_print_tr ) {
			dprintf( D_ALWAYS, "\t*FSM* Transitioning to state \"%s\"\n",
					StateNames.get_name(cur_state) );
		}
		state_ptr = find_state( cur_state );
		next_state = sigsetjmp( JmpBuf, TRUE );
		if( !next_state ) {

			if( state_ptr->func ) {
				h.allow_events( state_ptr->asynch_events );

				if ( transition != no_print_tr ) {
					dprintf( D_ALWAYS,
							"\t*FSM* Executing state func \"%s\" [ ",
							StateFuncNames.get_name((long)state_ptr->func) );
					state_ptr->display_events();
					dprintf( D_ALWAYS | D_NOHEADER, " ]\n" );
				}

				event = state_ptr->func();

				h.block_events( state_ptr->asynch_events );
			} else {
				event = -1;
			}

			transition = find_transition( event );

			if( transition->func ) {
				if (transition != no_print_tr) {
					dprintf( D_ALWAYS,
							"\t*FSM* Executing transition function \"%s\"\n",
							TransFuncNames.get_name((long)transition->func) );
				}
				transition->func();
			}
			next_state = transition->to;
		}
		cur_state = next_state;
	}
	dprintf( D_ALWAYS, "\t*FSM* Reached state \"%s\"\n", StateNames.get_name(cur_state) );

	h.de_install();
	CurFSA = NULL;
}

void
fsa_sig_handler( int event )
{
	Transition	*transition;

	transition = CurFSA->find_transition( event );

	if (transition != CurFSA->no_print_tr) {
		dprintf( D_ALWAYS, "\t*FSM* Got asynchronous event \"%s\"\n",
				EventNames.get_name(event) );
	}

	if( transition->func ) {
		if (transition != CurFSA->no_print_tr) {
			dprintf( D_ALWAYS,
					"\t*FSM* Executing transition function \"%s\"\n",
					TransFuncNames.get_name((long)transition->func) );
		}
		if ( transition->func() == -2 ) {
			dprintf( D_ALWAYS,"\t*FSM* Aborting transition function \"%s\"\n",
					TransFuncNames.get_name((long)transition->func) );
			return;
		}
	}
	if( transition->to ) {
		siglongjmp( JmpBuf, transition->to );
	}
	return;
}

void
State::display_events()
{
	NameTableIterator	next_event( EventNames );
	int					event;

	while( (event = next_event()) != -1 ) {
		if( sigismember(&asynch_events,event) == 1 ) {
			dprintf( D_ALWAYS | D_NOHEADER, "%s ", EventNames.get_name(event) );
		}
	}
}

void
State::display()
{

	dprintf( D_ALWAYS,
		"\t%-14s%-20s",
		StateNames.get_name(id),
		StateFuncNames.get_name((long)func)
	);

	display_events();
	dprintf( D_ALWAYS | D_NOHEADER, "\n" );
}

void
Transition::display()
{
	dprintf( D_ALWAYS,TransFmt, StateNames.get_name(from),
			EventNames.get_name(event), StateNames.get_name(to),
			TransFuncNames.get_name((long)func));
}

void
Transition::dot_print(FILE *file, const char *color)
{
	if (to != 0) {
		fprintf(file, "\t%s -> %s [label = \"%s(%s)\", color = \"%s\"];\n",
				StateNames.get_name(from),
				StateNames.get_name(to),
				EventNames.get_name(event),
				TransFuncNames.get_name((long)func),
				color);
	} else {
		fprintf(file, "\t%s -> %s [label = \"%s(%s)\", color = \"%s\"];\n",
				StateNames.get_name(from),
				StateNames.get_name(from),
				EventNames.get_name(event),
				TransFuncNames.get_name((long)func),
				color);
	}
}

void
StateMachine::display()
{
	int		i;

	dprintf( D_ALWAYS, "StateMachine {\n" );
	dprintf( D_ALWAYS, "    start_state = %s\n", StateNames.get_name(start_state) );
	dprintf( D_ALWAYS, "    end_state = %s\n", StateNames.get_name(end_state) );

	dprintf( D_ALWAYS, "\n" );
	dprintf( D_ALWAYS, "    StateTable:\n" );
	dprintf( D_ALWAYS, "\t%-14s%-20s%s\n", "name", "function", "asynch_events");
	dprintf( D_ALWAYS, "\t%-14s%-20s%s\n", "----", "--------", "-------------");
	for( i=0; i<n_states; i++ ) {
		StateTab[i].display();
	}
	dprintf( D_ALWAYS, "\n" );
	dprintf( D_ALWAYS, "    TransitionTable:\n" );
	dprintf( D_ALWAYS, TransFmt, "from", "event", "to", "function" );
	dprintf( D_ALWAYS, TransFmt, "----", "-----", "--", "--------" );
	for( i=0; i<n_transitions; i++ ) {
		TransitionTab[i].display();
	}
	dprintf( D_ALWAYS, "}\n" );
}

void
StateMachine::dot_print(FILE *file)
{
	int		i;
	const char	*color;

	fprintf(file, "digraph FSA {\n");

	for( i=0; i<n_transitions; i++ ) {
		color = (is_asynch_event(TransitionTab[i].event) ? "red" : "blue");
		TransitionTab[i].dot_print(file, color);
	}
	fprintf(file, "}\n");
}

State *
StateMachine::find_state( int id )
{
	int		i;

	for( i=0; i<n_states; i++ ) {
		if( StateTab[i].id == id ) {
			return &StateTab[i];
		}
	}

	EXCEPT( "ERROR: Can't find state with id %d", id );
	return NULL;	// EXCEPT doesn't return, but the compiler doesn't know that...
}

Transition *
StateMachine::find_transition( int event )
{
	int		i;

	for( i=0; i<n_transitions; i++ ) {
		if( TransitionTab[i].from == cur_state
										&& TransitionTab[i].event == event ) {
			return( &TransitionTab[i] );
		}
	}

	EXCEPT(
		"Can't find transition out of state \"%s\" for event \"%s\"",
		StateNames.get_name(cur_state),
		EventNames.get_name(event)
	);
	return NULL;	// EXCEPT doesn't return, but the compiler doesn't know that...
}

<commit_msg>Volatize variable used in longjmp to prevent warning #359<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_debug.h"
#include "condor_fix_setjmp.h"
#include "state_machine_driver.h"
#include "event_handler.unix.h"
#include "name_tab.h"

extern NameTable	StateNames;
extern NameTable	EventNames;
extern NameTable 	StateFuncNames;
extern NameTable	TransFuncNames;

static StateMachine	*CurFSA;
static sigjmp_buf		JmpBuf;

static const char	*TransFmt = "\t%-14s%-16s%-14s%-12s\n";

StateMachine::StateMachine(
	State *st, Transition *tr, const int sigs[], int start, int end
	) :
	start_state( start ),
	end_state( end ),
	StateTab( st ),
	TransitionTab( tr )
{
	int		i;

		// Calculate size of state table
	for( n_states=0; StateTab[n_states].id >= 0; n_states++ )
		;

		// Calculate size of transition table
	for( n_transitions=0; TransitionTab[n_transitions].from >= 0;
															n_transitions++)
		;

		// Package up set of signals into a sigset_t
	sigemptyset( &asynch_events );
	for( i=0; sigs[i]; i++ ) {
		sigaddset( &asynch_events, sigs[i] );
	}

		// Calculate signal mask for each state
	for( i=0; i<n_states; i++ ) {
		init_asynch_events( StateTab[i] );
	}
	no_print_tr = NULL;
	cur_state = -1;
}

/*
  Return TRUE if the given event is registered as an asynchronous event
  for this finite state machine, and FALSE otherwise.
*/
inline int
StateMachine::is_asynch_event( int event )
{
	return sigismember(&asynch_events,event) == 1;
}

/*
  Generate an individualized signal mask for a state.  The mask consists
  of those signals which the state machine has registered as an asynch
  event and for which this state has a transition.
*/
void
StateMachine::init_asynch_events( State &state )
{
	int		i;

	sigemptyset( &state.asynch_events );
	for( i=0; i<n_transitions; i++ ) {
		if( TransitionTab[i].from != state.id ) {
			continue;
		}
		if( is_asynch_event(TransitionTab[i].event) ) {
			sigaddset( &state.asynch_events, TransitionTab[i].event );
		}
	}
}

void
StateMachine::execute()
{
	State		*state_ptr;
	Transition	* volatile transition = 0;
	int			next_state;
	int			event;
	EventHandler	h( fsa_sig_handler, asynch_events );

	CurFSA = this;
	cur_state = start_state;

	h.display();
	h.install();

	while( cur_state != end_state ) {
		if ( transition != no_print_tr ) {
			dprintf( D_ALWAYS, "\t*FSM* Transitioning to state \"%s\"\n",
					StateNames.get_name(cur_state) );
		}
		state_ptr = find_state( cur_state );
		next_state = sigsetjmp( JmpBuf, TRUE );
		if( !next_state ) {

			if( state_ptr->func ) {
				h.allow_events( state_ptr->asynch_events );

				if ( transition != no_print_tr ) {
					dprintf( D_ALWAYS,
							"\t*FSM* Executing state func \"%s\" [ ",
							StateFuncNames.get_name((long)state_ptr->func) );
					state_ptr->display_events();
					dprintf( D_ALWAYS | D_NOHEADER, " ]\n" );
				}

				event = state_ptr->func();

				h.block_events( state_ptr->asynch_events );
			} else {
				event = -1;
			}

			transition = find_transition( event );

			if( transition->func ) {
				if (transition != no_print_tr) {
					dprintf( D_ALWAYS,
							"\t*FSM* Executing transition function \"%s\"\n",
							TransFuncNames.get_name((long)transition->func) );
				}
				transition->func();
			}
			next_state = transition->to;
		}
		cur_state = next_state;
	}
	dprintf( D_ALWAYS, "\t*FSM* Reached state \"%s\"\n", StateNames.get_name(cur_state) );

	h.de_install();
	CurFSA = NULL;
}

void
fsa_sig_handler( int event )
{
	Transition	*transition;

	transition = CurFSA->find_transition( event );

	if (transition != CurFSA->no_print_tr) {
		dprintf( D_ALWAYS, "\t*FSM* Got asynchronous event \"%s\"\n",
				EventNames.get_name(event) );
	}

	if( transition->func ) {
		if (transition != CurFSA->no_print_tr) {
			dprintf( D_ALWAYS,
					"\t*FSM* Executing transition function \"%s\"\n",
					TransFuncNames.get_name((long)transition->func) );
		}
		if ( transition->func() == -2 ) {
			dprintf( D_ALWAYS,"\t*FSM* Aborting transition function \"%s\"\n",
					TransFuncNames.get_name((long)transition->func) );
			return;
		}
	}
	if( transition->to ) {
		siglongjmp( JmpBuf, transition->to );
	}
	return;
}

void
State::display_events()
{
	NameTableIterator	next_event( EventNames );
	int					event;

	while( (event = next_event()) != -1 ) {
		if( sigismember(&asynch_events,event) == 1 ) {
			dprintf( D_ALWAYS | D_NOHEADER, "%s ", EventNames.get_name(event) );
		}
	}
}

void
State::display()
{

	dprintf( D_ALWAYS,
		"\t%-14s%-20s",
		StateNames.get_name(id),
		StateFuncNames.get_name((long)func)
	);

	display_events();
	dprintf( D_ALWAYS | D_NOHEADER, "\n" );
}

void
Transition::display()
{
	dprintf( D_ALWAYS,TransFmt, StateNames.get_name(from),
			EventNames.get_name(event), StateNames.get_name(to),
			TransFuncNames.get_name((long)func));
}

void
Transition::dot_print(FILE *file, const char *color)
{
	if (to != 0) {
		fprintf(file, "\t%s -> %s [label = \"%s(%s)\", color = \"%s\"];\n",
				StateNames.get_name(from),
				StateNames.get_name(to),
				EventNames.get_name(event),
				TransFuncNames.get_name((long)func),
				color);
	} else {
		fprintf(file, "\t%s -> %s [label = \"%s(%s)\", color = \"%s\"];\n",
				StateNames.get_name(from),
				StateNames.get_name(from),
				EventNames.get_name(event),
				TransFuncNames.get_name((long)func),
				color);
	}
}

void
StateMachine::display()
{
	int		i;

	dprintf( D_ALWAYS, "StateMachine {\n" );
	dprintf( D_ALWAYS, "    start_state = %s\n", StateNames.get_name(start_state) );
	dprintf( D_ALWAYS, "    end_state = %s\n", StateNames.get_name(end_state) );

	dprintf( D_ALWAYS, "\n" );
	dprintf( D_ALWAYS, "    StateTable:\n" );
	dprintf( D_ALWAYS, "\t%-14s%-20s%s\n", "name", "function", "asynch_events");
	dprintf( D_ALWAYS, "\t%-14s%-20s%s\n", "----", "--------", "-------------");
	for( i=0; i<n_states; i++ ) {
		StateTab[i].display();
	}
	dprintf( D_ALWAYS, "\n" );
	dprintf( D_ALWAYS, "    TransitionTable:\n" );
	dprintf( D_ALWAYS, TransFmt, "from", "event", "to", "function" );
	dprintf( D_ALWAYS, TransFmt, "----", "-----", "--", "--------" );
	for( i=0; i<n_transitions; i++ ) {
		TransitionTab[i].display();
	}
	dprintf( D_ALWAYS, "}\n" );
}

void
StateMachine::dot_print(FILE *file)
{
	int		i;
	const char	*color;

	fprintf(file, "digraph FSA {\n");

	for( i=0; i<n_transitions; i++ ) {
		color = (is_asynch_event(TransitionTab[i].event) ? "red" : "blue");
		TransitionTab[i].dot_print(file, color);
	}
	fprintf(file, "}\n");
}

State *
StateMachine::find_state( int id )
{
	int		i;

	for( i=0; i<n_states; i++ ) {
		if( StateTab[i].id == id ) {
			return &StateTab[i];
		}
	}

	EXCEPT( "ERROR: Can't find state with id %d", id );
	return NULL;	// EXCEPT doesn't return, but the compiler doesn't know that...
}

Transition *
StateMachine::find_transition( int event )
{
	int		i;

	for( i=0; i<n_transitions; i++ ) {
		if( TransitionTab[i].from == cur_state
										&& TransitionTab[i].event == event ) {
			return( &TransitionTab[i] );
		}
	}

	EXCEPT(
		"Can't find transition out of state \"%s\" for event \"%s\"",
		StateNames.get_name(cur_state),
		EventNames.get_name(event)
	);
	return NULL;	// EXCEPT doesn't return, but the compiler doesn't know that...
}

<|endoftext|>


<commit_before>/*
 * SessionRCompletions.cpp
 *
 * Copyright (C) 2014 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionRCompletions.hpp"

#include <core/Exec.hpp>

#include <boost/range/adaptors.hpp>

#include <r/RSexp.hpp>
#include <r/RInternal.hpp>
#include <r/RExec.hpp>
#include <r/RJson.hpp>
#include <r/RRoutines.hpp>
#include <r/ROptions.hpp>
#include <r/session/RClientState.hpp>
#include <r/session/RSessionUtils.hpp>

#include <core/system/FileScanner.hpp>

#include <core/r_util/RProjectFile.hpp>
#include <core/r_util/RSourceIndex.hpp>
#include <core/r_util/RPackageInfo.hpp>
#include <core/r_util/RSourceIndex.hpp>

#include <session/projects/SessionProjects.hpp>
#include <session/SessionModuleContext.hpp>

#include "SessionCodeSearch.hpp"

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace r_completions {

namespace {

char ends(char begins) {
   switch(begins) {
   case '(': return ')';
   case '[': return ']';
   case '{': return '}';
   }
   return '\0';
}

bool isBinaryOp(char character)
{
   return character == '~' ||
         character == '!' ||
         character == '@' ||
         character == '$' ||
         character == '%' ||
         character == '^' ||
         character == '&' ||
         character == '*' ||
         character == '-' ||
         character == '+' ||
         character == '*' ||
         character == '/' ||
         character == '=' ||
         character == '|' ||
         character == '<' ||
         character == '>' ||
         character == '?';

}

} // end anonymous namespace

std::string finishExpression(const std::string& expression)
{
   std::string result = expression;

   // If the last character of the expression is a binary op, then we
   // place a '.' after it
   int n = expression.length();
   if (isBinaryOp(expression[n - 1]))
      result.append(".");

   std::vector<char> terminators;

   char top = '\0';
   terminators.push_back(top);

   bool in_string = false;
   bool in_escape = false;

   for (int i = 0; i < n; i++) {

      char cur = expression[i];

      if (in_string) {

         if (in_escape) {
            in_escape = false;
            continue;
         }

         if (cur == '\\') {
            in_escape = true;
            continue;
         }

         if (cur != top) {
            continue;
         }

         in_string = false;
         terminators.pop_back();
         top = terminators.back();
         continue;

      }

      if (cur == top) {
         terminators.pop_back();
         top = terminators.back();
      } else if (cur == '(' || cur == '{' || cur == '[') {
         char end = ends(cur);
         top = end;
         terminators.push_back(top);
      } else if (cur == '"' || cur == '`' || cur == '\'') {
         top = cur;
         in_string = true;
         terminators.push_back(top);
      }

   }

   // append to the output
   for (std::size_t i = terminators.size() - 1; i > 0; --i)
      result.push_back(terminators[i]);

   return result;
}

namespace {

SEXP rs_finishExpression(SEXP stringSEXP)
{
   r::sexp::Protect rProtect;
   int n = r::sexp::length(stringSEXP);

   std::vector<std::string> output;
   output.reserve(n);
   for (int i = 0; i < n; ++i)
      output.push_back(finishExpression(CHAR(STRING_ELT(stringSEXP, i))));

   return r::sexp::create(output, &rProtect);
}

struct SourceIndexCompletions {
   std::vector<std::string> completions;
   std::vector<bool> isFunction;
   bool moreAvailable;
};

SourceIndexCompletions getSourceIndexCompletions(const std::string& token)
{
   // get functions from the source index
   std::vector<core::r_util::RSourceItem> items;
   bool moreAvailable = false;

   // TODO: wire up 'moreAvailable'
   modules::code_search::searchSource(token,
                                      1E3,
                                      true,
                                      &items,
                                      &moreAvailable);

   SourceIndexCompletions srcCompletions;
   BOOST_FOREACH(const core::r_util::RSourceItem& item, items)
   {
      if (item.braceLevel() == 0)
      {
         srcCompletions.completions.push_back(item.name());
         srcCompletions.isFunction.push_back(item.isFunction() || item.isMethod());
      }
   }

   srcCompletions.moreAvailable = moreAvailable;
   return srcCompletions;
}

SEXP rs_getSourceIndexCompletions(SEXP tokenSEXP)
{
   r::sexp::Protect protect;
   std::string token = r::sexp::asString(tokenSEXP);
   SourceIndexCompletions srcCompletions = getSourceIndexCompletions(token);

   std::vector<std::string> names;
   names.push_back("completions");
   names.push_back("isFunction");
   names.push_back("moreAvailable");

   SEXP resultSEXP = r::sexp::createList(names, &protect);
   r::sexp::setNamedListElement(resultSEXP, "completions", srcCompletions.completions);
   r::sexp::setNamedListElement(resultSEXP, "isFunction", srcCompletions.isFunction);
   r::sexp::setNamedListElement(resultSEXP, "moreAvailable", srcCompletions.moreAvailable);

   return resultSEXP;
}

bool subsequenceFilter(const FileInfo& fileInfo,
                       const std::string& pattern,
                       int parentPathLength,
                       int maxCount,
                       std::vector<std::string>* pPaths,
                       int* pCount,
                       bool* pMoreAvailable)
{
   if (*pCount >= maxCount)
   {
      *pMoreAvailable = true;
      return false;
   }

   bool isSubsequence = string_utils::isSubsequence(
            fileInfo.absolutePath().substr(parentPathLength + 2),
            pattern,
            true);

   if (isSubsequence)
   {
      ++*pCount;
      pPaths->push_back(fileInfo.absolutePath());
   }

   // Always add subdirectories
   if (fileInfo.isDirectory())
   {
      return true;
   }

   return false;
}

SEXP rs_scanFiles(SEXP pathSEXP,
                  SEXP patternSEXP,
                  SEXP maxCountSEXP)
{
   std::string path = r::sexp::asString(pathSEXP);
   std::string pattern = r::sexp::asString(patternSEXP);
   int maxCount = r::sexp::asInteger(maxCountSEXP);

   FilePath filePath(path);
   FileInfo fileInfo(filePath);
   tree<FileInfo> tree;

   core::system::FileScannerOptions options;
   options.recursive = true;
   options.yield = true;

   // Use a subsequence filter, and bail after too many files
   std::vector<std::string> paths;

   int count = 0;
   bool moreAvailable = false;
   options.filter = boost::bind(subsequenceFilter,
                                _1,
                                pattern,
                                path.length(),
                                maxCount,
                                &paths,
                                &count,
                                &moreAvailable);

   Error error = scanFiles(fileInfo, options, &tree);
   if (error)
      return R_NilValue;

   r::sexp::Protect protect;
   r::sexp::ListBuilder builder(&protect);

   builder.add("paths", paths);
   builder.add("more_available", moreAvailable);

   return r::sexp::create(builder, &protect);
}

SEXP rs_isSubsequence(SEXP stringsSEXP, SEXP querySEXP)
{
   std::vector<std::string> strings;
   if (!r::sexp::fillVectorString(stringsSEXP, &strings))
      return R_NilValue;

   std::string query = r::sexp::asString(querySEXP);

   std::vector<bool> result(strings.size());

   std::transform(strings.begin(),
                  strings.end(),
                  result.begin(),
                  boost::bind(
                     string_utils::isSubsequence,
                     _1,
                     query));

   r::sexp::Protect protect;
   return r::sexp::create(result, &protect);

}

SEXP rs_getActiveFrame(SEXP depthSEXP)
{
   int depth = r::sexp::asInteger(depthSEXP);
   RCNTXT* context = r::getGlobalContext();
   for (int i = 0; i < depth; ++i)
   {
      context = context->nextcontext;
      if (context == NULL)
         return R_NilValue;
   }
   return context->cloenv;
}

SEXP rs_getNAMESPACEImportedSymbols(SEXP documentIdSEXP)
{
   std::string documentId = r::sexp::asString(documentIdSEXP);
   boost::shared_ptr<core::r_util::RSourceIndex> index =
         code_search::rSourceIndex().get(documentId);

   using namespace core::r_util;
   std::vector<std::string> pkgs;

   BOOST_FOREACH(const std::string& pkg, RSourceIndex::getImportedPackages())
   {
      pkgs.push_back(pkg);
   }

   BOOST_FOREACH(const std::string& pkg,
                 RSourceIndex::getImportFromDirectives() | boost::adaptors::map_keys)
   {
      pkgs.push_back(pkg);
   }

   using namespace r::sexp;
   Protect protect;
   r::sexp::ListBuilder builder(&protect);

   BOOST_FOREACH(const std::string& pkg, pkgs)
   {
      const AsyncLibraryCompletions& completions = RSourceIndex::getCompletions(pkg);
      r::sexp::ListBuilder child(&protect);

      // If the inferred package is listed _only_ in the NAMESPACE 'importFrom',
      // then we want to selectively return symbols.
      if (index->getInferredPackages().count(pkg) == 0 &&
          RSourceIndex::getImportedPackages().count(pkg) == 0 &&
          RSourceIndex::getImportFromDirectives().count(pkg) != 0)
      {
         std::vector<std::string> exports;
         std::vector<int> types;

         std::set<std::string>& directives =
               RSourceIndex::getImportFromDirectives()[pkg];

         BOOST_FOREACH(const std::string& item, directives)
         {
            std::vector<std::string>::const_iterator it =
                  std::find(completions.exports.begin(),
                            completions.exports.end(),
                            item);

            std::size_t index = it - completions.exports.begin();

            exports.push_back(completions.exports[index]);
            types.push_back(completions.types[index]);
         }

         child.add("exports", exports);
         child.add("types", types);

      }
      else
      {
         child.add("exports", completions.exports);
         child.add("types", completions.types);
      }

      builder.add(pkg, child);
   }

   return r::sexp::create(builder, &protect);
}

SEXP rs_getInferredCompletions(SEXP packagesSEXP)
{
   using namespace rstudio::core::r_util;

   std::vector<std::string> packages;
   if (!r::sexp::fillVectorString(packagesSEXP, &packages))
      return R_NilValue;

   r::sexp::Protect protect;
   r::sexp::ListBuilder parent(&protect);

   for (std::vector<std::string>::const_iterator it = packages.begin();
        it != packages.end();
        ++it)
   {
      DEBUG("Adding entry for '" << *it << "'");
      AsyncLibraryCompletions completions = RSourceIndex::getCompletions(*it);

      r::sexp::ListBuilder builder(&protect);
      builder.add("exports", completions.exports);
      builder.add("types", completions.types);
      builder.add("functions", completions.functions);
      parent.add(*it, builder);
   }

   return r::sexp::create(parent, &protect);
}

SEXP rs_listInferredPackages(SEXP documentIdSEXP)
{
   std::string documentId = r::sexp::asString(documentIdSEXP);
   boost::shared_ptr<core::r_util::RSourceIndex> index =
         code_search::rSourceIndex().get(documentId);

   // NOTE: can occur when user edits file not in source index
   if (index == NULL)
      return R_NilValue;

   std::set<std::string> pkgs = index->getInferredPackages();
   pkgs.insert(index->getImportedPackages().begin(),
               index->getImportedPackages().end());

   r::sexp::Protect protect;
   return r::sexp::create(pkgs, &protect);

}

} // end anonymous namespace

Error initialize() {

   RS_REGISTER_CALL_METHOD(rs_finishExpression, 1);
   RS_REGISTER_CALL_METHOD(rs_getSourceIndexCompletions, 1);
   RS_REGISTER_CALL_METHOD(rs_scanFiles, 4);
   RS_REGISTER_CALL_METHOD(rs_isSubsequence, 2);
   RS_REGISTER_CALL_METHOD(rs_getActiveFrame, 1);
   RS_REGISTER_CALL_METHOD(rs_listInferredPackages, 1);
   RS_REGISTER_CALL_METHOD(rs_getInferredCompletions, 1);
   RS_REGISTER_CALL_METHOD(rs_getNAMESPACEImportedSymbols, 1);

   using boost::bind;
   using namespace module_context;
   ExecBlock initBlock;
   initBlock.addFunctions()
         (bind(sourceModuleRFile, "SessionRCompletions.R"));
   return initBlock.execute();
}

} // namespace r_completions
} // namespace modules
} // namespace session
} // namespace rstudio
<commit_msg>defend against missing index<commit_after>/*
 * SessionRCompletions.cpp
 *
 * Copyright (C) 2014 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionRCompletions.hpp"

#include <core/Exec.hpp>

#include <boost/range/adaptors.hpp>

#include <r/RSexp.hpp>
#include <r/RInternal.hpp>
#include <r/RExec.hpp>
#include <r/RJson.hpp>
#include <r/RRoutines.hpp>
#include <r/ROptions.hpp>
#include <r/session/RClientState.hpp>
#include <r/session/RSessionUtils.hpp>

#include <core/system/FileScanner.hpp>

#include <core/r_util/RProjectFile.hpp>
#include <core/r_util/RSourceIndex.hpp>
#include <core/r_util/RPackageInfo.hpp>
#include <core/r_util/RSourceIndex.hpp>

#include <session/projects/SessionProjects.hpp>
#include <session/SessionModuleContext.hpp>

#include "SessionCodeSearch.hpp"

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace r_completions {

namespace {

char ends(char begins) {
   switch(begins) {
   case '(': return ')';
   case '[': return ']';
   case '{': return '}';
   }
   return '\0';
}

bool isBinaryOp(char character)
{
   return character == '~' ||
         character == '!' ||
         character == '@' ||
         character == '$' ||
         character == '%' ||
         character == '^' ||
         character == '&' ||
         character == '*' ||
         character == '-' ||
         character == '+' ||
         character == '*' ||
         character == '/' ||
         character == '=' ||
         character == '|' ||
         character == '<' ||
         character == '>' ||
         character == '?';

}

} // end anonymous namespace

std::string finishExpression(const std::string& expression)
{
   std::string result = expression;

   // If the last character of the expression is a binary op, then we
   // place a '.' after it
   int n = expression.length();
   if (isBinaryOp(expression[n - 1]))
      result.append(".");

   std::vector<char> terminators;

   char top = '\0';
   terminators.push_back(top);

   bool in_string = false;
   bool in_escape = false;

   for (int i = 0; i < n; i++) {

      char cur = expression[i];

      if (in_string) {

         if (in_escape) {
            in_escape = false;
            continue;
         }

         if (cur == '\\') {
            in_escape = true;
            continue;
         }

         if (cur != top) {
            continue;
         }

         in_string = false;
         terminators.pop_back();
         top = terminators.back();
         continue;

      }

      if (cur == top) {
         terminators.pop_back();
         top = terminators.back();
      } else if (cur == '(' || cur == '{' || cur == '[') {
         char end = ends(cur);
         top = end;
         terminators.push_back(top);
      } else if (cur == '"' || cur == '`' || cur == '\'') {
         top = cur;
         in_string = true;
         terminators.push_back(top);
      }

   }

   // append to the output
   for (std::size_t i = terminators.size() - 1; i > 0; --i)
      result.push_back(terminators[i]);

   return result;
}

namespace {

SEXP rs_finishExpression(SEXP stringSEXP)
{
   r::sexp::Protect rProtect;
   int n = r::sexp::length(stringSEXP);

   std::vector<std::string> output;
   output.reserve(n);
   for (int i = 0; i < n; ++i)
      output.push_back(finishExpression(CHAR(STRING_ELT(stringSEXP, i))));

   return r::sexp::create(output, &rProtect);
}

struct SourceIndexCompletions {
   std::vector<std::string> completions;
   std::vector<bool> isFunction;
   bool moreAvailable;
};

SourceIndexCompletions getSourceIndexCompletions(const std::string& token)
{
   // get functions from the source index
   std::vector<core::r_util::RSourceItem> items;
   bool moreAvailable = false;

   // TODO: wire up 'moreAvailable'
   modules::code_search::searchSource(token,
                                      1E3,
                                      true,
                                      &items,
                                      &moreAvailable);

   SourceIndexCompletions srcCompletions;
   BOOST_FOREACH(const core::r_util::RSourceItem& item, items)
   {
      if (item.braceLevel() == 0)
      {
         srcCompletions.completions.push_back(item.name());
         srcCompletions.isFunction.push_back(item.isFunction() || item.isMethod());
      }
   }

   srcCompletions.moreAvailable = moreAvailable;
   return srcCompletions;
}

SEXP rs_getSourceIndexCompletions(SEXP tokenSEXP)
{
   r::sexp::Protect protect;
   std::string token = r::sexp::asString(tokenSEXP);
   SourceIndexCompletions srcCompletions = getSourceIndexCompletions(token);

   std::vector<std::string> names;
   names.push_back("completions");
   names.push_back("isFunction");
   names.push_back("moreAvailable");

   SEXP resultSEXP = r::sexp::createList(names, &protect);
   r::sexp::setNamedListElement(resultSEXP, "completions", srcCompletions.completions);
   r::sexp::setNamedListElement(resultSEXP, "isFunction", srcCompletions.isFunction);
   r::sexp::setNamedListElement(resultSEXP, "moreAvailable", srcCompletions.moreAvailable);

   return resultSEXP;
}

bool subsequenceFilter(const FileInfo& fileInfo,
                       const std::string& pattern,
                       int parentPathLength,
                       int maxCount,
                       std::vector<std::string>* pPaths,
                       int* pCount,
                       bool* pMoreAvailable)
{
   if (*pCount >= maxCount)
   {
      *pMoreAvailable = true;
      return false;
   }

   bool isSubsequence = string_utils::isSubsequence(
            fileInfo.absolutePath().substr(parentPathLength + 2),
            pattern,
            true);

   if (isSubsequence)
   {
      ++*pCount;
      pPaths->push_back(fileInfo.absolutePath());
   }

   // Always add subdirectories
   if (fileInfo.isDirectory())
   {
      return true;
   }

   return false;
}

SEXP rs_scanFiles(SEXP pathSEXP,
                  SEXP patternSEXP,
                  SEXP maxCountSEXP)
{
   std::string path = r::sexp::asString(pathSEXP);
   std::string pattern = r::sexp::asString(patternSEXP);
   int maxCount = r::sexp::asInteger(maxCountSEXP);

   FilePath filePath(path);
   FileInfo fileInfo(filePath);
   tree<FileInfo> tree;

   core::system::FileScannerOptions options;
   options.recursive = true;
   options.yield = true;

   // Use a subsequence filter, and bail after too many files
   std::vector<std::string> paths;

   int count = 0;
   bool moreAvailable = false;
   options.filter = boost::bind(subsequenceFilter,
                                _1,
                                pattern,
                                path.length(),
                                maxCount,
                                &paths,
                                &count,
                                &moreAvailable);

   Error error = scanFiles(fileInfo, options, &tree);
   if (error)
      return R_NilValue;

   r::sexp::Protect protect;
   r::sexp::ListBuilder builder(&protect);

   builder.add("paths", paths);
   builder.add("more_available", moreAvailable);

   return r::sexp::create(builder, &protect);
}

SEXP rs_isSubsequence(SEXP stringsSEXP, SEXP querySEXP)
{
   std::vector<std::string> strings;
   if (!r::sexp::fillVectorString(stringsSEXP, &strings))
      return R_NilValue;

   std::string query = r::sexp::asString(querySEXP);

   std::vector<bool> result(strings.size());

   std::transform(strings.begin(),
                  strings.end(),
                  result.begin(),
                  boost::bind(
                     string_utils::isSubsequence,
                     _1,
                     query));

   r::sexp::Protect protect;
   return r::sexp::create(result, &protect);

}

SEXP rs_getActiveFrame(SEXP depthSEXP)
{
   int depth = r::sexp::asInteger(depthSEXP);
   RCNTXT* context = r::getGlobalContext();
   for (int i = 0; i < depth; ++i)
   {
      context = context->nextcontext;
      if (context == NULL)
         return R_NilValue;
   }
   return context->cloenv;
}

SEXP rs_getNAMESPACEImportedSymbols(SEXP documentIdSEXP)
{
   std::string documentId = r::sexp::asString(documentIdSEXP);
   boost::shared_ptr<core::r_util::RSourceIndex> index =
         code_search::rSourceIndex().get(documentId);

   using namespace core::r_util;
   std::vector<std::string> pkgs;

   BOOST_FOREACH(const std::string& pkg, RSourceIndex::getImportedPackages())
   {
      pkgs.push_back(pkg);
   }

   BOOST_FOREACH(const std::string& pkg,
                 RSourceIndex::getImportFromDirectives() | boost::adaptors::map_keys)
   {
      pkgs.push_back(pkg);
   }

   using namespace r::sexp;
   Protect protect;
   r::sexp::ListBuilder builder(&protect);

   BOOST_FOREACH(const std::string& pkg, pkgs)
   {
      const AsyncLibraryCompletions& completions = RSourceIndex::getCompletions(pkg);
      r::sexp::ListBuilder child(&protect);

      // If the inferred package is listed _only_ in the NAMESPACE 'importFrom',
      // then we want to selectively return symbols.
      if ((index && index->getInferredPackages().count(pkg) == 0) &&
          RSourceIndex::getImportedPackages().count(pkg) == 0 &&
          RSourceIndex::getImportFromDirectives().count(pkg) != 0)
      {
         std::vector<std::string> exports;
         std::vector<int> types;

         std::set<std::string>& directives =
               RSourceIndex::getImportFromDirectives()[pkg];

         BOOST_FOREACH(const std::string& item, directives)
         {
            std::vector<std::string>::const_iterator it =
                  std::find(completions.exports.begin(),
                            completions.exports.end(),
                            item);

            std::size_t index = it - completions.exports.begin();

            exports.push_back(completions.exports[index]);
            types.push_back(completions.types[index]);
         }

         child.add("exports", exports);
         child.add("types", types);

      }
      else
      {
         child.add("exports", completions.exports);
         child.add("types", completions.types);
      }

      builder.add(pkg, child);
   }

   return r::sexp::create(builder, &protect);
}

SEXP rs_getInferredCompletions(SEXP packagesSEXP)
{
   using namespace rstudio::core::r_util;

   std::vector<std::string> packages;
   if (!r::sexp::fillVectorString(packagesSEXP, &packages))
      return R_NilValue;

   r::sexp::Protect protect;
   r::sexp::ListBuilder parent(&protect);

   for (std::vector<std::string>::const_iterator it = packages.begin();
        it != packages.end();
        ++it)
   {
      DEBUG("Adding entry for '" << *it << "'");
      AsyncLibraryCompletions completions = RSourceIndex::getCompletions(*it);

      r::sexp::ListBuilder builder(&protect);
      builder.add("exports", completions.exports);
      builder.add("types", completions.types);
      builder.add("functions", completions.functions);
      parent.add(*it, builder);
   }

   return r::sexp::create(parent, &protect);
}

SEXP rs_listInferredPackages(SEXP documentIdSEXP)
{
   std::string documentId = r::sexp::asString(documentIdSEXP);
   boost::shared_ptr<core::r_util::RSourceIndex> index =
         code_search::rSourceIndex().get(documentId);

   // NOTE: can occur when user edits file not in source index
   if (index == NULL)
      return R_NilValue;

   std::set<std::string> pkgs = index->getInferredPackages();
   pkgs.insert(index->getImportedPackages().begin(),
               index->getImportedPackages().end());

   r::sexp::Protect protect;
   return r::sexp::create(pkgs, &protect);

}

} // end anonymous namespace

Error initialize() {

   RS_REGISTER_CALL_METHOD(rs_finishExpression, 1);
   RS_REGISTER_CALL_METHOD(rs_getSourceIndexCompletions, 1);
   RS_REGISTER_CALL_METHOD(rs_scanFiles, 4);
   RS_REGISTER_CALL_METHOD(rs_isSubsequence, 2);
   RS_REGISTER_CALL_METHOD(rs_getActiveFrame, 1);
   RS_REGISTER_CALL_METHOD(rs_listInferredPackages, 1);
   RS_REGISTER_CALL_METHOD(rs_getInferredCompletions, 1);
   RS_REGISTER_CALL_METHOD(rs_getNAMESPACEImportedSymbols, 1);

   using boost::bind;
   using namespace module_context;
   ExecBlock initBlock;
   initBlock.addFunctions()
         (bind(sourceModuleRFile, "SessionRCompletions.R"));
   return initBlock.execute();
}

} // namespace r_completions
} // namespace modules
} // namespace session
} // namespace rstudio
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qdeclarativeutilmodule_p.h"
#include "qfxperf_p_p.h"
#include "qdeclarativeanimation_p.h"
#include "qdeclarativeanimation_p_p.h"
#include "qdeclarativebehavior_p.h"
#include "qdeclarativebind_p.h"
#include "qdeclarativeconnections_p.h"
#include "qdeclarativedatetimeformatter_p.h"
#include "qdeclarativeeasefollow_p.h"
#include "qdeclarativefontloader_p.h"
#include "qdeclarativelistaccessor_p.h"
#include "qdeclarativelistmodel_p.h"
#include "qdeclarativenullablevalue_p_p.h"
#include "qdeclarativenumberformatter_p.h"
#include "qdeclarativeopenmetaobject_p.h"
#include "qdeclarativepackage_p.h"
#include "qdeclarativepixmapcache_p.h"
#include "qdeclarativepropertychanges_p.h"
#include "qdeclarativepropertymap.h"
#include "qdeclarativespringfollow_p.h"
#include "qdeclarativestategroup_p.h"
#include "qdeclarativestateoperations_p.h"
#include "qdeclarativestate_p.h"
#include "qdeclarativestate_p_p.h"
#include "qdeclarativestyledtext_p.h"
#include "qdeclarativesystempalette_p.h"
#include "qdeclarativetimeline_p_p.h"
#include "qdeclarativetimer_p.h"
#include "qdeclarativetransitionmanager_p_p.h"
#include "qdeclarativetransition_p.h"
#include "qdeclarativeview.h"
#include "qdeclarativexmllistmodel_p.h"
#include "qnumberformat_p.h"
#include "qperformancelog_p_p.h"

void QDeclarativeUtilModule::defineModule()
{
    QML_REGISTER_TYPE(Qt,4,6,AnchorChanges,QDeclarativeAnchorChanges);
    QML_REGISTER_TYPE(Qt,4,6,Behavior,QDeclarativeBehavior);
    QML_REGISTER_TYPE(Qt,4,6,Binding,QDeclarativeBind);
    QML_REGISTER_TYPE(Qt,4,6,ColorAnimation,QDeclarativeColorAnimation);
    QML_REGISTER_TYPE(Qt,4,6,Connections,QDeclarativeConnections);
    QML_REGISTER_TYPE(Qt,4,6,DateTimeFormatter,QDeclarativeDateTimeFormatter);
    QML_REGISTER_TYPE(Qt,4,6,EaseFollow,QDeclarativeEaseFollow);;
    QML_REGISTER_TYPE(Qt,4,6,FontLoader,QDeclarativeFontLoader);
    QML_REGISTER_TYPE(Qt,4,6,ListElement,QDeclarativeListElement);
    QML_REGISTER_TYPE(Qt,4,6,NumberAnimation,QDeclarativeNumberAnimation);
    QML_REGISTER_TYPE(Qt,4,6,NumberFormatter,QDeclarativeNumberFormatter);;
    QML_REGISTER_TYPE(Qt,4,6,Package,QDeclarativePackage);
    QML_REGISTER_TYPE(Qt,4,6,ParallelAnimation,QDeclarativeParallelAnimation);
    QML_REGISTER_TYPE(Qt,4,6,ParentAction,QDeclarativeParentAction);
    QML_REGISTER_TYPE(Qt,4,6,ParentAnimation,QDeclarativeParentAnimation);
    QML_REGISTER_TYPE(Qt,4,6,ParentChange,QDeclarativeParentChange);
    QML_REGISTER_TYPE(Qt,4,6,PauseAnimation,QDeclarativePauseAnimation);
    QML_REGISTER_TYPE(Qt,4,6,PropertyAction,QDeclarativePropertyAction);
    QML_REGISTER_TYPE(Qt,4,6,PropertyAnimation,QDeclarativePropertyAnimation);
    QML_REGISTER_TYPE(Qt,4,6,RotationAnimation,QDeclarativeRotationAnimation);
    QML_REGISTER_TYPE(Qt,4,6,ScriptAction,QDeclarativeScriptAction);
    QML_REGISTER_TYPE(Qt,4,6,SequentialAnimation,QDeclarativeSequentialAnimation);
    QML_REGISTER_TYPE(Qt,4,6,SpringFollow,QDeclarativeSpringFollow);
    QML_REGISTER_TYPE(Qt,4,6,StateChangeScript,QDeclarativeStateChangeScript);
    QML_REGISTER_TYPE(Qt,4,6,StateGroup,QDeclarativeStateGroup);
    QML_REGISTER_TYPE(Qt,4,6,State,QDeclarativeState);
    QML_REGISTER_TYPE(Qt,4,6,SystemPalette,QDeclarativeSystemPalette);
    QML_REGISTER_TYPE(Qt,4,6,Timer,QDeclarativeTimer);
    QML_REGISTER_TYPE(Qt,4,6,Transition,QDeclarativeTransition);
    QML_REGISTER_TYPE(Qt,4,6,Vector3dAnimation,QDeclarativeVector3dAnimation);
#ifndef QT_NO_XMLPATTERNS
    QML_REGISTER_TYPE(Qt,4,6,XmlListModel,QDeclarativeXmlListModel);
    QML_REGISTER_TYPE(Qt,4,6,XmlRole,QDeclarativeXmlListModelRole);
#endif

    QML_REGISTER_NOCREATE_TYPE(QDeclarativeAnchors);
    QML_REGISTER_NOCREATE_TYPE(QDeclarativeAbstractAnimation);
    QML_REGISTER_NOCREATE_TYPE(QDeclarativeStateOperation);
    QML_REGISTER_NOCREATE_TYPE(QNumberFormat);

    QML_REGISTER_CUSTOM_TYPE(Qt, 4,6, ListModel, QDeclarativeListModel, QDeclarativeListModelParser);
    QML_REGISTER_CUSTOM_TYPE(Qt, 4,6, PropertyChanges, QDeclarativePropertyChanges, QDeclarativePropertyChangesParser);
    QML_REGISTER_CUSTOM_TYPE(Qt, 4,6, Connections, QDeclarativeConnections, QDeclarativeConnectionsParser);
}
<commit_msg>compile fix for WinCE<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qdeclarativeutilmodule_p.h"
#include "qfxperf_p_p.h"
#include "qdeclarativeanimation_p.h"
#include "qdeclarativeanimation_p_p.h"
#include "qdeclarativebehavior_p.h"
#include "qdeclarativebind_p.h"
#include "qdeclarativeconnections_p.h"
#include "qdeclarativedatetimeformatter_p.h"
#include "qdeclarativeeasefollow_p.h"
#include "qdeclarativefontloader_p.h"
#include "qdeclarativelistaccessor_p.h"
#include "qdeclarativelistmodel_p.h"
#include "qdeclarativenullablevalue_p_p.h"
#include "qdeclarativenumberformatter_p.h"
#include "qdeclarativeopenmetaobject_p.h"
#include "qdeclarativepackage_p.h"
#include "qdeclarativepixmapcache_p.h"
#include "qdeclarativepropertychanges_p.h"
#include "qdeclarativepropertymap.h"
#include "qdeclarativespringfollow_p.h"
#include "qdeclarativestategroup_p.h"
#include "qdeclarativestateoperations_p.h"
#include "qdeclarativestate_p.h"
#include "qdeclarativestate_p_p.h"
#include "qdeclarativestyledtext_p.h"
#include "qdeclarativesystempalette_p.h"
#include "qdeclarativetimeline_p_p.h"
#include "qdeclarativetimer_p.h"
#include "qdeclarativetransitionmanager_p_p.h"
#include "qdeclarativetransition_p.h"
#include "qdeclarativeview.h"
#ifndef QT_NO_XMLPATTERNS
#include "qdeclarativexmllistmodel_p.h"
#endif
#include "qnumberformat_p.h"
#include "qperformancelog_p_p.h"

void QDeclarativeUtilModule::defineModule()
{
    QML_REGISTER_TYPE(Qt,4,6,AnchorChanges,QDeclarativeAnchorChanges);
    QML_REGISTER_TYPE(Qt,4,6,Behavior,QDeclarativeBehavior);
    QML_REGISTER_TYPE(Qt,4,6,Binding,QDeclarativeBind);
    QML_REGISTER_TYPE(Qt,4,6,ColorAnimation,QDeclarativeColorAnimation);
    QML_REGISTER_TYPE(Qt,4,6,Connections,QDeclarativeConnections);
    QML_REGISTER_TYPE(Qt,4,6,DateTimeFormatter,QDeclarativeDateTimeFormatter);
    QML_REGISTER_TYPE(Qt,4,6,EaseFollow,QDeclarativeEaseFollow);;
    QML_REGISTER_TYPE(Qt,4,6,FontLoader,QDeclarativeFontLoader);
    QML_REGISTER_TYPE(Qt,4,6,ListElement,QDeclarativeListElement);
    QML_REGISTER_TYPE(Qt,4,6,NumberAnimation,QDeclarativeNumberAnimation);
    QML_REGISTER_TYPE(Qt,4,6,NumberFormatter,QDeclarativeNumberFormatter);;
    QML_REGISTER_TYPE(Qt,4,6,Package,QDeclarativePackage);
    QML_REGISTER_TYPE(Qt,4,6,ParallelAnimation,QDeclarativeParallelAnimation);
    QML_REGISTER_TYPE(Qt,4,6,ParentAction,QDeclarativeParentAction);
    QML_REGISTER_TYPE(Qt,4,6,ParentAnimation,QDeclarativeParentAnimation);
    QML_REGISTER_TYPE(Qt,4,6,ParentChange,QDeclarativeParentChange);
    QML_REGISTER_TYPE(Qt,4,6,PauseAnimation,QDeclarativePauseAnimation);
    QML_REGISTER_TYPE(Qt,4,6,PropertyAction,QDeclarativePropertyAction);
    QML_REGISTER_TYPE(Qt,4,6,PropertyAnimation,QDeclarativePropertyAnimation);
    QML_REGISTER_TYPE(Qt,4,6,RotationAnimation,QDeclarativeRotationAnimation);
    QML_REGISTER_TYPE(Qt,4,6,ScriptAction,QDeclarativeScriptAction);
    QML_REGISTER_TYPE(Qt,4,6,SequentialAnimation,QDeclarativeSequentialAnimation);
    QML_REGISTER_TYPE(Qt,4,6,SpringFollow,QDeclarativeSpringFollow);
    QML_REGISTER_TYPE(Qt,4,6,StateChangeScript,QDeclarativeStateChangeScript);
    QML_REGISTER_TYPE(Qt,4,6,StateGroup,QDeclarativeStateGroup);
    QML_REGISTER_TYPE(Qt,4,6,State,QDeclarativeState);
    QML_REGISTER_TYPE(Qt,4,6,SystemPalette,QDeclarativeSystemPalette);
    QML_REGISTER_TYPE(Qt,4,6,Timer,QDeclarativeTimer);
    QML_REGISTER_TYPE(Qt,4,6,Transition,QDeclarativeTransition);
    QML_REGISTER_TYPE(Qt,4,6,Vector3dAnimation,QDeclarativeVector3dAnimation);
#ifndef QT_NO_XMLPATTERNS
    QML_REGISTER_TYPE(Qt,4,6,XmlListModel,QDeclarativeXmlListModel);
    QML_REGISTER_TYPE(Qt,4,6,XmlRole,QDeclarativeXmlListModelRole);
#endif

    QML_REGISTER_NOCREATE_TYPE(QDeclarativeAnchors);
    QML_REGISTER_NOCREATE_TYPE(QDeclarativeAbstractAnimation);
    QML_REGISTER_NOCREATE_TYPE(QDeclarativeStateOperation);
    QML_REGISTER_NOCREATE_TYPE(QNumberFormat);

    QML_REGISTER_CUSTOM_TYPE(Qt, 4,6, ListModel, QDeclarativeListModel, QDeclarativeListModelParser);
    QML_REGISTER_CUSTOM_TYPE(Qt, 4,6, PropertyChanges, QDeclarativePropertyChanges, QDeclarativePropertyChangesParser);
    QML_REGISTER_CUSTOM_TYPE(Qt, 4,6, Connections, QDeclarativeConnections, QDeclarativeConnectionsParser);
}
<|endoftext|>


<commit_before>#include "kwic.h"
#include <iterator>
using wordVector=std::vector<std::vector<Word>>;

void kwic(std::istream &is, std::ostream &os){
	Word word{};
	std::vector<Word> words{};
	std::ostream_iterator<Word> out_it (os, " ");
	while(is >> word){
		words.push_back(word);
		word.value = "";
	}
	wordVector permutedVector = permuteWords(words);
	for (auto var = 0; var < permutedVector.size(); ++var) {
		std::copy(permutedVector.at(var).begin(), permutedVector.at(var).end(), out_it);
		os << "\n";
	}
}

std::vector<std::vector<Word>> permuteWords(std::vector<Word> words){
	wordVector permutedVector(words.size(), std::vector<Word>(words.size()));
	for (unsigned int var = 0; var < words.size(); ++var) {
		std::rotate_copy(words.begin(), words.begin()+var+1,words.end(), permutedVector.at(var).begin());
	}
	return permutedVector;
}

<commit_msg>Removed using keyword<commit_after>#include "kwic.h"
#include <iterator>

void kwic(std::istream &is, std::ostream &os){
	Word word{};
	std::vector<Word> words{};
	std::ostream_iterator<Word> out_it (os, " ");
	while(is >> word){
		words.push_back(word);
		word.value = "";
	}
	auto permutedVector = permuteWords(words);
	for (auto var = 0; var < permutedVector.size(); ++var) {
		std::copy(permutedVector.at(var).begin(), permutedVector.at(var).end(), out_it);
		os << "\n";
	}
}

std::vector<std::vector<Word>> permuteWords(std::vector<Word> words){
	std::vector<std::vector<Word>> permutedVector(words.size(), std::vector<Word>(words.size()));
	for (unsigned int var = 0; var < words.size(); ++var) {
		std::rotate_copy(words.begin(), words.begin()+var+1,words.end(), permutedVector.at(var).begin());
	}
	return permutedVector;
}

<|endoftext|>