/*
 * Copyright (c) 2016-2021 lymastee, All rights reserved.
 * Contact: lymastee@hotmail.com
 *
 * This file is part of the gslib project.
 *
 * 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.
 */

#pragma once

#ifndef treeop_00fc8cde_c6b6_464d_b51d_71eaad31b9ef_h
#define treeop_00fc8cde_c6b6_464d_b51d_71eaad31b9ef_h

#include <gslib/tree.h>

__gslib_begin__

/*
 * The original tree was created from top to bottom, to implement the new operation it might be needed
 * to create the tree from bottom to top.
 * These classes were designed to achieve that.
 * Caution:
 * You'd better NOT include me in headers.
 * You'd better use def_tr$ macros in a function scope.
 * with argumented def_tr$ versions, IE. like def_tr$_v1, def_tr$_v2, and so on...
 * the tree should NOT be a copy wrapper one.
 */

template<class _tree>
class treeop_helper
{
public:
    typedef _tree tree;
    typedef typename _tree::value value;
    typedef typename _tree::wrapper wrapper;
    typedef typename _tree::alloc alloc;
    typedef typename _tree::const_iterator const_iterator;
    typedef typename _tree::iterator iterator;
    typedef typename wrapper::children children;
};

template<class _tree>
class treeop_set
{
public:
    typedef treeop_helper<_tree> helper;
    typedef typename helper::tree tree;
    typedef typename helper::value value;
    typedef typename helper::wrapper wrapper;
    typedef typename helper::alloc alloc;
    typedef typename helper::const_iterator const_iterator;
    typedef typename helper::iterator iterator;
    typedef typename helper::children children;
    typedef children opset;

public:
    opset           _opset;

public:
    treeop_set() {}
    treeop_set(wrapper* w) { _opset.init(w); }
    treeop_set(treeop_set& rhs) { _opset.swap(rhs.dump()); }
    bool empty() const { return _opset.empty(); }
    bool unary() const { return _opset.size() == 1; }
    opset& dump() { return _opset; }
    treeop_set& operator+ (treeop_set& rhs) { return connect(rhs); }
    void acquire(treeop_set& ops)
    {
        assert(unary());
        wrapper* m = _opset.front();
        assert(m);
        m->acquire_children(ops.dump());
    }
    treeop_set& sub(treeop_set& ops)
    {
        acquire(ops);
        return *this;
    }
    treeop_set& connect(treeop_set& ops)
    {
        _opset.connect(ops.dump());
        return *this;
    }
    wrapper* detach()
    {
        assert(unary());
        wrapper* w = _opset.front();
        _opset.reset();
        return w;
    }
};

template<class _tree>
class treeop
{
public:
    typedef treeop_helper<_tree> helper;
    typedef typename helper::tree tree;
    typedef typename helper::value value;
    typedef typename helper::wrapper wrapper;
    typedef typename helper::alloc alloc;
    typedef typename helper::const_iterator const_iterator;
    typedef typename helper::iterator iterator;
    typedef typename helper::children children;
    typedef treeop_set<_tree> tropset;
    typedef children opset;

public:
    treeop(_tree& tr) { _tr = &tr; }
    void create(tropset& ops) { _tr->set_root(ops.detach()); }

protected:
    _tree*          _tr;
};

/*
 * Usage:
 * For example,
 * 1.if we wanted to create a tree in the following structure,
 *   { a = 1, b = "hello"; }
 *        { a = 2, b = "bingo"; }
 *            { a = 3, b = "bravo"; }
 *        { a = 6, b = "amigo"; }
 *   and the node was for: struct node { int a; string b; };
 *   We could write it like,
 *   typedef tree<node, _treenode_wrapper<node> > mytree;
 *   def_tr$(node1, mytree, ([&](){ a = 1, b = "hello"; }));
 *   def_tr$(node2, mytree, ([&](){ a = 2, b = "bingo"; }));
 *   def_tr$(node3, mytree, ([&](){ a = 3, b = "bravo"; }));
 *   def_tr$(node4, mytree, ([&](){ a = 6, b = "amigo"; }));
 *   tr$(node1).sub(
 *      tr$(node2).sub(
 *          tr$(node3)
 *          )
 *      + tr$(node4)
 *      );
 * 2.if your compiler doesn't support c++0x style of lambda,
 *   you may modify the def_tr$ micro a little bit, like assignments;
 *   then you could temporally write it like:
 *   typedef tree<node, _treenode_wrapper<node> > mytree;
 *   def_tr$(node1, mytree, (a = 1, b = "hello";));
 *   it works, just maybe unsafe.
 */

#define def_tr$(name, treeop, prototype, assignments) \
struct tag##name \
{ \
    typedef treeop::wrapper wrapper; \
    typedef treeop::value value; \
    typedef treeop::alloc alloc; \
    typedef treeop::tropset tropset; \
    struct constructor: \
        public prototype \
    { \
        constructor() { (assignments)(); } \
    }; \
    tropset create() \
    { \
        wrapper* w = alloc::born(); \
        w->born<constructor>(); \
        return tropset(w); \
    } \
} name;

#define def_tr$_v1(name, treeop, prototype, arg1, assignments) \
struct tag##name \
{ \
    typedef treeop::wrapper wrapper; \
    typedef treeop::value value; \
    typedef treeop::alloc alloc; \
    typedef treeop::tropset tropset; \
    typedef decltype(arg1) type1; \
    type1& ref_arg1; \
    tag##name(type1& arg1): ref_arg1(arg1) {} \
    struct constructor: \
        public prototype \
    { \
        constructor(type1& arg1) { (assignments)(arg1); } \
    }; \
    tropset create() \
    { \
        wrapper* w = alloc::born(); \
        w->born<constructor>(ref_arg1); \
        return tropset(w); \
    } \
} name(arg1);

#define def_tr$_v2(name, treeop, prototype, arg1, arg2, assignments) \
struct tag##name \
{ \
    typedef treeop::wrapper wrapper; \
    typedef treeop::value value; \
    typedef treeop::alloc alloc; \
    typedef treeop::tropset tropset; \
    typedef decltype(arg1) type1; \
    typedef decltype(arg2) type2; \
    type1& ref_arg1; \
    type2& ref_arg2; \
    tag##name(type1& arg1, type2& arg2): ref_arg1(arg1), ref_arg2(arg2) {} \
    struct constructor: \
        public prototype \
    { \
        constructor(type1& arg1, type2& arg2) { (assignments)(arg1, arg2); } \
    }; \
    tropset create() \
    { \
        wrapper* w = alloc::born(); \
        w->born<constructor>(ref_arg1, ref_arg2); \
        return tropset(w); \
    } \
} name(arg1, arg2);

#define def_tr$_v3(name, treeop, prototype, arg1, arg2, arg3, assignments) \
struct tag##name \
{ \
    typedef treeop::wrapper wrapper; \
    typedef treeop::value value; \
    typedef treeop::alloc alloc; \
    typedef treeop::tropset tropset; \
    typedef decltype(arg1) type1; \
    typedef decltype(arg2) type2; \
    typedef decltype(arg3) type3; \
    type1& ref_arg1; \
    type2& ref_arg2; \
    type3& ref_arg3; \
    tag##name(type1& arg1, type2& arg2, type3& arg3): ref_arg1(arg1), ref_arg2(arg2), ref_arg3(arg3) {} \
    struct constructor: \
        public prototype \
    { \
        constructor(type1& arg1, type2& arg2, type3& arg3) { (assignments)(arg1, arg2, arg3); } \
    }; \
    tropset create() \
    { \
        wrapper* w = alloc::born(); \
        w->born<constructor>(ref_arg1, ref_arg2, ref_arg3); \
        return tropset(w); \
    } \
} name(arg1, arg2, arg3);

#define tr$(name) (name.create())

__gslib_end__

#endif


//        Copyright The Authors 2018.
//    Distributed under the 3-Clause BSD License.
//    (See accompanying file LICENSE or copy at
//   https://opensource.org/licenses/BSD-3-Clause)

#pragma once

#include <cstdint>      // for std::uint8_t etc.
#include <type_traits>  // for std::underlying_type_t<>

#include <gsl/gsl>  // for gsl::span

#include <p2p/kademlia/buffer.h>
#include <p2p/kademlia/node.h>

namespace blocxxi {
namespace p2p {
namespace kademlia {

/*!
 * @brief Represents a message header block.
 *
 * In its serialized form, every message is composed of a header and a body. The
 * header contains the protocol version, the message body type, the ID (hash
 * 160) of the source node and a random token (hash 160) used to correlate
 * requests and responses.
 *
 * A serialized header uses the following layout:
 * ```
 *      <-----------------><-------...-------><-------...------->
 *            1 byte             20 bytes           20 bytes
 *        4 bits | 4 bits      source id          random token
 *        version  type
 *
 * ```
 */
struct Header final {
  /// Protocol version
  enum class Version : std::uint8_t {
    V1 = 1,
  } version_{Version::V1};

  /// Message body type
  enum class MessageType : std::uint8_t {
    PING_REQUEST,
    PING_RESPONSE,
    STORE_REQUEST,
    FIND_NODE_REQUEST,
    FIND_NODE_RESPONSE,
    FIND_VALUE_REQUEST,
    FIND_VALUE_RESPONSE,
  } type_{MessageType::PING_REQUEST};

