<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2013-2016.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://www.opensource.org/licenses/MIT)
//=======================================================================

#ifndef EXPECTED_H
#define EXPECTED_H

#include "types.hpp"
#include "algorithms.hpp"
#include "type_traits.hpp"
#include "utility.hpp"
#include "memory.hpp"
#include "new.hpp"

namespace std {

constexpr struct only_set_valid_t {} only_set_valid;

template <typename E>
struct exceptional {
    typedef E error_type;

    error_type error;

    exceptional(): error() {
        //Nothing else to init
    }

    explicit exceptional(error_type e) : error(e) {
        //Nothing else to init
    }
};

template<typename T, typename E>
union trivial_expected_storage {
    typedef T value_type;
    typedef E error_type;

    error_type error;
    value_type value;

    constexpr trivial_expected_storage() : value(){
        //Nothing else to init
    }

    constexpr trivial_expected_storage(const exceptional<error_type>& e) : error(e.error){
        //Nothing else to init
    }

    template<typename... Args>
    constexpr trivial_expected_storage(Args&&... args): value(std::forward<Args>(args)...){
        //Nothing else to init
    }

    ~trivial_expected_storage() = default;
};

template<typename E>
union trivial_expected_storage <void, E> {
    typedef void value_type;
    typedef E error_type;

    error_type error;

    constexpr trivial_expected_storage() {
        //Nothing else to init
    }

    constexpr trivial_expected_storage(const exceptional<error_type>& e) : error(e.error){
        //Nothing else to init
    }

    ~trivial_expected_storage() = default;
};

template<typename T, typename E>
union non_trivial_expected_storage {
    typedef T value_type;
    typedef E error_type;

    error_type error;
    value_type value;

    constexpr non_trivial_expected_storage() : value(){
        //Nothing else to init
    }

    constexpr non_trivial_expected_storage(exceptional<error_type>& e) : error(e.error){
        //Nothing else to init
    }

    template<typename... Args>
    constexpr non_trivial_expected_storage(Args&&... args): value(std::forward<Args>(args)...){
        //Nothing else to init
    }

    ~non_trivial_expected_storage() {};
};

template<typename E>
union non_trivial_expected_storage <void, E> {
    typedef void value_type;
    typedef E error_type;

    error_type error;

    constexpr non_trivial_expected_storage(){
        //Nothing else to init
    }

    constexpr non_trivial_expected_storage(exceptional<error_type>& e) : error(e.error){
        //Nothing else to init
    }

    ~non_trivial_expected_storage() {};
};

template<typename T, typename E>
struct trivial_expected_base {
    typedef T value_type;
    typedef E error_type;

    bool has_value;
    trivial_expected_storage<T, E> storage;

    trivial_expected_base() : has_value(true), storage(){
        //Nothing else to init
    }

    trivial_expected_base(only_set_valid_t, bool hv) : has_value(hv){
        //Nothing else to init
    }

    trivial_expected_base(const value_type& v) : has_value(true), storage(v){
        //Nothing else to init
    }

    trivial_expected_base(value_type&& v) : has_value(true), storage(std::forward<value_type>(v)){
        //Nothing else to init
    }

    trivial_expected_base(const exceptional<error_type>& e) : has_value(false), storage(e) {
        //Nothing else to init
    }

    ~trivial_expected_base() = default;
};

template<typename E>
struct trivial_expected_base <void, E> {
    typedef E error_type;

    bool has_value;
    trivial_expected_storage<void, E> storage;

    trivial_expected_base() : has_value(true), storage(){
        //Nothing else to init
    }

    trivial_expected_base(only_set_valid_t, bool hv) : has_value(hv){
        //Nothing else to init
    }

    trivial_expected_base(const exceptional<error_type>& e) : has_value(false), storage(e) {
        //Nothing else to init
    }

    ~trivial_expected_base() = default;
};

template<typename T, typename E>
struct non_trivial_expected_base {
    typedef T value_type;
    typedef E error_type;

    bool has_value;
    trivial_expected_storage<T, E> storage;

    non_trivial_expected_base() : has_value(true), storage(){
        //Nothing else to init
    }

    non_trivial_expected_base(only_set_valid_t, bool hv) : has_value(hv){
        //Nothing else to init
    }

    non_trivial_expected_base(const value_type& v) : has_value(true), storage(v){
        //Nothing else to init
    }

    non_trivial_expected_base(value_type&& v) : has_value(true), storage(std::forward<value_type>(v)){
        //Nothing else to init
    }

    non_trivial_expected_base(const exceptional<error_type>& e) : has_value(false), storage(e) {
        //Nothing else to init
    }

    ~non_trivial_expected_base(){
        if(has_value){
            storage.error.~value_type();
        } else {
            storage.error.~error_type();
        }
    }
};

template<typename E>
struct non_trivial_expected_base <void, E> {
    typedef E error_type;

    bool has_value;
    trivial_expected_storage<void, E> storage;

    non_trivial_expected_base() : has_value(true), storage(){
        //Nothing else to init
    }

    non_trivial_expected_base(only_set_valid_t, bool hv) : has_value(hv){
        //Nothing else to init
    }

    non_trivial_expected_base(const exceptional<error_type>& e) : has_value(false), storage(e) {
        //Nothing else to init
    }

    ~non_trivial_expected_base(){
        if(!has_value){
            storage.error.~error_type();
        }
    }
};

template <typename T, typename E>
using expected_base = typename std::conditional<
        std::is_trivially_destructible<T>::value && std::is_trivially_destructible<E>::value,
        trivial_expected_base<T, E>,
        non_trivial_expected_base<T, E>
    >::type;

template<typename T, typename E = size_t>
struct expected : expected_base<T, E> {
    typedef T value_type;
    typedef E error_type;

    typedef expected<T, E> this_type;
    typedef expected_base<T, E> base_type;

private:
    value_type* value_ptr() {
        return std::addressof(base_type::storage.value);
    }

    constexpr const value_type* value_ptr() const {
        return std::static_addressof(base_type::storage.value);
    }

    error_type* error_ptr() {
        return std::addressof(base_type::storage.error);
    }

    constexpr const error_type* error_ptr() const {
        return static_addressof(base_type::storage.error);
    }

    constexpr const bool& contained_has_value() const& {
        return base_type::has_value;
    }

    bool& contained_has_value() & {
        return base_type::has_value;
    }

    bool&& contained_has_value() && {
        return std::move(base_type::has_value);
    }

    constexpr const value_type& contained_value() const& {
        return base_type::storage.value;
    }

    value_type& contained_value() & {
        return base_type::storage.value;
    }

    value_type&& contained_value() && {
        return std::move(base_type::storage.value);
    }

    constexpr const error_type& contained_error() const& {
        return base_type::storage.error;
    }

    error_type& contained_error() & {
        return base_type::storage.error;
    }

    error_type&& contained_error() && {
        return std::move(base_type::storage.error);
    }

public:
    /* Constructors */

    constexpr expected(const value_type& v) : base_type(v){
        //Nothing else to init
    }

    constexpr expected(value_type&& v) : base_type(std::forward<value_type>(v)){
        //Nothing else to init
    }

    expected(const expected& rhs) : base_type(only_set_valid, rhs.valid()) {
        if(rhs.valid()){
            ::new (value_ptr()) value_type(rhs.contained_value());
        } else {
            ::new (error_ptr()) error_type(rhs.contained_error());
        }
    }

    expected(expected&& rhs) : base_type(only_set_valid, rhs.valid()) {
        if(rhs.valid()){
            new (value_ptr()) value_type(std::move(rhs.contained_value()));
        } else {
            new (error_ptr()) error_type(std::move(rhs.contained_error()));
        }
    }

    expected(const exceptional<error_type>& e) : base_type(e) {
        //Nothing else to init
    }

    expected() : base_type() {}

    ~expected() = default;

    /* Operators */
    expected& operator=(const expected& rhs){
        this_type(rhs).swap(*this);
        return *this;
    }

    expected& operator=(expected&& rhs){
        this_type(std::move(rhs)).swap(*this);
        return *this;
    }

    expected& operator=(const value_type& v){
        this_type(v).swap(*this);
        return *this;
    }

    expected& operator=(value_type&& v){
        this_type(std::move(v)).swap(*this);
        return *this;
    }

    /* Swap */

    void swap(expected& rhs){
        if (valid()){
            if (rhs.valid()){
                std::swap(contained_value(), rhs.contained_value());
            } else {
                error_type t = std::move(rhs.contained_error());
                new (rhs.value_ptr()) value_type(std::move(contained_value()));
                new (error_ptr()) error_type(t);
                std::swap(contained_has_value(), rhs.contained_has_value());
            }
        } else {
            if (rhs.valid()){
                rhs.swap(*this);
            } else {
                std::swap(contained_error(), rhs.contained_error());
            }
        }
    }

    /* Accessors */

    constexpr bool valid() const {
        return contained_has_value();
    }

    constexpr explicit operator bool() const {
        return valid();
    }

    constexpr const value_type& value() const {
        return contained_value();
    }

    constexpr const value_type&  operator*() const {
        return contained_value();
    }

    value_type& operator*(){
        return contained_value();
    }

    constexpr const value_type* operator->() const {
        return value_ptr();
    }

    value_type* operator->(){
        return value_ptr();
    }

    constexpr const error_type& error() const {
        return contained_error();
    }

    constexpr bool has_error(const error_type& e) const {
        return contained_error() == e;
    }

    constexpr exceptional<error_type> get_exceptional() const {
        return exceptional<error_type>(contained_error());
    }
};

template<typename E>
struct expected <void, E> : expected_base<void, E> {
    typedef void value_type;
    typedef E error_type;

    typedef expected<void, E> this_type;
    typedef expected_base<void, E> base_type;

private:
    error_type* error_ptr() {
        return std::addressof(base_type::storage.error);
    }

    constexpr const error_type* error_ptr() const {
        return static_addressof(base_type::storage.error);
    }

    constexpr const bool& contained_has_value() const& {
        return base_type::has_value;
    }

    bool& contained_has_value() & {
        return base_type::has_value;
    }

    bool&& contained_has_value() && {
        return std::move(base_type::has_value);
    }

    constexpr const error_type& contained_error() const& {
        return base_type::storage.error;
    }

    error_type& contained_error() & {
        return base_type::storage.error;
    }

    error_type&& contained_error() && {
        return std::move(base_type::storage.error);
    }

public:
    /* Constructors */

    expected(const expected& rhs) : base_type(only_set_valid, rhs.valid()) {
        if(!rhs.valid()){
            ::new (error_ptr()) error_type(rhs.contained_error());
        }
    }

    expected(expected&& rhs) : base_type(only_set_valid, rhs.valid()) {
        if(!rhs.valid()){
            new (error_ptr()) error_type(std::move(rhs.contained_error()));
        }
    }

    expected(const exceptional<error_type>& e) : base_type(e) {
        //Nothing else to init
    }

    expected() : base_type() {}

    ~expected() = default;

    /* Operators */
    expected& operator=(const expected& rhs){
        this_type(rhs).swap(*this);
        return *this;
    }

    expected& operator=(expected&& rhs){
        this_type(std::move(rhs)).swap(*this);
        return *this;
    }

    /* Swap */

