<commit_before>
/*
 * Copyright 2015 Cloudius Systems
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <stdint.h>
#include <memory>
#include "bytes.hh"
#include "utils/allocation_strategy.hh"
#include <seastar/core/unaligned.hh>
#include <unordered_map>

struct blob_storage {
    using size_type = uint32_t;
    using char_type = bytes_view::value_type;

    blob_storage** backref;
    size_type size;
    size_type frag_size;
    blob_storage* next;
    char_type data[];

    blob_storage(blob_storage** backref, size_type size, size_type frag_size) noexcept
        : backref(backref)
        , size(size)
        , frag_size(frag_size)
        , next(nullptr)
    {
        *unaligned_cast<blob_storage**>(backref) = this;
    }

    blob_storage(blob_storage&& o) noexcept
        : backref(o.backref)
        , size(o.size)
        , frag_size(o.frag_size)
        , next(o.next)
    {
        *unaligned_cast<blob_storage**>(backref) = this;
        o.next = nullptr;
        if (next) {
            next->backref = &next;
        }
        memcpy(data, o.data, frag_size);
    }
} __attribute__((packed));

// A managed version of "bytes" (can be used with LSA).
class managed_bytes {
    struct linearization_context {
        unsigned _nesting = 0;
        // Map from first blob_storage address to linearized version
        // We use the blob_storage address to be insentive to moving
        // a managed_bytes object.
        std::unordered_map<const blob_storage*, std::unique_ptr<bytes_view::value_type[]>> _state;
        void enter() {
            ++_nesting;
        }
        void leave() {
            if (!--_nesting) {
                _state.clear();
            }
        }
        void forget(const blob_storage* p);
    };
    static thread_local linearization_context _linearization_context;
public:
    struct linearization_context_guard {
        linearization_context_guard() {
            _linearization_context.enter();
        }
        ~linearization_context_guard() {
            _linearization_context.leave();
        }
    };
private:
    static constexpr size_t max_inline_size = 15;
    struct small_blob {
        bytes_view::value_type data[max_inline_size];
        int8_t size; // -1 -> use blob_storage
    };
    union {
        blob_storage* ptr;
        small_blob small;
    } _u;
    static_assert(sizeof(small_blob) > sizeof(blob_storage*), "inline size too small");
private:
    bool external() const {
        return _u.small.size < 0;
    }
    size_t max_seg(allocation_strategy& alctr) {
        return alctr.preferred_max_contiguous_allocation() - sizeof(blob_storage);
    }
    void free_chain(blob_storage* p) {
        if (p->next && _linearization_context._nesting) {
            _linearization_context.forget(p);
        }
        auto& alctr = current_allocator();
        while (p) {
            auto n = p->next;
            alctr.destroy(p);
            p = n;
        }
    }
    const bytes_view::value_type* read_linearize() const {
        if (!external()) {
            return _u.small.data;
        } else  if (!_u.ptr->next) {
            return _u.ptr->data;
        } else {
            return do_linearize();
        }
    }
    const bytes_view::value_type* do_linearize() const;
public:
    using size_type = blob_storage::size_type;
    struct initialized_later {};

    managed_bytes() {
        _u.small.size = 0;
    }

    managed_bytes(const blob_storage::char_type* ptr, size_type size)
        : managed_bytes(bytes_view(ptr, size)) {}

    managed_bytes(const bytes& b) : managed_bytes(static_cast<bytes_view>(b)) {}

    managed_bytes(initialized_later, size_type size) {
        if (size <= max_inline_size) {
            _u.small.size = size;
        } else {
            _u.small.size = -1;
            auto& alctr = current_allocator();
            auto maxseg = max_seg(alctr);
            auto now = std::min(size_t(size), maxseg);
            void* p = alctr.alloc(&standard_migrator<blob_storage>::object,
                sizeof(blob_storage) + now, alignof(blob_storage));
            auto first = new (p) blob_storage(&_u.ptr, size, now);
            auto last = first;
            size -= now;
            try {
                while (size) {
                    auto now = std::min(size_t(size), maxseg);
                    void* p = alctr.alloc(&standard_migrator<blob_storage>::object,
                        sizeof(blob_storage) + now, alignof(blob_storage));
                    last = new (p) blob_storage(&last->next, 0, now);
                    size -= now;
                }
            } catch (...) {
                free_chain(first);
                throw;
            }
        }
    }

    managed_bytes(bytes_view v) : managed_bytes(initialized_later(), v.size()) {
        auto p = v.data();
        auto s = v.size();
        if (!external()) {
            memcpy(_u.small.data, p, s);
            return;
        }
        auto b = _u.ptr;
        while (s) {
            memcpy(b->data, p, b->frag_size);
            p += b->frag_size;
            s -= b->frag_size;
            b = b->next;
        }
        assert(!b);
    }

    managed_bytes(std::initializer_list<bytes::value_type> b) : managed_bytes(b.begin(), b.size()) {}

    ~managed_bytes() {
        if (external()) {
            free_chain(_u.ptr);
        }
    }

    managed_bytes(const managed_bytes& o) : managed_bytes(initialized_later(), o.size()) {
        if (!external()) {
            memcpy(data(), o.data(), size());
            return;
        }
        auto s = size();
        blob_storage* const* next_src = &o._u.ptr;
        blob_storage* blob_src = nullptr;
        size_type size_src = 0;
        size_type offs_src = 0;
        blob_storage** next_dst = &_u.ptr;
        blob_storage* blob_dst = nullptr;
        size_type size_dst = 0;
        size_type offs_dst = 0;
        while (s) {
            if (!size_src) {
                blob_src = *unaligned_cast<blob_storage**>(next_src);
                next_src = &blob_src->next;
                size_src = blob_src->frag_size;
                offs_src = 0;
            }
            if (!size_dst) {
                blob_dst = *unaligned_cast<blob_storage**>(next_dst);
                next_dst = &blob_dst->next;
                size_dst = blob_dst->frag_size;
                offs_dst = 0;
            }
            auto now = std::min(size_src, size_dst);
            memcpy(blob_dst->data + offs_dst, blob_src->data + offs_src, now);
            s -= now;
            offs_src += now; size_src -= now;
            offs_dst += now; size_dst -= now;
        }
        assert(size_src == 0 && size_dst == 0);
    }

    managed_bytes(managed_bytes&& o) noexcept
        : _u(o._u)
    {
        if (external()) {
            if (_u.ptr) {
                _u.ptr->backref = &_u.ptr;
            }
        }
        o._u.small.size = 0;
    }

    managed_bytes& operator=(managed_bytes&& o) {
        if (this != &o) {
            this->~managed_bytes();
            new (this) managed_bytes(std::move(o));
        }
        return *this;
    }

    managed_bytes& operator=(const managed_bytes& o) {
        if (this != &o) {
            // FIXME: not exception safe
            this->~managed_bytes();
            new (this) managed_bytes(o);
        }
        return *this;
    }

    bool operator==(const managed_bytes& o) const {
        if (size() != o.size()) {
            return false;
        }
        if (!external()) {
            return bytes_view(*this) == bytes_view(o);
        } else {
            auto a = _u.ptr;
            auto a_data = a->data;
            auto a_remain = a->frag_size;
            a = a->next;
            auto b = o._u.ptr;
            auto b_data = b->data;
            auto b_remain = b->frag_size;
            b = b->next;
            while (a_remain || b_remain) {
                auto now = std::min(a_remain, b_remain);
                if (bytes_view(a_data, now) != bytes_view(b_data, now)) {
                    return false;
                }
                a_data += now;
                a_remain -= now;
                if (!a_remain && a) {
                    a_data = a->data;
                    a_remain = a->frag_size;
                    a = a->next;
                }
                b_data += now;
                b_remain -= now;
                if (!b_remain && b) {
                    b_data = b->data;
                    b_remain = b->frag_size;
                    b = b->next;
                }
            }
            return true;
        }
    }

    bool operator!=(const managed_bytes& o) const {
        return !(*this == o);
    }

    operator bytes_view() const {
        return { data(), size() };
    }

    bytes_view::value_type& operator[](size_type index) {
        return data()[index];
    }

    const bytes_view::value_type& operator[](size_type index) const {
        return data()[index];
    }

    size_type size() const {
        if (external()) {
            return _u.ptr->size;
        } else {
            return _u.small.size;
        }
    }

    const blob_storage::char_type* begin() const {
        return data();
    }

    const blob_storage::char_type* end() const {
        return data() + size();
    }

    blob_storage::char_type* begin() {
        return data();
    }

    blob_storage::char_type* end() {
        return data() + size();
    }

    bool empty() const {
        return _u.small.size == 0;
    }

    blob_storage::char_type* data() {
        if (external()) {
            assert(!_u.ptr->next);  // must be linearized
            return _u.ptr->data;
        } else {
            return _u.small.data;
        }
    }

    const blob_storage::char_type* data() const {
        return read_linearize();
    }

    template <typename Func>
    friend auto with_linearized_managed_bytes(Func&& func);
};

// Run func() while ensuring that reads of managed_bytes objects are
// temporarlily linearized
template <typename Func>
inline
decltype(auto)
with_linearized_managed_bytes(Func&& func) {
    managed_bytes::linearization_context_guard g;
    return func();
}

namespace std {

template <>
struct hash<managed_bytes> {
    size_t operator()(const managed_bytes& v) const {
        return hash<bytes_view>()(v);
    }
};

}
<commit_msg>managed_bytes: don't return auto from non-member function<commit_after>
/*
 * Copyright 2015 Cloudius Systems
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <stdint.h>
#include <memory>
#include "bytes.hh"
#include "utils/allocation_strategy.hh"
#include <seastar/core/unaligned.hh>
#include <unordered_map>
#include <type_traits>

struct blob_storage {
    using size_type = uint32_t;
    using char_type = bytes_view::value_type;

    blob_storage** backref;
    size_type size;
    size_type frag_size;
    blob_storage* next;
    char_type data[];

    blob_storage(blob_storage** backref, size_type size, size_type frag_size) noexcept
        : backref(backref)
        , size(size)
        , frag_size(frag_size)
        , next(nullptr)
    {
        *unaligned_cast<blob_storage**>(backref) = this;
    }

    blob_storage(blob_storage&& o) noexcept
        : backref(o.backref)
        , size(o.size)
        , frag_size(o.frag_size)
        , next(o.next)
    {
        *unaligned_cast<blob_storage**>(backref) = this;
        o.next = nullptr;
        if (next) {
            next->backref = &next;
        }
        memcpy(data, o.data, frag_size);
    }
} __attribute__((packed));

// A managed version of "bytes" (can be used with LSA).
class managed_bytes {
    struct linearization_context {
        unsigned _nesting = 0;
        // Map from first blob_storage address to linearized version
        // We use the blob_storage address to be insentive to moving
        // a managed_bytes object.
        std::unordered_map<const blob_storage*, std::unique_ptr<bytes_view::value_type[]>> _state;
        void enter() {
            ++_nesting;
        }
        void leave() {
            if (!--_nesting) {
                _state.clear();
            }
        }
        void forget(const blob_storage* p);
    };
    static thread_local linearization_context _linearization_context;
public:
    struct linearization_context_guard {
        linearization_context_guard() {
            _linearization_context.enter();
        }
        ~linearization_context_guard() {
            _linearization_context.leave();
        }
    };
private:
    static constexpr size_t max_inline_size = 15;
    struct small_blob {
        bytes_view::value_type data[max_inline_size];
        int8_t size; // -1 -> use blob_storage
    };
    union {
        blob_storage* ptr;
        small_blob small;
    } _u;
    static_assert(sizeof(small_blob) > sizeof(blob_storage*), "inline size too small");
private:
    bool external() const {
        return _u.small.size < 0;
    }
    size_t max_seg(allocation_strategy& alctr) {
        return alctr.preferred_max_contiguous_allocation() - sizeof(blob_storage);
    }
    void free_chain(blob_storage* p) {
        if (p->next && _linearization_context._nesting) {
            _linearization_context.forget(p);
        }
        auto& alctr = current_allocator();
        while (p) {
            auto n = p->next;
            alctr.destroy(p);
            p = n;
        }
    }
    const bytes_view::value_type* read_linearize() const {
        if (!external()) {
            return _u.small.data;
        } else  if (!_u.ptr->next) {
            return _u.ptr->data;
        } else {
            return do_linearize();
        }
    }
    const bytes_view::value_type* do_linearize() const;
public:
    using size_type = blob_storage::size_type;
    struct initialized_later {};

    managed_bytes() {
        _u.small.size = 0;
    }

    managed_bytes(const blob_storage::char_type* ptr, size_type size)
        : managed_bytes(bytes_view(ptr, size)) {}

    managed_bytes(const bytes& b) : managed_bytes(static_cast<bytes_view>(b)) {}

    managed_bytes(initialized_later, size_type size) {
        if (size <= max_inline_size) {
            _u.small.size = size;
        } else {
            _u.small.size = -1;
            auto& alctr = current_allocator();
            auto maxseg = max_seg(alctr);
            auto now = std::min(size_t(size), maxseg);
            void* p = alctr.alloc(&standard_migrator<blob_storage>::object,
                sizeof(blob_storage) + now, alignof(blob_storage));
            auto first = new (p) blob_storage(&_u.ptr, size, now);
            auto last = first;
            size -= now;
            try {
                while (size) {
                    auto now = std::min(size_t(size), maxseg);
                    void* p = alctr.alloc(&standard_migrator<blob_storage>::object,
                        sizeof(blob_storage) + now, alignof(blob_storage));
                    last = new (p) blob_storage(&last->next, 0, now);
                    size -= now;
                }
            } catch (...) {
                free_chain(first);
                throw;
            }
        }
    }

    managed_bytes(bytes_view v) : managed_bytes(initialized_later(), v.size()) {
        auto p = v.data();
        auto s = v.size();
        if (!external()) {
            memcpy(_u.small.data, p, s);
            return;
        }
        auto b = _u.ptr;
        while (s) {
            memcpy(b->data, p, b->frag_size);
            p += b->frag_size;
            s -= b->frag_size;
            b = b->next;
        }
        assert(!b);
    }

    managed_bytes(std::initializer_list<bytes::value_type> b) : managed_bytes(b.begin(), b.size()) {}

    ~managed_bytes() {
        if (external()) {
            free_chain(_u.ptr);
        }
    }

    managed_bytes(const managed_bytes& o) : managed_bytes(initialized_later(), o.size()) {
        if (!external()) {
            memcpy(data(), o.data(), size());
            return;
        }
        auto s = size();
        blob_storage* const* next_src = &o._u.ptr;
        blob_storage* blob_src = nullptr;
        size_type size_src = 0;
        size_type offs_src = 0;
        blob_storage** next_dst = &_u.ptr;
        blob_storage* blob_dst = nullptr;
        size_type size_dst = 0;
        size_type offs_dst = 0;
        while (s) {
            if (!size_src) {
                blob_src = *unaligned_cast<blob_storage**>(next_src);
                next_src = &blob_src->next;
                size_src = blob_src->frag_size;
                offs_src = 0;
            }
            if (!size_dst) {
                blob_dst = *unaligned_cast<blob_storage**>(next_dst);
                next_dst = &blob_dst->next;
                size_dst = blob_dst->frag_size;
                offs_dst = 0;
            }
            auto now = std::min(size_src, size_dst);
            memcpy(blob_dst->data + offs_dst, blob_src->data + offs_src, now);
            s -= now;
            offs_src += now; size_src -= now;
            offs_dst += now; size_dst -= now;
        }
        assert(size_src == 0 && size_dst == 0);
    }

    managed_bytes(managed_bytes&& o) noexcept
        : _u(o._u)
    {
        if (external()) {
            if (_u.ptr) {
                _u.ptr->backref = &_u.ptr;
            }
        }
        o._u.small.size = 0;
    }

    managed_bytes& operator=(managed_bytes&& o) {
        if (this != &o) {
            this->~managed_bytes();
            new (this) managed_bytes(std::move(o));
        }
        return *this;
    }

    managed_bytes& operator=(const managed_bytes& o) {
        if (this != &o) {
            // FIXME: not exception safe
            this->~managed_bytes();
            new (this) managed_bytes(o);
        }
        return *this;
    }

    bool operator==(const managed_bytes& o) const {
        if (size() != o.size()) {
            return false;
        }
        if (!external()) {
            return bytes_view(*this) == bytes_view(o);
        } else {
            auto a = _u.ptr;
            auto a_data = a->data;
            auto a_remain = a->frag_size;
            a = a->next;
            auto b = o._u.ptr;
            auto b_data = b->data;
            auto b_remain = b->frag_size;
            b = b->next;
            while (a_remain || b_remain) {
                auto now = std::min(a_remain, b_remain);
                if (bytes_view(a_data, now) != bytes_view(b_data, now)) {
                    return false;
                }
                a_data += now;
                a_remain -= now;
                if (!a_remain && a) {
                    a_data = a->data;
                    a_remain = a->frag_size;
                    a = a->next;
                }
                b_data += now;
                b_remain -= now;
                if (!b_remain && b) {
                    b_data = b->data;
                    b_remain = b->frag_size;
                    b = b->next;
                }
            }
            return true;
        }
    }

    bool operator!=(const managed_bytes& o) const {
        return !(*this == o);
    }

    operator bytes_view() const {
        return { data(), size() };
    }

    bytes_view::value_type& operator[](size_type index) {
        return data()[index];
    }

    const bytes_view::value_type& operator[](size_type index) const {
        return data()[index];
    }

    size_type size() const {
        if (external()) {
            return _u.ptr->size;
        } else {
            return _u.small.size;
        }
    }

    const blob_storage::char_type* begin() const {
        return data();
    }

    const blob_storage::char_type* end() const {
        return data() + size();
    }

    blob_storage::char_type* begin() {
        return data();
    }

    blob_storage::char_type* end() {
        return data() + size();
    }

    bool empty() const {
        return _u.small.size == 0;
    }

    blob_storage::char_type* data() {
        if (external()) {
            assert(!_u.ptr->next);  // must be linearized
            return _u.ptr->data;
        } else {
            return _u.small.data;
        }
    }

    const blob_storage::char_type* data() const {
        return read_linearize();
    }

    template <typename Func>
    friend std::result_of_t<Func()> with_linearized_managed_bytes(Func&& func);
};

// Run func() while ensuring that reads of managed_bytes objects are
// temporarlily linearized
template <typename Func>
inline
std::result_of_t<Func()>
with_linearized_managed_bytes(Func&& func) {
    managed_bytes::linearization_context_guard g;
    return func();
}

namespace std {

template <>
struct hash<managed_bytes> {
    size_t operator()(const managed_bytes& v) const {
        return hash<bytes_view>()(v);
    }
};

}
<|endoftext|>


<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */
/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#include <algorithm>
#include <iostream>
#include "core/reactor.hh"
#include "core/fstream.hh"
#include "core/shared_ptr.hh"
#include "core/app-template.hh"
#include "core/do_with.hh"
#include "test-utils.hh"