  /// ID of the source node (Hash 160)
  Node::IdType source_id_;
  /// A random token (Hash 160)
  blocxxi::crypto::Hash160 random_token_;
};

/*!
 * @brief Generalized function that can take any scoped enumerator and return
 * a compile time constant of the underlying type.
 *
 * Used specifically for the serialization and deserialization of headers. For
 * more details on the rational see Scott Meyers, Effective Modern C++ Item 10.
 *
 * @tparam TEnum the scoped enum class type.
 * @param [in] e_value any value of the scoped enum class.
 * @return a compile time constant of the underlying type corresponding to
 * e_value.
 */
template <typename TEnum>
constexpr std::underlying_type_t<TEnum> ToUnderlying(TEnum e_value) noexcept {
  return static_cast<std::underlying_type_t<TEnum>>(e_value);
}

/*!
 * @brief A template trait class used to carry extra information about the
 * messages types in use.
 *
 * The traits class T<M> lets us record such extra information about a message
 * class M, without requiring any change at all to M. Such extra information is
 * used to generically serialize and deserialize messages.
 *
 * @tparam TMessageBody the type of the message body described by this traits
 * class.
 */
template <typename TMessageBody>
struct MessageTraits;

/*!
 * @brief Serialize the header into the given buffer, which is expected to be
 * able to accomodate the header binary size (41 bytes) or expand as needed.
 *
 * @param [in] header header object to be serialized.
 * @param [out] buffer destination buffer for the header serialized binary form.
 */
void Serialize(Header const &header, Buffer &buffer);

/*!
 * @brief Deserialize the contents of the buffer into a Header object.
 *
 * @param [in] buffer a span over a range of bytes (std::uint8_t) representing
 * the header binary data.
 * @param [out] header the deserialized resulting header object.
 * @return an error code indicating success or failure of the deserialization.
 */
std::size_t Deserialize(BufferReader const &buffer, Header &header);

/// FIND_NODE request message body.
struct FindNodeRequestBody final {
  /// The hash 160 id of the node to find.
  Node::IdType node_id_;
};

/// Message traits template specialization for the FIND_NODE request message.
template <>
struct MessageTraits<FindNodeRequestBody> {
  static constexpr Header::MessageType TYPE_ID =
      Header::MessageType::FIND_NODE_REQUEST;
};

/*!
 * @brief Serialize a FIND_NODE request body into the given buffer.
 *
 * @param [in] body the request body.
 * @param [out] buffer the destination buffer.
 */
void Serialize(FindNodeRequestBody const &body, Buffer &buffer);

/*!
 * @brief Deserialize a FIND_NODE request body from the given buffer.
 *
 * @param [in] buffer the input buffer.
 * @param [out] body the resulting request body.
 * @return the number of consumed bytes from the input buffer. Subsequent
 * deserialization from the buffer need to start after the consumed bytes.
 */
std::size_t Deserialize(BufferReader const &buffer, FindNodeRequestBody &body);

/// FIND_NODE response message body.
struct FindNodeResponseBody final {
  /// The list of nodes in the response.
  std::vector<Node> peers_;
};

/// Message traits template specialization for the FIND_NODE response message.
template <>
struct MessageTraits<FindNodeResponseBody> {
  static constexpr Header::MessageType TYPE_ID =
      Header::MessageType::FIND_NODE_RESPONSE;
};

/*!
 * @brief Serialize a FIND_NODE response body into the given buffer.
 *
 * @param [in] body the response body.
 * @param [out] buffer the destination buffer.
 */
void Serialize(FindNodeResponseBody const &body, Buffer &buffer);

/*!
 * @brief Deserialize a FIND_NODE response body from the given buffer.
 *
 * @param [in] buffer the input buffer.
 * @param [out] body the resulting response body.
 * @return the number of consumed bytes from the input buffer. Subsequent
 * deserialization from the buffer need to start after the consumed bytes.
 */
std::size_t Deserialize(BufferReader const &buffer, FindNodeResponseBody &body);

/// FIND_VALUE request message body.
struct FindValueRequestBody final {
  /// The hash 160 key of the value to find.
  blocxxi::crypto::Hash160 value_key_;
};

/// Message traits template specialization for the FIND_VALUE request message.
template <>
struct MessageTraits<FindValueRequestBody> {
  static constexpr Header::MessageType TYPE_ID =
      Header::MessageType::FIND_VALUE_REQUEST;
};

/*!
 * @brief Serialize a FIND_VALUE request body into the given buffer.
 *
 * @param [in] body the request body.
 * @param [out] buffer the destination buffer.
 */
void Serialize(FindValueRequestBody const &body, Buffer &buffer);

/*!
 * @brief Deserialize a FIND_VALUE request body from the given buffer.
 *
 * @param [in] buffer the input buffer.
 * @param [out] body the resulting request body.
 * @return the number of consumed bytes from the input buffer. Subsequent
 * deserialization from the buffer need to start after the consumed bytes.
 */
std::size_t Deserialize(BufferReader const &buffer, FindValueRequestBody &body);

/// FIND_VALUE response message body.
struct FindValueResponseBody final {
  /// The value data  as a vector of bytes.
  std::vector<std::uint8_t> data_;
};

/// Message traits template specialization for the FIND_VALUE response message.
template <>
struct MessageTraits<FindValueResponseBody> {
  static constexpr Header::MessageType TYPE_ID =
      Header::MessageType::FIND_VALUE_RESPONSE;
};

/*!
 * @brief Serialize a FIND_VALUE response body into the given buffer.
 *
 * @param [in] body the response body.
 * @param [out] buffer the destination buffer.
 */
void Serialize(FindValueResponseBody const &body, Buffer &buffer);

/*!
 * @brief Deserialize a FIND_VALUE response body from the given buffer.
 *
 * @param [in] buffer the input buffer.
 * @param [out] body the resulting response body.
 * @return the number of consumed bytes from the input buffer. Subsequent
 * deserialization from the buffer need to start after the consumed bytes.
 */
std::size_t Deserialize(BufferReader const &buffer,
                        FindValueResponseBody &body);

/// STORE_VALUE request message body.
struct StoreValueRequestBody final {
  /// The hash 160 of the data key.
  blocxxi::crypto::Hash160 data_key_;
  /// The data value as a vector of bytes.
  std::vector<std::uint8_t> data_value_;
};

/// Message traits template specialization for the STORE_VALUE request message.
template <>
struct MessageTraits<StoreValueRequestBody> {
  static constexpr Header::MessageType TYPE_ID =
      Header::MessageType::STORE_REQUEST;
};

/*!
 * @brief Serialize a STORE_VALUE request body into the given buffer.
 *
 * @param [in] body the request body.
 * @param [out] buffer the destination buffer.
 */
void Serialize(StoreValueRequestBody const &body, Buffer &buffer);

/*!
 * @brief Deserialize a STORE_VALUE request body from the given buffer.
 *
 * @param [in] buffer the input buffer.
 * @param [out] body the resulting request body.
 * @return the number of consumed bytes from the input buffer. Subsequent
 * deserialization from the buffer need to start after the consumed bytes.
 */
std::size_t Deserialize(BufferReader const &buffer,
                        StoreValueRequestBody &body);

}  // namespace kademlia
}  // namespace p2p
}  // namespace blocxxi


#ifndef SEARCHPATTERNHEXMATCHER_HHHHH
#define SEARCHPATTERNHEXMATCHER_HHHHH

#include <gsl/string_span>
#include <vector>
#include <string>
#include <algorithm>

#include "SearchPatternBase.h"

namespace MPSig {
    namespace detail {
        class SearchPatternHexMatcher final : public SearchPatternBase {
        private:
            std::vector<std::pair<char, bool>> m_compiledPattern;
        public:
            SearchPatternHexMatcher(gsl::cstring_span<-1> hexPattern);

            virtual SearchPatternBase::ExecFirstResult<gsl_span_cit_t> ExecFirst(const MPSig::SigScannerMemoryData& data, gsl_span_cit_t begin, gsl_span_cit_t end) const override;
            virtual SearchPatternBase::ExecFirstResult<gsl_span_crit_t> ExecFirst(const MPSig::SigScannerMemoryData& data, gsl_span_crit_t begin, gsl_span_crit_t end) const override;

            virtual SearchPatternBase::ExecFirstResult<gsl_span_cit_t> ExecDepend(const MPSig::SigScannerMemoryData& data, gsl_span_cit_t begin, gsl_span_cit_t end) const override;
            virtual SearchPatternBase::ExecFirstResult<gsl_span_crit_t> ExecDepend(const MPSig::SigScannerMemoryData& data, gsl_span_crit_t begin, gsl_span_crit_t end) const override;

            virtual std::unique_ptr<SearchPatternBase> Clone() const override;
        };

    }
}

#endif


/*
 *  Copyright (C) 2021 FISCO BCOS.
 *  SPDX-License-Identifier: Apache-2.0
 *  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.
 *
 * @brief scale codec
 * @file Scale.h
 */
#pragma once
#include "Common.h"
#include "ScaleDecoderStream.h"
#include "ScaleEncoderStream.h"
#include <boost/system/system_error.hpp>
#include <boost/throw_exception.hpp>
#include <gsl/span>
#include <vector>

namespace bcos
{
namespace codec
{
namespace scale
{
/**
 * @brief convenience function for encoding primitives data to stream
 * @tparam Args primitive types to be encoded
 * @param args data to encode
 * @return encoded data
 */
template <typename... Args>
void encode(std::shared_ptr<bytes> _encodeData, Args&&... _args)
{
    ScaleEncoderStream s;
    (s << ... << std::forward<Args>(_args));
    *_encodeData = s.data();
}

template <typename... Args>
bytes encode(Args&&... _args)
{
    ScaleEncoderStream s;
    (s << ... << std::forward<Args>(_args));
    return s.data();
}

/**
 * @brief convenience function for decoding primitives data from stream
 * @tparam T primitive type that is decoded from provided span
 * @param span of bytes with encoded data
 * @return decoded T
 */
template <class T>
void decode(T& _decodedObject, gsl::span<byte const> _span)
{
    ScaleDecoderStream s(_span);
    s >> _decodedObject;
}

template <class T>
T decode(gsl::span<byte const> _span)
{
    T t;
    decode(t, _span);
    return t;
}
}  // namespace scale
}  // namespace codec
}  // namespace bcos


// Copyright © Matt Jones and Contributors. Licensed under the MIT Licence (MIT). See LICENCE.md in the repository root
// for more information.

#ifndef NOVELRT_INPUT_H
#define NOVELRT_INPUT_H

// Input Dependencies
#include "NovelRT/LoggingService.h"
#include "NovelRT/Maths/Maths.h"
#include "NovelRT/Timing/Timestamp.h"
#include <gsl/span>
#include <map>
#include <string>

/**
 * @Brief The input plugin API.
 */
namespace NovelRT::Input
{
    enum class KeyState;
    class IInputDevice;
    class NovelKey;
    struct InputAction;
}

// clang-format off
// Input Types
#include "IInputDevice.h"
#include "KeyState.h"
#include "NovelKey.h"
#include "InputAction.h"
// clang-format on

#endif // NOVELRT_INPUT_H


/* vector/gsl_vector_char.h
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef __GSL_VECTOR_CHAR_H__
#define __GSL_VECTOR_CHAR_H__

#if !defined( GSL_FUN )
#  if !defined( GSL_DLL )
#    define GSL_FUN extern
#  elif defined( BUILD_GSL_DLL )
#    define GSL_FUN extern __declspec(dllexport)
#  else
#    define GSL_FUN extern __declspec(dllimport)
#  endif
#endif

#include <stdlib.h>
#include <gsl/gsl_types.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_inline.h>
#include <gsl/gsl_check_range.h>
#include <gsl/gsl_block_char.h>

#undef __BEGIN_DECLS
#undef __END_DECLS
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS /* empty */
# define __END_DECLS /* empty */
#endif

__BEGIN_DECLS

typedef struct
{
  size_t size;
  size_t stride;
  char *data;
  gsl_block_char *block;
  int owner;
}
gsl_vector_char;

typedef struct
{
  gsl_vector_char vector;
} _gsl_vector_char_view;

typedef _gsl_vector_char_view gsl_vector_char_view;

typedef struct
{
  gsl_vector_char vector;
} _gsl_vector_char_const_view;

typedef const _gsl_vector_char_const_view gsl_vector_char_const_view;

/* Allocation */

GSL_FUN gsl_vector_char *gsl_vector_char_alloc (const size_t n);
GSL_FUN gsl_vector_char *gsl_vector_char_calloc (const size_t n);

GSL_FUN gsl_vector_char *gsl_vector_char_alloc_from_block (gsl_block_char * b,
                                                     const size_t offset,
                                                     const size_t n,
                                                     const size_t stride);

GSL_FUN gsl_vector_char *gsl_vector_char_alloc_from_vector (gsl_vector_char * v,
                                                      const size_t offset,
                                                      const size_t n,
                                                      const size_t stride);

GSL_FUN void gsl_vector_char_free (gsl_vector_char * v);

/* Views */

GSL_FUN _gsl_vector_char_view
gsl_vector_char_view_array (char *v, size_t n);

GSL_FUN _gsl_vector_char_view
gsl_vector_char_view_array_with_stride (char *base,
                                         size_t stride,
                                         size_t n);

GSL_FUN _gsl_vector_char_const_view
gsl_vector_char_const_view_array (const char *v, size_t n);

GSL_FUN _gsl_vector_char_const_view
gsl_vector_char_const_view_array_with_stride (const char *base,
                                               size_t stride,
                                               size_t n);

GSL_FUN _gsl_vector_char_view
gsl_vector_char_subvector (gsl_vector_char *v,
                            size_t i,
                            size_t n);

GSL_FUN _gsl_vector_char_view
gsl_vector_char_subvector_with_stride (gsl_vector_char *v,
                                        size_t i,
                                        size_t stride,
                                        size_t n);

