<commit_before>// Copyright 2010-2015 RethinkDB, all rights reserved.
#ifndef CLUSTERING_IMMEDIATE_CONSISTENCY_REMOTE_REPLICATOR_CLIENT_HPP_
#define CLUSTERING_IMMEDIATE_CONSISTENCY_REMOTE_REPLICATOR_CLIENT_HPP_

#include <queue>

#include "clustering/generic/registrant.hpp"
#include "clustering/immediate_consistency/backfill_throttler.hpp"
#include "clustering/immediate_consistency/remote_replicator_metadata.hpp"
#include "clustering/immediate_consistency/replica.hpp"
#include "concurrency/coro_pool.hpp"
#include "concurrency/queue/disk_backed_queue_wrapper.hpp"
#include "concurrency/semaphore.hpp"

class backfill_progress_tracker_t;

/* `remote_replicator_client_t` contacts a `remote_replicator_server_t` on another server
to sign up for writes to a given shard, and then applies them to a `store_t` on the same
server. It also performs a backfill to initialize the state of the `store_t`, and handles
the transition between the backfill and the streaming writes.

There is one `remote_replicator_client_t` on each secondary replica server of each shard.
`secondary_execution_t` constructs it. */

class remote_replicator_client_t {
public:
    /* Here's how the backfill works:

    1. We sign up for a stream of writes from the `remote_replicator_server_t`. Initially
        we let the writes queue up (in the form of blocked coroutines) as they arrive.
    2. We start backfilling from the `replica_t`. We ensure that the `replica_t` is on
        the same branch as the `remote_replicator_server_t`, and that the backfill's end
        timestamp is greater than or equal to the stream's begin timestamp.
    3. Suppose that the backfill sends us the range [-inf, K) at timestamp T and the
        range [K, L) at timestamp T+1. Then we unblock the streaming write with timestamp
        T+1 but only apply it to range [-inf, K). Then when the backfill sneds us the
        range [L, M) at timestamp T+2 we unblock the streaming write with timestamp T+2
        and apply it to the range [-inf, L). This way, every change gets applied exactly
        once, either as part of a streaming write or as part of a backfill. This
        procedure relies on the fact that the backfill proceeds from left to right
        monotonically and the versions it sends increase monotonically in timestamps.
    4. Any given write only remains queued up for as long as it takes for it to be
        applied on the `replica_t` and then for another chunk with the updated timestamp
        to be sent over the network.
    5. If the `backfill_throttler_t` tells us to pause, then while the backfill is paused
        we unconditionally apply writes to the area we've already backfilled. When the
        pause ends, we resume the backfill but ensure that the backfill resumes after the
        timestamp of the last write applied during the pause.

    The `remote_replicator_client_t` constructor blocks until this entire process is
    complete. The backfilled data will be safely flushed to disk by the time it returns.
    */

    remote_replicator_client_t(
        backfill_throttler_t *backfill_throttler,
        const backfill_config_t &backfill_config,
        backfill_progress_tracker_t *backfill_progress_tracker,
        mailbox_manager_t *mailbox_manager,
        const server_id_t &server_id,
        backfill_throttler_t::priority_t::critical_t is_critical_priority,

        const branch_id_t &branch_id,
        const remote_replicator_server_bcard_t &remote_replicator_server_bcard,
        const replica_bcard_t &replica_bcard,
        const server_id_t &primary_server_id,

        store_view_t *store,
        branch_history_manager_t *branch_history_manager,

        signal_t *interruptor) THROWS_ONLY(interrupted_exc_t);

    ~remote_replicator_client_t();

private:
    class timestamp_range_tracker_t;

    /* `on_write_async()`, `on_write_sync()`, and `on_read()` are mailbox callbacks for
    `write_async_mailbox_`, `write_sync_mailbox_`, and `read_mailbox_`. */
    void on_write_async(
            signal_t *interruptor,
            write_t &&write,
            state_timestamp_t timestamp,
            order_token_t order_token,
            const mailbox_t<void()>::address_t &ack_addr)
        THROWS_ONLY(interrupted_exc_t);

    void on_write_sync(
            signal_t *interruptor,
            const write_t &write,
            state_timestamp_t timestamp,
            order_token_t order_token,
            write_durability_t durability,
            const mailbox_t<void(write_response_t)>::address_t &ack_addr)
        THROWS_ONLY(interrupted_exc_t);

    void on_read(
            signal_t *interruptor,
            const read_t &read,
            state_timestamp_t min_timestamp,
            const mailbox_t<void(read_response_t)>::address_t &ack_addr)
        THROWS_ONLY(interrupted_exc_t);

    mailbox_manager_t *const mailbox_manager_;
    store_view_t *const store_;
    region_t const region_;   /* same as `store_->get_region()` */
    branch_id_t const branch_id_;

    /* During the constructor, we alternate between `PAUSED` and `BACKFILLING`. When the
    constructor is done, we switch to `STREAMING` mode and stay there. */
    enum class backfill_mode_t {
        /* We haven't backfilled completely, but we aren't currently backfilling either.
        Usually this means we're waiting for the backfill throttler. However, we will
        still accept streaming writes in the regions we've already backfilled. */
        PAUSED,
        /* We're actively receiving backfill items over the network. Whenever the
        backfill reaches a given timestamp, we'll also apply all writes at or before that
        timestamp; this is mediated by `backfilling_thresholds_`. */
        BACKFILLING,
        /* We finished backfilling and we're just applying writes as they arrive. */
        STREAMING
        };
    backfill_mode_t mode_;

    /* `timestamp_range_tracker_t` is essentially a `region_map_t<state_timestamp_t>`,
    but in a different format and optimized for this specific use case. The domain of
    `tracker_` is the region that has been backfilled thus far; the values are equal to
    the current timestamps in the B-tree metainfo. `tracker_` is used to make sure that
    every change gets applied either as a streaming change or as a backfilled change but
    not as both. `tracker_` exists only during the backfill; it gets destroyed after the
    backfill is over. */
    scoped_ptr_t<timestamp_range_tracker_t> tracker_;

    /* Returns `true` if the next write can be applied now, instead of having to wait for
    the backfill to make more progress. */
    bool next_write_can_proceed(mutex_assertion_t::acq_t *mutex_acq);

    /* If the next write cannot proceed, it will set `next_write_waiter_` and wait for it
    to be pulsed. */
    cond_t *next_write_waiter_;

    /* `timestamp_enforcer_` is used to order writes as they arrive. `replica_` will do
    its own ordering of writes, so `timestamp_enforcer_` is only important during the
    constructor before `replica_` has been created. */
    scoped_ptr_t<timestamp_enforcer_t> timestamp_enforcer_;

    /* `replica_` is created at the end of the constructor, once the backfill is over. */
    scoped_ptr_t<replica_t> replica_;

    /* `mutex_assertion_` protects `mode_`, `tracker_`, `next_write_waiter_`,
    `timestamp_enforcer_`, and `replica_`; but we aren't particularly careful about
    always acquiring it before accessing those variables. */
    mutex_assertion_t mutex_assertion_;

    /* `registered_` is pulsed once `timestamp_enforcer_` is set up. So
    `on_write_async()` has to wait for it before proceeding. */
    cond_t registered_;

    /* `cleanup_rwlock_` is used to temporarily lock out writes when doing the very last
    phase of the backfill. Writes acquire it in read mode; the last phase of the backfill
    acquires it in write mode. */
    rwlock_t cleanup_rwlock_;

    remote_replicator_client_bcard_t::write_async_mailbox_t write_async_mailbox_;
    remote_replicator_client_bcard_t::write_sync_mailbox_t write_sync_mailbox_;
    remote_replicator_client_bcard_t::read_mailbox_t read_mailbox_;

    /* We use `registrant_` to subscribe to a stream of reads and writes from the
    dispatcher via the `remote_replicator_server_t`. */
    scoped_ptr_t<registrant_t<remote_replicator_client_bcard_t> > registrant_;
};

#endif /* CLUSTERING_IMMEDIATE_CONSISTENCY_REMOTE_REPLICATOR_HPP_ */

<commit_msg>Clarify a comment.<commit_after>// Copyright 2010-2015 RethinkDB, all rights reserved.
#ifndef CLUSTERING_IMMEDIATE_CONSISTENCY_REMOTE_REPLICATOR_CLIENT_HPP_
#define CLUSTERING_IMMEDIATE_CONSISTENCY_REMOTE_REPLICATOR_CLIENT_HPP_

#include <queue>

#include "clustering/generic/registrant.hpp"
#include "clustering/immediate_consistency/backfill_throttler.hpp"
#include "clustering/immediate_consistency/remote_replicator_metadata.hpp"
#include "clustering/immediate_consistency/replica.hpp"
#include "concurrency/coro_pool.hpp"
#include "concurrency/queue/disk_backed_queue_wrapper.hpp"
#include "concurrency/semaphore.hpp"

class backfill_progress_tracker_t;

/* `remote_replicator_client_t` contacts a `remote_replicator_server_t` on another server
to sign up for writes to a given shard, and then applies them to a `store_t` on the same
server. It also performs a backfill to initialize the state of the `store_t`, and handles
the transition between the backfill and the streaming writes.

There is one `remote_replicator_client_t` on each secondary replica server of each shard.
`secondary_execution_t` constructs it. */

class remote_replicator_client_t {
public:
    /* Here's how the backfill works:

    1. We sign up for a stream of writes from the `remote_replicator_server_t`. Initially
        we let the writes queue up (in the form of blocked coroutines) as they arrive.
    2. We start backfilling from the `replica_t`. We ensure that the `replica_t` is on
        the same branch as the `remote_replicator_server_t`, and that the backfill's end
        timestamp is greater than or equal to the stream's begin timestamp.
    3. Suppose that the backfill sends us the range [-inf, K) at timestamp T and the
        range [K, L) at timestamp T+1. Then we unblock the streaming write with timestamp
        T+1 but only apply it to range [-inf, K). Then when the backfill sneds us the
        range [L, M) at timestamp T+2 we unblock the streaming write with timestamp T+2
        and apply it to the range [-inf, L). This way, every change gets applied exactly
        once, either as part of a streaming write or as part of a backfill. This
        procedure relies on the fact that the backfill proceeds from left to right
        monotonically and the versions it sends increase monotonically in timestamps.
    4. Any given write only remains queued up for as long as it takes for it to be
        applied on the `replica_t` and then for another chunk with the updated timestamp
        to be sent over the network.
    5. If the `backfill_throttler_t` tells us to pause, then while the backfill is paused
        we unconditionally apply writes to the area we've already backfilled. When the
        pause ends, we resume the backfill but ensure that all future backfilled chunks
        have timestamps greater than or equal to the timestamp of the last write
        backfilled during the pause. This is because during the pause we already
        discarded the parts of the streaming writes that applied to the unbackfilled
        area, so we have to receive those changes as part of the backfill or we won't
        get them at all.

    The `remote_replicator_client_t` constructor blocks until this entire process is
    complete. The backfilled data will be safely flushed to disk by the time it returns.
    */