struct writer {
    output_stream<char> out;
    writer(file f) : out(make_file_output_stream(
            make_lw_shared<file>(std::move(f)))) {}
};

struct reader {
    input_stream<char> in;
    reader(file f) : in(make_file_input_stream(
            make_lw_shared<file>(std::move(f)))) {}
};

SEASTAR_TEST_CASE(test_fstream) {
    static auto sem = make_lw_shared<semaphore>(0);

        engine().open_file_dma("testfile.tmp",
                open_flags::rw | open_flags::create | open_flags::truncate).then([] (file f) {
            auto w = make_shared<writer>(std::move(f));
            auto buf = static_cast<char*>(::malloc(4096));
            memset(buf, 0, 4096);
            buf[0] = '[';
            buf[1] = 'A';
            buf[4095] = ']';
            w->out.write(buf, 4096).then([buf, w] {
                ::free(buf);
                return make_ready_future<>();
            }).then([w] {
                auto buf = static_cast<char*>(::malloc(8192));
                memset(buf, 0, 8192);
                buf[0] = '[';
                buf[1] = 'B';
                buf[8191] = ']';
                return w->out.write(buf, 8192).then([buf, w] {
                    ::free(buf);
                    return w->out.close().then([w] {});
                });
            }).then([] {
                return engine().open_file_dma("testfile.tmp", open_flags::ro);
            }).then([] (file f) {
                /*  file content after running the above:
                 * 00000000  5b 41 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |[A..............|
                 * 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
                 * *
                 * 00000ff0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 5d  |...............]|
                 * 00001000  5b 42 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |[B..............|
                 * 00001010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
                 * *
                 * 00002ff0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 5d  |...............]|
                 * 00003000
                 */
                auto r = make_shared<reader>(std::move(f));
                return r->in.read_exactly(4096 + 8192).then([r] (temporary_buffer<char> buf) {
                    auto p = buf.get();
                    BOOST_REQUIRE(p[0] == '[' && p[1] == 'A' && p[4095] == ']');
                    BOOST_REQUIRE(p[4096] == '[' && p[4096 + 1] == 'B' && p[4096 + 8191] == ']');
                    return make_ready_future<>();
                });
            }).finally([] () {
                sem->signal();
            });
        });

    return sem->wait();
}

SEASTAR_TEST_CASE(test_fstream_unaligned) {
    static auto sem = make_lw_shared<semaphore>(0);

    engine().open_file_dma("testfile.tmp",
            open_flags::rw | open_flags::create | open_flags::truncate).then([] (file f) {
        auto w = make_shared<writer>(std::move(f));
        auto buf = static_cast<char*>(::malloc(40));
        memset(buf, 0, 40);
        buf[0] = '[';
        buf[1] = 'A';
        buf[39] = ']';
        w->out.write(buf, 40).then([buf, w] {
            ::free(buf);
            return w->out.close().then([w] {});
        }).then([] {
            return engine().open_file_dma("testfile.tmp", open_flags::ro);
        }).then([] (file f) {
            return do_with(std::move(f), [] (file& f) {
                return f.size().then([] (size_t size) {
                    // assert that file was indeed truncated to the amount of bytes written.
                    BOOST_REQUIRE(size == 40);
                    return make_ready_future<>();
                });
            });
        }).then([] {
            return engine().open_file_dma("testfile.tmp", open_flags::ro);
        }).then([] (file f) {
            auto r = make_shared<reader>(std::move(f));
            return r->in.read_exactly(40).then([r] (temporary_buffer<char> buf) {
                auto p = buf.get();
                BOOST_REQUIRE(p[0] == '[' && p[1] == 'A' && p[39] == ']');
                return make_ready_future<>();
            });
        }).finally([] () {
            sem->signal();
        });
    });

    return sem->wait();
}
<commit_msg>tests: fix fstream_test misuse of shared_ptr<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */
/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#include <algorithm>
#include <iostream>
#include "core/reactor.hh"
#include "core/fstream.hh"
#include "core/shared_ptr.hh"
#include "core/app-template.hh"
#include "core/do_with.hh"
#include "test-utils.hh"