GSL_FUN _gsl_vector_char_const_view
gsl_vector_char_const_subvector (const gsl_vector_char *v,
                                  size_t i,
                                  size_t n);

GSL_FUN _gsl_vector_char_const_view
gsl_vector_char_const_subvector_with_stride (const gsl_vector_char *v,
                                              size_t i,
                                              size_t stride,
                                              size_t n);

/* Operations */

GSL_FUN void gsl_vector_char_set_zero (gsl_vector_char * v);
GSL_FUN void gsl_vector_char_set_all (gsl_vector_char * v, char x);
GSL_FUN int gsl_vector_char_set_basis (gsl_vector_char * v, size_t i);

GSL_FUN int gsl_vector_char_fread (FILE * stream, gsl_vector_char * v);
GSL_FUN int gsl_vector_char_fwrite (FILE * stream, const gsl_vector_char * v);
GSL_FUN int gsl_vector_char_fscanf (FILE * stream, gsl_vector_char * v);
GSL_FUN int gsl_vector_char_fprintf (FILE * stream, const gsl_vector_char * v,
                              const char *format);

GSL_FUN int gsl_vector_char_memcpy (gsl_vector_char * dest, const gsl_vector_char * src);

GSL_FUN int gsl_vector_char_reverse (gsl_vector_char * v);

GSL_FUN int gsl_vector_char_swap (gsl_vector_char * v, gsl_vector_char * w);
GSL_FUN int gsl_vector_char_swap_elements (gsl_vector_char * v, const size_t i, const size_t j);

GSL_FUN char gsl_vector_char_max (const gsl_vector_char * v);
GSL_FUN char gsl_vector_char_min (const gsl_vector_char * v);
GSL_FUN void gsl_vector_char_minmax (const gsl_vector_char * v, char * min_out, char * max_out);

GSL_FUN size_t gsl_vector_char_max_index (const gsl_vector_char * v);
GSL_FUN size_t gsl_vector_char_min_index (const gsl_vector_char * v);
GSL_FUN void gsl_vector_char_minmax_index (const gsl_vector_char * v, size_t * imin, size_t * imax);

GSL_FUN int gsl_vector_char_add (gsl_vector_char * a, const gsl_vector_char * b);
GSL_FUN int gsl_vector_char_sub (gsl_vector_char * a, const gsl_vector_char * b);
GSL_FUN int gsl_vector_char_mul (gsl_vector_char * a, const gsl_vector_char * b);
GSL_FUN int gsl_vector_char_div (gsl_vector_char * a, const gsl_vector_char * b);
GSL_FUN int gsl_vector_char_scale (gsl_vector_char * a, const double x);
GSL_FUN int gsl_vector_char_add_constant (gsl_vector_char * a, const double x);

GSL_FUN int gsl_vector_char_isnull (const gsl_vector_char * v);
GSL_FUN int gsl_vector_char_ispos (const gsl_vector_char * v);
GSL_FUN int gsl_vector_char_isneg (const gsl_vector_char * v);
GSL_FUN int gsl_vector_char_isnonneg (const gsl_vector_char * v);

GSL_FUN INLINE_DECL char gsl_vector_char_get (const gsl_vector_char * v, const size_t i);
GSL_FUN INLINE_DECL void gsl_vector_char_set (gsl_vector_char * v, const size_t i, char x);
GSL_FUN INLINE_DECL char * gsl_vector_char_ptr (gsl_vector_char * v, const size_t i);
GSL_FUN INLINE_DECL const char * gsl_vector_char_const_ptr (const gsl_vector_char * v, const size_t i);

#ifdef HAVE_INLINE

INLINE_FUN
char
gsl_vector_char_get (const gsl_vector_char * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_VAL ("index out of range", GSL_EINVAL, 0);
    }
#endif
  return v->data[i * v->stride];
}

INLINE_FUN
void
gsl_vector_char_set (gsl_vector_char * v, const size_t i, char x)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_VOID ("index out of range", GSL_EINVAL);
    }
#endif
  v->data[i * v->stride] = x;
}

INLINE_FUN
char *
gsl_vector_char_ptr (gsl_vector_char * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_NULL ("index out of range", GSL_EINVAL);
    }
#endif
  return (char *) (v->data + i * v->stride);
}

INLINE_FUN
const char *
gsl_vector_char_const_ptr (const gsl_vector_char * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_NULL ("index out of range", GSL_EINVAL);
    }
#endif
  return (const char *) (v->data + i * v->stride);
}
#endif /* HAVE_INLINE */

__END_DECLS

#endif /* __GSL_VECTOR_CHAR_H__ */


/* -----------------------------------------------------------------------------
 * Copyright 2021 Jonathan Haigh
 * SPDX-License-Identifier: MIT
 * ---------------------------------------------------------------------------*/

#ifndef SQ_INCLUDE_GUARD_results_Filter_h_
#define SQ_INCLUDE_GUARD_results_Filter_h_

#include "core/Field.h"
#include "core/typeutil.h"
#include "parser/FilterSpec.h"

#include <gsl/gsl>
#include <memory>

namespace sq::results {

struct Filter;
using FilterPtr = std::unique_ptr<Filter>;

struct Filter {
  /**
   * Create a Filter for the given spec.
   */
  SQ_ND static FilterPtr create(const parser::FilterSpec &spec);

  /**
   * Apply this filter to a Result.
   */
  SQ_ND virtual Result operator()(Result &&result) const = 0;

  virtual ~Filter() = default;
  Filter() = default;
  Filter(const Filter &) = delete;
  Filter(Filter &&) = delete;
  Filter &operator=(const Filter &) = delete;
  Filter &operator=(Filter &&) = delete;
};

} // namespace sq::results

#endif // SQ_INCLUDE_GUARD_results_Filter_h_


#ifndef OPENMC_TALLIES_FILTER_DELAYEDGROUP_H
#define OPENMC_TALLIES_FILTER_DELAYEDGROUP_H

#include <vector>

#include <gsl/gsl>

#include "openmc/tallies/filter.h"

namespace openmc {

//==============================================================================
//! Bins outgoing fission neutrons in their delayed groups.
//!
//! The get_all_bins functionality is not actually used.  The bins are manually
//! iterated over in the scoring subroutines.
//==============================================================================

class DelayedGroupFilter : public Filter
{
public:
  //----------------------------------------------------------------------------
  // Constructors, destructors

  ~DelayedGroupFilter() = default;

  //----------------------------------------------------------------------------
  // Methods

  std::string type() const override {return "delayedgroup";}

  void from_xml(pugi::xml_node node) override;

  void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match)
  const override;

  void to_statepoint(hid_t filter_group) const override;

  std::string text_label(int bin) const override;

  //----------------------------------------------------------------------------
  // Accessors

  const std::vector<int>& groups() const { return groups_; }

  void set_groups(gsl::span<int> groups);

private:
  //----------------------------------------------------------------------------
  // Data members

  std::vector<int> groups_;
};

} // namespace openmc
#endif // OPENMC_TALLIES_FILTER_DELAYEDGROUP_H


/* spcopy.c
 *
 * Copyright (C) 2014 Patrick Alken
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <config.h>
#include <stdlib.h>
#include <math.h>
#include <gsl/gsl_spmatrix.h>
#include <gsl/gsl_errno.h>

#include "avl.c"

int
gsl_spmatrix_memcpy(gsl_spmatrix *dest, const gsl_spmatrix *src)
{
  const size_t M = src->size1;
  const size_t N = src->size2;

  if (M != dest->size1 || N != dest->size2)
    {
      GSL_ERROR("matrix sizes are different", GSL_EBADLEN);
    }
  else if (dest->sptype != src->sptype)
    {
      GSL_ERROR("cannot copy matrices of different storage formats",
                GSL_EINVAL);
    }
  else
    {
      int s = GSL_SUCCESS;
      size_t n;

      if (dest->nzmax < src->nz)
        {
          s = gsl_spmatrix_realloc(src->nz, dest);
          if (s)
            return s;
        }

      /* copy indices and data to dest */
      if (GSL_SPMATRIX_ISTRIPLET(src))
        {
          void *ptr;

          for (n = 0; n < src->nz; ++n)
            {
              dest->i[n] = src->i[n];
              dest->p[n] = src->p[n];
              dest->data[n] = src->data[n];

              /* copy binary tree data */
              ptr = avl_insert(dest->tree_data->tree, &dest->data[n]);
              if (ptr != NULL)
                {
                  GSL_ERROR("detected duplicate entry", GSL_EINVAL);
                }
            }
        }
      else if (GSL_SPMATRIX_ISCCS(src))
        {
          for (n = 0; n < src->nz; ++n)
            {
              dest->i[n] = src->i[n];
              dest->data[n] = src->data[n];
            }

          for (n = 0; n < src->size2 + 1; ++n)
            {
              dest->p[n] = src->p[n];
            }
        }
      else if (GSL_SPMATRIX_ISCRS(src))
        {
          for (n = 0; n < src->nz; ++n)
            {
              dest->i[n] = src->i[n];
              dest->data[n] = src->data[n];
            }

          for (n = 0; n < src->size1 + 1; ++n)
            {
              dest->p[n] = src->p[n];
            }
        }
      else
        {
          GSL_ERROR("invalid matrix type for src", GSL_EINVAL);
        }

      dest->nz = src->nz;

      return s;
    }
} /* gsl_spmatrix_memcpy() */


#pragma once

#include <gsl/gsl>
#include <vector>
#include <sstream>

namespace multiformats {

    //
    // Raw memory byte
    //
    using byte_t = uint8_t;

    //
    // Raw memory buffer
    //   Represents a contiguous run of byte_t elements, or a const view of it.
    //
    using buffer_t = std::vector<byte_t>;
    using bufferview_t = gsl::span<const byte_t>;

    //    Appends a buffer or a byte to a buffer
    inline buffer_t& operator += (buffer_t& _Left, bufferview_t _Right) {
        _Left.insert(_Left.end(), _Right.begin(), _Right.end());
        return _Left;
    }
    inline buffer_t& operator += (buffer_t& _Left, byte_t _Value) {
        _Left.push_back(_Value);
        return _Left;
    }

    //    Concatenates two buffers
    inline buffer_t operator + (bufferview_t _Left, bufferview_t _Right) {
        auto result = buffer_t(_Left.size() + _Right.size());
        std::copy(_Right.begin(), _Right.end(), std::copy(_Left.begin(), _Left.end(), result.begin()));
        return result;
    }

    //    Buffer comparison
    inline bool operator == (bufferview_t _Left, bufferview_t _Right) {
        return std::equal(_Left.begin(), _Left.end(), _Right.begin(), _Right.end());
    }

    inline bool operator != (bufferview_t _Left, bufferview_t _Right) {
        return !(_Left == _Right);
    }

    //
    // String and constant view of strings
    //
    using string_t = std::string;
    using stringview_t = gsl::cstring_span<>;

    inline std::vector<stringview_t> split(stringview_t s, char delim) {
        auto elems = std::vector<stringview_t>{};

        auto begin = s.begin();
        auto end = s.end();
        auto first = begin;
        while (first != end) {
            auto last = std::find(first, end, delim);
            elems.push_back(s.subspan(first - begin, last - first));
            if (last == end) break;
            first = last + 1;
        }

        return elems;
    }

    inline string_t operator+(stringview_t _Left, const string_t& _Right) { return (to_string(_Left) + _Right); }
    inline string_t operator+(const string_t& _Left, stringview_t _Right) { return (_Left + to_string(_Right)); }