    void swap(expected& rhs){
        if (valid()){
            if (!rhs.valid()){
                error_type t = std::move(rhs.contained_error());
                new (error_ptr()) error_type(t);
            }
        } else {
            if (!rhs.valid()){
                std::swap(contained_error(), rhs.contained_error());
            }
        }
    }

    /* Accessors */

    constexpr bool valid() const {
        return contained_has_value();
    }

    constexpr explicit operator bool() const {
        return valid();
    }

    constexpr const error_type& error() const {
        return contained_error();
    }

    constexpr bool has_error(const error_type& e) const {
        return contained_error() == e;
    }

    constexpr exceptional<error_type> get_exceptional() const {
        return exceptional<error_type>(contained_error());
    }
};

template<typename T>
inline expected<T> make_expected(T&& v){
    return expected<T>(std::forward<T>(v));
}

template<typename T>
inline expected<T> make_expected(const T& v){
    return expected<T>(v);
}

template<typename T, typename U, typename E>
inline expected<T, U> make_expected_from_error(E v){
    return expected<T, U>(exceptional<U>(v));
}

template<typename T, typename E>
inline expected<T, E> make_expected_from_error(E v){
    return expected<T, E>(exceptional<E>(v));
}

inline expected<void> make_expected(){
    return expected<void>();
}

// Make sure the size is maintained reasonable
static_assert(sizeof(expected<void>) == 2 * sizeof(size_t), "expected<void> should not have overhead");
static_assert(sizeof(expected<size_t>) == 2 * sizeof(size_t), "expected<void> should not have overhead");

} //end of namespace std

#endif
<commit_msg>Fix typo<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2013-2016.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://www.opensource.org/licenses/MIT)
//=======================================================================

#ifndef EXPECTED_H
#define EXPECTED_H

#include "types.hpp"
#include "algorithms.hpp"
#include "type_traits.hpp"
#include "utility.hpp"
#include "memory.hpp"
#include "new.hpp"

namespace std {

constexpr struct only_set_valid_t {} only_set_valid;

template <typename E>
struct exceptional {
    typedef E error_type;

    error_type error;

    exceptional(): error() {
        //Nothing else to init
    }

    explicit exceptional(error_type e) : error(e) {
        //Nothing else to init
    }
};

template<typename T, typename E>
union trivial_expected_storage {
    typedef T value_type;
    typedef E error_type;

    error_type error;
    value_type value;

    constexpr trivial_expected_storage() : value(){
        //Nothing else to init
    }

    constexpr trivial_expected_storage(const exceptional<error_type>& e) : error(e.error){
        //Nothing else to init
    }

    template<typename... Args>
    constexpr trivial_expected_storage(Args&&... args): value(std::forward<Args>(args)...){
        //Nothing else to init
    }

    ~trivial_expected_storage() = default;
};

template<typename E>
union trivial_expected_storage <void, E> {
    typedef void value_type;
    typedef E error_type;

    error_type error;

    constexpr trivial_expected_storage() {
        //Nothing else to init
    }

    constexpr trivial_expected_storage(const exceptional<error_type>& e) : error(e.error){
        //Nothing else to init
    }

    ~trivial_expected_storage() = default;
};

template<typename T, typename E>
union non_trivial_expected_storage {
    typedef T value_type;
    typedef E error_type;

    error_type error;
    value_type value;

    constexpr non_trivial_expected_storage() : value(){
        //Nothing else to init
    }

    constexpr non_trivial_expected_storage(exceptional<error_type>& e) : error(e.error){
        //Nothing else to init
    }

    template<typename... Args>
    constexpr non_trivial_expected_storage(Args&&... args): value(std::forward<Args>(args)...){
        //Nothing else to init
    }

    ~non_trivial_expected_storage() {};
};

template<typename E>
union non_trivial_expected_storage <void, E> {
    typedef void value_type;
    typedef E error_type;

    error_type error;

    constexpr non_trivial_expected_storage(){
        //Nothing else to init
    }

    constexpr non_trivial_expected_storage(exceptional<error_type>& e) : error(e.error){
        //Nothing else to init
    }

    ~non_trivial_expected_storage() {};
};

template<typename T, typename E>
struct trivial_expected_base {
    typedef T value_type;
    typedef E error_type;

    bool has_value;
    trivial_expected_storage<T, E> storage;

    trivial_expected_base() : has_value(true), storage(){
        //Nothing else to init
    }

    trivial_expected_base(only_set_valid_t, bool hv) : has_value(hv){
        //Nothing else to init
    }

    trivial_expected_base(const value_type& v) : has_value(true), storage(v){
        //Nothing else to init
    }

    trivial_expected_base(value_type&& v) : has_value(true), storage(std::forward<value_type>(v)){
        //Nothing else to init
    }

    trivial_expected_base(const exceptional<error_type>& e) : has_value(false), storage(e) {
        //Nothing else to init
    }

    ~trivial_expected_base() = default;
};

template<typename E>
struct trivial_expected_base <void, E> {
    typedef E error_type;

    bool has_value;
    trivial_expected_storage<void, E> storage;

    trivial_expected_base() : has_value(true), storage(){
        //Nothing else to init
    }

    trivial_expected_base(only_set_valid_t, bool hv) : has_value(hv){
        //Nothing else to init
    }

    trivial_expected_base(const exceptional<error_type>& e) : has_value(false), storage(e) {
        //Nothing else to init
    }

    ~trivial_expected_base() = default;
};

template<typename T, typename E>
struct non_trivial_expected_base {
    typedef T value_type;
    typedef E error_type;

    bool has_value;
    trivial_expected_storage<T, E> storage;

    non_trivial_expected_base() : has_value(true), storage(){
        //Nothing else to init
    }

    non_trivial_expected_base(only_set_valid_t, bool hv) : has_value(hv){
        //Nothing else to init
    }

    non_trivial_expected_base(const value_type& v) : has_value(true), storage(v){
        //Nothing else to init
    }

    non_trivial_expected_base(value_type&& v) : has_value(true), storage(std::forward<value_type>(v)){
        //Nothing else to init
    }

    non_trivial_expected_base(const exceptional<error_type>& e) : has_value(false), storage(e) {
        //Nothing else to init
    }

    ~non_trivial_expected_base(){
        if(has_value){
            storage.error.~value_type();
        } else {
            storage.error.~error_type();
        }
    }
};

template<typename E>
struct non_trivial_expected_base <void, E> {
    typedef E error_type;

    bool has_value;
    trivial_expected_storage<void, E> storage;

    non_trivial_expected_base() : has_value(true), storage(){
        //Nothing else to init
    }

    non_trivial_expected_base(only_set_valid_t, bool hv) : has_value(hv){
        //Nothing else to init
    }

    non_trivial_expected_base(const exceptional<error_type>& e) : has_value(false), storage(e) {
        //Nothing else to init
    }

    ~non_trivial_expected_base(){
        if(!has_value){
            storage.error.~error_type();
        }
    }
};

template <typename T, typename E>
using expected_base = typename std::conditional<
        std::is_trivially_destructible<T>::value && std::is_trivially_destructible<E>::value,
        trivial_expected_base<T, E>,
        non_trivial_expected_base<T, E>
    >::type;

template<typename T, typename E = size_t>
struct expected : expected_base<T, E> {
    typedef T value_type;
    typedef E error_type;

    typedef expected<T, E> this_type;
    typedef expected_base<T, E> base_type;

private:
    value_type* value_ptr() {
        return std::addressof(base_type::storage.value);
    }

    constexpr const value_type* value_ptr() const {
        return std::static_addressof(base_type::storage.value);
    }

    error_type* error_ptr() {
        return std::addressof(base_type::storage.error);
    }

    constexpr const error_type* error_ptr() const {
        return static_addressof(base_type::storage.error);
    }

    constexpr const bool& contained_has_value() const& {
        return base_type::has_value;
    }

    bool& contained_has_value() & {
        return base_type::has_value;
    }

    bool&& contained_has_value() && {
        return std::move(base_type::has_value);
    }

    constexpr const value_type& contained_value() const& {
        return base_type::storage.value;
    }

    value_type& contained_value() & {
        return base_type::storage.value;
    }

    value_type&& contained_value() && {
        return std::move(base_type::storage.value);
    }

    constexpr const error_type& contained_error() const& {
        return base_type::storage.error;
    }

    error_type& contained_error() & {
        return base_type::storage.error;
    }

    error_type&& contained_error() && {
        return std::move(base_type::storage.error);
    }

public:
    /* Constructors */

    constexpr expected(const value_type& v) : base_type(v){
        //Nothing else to init
    }

    constexpr expected(value_type&& v) : base_type(std::forward<value_type>(v)){
        //Nothing else to init
    }

    expected(const expected& rhs) : base_type(only_set_valid, rhs.valid()) {
        if(rhs.valid()){
            ::new (value_ptr()) value_type(rhs.contained_value());
        } else {
            ::new (error_ptr()) error_type(rhs.contained_error());
        }
    }

    expected(expected&& rhs) : base_type(only_set_valid, rhs.valid()) {
        if(rhs.valid()){
            new (value_ptr()) value_type(std::move(rhs.contained_value()));
        } else {
            new (error_ptr()) error_type(std::move(rhs.contained_error()));
        }
    }

    expected(const exceptional<error_type>& e) : base_type(e) {
        //Nothing else to init
    }

    expected() : base_type() {}

    ~expected() = default;

    /* Operators */
    expected& operator=(const expected& rhs){
        this_type(rhs).swap(*this);
        return *this;
    }

    expected& operator=(expected&& rhs){
        this_type(std::move(rhs)).swap(*this);
        return *this;
    }

    expected& operator=(const value_type& v){
        this_type(v).swap(*this);
        return *this;
    }

    expected& operator=(value_type&& v){
        this_type(std::move(v)).swap(*this);
        return *this;
    }

    /* Swap */

    void swap(expected& rhs){
        if (valid()){
            if (rhs.valid()){
                std::swap(contained_value(), rhs.contained_value());
            } else {
                error_type t = std::move(rhs.contained_error());
                new (rhs.value_ptr()) value_type(std::move(contained_value()));
                new (error_ptr()) error_type(t);
                std::swap(contained_has_value(), rhs.contained_has_value());
            }
        } else {
            if (rhs.valid()){
                rhs.swap(*this);
            } else {
                std::swap(contained_error(), rhs.contained_error());
            }
        }
    }

    /* Accessors */

    constexpr bool valid() const {
        return contained_has_value();
    }

    constexpr explicit operator bool() const {
        return valid();
    }

    constexpr const value_type& value() const {
        return contained_value();
    }

    constexpr const value_type&  operator*() const {
        return contained_value();
    }

    value_type& operator*(){
        return contained_value();
    }

    constexpr const value_type* operator->() const {
        return value_ptr();
    }

    value_type* operator->(){
        return value_ptr();
    }

    constexpr const error_type& error() const {
        return contained_error();
    }

    constexpr bool has_error(const error_type& e) const {
        return contained_error() == e;
    }

    constexpr exceptional<error_type> get_exceptional() const {
        return exceptional<error_type>(contained_error());
    }
};

template<typename E>
struct expected <void, E> : expected_base<void, E> {
    typedef void value_type;
    typedef E error_type;