struct writer {
    output_stream<char> out;
    writer(file f) : out(make_file_output_stream(
            make_lw_shared<file>(std::move(f)))) {}
};

struct reader {
    input_stream<char> in;
    reader(file f) : in(make_file_input_stream(
            make_lw_shared<file>(std::move(f)))) {}
};

SEASTAR_TEST_CASE(test_fstream) {
    auto sem = make_lw_shared<semaphore>(0);

        engine().open_file_dma("testfile.tmp",
                open_flags::rw | open_flags::create | open_flags::truncate).then([sem] (file f) {
            auto w = make_shared<writer>(std::move(f));
            auto buf = static_cast<char*>(::malloc(4096));
            memset(buf, 0, 4096);
            buf[0] = '[';
            buf[1] = 'A';
            buf[4095] = ']';
            w->out.write(buf, 4096).then([buf, w] {
                ::free(buf);
                return make_ready_future<>();
            }).then([w] {
                auto buf = static_cast<char*>(::malloc(8192));
                memset(buf, 0, 8192);
                buf[0] = '[';
                buf[1] = 'B';
                buf[8191] = ']';
                return w->out.write(buf, 8192).then([buf, w] {
                    ::free(buf);
                    return w->out.close().then([w] {});
                });
            }).then([] {
                return engine().open_file_dma("testfile.tmp", open_flags::ro);
            }).then([] (file f) {
                /*  file content after running the above:
                 * 00000000  5b 41 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |[A..............|
                 * 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
                 * *
                 * 00000ff0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 5d  |...............]|
                 * 00001000  5b 42 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |[B..............|
                 * 00001010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
                 * *
                 * 00002ff0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 5d  |...............]|
                 * 00003000
                 */
                auto r = make_shared<reader>(std::move(f));
                return r->in.read_exactly(4096 + 8192).then([r] (temporary_buffer<char> buf) {
                    auto p = buf.get();
                    BOOST_REQUIRE(p[0] == '[' && p[1] == 'A' && p[4095] == ']');
                    BOOST_REQUIRE(p[4096] == '[' && p[4096 + 1] == 'B' && p[4096 + 8191] == ']');
                    return make_ready_future<>();
                });
            }).finally([sem] () {
                sem->signal();
            });
        });

    return sem->wait();
}

SEASTAR_TEST_CASE(test_fstream_unaligned) {
    auto sem = make_lw_shared<semaphore>(0);

    engine().open_file_dma("testfile.tmp",
            open_flags::rw | open_flags::create | open_flags::truncate).then([sem] (file f) {
        auto w = make_shared<writer>(std::move(f));
        auto buf = static_cast<char*>(::malloc(40));
        memset(buf, 0, 40);
        buf[0] = '[';
        buf[1] = 'A';
        buf[39] = ']';
        w->out.write(buf, 40).then([buf, w] {
            ::free(buf);
            return w->out.close().then([w] {});
        }).then([] {
            return engine().open_file_dma("testfile.tmp", open_flags::ro);
        }).then([] (file f) {
            return do_with(std::move(f), [] (file& f) {
                return f.size().then([] (size_t size) {
                    // assert that file was indeed truncated to the amount of bytes written.
                    BOOST_REQUIRE(size == 40);
                    return make_ready_future<>();
                });
            });
        }).then([] {
            return engine().open_file_dma("testfile.tmp", open_flags::ro);
        }).then([] (file f) {
            auto r = make_shared<reader>(std::move(f));
            return r->in.read_exactly(40).then([r] (temporary_buffer<char> buf) {
                auto p = buf.get();
                BOOST_REQUIRE(p[0] == '[' && p[1] == 'A' && p[39] == ']');
                return make_ready_future<>();
            });
        }).finally([sem] () {
            sem->signal();
        });
    });

    return sem->wait();
}
<|endoftext|>


<commit_before>#ifndef FILTER__H__
#define FILTER__H__

namespace iter {

    //Forward declarations of Filter and filter
    template <typename FilterFunc, typename Container>
    class Filter;

    template <typename FilterFunc, typename Container>
    Filter<FilterFunc, Container> filter(FilterFunc, Container &);

    template <typename FilterFunc, typename Container>
    class Filter {
        // The filter function is the only thing allowed to create a Filter
        friend Filter filter<FilterFunc, Container>(FilterFunc, Container &);

        // Type of the Container::Iterator, but since the name of that
        // iterator can be anything, we have to grab it with this
        using contained_iter_type =
            decltype(((Container *)nullptr)->begin());

        // The type returned when dereferencing the Container::Iterator
        using contained_iter_ret =
            decltype(((contained_iter_type *)nullptr)->operator*());

        private:
            Container & container;
            FilterFunc filter_func;

            // Value constructor for use only in the filter function
            Filter(FilterFunc filter_func, Container & container) :
                container(container),
                filter_func(filter_func)
            { }
            Filter () = delete;
            Filter & operator=(const Filter &) = delete;
            // Default copy constructor used

        public:
            class Iterator {
                private:
                    contained_iter_type sub_iter;
                    const contained_iter_type sub_end;
                    FilterFunc filter_func;

                    // increment until the iterator points to is true on the
                    // predicate.  Called by constructor and operator++
                    void skip_failures() {
                        while (this->sub_iter != this->sub_end
                                && !this->filter_func(*this->sub_iter)) {
                            ++this->sub_iter;
                        }
                    }

                public:
                    Iterator (contained_iter_type iter,
                            contained_iter_type end,
                            FilterFunc filter_func) :
                        sub_iter(iter),
                        sub_end(end),
                        filter_func(filter_func)
                    {
                        this->skip_failures();
                    }

                    contained_iter_ret operator*() const {
                        return *this->sub_iter;
                    }

                    Iterator & operator++() {
                        ++this->sub_iter;
                        this->skip_failures();
                        return *this;
                    }

                    bool operator!=(const Iterator & other) const {
                        return this->sub_iter != other.sub_iter;
                    }
            };

            Iterator begin() const {
                return Iterator(
                        this->container.begin(),
                        this->container.end(),
                        this->filter_func);
            }

            Iterator end() const {
                return Iterator(
                        this->container.end(),
                        this->container.end(),
                        this->filter_func);
            }

    };

    // Helper function to instantiate a Filter
    template <typename FilterFunc, typename Container>
    Filter<FilterFunc, Container> filter(
            FilterFunc filter_func, Container & container) {
        return Filter<FilterFunc, Container>(filter_func, container);
    }

}

#endif //ifndef FILTER__H__
<commit_msg>Replaces ugly decltype with std::declval in filter<commit_after>#ifndef FILTER__H__
#define FILTER__H__

#include <utility>

namespace iter {

    //Forward declarations of Filter and filter
    template <typename FilterFunc, typename Container>
    class Filter;

    template <typename FilterFunc, typename Container>
    Filter<FilterFunc, Container> filter(FilterFunc, Container &);

    template <typename FilterFunc, typename Container>
    class Filter {
        // The filter function is the only thing allowed to create a Filter
        friend Filter filter<FilterFunc, Container>(FilterFunc, Container &);

        // Type of the Container::Iterator, but since the name of that
        // iterator can be anything, we have to grab it with this
        using contained_iter_type =
            decltype(std::declval<Container>().begin());

        // The type returned when dereferencing the Container::Iterator
        using contained_iter_ret =
            decltype(std::declval<contained_iter_type>().operator*());

        private:
            Container & container;
            FilterFunc filter_func;

            // Value constructor for use only in the filter function
            Filter(FilterFunc filter_func, Container & container) :
                container(container),
                filter_func(filter_func)
            { }
            Filter () = delete;
            Filter & operator=(const Filter &) = delete;
            // Default copy constructor used

        public:
            class Iterator {
                private:
                    contained_iter_type sub_iter;
                    const contained_iter_type sub_end;
                    FilterFunc filter_func;

                    // increment until the iterator points to is true on the
                    // predicate.  Called by constructor and operator++
                    void skip_failures() {
                        while (this->sub_iter != this->sub_end
                                && !this->filter_func(*this->sub_iter)) {
                            ++this->sub_iter;
                        }
                    }

                public:
                    Iterator (contained_iter_type iter,
                            contained_iter_type end,
                            FilterFunc filter_func) :
                        sub_iter(iter),
                        sub_end(end),
                        filter_func(filter_func)
                    {
                        this->skip_failures();
                    }

                    contained_iter_ret operator*() const {
                        return *this->sub_iter;
                    }

                    Iterator & operator++() {
                        ++this->sub_iter;
                        this->skip_failures();
                        return *this;
                    }

                    bool operator!=(const Iterator & other) const {
                        return this->sub_iter != other.sub_iter;
                    }
            };

            Iterator begin() const {
                return Iterator(
                        this->container.begin(),
                        this->container.end(),
                        this->filter_func);
            }

            Iterator end() const {
                return Iterator(
                        this->container.end(),
                        this->container.end(),
                        this->filter_func);
            }

    };

    // Helper function to instantiate a Filter
    template <typename FilterFunc, typename Container>
    Filter<FilterFunc, Container> filter(
            FilterFunc filter_func, Container & container) {
        return Filter<FilterFunc, Container>(filter_func, container);
    }

}

#endif //ifndef FILTER__H__
<|endoftext|>


<commit_before>#ifndef FILTER__H__
#define FILTER__H__

#include "iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>

namespace iter {

    //Forward declarations of Filter and filter
    template <typename FilterFunc, typename Container>
    class Filter;

    template <typename FilterFunc, typename Container>
    Filter<FilterFunc, Container> filter(FilterFunc, Container&&);

    template <typename FilterFunc, typename T>
    Filter<FilterFunc, std::initializer_list<T>> filter(
            FilterFunc, std::initializer_list<T>&&);

    template <typename FilterFunc, typename Container>
    class Filter {
        private:
            Container& container;
            FilterFunc filter_func;

            // The filter function is the only thing allowed to create a Filter
            friend Filter filter<FilterFunc, Container>(
                    FilterFunc, Container&&);

            template <typename FF, typename T>
            friend Filter<FF, std::initializer_list<T>> filter(
                    FF, std::initializer_list<T>&&);

            // Value constructor for use only in the filter function
            Filter(FilterFunc filter_func, Container&& container)
                : container{container},
                filter_func(filter_func)
            { }
            Filter() = delete;
            Filter& operator=(const Filter&) = delete;

        public:
            Filter(const Filter&) = default;

            class Iterator {
                protected:
                    iterator_type<Container> sub_iter;
                    const iterator_type<Container> sub_end;
                    FilterFunc filter_func;

                    // increment until the iterator points to is true on the
                    // predicate.  Called by constructor and operator++
                    void skip_failures() {
                        while (this->sub_iter != this->sub_end
                                && !this->filter_func(*this->sub_iter)) {
                            ++this->sub_iter;
                        }
                    }