    //
    // Conversions
    //   to_* methods create a new container and copy the content
    //   as_* methods return a const view of the container without copy
    //
    inline buffer_t to_buffer(stringview_t s) { return { s.begin(), s.end() }; }
    inline buffer_t to_buffer(const char* s)  { return to_buffer(gsl::ensure_z(s)); }

    inline bufferview_t as_buffer(stringview_t s) { return { reinterpret_cast<const byte_t*>(s.data()), gsl::narrow<ptrdiff_t>(s.size()) }; }
    inline stringview_t as_string(bufferview_t b) { return { reinterpret_cast<const char*>(b.data()), b.size() }; }

    inline string_t to_string(bufferview_t b) { return to_string(as_string(b)); }
}


#pragma once

#include <gsl/gsl>
#include <codecvt>
#include <locale>
#include <string>

#ifdef _MSC_VER
#include <string_view>
#else
// llvm-libc++ included with Android NDK r15c hasn't yet promoted the C++1z library fundamentals
// technical specification to the final C++17 specification for string_view.
// Force promote the types we need up into the std namespace.
#include <experimental/string_view>
namespace std
{
    using string_view = experimental::string_view;
    using wstring_view = experimental::wstring_view;
}
#endif

namespace arcana
{
    inline std::string utf16_to_utf8(gsl::cwzstring<> input)
    {
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        return converter.to_bytes(input);
    }

    inline std::wstring utf8_to_utf16(gsl::czstring<> input)
    {
        std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
        return converter.from_bytes(input);
    }

    inline std::string utf16_to_utf8(std::wstring_view input)
    {
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        return converter.to_bytes(input.data(), input.data() + input.size());
    }

    inline std::wstring utf8_to_utf16(std::string_view input)
    {
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        return converter.from_bytes(input.data(), input.data() + input.size());
    }

    struct string_compare
    {
        using is_transparent = std::true_type;

        bool operator()(gsl::cstring_span<> a, gsl::cstring_span<> b) const
        {
            return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
        }

        bool operator()(gsl::czstring_span<> a, gsl::czstring_span<> b) const
        {
            return (*this)(a.as_string_span(), b.as_string_span());
        }

        bool operator()(gsl::czstring<> a, gsl::czstring<> b) const
        {
            return strcmp(a, b) < 0;
        }
    };
}


/** \file real-compressor.c */
#ifndef __COMPLEARN_REALCOMPRESSOR_H
#define __COMPLEARN_REALCOMPRESSOR_H

#define COMPLEARN_REAL_COMPRESSOR_TYPE        (real_compressor_get_type ())
#define COMPLEARN_TYPE_REAL_COMPRESSOR        (real_compressor_get_type ())
#define COMPLEARN_REAL_COMPRESSOR(obj)        (G_TYPE_CHECK_INSTANCE_CAST ((obj), COMPLEARN_REAL_COMPRESSOR_TYPE, CompLearnRealCompressor))
#define IS_COMPLEARN_REAL_COMPRESSOR(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), COMPLEARN_REAL_COMPRESSOR_TYPE))
#define COMPLEARN_REAL_COMPRESSOR_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), COMPLEARN_REAL_COMPRESSOR_TYPE, CompLearnRealCompressorIface))

#include <glib.h>
#include <glib-object.h>
#include <glib/garray.h>
#include <gsl/gsl_matrix.h>

#define COMPLEARN_ERROR 1
#define COMPLEARN_ERROR_NO_COMPRESSOR_SET 100

typedef struct _CompLearnRealCompressor CompLearnRealCompressor;
typedef struct _CompLearnRealCompressorIface CompLearnRealCompressorIface;

struct _CompLearnRealCompressorIface {
  GTypeInterface parent;

  GString *(*compress)(CompLearnRealCompressor *self, const GString *input);
  GString *(*decompress)(CompLearnRealCompressor *self, const GString *input);
  GString *(*blurb)(CompLearnRealCompressor *self);
  GString *(*canonical_extension)(CompLearnRealCompressor *self);
  GString *(*name)(CompLearnRealCompressor *self);
  GString *(*compressor_version)(CompLearnRealCompressor *self);
  GString *(*binding_version)(CompLearnRealCompressor *self);
  gboolean (*is_threadsafe)(CompLearnRealCompressor *self);
  gboolean (*is_compressible)(CompLearnRealCompressor *self, const GString *input);
  gboolean (*is_decompressible)(CompLearnRealCompressor *self, const GString *input);
  gboolean (*is_just_size)(CompLearnRealCompressor *self);
  gboolean (*is_hash_function)(CompLearnRealCompressor *self);
  GString *(*hash)(CompLearnRealCompressor *self, const GString *input);
  gboolean (*is_operational)(CompLearnRealCompressor *self);
  gboolean (*is_private_property)(CompLearnRealCompressor *self, const char *propname);
  gdouble (*compressed_size)(CompLearnRealCompressor *self, const GString *input);
  guint64 (*window_size)(CompLearnRealCompressor *self);
  CompLearnRealCompressor *(*clone)(CompLearnRealCompressor *self);
};

GType real_compressor_get_type(void);

/// Compress the string by the compressor
/// \param[in] self is a pointer to compressor
/// \param[in] input is a pointer to a GString which must be compressed
/// \return a pointer to compressed string
GString *real_compressor_compress(CompLearnRealCompressor *self,const GString *input);
GString *real_compressor_hash(CompLearnRealCompressor *self,const GString *input);
/// Decompress the string by the compressor
/// \param[in] self is pointer to compressor
/// \param[in] input is a pointer to a GString which must be decompressed
/// \return a pointer to decompressed string
GString *real_compressor_decompress(CompLearnRealCompressor *self,const GString *input);
/// Calculate size of the compressed string
/// \param[in] self is a pointer to a compressor
/// \param[in] input is a pointer to string which must be compress
/// \return size of compressed string in bits
gdouble real_compressor_compressed_size(CompLearnRealCompressor *self,const GString *input);
/// Return a short text description of this compressor
/// \param[in] self is a pointer to a compressor
GString *real_compressor_blurb(CompLearnRealCompressor *self);
GString *real_compressor_name(CompLearnRealCompressor *self);
/// Display the compressor version
/// param[in] is a pointer to compressor
/// \return a GString holding a 3-part version
GString *real_compressor_compressor_version(CompLearnRealCompressor *self);
/// Display the compressor binding version
/// \param[in] is a pointer to compressor
/// \return a GString holding a 3-part version
GString *real_compressor_binding_version(CompLearnRealCompressor *self);
/// This function checks whether the string is compressible by the compressor
/// \param[in] self is a pointer to compressor
/// \param[in] input is a pointer to GString which is under test
/// \return true for every string
gboolean real_compressor_is_compressible(CompLearnRealCompressor *self, const GString *input);
/// Check whether the string is decompressible by the compressor
/// \param[in] self is a pointer to compressor
/// \param[in] input is a pointer to string which is under test
gboolean real_compressor_is_decompressible(CompLearnRealCompressor *self, const GString *input);

gboolean real_compressor_is_private_property(CompLearnRealCompressor *self, const char *input);
guint64 real_compressor_window_size(CompLearnRealCompressor *self);
gboolean real_compressor_is_threadsafe(CompLearnRealCompressor *self);
gboolean real_compressor_is_just_size(CompLearnRealCompressor *self);
gboolean real_compressor_is_hash_function(CompLearnRealCompressor *self);
GString *real_compressor_canonical_extension(CompLearnRealCompressor *rc);
gboolean real_compressor_is_operational(CompLearnRealCompressor *self);
CompLearnRealCompressor *real_compressor_clone(CompLearnRealCompressor *self);

#define SET_DEFAULT_PROPS(groupname, clt, mobj) \
  do { \
  GParamSpec **gps, **cur; \
  g_assert(mobj != NULL); \
    if (complearn_environment_get_nameable(groupname) == NULL) { \
      complearn_environment_register_nameable(groupname, G_OBJECT(mobj)); \
      break; \
    } \
  gps =g_object_class_list_properties(G_OBJECT_CLASS(clt(mobj)), NULL); \
  for (cur = gps; *cur; cur += 1) { \
    GValue v = {0,}; \
    g_value_init(&v, (*cur)->value_type); \
    g_param_value_set_default(*cur, &v); \
    g_object_set_property(G_OBJECT(mobj), (*cur)->name, &v); \
    complearn_environment_register_property(G_OBJECT(mobj), (*cur), &v); \
  } } while(0)

#define SET_DEFAULT_COMPRESSOR_PROPS(groupname, clt, mobj) \
  do { \
      SET_DEFAULT_PROPS(groupname, clt, mobj); \
    if (complearn_environment_get_nameable(groupname) == NULL) { \
      complearn_environment_register_compressor(mobj); \
    } \
  } while (0);

#endif

#define G_LOG_LEVEL_NOTICE G_LOG_LEVEL_USER_SHIFT
#define g_notice(...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_NOTICE, __VA_ARGS__)

void real_compressor_interface_init (gpointer g_iface, gpointer iface_data);


#pragma once

#include <halley/maths/vector2.h>
#include <halley/maths/rect.h>
#include <memory>
#include <halley/resources/resource.h>
#include <halley/text/halleystring.h>
#include <halley/data_structures/hash_map.h>
#include <gsl/span>
#include "halley/maths/vector4.h"

namespace Halley
{
	class Sprite;
	class Resources;
	class Serializer;
	class Deserializer;
	class ResourceDataStatic;
	class Texture;
	class ResourceLoader;
	class Material;
	class SpriteSheet;

	class SpriteSheetEntry
	{
	public:
		Vector2f pivot;
		Vector2i origPivot;
		Vector2f size;
		Rect4f coords;
		Vector4s trimBorder;
		Vector4s slices;
		int duration = 0;
		bool rotated = false;
		bool sliced = false;

		void serialize(Serializer& s) const;
		void deserialize(Deserializer& s);

#ifdef ENABLE_HOT_RELOAD
		SpriteSheet* parent = nullptr;
		uint32_t idx = 0;
#endif
	};

	class SpriteSheetFrameTag
	{
	public:
		String name;
		int from = 0;
		int to = 0;

		void serialize(Serializer& s) const;
		void deserialize(Deserializer& s);
	};

	class SpriteHotReloader {
	public:
		virtual ~SpriteHotReloader() = default;

#ifdef ENABLE_HOT_RELOAD
		void addSprite(Sprite* sprite, uint32_t idx) const;
		void removeSprite(Sprite* sprite) const;
		void updateSpriteIndex(Sprite* sprite, uint32_t idx) const;
		void clearSpriteRefs();

	protected:
		class SpritePointerHasher {
		public:
			std::size_t operator()(Sprite* ptr) const noexcept;
		};

		mutable std::unordered_map<Sprite*, uint32_t, SpritePointerHasher> spriteRefs;
#endif
	};

	class SpriteSheet final : public Resource, public SpriteHotReloader
	{
	public:
		SpriteSheet();
		~SpriteSheet();

		const std::shared_ptr<const Texture>& getTexture() const;
		const SpriteSheetEntry& getSprite(const String& name) const;
		const SpriteSheetEntry& getSprite(size_t idx) const;
		const SpriteSheetEntry* tryGetSprite(const String& name) const;
		const SpriteSheetEntry& getDummySprite() const;

		const std::vector<SpriteSheetFrameTag>& getFrameTags() const;
		std::vector<String> getSpriteNames() const;
		const HashMap<String, uint32_t>& getSpriteNameMap() const;

		size_t getSpriteCount() const;
		std::optional<size_t> getIndex(const String& name) const;
		bool hasSprite(const String& name) const;

		void loadJson(gsl::span<const gsl::byte> data);

		void addSprite(String name, const SpriteSheetEntry& sprite);
		void setTextureName(String name);