    remote_replicator_client_t(
        backfill_throttler_t *backfill_throttler,
        const backfill_config_t &backfill_config,
        backfill_progress_tracker_t *backfill_progress_tracker,
        mailbox_manager_t *mailbox_manager,
        const server_id_t &server_id,
        backfill_throttler_t::priority_t::critical_t is_critical_priority,

        const branch_id_t &branch_id,
        const remote_replicator_server_bcard_t &remote_replicator_server_bcard,
        const replica_bcard_t &replica_bcard,
        const server_id_t &primary_server_id,

        store_view_t *store,
        branch_history_manager_t *branch_history_manager,

        signal_t *interruptor) THROWS_ONLY(interrupted_exc_t);

    ~remote_replicator_client_t();

private:
    class timestamp_range_tracker_t;

    /* `on_write_async()`, `on_write_sync()`, and `on_read()` are mailbox callbacks for
    `write_async_mailbox_`, `write_sync_mailbox_`, and `read_mailbox_`. */
    void on_write_async(
            signal_t *interruptor,
            write_t &&write,
            state_timestamp_t timestamp,
            order_token_t order_token,
            const mailbox_t<void()>::address_t &ack_addr)
        THROWS_ONLY(interrupted_exc_t);

    void on_write_sync(
            signal_t *interruptor,
            const write_t &write,
            state_timestamp_t timestamp,
            order_token_t order_token,
            write_durability_t durability,
            const mailbox_t<void(write_response_t)>::address_t &ack_addr)
        THROWS_ONLY(interrupted_exc_t);

    void on_read(
            signal_t *interruptor,
            const read_t &read,
            state_timestamp_t min_timestamp,
            const mailbox_t<void(read_response_t)>::address_t &ack_addr)
        THROWS_ONLY(interrupted_exc_t);

    mailbox_manager_t *const mailbox_manager_;
    store_view_t *const store_;
    region_t const region_;   /* same as `store_->get_region()` */
    branch_id_t const branch_id_;

    /* During the constructor, we alternate between `PAUSED` and `BACKFILLING`. When the
    constructor is done, we switch to `STREAMING` mode and stay there. */
    enum class backfill_mode_t {
        /* We haven't backfilled completely, but we aren't currently backfilling either.
        Usually this means we're waiting for the backfill throttler. However, we will
        still accept streaming writes in the regions we've already backfilled. */
        PAUSED,
        /* We're actively receiving backfill items over the network. Whenever the
        backfill reaches a given timestamp, we'll also apply all writes at or before that
        timestamp; this is mediated by `backfilling_thresholds_`. */
        BACKFILLING,
        /* We finished backfilling and we're just applying writes as they arrive. */
        STREAMING
        };
    backfill_mode_t mode_;

    /* `timestamp_range_tracker_t` is essentially a `region_map_t<state_timestamp_t>`,
    but in a different format and optimized for this specific use case. The domain of
    `tracker_` is the region that has been backfilled thus far; the values are equal to
    the current timestamps in the B-tree metainfo. `tracker_` is used to make sure that
    every change gets applied either as a streaming change or as a backfilled change but
    not as both. `tracker_` exists only during the backfill; it gets destroyed after the
    backfill is over. */
    scoped_ptr_t<timestamp_range_tracker_t> tracker_;

    /* Returns `true` if the next write can be applied now, instead of having to wait for
    the backfill to make more progress. */
    bool next_write_can_proceed(mutex_assertion_t::acq_t *mutex_acq);

    /* If the next write cannot proceed, it will set `next_write_waiter_` and wait for it
    to be pulsed. */
    cond_t *next_write_waiter_;

    /* `timestamp_enforcer_` is used to order writes as they arrive. `replica_` will do
    its own ordering of writes, so `timestamp_enforcer_` is only important during the
    constructor before `replica_` has been created. */
    scoped_ptr_t<timestamp_enforcer_t> timestamp_enforcer_;

    /* `replica_` is created at the end of the constructor, once the backfill is over. */
    scoped_ptr_t<replica_t> replica_;

    /* `mutex_assertion_` protects `mode_`, `tracker_`, `next_write_waiter_`,
    `timestamp_enforcer_`, and `replica_`; but we aren't particularly careful about
    always acquiring it before accessing those variables. */
    mutex_assertion_t mutex_assertion_;

    /* `registered_` is pulsed once `timestamp_enforcer_` is set up. So
    `on_write_async()` has to wait for it before proceeding. */
    cond_t registered_;

    /* `cleanup_rwlock_` is used to temporarily lock out writes when doing the very last
    phase of the backfill. Writes acquire it in read mode; the last phase of the backfill
    acquires it in write mode. */
    rwlock_t cleanup_rwlock_;

    remote_replicator_client_bcard_t::write_async_mailbox_t write_async_mailbox_;
    remote_replicator_client_bcard_t::write_sync_mailbox_t write_sync_mailbox_;
    remote_replicator_client_bcard_t::read_mailbox_t read_mailbox_;

    /* We use `registrant_` to subscribe to a stream of reads and writes from the
    dispatcher via the `remote_replicator_server_t`. */
    scoped_ptr_t<registrant_t<remote_replicator_client_bcard_t> > registrant_;
};

#endif /* CLUSTERING_IMMEDIATE_CONSISTENCY_REMOTE_REPLICATOR_HPP_ */

<|endoftext|>


<commit_before>// Copyright 2010-2013 RethinkDB, all rights reserved.
#ifndef SERIALIZER_SERIALIZER_HPP_
#define SERIALIZER_SERIALIZER_HPP_

#include <vector>

#include "utils.hpp"
#include <boost/optional.hpp>

#include "arch/types.hpp"
#include "concurrency/cond_var.hpp"
#include "repli_timestamp.hpp"
#include "serializer/types.hpp"

struct index_write_op_t {
    block_id_t block_id;
    // Buf to write. None if not to be modified. Initialized but a null ptr if to be removed from lba.
    boost::optional<counted_t<standard_block_token_t> > token;
    boost::optional<repli_timestamp_t> recency; // Recency, if it should be modified.

    explicit index_write_op_t(block_id_t _block_id,
                              boost::optional<counted_t<standard_block_token_t> > _token = boost::none,
                              boost::optional<repli_timestamp_t> _recency = boost::none)
        : block_id(_block_id), token(_token), recency(_recency) { }
};

/* serializer_t is an abstract interface that describes how each serializer should
behave. It is implemented by log_serializer_t, semantic_checking_serializer_t, and
translator_serializer_t. */

/* Except as otherwise noted, the serializer's methods should only be
   called from the thread it was created on, and it should be
   destroyed on that same thread. */

class serializer_t : public home_thread_mixin_t {
public:
    typedef standard_block_token_t block_token_type;

    serializer_t() { }
    virtual ~serializer_t() { }

    /* The buffers that are used with do_read() and do_write() must be allocated using
    these functions. They can be safely called from any thread. */

    virtual scoped_malloc_t<ser_buffer_t> malloc() = 0;
    virtual scoped_malloc_t<ser_buffer_t> clone(const ser_buffer_t *) = 0;

    /* Allocates a new io account for the underlying file.
    Use delete to free it. */
    file_account_t *make_io_account(int priority);
    virtual file_account_t *make_io_account(int priority, int outstanding_requests_limit) = 0;

    /* Some serializer implementations support read-ahead to speed up cache warmup.
    This is supported through a serializer_read_ahead_callback_t which gets called whenever the serializer has read-ahead some buf.
    The callee can then decide whether it wants to use the offered buffer of discard it.
    */
    virtual void register_read_ahead_cb(serializer_read_ahead_callback_t *cb) = 0;
    virtual void unregister_read_ahead_cb(serializer_read_ahead_callback_t *cb) = 0;

    // Reading a block from the serializer.  Reads a block, blocks the coroutine.
    virtual void block_read(const counted_t<standard_block_token_t> &token,
                            void *buf, file_account_t *io_account) = 0;

    /* The index stores three pieces of information for each ID:
     * 1. A pointer to a data block on disk (which may be NULL)
     * 2. A repli_timestamp_t, called the "recency"
     * 3. A boolean, called the "delete bit" */

    /* max_block_id() and get_delete_bit() are used by the buffer cache to reconstruct
    the free list of unused block IDs. */

    /* Returns a block ID such that every existing block has an ID less than
     * that ID. Note that index_read(max_block_id() - 1) is not guaranteed to be
     * non-NULL. Note that for k > 0, max_block_id() - k might have never been
     * created. */
    virtual block_id_t max_block_id() = 0;

    /* Gets a block's timestamp.  This may return repli_timestamp_t::invalid. */
    virtual repli_timestamp_t get_recency(block_id_t id) = 0;

    /* Reads the block's delete bit. */
    virtual bool get_delete_bit(block_id_t id) = 0;

    /* Reads the block's actual data */
    virtual counted_t<standard_block_token_t> index_read(block_id_t block_id) = 0;

    /* index_write() applies all given index operations in an atomic way */
    virtual void index_write(const std::vector<index_write_op_t>& write_ops, file_account_t *io_account) = 0;

    /* Non-blocking variants */
    virtual counted_t<standard_block_token_t> block_write(const void *buf, block_id_t block_id, file_account_t *io_account, iocallback_t *cb) = 0;

    // RSI: Rename this later.
    struct block_write_info_t {
        // RSI: Add block_size_t param.
        const void *buf;
        block_id_t block_id;

        block_write_info_t(const void *_buf, block_id_t _block_id)
            : buf(_buf), block_id(_block_id) { }
    };

    virtual std::vector<counted_t<standard_block_token_t> >
    block_writes(const std::vector<block_write_info_t> &write_infos,
                 file_account_t *io_account,
                 iocallback_t *cb);

    /* The size, in bytes, of each serializer block */
    virtual block_size_t get_block_size() const = 0;

    /* Return true if no other processes have the file locked */
    virtual bool coop_lock_and_check() = 0;

private:
    DISABLE_COPYING(serializer_t);
};

// The do_write interface is now obvious helper functions

struct serializer_write_launched_callback_t {
    virtual void on_write_launched(const counted_t<standard_block_token_t>& token) = 0;
    virtual ~serializer_write_launched_callback_t() {}
};
struct serializer_write_t {
    block_id_t block_id;

    enum { UPDATE, DELETE, TOUCH } action_type;
    union {
        struct {
            const void *buf;
            repli_timestamp_t recency;
            iocallback_t *io_callback;
            serializer_write_launched_callback_t *launch_callback;
        } update;
        struct {
            repli_timestamp_t recency;
        } touch;
    } action;