    typedef expected<void, E> this_type;
    typedef expected_base<void, E> base_type;

private:
    error_type* error_ptr() {
        return std::addressof(base_type::storage.error);
    }

    constexpr const error_type* error_ptr() const {
        return static_addressof(base_type::storage.error);
    }

    constexpr const bool& contained_has_value() const& {
        return base_type::has_value;
    }

    bool& contained_has_value() & {
        return base_type::has_value;
    }

    bool&& contained_has_value() && {
        return std::move(base_type::has_value);
    }

    constexpr const error_type& contained_error() const& {
        return base_type::storage.error;
    }

    error_type& contained_error() & {
        return base_type::storage.error;
    }

    error_type&& contained_error() && {
        return std::move(base_type::storage.error);
    }

public:
    /* Constructors */

    expected(const expected& rhs) : base_type(only_set_valid, rhs.valid()) {
        if(!rhs.valid()){
            ::new (error_ptr()) error_type(rhs.contained_error());
        }
    }

    expected(expected&& rhs) : base_type(only_set_valid, rhs.valid()) {
        if(!rhs.valid()){
            new (error_ptr()) error_type(std::move(rhs.contained_error()));
        }
    }

    expected(const exceptional<error_type>& e) : base_type(e) {
        //Nothing else to init
    }

    expected() : base_type() {}

    ~expected() = default;

    /* Operators */
    expected& operator=(const expected& rhs){
        this_type(rhs).swap(*this);
        return *this;
    }

    expected& operator=(expected&& rhs){
        this_type(std::move(rhs)).swap(*this);
        return *this;
    }

    /* Swap */

    void swap(expected& rhs){
        if (valid()){
            if (!rhs.valid()){
                error_type t = std::move(rhs.contained_error());
                new (error_ptr()) error_type(t);
            }
        } else {
            if (!rhs.valid()){
                std::swap(contained_error(), rhs.contained_error());
            }
        }
    }

    /* Accessors */

    constexpr bool valid() const {
        return contained_has_value();
    }

    constexpr explicit operator bool() const {
        return valid();
    }

    constexpr const error_type& error() const {
        return contained_error();
    }

    constexpr bool has_error(const error_type& e) const {
        return contained_error() == e;
    }

    constexpr exceptional<error_type> get_exceptional() const {
        return exceptional<error_type>(contained_error());
    }
};

template<typename T>
inline expected<T> make_expected(T&& v){
    return expected<T>(std::forward<T>(v));
}

template<typename T>
inline expected<T> make_expected(const T& v){
    return expected<T>(v);
}

template<typename T, typename U, typename E>
inline expected<T, U> make_expected_from_error(E v){
    return expected<T, U>(exceptional<U>(v));
}

template<typename T, typename E>
inline expected<T, E> make_expected_from_error(E v){
    return expected<T, E>(exceptional<E>(v));
}

inline expected<void> make_expected(){
    return expected<void>();
}

// Make sure the size is maintained reasonable
static_assert(sizeof(expected<void>) == 2 * sizeof(size_t), "expected<void> should not have overhead");
static_assert(sizeof(expected<size_t>) == 2 * sizeof(size_t), "expected<size_t> should not have overhead");

} //end of namespace std

#endif
<|endoftext|>


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

#include <ccpp_dds_dcps.h>
#include <dds_dcps.h>

#include "rmw/allocators.h"
#include "rmw/error_handling.h"
#include "rmw/impl/cpp/macros.hpp"
#include "rmw/rmw.h"
#include "rmw/types.h"

#include "identifier.hpp"
#include "types.hpp"

// The extern "C" here enforces that overloading is not used.
extern "C"
{
rmw_waitset_t *
rmw_create_waitset(rmw_guard_conditions_t * fixed_guard_conditions, size_t max_conditions)
{
  rmw_waitset_t * waitset = rmw_waitset_allocate();
  OpenSpliceWaitSetInfo * waitset_info = nullptr;
  DDS::GuardCondition * dds_guard_cond = nullptr;
  DDS::ReturnCode_t ret;

  // From here onward, error results in unrolling in the goto fail block.
  if (!waitset) {
    RMW_SET_ERROR_MSG("failed to allocate waitset");
    goto fail;
  }
  waitset->implementation_identifier = opensplice_cpp_identifier;
  waitset->data = rmw_allocate(sizeof(OpenSpliceWaitSetInfo));

  waitset_info = static_cast<OpenSpliceWaitSetInfo *>(waitset->data);

  if (!waitset_info) {
    RMW_SET_ERROR_MSG("failed to allocate waitset implementation struct");
    goto fail;
  }

  waitset_info->waitset = static_cast<DDS::WaitSet *>(rmw_allocate(sizeof(DDS::WaitSet)));
  if (!waitset_info->waitset) {
    RMW_SET_ERROR_MSG("failed to allocate waitset");
    goto fail;
  }

  RMW_TRY_PLACEMENT_NEW(
    waitset_info->waitset, waitset_info->waitset, goto fail, DDS::WaitSet)

  // Now allocate storage for the ConditionSeq objects
  waitset_info->active_conditions =
    static_cast<DDS::ConditionSeq *>(rmw_allocate(sizeof(DDS::ConditionSeq)));
  if (!waitset_info->active_conditions) {
    RMW_SET_ERROR_MSG("failed to allocate active_conditions sequence");
    goto fail;
  }

  waitset_info->attached_conditions =
    static_cast<DDS::ConditionSeq *>(rmw_allocate(sizeof(DDS::ConditionSeq)));
  if (!waitset_info->attached_conditions) {
    RMW_SET_ERROR_MSG("failed to allocate attached_conditions sequence");
    goto fail;
  }

  // If max_conditions is greater than zero, re-allocate both ConditionSeqs to max_conditions
  if (max_conditions > 0) {
    RMW_TRY_PLACEMENT_NEW(
      waitset_info->active_conditions, waitset_info->active_conditions, goto fail,
      DDS::ConditionSeq, static_cast<DDS::ULong>(max_conditions))

    RMW_TRY_PLACEMENT_NEW(
      waitset_info->attached_conditions, waitset_info->attached_conditions, goto fail,
      DDS::ConditionSeq,
      static_cast<DDS::ULong>(max_conditions))
  } else {
    // Else, don't preallocate: the vectors will size dynamically when rmw_wait is called.
    // Default-construct the ConditionSeqs.
    RMW_TRY_PLACEMENT_NEW(
      waitset_info->active_conditions, waitset_info->active_conditions, goto fail,
      DDS::ConditionSeq)

    RMW_TRY_PLACEMENT_NEW(
      waitset_info->attached_conditions, waitset_info->attached_conditions, goto fail,
      DDS::ConditionSeq)
  }

  waitset->fixed_guard_conditions = fixed_guard_conditions;
  if (fixed_guard_conditions) {
    if (!fixed_guard_conditions->guard_conditions) {
      RMW_SET_ERROR_MSG("Received invalid guard condition array");
      goto fail;
    }
    // We also need to attach the fixed guard conditions to the waitset (and detach them in destroy)
    for (size_t i = 0; i < fixed_guard_conditions->guard_condition_count; ++i) {
      void * guard_cond = fixed_guard_conditions->guard_conditions[i];
      if (!guard_cond) {
        RMW_SET_ERROR_MSG("Received invalid guard condition");
        goto fail;
      }
      dds_guard_cond = static_cast<DDS::GuardCondition *>(guard_cond);
      ret = waitset_info->waitset->attach_condition(dds_guard_cond);
      if (ret != DDS::RETCODE_OK) {
        RMW_SET_ERROR_MSG("Failed to attach condition to waitset");
      }
    }
  }

  return waitset;

fail:
  if (waitset_info) {
    if (waitset_info->active_conditions) {
      // How to know which constructor threw?
      RMW_TRY_DESTRUCTOR_FROM_WITHIN_FAILURE(
        waitset_info->active_conditions->~DDS_DCPSUObjSeq(), ConditionSeq)
      rmw_free(waitset_info->active_conditions);
    }
    if (waitset_info->attached_conditions) {
      RMW_TRY_DESTRUCTOR_FROM_WITHIN_FAILURE(
        waitset_info->attached_conditions->~DDS_DCPSUObjSeq(), ConditionSeq)
      rmw_free(waitset_info->attached_conditions);
    }
    if (waitset_info->waitset) {
      RMW_TRY_DESTRUCTOR_FROM_WITHIN_FAILURE(waitset_info->waitset->~WaitSet(), WaitSet)
      rmw_free(waitset_info->waitset);
    }
    waitset_info = nullptr;
  }
  if (waitset) {
    if (waitset->data) {
      rmw_free(waitset->data);
    }
    rmw_waitset_free(waitset);
  }
  return nullptr;
}

rmw_ret_t
rmw_destroy_waitset(rmw_waitset_t * waitset)
{
  if (!waitset) {
    RMW_SET_ERROR_MSG("waitset handle is null");
    return RMW_RET_ERROR;
  }
  RMW_CHECK_TYPE_IDENTIFIERS_MATCH(
    waitset handle,
    waitset->implementation_identifier, opensplice_cpp_identifier,
    return RMW_RET_ERROR)

  auto result = RMW_RET_OK;
  OpenSpliceWaitSetInfo * waitset_info = static_cast<OpenSpliceWaitSetInfo *>(waitset->data);
  DDS::WaitSet * dds_waitset =
    static_cast<DDS::WaitSet *>(waitset_info->waitset);

  rmw_guard_conditions_t * fixed_guard_conditions = waitset->fixed_guard_conditions;
  if (fixed_guard_conditions && fixed_guard_conditions->guard_conditions && dds_waitset) {
    // We also need to attach the fixed guard conditions to the waitset (and detach them in destroy)
    for (size_t i = 0; i < fixed_guard_conditions->guard_condition_count; ++i) {
      void * guard_cond = fixed_guard_conditions->guard_conditions[i];
      if (!guard_cond) {
        continue;
      }
      DDS::GuardCondition * dds_guard_cond = static_cast<DDS::GuardCondition *>(guard_cond);
      if (!dds_guard_cond) {
        continue;
      }
      DDS::ReturnCode_t ret = dds_waitset->detach_condition(dds_guard_cond);
      if (ret != DDS::RETCODE_OK) {
        RMW_SET_ERROR_MSG("Failed to detach condition from waitset");
      }
    }
  }

  // Explicitly call destructor since the "placement new" was used

  if (waitset_info->active_conditions) {
    RMW_TRY_DESTRUCTOR(
      waitset_info->active_conditions->~DDS_DCPSUObjSeq(), ConditionSeq, result = RMW_RET_ERROR)
    rmw_free(waitset_info->active_conditions);
  }
  if (waitset_info->attached_conditions) {
    RMW_TRY_DESTRUCTOR(
      waitset_info->attached_conditions->~DDS_DCPSUObjSeq(), ConditionSeq, result = RMW_RET_ERROR)
    rmw_free(waitset_info->attached_conditions);
  }
  if (waitset_info->waitset) {
    RMW_TRY_DESTRUCTOR(waitset_info->waitset->~WaitSet(), WaitSet, result = RMW_RET_ERROR)
    rmw_free(waitset_info->waitset);
    waitset_info = nullptr;
  }
  if (waitset->data) {
    rmw_free(waitset->data);
  }
  if (waitset) {
    rmw_waitset_free(waitset);
  }
  return result;
}
}  // extern "C"
<commit_msg>check for empty fixed guard condition in waitset<commit_after>// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <ccpp_dds_dcps.h>
#include <dds_dcps.h>