		std::shared_ptr<Material> getMaterial(const String& name) const;
		void setDefaultMaterialName(String materialName);
		const String& getDefaultMaterialName() const;
		void clearMaterialCache() const;

		static std::unique_ptr<SpriteSheet> loadResource(ResourceLoader& loader);
		constexpr static AssetType getAssetType() { return AssetType::SpriteSheet; }
		void reload(Resource&& resource) override;

		void serialize(Serializer& s) const;
		void deserialize(Deserializer& s);

	private:
		constexpr static int version = 1;

		Resources* resources = nullptr;

		std::vector<SpriteSheetEntry> sprites;
		SpriteSheetEntry dummySprite;
		HashMap<String, uint32_t> spriteIdx;
		std::vector<SpriteSheetFrameTag> frameTags;

		String textureName;
		mutable std::shared_ptr<const Texture> texture;

		String defaultMaterialName;
		mutable HashMap<String, std::weak_ptr<Material>> materials;

		void loadTexture(Resources& resources) const;
		void assignIds();
	};

	class SpriteResource final : public Resource, public SpriteHotReloader
	{
	public:
		SpriteResource();
		SpriteResource(const std::shared_ptr<const SpriteSheet>& spriteSheet, size_t idx);
		~SpriteResource();

		const SpriteSheetEntry& getSprite() const;
		size_t getIdx() const;
		std::shared_ptr<const SpriteSheet> getSpriteSheet() const;

		std::shared_ptr<Material> getMaterial(const String& name) const;
		const String& getDefaultMaterialName() const;

		constexpr static AssetType getAssetType() { return AssetType::Sprite; }
		static std::unique_ptr<SpriteResource> loadResource(ResourceLoader& loader);
		void reload(Resource&& resource) override;

		void serialize(Serializer& s) const;
		void deserialize(Deserializer& s);

	private:
		std::weak_ptr<const SpriteSheet> spriteSheet;
		uint64_t idx = -1;
		Resources* resources = nullptr;
	};
}


#pragma once

#include <winrt\Windows.Foundation.h>
#include <cstdint>
#include <d3d11.h>
#include <DirectXMath.h>
#include <dxgidebug.h>
#include <gsl\gsl>
#include "GameException.h"

namespace Library
{
	enum class ShaderStages
	{
		IA,
		VS,
		HS,
		DS,
		GS,
		SO,
		RS,
		PS,
		OM,

		CS
	};

	const std::array<ShaderStages, 6> ProgrammableGraphicsShaderStages
	{
		ShaderStages::VS,
		ShaderStages::HS,
		ShaderStages::DS,
		ShaderStages::GS,
		ShaderStages::PS,
		ShaderStages::CS,
	};

	inline bool ShaderStageIsProgrammable(ShaderStages shaderStage)
	{
		static const std::map<ShaderStages, bool> isProgrammableMap
		{
			{ShaderStages::IA, false },
			{ ShaderStages::VS, true },
			{ ShaderStages::HS, true },
			{ ShaderStages::DS, true },
			{ ShaderStages::GS, true },
			{ ShaderStages::SO, false },
			{ ShaderStages::RS, false },
			{ ShaderStages::PS, true },
			{ ShaderStages::OM, false },
			{ ShaderStages::CS, true },
		};

		return isProgrammableMap.at(shaderStage);
	}

	void CreateIndexBuffer(gsl::not_null<ID3D11Device*> device, const gsl::span<const std::uint16_t>& indices, gsl::not_null<ID3D11Buffer**> indexBuffer);
	void CreateIndexBuffer(gsl::not_null<ID3D11Device*> device, const gsl::span<const std::uint32_t>& indices, gsl::not_null<ID3D11Buffer**> indexBuffer);
	void CreateConstantBuffer(gsl::not_null<ID3D11Device*> device, std::size_t byteWidth, gsl::not_null<ID3D11Buffer**> constantBuffer);

	inline float ConvertDipsToPixels(float dips, float dpi)
	{
		static const float dipsPerInch = 96.0f;
		return floorf(dips * dpi / dipsPerInch + 0.5f); // Round to nearest integer.
	}

#if defined(DEBUG) || defined(_DEBUG)
	// Check for SDK Layer support.
	inline bool SdkLayersAvailable()
	{
		HRESULT hr = D3D11CreateDevice(
			nullptr,
			D3D_DRIVER_TYPE_NULL,       // There is no need to create a real hardware device.
			0,
			D3D11_CREATE_DEVICE_DEBUG,  // Check for the SDK layers.
			nullptr,                    // Any feature level will do.
			0,
			D3D11_SDK_VERSION,          // Always set this to D3D11_SDK_VERSION for Windows Store apps.
			nullptr,                    // No need to keep the D3D device reference.
			nullptr,                    // No need to know the feature level.
			nullptr                     // No need to keep the D3D device context reference.
			);

		return SUCCEEDED(hr);
	}
#endif

#if defined(DEBUG) || defined(_DEBUG)
	inline void DumpD3DDebug()
	{
		winrt::com_ptr<IDXGIDebug1> debugInterface = nullptr;
		ThrowIfFailed(DXGIGetDebugInterface1(0, IID_PPV_ARGS(debugInterface.put())));
		ThrowIfFailed(debugInterface->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL));
	}
#endif
}


#ifndef __GSL_SORT_VECTOR_H__
#define __GSL_SORT_VECTOR_H__

#if !defined( GSL_FUN )
#  if !defined( GSL_DLL )
#    define GSL_FUN extern
#  elif defined( BUILD_GSL_DLL )
#    define GSL_FUN extern __declspec(dllexport)
#  else
#    define GSL_FUN extern __declspec(dllimport)
#  endif
#endif

#include <gsl/gsl_sort_vector_long_double.h>
#include <gsl/gsl_sort_vector_double.h>
#include <gsl/gsl_sort_vector_float.h>

#include <gsl/gsl_sort_vector_ulong.h>
#include <gsl/gsl_sort_vector_long.h>

#include <gsl/gsl_sort_vector_uint.h>
#include <gsl/gsl_sort_vector_int.h>

#include <gsl/gsl_sort_vector_ushort.h>
#include <gsl/gsl_sort_vector_short.h>

#include <gsl/gsl_sort_vector_uchar.h>
#include <gsl/gsl_sort_vector_char.h>

#endif /* __GSL_SORT_VECTOR_H__ */


#pragma once

#include <unordered_map>
#include <vector>

#include <gsl/span>
#include <json.hpp>
#include <optional.hpp>

#include "Quiver/Animation/AnimationData.h"
#include "Quiver/Animation/AnimationId.h"
#include "Quiver/Animation/Rect.h"
#include "Quiver/Animation/TimeUnit.h"

namespace qvr
{

// Tells us about where to find an Animation on disk.
struct AnimationSourceInfo {
	std::string name;
	std::string filename;
};

inline bool operator==(const AnimationSourceInfo& a, const AnimationSourceInfo& b) {
	return a.name == b.name && a.filename == b.filename;
}

class AnimationLibrary
{
public:
	AnimationId Add(const AnimationData& anim);
	AnimationId Add(
		const AnimationData& anim,
		const AnimationSourceInfo& sourceInfo);

	bool Remove(const AnimationId anim);

	bool Contains(const AnimationId anim) const;

	auto GetCount() const -> int;

	auto GetAnimation(const AnimationSourceInfo& sourceInfo)
		const -> AnimationId;

	auto GetSourceInfo(const AnimationId anim)
		const -> std::experimental::optional<AnimationSourceInfo>;

	auto GetFrameCount(const AnimationId anim) const -> int;
	auto GetViewCount(const AnimationId anim) const -> int;
	auto HasAltViews(const AnimationId anim) const -> bool;

	auto GetRect(
		const AnimationId anim,
		const int frameIndex,
		const int viewIndex = 0)
			const -> Animation::Rect;

	auto GetRects(
		const AnimationId anim,
		const int frameIndex)
			const -> gsl::span<const Animation::Rect>;

	auto GetTime(
		const AnimationId anim,
		const int frameIndex)
			const -> Animation::TimeUnit;

	auto GetIds() const -> std::vector<AnimationId>;

	friend void to_json(nlohmann::json& j, const AnimationLibrary& animations);

private:
	struct AnimationInfo {
		AnimationInfo(
			const unsigned indexOfFirstRect,
			const unsigned indexOfFirstTime,
			const unsigned numRects,
			const unsigned numRectsPerFrame)
			: mIndexOfFirstRect(indexOfFirstRect)
			, mIndexOfFirstTime(indexOfFirstTime)
			, mNumRects(numRects)
			, mNumRectsPerFrame(numRectsPerFrame)
		{}

		AnimationInfo(const AnimationInfo& other) = default;

		AnimationInfo() = default;

		unsigned NumFrames() const { return mNumRects / mNumRectsPerFrame; }

		std::experimental::optional<AnimationSourceInfo> mSourceInfo;

		unsigned mIndexOfFirstRect = 0;
		unsigned mIndexOfFirstTime = 0;
		unsigned mNumRects = 0;
		unsigned mNumRectsPerFrame = 0;
	};

	std::unordered_map<AnimationId, AnimationInfo> infos;

	// Time values for each frame in every animation.
	std::vector<Animation::TimeUnit> allFrameTimes;

	// Rects for each frame in every animation, including alt view rects.
	std::vector<Animation::Rect> allFrameRects;
};

void to_json(nlohmann::json& j, const AnimationLibrary& animations);
void to_json(nlohmann::json& j, const AnimationSourceInfo& sourceInfo);

void from_json(const nlohmann::json& j, AnimationLibrary& animations);
void from_json(const nlohmann::json& j, AnimationSourceInfo& animationSource);

}


#if !defined(fvSupport_h)
#define fvSupport_h

#include <petsc.h>

PETSC_EXTERN PetscErrorCode DMPlexReconstructGradientsFVM_MulfiField(DM dm, PetscFV fvm,  Vec locX, Vec grad);
PETSC_EXTERN PetscErrorCode DMPlexGetDataFVM_MulfiField(DM dm, PetscFV fv, Vec *cellgeom, Vec *facegeom, DM *gradDM);

#endif


#pragma once

#include <halley/maths/vector2.h>
#include <halley/time/halleytime.h>
#include <halley/core/graphics/sprite/sprite.h>
#include <gsl/gsl>
#include <thread>
#include <mutex>
#include <atomic>

namespace Halley
{
	class RenderContext;
	class TextureDescriptor;
	class VideoAPI;
	class AudioAPI;
	class StreamingAudioClip;
	class IAudioHandle;
	class TextureRenderTarget;

	enum class MoviePlayerState
	{
		Uninitialised,
		Loading,
		Paused,
		StartingToPlay,
		Playing,
		Finished
	};

	enum class MoviePlayerStreamType
	{
		Unknown,
		Video,
		Audio,
		Other
	};

	class MoviePlayerStream
	{
	public:
		MoviePlayerStreamType type = MoviePlayerStreamType::Unknown;
		bool playing = true;
		bool eof = false;
	};

	struct PendingFrame
	{
		std::shared_ptr<Texture> texture;
		Time time;
	};

	struct MoviePlayerAliveFlag
	{
		bool isAlive = true;
		mutable std::mutex mutex;
	};

	class MoviePlayer
	{
	public:
		MoviePlayer(VideoAPI& video, AudioAPI& audio);
		virtual ~MoviePlayer();

		void play();
		void pause();
		void reset();
		void stop();

		virtual bool hasError() const;

		virtual void update(Time t);
		void render(Resources& resources, RenderContext& rc);
		Sprite getSprite(Resources& resources);

		MoviePlayerState getState() const;
		Vector2i getSize() const;