                public:
                    Iterator (iterator_type<Container> iter,
                            iterator_type<Container> end,
                            FilterFunc filter_func)
                        : sub_iter{iter},
                        sub_end{end},
                        filter_func(filter_func)
                    {
                        this->skip_failures();
                    }

                    iterator_deref<Container> operator*() const {
                        return *this->sub_iter;
                    }

                    Iterator& operator++() {
                        ++this->sub_iter;
                        this->skip_failures();
                        return *this;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->sub_iter != other.sub_iter;
                    }
            };

            Iterator begin() {
                return {std::begin(this->container),
                        std::end(this->container),
                        this->filter_func};
            }

            Iterator end() {
                return {std::end(this->container),
                        std::end(this->container),
                        this->filter_func};
            }

    };

    // Helper function to instantiate a Filter
    template <typename FilterFunc, typename Container>
    Filter<FilterFunc, Container> filter(
            FilterFunc filter_func, Container&& container) {
        return {filter_func, std::forward<Container>(container)};
    }

    template <typename FilterFunc, typename T>
    Filter<FilterFunc, std::initializer_list<T>> filter(
            FilterFunc filter_func,
            std::initializer_list<T>&& il)
    {
        return {filter_func, std::move(il)};
    }

    namespace detail {

        template <typename T>
        bool boolean_cast(const T& t) {
            return bool(t);
        }

        template <typename Container>
        class BoolTester {
            public:
                bool operator() (const iterator_deref<Container> item) const {
                    return bool(item);
                }
        };
    }

    template <typename Container>
    auto filter(Container&& container) ->
            decltype(filter(
                        detail::BoolTester<Container>(),
                        std::forward<Container>(container))) {
        return filter(
                detail::BoolTester<Container>(),
                std::forward<Container>(container));
    }

    template <typename T>
    auto filter(std::initializer_list<T>&& il) ->
            decltype(filter(
                        detail::BoolTester<std::initializer_list<T>>(),
                        std::move(il))) {
           return filter(
                   detail::BoolTester<std::initializer_list<T>>(),
                   std::move(il));
    }

}

#endif //ifndef FILTER__H__
<commit_msg>Corrects support for temporaries in filter<commit_after>#ifndef FILTER__H__
#define FILTER__H__

#include "iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>

namespace iter {

    //Forward declarations of Filter and filter
    template <typename FilterFunc, typename Container>
    class Filter;

    template <typename FilterFunc, typename Container>
    Filter<FilterFunc, Container> filter(FilterFunc, Container&&);

    template <typename FilterFunc, typename T>
    Filter<FilterFunc, std::initializer_list<T>> filter(
            FilterFunc, std::initializer_list<T>);

    template <typename FilterFunc, typename Container>
    class Filter {
        private:
            Container container;
            FilterFunc filter_func;

            // The filter function is the only thing allowed to create a Filter
            friend Filter filter<FilterFunc, Container>(
                    FilterFunc, Container&&);

            template <typename FF, typename T>
            friend Filter<FF, std::initializer_list<T>> filter(
                    FF, std::initializer_list<T>);

            // Value constructor for use only in the filter function
            Filter(FilterFunc filter_func, Container container)
                : container(std::forward<Container>(container)),
                filter_func(filter_func)
            { }
            Filter() = delete;
            Filter& operator=(const Filter&) = delete;

        public:
            Filter(const Filter&) = default;

            class Iterator {
                protected:
                    iterator_type<Container> sub_iter;
                    const iterator_type<Container> sub_end;
                    FilterFunc filter_func;

                    // increment until the iterator points to is true on the
                    // predicate.  Called by constructor and operator++
                    void skip_failures() {
                        while (this->sub_iter != this->sub_end
                                && !this->filter_func(*this->sub_iter)) {
                            ++this->sub_iter;
                        }
                    }

                public:
                    Iterator (iterator_type<Container> iter,
                            iterator_type<Container> end,
                            FilterFunc filter_func)
                        : sub_iter{iter},
                        sub_end{end},
                        filter_func(filter_func)
                    {
                        this->skip_failures();
                    }

                    iterator_deref<Container> operator*() const {
                        return *this->sub_iter;
                    }

                    Iterator& operator++() {
                        ++this->sub_iter;
                        this->skip_failures();
                        return *this;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->sub_iter != other.sub_iter;
                    }
            };

            Iterator begin() {
                return {std::begin(this->container),
                        std::end(this->container),
                        this->filter_func};
            }

            Iterator end() {
                return {std::end(this->container),
                        std::end(this->container),
                        this->filter_func};
            }

    };

    // Helper function to instantiate a Filter
    template <typename FilterFunc, typename Container>
    Filter<FilterFunc, Container> filter(
            FilterFunc filter_func, Container&& container) {
        return {filter_func, std::forward<Container>(container)};
    }

    template <typename FilterFunc, typename T>
    Filter<FilterFunc, std::initializer_list<T>> filter(
            FilterFunc filter_func,
            std::initializer_list<T> il)
    {
        return {filter_func, std::move(il)};
    }

    namespace detail {

        template <typename T>
        bool boolean_cast(const T& t) {
            return bool(t);
        }

        template <typename Container>
        class BoolTester {
            public:
                bool operator() (const iterator_deref<Container> item) const {
                    return bool(item);
                }
        };
    }

    template <typename Container>
    auto filter(Container&& container) ->
            decltype(filter(
                        detail::BoolTester<Container>(),
                        std::forward<Container>(container))) {
        return filter(
                detail::BoolTester<Container>(),
                std::forward<Container>(container));
    }

    template <typename T>
    auto filter(std::initializer_list<T>&& il) ->
            decltype(filter(
                        detail::BoolTester<std::initializer_list<T>>(),
                        std::move(il))) {
           return filter(
                   detail::BoolTester<std::initializer_list<T>>(),
                   std::move(il));
    }

}

#endif //ifndef FILTER__H__
<|endoftext|>


<commit_before>#ifndef MS_RTC_CODECS_H264_HPP
#define MS_RTC_CODECS_H264_HPP

#include "common.hpp"
#include "RTC/Codecs/PayloadDescriptorHandler.hpp"
#include "RTC/RtpPacket.hpp"

namespace RTC
{
	namespace Codecs
	{
		class H264
		{
		public:
			struct PayloadDescriptor : public RTC::Codecs::PayloadDescriptor
			{
				/* Pure virtual methods inherited from RTC::Codecs::PayloadDescriptor. */
				~PayloadDescriptor() = default;

				void Dump() const override;

				// Fields in frame-marking extension.
				uint8_t s : 1;          // Start of Frame.
				uint8_t e : 1;          // End of Frame.
				uint8_t i : 1;          // Independent Frame.
				uint8_t d : 1;          // Discardable Frame.
				uint8_t b : 1;          // Base Layer Sync.
				uint8_t tid{ 0 };       // Temporal layer id.
				uint8_t lid{ 0 };       // Spatial layer id.
				uint8_t tl0picidx{ 0 }; // TL0PICIDX
				// Parsed values.
				bool hasLid{ false };
				bool hasTl0picidx{ false };
				bool isKeyFrame{ false };
			};

		public:
			static H264::PayloadDescriptor* Parse(
			  const uint8_t* data,
			  size_t len,
			  RTC::RtpPacket::FrameMarking* frameMarking = nullptr,
			  uint8_t frameMarkingLen                    = 0);
			static void ProcessRtpPacket(RTC::RtpPacket* packet);

		public:
			class EncodingContext : public RTC::Codecs::EncodingContext
			{
			public:
				~EncodingContext() = default;

				/* Pure virtual methods inherited from RTC::Codecs::EncodingContext. */
			public:
				void SyncRequired() override;
			};

		public:
			class PayloadDescriptorHandler : public RTC::Codecs::PayloadDescriptorHandler
			{
			public:
				explicit PayloadDescriptorHandler(PayloadDescriptor* payloadDescriptor);
				~PayloadDescriptorHandler() = default;

			public:
				void Dump() const override;
				bool Process(RTC::Codecs::EncodingContext* context, uint8_t* data) override;
				void Restore(uint8_t* data) override;
				uint8_t GetSpatialLayer() const override;
				uint8_t GetTemporalLayer() const override;
				bool IsKeyFrame() const override;

			private:
				std::unique_ptr<PayloadDescriptor> payloadDescriptor;
			};
		};

		/* Inline EncondingContext methods. */

		inline void H264::EncodingContext::SyncRequired()
		{
		}

		/* Inline PayloadDescriptorHandler methods. */

		inline void H264::PayloadDescriptorHandler::Dump() const
		{
			this->payloadDescriptor->Dump();
		}

		inline uint8_t H264::PayloadDescriptorHandler::GetSpatialLayer() const
		{
			return 0u;
		}

		inline uint8_t H264::PayloadDescriptorHandler::GetTemporalLayer() const
		{
			return this->payloadDescriptor->tid;
		}

		inline bool H264::PayloadDescriptorHandler::IsKeyFrame() const
		{
			return this->payloadDescriptor->isKeyFrame;
		}
	} // namespace Codecs
} // namespace RTC

#endif
<commit_msg>Make clang tidy happy<commit_after>#ifndef MS_RTC_CODECS_H264_HPP
#define MS_RTC_CODECS_H264_HPP

#include "common.hpp"
#include "RTC/Codecs/PayloadDescriptorHandler.hpp"
#include "RTC/RtpPacket.hpp"

namespace RTC
{
	namespace Codecs
	{
		class H264
		{
		public:
			struct PayloadDescriptor : public RTC::Codecs::PayloadDescriptor
			{
				/* Pure virtual methods inherited from RTC::Codecs::PayloadDescriptor. */
				~PayloadDescriptor() = default;

				void Dump() const override;

				// Fields in frame-marking extension.
				uint8_t s : 1;          // Start of Frame.
				uint8_t e : 1;          // End of Frame.
				uint8_t i : 1;          // Independent Frame.
				uint8_t d : 1;          // Discardable Frame.
				uint8_t b : 1;          // Base Layer Sync.
				uint8_t tid{ 0 };       // Temporal layer id.
				uint8_t lid{ 0 };       // Spatial layer id.
				uint8_t tl0picidx{ 0 }; // TL0PICIDX
				// Parsed values.
				bool hasLid{ false };
				bool hasTl0picidx{ false };
				bool isKeyFrame{ false };
			};

		public:
			static H264::PayloadDescriptor* Parse(
			  const uint8_t* data,
			  size_t len,
			  RTC::RtpPacket::FrameMarking* frameMarking = nullptr,
			  uint8_t frameMarkingLen                    = 0);
			static void ProcessRtpPacket(RTC::RtpPacket* packet);

		public:
			class EncodingContext : public RTC::Codecs::EncodingContext
			{
			public:
				~EncodingContext() = default;

				/* Pure virtual methods inherited from RTC::Codecs::EncodingContext. */
			public:
				void SyncRequired() override;
			};

		public:
			class PayloadDescriptorHandler : public RTC::Codecs::PayloadDescriptorHandler
			{
			public:
				explicit PayloadDescriptorHandler(PayloadDescriptor* payloadDescriptor);
				~PayloadDescriptorHandler() = default;

			public:
				void Dump() const override;
				bool Process(RTC::Codecs::EncodingContext* encodingContext, uint8_t* data) override;
				void Restore(uint8_t* data) override;
				uint8_t GetSpatialLayer() const override;
				uint8_t GetTemporalLayer() const override;
				bool IsKeyFrame() const override;