    static serializer_write_t make_touch(block_id_t block_id, repli_timestamp_t recency);
    static serializer_write_t make_update(block_id_t block_id, repli_timestamp_t recency, const void *buf,
                                          iocallback_t *io_callback = NULL,
                                          serializer_write_launched_callback_t *launch_callback = NULL);
    static serializer_write_t make_delete(block_id_t block_id);
};

/* A bad wrapper for doing block writes and index writes.
 */
void do_writes(serializer_t *ser, const std::vector<serializer_write_t>& writes, file_account_t *io_account);

// Helpers for default implementations that can be used on log_serializer_t.

template <class serializer_type>
void serializer_index_write(serializer_type *ser, const index_write_op_t& op, file_account_t *io_account) {
    std::vector<index_write_op_t> ops;
    ops.push_back(op);
    return ser->index_write(ops, io_account);
}

counted_t<standard_block_token_t> serializer_block_write(serializer_t *ser, const void *buf,
                                                         block_id_t block_id, file_account_t *io_account);

#endif /* SERIALIZER_SERIALIZER_HPP_ */
<commit_msg>Added comment about serializer_t::block_writes.<commit_after>// Copyright 2010-2013 RethinkDB, all rights reserved.
#ifndef SERIALIZER_SERIALIZER_HPP_
#define SERIALIZER_SERIALIZER_HPP_

#include <vector>

#include "utils.hpp"
#include <boost/optional.hpp>

#include "arch/types.hpp"
#include "concurrency/cond_var.hpp"
#include "repli_timestamp.hpp"
#include "serializer/types.hpp"

struct index_write_op_t {
    block_id_t block_id;
    // Buf to write. None if not to be modified. Initialized but a null ptr if to be removed from lba.
    boost::optional<counted_t<standard_block_token_t> > token;
    boost::optional<repli_timestamp_t> recency; // Recency, if it should be modified.

    explicit index_write_op_t(block_id_t _block_id,
                              boost::optional<counted_t<standard_block_token_t> > _token = boost::none,
                              boost::optional<repli_timestamp_t> _recency = boost::none)
        : block_id(_block_id), token(_token), recency(_recency) { }
};

/* serializer_t is an abstract interface that describes how each serializer should
behave. It is implemented by log_serializer_t, semantic_checking_serializer_t, and
translator_serializer_t. */

/* Except as otherwise noted, the serializer's methods should only be
   called from the thread it was created on, and it should be
   destroyed on that same thread. */

class serializer_t : public home_thread_mixin_t {
public:
    typedef standard_block_token_t block_token_type;

    serializer_t() { }
    virtual ~serializer_t() { }

    /* The buffers that are used with do_read() and do_write() must be allocated using
    these functions. They can be safely called from any thread. */

    virtual scoped_malloc_t<ser_buffer_t> malloc() = 0;
    virtual scoped_malloc_t<ser_buffer_t> clone(const ser_buffer_t *) = 0;

    /* Allocates a new io account for the underlying file.
    Use delete to free it. */
    file_account_t *make_io_account(int priority);
    virtual file_account_t *make_io_account(int priority, int outstanding_requests_limit) = 0;

    /* Some serializer implementations support read-ahead to speed up cache warmup.
    This is supported through a serializer_read_ahead_callback_t which gets called whenever the serializer has read-ahead some buf.
    The callee can then decide whether it wants to use the offered buffer of discard it.
    */
    virtual void register_read_ahead_cb(serializer_read_ahead_callback_t *cb) = 0;
    virtual void unregister_read_ahead_cb(serializer_read_ahead_callback_t *cb) = 0;

    // Reading a block from the serializer.  Reads a block, blocks the coroutine.
    virtual void block_read(const counted_t<standard_block_token_t> &token,
                            void *buf, file_account_t *io_account) = 0;

    /* The index stores three pieces of information for each ID:
     * 1. A pointer to a data block on disk (which may be NULL)
     * 2. A repli_timestamp_t, called the "recency"
     * 3. A boolean, called the "delete bit" */

    /* max_block_id() and get_delete_bit() are used by the buffer cache to reconstruct
    the free list of unused block IDs. */

    /* Returns a block ID such that every existing block has an ID less than
     * that ID. Note that index_read(max_block_id() - 1) is not guaranteed to be
     * non-NULL. Note that for k > 0, max_block_id() - k might have never been
     * created. */
    virtual block_id_t max_block_id() = 0;

    /* Gets a block's timestamp.  This may return repli_timestamp_t::invalid. */
    virtual repli_timestamp_t get_recency(block_id_t id) = 0;

    /* Reads the block's delete bit. */
    virtual bool get_delete_bit(block_id_t id) = 0;

    /* Reads the block's actual data */
    virtual counted_t<standard_block_token_t> index_read(block_id_t block_id) = 0;

    /* index_write() applies all given index operations in an atomic way */
    virtual void index_write(const std::vector<index_write_op_t>& write_ops, file_account_t *io_account) = 0;

    /* Non-blocking variants */
    virtual counted_t<standard_block_token_t> block_write(const void *buf, block_id_t block_id, file_account_t *io_account, iocallback_t *cb) = 0;

    // RSI: Rename this later.
    struct block_write_info_t {
        // RSI: Add block_size_t param.
        const void *buf;
        block_id_t block_id;

        block_write_info_t(const void *_buf, block_id_t _block_id)
            : buf(_buf), block_id(_block_id) { }
    };

    // Returns block tokens in the same order as write_infos.
    virtual std::vector<counted_t<standard_block_token_t> >
    block_writes(const std::vector<block_write_info_t> &write_infos,
                 file_account_t *io_account,
                 iocallback_t *cb);

    /* The size, in bytes, of each serializer block */
    virtual block_size_t get_block_size() const = 0;

    /* Return true if no other processes have the file locked */
    virtual bool coop_lock_and_check() = 0;

private:
    DISABLE_COPYING(serializer_t);
};

// The do_write interface is now obvious helper functions

struct serializer_write_launched_callback_t {
    virtual void on_write_launched(const counted_t<standard_block_token_t>& token) = 0;
    virtual ~serializer_write_launched_callback_t() {}
};
struct serializer_write_t {
    block_id_t block_id;

    enum { UPDATE, DELETE, TOUCH } action_type;
    union {
        struct {
            const void *buf;
            repli_timestamp_t recency;
            iocallback_t *io_callback;
            serializer_write_launched_callback_t *launch_callback;
        } update;
        struct {
            repli_timestamp_t recency;
        } touch;
    } action;

    static serializer_write_t make_touch(block_id_t block_id, repli_timestamp_t recency);
    static serializer_write_t make_update(block_id_t block_id, repli_timestamp_t recency, const void *buf,
                                          iocallback_t *io_callback = NULL,
                                          serializer_write_launched_callback_t *launch_callback = NULL);
    static serializer_write_t make_delete(block_id_t block_id);
};

/* A bad wrapper for doing block writes and index writes.
 */
void do_writes(serializer_t *ser, const std::vector<serializer_write_t>& writes, file_account_t *io_account);

// Helpers for default implementations that can be used on log_serializer_t.

template <class serializer_type>
void serializer_index_write(serializer_type *ser, const index_write_op_t& op, file_account_t *io_account) {
    std::vector<index_write_op_t> ops;
    ops.push_back(op);
    return ser->index_write(ops, io_account);
}

counted_t<standard_block_token_t> serializer_block_write(serializer_t *ser, const void *buf,
                                                         block_id_t block_id, file_account_t *io_account);

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


<commit_before>// Copyright (c) 2013-2017, Matt Godbolt
// 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.
//
// 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 HOLDER 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.

#include "internal/ConcreteResponse.h"

#include "seasocks/Response.h"

namespace seasocks {

std::shared_ptr<Response> Response::unhandled() {
    static std::shared_ptr<Response> unhandled;
    return unhandled;
}

std::shared_ptr<Response> Response::notFound() {
    static std::shared_ptr<Response> notFound = std::make_shared<ConcreteResponse>(
                                            ConcreteResponse(ResponseCode::NotFound,
                                            "Not found", "text/plain",
                                            SynchronousResponse::Headers(), false));
    return notFound;
}

std::shared_ptr<Response> Response::error(ResponseCode code, const std::string& reason) {
    return  std::make_shared<ConcreteResponse>(
                code, reason, "text/plain",
                SynchronousResponse::Headers(), false);
}

std::shared_ptr<Response> Response::textResponse(const std::string& response) {
    return std::make_shared<ConcreteResponse>(
                ResponseCode::Ok,
                response, "text/plain",
                SynchronousResponse::Headers(), true);
}

std::shared_ptr<Response> Response::jsonResponse(const std::string& response) {
    return std::make_shared<ConcreteResponse>(
                ResponseCode::Ok, response,
                "application/json",
                SynchronousResponse::Headers(), true);
}

std::shared_ptr<Response> Response::htmlResponse(const std::string& response) {
    return std::make_shared<ConcreteResponse>(
                ResponseCode::Ok, response,
                "text/html",
                SynchronousResponse::Headers(), true);
}

}
<commit_msg>Small fix.<commit_after>// Copyright (c) 2013-2017, Matt Godbolt
// 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.
//
// 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 HOLDER 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.

#include "internal/ConcreteResponse.h"

#include "seasocks/Response.h"