#include "rmw/allocators.h"
#include "rmw/error_handling.h"
#include "rmw/impl/cpp/macros.hpp"
#include "rmw/rmw.h"
#include "rmw/types.h"

#include "identifier.hpp"
#include "types.hpp"

// The extern "C" here enforces that overloading is not used.
extern "C"
{
rmw_waitset_t *
rmw_create_waitset(rmw_guard_conditions_t * fixed_guard_conditions, size_t max_conditions)
{
  rmw_waitset_t * waitset = rmw_waitset_allocate();
  OpenSpliceWaitSetInfo * waitset_info = nullptr;
  DDS::GuardCondition * dds_guard_cond = nullptr;
  DDS::ReturnCode_t ret;

  // From here onward, error results in unrolling in the goto fail block.
  if (!waitset) {
    RMW_SET_ERROR_MSG("failed to allocate waitset");
    goto fail;
  }
  waitset->implementation_identifier = opensplice_cpp_identifier;
  waitset->data = rmw_allocate(sizeof(OpenSpliceWaitSetInfo));

  waitset_info = static_cast<OpenSpliceWaitSetInfo *>(waitset->data);

  if (!waitset_info) {
    RMW_SET_ERROR_MSG("failed to allocate waitset implementation struct");
    goto fail;
  }

  waitset_info->waitset = static_cast<DDS::WaitSet *>(rmw_allocate(sizeof(DDS::WaitSet)));
  if (!waitset_info->waitset) {
    RMW_SET_ERROR_MSG("failed to allocate waitset");
    goto fail;
  }

  RMW_TRY_PLACEMENT_NEW(
    waitset_info->waitset, waitset_info->waitset, goto fail, DDS::WaitSet)

  // Now allocate storage for the ConditionSeq objects
  waitset_info->active_conditions =
    static_cast<DDS::ConditionSeq *>(rmw_allocate(sizeof(DDS::ConditionSeq)));
  if (!waitset_info->active_conditions) {
    RMW_SET_ERROR_MSG("failed to allocate active_conditions sequence");
    goto fail;
  }

  waitset_info->attached_conditions =
    static_cast<DDS::ConditionSeq *>(rmw_allocate(sizeof(DDS::ConditionSeq)));
  if (!waitset_info->attached_conditions) {
    RMW_SET_ERROR_MSG("failed to allocate attached_conditions sequence");
    goto fail;
  }

  // If max_conditions is greater than zero, re-allocate both ConditionSeqs to max_conditions
  if (max_conditions > 0) {
    RMW_TRY_PLACEMENT_NEW(
      waitset_info->active_conditions, waitset_info->active_conditions, goto fail,
      DDS::ConditionSeq, static_cast<DDS::ULong>(max_conditions))

    RMW_TRY_PLACEMENT_NEW(
      waitset_info->attached_conditions, waitset_info->attached_conditions, goto fail,
      DDS::ConditionSeq,
      static_cast<DDS::ULong>(max_conditions))
  } else {
    // Else, don't preallocate: the vectors will size dynamically when rmw_wait is called.
    // Default-construct the ConditionSeqs.
    RMW_TRY_PLACEMENT_NEW(
      waitset_info->active_conditions, waitset_info->active_conditions, goto fail,
      DDS::ConditionSeq)

    RMW_TRY_PLACEMENT_NEW(
      waitset_info->attached_conditions, waitset_info->attached_conditions, goto fail,
      DDS::ConditionSeq)
  }

  waitset->fixed_guard_conditions = fixed_guard_conditions;
  if (fixed_guard_conditions && fixed_guard_conditions->guard_condition_count > 0) {
    if (!fixed_guard_conditions->guard_conditions) {
      RMW_SET_ERROR_MSG("Received invalid guard condition array");
      goto fail;
    }
    // We also need to attach the fixed guard conditions to the waitset (and detach them in destroy)
    for (size_t i = 0; i < fixed_guard_conditions->guard_condition_count; ++i) {
      void * guard_cond = fixed_guard_conditions->guard_conditions[i];
      if (!guard_cond) {
        RMW_SET_ERROR_MSG("Received invalid guard condition");
        goto fail;
      }
      dds_guard_cond = static_cast<DDS::GuardCondition *>(guard_cond);
      ret = waitset_info->waitset->attach_condition(dds_guard_cond);
      if (ret != DDS::RETCODE_OK) {
        RMW_SET_ERROR_MSG("Failed to attach condition to waitset");
      }
    }
  }

  return waitset;

fail:
  if (waitset_info) {
    if (waitset_info->active_conditions) {
      // How to know which constructor threw?
      RMW_TRY_DESTRUCTOR_FROM_WITHIN_FAILURE(
        waitset_info->active_conditions->~DDS_DCPSUObjSeq(), ConditionSeq)
      rmw_free(waitset_info->active_conditions);
    }
    if (waitset_info->attached_conditions) {
      RMW_TRY_DESTRUCTOR_FROM_WITHIN_FAILURE(
        waitset_info->attached_conditions->~DDS_DCPSUObjSeq(), ConditionSeq)
      rmw_free(waitset_info->attached_conditions);
    }
    if (waitset_info->waitset) {
      RMW_TRY_DESTRUCTOR_FROM_WITHIN_FAILURE(waitset_info->waitset->~WaitSet(), WaitSet)
      rmw_free(waitset_info->waitset);
    }
    waitset_info = nullptr;
  }
  if (waitset) {
    if (waitset->data) {
      rmw_free(waitset->data);
    }
    rmw_waitset_free(waitset);
  }
  return nullptr;
}

rmw_ret_t
rmw_destroy_waitset(rmw_waitset_t * waitset)
{
  if (!waitset) {
    RMW_SET_ERROR_MSG("waitset handle is null");
    return RMW_RET_ERROR;
  }
  RMW_CHECK_TYPE_IDENTIFIERS_MATCH(
    waitset handle,
    waitset->implementation_identifier, opensplice_cpp_identifier,
    return RMW_RET_ERROR)

  auto result = RMW_RET_OK;
  OpenSpliceWaitSetInfo * waitset_info = static_cast<OpenSpliceWaitSetInfo *>(waitset->data);
  DDS::WaitSet * dds_waitset =
    static_cast<DDS::WaitSet *>(waitset_info->waitset);

  rmw_guard_conditions_t * fixed_guard_conditions = waitset->fixed_guard_conditions;
  if (fixed_guard_conditions && fixed_guard_conditions->guard_conditions && dds_waitset) {
    // We also need to attach the fixed guard conditions to the waitset (and detach them in destroy)
    for (size_t i = 0; i < fixed_guard_conditions->guard_condition_count; ++i) {
      void * guard_cond = fixed_guard_conditions->guard_conditions[i];
      if (!guard_cond) {
        continue;
      }
      DDS::GuardCondition * dds_guard_cond = static_cast<DDS::GuardCondition *>(guard_cond);
      if (!dds_guard_cond) {
        continue;
      }
      DDS::ReturnCode_t ret = dds_waitset->detach_condition(dds_guard_cond);
      if (ret != DDS::RETCODE_OK) {
        RMW_SET_ERROR_MSG("Failed to detach condition from waitset");
      }
    }
  }

  // Explicitly call destructor since the "placement new" was used

  if (waitset_info->active_conditions) {
    RMW_TRY_DESTRUCTOR(
      waitset_info->active_conditions->~DDS_DCPSUObjSeq(), ConditionSeq, result = RMW_RET_ERROR)
    rmw_free(waitset_info->active_conditions);
  }
  if (waitset_info->attached_conditions) {
    RMW_TRY_DESTRUCTOR(
      waitset_info->attached_conditions->~DDS_DCPSUObjSeq(), ConditionSeq, result = RMW_RET_ERROR)
    rmw_free(waitset_info->attached_conditions);
  }
  if (waitset_info->waitset) {
    RMW_TRY_DESTRUCTOR(waitset_info->waitset->~WaitSet(), WaitSet, result = RMW_RET_ERROR)
    rmw_free(waitset_info->waitset);
    waitset_info = nullptr;
  }
  if (waitset->data) {
    rmw_free(waitset->data);
  }
  if (waitset) {
    rmw_waitset_free(waitset);
  }
  return result;
}
}  // extern "C"
<|endoftext|>