	protected:
		virtual void requestVideoFrame() = 0;
		virtual void requestAudioFrame() = 0;
		virtual void onReset();
		virtual void onStartPlay();
		virtual void waitForVideoInfo();
		virtual bool needsYV12Conversion() const;
		virtual bool shouldRecycleTextures() const;
		virtual void onDoneUsingTexture(std::shared_ptr<Texture> texture);
		virtual Rect4i getCropRect() const;

		void setVideoSize(Vector2i size);

		VideoAPI& getVideoAPI() const;
		AudioAPI& getAudioAPI() const;

		void onVideoFrameAvailable(Time time, TextureDescriptor&& descriptor);
		void onVideoFrameAvailable(Time time, std::shared_ptr<Texture> texture);
		void onAudioFrameAvailable(Time time, gsl::span<const short> samples);
		void onAudioFrameAvailable(Time time, gsl::span<const float> samples);

		std::shared_ptr<MoviePlayerAliveFlag> getAliveFlag() const;

		std::vector<MoviePlayerStream> streams;
		std::list<std::shared_ptr<Texture>> recycleTexture;
		std::list<PendingFrame> pendingFrames;
		int maxVideoFrames;
		int maxAudioSamples;

	private:
		VideoAPI& video;
		AudioAPI& audio;

		MoviePlayerState state = MoviePlayerState::Uninitialised;

		Vector2i videoSize;
		std::shared_ptr<Texture> currentTexture;
		std::shared_ptr<TextureRenderTarget> renderTarget;
		std::shared_ptr<Texture> renderTexture;

		std::shared_ptr<StreamingAudioClip> streamingClip;
		std::shared_ptr<IAudioHandle> audioHandle;

		std::atomic<bool> threadRunning;
		std::atomic<bool> threadAborted;
		std::thread workerThread;
		std::shared_ptr<MoviePlayerAliveFlag> aliveFlag;

		Time time = 0;

		void startThread();
		void stopThread();
		void threadEntry();

		virtual bool useCustomThreads() const;
		virtual void stopCustomThreads();

		bool needsMoreVideoFrames() const;
		bool needsMoreAudioFrames() const;
	};
}


#pragma once

#define NOMINMAX
#include <windows.h>

#include <unknwn.h>
#include <restrictederrorinfo.h>
#include <hstring.h>
#include <MemoryBuffer.h>

// DirectX
#include <windows.ui.xaml.media.dxinterop.h>
#include <d3d11.h>
#include <dxgi.h>
#include <dxgi1_2.h>
#include <dxgi1_3.h>
#include <DirectXMath.h>

// C++/WinRT
#include "winrt/Microsoft.UI.Xaml.Automation.Peers.h"
#include "winrt/Microsoft.UI.Xaml.Controls.Primitives.h"
#include "winrt/Microsoft.UI.Xaml.Media.h"
#include "winrt/Microsoft.UI.Xaml.XamlTypeInfo.h"
#include "winrt/Windows.ApplicationModel.h"
#include "winrt/Windows.ApplicationModel.Activation.h"
#include "winrt/Windows.ApplicationModel.Resources.h"
#include "winrt/Windows.Foundation.h"
#include "winrt/Windows.Foundation.Collections.h"
#include "winrt/Windows.Globalization.NumberFormatting.h"
#include "winrt/Windows.Media.h"
#include "winrt/Windows.Media.Audio.h"
#include "winrt/Windows.Media.MediaProperties.h"
#include "winrt/Windows.Media.Render.h"
#include "winrt/Windows.Storage.h"
#include "winrt/Windows.Storage.Pickers.h"
#include "winrt/Windows.Storage.Streams.h"
#include "winrt/Windows.System.Threading.h"
#include "winrt/Windows.UI.Core.h"
#include "winrt/Windows.UI.Xaml.h"
#include "winrt/Windows.UI.Xaml.Controls.h"
#include "winrt/Windows.UI.Xaml.Controls.Primitives.h"
#include "winrt/Windows.UI.Xaml.Data.h"
#include "winrt/Windows.UI.Xaml.Documents.h"
#include "winrt/Windows.UI.Xaml.Interop.h"
#include "winrt/Windows.UI.Xaml.Input.h"
#include "winrt/Windows.UI.Xaml.Markup.h"
#include "winrt/Windows.UI.Xaml.Navigation.h"

#include <algorithm>
#include <array>
#include <chrono>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
#include <stdexcept>
#include <thread>
#include <sstream>

#include <gsl/gsl>


///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// 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.
//
///////////////////////////////////////////////////////////////////////////////

#ifndef GSL_SPAN_H
#define GSL_SPAN_H

#include <gsl/gsl_assert> // for Expects
#include <gsl/gsl_byte>   // for byte
#include <gsl/gsl_util>   // for narrow_cast, narrow

#include <algorithm> // for lexicographical_compare
#include <array>     // for array
#include <cstddef>   // for ptrdiff_t, size_t, nullptr_t
#include <iterator>  // for reverse_iterator, distance, random_access_...
#include <limits>
#include <stdexcept>
#include <type_traits> // for enable_if_t, declval, is_convertible, inte...
#include <utility>
#include <memory> // for std::addressof

#ifdef _MSC_VER
#pragma warning(push)

// turn off some warnings that are noisy about our Expects statements
#pragma warning(disable : 4127) // conditional expression is constant
#pragma warning(disable : 4702) // unreachable code

// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
#pragma warning(disable : 26495) // uninitalized member when constructor calls constructor
#pragma warning(disable : 26446) // parser bug does not allow attributes on some templates

#if _MSC_VER < 1910
#pragma push_macro("constexpr")
#define constexpr /*constexpr*/
#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND

#endif // _MSC_VER < 1910
#endif // _MSC_VER

// See if we have enough C++17 power to use a static constexpr data member
// without needing an out-of-line definition
#if !(defined(__cplusplus) && (__cplusplus >= 201703L))
#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
#endif // !(defined(__cplusplus) && (__cplusplus >= 201703L))

// GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t)
// While there is a conversion from signed to unsigned, it happens at
// compiletime, so the compiler wouldn't have to warn indiscriminently, but
// could check if the source value actually doesn't fit into the target type
// and only warn in those cases.
#if __GNUC__ > 6
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif

namespace gsl
{

// [views.constants], constants
constexpr const std::ptrdiff_t dynamic_extent = -1;

template <class ElementType, std::ptrdiff_t Extent = dynamic_extent>
class span;

// implementation details
namespace details
{
    template <class T>
    struct is_span_oracle : std::false_type
    {
    };

    template <class ElementType, std::ptrdiff_t Extent>
    struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type
    {
    };

    template <class T>
    struct is_span : public is_span_oracle<std::remove_cv_t<T>>
    {
    };

    template <class T>
    struct is_std_array_oracle : std::false_type
    {
    };

    template <class ElementType, std::size_t Extent>
    struct is_std_array_oracle<std::array<ElementType, Extent>> : std::true_type
    {
    };

    template <class T>
    struct is_std_array : public is_std_array_oracle<std::remove_cv_t<T>>
    {
    };

    template <std::ptrdiff_t From, std::ptrdiff_t To>
    struct is_allowed_extent_conversion
        : public std::integral_constant<bool, From == To || From == gsl::dynamic_extent ||
                                                  To == gsl::dynamic_extent>
    {
    };

    template <class From, class To>
    struct is_allowed_element_type_conversion
        : public std::integral_constant<bool, std::is_convertible<From (*)[], To (*)[]>::value>
    {
    };

    template <class Span, bool IsConst>
    class span_iterator
    {
        using element_type_ = typename Span::element_type;

    public:
#ifdef _MSC_VER
        // Tell Microsoft standard library that span_iterators are checked.
        using _Unchecked_type = typename Span::pointer;
#endif

        using iterator_category = std::random_access_iterator_tag;
        using value_type = std::remove_cv_t<element_type_>;
        using difference_type = typename Span::index_type;

        using reference = std::conditional_t<IsConst, const element_type_, element_type_>&;
        using pointer = std::add_pointer_t<reference>;

        span_iterator() = default;

        constexpr span_iterator(const Span* span, typename Span::index_type idx) noexcept
            : span_(span), index_(idx)
        {}

        friend span_iterator<Span, true>;
        template <bool B, std::enable_if_t<!B && IsConst>* = nullptr>
        constexpr span_iterator(const span_iterator<Span, B>& other) noexcept
            : span_iterator(other.span_, other.index_)
        {}

        GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
        constexpr reference operator*() const
        {
            Expects(index_ != span_->size());
            return *(span_->data() + index_);
        }

        constexpr pointer operator->() const
        {
            Expects(index_ != span_->size());
            return span_->data() + index_;
        }

        constexpr span_iterator& operator++()
        {
            Expects(0 <= index_ && index_ != span_->size());
            ++index_;
            return *this;
        }

        constexpr span_iterator operator++(int)
        {
            auto ret = *this;
            ++(*this);
            return ret;
        }

        constexpr span_iterator& operator--()
        {
            Expects(index_ != 0 && index_ <= span_->size());
            --index_;
            return *this;
        }

        constexpr span_iterator operator--(int)
        {
            auto ret = *this;
            --(*this);
            return ret;
        }

        constexpr span_iterator operator+(difference_type n) const
        {
            auto ret = *this;
            return ret += n;
        }

        friend constexpr span_iterator operator+(difference_type n, span_iterator const& rhs)
        {
            return rhs + n;
        }

        constexpr span_iterator& operator+=(difference_type n)
        {
            Expects((index_ + n) >= 0 && (index_ + n) <= span_->size());
            index_ += n;
            return *this;
        }

        constexpr span_iterator operator-(difference_type n) const
        {
            auto ret = *this;
            return ret -= n;
        }

        constexpr span_iterator& operator-=(difference_type n) { return *this += -n; }

        constexpr difference_type operator-(span_iterator rhs) const
        {
            Expects(span_ == rhs.span_);
            return index_ - rhs.index_;
        }

        constexpr reference operator[](difference_type n) const { return *(*this + n); }

        constexpr friend bool operator==(span_iterator lhs, span_iterator rhs) noexcept
        {
            return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_;
        }

        constexpr friend bool operator!=(span_iterator lhs, span_iterator rhs) noexcept
        {
            return !(lhs == rhs);
        }

        constexpr friend bool operator<(span_iterator lhs, span_iterator rhs) noexcept
        {
            return lhs.index_ < rhs.index_;
        }

        constexpr friend bool operator<=(span_iterator lhs, span_iterator rhs) noexcept
        {
            return !(rhs < lhs);
        }

        constexpr friend bool operator>(span_iterator lhs, span_iterator rhs) noexcept
        {
            return rhs < lhs;
        }

        constexpr friend bool operator>=(span_iterator lhs, span_iterator rhs) noexcept
        {
            return !(rhs > lhs);
        }

#ifdef _MSC_VER
        // MSVC++ iterator debugging support; allows STL algorithms in 15.8+
        // to unwrap span_iterator to a pointer type after a range check in STL
        // algorithm calls
        friend constexpr void _Verify_range(span_iterator lhs, span_iterator rhs) noexcept
        { // test that [lhs, rhs) forms a valid range inside an STL algorithm
            Expects(lhs.span_ == rhs.span_        // range spans have to match
                    && lhs.index_ <= rhs.index_); // range must not be transposed
        }

        constexpr void _Verify_offset(const difference_type n) const noexcept
        { // test that the iterator *this + n is a valid range in an STL
            // algorithm call
            Expects((index_ + n) >= 0 && (index_ + n) <= span_->size());
        }

        GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
        constexpr pointer _Unwrapped() const noexcept
        { // after seeking *this to a high water mark, or using one of the
            // _Verify_xxx functions above, unwrap this span_iterator to a raw
            // pointer
            return span_->data() + index_;
        }

        // Tell the STL that span_iterator should not be unwrapped if it can't
        // validate in advance, even in release / optimized builds:
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
        static constexpr const bool _Unwrap_when_unverified = false;
#else
        static constexpr bool _Unwrap_when_unverified = false;
#endif
        GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive
        constexpr void _Seek_to(const pointer p) noexcept
        { // adjust the position of *this to previously verified location p
            // after _Unwrapped
            index_ = p - span_->data();
        }
#endif

    protected:
        const Span* span_ = nullptr;
        std::ptrdiff_t index_ = 0;
    };

    template <std::ptrdiff_t Ext>
    class extent_type
    {
    public:
        using index_type = std::ptrdiff_t;

        static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size.");

        constexpr extent_type() noexcept {}

        template <index_type Other>
        constexpr extent_type(extent_type<Other> ext)
        {
            static_assert(Other == Ext || Other == dynamic_extent,
                          "Mismatch between fixed-size extent and size of initializing data.");
            Expects(ext.size() == Ext);
        }

        constexpr extent_type(index_type size) { Expects(size == Ext); }

        constexpr index_type size() const noexcept { return Ext; }
    };

    template <>
    class extent_type<dynamic_extent>
    {
    public:
        using index_type = std::ptrdiff_t;

        template <index_type Other>
        explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size())
        {}

        explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); }

        constexpr index_type size() const noexcept { return size_; }

    private:
        index_type size_;
    };

    template <class ElementType, std::ptrdiff_t Extent, std::ptrdiff_t Offset, std::ptrdiff_t Count>
    struct calculate_subspan_type
    {
        using type = span<ElementType, Count != dynamic_extent
                                           ? Count
                                           : (Extent != dynamic_extent ? Extent - Offset : Extent)>;
    };
} // namespace details

// [span], class template span
template <class ElementType, std::ptrdiff_t Extent>
class span
{
public:
    // constants and types
    using element_type = ElementType;
    using value_type = std::remove_cv_t<ElementType>;
    using index_type = std::ptrdiff_t;
    using pointer = element_type*;
    using reference = element_type&;

    using iterator = details::span_iterator<span<ElementType, Extent>, false>;
    using const_iterator = details::span_iterator<span<ElementType, Extent>, true>;
    using reverse_iterator = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;

    using size_type = index_type;

#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
    static constexpr const index_type extent{Extent};
#else
    static constexpr index_type extent{Extent};
#endif

    // [span.cons], span constructors, copy, assignment, and destructor
    template <bool Dependent = false,
              // "Dependent" is needed to make "std::enable_if_t<Dependent || Extent <= 0>" SFINAE,
              // since "std::enable_if_t<Extent <= 0>" is ill-formed when Extent is greater than 0.
              class = std::enable_if_t<(Dependent || Extent <= 0)>>
    constexpr span() noexcept : storage_(nullptr, details::extent_type<0>())
    {}

    constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {}

    constexpr span(pointer firstElem, pointer lastElem)
        : storage_(firstElem, std::distance(firstElem, lastElem))
    {}

    template <std::size_t N>
    constexpr span(element_type (&arr)[N]) noexcept
        : storage_(KnownNotNull{std::addressof(arr[0])}, details::extent_type<N>())
    {}

    template <std::size_t N, class = std::enable_if_t<(N > 0)>>
    constexpr span(std::array<std::remove_const_t<element_type>, N>& arr) noexcept
        : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
    {
    }

    constexpr span(std::array<std::remove_const_t<element_type>, 0>&) noexcept
        : storage_(static_cast<pointer>(nullptr), details::extent_type<0>())
    {
    }

    template <std::size_t N, class = std::enable_if_t<(N > 0)>>
    constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) noexcept
        : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
    {
    }

    constexpr span(const std::array<std::remove_const_t<element_type>, 0>&) noexcept
        : storage_(static_cast<pointer>(nullptr), details::extent_type<0>())
    {
    }

    // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement
    // on Container to be a contiguous sequence container.
    template <class Container,
              class = std::enable_if_t<
                  !details::is_span<Container>::value && !details::is_std_array<Container>::value &&
                  std::is_convertible<typename Container::pointer, pointer>::value &&
                  std::is_convertible<typename Container::pointer,
                                      decltype(std::declval<Container>().data())>::value>>
    constexpr span(Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
    {}

    template <class Container,
              class = std::enable_if_t<
                  std::is_const<element_type>::value && !details::is_span<Container>::value &&
                  std::is_convertible<typename Container::pointer, pointer>::value &&
                  std::is_convertible<typename Container::pointer,
                                      decltype(std::declval<Container>().data())>::value>>
    constexpr span(const Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
    {}

    constexpr span(const span& other) noexcept = default;

    template <
        class OtherElementType, std::ptrdiff_t OtherExtent,
        class = std::enable_if_t<
            details::is_allowed_extent_conversion<OtherExtent, Extent>::value &&
            details::is_allowed_element_type_conversion<OtherElementType, element_type>::value>>
    constexpr span(const span<OtherElementType, OtherExtent>& other)
        : storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
    {}

    ~span() noexcept = default;
    constexpr span& operator=(const span& other) noexcept = default;

    // [span.sub], span subviews
    template <std::ptrdiff_t Count>
    constexpr span<element_type, Count> first() const
    {
        Expects(Count >= 0 && Count <= size());
        return {data(), Count};
    }

    template <std::ptrdiff_t Count>
    GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
    constexpr span<element_type, Count> last() const
    {
        Expects(Count >= 0 && size() - Count >= 0);
        return {data() + (size() - Count), Count};
    }

    template <std::ptrdiff_t Offset, std::ptrdiff_t Count = dynamic_extent>
    GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
    constexpr auto subspan() const ->
        typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
    {
        Expects((Offset >= 0 && size() - Offset >= 0) &&
                (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size())));

        return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
    }

    constexpr span<element_type, dynamic_extent> first(index_type count) const
    {
        Expects(count >= 0 && count <= size());
        return {data(), count};
    }

    constexpr span<element_type, dynamic_extent> last(index_type count) const
    {
        return make_subspan(size() - count, dynamic_extent, subspan_selector<Extent>{});
    }

    constexpr span<element_type, dynamic_extent> subspan(index_type offset,
                                                         index_type count = dynamic_extent) const
    {
        return make_subspan(offset, count, subspan_selector<Extent>{});
    }

    // [span.obs], span observers
    constexpr index_type size() const noexcept { return storage_.size(); }
    constexpr index_type size_bytes() const noexcept
    {
        return size() * narrow_cast<index_type>(sizeof(element_type));
    }
    constexpr bool empty() const noexcept { return size() == 0; }

    // [span.elem], span element access
    GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
    constexpr reference operator[](index_type idx) const
    {
        Expects(CheckRange(idx, storage_.size()));
        return data()[idx];
    }

    constexpr reference at(index_type idx) const { return this->operator[](idx); }
    constexpr reference operator()(index_type idx) const { return this->operator[](idx); }
    constexpr pointer data() const noexcept { return storage_.data(); }

    // [span.iter], span iterator support
    constexpr iterator begin() const noexcept { return {this, 0}; }
    constexpr iterator end() const noexcept { return {this, size()}; }

    constexpr const_iterator cbegin() const noexcept { return {this, 0}; }
    constexpr const_iterator cend() const noexcept { return {this, size()}; }

    constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
    constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }

    constexpr const_reverse_iterator crbegin() const noexcept
    {
        return const_reverse_iterator{cend()};
    }
    constexpr const_reverse_iterator crend() const noexcept
    {
        return const_reverse_iterator{cbegin()};
    }

#ifdef _MSC_VER
    // Tell MSVC how to unwrap spans in range-based-for
    constexpr pointer _Unchecked_begin() const noexcept { return data(); }
    constexpr pointer _Unchecked_end() const noexcept
    {
        GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
        return data() + size();
    }
#endif // _MSC_VER

private:
    static bool CheckRange(index_type idx, index_type size)
    {
        // Optimization:
        //
        // idx >= 0 && idx < size
        // =>
        // static_cast<size_t>(idx) < static_cast<size_t>(size)
        //
        // because size >=0 by span construction, and negative idx will
        // wrap around to a value always greater than size when casted.

        // check if we have enough space to wrap around
        if (sizeof(index_type) <= sizeof(size_t))
        {
            return narrow_cast<size_t>(idx) < narrow_cast<size_t>(size);
        }
        else
        {
            return idx >= 0 && idx < size;
        }
    }

    // Needed to remove unnecessary null check in subspans
    struct KnownNotNull
    {
        pointer p;
    };

    // this implementation detail class lets us take advantage of the
    // empty base class optimization to pay for only storage of a single
    // pointer in the case of fixed-size spans
    template <class ExtentType>
    class storage_type : public ExtentType
    {
    public:
        // KnownNotNull parameter is needed to remove unnecessary null check
        // in subspans and constructors from arrays
        template <class OtherExtentType>
        constexpr storage_type(KnownNotNull data, OtherExtentType ext)
            : ExtentType(ext), data_(data.p)
        {
            Expects(ExtentType::size() >= 0);
        }

        template <class OtherExtentType>
        constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
        {
            Expects(ExtentType::size() >= 0);
            Expects(data || ExtentType::size() == 0);
        }

        constexpr pointer data() const noexcept { return data_; }

    private:
        pointer data_;
    };

    storage_type<details::extent_type<Extent>> storage_;

    // The rest is needed to remove unnecessary null check
    // in subspans and constructors from arrays
    constexpr span(KnownNotNull ptr, index_type count) : storage_(ptr, count) {}

    template <std::ptrdiff_t CallerExtent>
    class subspan_selector
    {
    };

    template <std::ptrdiff_t CallerExtent>
    span<element_type, dynamic_extent> make_subspan(index_type offset, index_type count,
                                                    subspan_selector<CallerExtent>) const
    {
        const span<element_type, dynamic_extent> tmp(*this);
        return tmp.subspan(offset, count);
    }

    GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
    span<element_type, dynamic_extent> make_subspan(index_type offset, index_type count,
                                                    subspan_selector<dynamic_extent>) const
    {
        Expects(offset >= 0 && size() - offset >= 0);

        if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; }

        Expects(count >= 0 && size() - offset >= count);
        return {KnownNotNull{data() + offset}, count};
    }
};

#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
template <class ElementType, std::ptrdiff_t Extent>
constexpr const typename span<ElementType, Extent>::index_type span<ElementType, Extent>::extent;
#endif

// [span.comparison], span comparison operators
template <class ElementType, std::ptrdiff_t FirstExtent, std::ptrdiff_t SecondExtent>
constexpr bool operator==(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r)
{
    return std::equal(l.begin(), l.end(), r.begin(), r.end());
}

template <class ElementType, std::ptrdiff_t Extent>
constexpr bool operator!=(span<ElementType, Extent> l, span<ElementType, Extent> r)
{
    return !(l == r);
}

template <class ElementType, std::ptrdiff_t Extent>
constexpr bool operator<(span<ElementType, Extent> l, span<ElementType, Extent> r)
{
    return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
}

template <class ElementType, std::ptrdiff_t Extent>
constexpr bool operator<=(span<ElementType, Extent> l, span<ElementType, Extent> r)
{
    return !(l > r);
}

template <class ElementType, std::ptrdiff_t Extent>
constexpr bool operator>(span<ElementType, Extent> l, span<ElementType, Extent> r)
{
    return r < l;
}