namespace seasocks {

std::shared_ptr<Response> Response::unhandled() {
    static std::shared_ptr<Response> unhandled;
    return unhandled;
}

std::shared_ptr<Response> Response::notFound() {
    static std::shared_ptr<Response> notFound = std::make_shared<ConcreteResponse>(
                                            ResponseCode::NotFound,
                                            "Not found", "text/plain",
                                            SynchronousResponse::Headers(), false);
    return notFound;
}

std::shared_ptr<Response> Response::error(ResponseCode code, const std::string& reason) {
    return  std::make_shared<ConcreteResponse>(
                code, reason, "text/plain",
                SynchronousResponse::Headers(), false);
}

std::shared_ptr<Response> Response::textResponse(const std::string& response) {
    return std::make_shared<ConcreteResponse>(
                ResponseCode::Ok,
                response, "text/plain",
                SynchronousResponse::Headers(), true);
}

std::shared_ptr<Response> Response::jsonResponse(const std::string& response) {
    return std::make_shared<ConcreteResponse>(
                ResponseCode::Ok, response,
                "application/json",
                SynchronousResponse::Headers(), true);
}

std::shared_ptr<Response> Response::htmlResponse(const std::string& response) {
    return std::make_shared<ConcreteResponse>(
                ResponseCode::Ok, response,
                "text/html",
                SynchronousResponse::Headers(), true);
}

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_rsc.hxx"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>

#ifdef _RSCERROR_H
#include <rscerror.h>
#endif
#include <rschash.hxx>
#include <rscdb.hxx>
#include <rsctop.hxx>
#include <rsckey.hxx>
#include <rscpar.hxx>
#include <rscdef.hxx>

#include "rsclex.hxx"
#include <yyrscyacc.hxx>

#include <rtl/textcvt.h>
#include <rtl/textenc.h>

using namespace rtl;

const char* StringContainer::putString( const char* pString )
{
    OString aString( static_cast<const sal_Char*>(pString) );
    std::pair<
        std::hash_set< OString, OStringHash >::iterator,
        bool > aInsert =
        m_aStrings.insert( aString );

    return aInsert.first->getStr();
}

/*************************************************************************/
int             c;
BOOL            bLastInclude;// War letztes Symbol INCLUDE
RscFileInst*    pFI;
RscTypCont*     pTC;
RscExpression * pExp;
struct KeyVal {
    int     nKeyWord;
    YYSTYPE aYYSType;
} aKeyVal[ 1 ];
BOOL bTargetDefined;

StringContainer* pStringContainer = NULL;

/****************** C O D E **********************************************/
UINT32 GetNumber(){
    UINT32  l = 0;
    UINT32  nLog = 10;

    if( '0' == c ){
        c = pFI->GetFastChar();
        if( 'x' == c ){
            nLog = 16;
            c = pFI->GetFastChar();
        }
    };

    if( nLog == 16 ){
        while( isxdigit( c ) ){
            if( isdigit( c ) )
                l = l * nLog + (c - '0');
            else
                l = l * nLog + (toupper( c ) - 'A' + 10 );
            c = pFI->GetFastChar();
        }
    }
    else{
        while( isdigit( c ) || 'x' == c ){
            l = l * nLog + (c - '0');
            c = pFI->GetFastChar();
        }
    }

    while( c=='U' || c=='u' || c=='l' || c=='L' ) //Wg. Unsigned Longs
        c = pFI->GetFastChar();

    if( l > 0x7fffffff ) //Oberstes bit gegebenenfalls abschneiden;
        l &= 0x7fffffff;

    return( l );
}

int MakeToken( YYSTYPE * pTokenVal ){
    int             c1;
    char *          pStr;

    while( TRUE ){  // Kommentare und Leerzeichen ueberlesen
        while( isspace( c ) )
            c = pFI->GetFastChar();
        if( '/' == c ){
            c1 = c;
            c = pFI->GetFastChar();
            if( '/' == c ){
                while( '\n' != c && !pFI->IsEof() )
                    c = pFI->GetFastChar();
                c = pFI->GetFastChar();
            }
            else if( '*' == c ){
                c = pFI->GetFastChar();
                do {
                    while( '*' != c && !pFI->IsEof() )
                        c = pFI->GetFastChar();
                    c = pFI->GetFastChar();
                } while( '/' != c && !pFI->IsEof() );
                c = pFI->GetFastChar();
            }
            else
                return( c1 );
        }
        else
            break;
    };

    if( c == pFI->IsEof() ){
        return( 0 );
    }

    if( bLastInclude ){
        bLastInclude = FALSE; //Zuruecksetzten
        if( '<' == c ){
            OStringBuffer aBuf( 256 );
            c = pFI->GetFastChar();
            while( '>' != c && !pFI->IsEof() )
            {
                aBuf.append( sal_Char(c) );
                c = pFI->GetFastChar();
            };
            c = pFI->GetFastChar();
            pTokenVal->string = const_cast<char*>(pStringContainer->putString( aBuf.getStr() ));
            return( INCLUDE_STRING );
        };
    }

    if( c == '"' )
    {
        OStringBuffer aBuf( 256 );
        BOOL bDone = FALSE;
        while( !bDone && !pFI->IsEof() && c )
        {
            c = pFI->GetFastChar();
            if( c == '"' )
            {
                c = pFI->GetFastChar();
                if( c == '"' )
                {
                    aBuf.append( '"' );
                    aBuf.append( '"' );
                }
                else
                    bDone = TRUE;
            }
            else if( c == '\\' )
            {
                aBuf.append( '\\' );
                c = pFI->GetFastChar();
                if( c )
                    aBuf.append( sal_Char(c) );
            }
            else
                aBuf.append( sal_Char(c) );
        }
        pStr = pTokenVal->string = const_cast<char*>(pStringContainer->putString( aBuf.getStr() ));
        return( STRING );
    }
    if (isdigit (c)){
        pTokenVal->value = GetNumber();
        return( NUMBER );
    }

    if( isalpha (c) || (c == '_') ){
        Atom        nHashId;
        OStringBuffer aBuf( 256 );

        while( isalnum (c) || (c == '_') || (c == '-') )
        {
            aBuf.append( sal_Char(c) );
            c = pFI->GetFastChar();
        }

        nHashId = pHS->getID( aBuf.getStr(), true );
        if( InvalidAtom != nHashId )
        {
            KEY_STRUCT  aKey;

            // Suche nach dem Schluesselwort
            if( pTC->aNmTb.Get( nHashId, &aKey ) )
            {

                // Schluesselwort gefunden
                switch( aKey.nTyp )
                {
                    case CLASSNAME:
                        pTokenVal->pClass = (RscTop *)aKey.yylval;
                        break;
                    case VARNAME:
                        pTokenVal->varid = aKey.nName;
                        break;
                    case CONSTNAME:
                        pTokenVal->constname.hashid = aKey.nName;
                        pTokenVal->constname.nValue = aKey.yylval;
                        break;
                    case BOOLEAN:
                        pTokenVal->svbool = (BOOL)aKey.yylval;
                        break;
                    case INCLUDE:
                        bLastInclude = TRUE;
                    default:
                        pTokenVal->value = aKey.yylval;
                };

                return( aKey.nTyp );
            }
            else
            {
                pTokenVal->string = const_cast<char*>(pStringContainer->putString( aBuf.getStr() ));
                return( SYMBOL );
            }
        }
        else{       // Symbol
            RscDefine  * pDef;

            pDef = pTC->aFileTab.FindDef( aBuf.getStr() );
            if( pDef ){
                pTokenVal->defineele = pDef;

                return( RSCDEFINE );
            }

            pTokenVal->string = const_cast<char*>(pStringContainer->putString( aBuf.getStr() ));
            return( SYMBOL );
        }
    }

    if( c=='<' )
    {
        c = pFI->GetFastChar();
        if( c=='<' )
        {
            c = pFI->GetFastChar();
            return LEFTSHIFT;
        }
        else
            return '<';
    }

    if( c=='>' )
    {
        c = pFI->GetFastChar();
        if( c=='>' )
        {
            c = pFI->GetFastChar();
            return RIGHTSHIFT;
        }
        else
            return '>';
    }

    c1 = c;
    c = pFI->GetFastChar();
    return( c1 );
}

#if defined( RS6000 ) || defined( HP9000 ) || defined( SCO )
extern "C" int yylex()
#else
int yylex()
#endif
{
    if( bTargetDefined )
        bTargetDefined = FALSE;
    else
        aKeyVal[ 0 ].nKeyWord =
                     MakeToken( &aKeyVal[ 0 ].aYYSType );

    yylval = aKeyVal[ 0 ].aYYSType;
    return( aKeyVal[ 0 ].nKeyWord );
}

/****************** yyerror **********************************************/
#ifdef RS6000
extern "C" void yyerror( char* pMessage )
#elif defined HP9000 || defined SCO || defined SOLARIS
extern "C" void yyerror( const char* pMessage )
#else
void yyerror( char* pMessage )
#endif
{
    pTC->pEH->Error( ERR_YACC, NULL, RscId(), pMessage );
}

/****************** parser start function ********************************/
void InitParser( RscFileInst * pFileInst )
{
    pTC = pFileInst->pTypCont;          // Datenkontainer setzten
    pFI = pFileInst;
    pStringContainer = new StringContainer();
    pExp = NULL;                //fuer MacroParser
    bTargetDefined = FALSE;

    // Anfangszeichen initialisieren
    bLastInclude = FALSE;
    c = pFI->GetFastChar();
}

void EndParser(){
    // Stack abraeumen
    while( ! S.IsEmpty() )
        S.Pop();

    // free string container
    delete pStringContainer;
    pStringContainer = NULL;

    if( pExp )
        delete pExp;
    pTC      = NULL;
    pFI      = NULL;
    pExp     = NULL;

}

void IncludeParser( RscFileInst * pFileInst )
{
    int           nToken;   // Wert des Tokens
    YYSTYPE       aYYSType; // Daten des Tokens
    RscFile     * pFName;   // Filestruktur
    ULONG         lKey;     // Fileschluessel
    RscTypCont  * pTypCon  = pFileInst->pTypCont;

    pFName = pTypCon->aFileTab.Get( pFileInst->GetFileIndex() );
    InitParser( pFileInst );

    nToken = MakeToken( &aYYSType );
    while( 0 != nToken && CLASSNAME != nToken ){
        if( '#' == nToken ){
            if( INCLUDE == (nToken = MakeToken( &aYYSType )) ){
                if( STRING == (nToken = MakeToken( &aYYSType )) ){
                    lKey = pTypCon->aFileTab.NewIncFile( aYYSType.string,
                                                         aYYSType.string );
                    pFName->InsertDependFile( lKey, LIST_APPEND );
                }
                else if( INCLUDE_STRING == nToken ){
                    lKey = pTypCon->aFileTab.NewIncFile( aYYSType.string,
                                                         ByteString() );
                    pFName->InsertDependFile( lKey, LIST_APPEND );
                };
            };
        };
        nToken = MakeToken( &aYYSType );
    };

    EndParser();
}

ERRTYPE parser( RscFileInst * pFileInst )
{
    ERRTYPE aError;

    InitParser( pFileInst );

    aError = yyparse();

    EndParser();

    // yyparser gibt 0 zurueck, wenn erfolgreich
    if( 0 == aError )
        aError.Clear();
    if( pFileInst->pTypCont->pEH->nErrors )
        aError = ERR_ERROR;
    pFileInst->SetError( aError );
    return( aError );
}

RscExpression * MacroParser( RscFileInst & rFileInst )
{
    ERRTYPE       aError;
    RscExpression * pExpression;

    InitParser( &rFileInst );

    //Ziel auf macro_expression setzen
    aKeyVal[ 0 ].nKeyWord = MACROTARGET;
    bTargetDefined = TRUE;
    aError = yyparse();

    pExpression = pExp;
    //EndParser() wuerde pExp loeschen
    if( pExp )
        pExp = NULL;

    EndParser();

    // yyparser gibt 0 zurueck, wenn erfolgreich
    if( 0 == aError )
        aError.Clear();
    if( rFileInst.pTypCont->pEH->nErrors )
        aError = ERR_ERROR;
    rFileInst.SetError( aError );

    //im Fehlerfall pExpression loeschen
    if( aError.IsError() && pExpression ){
        delete pExpression;
        pExpression = NULL;
    };
    return( pExpression );
}

<commit_msg>vcl113: #i43066# handle string concatenations in lexer<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_rsc.hxx"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>

#ifdef _RSCERROR_H
#include <rscerror.h>
#endif
#include <rschash.hxx>
#include <rscdb.hxx>
#include <rsctop.hxx>
#include <rsckey.hxx>
#include <rscpar.hxx>
#include <rscdef.hxx>

#include "rsclex.hxx"
#include <yyrscyacc.hxx>

#include <rtl/textcvt.h>
#include <rtl/textenc.h>

using namespace rtl;

const char* StringContainer::putString( const char* pString )
{
    OString aString( static_cast<const sal_Char*>(pString) );
    std::pair<
        std::hash_set< OString, OStringHash >::iterator,
        bool > aInsert =
        m_aStrings.insert( aString );

    return aInsert.first->getStr();
}

/*************************************************************************/
int             c;
BOOL            bLastInclude;// War letztes Symbol INCLUDE
RscFileInst*    pFI;
RscTypCont*     pTC;
RscExpression * pExp;
struct KeyVal {
    int     nKeyWord;
    YYSTYPE aYYSType;
} aKeyVal[ 1 ];
BOOL bTargetDefined;

StringContainer* pStringContainer = NULL;

/****************** C O D E **********************************************/
UINT32 GetNumber(){
    UINT32  l = 0;
    UINT32  nLog = 10;

    if( '0' == c ){
        c = pFI->GetFastChar();
        if( 'x' == c ){
            nLog = 16;
            c = pFI->GetFastChar();
        }
    };

    if( nLog == 16 ){
        while( isxdigit( c ) ){
            if( isdigit( c ) )
                l = l * nLog + (c - '0');
            else
                l = l * nLog + (toupper( c ) - 'A' + 10 );
            c = pFI->GetFastChar();
        }
    }
    else{
        while( isdigit( c ) || 'x' == c ){
            l = l * nLog + (c - '0');
            c = pFI->GetFastChar();
        }
    }

    while( c=='U' || c=='u' || c=='l' || c=='L' ) //Wg. Unsigned Longs
        c = pFI->GetFastChar();

    if( l > 0x7fffffff ) //Oberstes bit gegebenenfalls abschneiden;
        l &= 0x7fffffff;

    return( l );
}

int MakeToken( YYSTYPE * pTokenVal ){
    int             c1;
    char *          pStr;

    while( TRUE ){  // Kommentare und Leerzeichen ueberlesen
        while( isspace( c ) )
            c = pFI->GetFastChar();
        if( '/' == c ){
            c1 = c;
            c = pFI->GetFastChar();
            if( '/' == c ){
                while( '\n' != c && !pFI->IsEof() )
                    c = pFI->GetFastChar();
                c = pFI->GetFastChar();
            }
            else if( '*' == c ){
                c = pFI->GetFastChar();
                do {
                    while( '*' != c && !pFI->IsEof() )
                        c = pFI->GetFastChar();
                    c = pFI->GetFastChar();
                } while( '/' != c && !pFI->IsEof() );
                c = pFI->GetFastChar();
            }
            else
                return( c1 );
        }
        else
            break;
    };

    if( c == pFI->IsEof() ){
        return( 0 );
    }

    if( bLastInclude ){
        bLastInclude = FALSE; //Zuruecksetzten
        if( '<' == c ){
            OStringBuffer aBuf( 256 );
            c = pFI->GetFastChar();
            while( '>' != c && !pFI->IsEof() )
            {
                aBuf.append( sal_Char(c) );
                c = pFI->GetFastChar();
            };
            c = pFI->GetFastChar();
            pTokenVal->string = const_cast<char*>(pStringContainer->putString( aBuf.getStr() ));
            return( INCLUDE_STRING );
        };
    }

    if( c == '"' )
    {
        OStringBuffer aBuf( 256 );
        BOOL bDone = FALSE;
        while( !bDone && !pFI->IsEof() && c )
        {
            c = pFI->GetFastChar();
            if( c == '"' )
            {
                do
                {
                    c = pFI->GetFastChar();
                }
                while( isblank( c ) );
                if( c == '"' )
                {
                    // this is a continued string
                    // note: multiline string continuations are handled by the parser
                    // see rscyacc.y
                }
                else
                    bDone = TRUE;
            }
            else if( c == '\\' )
            {
                aBuf.append( '\\' );
                c = pFI->GetFastChar();
                if( c )
                    aBuf.append( sal_Char(c) );
            }
            else
                aBuf.append( sal_Char(c) );
        }
        pStr = pTokenVal->string = const_cast<char*>(pStringContainer->putString( aBuf.getStr() ));
        return( STRING );
    }
    if (isdigit (c)){
        pTokenVal->value = GetNumber();
        return( NUMBER );
    }

    if( isalpha (c) || (c == '_') ){
        Atom        nHashId;
        OStringBuffer aBuf( 256 );

        while( isalnum (c) || (c == '_') || (c == '-') )
        {
            aBuf.append( sal_Char(c) );
            c = pFI->GetFastChar();
        }

        nHashId = pHS->getID( aBuf.getStr(), true );
        if( InvalidAtom != nHashId )
        {
            KEY_STRUCT  aKey;

            // Suche nach dem Schluesselwort
            if( pTC->aNmTb.Get( nHashId, &aKey ) )
            {

                // Schluesselwort gefunden
                switch( aKey.nTyp )
                {
                    case CLASSNAME:
                        pTokenVal->pClass = (RscTop *)aKey.yylval;
                        break;
                    case VARNAME:
                        pTokenVal->varid = aKey.nName;
                        break;
                    case CONSTNAME:
                        pTokenVal->constname.hashid = aKey.nName;
                        pTokenVal->constname.nValue = aKey.yylval;
                        break;
                    case BOOLEAN:
                        pTokenVal->svbool = (BOOL)aKey.yylval;
                        break;
                    case INCLUDE:
                        bLastInclude = TRUE;
                    default:
                        pTokenVal->value = aKey.yylval;
                };

                return( aKey.nTyp );
            }
            else
            {
                pTokenVal->string = const_cast<char*>(pStringContainer->putString( aBuf.getStr() ));
                return( SYMBOL );
            }
        }
        else{       // Symbol
            RscDefine  * pDef;

            pDef = pTC->aFileTab.FindDef( aBuf.getStr() );
            if( pDef ){
                pTokenVal->defineele = pDef;

                return( RSCDEFINE );
            }

            pTokenVal->string = const_cast<char*>(pStringContainer->putString( aBuf.getStr() ));
            return( SYMBOL );
        }
    }

    if( c=='<' )
    {
        c = pFI->GetFastChar();
        if( c=='<' )
        {
            c = pFI->GetFastChar();
            return LEFTSHIFT;
        }
        else
            return '<';
    }

    if( c=='>' )
    {
        c = pFI->GetFastChar();
        if( c=='>' )
        {
            c = pFI->GetFastChar();
            return RIGHTSHIFT;
        }
        else
            return '>';
    }

    c1 = c;
    c = pFI->GetFastChar();
    return( c1 );
}

#if defined( RS6000 ) || defined( HP9000 ) || defined( SCO )
extern "C" int yylex()
#else
int yylex()
#endif
{
    if( bTargetDefined )
        bTargetDefined = FALSE;
    else
        aKeyVal[ 0 ].nKeyWord =
                     MakeToken( &aKeyVal[ 0 ].aYYSType );

    yylval = aKeyVal[ 0 ].aYYSType;
    return( aKeyVal[ 0 ].nKeyWord );
}

/****************** yyerror **********************************************/
#ifdef RS6000
extern "C" void yyerror( char* pMessage )
#elif defined HP9000 || defined SCO || defined SOLARIS
extern "C" void yyerror( const char* pMessage )
#else
void yyerror( char* pMessage )
#endif
{
    pTC->pEH->Error( ERR_YACC, NULL, RscId(), pMessage );
}

/****************** parser start function ********************************/
void InitParser( RscFileInst * pFileInst )
{
    pTC = pFileInst->pTypCont;          // Datenkontainer setzten
    pFI = pFileInst;
    pStringContainer = new StringContainer();
    pExp = NULL;                //fuer MacroParser
    bTargetDefined = FALSE;

    // Anfangszeichen initialisieren
    bLastInclude = FALSE;
    c = pFI->GetFastChar();
}

void EndParser(){
    // Stack abraeumen
    while( ! S.IsEmpty() )
        S.Pop();

    // free string container
    delete pStringContainer;
    pStringContainer = NULL;

    if( pExp )
        delete pExp;
    pTC      = NULL;
    pFI      = NULL;
    pExp     = NULL;

}

void IncludeParser( RscFileInst * pFileInst )
{
    int           nToken;   // Wert des Tokens
    YYSTYPE       aYYSType; // Daten des Tokens
    RscFile     * pFName;   // Filestruktur
    ULONG         lKey;     // Fileschluessel
    RscTypCont  * pTypCon  = pFileInst->pTypCont;

    pFName = pTypCon->aFileTab.Get( pFileInst->GetFileIndex() );
    InitParser( pFileInst );

    nToken = MakeToken( &aYYSType );
    while( 0 != nToken && CLASSNAME != nToken ){
        if( '#' == nToken ){
            if( INCLUDE == (nToken = MakeToken( &aYYSType )) ){
                if( STRING == (nToken = MakeToken( &aYYSType )) ){
                    lKey = pTypCon->aFileTab.NewIncFile( aYYSType.string,
                                                         aYYSType.string );
                    pFName->InsertDependFile( lKey, LIST_APPEND );
                }
                else if( INCLUDE_STRING == nToken ){
                    lKey = pTypCon->aFileTab.NewIncFile( aYYSType.string,
                                                         ByteString() );
                    pFName->InsertDependFile( lKey, LIST_APPEND );
                };
            };
        };
        nToken = MakeToken( &aYYSType );
    };

    EndParser();
}

ERRTYPE parser( RscFileInst * pFileInst )
{
    ERRTYPE aError;

    InitParser( pFileInst );

    aError = yyparse();

    EndParser();

    // yyparser gibt 0 zurueck, wenn erfolgreich
    if( 0 == aError )
        aError.Clear();
    if( pFileInst->pTypCont->pEH->nErrors )
        aError = ERR_ERROR;
    pFileInst->SetError( aError );
    return( aError );
}

RscExpression * MacroParser( RscFileInst & rFileInst )
{
    ERRTYPE       aError;
    RscExpression * pExpression;

    InitParser( &rFileInst );

    //Ziel auf macro_expression setzen
    aKeyVal[ 0 ].nKeyWord = MACROTARGET;
    bTargetDefined = TRUE;
    aError = yyparse();

    pExpression = pExp;
    //EndParser() wuerde pExp loeschen
    if( pExp )
        pExp = NULL;

    EndParser();

    // yyparser gibt 0 zurueck, wenn erfolgreich
    if( 0 == aError )
        aError.Clear();
    if( rFileInst.pTypCont->pEH->nErrors )
        aError = ERR_ERROR;
    rFileInst.SetError( aError );

    //im Fehlerfall pExpression loeschen
    if( aError.IsError() && pExpression ){
        delete pExpression;
        pExpression = NULL;
    };
    return( pExpression );
}

<|endoftext|>


<commit_before>
/**
 * PS Move API
 * Copyright (c) 2011 Thomas Perl <thp.io/about>
 * All Rights Reserved
 **/

#include "psmoveqt.hpp"

#include <QtDeclarative>
#include <QtDebug>

PSMoveQt::PSMoveQt()
{
    _move = psmove_connect();
    _timer.setInterval(10);
    /* FIXME: initialize fields */
    _buttons = 0;

    /**
     * Re-sending the LED color value every 4 secs should be enough.
     * For this we need a timer, and when color and/or rumble are
     * set to a non-zero value, we need to activate it.
     **/
    _colorTimer.setInterval(4000);
    connect(this, SIGNAL(enabledChanged()),
            this, SLOT(checkColorTimer()));
    connect(this, SIGNAL(colorChanged()),
            this, SLOT(checkColorTimer()));
    connect(this, SIGNAL(rumbleChanged()),
            this, SLOT(checkColorTimer()));

    connect(&_timer, SIGNAL(timeout()),
            this, SLOT(onTimeout()));
    connect(&_colorTimer, SIGNAL(timeout()),
            this, SLOT(onColorTimeout()));
}

PSMoveQt::~PSMoveQt()
{
    /* Switch off LEDs + rumble on exit */
    setColor(Qt::black);
    setRumble(0);

    psmove_disconnect(_move);
}

void
PSMoveQt::registerQML()
{
    qmlRegisterType<PSMoveQt>("com.thpinfo.psmove", 1, 0, "PSMove");
}

bool
PSMoveQt::enabled()
{
    return _timer.isActive();
}

void
PSMoveQt::setEnabled(bool enabled)
{
    if (enabled && !_timer.isActive()) {
        /* Activate */
        _timer.start();
        emit enabledChanged();
    } else if (!enabled && _timer.isActive()) {
        /* Deactivate */
        _timer.stop();
        emit enabledChanged();
    }
}

int
PSMoveQt::trigger()
{
    return _trigger;
}

void
PSMoveQt::setTrigger(int trigger)
{
    if (_trigger != trigger) {
        _trigger = trigger;
        emit triggerChanged();
    }
}

QColor
PSMoveQt::color()
{
    return _color;
}

void
PSMoveQt::setColor(QColor color)
{
    if (_color != color) {
        _color = color;
        psmove_set_leds(_move, color.red(), color.green(), color.blue());
        psmove_update_leds(_move);

        emit colorChanged();
    }
}

int
PSMoveQt::rumble()
{
    return _rumble;
}

void
PSMoveQt::setRumble(int rumble)
{
    if (_rumble != rumble) {
        _rumble = rumble;
        psmove_set_rumble(_move, _rumble);
        psmove_update_leds(_move);

        emit rumbleChanged();
    }
}

void
PSMoveQt::onTimeout()
{
    int gx, gy, gz, buttons;

    while (psmove_poll(_move)) {
        setTrigger(psmove_get_trigger(_move));
        psmove_get_gyroscope(_move, &gx, &gy, &gz);
        if (gx != _gx || gy != _gy || gz != _gz) {
            _gx = gx;
            _gy = gy;
            _gz = gz;
            emit gyroChanged();
        }
        buttons = psmove_get_buttons(_move);
        if (buttons != _buttons) {
            /* FIXME: Make more generic + for all buttons */
            if (buttons & Btn_MOVE && !(_buttons & Btn_MOVE)) {
                emit buttonPressed(PSMoveQt::Move);
            } else if (!(buttons & Btn_MOVE) && _buttons & Btn_MOVE) {
                emit buttonReleased(PSMoveQt::Move);
            }
            if (buttons & Btn_PS && !(_buttons & Btn_PS)) {
                emit buttonPressed(PSMoveQt::PS);
            } else if (!(buttons & Btn_PS) && _buttons & Btn_PS) {
                emit buttonReleased(PSMoveQt::PS);
            }
            _buttons = buttons;
        }
    }
}

void
PSMoveQt::onColorTimeout()
{
    /* Re-send the LED color data so it doesn't go off */
    psmove_update_leds(_move);
}

void
PSMoveQt::checkColorTimer()
{
    bool shouldRun = _timer.isActive() &&
        ((_color.red() + _color.green() + _color.blue() + _rumble) > 0);

    if (shouldRun && !_colorTimer.isActive()) {
        /* Enable color timer */
        _colorTimer.start();
    } else if (!shouldRun && _colorTimer.isActive()) {
        /* Disable color timer */
        _colorTimer.stop();
    }
}

<commit_msg>Qt interface: Initialize fields; code cleanup<commit_after>
/**
 * PS Move API
 * Copyright (c) 2011 Thomas Perl <thp.io/about>
 * All Rights Reserved
 **/

#include "psmoveqt.hpp"

#include <QtDeclarative>
#include <QtDebug>

/* Update interval for sensor readings and LED setting */
#define INTERVAL_SENSORS 10
#define INTERVAL_RGBLEDS 4000

PSMoveQt::PSMoveQt()
    : _move(psmove_connect()),
      _timer(),
      _colorTimer(),
      _trigger(0),
      _color(Qt::black),
      _rumble(0),
      _gx(0),
      _gy(0),
      _gz(0),
      _buttons(0)
{
    _timer.setInterval(INTERVAL_SENSORS);

    /**
     * Re-sending the LED color value every 4 secs should be enough.
     * For this we need a timer, and when color and/or rumble are
     * set to a non-zero value, we need to activate it.
     **/
    _colorTimer.setInterval(INTERVAL_RGBLEDS);
    connect(this, SIGNAL(enabledChanged()),
            this, SLOT(checkColorTimer()));
    connect(this, SIGNAL(colorChanged()),
            this, SLOT(checkColorTimer()));
    connect(this, SIGNAL(rumbleChanged()),
            this, SLOT(checkColorTimer()));

    connect(&_timer, SIGNAL(timeout()),
            this, SLOT(onTimeout()));
    connect(&_colorTimer, SIGNAL(timeout()),
            this, SLOT(onColorTimeout()));
}

PSMoveQt::~PSMoveQt()
{
    if (_move != NULL) {
        /* Switch off LEDs + rumble on exit */
        setColor(Qt::black);
        setRumble(0);

        psmove_disconnect(_move);
    }
}

void
PSMoveQt::registerQML()
{
    qmlRegisterType<PSMoveQt>("com.thpinfo.psmove", 1, 0, "PSMove");
}

bool
PSMoveQt::enabled()
{
    return _timer.isActive();
}

void
PSMoveQt::setEnabled(bool enabled)
{
    if (enabled && !_timer.isActive()) {
        /* Activate */
        _timer.start();
        emit enabledChanged();
    } else if (!enabled && _timer.isActive()) {
        /* Deactivate */
        _timer.stop();
        emit enabledChanged();
    }
}

int
PSMoveQt::trigger()
{
    return _trigger;
}

void
PSMoveQt::setTrigger(int trigger)
{
    if (_trigger != trigger) {
        _trigger = trigger;
        emit triggerChanged();
    }
}

QColor
PSMoveQt::color()
{
    return _color;
}

void
PSMoveQt::setColor(QColor color)
{
    if (_color != color) {
        _color = color;
        psmove_set_leds(_move, color.red(), color.green(), color.blue());
        psmove_update_leds(_move);

        emit colorChanged();
    }
}

int
PSMoveQt::rumble()
{
    return _rumble;
}

void
PSMoveQt::setRumble(int rumble)
{
    if (_rumble != rumble) {
        _rumble = rumble;
        psmove_set_rumble(_move, _rumble);
        psmove_update_leds(_move);

        emit rumbleChanged();
    }
}

void
PSMoveQt::onTimeout()
{
    int gx, gy, gz, buttons;

    while (psmove_poll(_move)) {
        setTrigger(psmove_get_trigger(_move));
        psmove_get_gyroscope(_move, &gx, &gy, &gz);
        if (gx != _gx || gy != _gy || gz != _gz) {
            _gx = gx;
            _gy = gy;
            _gz = gz;
            emit gyroChanged();
        }
        buttons = psmove_get_buttons(_move);
        if (buttons != _buttons) {
            /* FIXME: Make more generic + for all buttons */
            if (buttons & Btn_MOVE && !(_buttons & Btn_MOVE)) {
                emit buttonPressed(PSMoveQt::Move);
            } else if (!(buttons & Btn_MOVE) && _buttons & Btn_MOVE) {
                emit buttonReleased(PSMoveQt::Move);
            }
            if (buttons & Btn_PS && !(_buttons & Btn_PS)) {
                emit buttonPressed(PSMoveQt::PS);
            } else if (!(buttons & Btn_PS) && _buttons & Btn_PS) {
                emit buttonReleased(PSMoveQt::PS);
            }
            _buttons = buttons;
        }
    }
}

void
PSMoveQt::onColorTimeout()
{
    /* Re-send the LED color data so it doesn't go off */
    psmove_update_leds(_move);
}

void
PSMoveQt::checkColorTimer()
{
    bool shouldRun = _timer.isActive() &&
        ((_color.red() + _color.green() + _color.blue() + _rumble) > 0);

    if (shouldRun && !_colorTimer.isActive()) {
        /* Enable color timer */
        _colorTimer.start();
    } else if (!shouldRun && _colorTimer.isActive()) {
        /* Disable color timer */
        _colorTimer.stop();
    }
}

<|endoftext|>


<commit_before>#include "Board.h"
#include "Pawn.h"
#include "Rook.h"
#include "Knight.h"
#include "Bishop.h"
#include "Queen.h"
#include "King.h"
#include <iostream>
#include <sstream>

namespace Chess {
	Board::Board() {
		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				pieces[x][y] = nullptr;
			}
		}