			private:
				std::unique_ptr<PayloadDescriptor> payloadDescriptor;
			};
		};

		/* Inline EncondingContext methods. */

		inline void H264::EncodingContext::SyncRequired()
		{
		}

		/* Inline PayloadDescriptorHandler methods. */

		inline void H264::PayloadDescriptorHandler::Dump() const
		{
			this->payloadDescriptor->Dump();
		}

		inline uint8_t H264::PayloadDescriptorHandler::GetSpatialLayer() const
		{
			return 0u;
		}

		inline uint8_t H264::PayloadDescriptorHandler::GetTemporalLayer() const
		{
			return this->payloadDescriptor->tid;
		}

		inline bool H264::PayloadDescriptorHandler::IsKeyFrame() const
		{
			return this->payloadDescriptor->isKeyFrame;
		}
	} // namespace Codecs
} // namespace RTC

#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: Dff.cxx,v $
 * $Revision: 1.12 $
 *
 * 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.
 *
 ************************************************************************/

#include "Dff.hxx"
#include <doctok/resourceids.hxx>
#include <resourcemodel/WW8ResourceModel.hxx>
#include "resources.hxx"

namespace writerfilter {
namespace doctok {

typedef boost::shared_ptr<WW8Value> WW8ValueSharedPointer_t;

DffRecord::DffRecord(WW8Stream & rStream, sal_uInt32 nOffset,
                     sal_uInt32 nCount)
: WW8StructBase(rStream, nOffset, nCount), bInitialized(false)
{
}

DffRecord::DffRecord(WW8StructBase * pParent, sal_uInt32 nOffset,
                     sal_uInt32 nCount)
: WW8StructBase(pParent, nOffset, nCount), bInitialized(false)
{
}

Records_t::iterator DffRecord::begin()
{
    if (! bInitialized)
        initChildren();

    return mRecords.begin();
}

Records_t::iterator DffRecord::end()
{
    if (! bInitialized)
        initChildren();

    return mRecords.end();
}

bool DffRecord::isContainer() const
{
    return getVersion() == 0xf;
}

sal_uInt32 DffRecord::calcSize() const
{
    sal_uInt32 nResult = 0;

    switch (getRecordType())
    {
    case 0xf000:
    case 0xf001:
    case 0xf002:
    case 0xf003:
    case 0xf004:
        nResult = getU32(0x4) + 8;

        break;
    case 0xf700:
        nResult = 8;

        break;
    default:
        nResult = getU32(0x4);

        if (! isContainer())
            nResult += 8;
        break;
    }

    return nResult;
}

sal_uInt32 DffRecord::getVersion() const
{
    return getU8(0x0) & 0xf;
}

sal_uInt32 DffRecord::getInstance() const
{
    return (getU16(0x0) & 0xfff0) >> 4;
}

sal_uInt32 DffRecord::getRecordType() const
{
    return getU16(0x2);
}

void DffRecord::initChildren()
{
    if (isContainer())
    {
        sal_uInt32 nOffset = 8;
        sal_uInt32 nCount = calcSize();

        while (nCount - nOffset >= 8)
        {
            sal_uInt32 nSize = 0;
            boost::shared_ptr<DffRecord> pRec
                (createDffRecord(this, nOffset, &nSize));

            if (nSize == 0)
                break;

            mRecords.push_back(pRec);

            nOffset += nSize;
        }
    }

    bInitialized = true;
}

Records_t DffRecord::findRecords(sal_uInt32 nType, bool bRecursive, bool bAny)
{
    Records_t aResult;

    findRecords(nType, aResult, bRecursive, bAny);

    return aResult;
}

void DffRecord::findRecords
(sal_uInt32 nType, Records_t & rRecords, bool bRecursive, bool bAny)
{
    Records_t::iterator aIt = begin();

    while (aIt != end())
    {
        Pointer_t pPointer = *aIt;
        if (bAny || pPointer->getRecordType() == nType)
            rRecords.push_back(pPointer);

        if (bRecursive)
            pPointer->findRecords(nType, rRecords, bRecursive,
                                      bAny);

        ++aIt;
    }
}

void DffRecord::resolveChildren(Properties & rHandler)
{
    Records_t::iterator aIt;
    for (aIt = begin(); aIt != end(); ++aIt)
    {
        rHandler.sprm(**aIt);
    }
}

void DffRecord::resolveLocal(Properties &)
{
}

void DffRecord::resolve(Properties & rHandler)
{
    WW8Value::Pointer_t pVal = createValue(getRecordType());
    rHandler.attribute(NS_rtf::LN_dfftype, *pVal);

    pVal = createValue(getInstance());
    rHandler.attribute(NS_rtf::LN_dffinstance, *pVal);

    pVal = createValue(getVersion());
    rHandler.attribute(NS_rtf::LN_dffversion, *pVal);

    pVal = createValue(getU32(0x0));
    rHandler.attribute(NS_rtf::LN_dffheader, *pVal);

    if (isContainer())
    {
        resolveChildren(rHandler);
    }

    resolveLocal(rHandler);

#if 1
    WW8BinaryObjReference::Pointer_t pBinObjRef
        (new WW8BinaryObjReference(this, 0, getCount()));
    WW8Sprm aSprm(pBinObjRef);

    rHandler.sprm(aSprm);
#endif
}

sal_uInt32 DffRecord::getShapeType()
{
    sal_uInt32 nResult = 0;

    Records_t aRecords = findRecords(0xf00a);

    if (aRecords.size() > 0)
    {
        DffFSP * pDffFSP = dynamic_cast<DffFSP*>((*aRecords.begin()).get());
        nResult = pDffFSP->get_shptype();
    }

    return nResult;
}

sal_uInt32 DffRecord::getShapeId()
{
    sal_uInt32 nResult = 0;

    Records_t aRecords = findRecords(0xf00a);

    if (aRecords.size() > 0)
    {
        DffFSP * pDffFSP = dynamic_cast<DffFSP*>((*aRecords.begin()).get());
        nResult = pDffFSP->get_shpid();
    }

    return nResult;
}

class DffOPTHandler : public Properties
{
    map<int, WW8ValueSharedPointer_t> mMap;
    int nId;

public:
    DffOPTHandler() : nId(0) {}
    virtual ~DffOPTHandler() {}

    virtual void attribute(Id name, Value & val)
    {
        switch (name)
        {
        case NS_rtf::LN_shppid:
            nId = val.getInt();
            break;
        case NS_rtf::LN_shpvalue:
            {
                WW8Value & rTmpVal = dynamic_cast<WW8Value &>(val);
                WW8ValueSharedPointer_t
                    pVal(dynamic_cast<WW8Value *>(rTmpVal.clone()));
                mMap[nId] = pVal;
            }
        }
    }

    virtual void sprm(Sprm & /*sprm_*/)
    {
    }

    WW8ValueSharedPointer_t & getValue(int nId_)
    {
        return mMap[nId_];
    }

};

sal_uInt32 DffRecord::getShapeBid()
{
    sal_uInt32 nResult = 0;

    if (getShapeType() == 75)
    {
        Records_t aRecords = findRecords(0xf00b);

        if (aRecords.size() > 0)
        {
            DffOPTHandler aHandler;
            DffOPT * pOpts = dynamic_cast<DffOPT*>((*aRecords.begin()).get());

            sal_uInt32 nCount = pOpts->get_property_count();

            for (sal_uInt32 n = 0; n < nCount; ++n)
            {
                pOpts->get_property(n)->resolve(aHandler);
            }

            WW8ValueSharedPointer_t pVal = aHandler.getValue(260);

            if (pVal.get() != NULL)
                nResult = pVal->getInt();
        }
    }

    return nResult;
}

string DffRecord::getType() const
{
    return "DffRecord";
}

Value::Pointer_t DffRecord::getValue()
{
    return Value::Pointer_t();
}

writerfilter::Reference<BinaryObj>::Pointer_t DffRecord::getBinary()
{
    return writerfilter::Reference<BinaryObj>::Pointer_t();
}

writerfilter::Reference<Stream>::Pointer_t DffRecord::getStream()
{
    return writerfilter::Reference<Stream>::Pointer_t();
}

writerfilter::Reference<Properties>::Pointer_t DffRecord::getProps()
{
    return writerfilter::Reference<Properties>::Pointer_t(this->clone());
}

string DffRecord::toString() const
{
    char sBuffer[1024];

    snprintf(sBuffer, sizeof(sBuffer),
             "<dffrecord type=\"%" SAL_PRIuUINT32 "\" instance=\"%" SAL_PRIuUINT32 "\" version=\"%" SAL_PRIuUINT32 "\">\n",
             getRecordType(), getInstance(), getVersion());
    string aResult = sBuffer;

    if (!isContainer())
        aResult += mSequence.toString();
    else
    {
        WW8StructBase::Sequence aSeq(mSequence, 0, 8);
        aResult += aSeq.toString();
    }

    aResult += "</dffrecord>";

    return aResult;
}

string DffRecord::getName() const
{
    return "";
}

Sprm::Kind DffRecord::getKind()
{
    return Sprm::UNKNOWN;
}

DffBlock::DffBlock(WW8Stream & rStream, sal_uInt32 nOffset,
                   sal_uInt32 nCount, sal_uInt32 nPadding)
: WW8StructBase(rStream, nOffset, nCount), bInitialized(false),
  mnPadding(nPadding)
{
}

DffBlock::DffBlock(WW8StructBase * pParent, sal_uInt32 nOffset,
                   sal_uInt32 nCount, sal_uInt32 nPadding)
: WW8StructBase(pParent, nOffset, nCount), bInitialized(false),
  mnPadding(nPadding)
{
}

DffBlock::DffBlock(const DffBlock & rSrc)
: WW8StructBase(rSrc), writerfilter::Reference<Properties>(rSrc),
  bInitialized(false), mnPadding(rSrc.mnPadding)
{
}

void DffBlock::initChildren()
{
    sal_uInt32 nOffset = 0;
    sal_uInt32 nCount = getCount();

    while (nOffset < nCount)
    {
        sal_uInt32 nSize = 0;
        DffRecord::Pointer_t pDffRecord
            (createDffRecord(this, nOffset, &nSize));

        if (nSize == 0)
            break;

        mRecords.push_back(pDffRecord);

        nOffset +=  nSize + mnPadding;
    }

    bInitialized = true;
}

Records_t DffBlock::findRecords(sal_uInt32 nType, bool bRecursive, bool bAny)
{
    Records_t aResult;

    findRecords(nType, aResult, bRecursive, bAny);

    return aResult;
}

void DffBlock::findRecords
(sal_uInt32 nType, Records_t & rRecords, bool bRecursive, bool bAny)
{
    Records_t::iterator aIt = begin();

    while (aIt != end())
    {
        DffRecord::Pointer_t pPointer(*aIt);

        if (bAny || pPointer->getRecordType() == nType)
            rRecords.push_back(pPointer);

        if (bRecursive)
            pPointer->findRecords(nType, rRecords, bRecursive,
                                  bAny);

        ++aIt;
    }
}

void DffBlock::resolve(Properties & rHandler)
{
    Records_t::iterator aIt;

    for (aIt = begin(); aIt != end(); ++aIt)
    {
        DffRecord * pDff = aIt->get();
        rHandler.sprm(*pDff);
    }
}

DffRecord::Pointer_t DffBlock::getShape(sal_uInt32 nSpid)
{
    DffRecord::Pointer_t pResult;

    Records_t aRecords = findRecords(0xf004);
    Records_t::iterator aIt;
    for (aIt = aRecords.begin(); aIt != aRecords.end(); ++aIt)
    {
        DffRecord::Pointer_t pPointer = *aIt;

        Records_t aFSPs = pPointer->findRecords(0xf00a);
        Records_t::iterator aItFSP = aFSPs.begin();

        if (aItFSP != aFSPs.end())
        {
            DffFSP * pFSP = dynamic_cast<DffFSP *>((*aItFSP).get());

            if (pFSP->get_shpid() == nSpid)
            {
                pResult = pPointer;

                break;
            }
        }
    }

    return pResult;
}

DffRecord::Pointer_t DffBlock::getBlip(sal_uInt32 nBlip)
{
    DffRecord::Pointer_t pResult;

    if (nBlip > 0)
    {
        nBlip--;

        Records_t aRecords = findRecords(0xf007);

        if (nBlip < aRecords.size())
        {
            pResult = aRecords[nBlip];
        }
    }

    return pResult;
}

Records_t::iterator DffBlock::begin()
{
    if (! bInitialized)
        initChildren();

    return mRecords.begin();
}

Records_t::iterator DffBlock::end()
{
    if (! bInitialized)
        initChildren();

    return mRecords.end();
}

string DffBlock::getType() const
{
    return "DffBlock";
}

}}
<commit_msg>INTEGRATION: CWS hr51 (1.12.12); FILE MERGED 2008/06/06 14:12:15 hr 1.12.12.1: #i88947#: includes<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: Dff.cxx,v $
 * $Revision: 1.13 $
 *
 * 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.
 *
 ************************************************************************/