<commit_before>/**************************************************kernel_size_w*****************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/

#include "miopen/solver.hpp"
#include "miopen/handle.hpp"

namespace miopen {
namespace solver {

bool ConvOclDirectFwd3x3::IsApplicable(const ConvolutionContext& params) const
{
    if(!params.Is2d())
        return false;
    if(!(params.IsFp32() || params.IsFp16() || params.IsBfp16()))
        return false;

    return params.kernel_size_w == 3 && params.kernel_size_h == 3 && params.pad_w == 1 &&
           params.pad_h == 1 && params.kernel_stride_w == 1 && params.kernel_stride_h == 1 &&
           params.kernel_dilation_w == 1 && params.kernel_dilation_h == 1 &&
           params.group_counts == 1 && params.direction.IsForward() &&
           (params.out_width == 512 || params.out_width == 64 || params.out_width == 128 ||
            params.out_width == 256);
}

ConvSolution ConvOclDirectFwd3x3::GetSolution(const ConvolutionContext& params) const
{
    ConvSolution result;
    // size_t localMemSize = params.stream.GetLocalMemorySize();
    auto hw_wave_sz = 64;
    // auto dev_local_mem_sz = localMemSize; // in bytes
    int n_waves = 4;

    int wei_cstride = params.kernel_size_w * params.kernel_size_h;
    int wei_bstride = params.n_inputs * wei_cstride;

    result.out_pix_tile0   = 4;
    result.out_pix_tile1   = 2;
    result.n_stacks        = 1;
    result.n_out_pix_tiles = 4;
    int read_unit          = result.out_pix_tile0;
    //	std::string READ_TYPE = (read_unit == 1) ? "_FLOAT" : "_FLOAT" +
    // std::to_string(static_cast<long long>(read_unit));
    // MD: read_unit is never == 1
    std::string READ_TYPE = "_FLOAT" + std::to_string(static_cast<long long>(read_unit));

    int GRP_SZ = hw_wave_sz * n_waves;

    int ALU_EXTENT_X     = (params.out_width + read_unit - 1) / read_unit;
    auto LG2ALU_EXTENT_X = static_cast<int>(std::ceil(std::log(ALU_EXTENT_X) / std::log(2)));
    int ALU_EXTENT_Y     = (GRP_SZ >> LG2ALU_EXTENT_X);
    auto LG2ALU_EXTENT_Y = static_cast<int>(std::ceil(std::log(ALU_EXTENT_Y) / std::log(2)));

    // the wave is logical is a unit of shareing weights in SGPRs
    // it cannot be less than HW_WAVE_SIZE = 64
    // it cannot be larger than the group size.

    int LG2_WAVE_SZ0    = std::ceil(std::log(ALU_EXTENT_X) / std::log(2));
    int logical_wave_sz = std::max(1, ALU_EXTENT_X / hw_wave_sz) * hw_wave_sz;
    if(logical_wave_sz > GRP_SZ)
    {
        MIOPEN_LOG_E("logical_wave_sz > GRP_SZ");
        return ConvSolution(static_cast<miopenStatus_t>(-1));
    }
    int logical_n_waves = std::max(1, GRP_SZ / logical_wave_sz);
    int LG2_WAVE_SZ     = std::ceil(std::log(logical_wave_sz) / std::log(2));
    int WAVE_SZ1        = (logical_wave_sz >> LG2_WAVE_SZ0);
    int lg2_n_waves     = std::ceil(std::log(logical_n_waves) / std::log(2));
    int N_WAVES_MASK    = (1 << lg2_n_waves) - 1;

    int OUT_EXTENT1 = result.out_pix_tile1 * WAVE_SZ1;
    int OUT_EXTENT0 = (result.out_pix_tile0 << LG2_WAVE_SZ0);

    int total_out_maps = result.n_out_pix_tiles * logical_n_waves;

    // number of batches inside wk_item
    result.n_stacks = std::min(params.batch_sz, result.n_stacks);

    int N_HEIGHT_EXTENTS = (params.out_height + OUT_EXTENT1 - 1) / OUT_EXTENT1;
    int N_WIDTH_EXTENTS  = (params.out_width + OUT_EXTENT0 - 1) / OUT_EXTENT0;
    int N_GROUPS_PER_MAP = N_HEIGHT_EXTENTS * N_WIDTH_EXTENTS;

    result.grp_tile0 = GRP_SZ;
    result.grp_tile1 = 1;
    int grp_tile2    = 1;
    // auto in_tile0 = OUT_EXTENT0;
    // auto in_tile1 = OUT_EXTENT1;
    auto n_in_data_tiles = 1;

    //	_gen_comp_options += std::string(" -limit-vector-registers=64 ");

    KernelInfo construction_parameters;

    construction_parameters.comp_options =
        std::string(" -DMLO_DIR_FORWARD=") + (params.direction.IsForward() ? "1" : "0") +
        std::string(" -DMLO_GRP_SZ=") + std::to_string(static_cast<long long>(GRP_SZ)) +
        std::string(" -DMLO_GRP_SZ0=") + std::to_string(static_cast<long long>(result.grp_tile0)) +
        std::string(" -DMLO_GRP_SZ1=") + std::to_string(static_cast<long long>(result.grp_tile1)) +
        std::string(" -DMLO_GRP_SZ2=") + std::to_string(static_cast<long long>(grp_tile2)) +
        std::string(" -DMLO_FILTER_SIZE0=") +
        std::to_string(static_cast<long long>(params.kernel_size_w)) +
        std::string(" -DMLO_FILTER_SIZE1=") +
        std::to_string(static_cast<long long>(params.kernel_size_h)) +
        std::string(" -DMLO_FILTER_PAD0=") + std::to_string(static_cast<long long>(params.pad_w)) +
        std::string(" -DMLO_FILTER_PAD1=") + std::to_string(static_cast<long long>(params.pad_h)) +
        std::string(" -DMLO_N_OUTPUTS=") +
        std::to_string(static_cast<long long>(params.n_outputs)) + std::string(" -DMLO_N_INPUTS=") +
        std::to_string(static_cast<long long>(params.n_inputs)) + std::string(" -DMLO_BATCH_SZ=") +
        std::to_string(static_cast<long long>(params.batch_sz)) +
        std::string(" -DMLO_OUT_BATCH_STRIDE=") +
        std::to_string(static_cast<long long>(params.out_batch_stride)) +
        std::string(" -DMLO_OUT_CHANNEL_STRIDE=") +
        std::to_string(static_cast<long long>(params.out_channel_stride)) +
        std::string(" -DMLO_OUT_STRIDE=") +
        std::to_string(static_cast<long long>(params.out_stride)) +
        std::string(" -DMLO_IN_BATCH_STRIDE=") +
        std::to_string(static_cast<long long>(params.in_batch_stride)) +
        std::string(" -DMLO_IN_CHANNEL_STRIDE=") +
        std::to_string(static_cast<long long>(params.in_channel_stride)) +
        std::string(" -DMLO_IN_STRIDE=") +
        std::to_string(static_cast<long long>(params.in_stride)) +
        std::string(" -DMLO_WEI_BATCH_STRIDE=") +
        std::to_string(static_cast<long long>(wei_bstride)) +
        std::string(" -DMLO_WEI_CHANNEL_STRIDE=") +
        std::to_string(static_cast<long long>(wei_cstride)) + std::string(" -DMLO_IN_WIDTH=") +
        std::to_string(static_cast<long long>(params.in_width)) + std::string(" -DMLO_IN_HEIGHT=") +
        std::to_string(static_cast<long long>(params.in_height)) +
        std::string(" -DMLO_N_LCL_BATCHS=") +
        std::to_string(static_cast<long long>(result.n_stacks)) // # of diff stacks (part of batch).
        + std::string(" -DMLO_N_LCL_OUT_MAPS=") +
        std::to_string(static_cast<long long>(
            result.n_out_pix_tiles)) // # output pixel tiles per wk-item (ALU)
        + std::string(" -DMLO_N_LCL_IN_MAPS=") +
        std::to_string(
            static_cast<long long>(n_in_data_tiles)) // total # of blocks of different inputs in LDS
        + std::string(" -DMLO_OUT_TILE0=") +
        std::to_string(
            static_cast<long long>(result.out_pix_tile0)) // size of ouptput tile per wk-item (ALU))
        + std::string(" -DMLO_OUT_TILE1=") +
        std::to_string(static_cast<long long>(result.out_pix_tile1)) //
        + std::string(" -DMLO_ALU_EXTENT_X=") +
        std::to_string(static_cast<long long>(ALU_EXTENT_X)) +
        std::string(" -DMLO_LG2ALU_EXTENT_X=") +
        std::to_string(static_cast<long long>(LG2ALU_EXTENT_X)) +
        std::string(" -DMLO_ALU_EXTENT_Y=") + std::to_string(static_cast<long long>(ALU_EXTENT_Y)) +
        std::string(" -DMLO_LG2ALU_EXTENT_Y=") +
        std::to_string(static_cast<long long>(LG2ALU_EXTENT_Y)) +
        std::string(" -DMLO_OUT_EXTENT1=") + std::to_string(static_cast<long long>(OUT_EXTENT1)) +
        std::string(" -DMLO_OUT_EXTENT0=") + std::to_string(static_cast<long long>(OUT_EXTENT0)) +
        std::string(" -DMLO_N_WAVES=") + std::to_string(static_cast<long long>(logical_n_waves)) +
        std::string(" -DMLO_N_WAVES_MASK=") + std::to_string(static_cast<long long>(N_WAVES_MASK)) +
        std::string(" -DMLO_LG2_WAVE_SZ=") + std::to_string(static_cast<long long>(LG2_WAVE_SZ)) +
        std::string(" -DMLO_LG2_WAVE_SZ0=") + std::to_string(static_cast<long long>(LG2_WAVE_SZ0)) +
        std::string(" -DMLO_READ_TYPE=") + READ_TYPE + std::string(" -DMLO_READ_UNIT=") +
        std::to_string(static_cast<long long>(read_unit)) + std::string(" -DMLO_CONV_BIAS=") +
        std::to_string(static_cast<long long>(params.bias)) + params.general_compile_options;

    std::cout << " MIOpenConvD3x3 " << construction_parameters.comp_options << std::endl;
    construction_parameters.l_wk.push_back(result.grp_tile0);
    construction_parameters.l_wk.push_back(result.grp_tile1);
    construction_parameters.l_wk.push_back(grp_tile2);

    size_t gbl_wk0 = N_GROUPS_PER_MAP;

    size_t gbl_wk1 = (params.n_outputs + total_out_maps - 1) / total_out_maps;
    size_t gbl_wk2 = (params.batch_sz + result.n_stacks - 1) / result.n_stacks;

    construction_parameters.g_wk.push_back(gbl_wk0 * result.grp_tile0);
    construction_parameters.g_wk.push_back(gbl_wk1);
    construction_parameters.g_wk.push_back(gbl_wk2);

    construction_parameters.kernel_file = "MIOpenConvD3x3.cl";
    construction_parameters.kernel_name = "MIOpenCvD3x3_WSR0";

    result.construction_params.push_back(construction_parameters);
    return result;
}
} // namespace solver
} // namespace miopen
<commit_msg>fix comment in conv_ocl_dir2D3x3.cpp (#2003)<commit_after>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/

#include "miopen/solver.hpp"
#include "miopen/handle.hpp"

namespace miopen {
namespace solver {

bool ConvOclDirectFwd3x3::IsApplicable(const ConvolutionContext& params) const
{
    if(!params.Is2d())
        return false;
    if(!(params.IsFp32() || params.IsFp16() || params.IsBfp16()))
        return false;

    return params.kernel_size_w == 3 && params.kernel_size_h == 3 && params.pad_w == 1 &&
           params.pad_h == 1 && params.kernel_stride_w == 1 && params.kernel_stride_h == 1 &&
           params.kernel_dilation_w == 1 && params.kernel_dilation_h == 1 &&
           params.group_counts == 1 && params.direction.IsForward() &&
           (params.out_width == 512 || params.out_width == 64 || params.out_width == 128 ||
            params.out_width == 256);
}

ConvSolution ConvOclDirectFwd3x3::GetSolution(const ConvolutionContext& params) const
{
    ConvSolution result;
    // size_t localMemSize = params.stream.GetLocalMemorySize();
    auto hw_wave_sz = 64;
    // auto dev_local_mem_sz = localMemSize; // in bytes
    int n_waves = 4;

    int wei_cstride = params.kernel_size_w * params.kernel_size_h;
    int wei_bstride = params.n_inputs * wei_cstride;

    result.out_pix_tile0   = 4;
    result.out_pix_tile1   = 2;
    result.n_stacks        = 1;
    result.n_out_pix_tiles = 4;
    int read_unit          = result.out_pix_tile0;
    //	std::string READ_TYPE = (read_unit == 1) ? "_FLOAT" : "_FLOAT" +
    // std::to_string(static_cast<long long>(read_unit));
    // MD: read_unit is never == 1
    std::string READ_TYPE = "_FLOAT" + std::to_string(static_cast<long long>(read_unit));

    int GRP_SZ = hw_wave_sz * n_waves;

    int ALU_EXTENT_X     = (params.out_width + read_unit - 1) / read_unit;
    auto LG2ALU_EXTENT_X = static_cast<int>(std::ceil(std::log(ALU_EXTENT_X) / std::log(2)));
    int ALU_EXTENT_Y     = (GRP_SZ >> LG2ALU_EXTENT_X);
    auto LG2ALU_EXTENT_Y = static_cast<int>(std::ceil(std::log(ALU_EXTENT_Y) / std::log(2)));

    // the wave is logical is a unit of shareing weights in SGPRs
    // it cannot be less than HW_WAVE_SIZE = 64
    // it cannot be larger than the group size.

    int LG2_WAVE_SZ0    = std::ceil(std::log(ALU_EXTENT_X) / std::log(2));
    int logical_wave_sz = std::max(1, ALU_EXTENT_X / hw_wave_sz) * hw_wave_sz;
    if(logical_wave_sz > GRP_SZ)
    {
        MIOPEN_LOG_E("logical_wave_sz > GRP_SZ");
        return ConvSolution(static_cast<miopenStatus_t>(-1));
    }
    int logical_n_waves = std::max(1, GRP_SZ / logical_wave_sz);
    int LG2_WAVE_SZ     = std::ceil(std::log(logical_wave_sz) / std::log(2));
    int WAVE_SZ1        = (logical_wave_sz >> LG2_WAVE_SZ0);
    int lg2_n_waves     = std::ceil(std::log(logical_n_waves) / std::log(2));
    int N_WAVES_MASK    = (1 << lg2_n_waves) - 1;

    int OUT_EXTENT1 = result.out_pix_tile1 * WAVE_SZ1;
    int OUT_EXTENT0 = (result.out_pix_tile0 << LG2_WAVE_SZ0);

    int total_out_maps = result.n_out_pix_tiles * logical_n_waves;

    // number of batches inside wk_item
    result.n_stacks = std::min(params.batch_sz, result.n_stacks);

    int N_HEIGHT_EXTENTS = (params.out_height + OUT_EXTENT1 - 1) / OUT_EXTENT1;
    int N_WIDTH_EXTENTS  = (params.out_width + OUT_EXTENT0 - 1) / OUT_EXTENT0;
    int N_GROUPS_PER_MAP = N_HEIGHT_EXTENTS * N_WIDTH_EXTENTS;

    result.grp_tile0 = GRP_SZ;
    result.grp_tile1 = 1;
    int grp_tile2    = 1;
    // auto in_tile0 = OUT_EXTENT0;
    // auto in_tile1 = OUT_EXTENT1;
    auto n_in_data_tiles = 1;

    //	_gen_comp_options += std::string(" -limit-vector-registers=64 ");

    KernelInfo construction_parameters;

    construction_parameters.comp_options =
        std::string(" -DMLO_DIR_FORWARD=") + (params.direction.IsForward() ? "1" : "0") +
        std::string(" -DMLO_GRP_SZ=") + std::to_string(static_cast<long long>(GRP_SZ)) +
        std::string(" -DMLO_GRP_SZ0=") + std::to_string(static_cast<long long>(result.grp_tile0)) +
        std::string(" -DMLO_GRP_SZ1=") + std::to_string(static_cast<long long>(result.grp_tile1)) +
        std::string(" -DMLO_GRP_SZ2=") + std::to_string(static_cast<long long>(grp_tile2)) +
        std::string(" -DMLO_FILTER_SIZE0=") +
        std::to_string(static_cast<long long>(params.kernel_size_w)) +
        std::string(" -DMLO_FILTER_SIZE1=") +
        std::to_string(static_cast<long long>(params.kernel_size_h)) +
        std::string(" -DMLO_FILTER_PAD0=") + std::to_string(static_cast<long long>(params.pad_w)) +
        std::string(" -DMLO_FILTER_PAD1=") + std::to_string(static_cast<long long>(params.pad_h)) +
        std::string(" -DMLO_N_OUTPUTS=") +
        std::to_string(static_cast<long long>(params.n_outputs)) + std::string(" -DMLO_N_INPUTS=") +
        std::to_string(static_cast<long long>(params.n_inputs)) + std::string(" -DMLO_BATCH_SZ=") +
        std::to_string(static_cast<long long>(params.batch_sz)) +
        std::string(" -DMLO_OUT_BATCH_STRIDE=") +
        std::to_string(static_cast<long long>(params.out_batch_stride)) +
        std::string(" -DMLO_OUT_CHANNEL_STRIDE=") +
        std::to_string(static_cast<long long>(params.out_channel_stride)) +
        std::string(" -DMLO_OUT_STRIDE=") +
        std::to_string(static_cast<long long>(params.out_stride)) +
        std::string(" -DMLO_IN_BATCH_STRIDE=") +
        std::to_string(static_cast<long long>(params.in_batch_stride)) +
        std::string(" -DMLO_IN_CHANNEL_STRIDE=") +
        std::to_string(static_cast<long long>(params.in_channel_stride)) +
        std::string(" -DMLO_IN_STRIDE=") +
        std::to_string(static_cast<long long>(params.in_stride)) +
        std::string(" -DMLO_WEI_BATCH_STRIDE=") +
        std::to_string(static_cast<long long>(wei_bstride)) +
        std::string(" -DMLO_WEI_CHANNEL_STRIDE=") +
        std::to_string(static_cast<long long>(wei_cstride)) + std::string(" -DMLO_IN_WIDTH=") +
        std::to_string(static_cast<long long>(params.in_width)) + std::string(" -DMLO_IN_HEIGHT=") +
        std::to_string(static_cast<long long>(params.in_height)) +
        std::string(" -DMLO_N_LCL_BATCHS=") +
        std::to_string(static_cast<long long>(result.n_stacks)) // # of diff stacks (part of batch).
        + std::string(" -DMLO_N_LCL_OUT_MAPS=") +
        std::to_string(static_cast<long long>(
            result.n_out_pix_tiles)) // # output pixel tiles per wk-item (ALU)
        + std::string(" -DMLO_N_LCL_IN_MAPS=") +
        std::to_string(
            static_cast<long long>(n_in_data_tiles)) // total # of blocks of different inputs in LDS
        + std::string(" -DMLO_OUT_TILE0=") +
        std::to_string(
            static_cast<long long>(result.out_pix_tile0)) // size of ouptput tile per wk-item (ALU))
        + std::string(" -DMLO_OUT_TILE1=") +
        std::to_string(static_cast<long long>(result.out_pix_tile1)) //
        + std::string(" -DMLO_ALU_EXTENT_X=") +
        std::to_string(static_cast<long long>(ALU_EXTENT_X)) +
        std::string(" -DMLO_LG2ALU_EXTENT_X=") +
        std::to_string(static_cast<long long>(LG2ALU_EXTENT_X)) +
        std::string(" -DMLO_ALU_EXTENT_Y=") + std::to_string(static_cast<long long>(ALU_EXTENT_Y)) +
        std::string(" -DMLO_LG2ALU_EXTENT_Y=") +
        std::to_string(static_cast<long long>(LG2ALU_EXTENT_Y)) +
        std::string(" -DMLO_OUT_EXTENT1=") + std::to_string(static_cast<long long>(OUT_EXTENT1)) +
        std::string(" -DMLO_OUT_EXTENT0=") + std::to_string(static_cast<long long>(OUT_EXTENT0)) +
        std::string(" -DMLO_N_WAVES=") + std::to_string(static_cast<long long>(logical_n_waves)) +
        std::string(" -DMLO_N_WAVES_MASK=") + std::to_string(static_cast<long long>(N_WAVES_MASK)) +
        std::string(" -DMLO_LG2_WAVE_SZ=") + std::to_string(static_cast<long long>(LG2_WAVE_SZ)) +
        std::string(" -DMLO_LG2_WAVE_SZ0=") + std::to_string(static_cast<long long>(LG2_WAVE_SZ0)) +
        std::string(" -DMLO_READ_TYPE=") + READ_TYPE + std::string(" -DMLO_READ_UNIT=") +
        std::to_string(static_cast<long long>(read_unit)) + std::string(" -DMLO_CONV_BIAS=") +
        std::to_string(static_cast<long long>(params.bias)) + params.general_compile_options;

    std::cout << " MIOpenConvD3x3 " << construction_parameters.comp_options << std::endl;
    construction_parameters.l_wk.push_back(result.grp_tile0);
    construction_parameters.l_wk.push_back(result.grp_tile1);
    construction_parameters.l_wk.push_back(grp_tile2);

    size_t gbl_wk0 = N_GROUPS_PER_MAP;

    size_t gbl_wk1 = (params.n_outputs + total_out_maps - 1) / total_out_maps;
    size_t gbl_wk2 = (params.batch_sz + result.n_stacks - 1) / result.n_stacks;

    construction_parameters.g_wk.push_back(gbl_wk0 * result.grp_tile0);
    construction_parameters.g_wk.push_back(gbl_wk1);
    construction_parameters.g_wk.push_back(gbl_wk2);

    construction_parameters.kernel_file = "MIOpenConvD3x3.cl";
    construction_parameters.kernel_name = "MIOpenCvD3x3_WSR0";

    result.construction_params.push_back(construction_parameters);
    return result;
}
} // namespace solver
} // namespace miopen
<|endoftext|>


<commit_before><commit_msg>fixup!<commit_after><|endoftext|>


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

/**
 * @file
 * Miss Status and Handling Register (MSHR) declaration.
 */