		// Black pawns
		for (int x = 0; x < 8; x++) {
			pieces[x][6] = new Pawn(Position(x, 6), false);
		}

		// White pawns
		for (int x = 0; x < 8; x++) {
			pieces[x][1] = new Pawn(Position(x, 1), true);
		}

		// Rooks
		pieces[0][7] = new Rook(Position(0, 7), false);
		pieces[7][7] = new Rook(Position(7, 7), false);
		pieces[0][0] = new Rook(Position(0, 0), true);
		pieces[7][0] = new Rook(Position(7, 0), true);

		// Knights
		pieces[1][7] = new Knight(Position(1, 7), false);
		pieces[6][7] = new Knight(Position(6, 7), false);
		pieces[1][0] = new Knight(Position(1, 0), true);
		pieces[6][0] = new Knight(Position(6, 0), true);

		// Bishops
		pieces[2][7] = new Bishop(Position(2, 7), false);
		pieces[5][7] = new Bishop(Position(5, 7), false);
		pieces[2][0] = new Bishop(Position(2, 0), true);
		pieces[5][0] = new Bishop(Position(5, 0), true);

		// Queens
		pieces[3][7] = new Queen(Position(3, 7), false);
		pieces[3][0] = new Queen(Position(3, 0), true);

		// Kings
		pieces[4][7] = new King(Position(4, 7), false);
		pieces[4][0] = new King(Position(4, 0), true);
		addBoardToMap();
	}

	Board::~Board() {
		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				if (pieces[x][y] != nullptr)
					delete pieces[x][y];
			}
		}
	}

	GameState Board::getState() const {
		return state;
	}

	Piece* Board::getPiece(const Position& position) const {
		return pieces[position.x][position.y];
	}

	bool Board::mustPromote() {
		return needsToPromote;
	}

	bool Board::move(const Position& oldPosition, const Position& newPosition) {
		Piece* piece = getPiece(oldPosition);
		Piece* targetPiece = getPiece(newPosition);

		if (piece != nullptr) {
			// Check if the piece is of the right color.
			if (piece->isWhite() == (turn % 2 == 0)) {
				halfMovesSinceCapture++;
				// Check if the move is legal.
				if (piece->isLegal(*this, newPosition)) {
					pieces[oldPosition.x][oldPosition.y] = nullptr;

					// En passant.
					if (pieces[newPosition.x][newPosition.y] == nullptr && (piece->notation() == 'p' || piece->notation() == 'P') && newPosition.x != oldPosition.x){
						if (piece->isWhite()) {
							delete pieces[newPosition.x][newPosition.y - 1];
							pieces[newPosition.x][newPosition.y - 1] = nullptr;
							halfMovesSinceCapture = 0;
						} else {
							delete pieces[newPosition.x][newPosition.y + 1];
							pieces[newPosition.x][newPosition.y + 1] = nullptr;
							halfMovesSinceCapture = 0;
						}
					}

					// Castling
					if (piece->notation() == 'k' || piece->notation() == 'K') {
						if (newPosition.x - oldPosition.x == 2){
							Piece* tempPiece = getPiece(Position(7, newPosition.y));
							pieces[7][newPosition.y] = nullptr;
							pieces[5][newPosition.y] = tempPiece;
							tempPiece->move(Position(5, newPosition.y));
						} else if (newPosition.x - oldPosition.x == -2) {
							Piece* tempPiece = getPiece(Position(0, newPosition.y));
							pieces[0][newPosition.y] = nullptr;
							pieces[3][newPosition.y] = tempPiece;
							tempPiece->move(Position(3, newPosition.y));
						}
					}

					// Delete captured enemy piece.
					if (pieces[newPosition.x][newPosition.y] != nullptr){
						delete pieces[newPosition.x][newPosition.y];
						halfMovesSinceCapture = 0;
					}
					// Update pieces and piece position
					pieces[newPosition.x][newPosition.y] = piece;
					if (piece->notation() == 'p' || piece->notation() == 'P')
						halfMovesSinceCapture = 0;
					piece->move(newPosition);

					// Promote pawns
					if(newPosition.y == 7 || newPosition.y == 0){
						if (piece->notation() == 'p' || piece->notation() == 'P'){
							needsToPromote = true;
						}
					}

					// Set and reset lastMovedPiece
					if (lastMovedPawn != nullptr){
						if (lastMovedPawn->getLastMoveWasDouble()){
							//lastMovedPawn->resetLastMoveWasDouble(); //orsakar krasch..
						}
					}
					lastMovedPawn = dynamic_cast<Pawn*>(getPiece(newPosition));

					turn++;
					if (state == GameState::BLACKPLAYS)
						state = GameState::WHITEPLAYS;
					else
						state = GameState::BLACKPLAYS;

					std::string tempstring = toFENString(false);
					std::cout << tempstring << '\n';
					addBoardToMap();
					if(isThreeFoldRepitition())
						state = GameState::DRAW;
					if (isFiftyMoveSincePawnOrCapture())
						state = GameState::DRAW;
					if (!sufficientMaterial())
						state = GameState::DRAW;
					checkWin();
					return true;
				}
			}
		}

		return false;
	}

	bool Board::willLeaveKingChecked(const Position& oldPosition, const Position& newPosition) {
		Piece* oldPiece = getPiece(oldPosition);
		Piece* newPiece = getPiece(newPosition);

		Piece* piece;
		switch (oldPiece->notation()) {
		case 'Q':
		case 'q':
			piece = new Queen(oldPiece->getPosition(), oldPiece->isWhite());
			break;
		case 'K':
		case 'k':
			piece = new King(oldPiece->getPosition(), oldPiece->isWhite());
			break;
		case 'P':
		case 'p':
			piece = new Pawn(oldPiece->getPosition(), oldPiece->isWhite());
			break;
		case 'R':
		case 'r':
			piece = new Rook(oldPiece->getPosition(), oldPiece->isWhite());
			break;
		case 'B':
		case 'b':
			piece = new Bishop(oldPiece->getPosition(), oldPiece->isWhite());
			break;
		case 'N':
		case 'n':
			piece = new Knight(oldPiece->getPosition(), oldPiece->isWhite());
			break;
		}

		pieces[newPosition.x][newPosition.y] = piece;
		piece->move(newPosition);
		pieces[oldPosition.x][oldPosition.y] = nullptr;

		King* king = getKing((turn % 2 == 0));
		bool checked = king->isChecked(*this);

		delete piece;
		pieces[newPosition.x][newPosition.y] = newPiece;
		pieces[oldPosition.x][oldPosition.y] = oldPiece;

		return checked;
	}

	void Board::promotePawn(Piece* pawn, PromoteTypes type) {
		Position position = pawn->getPosition();
		bool white = pawn->isWhite();
		delete pawn;

		switch (type) {
		case PromoteTypes::QUEEN:
			pieces[position.x][position.y] = new Queen(position, white);
			break;
		case PromoteTypes::ROOK:
			pieces[position.x][position.y] = new Rook(position, white);
			break;
		case PromoteTypes::BISHOP:
			pieces[position.x][position.y] = new Bishop(position, white);
			break;
		case PromoteTypes::KNIGHT:
			pieces[position.x][position.y] = new Knight(position, white);
			break;
		}
		needsToPromote = false;
	}
	void Board::addBoardToMap() {
		std::string tempstring = toFENString(false);
		if (previousBoards.find(tempstring) == previousBoards.end()) {
			previousBoards[tempstring] = 0;
		} else{
			previousBoards[tempstring] += 1;
		}
	}

	std::string Board::toFENString(bool addExtraData) const {
		std::string tempstring;
		int emptyCounter = 0;
		for (int y = 7; y >= 0; y--) {
			for (int x = 0; x < 8; x++){
				if (pieces[x][y] == nullptr)
					emptyCounter++;
				else {
					if (emptyCounter != 0)
						tempstring += std::to_string(emptyCounter);
					tempstring.append(1, pieces[x][y]->notation());
					emptyCounter = 0;
				}
			}
			if (emptyCounter != 0) {
				tempstring += std::to_string(emptyCounter);
				emptyCounter = 0;
			}
			tempstring += '/';
		}
		// Who played the turn?
		if (state == GameState::BLACKPLAYS)
			tempstring += "w";
		else
			tempstring += "b";

		if (addExtraData) {
			// Number of half turns since last capture or pawn move.
			tempstring += ' ' + std::to_string(halfMovesSinceCapture) + ' ';
			// Number of full moves.
			tempstring += std::to_string((turn+1) / 2);
		}
		return tempstring;
	}

	bool Board::isThreeFoldRepitition() {
		return previousBoards[toFENString(false)] == 3;
	}

	bool Board::isFiftyMoveSincePawnOrCapture() const {
		return halfMovesSinceCapture >= 100;
	}

	void Board::checkWin() {
		bool white = (state == GameState::WHITEPLAYS);

		bool canMove = false;
		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				Piece* piece = getPiece(Position(x, y));
				if (piece != nullptr && piece->isWhite() == white) {
					if (!piece->legalMoves(*this).empty()) {
						canMove = true;
						break;
					}
				}
			}
		}

		if (!canMove) {
			if (getKing(white)->isChecked(*this)) {
				if (white)
					state = GameState::BLACKWIN;
				else
					state = GameState::WHITEWIN;
			} else {
				state = GameState::DRAW;
			}
		}
	}

	bool Board::sufficientMaterial() const {
		// Get the material on the board.
		int pieceTypes[6] = { 0 };

		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				Piece* piece = getPiece(Position(x, y));
				if (piece != nullptr) {
					switch (piece->notation()) {
					case 'Q':
					case 'q':
						pieceTypes[0]++;
						break;
					case 'P':
					case 'p':
						pieceTypes[1]++;
						break;
					case 'R':
					case 'r':
						pieceTypes[2]++;
						break;
					case 'N':
					case 'n':
						pieceTypes[3]++;
						break;
					case 'B':
					case 'b':
						pieceTypes[((x + y) % 2 == 0) ? 4 : 5]++;
						break;
					}
				}
			}
		}

		// If there's a queen, pawn or rook on the board, there is sufficient material.
		if (pieceTypes[0] > 0 || pieceTypes[1] > 0 || pieceTypes[2] > 0)
			return true;

		// If there are 2 or more knights on the board, there is sufficient material.
		if (pieceTypes[3] > 1)
			return true;

		// If there are pieces from 2 or more categories (knight, bishop on light square, bishop on dark square), there is sufficient material.
		if ((pieceTypes[3] > 0) + (pieceTypes[4] > 0) + (pieceTypes[5] > 0) >= 2)
			return true;

		return false;

	}

	King* Board::getKing(bool white) const {
		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				Piece* piece = getPiece(Position(x, y));
				if (piece != nullptr && piece->notation() == (white ? 'K' : 'k'))
					return dynamic_cast<King*>(piece);
			}
		}

		return nullptr;
	}
}<commit_msg>fix promotePawn<commit_after>#include "Board.h"
#include "Pawn.h"
#include "Rook.h"
#include "Knight.h"
#include "Bishop.h"
#include "Queen.h"
#include "King.h"
#include <iostream>
#include <sstream>