#include <stdio.h>
#include "Dff.hxx"
#include <doctok/resourceids.hxx>
#include <resourcemodel/WW8ResourceModel.hxx>
#include "resources.hxx"

namespace writerfilter {
namespace doctok {

typedef boost::shared_ptr<WW8Value> WW8ValueSharedPointer_t;

DffRecord::DffRecord(WW8Stream & rStream, sal_uInt32 nOffset,
                     sal_uInt32 nCount)
: WW8StructBase(rStream, nOffset, nCount), bInitialized(false)
{
}

DffRecord::DffRecord(WW8StructBase * pParent, sal_uInt32 nOffset,
                     sal_uInt32 nCount)
: WW8StructBase(pParent, nOffset, nCount), bInitialized(false)
{
}

Records_t::iterator DffRecord::begin()
{
    if (! bInitialized)
        initChildren();

    return mRecords.begin();
}

Records_t::iterator DffRecord::end()
{
    if (! bInitialized)
        initChildren();

    return mRecords.end();
}

bool DffRecord::isContainer() const
{
    return getVersion() == 0xf;
}

sal_uInt32 DffRecord::calcSize() const
{
    sal_uInt32 nResult = 0;

    switch (getRecordType())
    {
    case 0xf000:
    case 0xf001:
    case 0xf002:
    case 0xf003:
    case 0xf004:
        nResult = getU32(0x4) + 8;

        break;
    case 0xf700:
        nResult = 8;

        break;
    default:
        nResult = getU32(0x4);

        if (! isContainer())
            nResult += 8;
        break;
    }

    return nResult;
}

sal_uInt32 DffRecord::getVersion() const
{
    return getU8(0x0) & 0xf;
}

sal_uInt32 DffRecord::getInstance() const
{
    return (getU16(0x0) & 0xfff0) >> 4;
}

sal_uInt32 DffRecord::getRecordType() const
{
    return getU16(0x2);
}

void DffRecord::initChildren()
{
    if (isContainer())
    {
        sal_uInt32 nOffset = 8;
        sal_uInt32 nCount = calcSize();

        while (nCount - nOffset >= 8)
        {
            sal_uInt32 nSize = 0;
            boost::shared_ptr<DffRecord> pRec
                (createDffRecord(this, nOffset, &nSize));

            if (nSize == 0)
                break;

            mRecords.push_back(pRec);

            nOffset += nSize;
        }
    }

    bInitialized = true;
}

Records_t DffRecord::findRecords(sal_uInt32 nType, bool bRecursive, bool bAny)
{
    Records_t aResult;

    findRecords(nType, aResult, bRecursive, bAny);

    return aResult;
}

void DffRecord::findRecords
(sal_uInt32 nType, Records_t & rRecords, bool bRecursive, bool bAny)
{
    Records_t::iterator aIt = begin();

    while (aIt != end())
    {
        Pointer_t pPointer = *aIt;
        if (bAny || pPointer->getRecordType() == nType)
            rRecords.push_back(pPointer);

        if (bRecursive)
            pPointer->findRecords(nType, rRecords, bRecursive,
                                      bAny);

        ++aIt;
    }
}

void DffRecord::resolveChildren(Properties & rHandler)
{
    Records_t::iterator aIt;
    for (aIt = begin(); aIt != end(); ++aIt)
    {
        rHandler.sprm(**aIt);
    }
}

void DffRecord::resolveLocal(Properties &)
{
}

void DffRecord::resolve(Properties & rHandler)
{
    WW8Value::Pointer_t pVal = createValue(getRecordType());
    rHandler.attribute(NS_rtf::LN_dfftype, *pVal);

    pVal = createValue(getInstance());
    rHandler.attribute(NS_rtf::LN_dffinstance, *pVal);

    pVal = createValue(getVersion());
    rHandler.attribute(NS_rtf::LN_dffversion, *pVal);

    pVal = createValue(getU32(0x0));
    rHandler.attribute(NS_rtf::LN_dffheader, *pVal);

    if (isContainer())
    {
        resolveChildren(rHandler);
    }

    resolveLocal(rHandler);

#if 1
    WW8BinaryObjReference::Pointer_t pBinObjRef
        (new WW8BinaryObjReference(this, 0, getCount()));
    WW8Sprm aSprm(pBinObjRef);

    rHandler.sprm(aSprm);
#endif
}

sal_uInt32 DffRecord::getShapeType()
{
    sal_uInt32 nResult = 0;

    Records_t aRecords = findRecords(0xf00a);

    if (aRecords.size() > 0)
    {
        DffFSP * pDffFSP = dynamic_cast<DffFSP*>((*aRecords.begin()).get());
        nResult = pDffFSP->get_shptype();
    }

    return nResult;
}

sal_uInt32 DffRecord::getShapeId()
{
    sal_uInt32 nResult = 0;

    Records_t aRecords = findRecords(0xf00a);

    if (aRecords.size() > 0)
    {
        DffFSP * pDffFSP = dynamic_cast<DffFSP*>((*aRecords.begin()).get());
        nResult = pDffFSP->get_shpid();
    }

    return nResult;
}

class DffOPTHandler : public Properties
{
    map<int, WW8ValueSharedPointer_t> mMap;
    int nId;

public:
    DffOPTHandler() : nId(0) {}
    virtual ~DffOPTHandler() {}

    virtual void attribute(Id name, Value & val)
    {
        switch (name)
        {
        case NS_rtf::LN_shppid:
            nId = val.getInt();
            break;
        case NS_rtf::LN_shpvalue:
            {
                WW8Value & rTmpVal = dynamic_cast<WW8Value &>(val);
                WW8ValueSharedPointer_t
                    pVal(dynamic_cast<WW8Value *>(rTmpVal.clone()));
                mMap[nId] = pVal;
            }
        }
    }

    virtual void sprm(Sprm & /*sprm_*/)
    {
    }

    WW8ValueSharedPointer_t & getValue(int nId_)
    {
        return mMap[nId_];
    }

};

sal_uInt32 DffRecord::getShapeBid()
{
    sal_uInt32 nResult = 0;

    if (getShapeType() == 75)
    {
        Records_t aRecords = findRecords(0xf00b);

        if (aRecords.size() > 0)
        {
            DffOPTHandler aHandler;
            DffOPT * pOpts = dynamic_cast<DffOPT*>((*aRecords.begin()).get());

            sal_uInt32 nCount = pOpts->get_property_count();

            for (sal_uInt32 n = 0; n < nCount; ++n)
            {
                pOpts->get_property(n)->resolve(aHandler);
            }

            WW8ValueSharedPointer_t pVal = aHandler.getValue(260);

            if (pVal.get() != NULL)
                nResult = pVal->getInt();
        }
    }

    return nResult;
}

string DffRecord::getType() const
{
    return "DffRecord";
}

Value::Pointer_t DffRecord::getValue()
{
    return Value::Pointer_t();
}

writerfilter::Reference<BinaryObj>::Pointer_t DffRecord::getBinary()
{
    return writerfilter::Reference<BinaryObj>::Pointer_t();
}

writerfilter::Reference<Stream>::Pointer_t DffRecord::getStream()
{
    return writerfilter::Reference<Stream>::Pointer_t();
}

writerfilter::Reference<Properties>::Pointer_t DffRecord::getProps()
{
    return writerfilter::Reference<Properties>::Pointer_t(this->clone());
}

string DffRecord::toString() const
{
    char sBuffer[1024];

    snprintf(sBuffer, sizeof(sBuffer),
             "<dffrecord type=\"%" SAL_PRIuUINT32 "\" instance=\"%" SAL_PRIuUINT32 "\" version=\"%" SAL_PRIuUINT32 "\">\n",
             getRecordType(), getInstance(), getVersion());
    string aResult = sBuffer;

    if (!isContainer())
        aResult += mSequence.toString();
    else
    {
        WW8StructBase::Sequence aSeq(mSequence, 0, 8);
        aResult += aSeq.toString();
    }

    aResult += "</dffrecord>";

    return aResult;
}

string DffRecord::getName() const
{
    return "";
}

Sprm::Kind DffRecord::getKind()
{
    return Sprm::UNKNOWN;
}

DffBlock::DffBlock(WW8Stream & rStream, sal_uInt32 nOffset,
                   sal_uInt32 nCount, sal_uInt32 nPadding)
: WW8StructBase(rStream, nOffset, nCount), bInitialized(false),
  mnPadding(nPadding)
{
}

DffBlock::DffBlock(WW8StructBase * pParent, sal_uInt32 nOffset,
                   sal_uInt32 nCount, sal_uInt32 nPadding)
: WW8StructBase(pParent, nOffset, nCount), bInitialized(false),
  mnPadding(nPadding)
{
}

DffBlock::DffBlock(const DffBlock & rSrc)
: WW8StructBase(rSrc), writerfilter::Reference<Properties>(rSrc),
  bInitialized(false), mnPadding(rSrc.mnPadding)
{
}

void DffBlock::initChildren()
{
    sal_uInt32 nOffset = 0;
    sal_uInt32 nCount = getCount();

    while (nOffset < nCount)
    {
        sal_uInt32 nSize = 0;
        DffRecord::Pointer_t pDffRecord
            (createDffRecord(this, nOffset, &nSize));

        if (nSize == 0)
            break;

        mRecords.push_back(pDffRecord);

        nOffset +=  nSize + mnPadding;
    }

    bInitialized = true;
}

Records_t DffBlock::findRecords(sal_uInt32 nType, bool bRecursive, bool bAny)
{
    Records_t aResult;

    findRecords(nType, aResult, bRecursive, bAny);

    return aResult;
}

void DffBlock::findRecords
(sal_uInt32 nType, Records_t & rRecords, bool bRecursive, bool bAny)
{
    Records_t::iterator aIt = begin();

    while (aIt != end())
    {
        DffRecord::Pointer_t pPointer(*aIt);

        if (bAny || pPointer->getRecordType() == nType)
            rRecords.push_back(pPointer);

        if (bRecursive)
            pPointer->findRecords(nType, rRecords, bRecursive,
                                  bAny);

        ++aIt;
    }
}

void DffBlock::resolve(Properties & rHandler)
{
    Records_t::iterator aIt;

    for (aIt = begin(); aIt != end(); ++aIt)
    {
        DffRecord * pDff = aIt->get();
        rHandler.sprm(*pDff);
    }
}

DffRecord::Pointer_t DffBlock::getShape(sal_uInt32 nSpid)
{
    DffRecord::Pointer_t pResult;

    Records_t aRecords = findRecords(0xf004);
    Records_t::iterator aIt;
    for (aIt = aRecords.begin(); aIt != aRecords.end(); ++aIt)
    {
        DffRecord::Pointer_t pPointer = *aIt;

        Records_t aFSPs = pPointer->findRecords(0xf00a);
        Records_t::iterator aItFSP = aFSPs.begin();

        if (aItFSP != aFSPs.end())
        {
            DffFSP * pFSP = dynamic_cast<DffFSP *>((*aItFSP).get());

            if (pFSP->get_shpid() == nSpid)
            {
                pResult = pPointer;

                break;
            }
        }
    }

    return pResult;
}

DffRecord::Pointer_t DffBlock::getBlip(sal_uInt32 nBlip)
{
    DffRecord::Pointer_t pResult;

    if (nBlip > 0)
    {
        nBlip--;

        Records_t aRecords = findRecords(0xf007);

        if (nBlip < aRecords.size())
        {
            pResult = aRecords[nBlip];
        }
    }

    return pResult;
}

Records_t::iterator DffBlock::begin()
{
    if (! bInitialized)
        initChildren();

    return mRecords.begin();
}

Records_t::iterator DffBlock::end()
{
    if (! bInitialized)
        initChildren();

    return mRecords.end();
}

string DffBlock::getType() const
{
    return "DffBlock";
}

}}
<|endoftext|>