#ifndef __MSHR_HH__
#define __MSHR_HH__

#include <list>

#include "mem/packet.hh"

class CacheBlk;
class MSHRQueue;

/**
 * Miss Status and handling Register. This class keeps all the information
 * needed to handle a cache miss including a list of target requests.
 */
class MSHR : public Packet::SenderState
{

  public:

    class Target {
      public:
        Tick recvTime;  //!< Time when request was received (for stats)
        Tick readyTime; //!< Time when request is ready to be serviced
        Counter order;  //!< Global order (for memory consistency mgmt)
        PacketPtr pkt;  //!< Pending request packet.
        bool cpuSide;   //!< Did request come from cpu side or mem side?

        bool isCpuSide() { return cpuSide; }

        Target(PacketPtr _pkt, Tick _readyTime, Counter _order, bool _cpuSide)
            : recvTime(curTick), readyTime(_readyTime), order(_order),
              pkt(_pkt), cpuSide(_cpuSide)
        {}
    };

    /** Defines the Data structure of the MSHR targetlist. */
    typedef std::list<Target> TargetList;
    /** Target list iterator. */
    typedef std::list<Target>::iterator TargetListIterator;
    /** A list of MSHRs. */
    typedef std::list<MSHR *> List;
    /** MSHR list iterator. */
    typedef List::iterator Iterator;
    /** MSHR list const_iterator. */
    typedef List::const_iterator ConstIterator;

    /** Pointer to queue containing this MSHR. */
    MSHRQueue *queue;

    /** Cycle when ready to issue */
    Tick readyTime;

    /** Order number assigned by the miss queue. */
    Counter order;

    /** Address of the request. */
    Addr addr;

    /** Size of the request. */
    int size;

    /** True if the request has been sent to the bus. */
    bool inService;

    /** True if we will be putting the returned block in the cache */
    bool isCacheFill;
    /** True if we need to get an exclusive copy of the block. */
    bool needsExclusive;

    /** True if the request is uncacheable */
    bool _isUncacheable;

    bool deferredNeedsExclusive;
    bool pendingInvalidate;
    bool pendingShared;

    /** Thread number of the miss. */
    short threadNum;
    /** The number of currently allocated targets. */
    short ntargets;

    /** Data buffer (if needed).  Currently used only for pending
     * upgrade handling. */
    uint8_t *data;

    /**
     * Pointer to this MSHR on the ready list.
     * @sa MissQueue, MSHRQueue::readyList
     */
    Iterator readyIter;

    /**
     * Pointer to this MSHR on the allocated list.
     * @sa MissQueue, MSHRQueue::allocatedList
     */
    Iterator allocIter;

private:
    /** List of all requests that match the address */
    TargetList targets;

    TargetList deferredTargets;

public:

    bool isUncacheable() { return _isUncacheable; }