namespace Chess {
	Board::Board() {
		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				pieces[x][y] = nullptr;
			}
		}

		// Black pawns
		for (int x = 0; x < 8; x++) {
			pieces[x][6] = new Pawn(Position(x, 6), false);
		}

		// White pawns
		for (int x = 0; x < 8; x++) {
			pieces[x][1] = new Pawn(Position(x, 1), true);
		}

		// Rooks
		pieces[0][7] = new Rook(Position(0, 7), false);
		pieces[7][7] = new Rook(Position(7, 7), false);
		pieces[0][0] = new Rook(Position(0, 0), true);
		pieces[7][0] = new Rook(Position(7, 0), true);

		// Knights
		pieces[1][7] = new Knight(Position(1, 7), false);
		pieces[6][7] = new Knight(Position(6, 7), false);
		pieces[1][0] = new Knight(Position(1, 0), true);
		pieces[6][0] = new Knight(Position(6, 0), true);

		// Bishops
		pieces[2][7] = new Bishop(Position(2, 7), false);
		pieces[5][7] = new Bishop(Position(5, 7), false);
		pieces[2][0] = new Bishop(Position(2, 0), true);
		pieces[5][0] = new Bishop(Position(5, 0), true);

		// Queens
		pieces[3][7] = new Queen(Position(3, 7), false);
		pieces[3][0] = new Queen(Position(3, 0), true);

		// Kings
		pieces[4][7] = new King(Position(4, 7), false);
		pieces[4][0] = new King(Position(4, 0), true);
		addBoardToMap();
	}

	Board::~Board() {
		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				if (pieces[x][y] != nullptr)
					delete pieces[x][y];
			}
		}
	}

	GameState Board::getState() const {
		return state;
	}

	Piece* Board::getPiece(const Position& position) const {
		return pieces[position.x][position.y];
	}

	bool Board::mustPromote() {
		return needsToPromote;
	}

	bool Board::move(const Position& oldPosition, const Position& newPosition) {
		Piece* piece = getPiece(oldPosition);
		Piece* targetPiece = getPiece(newPosition);

		if (piece != nullptr) {
			// Check if the piece is of the right color.
			if (piece->isWhite() == (turn % 2 == 0)) {
				halfMovesSinceCapture++;
				// Check if the move is legal.
				if (piece->isLegal(*this, newPosition)) {
					pieces[oldPosition.x][oldPosition.y] = nullptr;

					// En passant.
					if (pieces[newPosition.x][newPosition.y] == nullptr && (piece->notation() == 'p' || piece->notation() == 'P') && newPosition.x != oldPosition.x){
						if (piece->isWhite()) {
							delete pieces[newPosition.x][newPosition.y - 1];
							pieces[newPosition.x][newPosition.y - 1] = nullptr;
							halfMovesSinceCapture = 0;
						} else {
							delete pieces[newPosition.x][newPosition.y + 1];
							pieces[newPosition.x][newPosition.y + 1] = nullptr;
							halfMovesSinceCapture = 0;
						}
					}

					// Castling
					if (piece->notation() == 'k' || piece->notation() == 'K') {
						if (newPosition.x - oldPosition.x == 2){
							Piece* tempPiece = getPiece(Position(7, newPosition.y));
							pieces[7][newPosition.y] = nullptr;
							pieces[5][newPosition.y] = tempPiece;
							tempPiece->move(Position(5, newPosition.y));
						} else if (newPosition.x - oldPosition.x == -2) {
							Piece* tempPiece = getPiece(Position(0, newPosition.y));
							pieces[0][newPosition.y] = nullptr;
							pieces[3][newPosition.y] = tempPiece;
							tempPiece->move(Position(3, newPosition.y));
						}
					}

					// Delete captured enemy piece.
					if (pieces[newPosition.x][newPosition.y] != nullptr){
						delete pieces[newPosition.x][newPosition.y];
						halfMovesSinceCapture = 0;
					}
					// Update pieces and piece position
					pieces[newPosition.x][newPosition.y] = piece;
					if (piece->notation() == 'p' || piece->notation() == 'P')
						halfMovesSinceCapture = 0;
					piece->move(newPosition);

					// Promote pawns
					if(newPosition.y == 7 || newPosition.y == 0){
						if (piece->notation() == 'p' || piece->notation() == 'P'){
							needsToPromote = true;
						}
					}

					// Set and reset lastMovedPiece
					if (lastMovedPawn != nullptr){
						if (lastMovedPawn->getLastMoveWasDouble()){
							//lastMovedPawn->resetLastMoveWasDouble(); //orsakar krasch..
						}
					}
					lastMovedPawn = dynamic_cast<Pawn*>(getPiece(newPosition));

					turn++;
					if (state == GameState::BLACKPLAYS)
						state = GameState::WHITEPLAYS;
					else
						state = GameState::BLACKPLAYS;

					std::string tempstring = toFENString(false);
					std::cout << tempstring << '\n';
					addBoardToMap();
					if(isThreeFoldRepitition())
						state = GameState::DRAW;
					if (isFiftyMoveSincePawnOrCapture())
						state = GameState::DRAW;
					if (!sufficientMaterial())
						state = GameState::DRAW;
					checkWin();
					return true;
				}
			}
		}

		return false;
	}

	bool Board::willLeaveKingChecked(const Position& oldPosition, const Position& newPosition) {
		Piece* oldPiece = getPiece(oldPosition);
		Piece* newPiece = getPiece(newPosition);

		Piece* piece;
		switch (oldPiece->notation()) {
		case 'Q':
		case 'q':
			piece = new Queen(oldPiece->getPosition(), oldPiece->isWhite());
			break;
		case 'K':
		case 'k':
			piece = new King(oldPiece->getPosition(), oldPiece->isWhite());
			break;
		case 'P':
		case 'p':
			piece = new Pawn(oldPiece->getPosition(), oldPiece->isWhite());
			break;
		case 'R':
		case 'r':
			piece = new Rook(oldPiece->getPosition(), oldPiece->isWhite());
			break;
		case 'B':
		case 'b':
			piece = new Bishop(oldPiece->getPosition(), oldPiece->isWhite());
			break;
		case 'N':
		case 'n':
			piece = new Knight(oldPiece->getPosition(), oldPiece->isWhite());
			break;
		}

		pieces[newPosition.x][newPosition.y] = piece;
		piece->move(newPosition);
		pieces[oldPosition.x][oldPosition.y] = nullptr;

		King* king = getKing((turn % 2 == 0));
		bool checked = king->isChecked(*this);

		delete piece;
		pieces[newPosition.x][newPosition.y] = newPiece;
		pieces[oldPosition.x][oldPosition.y] = oldPiece;

		return checked;
	}

	void Board::promotePawn(Piece* pawn, PromoteTypes type) {
		Position position = pawn->getPosition();
		bool white = pawn->isWhite();
		delete pawn;

		switch (type) {
		case PromoteTypes::QUEEN:
			pieces[position.x][position.y] = new Queen(position, white);
			break;
		case PromoteTypes::ROOK:
			pieces[position.x][position.y] = new Rook(position, white);
			break;
		case PromoteTypes::BISHOP:
			pieces[position.x][position.y] = new Bishop(position, white);
			break;
		case PromoteTypes::KNIGHT:
			pieces[position.x][position.y] = new Knight(position, white);
			break;
		}
		checkWin();
		needsToPromote = false;
	}
	void Board::addBoardToMap() {
		std::string tempstring = toFENString(false);
		if (previousBoards.find(tempstring) == previousBoards.end()) {
			previousBoards[tempstring] = 0;
		} else{
			previousBoards[tempstring] += 1;
		}
	}

	std::string Board::toFENString(bool addExtraData) const {
		std::string tempstring;
		int emptyCounter = 0;
		for (int y = 7; y >= 0; y--) {
			for (int x = 0; x < 8; x++){
				if (pieces[x][y] == nullptr)
					emptyCounter++;
				else {
					if (emptyCounter != 0)
						tempstring += std::to_string(emptyCounter);
					tempstring.append(1, pieces[x][y]->notation());
					emptyCounter = 0;
				}
			}
			if (emptyCounter != 0) {
				tempstring += std::to_string(emptyCounter);
				emptyCounter = 0;
			}
			tempstring += '/';
		}
		// Who played the turn?
		if (state == GameState::BLACKPLAYS)
			tempstring += "w";
		else
			tempstring += "b";

		if (addExtraData) {
			// Number of half turns since last capture or pawn move.
			tempstring += ' ' + std::to_string(halfMovesSinceCapture) + ' ';
			// Number of full moves.
			tempstring += std::to_string((turn+1) / 2);
		}
		return tempstring;
	}

	bool Board::isThreeFoldRepitition() {
		return previousBoards[toFENString(false)] == 3;
	}

	bool Board::isFiftyMoveSincePawnOrCapture() const {
		return halfMovesSinceCapture >= 100;
	}

	void Board::checkWin() {
		bool white = (state == GameState::WHITEPLAYS);

		bool canMove = false;
		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				Piece* piece = getPiece(Position(x, y));
				if (piece != nullptr && piece->isWhite() == white) {
					if (!piece->legalMoves(*this).empty()) {
						canMove = true;
						break;
					}
				}
			}
		}

		if (!canMove) {
			if (getKing(white)->isChecked(*this)) {
				if (white)
					state = GameState::BLACKWIN;
				else
					state = GameState::WHITEWIN;
			} else {
				state = GameState::DRAW;
			}
		}
	}

	bool Board::sufficientMaterial() const {
		// Get the material on the board.
		int pieceTypes[6] = { 0 };

		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				Piece* piece = getPiece(Position(x, y));
				if (piece != nullptr) {
					switch (piece->notation()) {
					case 'Q':
					case 'q':
						pieceTypes[0]++;
						break;
					case 'P':
					case 'p':
						pieceTypes[1]++;
						break;
					case 'R':
					case 'r':
						pieceTypes[2]++;
						break;
					case 'N':
					case 'n':
						pieceTypes[3]++;
						break;
					case 'B':
					case 'b':
						pieceTypes[((x + y) % 2 == 0) ? 4 : 5]++;
						break;
					}
				}
			}
		}

		// If there's a queen, pawn or rook on the board, there is sufficient material.
		if (pieceTypes[0] > 0 || pieceTypes[1] > 0 || pieceTypes[2] > 0)
			return true;

		// If there are 2 or more knights on the board, there is sufficient material.
		if (pieceTypes[3] > 1)
			return true;

		// If there are pieces from 2 or more categories (knight, bishop on light square, bishop on dark square), there is sufficient material.
		if ((pieceTypes[3] > 0) + (pieceTypes[4] > 0) + (pieceTypes[5] > 0) >= 2)
			return true;

		return false;

	}

	King* Board::getKing(bool white) const {
		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				Piece* piece = getPiece(Position(x, y));
				if (piece != nullptr && piece->notation() == (white ? 'K' : 'k'))
					return dynamic_cast<King*>(piece);
			}
		}

		return nullptr;
	}
}<|endoftext|>