<commit_before><commit_msg>Fix in backward time of the visualizer<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#include <hspp/Tasks/SimpleTasks/ControlTask.hpp>
#include <hspp/Tasks/SimpleTasks/IncludeTask.hpp>

namespace Hearthstonepp::SimpleTasks
{
ControlTask::ControlTask(EntityType entityType) : ITask(entityType)
{
    // Do nothing
}

TaskID ControlTask::GetTaskID() const
{
    return TaskID::CONTROL;
}

MetaData ControlTask::Impl(Player& player)
{
    auto entities = IncludeTask::GetEntities(m_entityType, player, m_target);
    auto& myField = player.GetField();
    auto& opField = player.GetOpponent().GetField();

    if (myField.GetNumOfMinions() == FIELD_SIZE)
    {
        return MetaData::CONTROL_FIELD_IS_FULL;
    }

    for (auto& entity : entities)
    {
        auto fieldIter = std::find(opField.begin(), opField.end(), entity);
        if (fieldIter == opField.end())
        {
            return MetaData::CONTROL_INVALID_TARGET;
        }

        myField.emplace_back(*fieldIter);
        opField.erase(fieldIter);
    }

    return MetaData::CONTROL_SUCCESS;
}
}  // namespace Hearthstonepp::SimpleTasks
<commit_msg>[ci skip] refactor: Apply changes of Battlefield::AddMinion() method<commit_after>// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#include <hspp/Tasks/SimpleTasks/ControlTask.hpp>
#include <hspp/Tasks/SimpleTasks/IncludeTask.hpp>

namespace Hearthstonepp::SimpleTasks
{
ControlTask::ControlTask(EntityType entityType) : ITask(entityType)
{
    // Do nothing
}

TaskID ControlTask::GetTaskID() const
{
    return TaskID::CONTROL;
}

MetaData ControlTask::Impl(Player& player)
{
    auto entities = IncludeTask::GetEntities(m_entityType, player, m_target);
    auto& myField = player.GetField();
    auto& opField = player.GetOpponent().GetField();

    if (myField.GetNumOfMinions() == FIELD_SIZE)
    {
        return MetaData::CONTROL_FIELD_IS_FULL;
    }

    for (auto& entity : entities)
    {
        const auto minion = dynamic_cast<Minion*>(entity);
        if (minion == nullptr)
        {
            continue;
        }

        auto minionPos = opField.FindMinionPos(*minion);
        if (!minionPos.has_value())
        {
            continue;
        }

        myField.AddMinion(*minion, minionPos.value());
        opField.RemoveMinion(*minion);
    }

    return MetaData::CONTROL_SUCCESS;
}
}  // namespace Hearthstonepp::SimpleTasks
<|endoftext|>


<commit_before>/* mbed Microcontroller Library
 * Copyright (c) 2017 ARM Limited
 *
 * 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.
 */

#if !DEVICE_FLASH
    #error [NOT_SUPPORTED] Flash API not supported for this target
#endif

#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"

#include "mbed.h"
#include "flash_api.h"

using namespace utest::v1;

#define TEST_CYCLES         1000000
#define ALLOWED_DRIFT_PPM   1000         //0.1%

/*
    return values to be checked are documented at:
        http://arm-software.github.io/CMSIS_5/Pack/html/algorithmFunc.html#Verify
*/

#ifndef ALIGN_DOWN
#define ALIGN_DOWN(x, a) ((x)& ~((a) - 1))
#endif

static int timer_diff_start;

static void erase_range(flash_t *flash, uint32_t addr, uint32_t size)
{
    while (size > 0) {
        uint32_t sector_size = flash_get_sector_size(flash, addr);
        TEST_ASSERT_NOT_EQUAL(0, sector_size);
        int32_t ret = flash_erase_sector(flash, addr);
        TEST_ASSERT_EQUAL_INT32(0, ret);
        addr += sector_size;
        size = size > sector_size ? size - sector_size : 0;
    }
}

__attribute__((noinline)) static int time_cpu_cycles(uint32_t cycles)
{
    Timer timer;
    timer.start();

    int timer_start = timer.read_us();

    volatile uint32_t delay = (volatile uint32_t)cycles;
    while (delay--);

    int timer_end = timer.read_us();

    timer.stop();
    return timer_end - timer_start;
}

void flash_init_test()
{
    timer_diff_start = time_cpu_cycles(TEST_CYCLES);

    flash_t test_flash;
    int32_t ret = flash_init(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);
    ret = flash_free(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);
}

void flash_mapping_alignment_test()
{
    flash_t test_flash;
    int32_t ret = flash_init(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);

    const uint32_t page_size = flash_get_page_size(&test_flash);
    const uint32_t flash_start = flash_get_start_address(&test_flash);
    const uint32_t flash_size = flash_get_size(&test_flash);
    TEST_ASSERT_TRUE(page_size != 0UL);

    uint32_t sector_size = flash_get_sector_size(&test_flash, flash_start);
    for (uint32_t offset = 0; offset < flash_size;  offset += sector_size) {
        const uint32_t sector_start = flash_start + offset;
        sector_size = flash_get_sector_size(&test_flash, sector_start);
        const uint32_t sector_end = sector_start + sector_size - 1;
        const uint32_t end_sector_size = flash_get_sector_size(&test_flash, sector_end);

        // Sector size must be a valid value
        TEST_ASSERT_NOT_EQUAL(MBED_FLASH_INVALID_SIZE, sector_size);
        // Sector size must be greater than zero
        TEST_ASSERT_NOT_EQUAL(0, sector_size);
        // All flash sectors must be a multiple of page size
        TEST_ASSERT_EQUAL(0, sector_size % page_size);
        // Sector address must be a multiple of sector size
        TEST_ASSERT_EQUAL(0, sector_start % sector_size);
        // All address in a sector must return the same sector size
        TEST_ASSERT_EQUAL(sector_size, end_sector_size);

    }

    // Make sure unmapped flash is reported correctly
    TEST_ASSERT_EQUAL(MBED_FLASH_INVALID_SIZE, flash_get_sector_size(&test_flash, flash_start - 1));
    TEST_ASSERT_EQUAL(MBED_FLASH_INVALID_SIZE, flash_get_sector_size(&test_flash, flash_start + flash_size));

    ret = flash_free(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);
}

void flash_erase_sector_test()
{
    flash_t test_flash;
    int32_t ret = flash_init(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);

    uint32_t addr_after_last = flash_get_start_address(&test_flash) + flash_get_size(&test_flash);
    uint32_t last_sector_size = flash_get_sector_size(&test_flash, addr_after_last - 1);
    uint32_t last_sector = addr_after_last - last_sector_size;
    TEST_ASSERT_EQUAL_INT32(0, last_sector % last_sector_size);
    ret = flash_erase_sector(&test_flash, last_sector);
    TEST_ASSERT_EQUAL_INT32(0, ret);

    ret = flash_free(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);
}

// Erase sector, write one page, erase sector and write new data
void flash_program_page_test()
{
    flash_t test_flash;
    int32_t ret = flash_init(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);

    uint32_t test_size = flash_get_page_size(&test_flash);
    uint8_t *data = new uint8_t[test_size];
    for (uint32_t i = 0; i < test_size; i++) {
        data[i] = 0xCE;
    }

    // the one before the last page in the system
    uint32_t address = flash_get_start_address(&test_flash) + flash_get_size(&test_flash) - (2*test_size);

    // sector size might not be same as page size
    uint32_t erase_sector_boundary = ALIGN_DOWN(address, flash_get_sector_size(&test_flash, address));
    ret = flash_erase_sector(&test_flash, erase_sector_boundary);
    TEST_ASSERT_EQUAL_INT32(0, ret);

    ret = flash_program_page(&test_flash, address, data, test_size);
    TEST_ASSERT_EQUAL_INT32(0, ret);
    uint8_t *data_flashed = (uint8_t *)address;
    TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, test_size);

    // sector size might not be same as page size
    erase_sector_boundary = ALIGN_DOWN(address, flash_get_sector_size(&test_flash, address));
    ret = flash_erase_sector(&test_flash, erase_sector_boundary);
    TEST_ASSERT_EQUAL_INT32(0, ret);

    // write another data to be certain we are re-flashing
    for (uint32_t i = 0; i < test_size; i++) {
        data[i] = 0xAC;
    }
    ret = flash_program_page(&test_flash, address, data, test_size);
    TEST_ASSERT_EQUAL_INT32(0, ret);
    TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, test_size);

    ret = flash_free(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);
    delete[] data;
}