    /**
     * Allocate a miss to this MSHR.
     * @param cmd The requesting command.
     * @param addr The address of the miss.
     * @param asid The address space id of the miss.
     * @param size The number of bytes to request.
     * @param pkt  The original miss.
     */
    void allocate(Addr addr, int size, PacketPtr pkt,
                  Tick when, Counter _order);

    /**
     * Mark this MSHR as free.
     */
    void deallocate();

    /**
     * Add a request to the list of targets.
     * @param target The target.
     */
    void allocateTarget(PacketPtr target, Tick when, Counter order);
    void allocateSnoopTarget(PacketPtr target, Tick when, Counter order);

    /** A simple constructor. */
    MSHR();
    /** A simple destructor. */
    ~MSHR();

    /**
     * Returns the current number of allocated targets.
     * @return The current number of allocated targets.
     */
    int getNumTargets() { return ntargets; }

    /**
     * Returns a pointer to the target list.
     * @return a pointer to the target list.
     */
    TargetList* getTargetList() { return &targets; }

    /**
     * Returns a reference to the first target.
     * @return A pointer to the first target.
     */
    Target *getTarget() { return &targets.front(); }

    /**
     * Pop first target.
     */
    void popTarget()
    {
        --ntargets;
        targets.pop_front();
    }

    /**
     * Returns true if there are targets left.
     * @return true if there are targets
     */
    bool hasTargets() { return !targets.empty(); }

    bool isSimpleForward()
    {
        if (getNumTargets() != 1)
            return false;
        Target *tgt = getTarget();
        return tgt->isCpuSide() && !tgt->pkt->needsResponse();
    }

    bool promoteDeferredTargets();

    void handleFill(Packet *pkt, CacheBlk *blk);

    /**
     * Prints the contents of this MSHR to stderr.
     */
    void dump();
};

#endif //__MSHR_HH__
<commit_msg>Assert that an mshr has a target in getTarget().<commit_after>/*
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Erik Hallnor
 */

/**
 * @file
 * Miss Status and Handling Register (MSHR) declaration.
 */

#ifndef __MSHR_HH__
#define __MSHR_HH__

#include <list>

#include "mem/packet.hh"

class CacheBlk;
class MSHRQueue;

/**
 * Miss Status and handling Register. This class keeps all the information
 * needed to handle a cache miss including a list of target requests.
 */
class MSHR : public Packet::SenderState
{

  public:

    class Target {
      public:
        Tick recvTime;  //!< Time when request was received (for stats)
        Tick readyTime; //!< Time when request is ready to be serviced
        Counter order;  //!< Global order (for memory consistency mgmt)
        PacketPtr pkt;  //!< Pending request packet.
        bool cpuSide;   //!< Did request come from cpu side or mem side?

        bool isCpuSide() { return cpuSide; }

        Target(PacketPtr _pkt, Tick _readyTime, Counter _order, bool _cpuSide)
            : recvTime(curTick), readyTime(_readyTime), order(_order),
              pkt(_pkt), cpuSide(_cpuSide)
        {}
    };

    /** Defines the Data structure of the MSHR targetlist. */
    typedef std::list<Target> TargetList;
    /** Target list iterator. */
    typedef std::list<Target>::iterator TargetListIterator;
    /** A list of MSHRs. */
    typedef std::list<MSHR *> List;
    /** MSHR list iterator. */
    typedef List::iterator Iterator;
    /** MSHR list const_iterator. */
    typedef List::const_iterator ConstIterator;

    /** Pointer to queue containing this MSHR. */
    MSHRQueue *queue;

    /** Cycle when ready to issue */
    Tick readyTime;

    /** Order number assigned by the miss queue. */
    Counter order;

    /** Address of the request. */
    Addr addr;

    /** Size of the request. */
    int size;

    /** True if the request has been sent to the bus. */
    bool inService;

    /** True if we will be putting the returned block in the cache */
    bool isCacheFill;
    /** True if we need to get an exclusive copy of the block. */
    bool needsExclusive;

    /** True if the request is uncacheable */
    bool _isUncacheable;

    bool deferredNeedsExclusive;
    bool pendingInvalidate;
    bool pendingShared;

    /** Thread number of the miss. */
    short threadNum;
    /** The number of currently allocated targets. */
    short ntargets;

    /** Data buffer (if needed).  Currently used only for pending
     * upgrade handling. */
    uint8_t *data;

    /**
     * Pointer to this MSHR on the ready list.
     * @sa MissQueue, MSHRQueue::readyList
     */
    Iterator readyIter;

    /**
     * Pointer to this MSHR on the allocated list.
     * @sa MissQueue, MSHRQueue::allocatedList
     */
    Iterator allocIter;

private:
    /** List of all requests that match the address */
    TargetList targets;

    TargetList deferredTargets;

public:

    bool isUncacheable() { return _isUncacheable; }

    /**
     * Allocate a miss to this MSHR.
     * @param cmd The requesting command.
     * @param addr The address of the miss.
     * @param asid The address space id of the miss.
     * @param size The number of bytes to request.
     * @param pkt  The original miss.
     */
    void allocate(Addr addr, int size, PacketPtr pkt,
                  Tick when, Counter _order);

    /**
     * Mark this MSHR as free.
     */
    void deallocate();

    /**
     * Add a request to the list of targets.
     * @param target The target.
     */
    void allocateTarget(PacketPtr target, Tick when, Counter order);
    void allocateSnoopTarget(PacketPtr target, Tick when, Counter order);

    /** A simple constructor. */
    MSHR();
    /** A simple destructor. */
    ~MSHR();

    /**
     * Returns the current number of allocated targets.
     * @return The current number of allocated targets.
     */
    int getNumTargets() { return ntargets; }

    /**
     * Returns a pointer to the target list.
     * @return a pointer to the target list.
     */
    TargetList* getTargetList() { return &targets; }

    /**
     * Returns true if there are targets left.
     * @return true if there are targets
     */
    bool hasTargets() { return !targets.empty(); }

    /**
     * Returns a reference to the first target.
     * @return A pointer to the first target.
     */
    Target *getTarget() { assert(hasTargets());  return &targets.front(); }

    /**
     * Pop first target.
     */
    void popTarget()
    {
        --ntargets;
        targets.pop_front();
    }

    bool isSimpleForward()
    {
        if (getNumTargets() != 1)
            return false;
        Target *tgt = getTarget();
        return tgt->isCpuSide() && !tgt->pkt->needsResponse();
    }

    bool promoteDeferredTargets();

    void handleFill(Packet *pkt, CacheBlk *blk);

    /**
     * Prints the contents of this MSHR to stderr.
     */
    void dump();
};

#endif //__MSHR_HH__
<|endoftext|>


<commit_before>/***************************************************************************
    copyright            : (C) 2002 - 2008 by Scott Wheeler
    email                : wheeler@kde.org
 ***************************************************************************/

/***************************************************************************
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License version   *
 *   2.1 as published by the Free Software Foundation.                     *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful, but   *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA         *
 *   02110-1301  USA                                                       *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#include <algorithm>
#include <vector>

#include <tbytevector.h>
#include <tdebug.h>
#include <tstring.h>

#include "rifffile.h"
#include "riffutils.h"

using namespace TagLib;

struct Chunk
{
  ByteVector   name;
  unsigned int offset;
  unsigned int size;
  unsigned int padding;
};

class RIFF::File::FilePrivate
{
public:
  FilePrivate(Endianness endianness) :
    endianness(endianness),
    size(0),
    sizeOffset(0) {}

  const Endianness endianness;

  unsigned int size;
  long sizeOffset;

  std::vector<Chunk> chunks;
};

////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

RIFF::File::~File()
{
  delete d;
}

////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////

RIFF::File::File(FileName file, Endianness endianness) :
  TagLib::File(file),
  d(new FilePrivate(endianness))
{
  if(isOpen())
    read();
}

RIFF::File::File(IOStream *stream, Endianness endianness) :
  TagLib::File(stream),
  d(new FilePrivate(endianness))
{
  if(isOpen())
    read();
}

unsigned int RIFF::File::riffSize() const
{
  return d->size;
}

unsigned int RIFF::File::chunkCount() const
{
  return d->chunks.size();
}

unsigned int RIFF::File::chunkDataSize(unsigned int i) const
{
  if(i >= d->chunks.size()) {
    debug("RIFF::File::chunkPadding() - Index out of range. Returning 0.");
    return 0;
  }

  return d->chunks[i].size;
}

unsigned int RIFF::File::chunkOffset(unsigned int i) const
{
  if(i >= d->chunks.size()) {
    debug("RIFF::File::chunkPadding() - Index out of range. Returning 0.");
    return 0;
  }

  return d->chunks[i].offset;
}

unsigned int RIFF::File::chunkPadding(unsigned int i) const
{
  if(i >= d->chunks.size()) {
    debug("RIFF::File::chunkPadding() - Index out of range. Returning 0.");
    return 0;
  }

  return d->chunks[i].padding;
}

ByteVector RIFF::File::chunkName(unsigned int i) const
{
  if(i >= d->chunks.size()) {
    debug("RIFF::File::chunkName() - Index out of range. Returning an empty vector.");
    return ByteVector();
  }

  return d->chunks[i].name;
}

ByteVector RIFF::File::chunkData(unsigned int i)
{
  if(i >= d->chunks.size()) {
    debug("RIFF::File::chunkData() - Index out of range. Returning an empty vector.");
    return ByteVector();
  }

  seek(d->chunks[i].offset);
  return readBlock(d->chunks[i].size);
}

void RIFF::File::setChunkData(unsigned int i, const ByteVector &data)
{
  if(i >= d->chunks.size()) {
    debug("RIFF::File::setChunkData() - Index out of range.");
    return;
  }

  // Now update the specific chunk

  std::vector<Chunk>::iterator it = d->chunks.begin();
  std::advance(it, i);

  const int originalSize = it->size + it->padding;

  writeChunk(it->name, data, it->offset - 8, it->size + it->padding + 8);

  it->size    = data.size();
  it->padding = data.size() % 1;

  const int diff = it->size + it->padding - originalSize;

  // Now update the internal offsets

  for(++it; it != d->chunks.end(); ++it)
    it->offset += diff;

  // Update the global size.

  updateGlobalSize();
}

void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data)
{
  setChunkData(name, data, false);
}

void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate)
{
  if(d->chunks.size() == 0) {
    debug("RIFF::File::setChunkData - No valid chunks found.");
    return;
  }

  if(alwaysCreate && name != "LIST") {
    debug("RIFF::File::setChunkData - alwaysCreate should be used for only \"LIST\" chunks.");
    return;
  }

  if(!alwaysCreate) {
    for(unsigned int i = 0; i < d->chunks.size(); i++) {
      if(d->chunks[i].name == name) {
        setChunkData(i, data);
        return;
      }
    }
  }

  // Couldn't find an existing chunk, so let's create a new one.

  // Adjust the padding of the last chunk to place the new chunk at even position.

  Chunk &last = d->chunks.back();

  long offset = last.offset + last.size + last.padding;
  if(offset & 1) {
    if(last.padding == 1) {
      last.padding = 0; // This should not happen unless the file is corrupted.
      offset--;
      removeBlock(offset, 1);
    }
    else {
      insert(ByteVector("\0", 1), offset, 0);
      last.padding = 1;
      offset++;
    }
  }

  // Now add the chunk to the file.

  writeChunk(name, data, offset, 0);

  // And update our internal structure

  Chunk chunk;
  chunk.name    = name;
  chunk.size    = data.size();
  chunk.offset  = offset + 8;
  chunk.padding = data.size() % 2;

  d->chunks.push_back(chunk);

  // Update the global size.

  updateGlobalSize();
}

void RIFF::File::removeChunk(unsigned int i)
{
  if(i >= d->chunks.size()) {
    debug("RIFF::File::removeChunk() - Index out of range.");
    return;
  }

  std::vector<Chunk>::iterator it = d->chunks.begin();
  std::advance(it, i);

  const unsigned int removeSize = it->size + it->padding + 8;
  removeBlock(it->offset - 8, removeSize);
  it = d->chunks.erase(it);

  for(; it != d->chunks.end(); ++it)
    it->offset -= removeSize;

  // Update the global size.

  updateGlobalSize();
}

void RIFF::File::removeChunk(const ByteVector &name)
{
  for(int i = d->chunks.size() - 1; i >= 0; --i) {
    if(d->chunks[i].name == name)
      removeChunk(i);
  }
}

////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

void RIFF::File::read()
{
  const bool bigEndian = (d->endianness == BigEndian);

  long offset = tell();

  offset += 4;
  d->sizeOffset = offset;

  seek(offset);
  d->size = readBlock(4).toUInt(bigEndian);

  offset += 8;
  seek(offset);

  // + 8: chunk header at least, fix for additional junk bytes
  while(offset + 8 <= length()) {

    seek(offset);
    const ByteVector   chunkName = readBlock(4);
    const unsigned int chunkSize = readBlock(4).toUInt(bigEndian);

    if(!isValidChunkName(chunkName)) {
      debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid ID");
      setValid(false);
      break;
    }

    if(static_cast<long long>(tell()) + chunkSize > length()) {
      debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid size (larger than the file size)");
      setValid(false);
      break;
    }

    offset += 8;

    Chunk chunk;
    chunk.name   = chunkName;
    chunk.size   = chunkSize;
    chunk.offset = offset;

    offset += chunk.size;

    seek(offset);

    // Check padding

    chunk.padding = 0;

    if(offset & 1) {
      const ByteVector iByte = readBlock(1);
      if(iByte.size() == 1 && iByte[0] == '\0') {
        chunk.padding = 1;
        offset++;
      }
    }

    d->chunks.push_back(chunk);
  }
}

void RIFF::File::writeChunk(const ByteVector &name, const ByteVector &data,
                            unsigned long offset, unsigned long replace)
{
  ByteVector combined;

  combined.append(name);
  combined.append(ByteVector::fromUInt(data.size(), d->endianness == BigEndian));
  combined.append(data);

  if(data.size() & 1)
    combined.resize(combined.size() + 1, '\0');

  insert(combined, offset, replace);
}

void RIFF::File::updateGlobalSize()
{
  const Chunk first = d->chunks.front();
  const Chunk last  = d->chunks.back();
  d->size = last.offset + last.size + last.padding - first.offset + 12;

  const ByteVector data = ByteVector::fromUInt(d->size, d->endianness == BigEndian);
  insert(data, d->sizeOffset, 4);
}
<commit_msg>Remove some useless seek()/tell() from RIFF::File.<commit_after>/***************************************************************************
    copyright            : (C) 2002 - 2008 by Scott Wheeler
    email                : wheeler@kde.org
 ***************************************************************************/