template <class ElementType, std::ptrdiff_t Extent>
constexpr bool operator>=(span<ElementType, Extent> l, span<ElementType, Extent> r)
{
    return !(l < r);
}

namespace details
{
    // if we only supported compilers with good constexpr support then
    // this pair of classes could collapse down to a constexpr function

    // we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as
    // constexpr
    // and so will fail compilation of the template
    template <class ElementType, std::ptrdiff_t Extent>
    struct calculate_byte_size
        : std::integral_constant<std::ptrdiff_t,
                                 static_cast<std::ptrdiff_t>(sizeof(ElementType) *
                                                             static_cast<std::size_t>(Extent))>
    {
    };

    template <class ElementType>
    struct calculate_byte_size<ElementType, dynamic_extent>
        : std::integral_constant<std::ptrdiff_t, dynamic_extent>
    {
    };
} // namespace details

// [span.objectrep], views of object representation
template <class ElementType, std::ptrdiff_t Extent>
span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
as_bytes(span<ElementType, Extent> s) noexcept
{
    GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
    return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
}

template <class ElementType, std::ptrdiff_t Extent,
          class = std::enable_if_t<!std::is_const<ElementType>::value>>
span<byte, details::calculate_byte_size<ElementType, Extent>::value>
as_writeable_bytes(span<ElementType, Extent> s) noexcept
{
    GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
    return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
}

//
// make_span() - Utility functions for creating spans
//
template <class ElementType>
constexpr span<ElementType> make_span(ElementType* ptr,
                                      typename span<ElementType>::index_type count)
{
    return span<ElementType>(ptr, count);
}

template <class ElementType>
constexpr span<ElementType> make_span(ElementType* firstElem, ElementType* lastElem)
{
    return span<ElementType>(firstElem, lastElem);
}

template <class ElementType, std::size_t N>
constexpr span<ElementType, N> make_span(ElementType (&arr)[N]) noexcept
{
    return span<ElementType, N>(arr);
}

template <class Container>
constexpr span<typename Container::value_type> make_span(Container& cont)
{
    return span<typename Container::value_type>(cont);
}

template <class Container>
constexpr span<const typename Container::value_type> make_span(const Container& cont)
{
    return span<const typename Container::value_type>(cont);
}

template <class Ptr>
constexpr span<typename Ptr::element_type> make_span(Ptr& cont, std::ptrdiff_t count)
{
    return span<typename Ptr::element_type>(cont, count);
}

template <class Ptr>
constexpr span<typename Ptr::element_type> make_span(Ptr& cont)
{
    return span<typename Ptr::element_type>(cont);
}

// Specialization of gsl::at for span
template <class ElementType, std::ptrdiff_t Extent>
constexpr ElementType& at(span<ElementType, Extent> s, index i)
{
    // No bounds checking here because it is done in span::operator[] called below
    return s[i];
}

} // namespace gsl

#ifdef _MSC_VER
#if _MSC_VER < 1910
#undef constexpr
#pragma pop_macro("constexpr")

#endif // _MSC_VER < 1910

#pragma warning(pop)
#endif // _MSC_VER

#if __GNUC__ > 6
#pragma GCC diagnostic pop
#endif // __GNUC__ > 6

#endif // GSL_SPAN_H


#pragma once

#include <gsl.h>

#include <QmitkAbstractView.h>

#include "ui_SolverSetupView.h"
#include "ui_BoundaryConditionTypeSelectionDialog.h"

#include <HierarchyManager.h>

#include <ImmutableRanges.h>

#include "SolverStudyUIDsTableModel.h"

namespace crimson
{
class ISolverSetupManager;
}

/*! \brief   SolverSetupView allows the user to set up the solver and to write the prepared simulation to disk. */
class SolverSetupView : public QmitkAbstractView
{
    Q_OBJECT

public:
    static const std::string VIEW_ID;

    SolverSetupView();
    ~SolverSetupView();

    void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, const QList<mitk::DataNode::Pointer>& nodes) override;
    void NodeRemoved(const mitk::DataNode* node) override;
    void NodeChanged(const mitk::DataNode* node) override;

private slots:
    void writeSolverSetup();
	void runSimulation();
    void loadSolution();
    void showSolution(bool show);
    void createSolverRoot();
    void createSolverParameters();
    void createSolverStudy();
    void createBoundaryConditionSet();
    void createBoundaryCondition();
    void createMaterial();
    void showMaterial();
    void exportMaterials();
    void setMeshNodeForStudy(const mitk::DataNode*);
    void setSolverParametersNodeForStudy(const mitk::DataNode*);

private:
    void CreateQtPartControl(QWidget* parent) override;
    void SetFocus() override;

    void _updateUI();

    template <class T, class... Args>
    void createSolverObject(mitk::DataNode* ownerNode, Args... additionalArgs);

private:
    // Ui and main widget of this view
    Ui::SolverSetupWidget _UI;

    void _setCurrentRootNode(mitk::DataNode* node);
    void _setCurrentSolverRootNode(mitk::DataNode* node);

    void _findCurrentSolverSetupManager();

    void _setCurrentBoundaryConditionSetNode(mitk::DataNode* node);
    void _setCurrentBoundaryConditionNode(mitk::DataNode* node);
    void _setCurrentMaterialNode(mitk::DataNode* node);
    void _setCurrentSolverParametersNode(mitk::DataNode* node);
    void _setCurrentSolverStudyNode(mitk::DataNode* node);
    void _setupSolverStudyComboBoxes();

    void _selectDataNode(mitk::DataNode* node);

    void _serviceChanged(const us::ServiceEvent event);

    void _solverStudyNodeModified();
    unsigned long _solverStudyObserverTag = -1;

    void _ensureApplyToAllWalls(mitk::DataNode* node) const;
    gsl::cstring_span<> _getTypeNameToCreate(crimson::ImmutableValueRange<gsl::cstring_span<>> options);

    mitk::DataNode* _currentSolverRootNode = nullptr;
    mitk::DataNode* _currentRootNode = nullptr;
    crimson::HierarchyManager::NodeType _currentRootNodeType;
    mitk::DataNode* _currentVesselTreeNode = nullptr;
    mitk::DataNode* _currentBoundaryConditionSetNode = nullptr;
    mitk::DataNode* _currentBoundaryConditionNode = nullptr;
    mitk::DataNode* _currentMaterialNode = nullptr;
    mitk::DataNode* _currentSolverStudyNode = nullptr;
    mitk::DataNode* _currentSolverParametersNode = nullptr;
    mitk::DataNode* _currentSolidNode = nullptr;
    crimson::ISolverSetupManager* _currentSolverSetupManager = nullptr;

    struct RemoveNodeDeleter {
        void operator()(mitk::DataNode* node);
    };

    std::unique_ptr<mitk::DataNode, RemoveNodeDeleter> _materialVisNodePtr;

    Ui::boundaryConditionTypeSelectionDialog _typeSelectionDialogUi;
    QDialog _typeSelectionDialog;

    crimson::SolverStudyUIDsTableModel _solverStudyBCSetsModel;
    crimson::SolverStudyUIDsTableModel _solverStudyMaterialsModel;
};


/**
*\file utils.h
*\author weckyy702 (weckyy702@gmail.com)
*\brief Utility and core Header file
*\date 2021-03-25
*
*MIT License
*Copyright (c) [2021] [Weckyy702 (weckyy702@gmail.com | https://github.com/Weckyy702)]
*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.
*
*/
#ifndef RAYCHEL_CORE_H
#define RAYCHEL_CORE_H

#include <cstdint>
#include <limits>
#if !((defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L))
    #error "C++(17) compilation is required!"
#endif

#include <cassert>
#include <cmath>
#include <cstddef>
#include <gsl/gsl>
#include <type_traits>

//convenience headers
#include <memory>
#include <optional>
#include <utility>
#include <vector>

#include "CMakeSettings.h"
#include "Logger.h"
#include "RaychelMath/constants.h"
#include "RaychelMath/equivalent.h"

#if defined(__clang__) || defined(__GNUC__)
    #define RAYCHEL_FUNC_NAME __PRETTY_FUNCTION__
#elif defined(_MSC_VER)
    #define RAYCHEL_FUNC_NAME __FUNCSIG__
#else
    #error "Unknown compiler detected!"
#endif

#ifdef RAYCHEL_DEBUG
    #define RAYCHEL_LOG(...) Logger::debug(RAYCHEL_FUNC_NAME, ": ", __VA_ARGS__, '\n');
#else
    #define RAYCHEL_LOG(...)
#endif

//terminate the application with the provided message
#ifndef RAYCHEL_NO_LOGGER
    #define RAYCHEL_TERMINATE(...)                                                                                \
        Logger::fatal(RAYCHEL_FUNC_NAME, " at (", __FILE__, ":", __LINE__, "): ", __VA_ARGS__, '\n');                                                \
        std::exit(0x41);
#else
    #define RAYCHEL_TERMINATE(...) std::exit(0x41);
#endif

#if defined(RAYCHEL_DEBUG) || !defined(NDEBUG)
    #define RAYCHEL_ASSERT(exp)                                                                                \
        if (!(exp)) {                                                                                \
            RAYCHEL_TERMINATE("Assertion '", GSL_STRINGIFY(exp), "' failed!");                                                                       \
        }
#else
    #define RAYCHEL_ASSERT(exp) Expects(exp)
#endif

#define RAYCHEL_ASSERT_NOT_REACHED RAYCHEL_TERMINATE("Assertion failed! Expected to not execute ", __FILE__, ":", __LINE__)

//#define RAYCHEL_LOGICALLY_EQUAL //<-- activates logical equivalency for vector-like types

#define RAYCHEL_THROW_EXCEPTION(msg, fatal) throw ::Raychel::exception_context{msg, RAYCHEL_FUNC_NAME, fatal};

#define RAYCHEL_ASSERT_NORMALIZED(vec) RAYCHEL_ASSERT(equivalent(magSq(vec), 1.0f));

namespace Raychel {

    using gsl::byte, gsl::not_null;
    using std::size_t;

    template <typename _num>
    struct vec2Imp;
    template <typename _num>
    struct vec3Imp;
    template <typename _num>
    struct colorImp;
    /*TODO: implement
	template<typename _num>
	class colorAlphaImp;
	*/
    template <typename _num>
    class QuaternionImp;
    template <typename _num>
    struct TransformImp;

    template <typename _number>
    constexpr _number sq(_number x)
    {
        static_assert(std::is_arithmetic_v<_number>, "Raychel::sq<T> requires T to be of arithmetic type!");
        return x * x;
    }

    /**
	*\brief Linearly interpolate between two numbers
	*
	*\tparam _number Type of number to interpolate. Must be arithmetic
	*\param a first number (x=0.0)
	*\param b second number (x=1.0)
	*\param x value of interpolation
	*\return _number the interpolated number
	*/
    template <typename _number>
    constexpr _number lerp(_number a, _number b, long double x)
    {
        return (x * b) + ((1.0 - x) * a);
    }

    template <typename _integral>
    constexpr _integral bit(size_t shift)
    {
        static_assert(std::is_integral_v<_integral>, "Raychel::bit<T> requires T to be of integral type!");
        RAYCHEL_ASSERT(shift < (sizeof(_integral) * 8));
        return static_cast<_integral>(1U << shift);
    }

    /**
	*\brief Get number of digits in a number
	*
	*\param num The number with its digits
	*\return constexpr int
	*/
    constexpr int numDigits(unsigned long long num, unsigned int base = 10U)
    {
        int digits = 0;

        do {
            digits++;
            num /= base;
        } while (num != 0);

        return digits;
    }

} // namespace Raychel

#endif // !RAYCHEL_CORE_H