// make sure programming works with an unaligned data buffer
void flash_buffer_alignment_test()
{
    flash_t test_flash;
    int32_t ret = flash_init(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);

    const uint32_t page_size = flash_get_page_size(&test_flash);
    const uint32_t buf_size = page_size + 4;
    uint8_t *data = new uint8_t[buf_size];
    for (uint32_t i = 0; i < buf_size; i++) {
        data[i] = i & 0xFF;
    }

    // use the last four pages for the alignment test
    const uint32_t flash_end = flash_get_start_address(&test_flash) + flash_get_size(&test_flash);
    const uint32_t test_addr = flash_end - page_size * 4;
    const uint32_t erase_sector_boundary = ALIGN_DOWN(test_addr, flash_get_sector_size(&test_flash, test_addr));
    erase_range(&test_flash, erase_sector_boundary, flash_end - erase_sector_boundary);

    // make sure page program works with an unaligned data buffer
    for (uint32_t i = 0; i < 4; i++) {
        const uint32_t addr = test_addr + i * page_size;
        ret = flash_program_page(&test_flash, addr, data + i, page_size);
        TEST_ASSERT_EQUAL_INT32(0, ret);
        uint8_t *data_flashed = (uint8_t *)addr;
        TEST_ASSERT_EQUAL_UINT8_ARRAY(data + i, data_flashed, page_size);
    }

    ret = flash_free(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);
    delete[] data;
}

// check the execution speed at the start and end of the test to make sure
// cache settings weren't changed
void flash_clock_and_cache_test()
{
    const int timer_diff_end = time_cpu_cycles(TEST_CYCLES);
    const int acceptable_range = timer_diff_start / (1000000 / ALLOWED_DRIFT_PPM);
    TEST_ASSERT_UINT32_WITHIN(acceptable_range, timer_diff_start, timer_diff_end);
}

Case cases[] = {
    Case("Flash - init", flash_init_test),
    Case("Flash - mapping alignment", flash_mapping_alignment_test),
    Case("Flash - erase sector", flash_erase_sector_test),
    Case("Flash - program page", flash_program_page_test),
    Case("Flash - buffer alignment test", flash_buffer_alignment_test),
    Case("Flash - clock and cache test", flash_clock_and_cache_test),
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
    GREENTEA_SETUP(20, "default_auto");
    return greentea_test_setup_handler(number_of_cases);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);

int main() {
    Harness::run(specification);
}
<commit_msg>Assembly based loop for timing test<commit_after>/* mbed Microcontroller Library
 * Copyright (c) 2017 ARM Limited
 *
 * 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.
 */

#if !DEVICE_FLASH
    #error [NOT_SUPPORTED] Flash API not supported for this target
#endif

#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"

#include "mbed.h"
#include "flash_api.h"

using namespace utest::v1;

#define TEST_CYCLES         1000000
#define ALLOWED_DRIFT_PPM   1000         //0.1%

/*
    return values to be checked are documented at:
        http://arm-software.github.io/CMSIS_5/Pack/html/algorithmFunc.html#Verify
*/

#ifndef ALIGN_DOWN
#define ALIGN_DOWN(x, a) ((x)& ~((a) - 1))
#endif

static int timer_diff_start;

static void erase_range(flash_t *flash, uint32_t addr, uint32_t size)
{
    while (size > 0) {
        uint32_t sector_size = flash_get_sector_size(flash, addr);
        TEST_ASSERT_NOT_EQUAL(0, sector_size);
        int32_t ret = flash_erase_sector(flash, addr);
        TEST_ASSERT_EQUAL_INT32(0, ret);
        addr += sector_size;
        size = size > sector_size ? size - sector_size : 0;
    }
}
#ifdef __CC_ARM
MBED_NOINLINE
__asm static void delay_loop(uint32_t count)
{
1
  SUBS a1, a1, #1
  BCS  %BT1
  BX   lr
}
#elif defined (__ICCARM__)
MBED_NOINLINE
static void delay_loop(uint32_t count)
{
  __asm volatile(
    "loop: \n"
    " SUBS %0, %0, #1 \n"
    " BCS.n  loop\n"
    : "+r" (count)
    :
    : "cc"
  );
}
#else // GCC
MBED_NOINLINE
static void delay_loop(uint32_t count)
{
  __asm__ volatile (
    "%=:\n\t"
#if defined(__thumb__) && !defined(__thumb2__)
    "SUB  %0, #1\n\t"
#else
    "SUBS %0, %0, #1\n\t"
#endif
    "BCS  %=b\n\t"
    : "+l" (count)
    :
    : "cc"
  );
}
#endif

MBED_NOINLINE
static int time_cpu_cycles(uint32_t cycles)
{
    Timer timer;
    timer.start();

    int timer_start = timer.read_us();

    volatile uint32_t delay = (volatile uint32_t)cycles;
	delay_loop(delay);
    int timer_end = timer.read_us();

    timer.stop();
    return timer_end - timer_start;
}

void flash_init_test()
{
    timer_diff_start = time_cpu_cycles(TEST_CYCLES);

    flash_t test_flash;
    int32_t ret = flash_init(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);
    ret = flash_free(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);
}

void flash_mapping_alignment_test()
{
    flash_t test_flash;
    int32_t ret = flash_init(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);

    const uint32_t page_size = flash_get_page_size(&test_flash);
    const uint32_t flash_start = flash_get_start_address(&test_flash);
    const uint32_t flash_size = flash_get_size(&test_flash);
    TEST_ASSERT_TRUE(page_size != 0UL);

    uint32_t sector_size = flash_get_sector_size(&test_flash, flash_start);
    for (uint32_t offset = 0; offset < flash_size;  offset += sector_size) {
        const uint32_t sector_start = flash_start + offset;
        sector_size = flash_get_sector_size(&test_flash, sector_start);
        const uint32_t sector_end = sector_start + sector_size - 1;
        const uint32_t end_sector_size = flash_get_sector_size(&test_flash, sector_end);

        // Sector size must be a valid value
        TEST_ASSERT_NOT_EQUAL(MBED_FLASH_INVALID_SIZE, sector_size);
        // Sector size must be greater than zero
        TEST_ASSERT_NOT_EQUAL(0, sector_size);
        // All flash sectors must be a multiple of page size
        TEST_ASSERT_EQUAL(0, sector_size % page_size);
        // Sector address must be a multiple of sector size
        TEST_ASSERT_EQUAL(0, sector_start % sector_size);
        // All address in a sector must return the same sector size
        TEST_ASSERT_EQUAL(sector_size, end_sector_size);

    }

    // Make sure unmapped flash is reported correctly
    TEST_ASSERT_EQUAL(MBED_FLASH_INVALID_SIZE, flash_get_sector_size(&test_flash, flash_start - 1));
    TEST_ASSERT_EQUAL(MBED_FLASH_INVALID_SIZE, flash_get_sector_size(&test_flash, flash_start + flash_size));

    ret = flash_free(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);
}

void flash_erase_sector_test()
{
    flash_t test_flash;
    int32_t ret = flash_init(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);

    uint32_t addr_after_last = flash_get_start_address(&test_flash) + flash_get_size(&test_flash);
    uint32_t last_sector_size = flash_get_sector_size(&test_flash, addr_after_last - 1);
    uint32_t last_sector = addr_after_last - last_sector_size;
    TEST_ASSERT_EQUAL_INT32(0, last_sector % last_sector_size);
    ret = flash_erase_sector(&test_flash, last_sector);
    TEST_ASSERT_EQUAL_INT32(0, ret);

    ret = flash_free(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);
}

// Erase sector, write one page, erase sector and write new data
void flash_program_page_test()
{
    flash_t test_flash;
    int32_t ret = flash_init(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);

    uint32_t test_size = flash_get_page_size(&test_flash);
    uint8_t *data = new uint8_t[test_size];
    for (uint32_t i = 0; i < test_size; i++) {
        data[i] = 0xCE;
    }

    // the one before the last page in the system
    uint32_t address = flash_get_start_address(&test_flash) + flash_get_size(&test_flash) - (2*test_size);

    // sector size might not be same as page size
    uint32_t erase_sector_boundary = ALIGN_DOWN(address, flash_get_sector_size(&test_flash, address));
    ret = flash_erase_sector(&test_flash, erase_sector_boundary);
    TEST_ASSERT_EQUAL_INT32(0, ret);

    ret = flash_program_page(&test_flash, address, data, test_size);
    TEST_ASSERT_EQUAL_INT32(0, ret);
    uint8_t *data_flashed = (uint8_t *)address;
    TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, test_size);

    // sector size might not be same as page size
    erase_sector_boundary = ALIGN_DOWN(address, flash_get_sector_size(&test_flash, address));
    ret = flash_erase_sector(&test_flash, erase_sector_boundary);
    TEST_ASSERT_EQUAL_INT32(0, ret);

    // write another data to be certain we are re-flashing
    for (uint32_t i = 0; i < test_size; i++) {
        data[i] = 0xAC;
    }
    ret = flash_program_page(&test_flash, address, data, test_size);
    TEST_ASSERT_EQUAL_INT32(0, ret);
    TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, test_size);

    ret = flash_free(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);
    delete[] data;
}

// make sure programming works with an unaligned data buffer
void flash_buffer_alignment_test()
{
    flash_t test_flash;
    int32_t ret = flash_init(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);

    const uint32_t page_size = flash_get_page_size(&test_flash);
    const uint32_t buf_size = page_size + 4;
    uint8_t *data = new uint8_t[buf_size];
    for (uint32_t i = 0; i < buf_size; i++) {
        data[i] = i & 0xFF;
    }

    // use the last four pages for the alignment test
    const uint32_t flash_end = flash_get_start_address(&test_flash) + flash_get_size(&test_flash);
    const uint32_t test_addr = flash_end - page_size * 4;
    const uint32_t erase_sector_boundary = ALIGN_DOWN(test_addr, flash_get_sector_size(&test_flash, test_addr));
    erase_range(&test_flash, erase_sector_boundary, flash_end - erase_sector_boundary);

    // make sure page program works with an unaligned data buffer
    for (uint32_t i = 0; i < 4; i++) {
        const uint32_t addr = test_addr + i * page_size;
        ret = flash_program_page(&test_flash, addr, data + i, page_size);
        TEST_ASSERT_EQUAL_INT32(0, ret);
        uint8_t *data_flashed = (uint8_t *)addr;
        TEST_ASSERT_EQUAL_UINT8_ARRAY(data + i, data_flashed, page_size);
    }

    ret = flash_free(&test_flash);
    TEST_ASSERT_EQUAL_INT32(0, ret);
    delete[] data;
}

// check the execution speed at the start and end of the test to make sure
// cache settings weren't changed
void flash_clock_and_cache_test()
{
    const int timer_diff_end = time_cpu_cycles(TEST_CYCLES);
    const int acceptable_range = timer_diff_start / (1000000 / ALLOWED_DRIFT_PPM);
    TEST_ASSERT_UINT32_WITHIN(acceptable_range, timer_diff_start, timer_diff_end);
}

Case cases[] = {
    Case("Flash - init", flash_init_test),
    Case("Flash - mapping alignment", flash_mapping_alignment_test),
    Case("Flash - erase sector", flash_erase_sector_test),
    Case("Flash - program page", flash_program_page_test),
    Case("Flash - buffer alignment test", flash_buffer_alignment_test),
    Case("Flash - clock and cache test", flash_clock_and_cache_test),
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
    GREENTEA_SETUP(20, "default_auto");
    return greentea_test_setup_handler(number_of_cases);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);

int main() {
    Harness::run(specification);
}
<|endoftext|>


<commit_before>#include <utils/utils.h>
<commit_msg>Added a unit test for like_t.<commit_after>#include <utils/utils.h>

using namespace utils;

static_assert(std::is_same<like_t<const int &&, float>, const float &&>::value);
<|endoftext|>