/***************************************************************************
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License version   *
 *   2.1 as published by the Free Software Foundation.                     *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful, but   *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA         *
 *   02110-1301  USA                                                       *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#include <algorithm>
#include <vector>

#include <tbytevector.h>
#include <tdebug.h>
#include <tstring.h>

#include "rifffile.h"
#include "riffutils.h"

using namespace TagLib;

struct Chunk
{
  ByteVector   name;
  unsigned int offset;
  unsigned int size;
  unsigned int padding;
};

class RIFF::File::FilePrivate
{
public:
  FilePrivate(Endianness endianness) :
    endianness(endianness),
    size(0),
    sizeOffset(0) {}

  const Endianness endianness;

  unsigned int size;
  long sizeOffset;

  std::vector<Chunk> chunks;
};

////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

RIFF::File::~File()
{
  delete d;
}

////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////

RIFF::File::File(FileName file, Endianness endianness) :
  TagLib::File(file),
  d(new FilePrivate(endianness))
{
  if(isOpen())
    read();
}

RIFF::File::File(IOStream *stream, Endianness endianness) :
  TagLib::File(stream),
  d(new FilePrivate(endianness))
{
  if(isOpen())
    read();
}

unsigned int RIFF::File::riffSize() const
{
  return d->size;
}

unsigned int RIFF::File::chunkCount() const
{
  return d->chunks.size();
}

unsigned int RIFF::File::chunkDataSize(unsigned int i) const
{
  if(i >= d->chunks.size()) {
    debug("RIFF::File::chunkPadding() - Index out of range. Returning 0.");
    return 0;
  }

  return d->chunks[i].size;
}

unsigned int RIFF::File::chunkOffset(unsigned int i) const
{
  if(i >= d->chunks.size()) {
    debug("RIFF::File::chunkPadding() - Index out of range. Returning 0.");
    return 0;
  }

  return d->chunks[i].offset;
}

unsigned int RIFF::File::chunkPadding(unsigned int i) const
{
  if(i >= d->chunks.size()) {
    debug("RIFF::File::chunkPadding() - Index out of range. Returning 0.");
    return 0;
  }

  return d->chunks[i].padding;
}

ByteVector RIFF::File::chunkName(unsigned int i) const
{
  if(i >= d->chunks.size()) {
    debug("RIFF::File::chunkName() - Index out of range. Returning an empty vector.");
    return ByteVector();
  }

  return d->chunks[i].name;
}

ByteVector RIFF::File::chunkData(unsigned int i)
{
  if(i >= d->chunks.size()) {
    debug("RIFF::File::chunkData() - Index out of range. Returning an empty vector.");
    return ByteVector();
  }

  seek(d->chunks[i].offset);
  return readBlock(d->chunks[i].size);
}

void RIFF::File::setChunkData(unsigned int i, const ByteVector &data)
{
  if(i >= d->chunks.size()) {
    debug("RIFF::File::setChunkData() - Index out of range.");
    return;
  }

  // Now update the specific chunk

  std::vector<Chunk>::iterator it = d->chunks.begin();
  std::advance(it, i);

  const int originalSize = it->size + it->padding;

  writeChunk(it->name, data, it->offset - 8, it->size + it->padding + 8);

  it->size    = data.size();
  it->padding = data.size() % 1;

  const int diff = it->size + it->padding - originalSize;

  // Now update the internal offsets

  for(++it; it != d->chunks.end(); ++it)
    it->offset += diff;

  // Update the global size.

  updateGlobalSize();
}

void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data)
{
  setChunkData(name, data, false);
}

void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate)
{
  if(d->chunks.size() == 0) {
    debug("RIFF::File::setChunkData - No valid chunks found.");
    return;
  }

  if(alwaysCreate && name != "LIST") {
    debug("RIFF::File::setChunkData - alwaysCreate should be used for only \"LIST\" chunks.");
    return;
  }

  if(!alwaysCreate) {
    for(unsigned int i = 0; i < d->chunks.size(); i++) {
      if(d->chunks[i].name == name) {
        setChunkData(i, data);
        return;
      }
    }
  }

  // Couldn't find an existing chunk, so let's create a new one.

  // Adjust the padding of the last chunk to place the new chunk at even position.

  Chunk &last = d->chunks.back();

  long offset = last.offset + last.size + last.padding;
  if(offset & 1) {
    if(last.padding == 1) {
      last.padding = 0; // This should not happen unless the file is corrupted.
      offset--;
      removeBlock(offset, 1);
    }
    else {
      insert(ByteVector("\0", 1), offset, 0);
      last.padding = 1;
      offset++;
    }
  }

  // Now add the chunk to the file.

  writeChunk(name, data, offset, 0);

  // And update our internal structure

  Chunk chunk;
  chunk.name    = name;
  chunk.size    = data.size();
  chunk.offset  = offset + 8;
  chunk.padding = data.size() % 2;

  d->chunks.push_back(chunk);

  // Update the global size.

  updateGlobalSize();
}

void RIFF::File::removeChunk(unsigned int i)
{
  if(i >= d->chunks.size()) {
    debug("RIFF::File::removeChunk() - Index out of range.");
    return;
  }

  std::vector<Chunk>::iterator it = d->chunks.begin();
  std::advance(it, i);

  const unsigned int removeSize = it->size + it->padding + 8;
  removeBlock(it->offset - 8, removeSize);
  it = d->chunks.erase(it);

  for(; it != d->chunks.end(); ++it)
    it->offset -= removeSize;

  // Update the global size.

  updateGlobalSize();
}

void RIFF::File::removeChunk(const ByteVector &name)
{
  for(int i = d->chunks.size() - 1; i >= 0; --i) {
    if(d->chunks[i].name == name)
      removeChunk(i);
  }
}

////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

void RIFF::File::read()
{
  const bool bigEndian = (d->endianness == BigEndian);

  long offset = tell();

  offset += 4;
  d->sizeOffset = offset;

  seek(offset);
  d->size = readBlock(4).toUInt(bigEndian);

  offset += 8;

  // + 8: chunk header at least, fix for additional junk bytes
  while(offset + 8 <= length()) {

    seek(offset);
    const ByteVector   chunkName = readBlock(4);
    const unsigned int chunkSize = readBlock(4).toUInt(bigEndian);

    if(!isValidChunkName(chunkName)) {
      debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid ID");
      setValid(false);
      break;
    }

    if(static_cast<long long>(offset) + 8 + chunkSize > length()) {
      debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid size (larger than the file size)");
      setValid(false);
      break;
    }

    Chunk chunk;
    chunk.name    = chunkName;
    chunk.size    = chunkSize;
    chunk.offset  = offset + 8;
    chunk.padding = 0;

    offset = chunk.offset + chunk.size;

    // Check padding

    if(offset & 1) {
      seek(offset);
      const ByteVector iByte = readBlock(1);
      if(iByte.size() == 1 && iByte[0] == '\0') {
        chunk.padding = 1;
        offset++;
      }
    }

    d->chunks.push_back(chunk);
  }
}

void RIFF::File::writeChunk(const ByteVector &name, const ByteVector &data,
                            unsigned long offset, unsigned long replace)
{
  ByteVector combined;

  combined.append(name);
  combined.append(ByteVector::fromUInt(data.size(), d->endianness == BigEndian));
  combined.append(data);

  if(data.size() & 1)
    combined.resize(combined.size() + 1, '\0');

  insert(combined, offset, replace);
}

void RIFF::File::updateGlobalSize()
{
  const Chunk first = d->chunks.front();
  const Chunk last  = d->chunks.back();
  d->size = last.offset + last.size + last.padding - first.offset + 12;

  const ByteVector data = ByteVector::fromUInt(d->size, d->endianness == BigEndian);
  insert(data, d->sizeOffset, 4);
}
<|endoftext|>