/*
 * Copyright (c) 2016-2020 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 basis_40d2b174_3729_49b6_a8d6_5b7ac75a2483_h
#define basis_40d2b174_3729_49b6_a8d6_5b7ac75a2483_h

#include <gslib/std.h>
#include <gslib/string.h>
#include <gslib/tree.h>
#include <ariel/widget.h>

namespace ui_editor {

using gs::rect;
using gs::rectf;
using gs::point;
using gs::pointf;
using gs::string;
using gs::list;
using gs::unordered_map;
using gs::gchar;
using gs::uint;
using gs::real;
using gs::real32;
using gs::ariel::painter;
using gs::ariel::wsys_manager;
using gs::ariel::unikey;
typedef gs::ariel::widget core_widget;

struct ui_proc_node;
typedef unordered_map<string, string> ui_prop_map;
typedef unordered_map<string, ui_proc_node> ui_proc_map;

struct ui_proc_node
{
    string              args;
    string              injection;
};

// class ui_editor_configs
// {
//
// };

struct ui_macro
{
    string              name;
    string              definition;

public:
    ui_macro(const string& n): name(n) {}
    ui_macro(const string& n, const string& d): name(n), definition(d) {}
};

typedef list<string> ui_includes;
typedef list<ui_macro> ui_macros;

class ui_src_entry
{
public:
    void add_include(const string& str);
    void add_include_group(const string& strgroup);
    void add_macro(const string& name) { _macro_list.push_back(ui_macro(name)); }
    void add_macro(const string& name, const string& def) { _macro_list.push_back(ui_macro(name, def)); }
    void set_preproc(const string& preproc) { _preproc_injections = preproc; }
    void set_postproc(const string& postproc) { _postproc_injections = postproc; }
    void set_output(const string& str) { _output_name = str; }
    void set_export(const string& str) { _export_name = str; }
    const ui_includes& get_includes() const { return _include_list; }
    const ui_macros& get_macros() const { return _macro_list; }
    const string& get_preproc() const { return _preproc_injections; }
    const string& get_postproc() const { return _postproc_injections; }
    const string& get_output() const { return _output_name; }
    const string& get_export() const { return _export_name; }

protected:
    ui_includes         _include_list;
    ui_macros           _macro_list;
    string              _preproc_injections;
    string              _postproc_injections;
    string              _output_name;       /* for output file name */
    string              _export_name;       /* for export class name */
};

class ui_editor_context
{
public:
    typedef unordered_map<string, int> var_index_map;

public:
    ui_src_entry& get_src_entry() { return _src_entry; }
    const ui_src_entry& const_src_entry() const { return _src_entry; }
    int acquire_variable_index(const string& vartype);
    int query_variable_index(const string& vartype) const;
    int acquire_variable_name(string& name, const string& vartype);

protected:
    ui_src_entry        _src_entry;
    var_index_map       _index_map;
};

class ui_node
{
public:
    rect                position;
    string              type;
    string              name;
    string              variable;
    bool                is_instance;
    ui_prop_map         prop_map;
    ui_proc_map         proc_map;
    core_widget*        assoc_widget;

public:
    ui_node(): is_instance(false), assoc_widget(nullptr) {}
};

typedef gs::_treenode_cpy_wrapper<ui_node> ui_node_wrapper;
typedef gs::tree<ui_node, ui_node_wrapper> ui_tree;

typedef core_widget* (__stdcall *pfn_create_widget)(wsys_manager* wsys, core_widget* parent, ui_node& uinode);

class ui_transparent_layer:
    public core_widget
{
public:
    ui_transparent_layer(wsys_manager* m);
    void install_reflection_widget(core_widget* refw);
    core_widget* get_reflection_widget() const { return _reflection_widget; }

public:
    virtual ~ui_transparent_layer();
    virtual void on_reflection_close();
    virtual void on_reflection_show(bool b);
    virtual void on_reflection_enable(bool b);
    virtual void on_reflection_move(const rect& rc);
    virtual void on_reflection_char(uint um, uint ch) {}
    virtual void on_reflection_caret() {}
    virtual void on_reflection_capture(bool b) {}
    virtual void on_reflection_focus(bool b) {}
    virtual void on_reflection_scroll(const point& pt, real32 scr, bool vert) {}
    virtual void on_reflection_accelerator(unikey key, uint mask) {}

protected:
    core_widget*        _reflection_widget;

protected:
    void sync_size_with_reflection();
};

class ui_edit_control;

class ui_editor_layer:
    public ui_transparent_layer
{
public:
    enum size_orient
    {
        so_none,
        so_n,
        so_s,
        so_e,
        so_w,
        so_ne,
        so_nw,
        so_se,
        so_sw,
    };

public:
    ui_editor_layer(wsys_manager* m);
    void initialize(ui_node& uinode);
    void install_reflection_widget(core_widget* refw);
    ui_node* get_ui_node() const { return _assoc_ui_node; }

public:
    virtual void on_reflection_press(uint um, unikey uk, const point& pt);
    virtual void on_reflection_click(uint um, unikey uk, const point& pt);
    virtual void on_reflection_hover(uint um, const point& pt);
    virtual void on_reflection_leave(uint um, const point& pt);
    virtual void on_reflection_keydown(uint um, unikey uk);
    virtual void on_reflection_keyup(uint um, unikey uk);

protected:
    ui_node*            _assoc_ui_node;
    ui_edit_control*    _edit_ctl;

protected:
    void refresh_cursor(const point& pt);
    size_orient get_size_orient(const point& pt, int accuracy = 3) const;
    void try_install_edit_control(const point& pt);
    void try_uninstall_edit_control();
    void refresh_edit_control(uint um, const point& pt);
};

extern bool ui_create_widgets(wsys_manager* wsys, core_widget* root_layer, ui_tree& uicore);
//extern bool ui_;

}

#endif


/* GLIB - Library of useful routines for C programming
 * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
 * file for a list of people on the GLib Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GLib at ftp://ftp.gtk.org/pub/gtk/.
 */

#ifndef __G_LIB_H__
#define __G_LIB_H__

#include <galloca.h>
#include <garray.h>
#include <gasyncqueue.h>
#include <gbacktrace.h>
#include <gcache.h>
#include <gcompat.h>
#include <gcompletion.h>
#include <gconvert.h>
#include <gdataset.h>
#include <gdate.h>
#include <gerror.h>
#include <gfileutils.h>
#include <ghash.h>
#include <ghook.h>
#include <giochannel.h>
#include <glist.h>
#include <gmacros.h>
#include <gmain.h>
#include <gmarkup.h>
#include <gmem.h>
#include <gmessages.h>
#include <gnode.h>
#include <gprimes.h>
#include <gqsort.h>
#include <gquark.h>
#include <gqueue.h>
#include <grand.h>
#include <grel.h>
#include <gscanner.h>
#include <gshell.h>
#include <gslist.h>
#include <gspawn.h>
#include <gstrfuncs.h>
#include <gstring.h>
#include <gthread.h>
#include <gthreadpool.h>
#include <gtimer.h>
#include <gtree.h>
#include <gtypes.h>
#include <gunicode.h>
#include <gutils.h>
#ifdef G_OS_WIN32
#include <gwin32.h>
#endif

#endif /* __G_LIB_H__ */


/***
 * Copyright 2020 The Katla Authors
 *
 * 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.
 */
#ifndef KATLA_MQTT_MESSAGE_H
#define KATLA_MQTT_MESSAGE_H

#include "outcome/outcome.hpp"

#include <gsl/span>

namespace katla {

enum class MqttQos {AtMostOnce = 0, AtLeastOnce = 1, ExactlyOnce = 2};

struct MqttMessage {
    int messageId {};
    std::string topic;
    gsl::span<std::byte> payload;
    MqttQos qos;
    bool retain;
};

} // namespace katla

#endif


#pragma once

#include <winrt\Windows.Foundation.h>
#include <d3d11.h>
#include <DirectXMath.h>
#include <gsl\gsl>

namespace Library
{
	class SamplerStates final
	{
	public:
		inline static winrt::com_ptr<ID3D11SamplerState> TrilinearWrap;
		inline static winrt::com_ptr<ID3D11SamplerState> TrilinearMirror;
		inline static winrt::com_ptr<ID3D11SamplerState> TrilinearClamp;
		inline static winrt::com_ptr<ID3D11SamplerState> TrilinearBorder;
		inline static winrt::com_ptr<ID3D11SamplerState> PointClamp;
		inline static winrt::com_ptr<ID3D11SamplerState> DepthMap;
		inline static winrt::com_ptr<ID3D11SamplerState> ShadowMap;
		inline static winrt::com_ptr<ID3D11SamplerState> PcfShadowMap;

		static DirectX::XMVECTORF32 BorderColor;
		static DirectX::XMVECTORF32 ShadowMapBorderColor;

		static void Initialize(gsl::not_null<ID3D11Device*> direct3DDevice);
		static void Shutdown();

		SamplerStates() = delete;
		SamplerStates(const SamplerStates&) = delete;
		SamplerStates& operator=(const SamplerStates&) = delete;
		SamplerStates(SamplerStates&&) = delete;
		SamplerStates& operator=(SamplerStates&&) = delete;
		~SamplerStates() = default;
	};
}


#ifndef _UI_HELPERS_H_
#define _UI_HELPERS_H_

#define OEMRESOURCE

#include <algorithm>
#include <functional>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <vector>

#include <ppl.h>

#include <gsl/gsl>

// Included before windows.h, because pfc.h includes winsock2.h
#include "../pfc/pfc.h"

#include <windows.h>
#include <WindowsX.h>
#include <SHLWAPI.H>
#include <vssym32.h>
#include <uxtheme.h>
#include <shldisp.h>
#include <ShlObj.h>
#include <gdiplus.h>
#include <Usp10.h>
#include <CommonControls.h>

#include <wil/resource.h>

// Windows SDK headers define min and max macros, which are used by gdiplus.h.
//
// This undefines them temporarily to avoid conflicts with the C++ standard
// library. They are redefined at the end of this header.
#ifdef max
#define _UI_HELPERS_OLD_MAX_
#undef max
#endif

#ifdef min
#define _UI_HELPERS_OLD_MIN_
#undef min
#endif

#include "../mmh/stdafx.h"

#ifndef RECT_CX
#define RECT_CX(rc) (rc.right - rc.left)
#endif

#ifndef RECT_CY
#define RECT_CY(rc) (rc.bottom - rc.top)
#endif

#include "literals.h"

#include "handle.h"
#include "win32_helpers.h"
#include "ole.h"

#include "dialog.h"
#include "dpi.h"
#include "container_window.h"
#include "message_hook.h"
#include "trackbar.h"
#include "solid_fill.h"
#include "theming.h"

#include "gdi.h"
#include "text_drawing.h"
#include "list_view/list_view.h"
#include "drag_image.h"
#include "info_box.h"
#include "menu.h"

#include "ole/data_object.h"
#include "ole/enum_format_etc.h"

#ifdef _UI_HELPERS_OLD_MAX_
#define max(a, b) (((a) > (b)) ? (a) : (b))
#undef _UI_HELPERS_OLD_MAX_
#endif

#ifdef _UI_HELPERS_OLD_MIN_
#define min(a, b) (((a) < (b)) ? (a) : (b))
#undef _UI_HELPERS_OLD_MIN_
#endif

#endif


/*
   Copyright [2017-2019] [IBM Corporation]
   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.
*/

#ifndef COMANCHE_HSTORE_POOL_MANAGER_H
#define COMANCHE_HSTORE_POOL_MANAGER_H

#include <api/kvstore_itf.h> /* status_t */

#include "alloc_key.h"

#include <common/logging.h> /* log_source */
#include <nupm/region_descriptor.h>
#include <gsl/pointers>
#include <sys/uio.h>
#include <cstddef>
#include <functional>
#include <string>
#include <system_error>

struct pool_path;

#pragma GCC diagnostic push
// #pragma GCC diagnostic ignored "-Wunused-parameter"

enum class pool_ec
{
  pool_fail,
  pool_unsupported_mode,
  region_fail,
  region_fail_general_exception,
  region_fail_api_exception,
};

struct pool_category
  : public std::error_category
{
  const char* name() const noexcept override { return "pool_category"; }
  std::string message( int condition ) const noexcept override
  {
    switch ( condition )
    {
    case int(pool_ec::pool_fail):
      return "default pool failure";
    case int(pool_ec::pool_unsupported_mode):
      return "pool unsupported flags";
    case int(pool_ec::region_fail):
      return "region-backed pool failure";
    case int(pool_ec::region_fail_general_exception):
      return "region-backed pool failure (General_exception)";
    case int(pool_ec::region_fail_api_exception):
      return "region-backed pool failure (API_exception)";
    default:
      return "unknown pool failure";
    }
  }
};

namespace
{
  pool_category pool_error_category;
}

struct pool_error
  : public std::error_condition
{
  std::string _msg;
public:
  pool_error(const std::string &msg_, pool_ec val_)
    : std::error_condition(int(val_), pool_error_category)
    , _msg(msg_)
  {}

};

struct dax_manager;

template <typename Pool>
  struct pool_manager
    : protected common::log_source
  {
    pool_manager(unsigned debug_level_) : common::log_source(debug_level_) {}
    virtual ~pool_manager() {}

    virtual void pool_create_check(const std::size_t size_) = 0;

    virtual void pool_close_check(const std::string &) = 0;

    virtual nupm::region_descriptor pool_get_regions(const Pool &) const = 0;

    /*
     * throws pool_error if create_region fails
     */
    virtual auto pool_create_1(
      const pool_path &path_
      , std::size_t size_
    ) -> nupm::region_descriptor = 0;

    virtual auto pool_create_2(
      AK_FORMAL
      const nupm::region_descriptor & rac
      , component::IKVStore::flags_t flags
      , std::size_t expected_obj_count
    ) -> std::unique_ptr<Pool> = 0;

    virtual auto pool_open_1(
      const pool_path &path_
    ) -> nupm::region_descriptor = 0;

    virtual auto pool_open_2(
      AK_FORMAL
      const nupm::region_descriptor & access_
      , component::IKVStore::flags_t flags_
    ) -> std::unique_ptr<Pool> = 0;

    virtual void pool_delete(const pool_path &path) = 0;
    virtual const std::unique_ptr<dax_manager> & get_dax_manager() const = 0;
  };
#pragma GCC diagnostic pop

#endif


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

#ifndef CL_COMMAND_QUEUE
#define CL_COMMAND_QUEUE

#ifdef __APPLE__
	#include <OpenCL/cl.h>
#else
	#include <CL/cl.h>
#endif

#include <cl/Kernel.h>
#include <cl/Event.h>
#include <cl/Memory.h>

#include <util/util.h>

#include <gsl/span>

#include <array>
#include <vector>
#include <cstddef>

namespace cl
{
	struct Context;
	struct Device;

	enum NDRange : cl_uint
	{
		Range1D = 1,
		Range2D = 2,
		Range3D = 3,
	};

	struct Range
	{
		std::size_t offset;
		std::size_t size;
	};

	enum class ExecMode : cl_command_queue_properties
	{
		   InOrder = 0,
		OutOfOrder = CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE,
	};

	enum class Profiling : cl_command_queue_properties
	{
		 Enable = CL_QUEUE_PROFILING_ENABLE,
		Disable = 0,
	};

	struct CommandQueue
	{
		cl_command_queue clCommandQueue;

		CommandQueue
		(
			const Context& context, const Device& device,
			ExecMode  execMode  = ExecMode::InOrder,
			Profiling profiling = Profiling::Disable
		);

		~CommandQueue ();

		CommandQueue (CommandQueue&& commandQueue);
		CommandQueue (const CommandQueue& commandQueue) = delete;

		CommandQueue& operator = (CommandQueue&& commandQueue);
		CommandQueue& operator = (const CommandQueue& commandQueue) = delete;

		struct Properties
		{
			ExecMode  execMode;
			Profiling profiling;
		};

		enum class Info : cl_command_queue_info
		{
			ReferenceCount = CL_QUEUE_REFERENCE_COUNT,
			Properties     = CL_QUEUE_PROPERTIES,
		};

		template <Info info>
		auto GetInfo() const
		{
			auto infoSize = std::size_t { 0 };
			auto result = clGetCommandQueueInfo
			(
				clCommandQueue, util::enum_cast(info),
				0, nullptr, &infoSize
			);
			assert(result == CL_SUCCESS);

			auto infoBytes = std::vector<std::byte>
			{
				infoSize, std::byte { 0x00 }
			};
			result = clGetCommandQueueInfo
			(
				clCommandQueue, util::enum_cast(info),
				infoBytes.size(), infoBytes.data(), nullptr
			);
			assert(result == CL_SUCCESS);

			return InfoResult<info>::FromBytes(infoBytes);
		}

		template <NDRange WorkDimension>
		Event EnqueueKernel
		(
			const Kernel& kernel,
			const std::array<size_t, WorkDimension>& globalWorkSize,
			const std::array<size_t, WorkDimension>&  localWorkSize,
			const std::vector<Event>& waitEvents
		)
		{
			static_assert(sizeof(Event) == sizeof(cl_event));

			const auto globalWorkOffset = std::array<size_t, WorkDimension> { };

			auto signalEvent = cl_event { };

			auto result = clEnqueueNDRangeKernel
			(
				clCommandQueue, kernel.clKernel,
				WorkDimension,
				globalWorkOffset.data(),
				globalWorkSize.data(), localWorkSize.data(),
				static_cast<cl_uint>(waitEvents.size()),
				reinterpret_cast<const cl_event*>(util::data_or_null(waitEvents)),
				&signalEvent
			);
			assert(result == CL_SUCCESS);

			return Event { signalEvent };
		}

		template <typename ValueType>
		Event EnqueueReadBuffer
		(
			const Memory<ValueType>& memory,
			const gsl::span<ValueType> buffer,
			const Range& range,
			const std::vector<Event>& waitEvents
		)
		{
			assert(buffer.size() >= static_cast<std::ptrdiff_t>(range.size));

			auto signalEvent = cl_event { };

			auto result = clEnqueueReadBuffer
			(
				clCommandQueue, memory.clMemory,
				cl_bool { CL_BLOCKING },
				range.offset, sizeof(ValueType) * range.size,
				buffer.data(),
				static_cast<cl_uint>(waitEvents.size()),
				reinterpret_cast<const cl_event*>(util::data_or_null(waitEvents)),
				&signalEvent
			);
			assert(result == CL_SUCCESS);

			return Event { signalEvent };
		}

	private:

		template <Info info>
		struct InfoResult;
	};

	template <>
	struct CommandQueue::InfoResult<CommandQueue::Info::ReferenceCount>
	{
		static cl_uint
		FromBytes (const std::vector<std::byte>& infoBytes);
	};

	template <>
	struct CommandQueue::InfoResult<CommandQueue::Info::Properties>
	{
		static CommandQueue::Properties
		FromBytes (const std::vector<std::byte>& infoBytes);
	};
}

#endif


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

///
/// @file bfgsl.h
///

#ifndef BFGSL_H
#define BFGSL_H

#if defined(__clang__) || defined(__GNUC__)
#pragma GCC system_header
#endif

#include <string.h>

/// @cond

#define concat1(a,b) a ## b
#define concat2(a,b) concat1(a,b)
#define ___ concat2(dont_care, __COUNTER__)

/// @endcond

#ifndef NEED_GSL_LITE

#include <gsl/gsl>

namespace gsl
{

/// @cond

#define expects(cond) Expects(cond)
#define ensures(cond) Ensures(cond)

template <class F>
class final_act_success
{
public:
    explicit final_act_success(F f) noexcept : f_(std::move(f)), invoke_(true) {}

    final_act_success(final_act_success &&other) noexcept : f_(std::move(other.f_)), invoke_(other.invoke_)
    {
        other.invoke_ = false;
    }

    final_act_success(const final_act_success &) = delete;
    final_act_success &operator=(const final_act_success &) = delete;

    ~final_act_success() noexcept
    {
        if (std::uncaught_exception()) {
            return;
        }

        if (invoke_) { f_(); }
    }

private:
    F f_;
    bool invoke_;
};

template <class F>
class final_act_failure
{
public:
    explicit final_act_failure(F f) noexcept : f_(std::move(f)), invoke_(true) {}

    final_act_failure(final_act_failure &&other) noexcept : f_(std::move(other.f_)), invoke_(other.invoke_)
    {
        other.invoke_ = false;
    }

    final_act_failure(const final_act_failure &) = delete;
    final_act_failure &operator=(const final_act_failure &) = delete;

    ~final_act_failure() noexcept
    {
        if (!std::uncaught_exception()) {
            return;
        }

        if (invoke_) { f_(); }
    }

private:
    F f_;
    bool invoke_;
};

template <class F>
inline final_act_success<F> on_success(const F &f) noexcept
{
    return final_act_success<F>(f);
}

template <class F>
inline final_act_success<F> on_success(F &&f) noexcept
{
    return final_act_success<F>(std::forward<F>(f));
}

template <class F>
inline final_act_failure<F> on_failure(const F &f) noexcept
{
    return final_act_failure<F>(f);
}

template <class F>
inline final_act_failure<F> on_failure(F &&f) noexcept
{
    return final_act_failure<F>(std::forward<F>(f));
}

/// @endcond

/// Memset
///
/// Same as std::memset, but for spans
///
/// @param dst The span to memset
/// @param val The value to set the span to
/// @return Returns dst
///
template<class DstElementType, std::ptrdiff_t DstExtent, class T>
auto memset(span<DstElementType, DstExtent> dst, T val)
{
    expects(dst.size() > 0);

    return std::memset(
               dst.data(),
               static_cast<int>(val),
               static_cast<std::size_t>(dst.size())
           );
}

}

#else

#ifdef NEED_STD_LITE
#include <bfstd.h>
#endif

/// @cond

#if defined(__clang__) || defined(__GNUC__)
#define gsl_likely(x) __builtin_expect(!!(x), 1)
#define gsl_unlikely(x) __builtin_expect(!!(x), 0)
#else
#define gsl_likely(x) (x)
#define gsl_unlikely(x) (x)
#endif

#ifndef GSL_ABORT
#define GSL_ABORT abort
#endif

#define expects(cond)                                                                              \
    if (gsl_unlikely(!(cond))) {                                                                   \
        GSL_ABORT();                                                                               \
    }
#define ensures(cond)                                                                              \
    if (gsl_unlikely(!(cond))) {                                                                   \
        GSL_ABORT();                                                                               \
    }

/// @endcond

namespace gsl
{

/// Narrow Cast
///
/// A rename of static_cast to indicate a narrow (e.g. 64bit to 32bit)
///
/// @param u the value to narrow
/// @return static_cast<T>(u)
///
template<class T, class U>
inline constexpr T
narrow_cast(U &&u) noexcept
{
    return static_cast<T>(std::forward<U>(u));
}

/// At
///
/// Returns a reference to an element in an array given an index. Unlike
/// the [] operator, if the indexis out-of-bounds, an exception is thrown,
/// or std::terminate() is called.
///
/// @param arr the array
/// @param index the index of the element to retrieve.
/// @return a reference to
///
template<class T, size_t N, class I>
constexpr T &
at(T(&arr)[N], I index)
{
    expects(index >= 0 && index < narrow_cast<I>(N));
    return arr[static_cast<size_t>(index)];
}

/// At
///
/// Returns a reference to an element in an array given an index. Unlike
/// the [] operator, if the indexis out-of-bounds, an exception is thrown,
/// or std::terminate() is called.
///
/// @param arr the array
/// @param index the index of the element to retrieve.
/// @return a reference to
///
template<class T, size_t N, class I>
const constexpr T &
at(const T(&arr)[N], I index)
{
    expects(index >= 0 && index < narrow_cast<I>(N));
    return arr[static_cast<size_t>(index)];
}

/// At
///
/// Returns a reference to an element in an array given an index. Unlike
/// the [] operator, if the indexis out-of-bounds, an exception is thrown,
/// or std::terminate() is called.
///
/// @param arr the array
/// @param N the size of the array
/// @param index the index of the element to retrieve.
/// @return a reference to
///
template<class T, class I>
constexpr T &
at(T *arr, size_t N, I index)
{
    expects(index >= 0 && index < narrow_cast<I>(N));
    return arr[static_cast<size_t>(index)];
}

/// At
///
/// Returns a reference to an element in an array given an index. Unlike
/// the [] operator, if the indexis out-of-bounds, an exception is thrown,
/// or std::terminate() is called.
///
/// @param arr the array
/// @param N the size of the array
/// @param index the index of the element to retrieve.
/// @return a reference to
///
template<class T, class I>
const constexpr T &
at(const T *arr, size_t N, I index)
{
    expects(index >= 0 && index < narrow_cast<I>(N));
    return arr[static_cast<size_t>(index)];
}

}

#endif

#endif


#pragma once
/*For Engine Only*/
//#include <glad\glad.h>
//#include <GLFW\glfw3.h>
//#include <gsl\gsl>
//#include <SOIL2.h>
//#include <imgui.h>
//#include <glm\glm.hpp>
//#include <spdlog\spdlog.h>
//
///*Logger System*/
//#include "BooErEngine\Utils\Log.h"
//
///*Event's System*/
//#include "BooErEngine\Events\Event.h"
//#include "BooErEngine\Events\AppEvent.h"
//
///* Layer System*/
//#include "BooErEngine\Layers\LayerSatck.h"
//
///* InputMgr */
//#include "BooErEngine\ImputMgr.h"
//#include "BooErEngine\Platforms\Windows\WindowsInputMgr.h"


#pragma once

#include <boost/variant.hpp>
//#include <gsl/span>
#include <gsl/gsl>
#include <boost/system/system_error.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/write.hpp>

namespace mothbus
{
	template<class ...T>
	using variant = boost::variant<T...>;

	template<class T>//, std::ptrdiff_t Extent=gsl::dynamic_extent>
	using span = gsl::span<T>;//, Extent>;

	using byte = gsl::byte;

	template <typename SyncWriteStream, typename ConstBufferSequence>
	inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers)
	{
		return boost::asio::write(s, buffers);
	}

	template <typename SyncWriteStream, typename ConstBufferSequence, typename ErrorCode>
	inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, ErrorCode& ec)
	{
		return boost::asio::write(s, buffers, ec);
	}

	template <typename SyncReadStream, typename MutableBufferSequence>
	inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers)
	{
		return boost::asio::read(s, buffers);
	}

	template <typename SyncReadStream, typename MutableBufferSequence, typename ErrorCode>
	inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,  ErrorCode& ec)
	{
		return boost::asio::read(s, buffers, ec);
	}

	template <typename SyncReadStream, typename MutableBufferSequence, typename ReadHandler>
	inline void async_read(SyncReadStream& s, const MutableBufferSequence& buffers, ReadHandler&& handler)
	{
		boost::asio::async_read(s, buffers, std::forward<ReadHandler>(handler));
	}

	class modbus_exception// : public std::runtime_error
	{
	public:
		modbus_exception(int error_code):
		error_code(error_code)
		{}

		int error_code;
	};
}


#pragma once
#define VULKAN_H_ 1
#include <vulkan/vk_platform.h>
#include <vulkan/vulkan_core.h>

#if defined(VK_USE_PLATFORM_WIN32_KHR)
// This is to avoid including Windows.h
#ifndef DECLARE_HANDLE
using HANDLE = void*;

#define DECLARE_HANDLE(name) struct name##__; typedef struct name##__ *name
DECLARE_HANDLE(HINSTANCE);
DECLARE_HANDLE(HMONITOR);
DECLARE_HANDLE(HWND);
#undef DECLARE_HANDLE

struct _SECURITY_ATTRIBUTES;
using SECURITY_ATTRIBUTES = _SECURITY_ATTRIBUTES;

using LPCWSTR = const wchar_t*;
using PCWSTR = const wchar_t*;
using DWORD = unsigned long; // NOLINT(google-runtime-int)
#endif

// ReSharper disable once CppUnusedIncludeDirective
#include <vulkan/vulkan_win32.h>
#endif

#if defined(VK_USE_PLATFORM_XCB_KHR)
typedef struct xcb_connection_t xcb_connection_t;
typedef uint32_t xcb_window_t;
typedef uint32_t xcb_visualid_t;

// ReSharper disable once CppUnusedIncludeDirective
#include <vulkan/vulkan_xcb.h>
#endif

#if defined(VK_USE_PLATFORM_XLIB_KHR)
typedef struct _XDisplay Display;
typedef unsigned long XID;
typedef XID Window;
typedef unsigned long VisualID;

// ReSharper disable once CppUnusedIncludeDirective
#include <vulkan/vulkan_xlib.h>
#endif

#if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT)
typedef struct _XDisplay Display;
typedef unsigned long XID;
typedef XID Window;
typedef unsigned long VisualID;
typedef XID RROutput;

// ReSharper disable once CppUnusedIncludeDirective
#include <vulkan/vulkan_xlib_xrandr.h>
#endif

#include "Config.h"

#include <vulkan/vk_icd.h>

#include <gsl/gsl>

#if !defined(_MSC_VER)
#define __debugbreak() __asm__("int3")

inline void strcpy_s(char* destination, const char* source)
{
	strcpy(destination, source);
}
#endif
#define TODO_ERROR() if (1) { __debugbreak(); abort(); } else (void)0
#define FATAL_ERROR() if (1) { __debugbreak(); abort(); } else (void)0

#if defined(_MSC_VER)
#define CP_DLL_EXPORT __declspec(dllexport)
#else
#define CP_DLL_EXPORT
#endif

#pragma warning(push)
#pragma warning(disable: 26490 26474 26408 26409)

struct DeviceMemory;

class Buffer;
class BufferView;
class CommandBuffer;
class CommandPool;
class CompiledShaderModule;
class ComputePipeline;
class DescriptorPool;
class DescriptorSet;
class DescriptorSetLayout;
class Device;
class Event;
class Fence;
class Framebuffer;
class GraphicsPipeline;
class Image;
class ImageView;
class Instance;
class PhysicalDevice;
class Pipeline;
class PipelineCache;
class PipelineLayout;
class QueryPool;
class Queue;
class RenderPass;
class Sampler;
class Semaphore;
class ShaderModule;

#if defined(VK_NV_ray_tracing)
class RayTracingPipeline;
#endif

template<typename LocalType>
struct VulkanTypeHelper;

#define VK_TYPE_HELPER(VulkanType, LocalType, NonDispatchable) template<> struct VulkanTypeHelper<LocalType> { static constexpr auto IsNonDispatchable = NonDispatchable; using Type = VulkanType; }

VK_TYPE_HELPER(VkInstance, Instance, false);

VK_TYPE_HELPER(VkPhysicalDevice, PhysicalDevice, false);

VK_TYPE_HELPER(VkDevice, Device, false);

VK_TYPE_HELPER(VkQueue, Queue, false);

VK_TYPE_HELPER(VkSemaphore, Semaphore, true);

VK_TYPE_HELPER(VkCommandBuffer, CommandBuffer, false);

VK_TYPE_HELPER(VkFence, Fence, true);

VK_TYPE_HELPER(VkDeviceMemory, DeviceMemory, true);

VK_TYPE_HELPER(VkBuffer, Buffer, true);

VK_TYPE_HELPER(VkImage, Image, true);

VK_TYPE_HELPER(VkEvent, Event, true);

VK_TYPE_HELPER(VkQueryPool, QueryPool, true);

VK_TYPE_HELPER(VkBufferView, BufferView, true);

VK_TYPE_HELPER(VkImageView, ImageView, true);

VK_TYPE_HELPER(VkShaderModule, ShaderModule, true);

VK_TYPE_HELPER(VkPipelineCache, PipelineCache, true);

VK_TYPE_HELPER(VkPipelineLayout, PipelineLayout, true);

VK_TYPE_HELPER(VkRenderPass, RenderPass, true);

VK_TYPE_HELPER(VkPipeline, Pipeline, true);

VK_TYPE_HELPER(VkPipeline, ComputePipeline, true);

VK_TYPE_HELPER(VkPipeline, GraphicsPipeline, true);

#if defined(VK_NV_ray_tracing)
VK_TYPE_HELPER(VkPipeline, RayTracingPipeline, true);
#endif

VK_TYPE_HELPER(VkDescriptorSetLayout, DescriptorSetLayout, true);

VK_TYPE_HELPER(VkSampler, Sampler, true);

VK_TYPE_HELPER(VkDescriptorPool, DescriptorPool, true);

VK_TYPE_HELPER(VkDescriptorSet, DescriptorSet, true);

VK_TYPE_HELPER(VkFramebuffer, Framebuffer, true);

VK_TYPE_HELPER(VkCommandPool, CommandPool, true);

#if defined(VK_VERSION_1_1)
class DescriptorUpdateTemplate;
class SamplerYcbcrConversion;

VK_TYPE_HELPER(VkSamplerYcbcrConversion, SamplerYcbcrConversion, true);

VK_TYPE_HELPER(VkDescriptorUpdateTemplate, DescriptorUpdateTemplate, true);
#endif

#if defined(VK_KHR_surface)
VK_TYPE_HELPER(VkSurfaceKHR, VkIcdSurfaceBase, true);

#if defined(VK_USE_PLATFORM_WIN32_KHR)
VK_TYPE_HELPER(VkSurfaceKHR, VkIcdSurfaceWin32, true);
#endif

#if defined(VK_USE_PLATFORM_XCB_KHR)
VK_TYPE_HELPER(VkSurfaceKHR, VkIcdSurfaceXcb, true);
#endif

#if defined(VK_USE_PLATFORM_XLIB_KHR)
VK_TYPE_HELPER(VkSurfaceKHR, VkIcdSurfaceXlib, true);
#endif
#endif

#if defined(VK_KHR_swapchain)
class Swapchain;
VK_TYPE_HELPER(VkSwapchainKHR, Swapchain, true);
#endif

#if defined(VK_KHR_display)
class VDisplay;
class DisplayMode;

VK_TYPE_HELPER(VkDisplayKHR, VDisplay, true);
VK_TYPE_HELPER(VkDisplayModeKHR, DisplayMode, true);
#endif

#if defined(VK_EXT_debug_report)
class DebugReportCallback;
VK_TYPE_HELPER(VkDebugReportCallbackEXT, DebugReportCallback, true);
#endif

#if defined(VK_NVX_device_generated_commands)
class IndirectCommandsLayout;
class ObjectTable;

VK_TYPE_HELPER(VkObjectTableNVX, ObjectTable, true);

VK_TYPE_HELPER(VkIndirectCommandsLayoutNVX, IndirectCommandsLayout, true);
#endif

#if defined(VK_EXT_debug_utils)
class DebugUtilsMessenger;
VK_TYPE_HELPER(VkDebugUtilsMessengerEXT, DebugUtilsMessenger, true);
#endif

#if defined(VK_EXT_validation_cache)
class ValidationCache;
VK_TYPE_HELPER(VkValidationCacheEXT, ValidationCache, true);
#endif

#if defined(VK_NV_ray_tracing)
class AccelerationStructure;
VK_TYPE_HELPER(VkAccelerationStructureNV, AccelerationStructure, true);
#endif

#if defined(VK_INTEL_performance_query)
class PerformanceConfiguration;
VK_TYPE_HELPER(VkPerformanceConfigurationINTEL, PerformanceConfiguration, true);
#endif

#undef VK_TYPE_HELPER

template<typename T, class... Types>
T* Allocate(const VkAllocationCallbacks* pAllocator, VkSystemAllocationScope allocationScope, Types&& ... args)
{
	constexpr auto size = VulkanTypeHelper<T>::IsNonDispatchable ? sizeof(T) : sizeof(T) + 16;
	const auto data = pAllocator
		                  ? static_cast<uint8_t*>(pAllocator->pfnAllocation(pAllocator->pUserData, size, 16, allocationScope))
		                  : static_cast<uint8_t*>(malloc(size));

	if (!data)
	{
		return nullptr;
	}

	if (VulkanTypeHelper<T>::IsNonDispatchable)
	{
		return new(data) T(std::forward<Types>(args)...);
	}

	*static_cast<uintptr_t*>(static_cast<void*>(data)) = ICD_LOADER_MAGIC;
	return new(data + 16) T(std::forward<Types>(args)...);
}

template<typename T>
void Free(T* value, const VkAllocationCallbacks* pAllocator) noexcept
{
	value->OnDelete(pAllocator);
	value->~T();
	const auto data = static_cast<uint8_t*>(static_cast<void*>(value)) - (VulkanTypeHelper<T>::IsNonDispatchable ? 0 : 16);

	if (pAllocator)
	{
		pAllocator->pfnFree(pAllocator->pUserData, data);
	}
	else
	{
		free(data);
	}
}

#if defined(VK_USE_PLATFORM_WIN32_KHR)
template<>
inline void Free(VkIcdSurfaceWin32* value, const VkAllocationCallbacks* pAllocator) noexcept
{
	if (pAllocator)
	{
		pAllocator->pfnFree(pAllocator->pUserData, value);
	}
	else
	{
		free(value);
	}
}
#endif

#if defined(VK_USE_PLATFORM_XCB_KHR)
template<>
inline void Free(VkIcdSurfaceXcb* value, const VkAllocationCallbacks* pAllocator) noexcept
{
	if (pAllocator)
	{
		pAllocator->pfnFree(pAllocator->pUserData, value);
	}
	else
	{
		free(value);
	}
}
#endif

#if defined(VK_USE_PLATFORM_XLIB_KHR)
template<>
inline void Free(VkIcdSurfaceXlib* value, const VkAllocationCallbacks* pAllocator) noexcept
{
	if (pAllocator)
	{
		pAllocator->pfnFree(pAllocator->pUserData, value);
	}
	else
	{
		free(value);
	}
}
#endif

template<bool IsNonDispatchable>
void WrapVulkan(void* local, uint64_t* vulkan) noexcept;

template<bool IsNonDispatchable>
void* UnwrapVulkan(uint64_t vulkanValue) noexcept;

template<>
inline void WrapVulkan<false>(void* local, uint64_t* vulkan) noexcept
{
	assert(local);
	assert(vulkan);
	const auto data = static_cast<uint8_t*>(local);
	*vulkan = reinterpret_cast<uint64_t>(data - 16);
}

template<>
inline void* UnwrapVulkan<false>(uint64_t vulkanValue) noexcept
{
	assert(vulkanValue);
	return reinterpret_cast<void*>(vulkanValue + 16);
}

template<>
inline void WrapVulkan<true>(void* local, uint64_t* vulkan) noexcept
{
	assert(local);
	assert(vulkan);
	*vulkan = reinterpret_cast<uint64_t>(local);
}

template<>
inline void* UnwrapVulkan<true>(uint64_t vulkanValue) noexcept
{
	assert(vulkanValue);
	return reinterpret_cast<void*>(vulkanValue);
}

template<typename LocalType>
void WrapVulkan(LocalType* local, typename VulkanTypeHelper<LocalType>::Type* vulkan) noexcept
{
	WrapVulkan<VulkanTypeHelper<LocalType>::IsNonDispatchable>(local, reinterpret_cast<uint64_t*>(vulkan));
}

template<typename LocalType>
LocalType* UnwrapVulkan(typename VulkanTypeHelper<LocalType>::Type vulkanValue) noexcept
{
	return reinterpret_cast<LocalType*>(UnwrapVulkan<VulkanTypeHelper<LocalType>::IsNonDispatchable>(reinterpret_cast<uint64_t>(vulkanValue)));
}
#pragma warning(pop)

constexpr auto PI = 3.14159265358979323846;


#pragma once

#include "icode_generator.h"
#include <halley/data_structures/hash_map.h>
#include <gsl/gsl>
#include "halley/file/path.h"

namespace YAML
{
	class Node;
}

namespace Halley
{
	class ComponentSchema;
	class SystemSchema;
	class MessageSchema;
	class CustomTypeSchema;

	class Codegen
	{
		struct Stats
		{
			int written = 0;
			int skipped = 0;
			std::vector<Path> files;
		};

		static bool doNothing(float, String) { return true; }

	public:
		using ProgressReporter = std::function<bool(float, String)>;

		static void run(Path inDir, Path outDir);

		explicit Codegen(bool verbose = false);

		void loadSources(std::vector<std::pair<String, gsl::span<const gsl::byte>>> files, ProgressReporter progress = &doNothing);
		void validate(ProgressReporter progress = &doNothing);
		void process();
		bool writeFile(Path path, const char* data, size_t dataSize, bool stub) const;
		void writeFiles(Path directory, const CodeGenResult& files, Stats& stats) const;
		std::vector<Path> generateCode(Path directory, ProgressReporter progress = &doNothing);

	private:
		void addSource(String name, gsl::span<const gsl::byte> data);
		void addComponent(YAML::Node rootNode);
		void addSystem(YAML::Node rootNode);
		void addMessage(YAML::Node rootNode);
		void addType(YAML::Node rootNode);
		String getInclude(String typeName) const;

		bool verbose;
		HashMap<String, ComponentSchema> components;
		HashMap<String, SystemSchema> systems;
		HashMap<String, MessageSchema> messages;
		HashMap<String, CustomTypeSchema> types;
	};
}


#pragma once

#include "CesiumGltf/MetadataArrayView.h"
#include "CesiumGltf/PropertyType.h"
#include "CesiumGltf/PropertyTypeTraits.h"

#include <gsl/span>

#include <cassert>
#include <cstddef>
#include <cstdint>
#include <string_view>
#include <type_traits>

namespace CesiumGltf {
/**
 * @brief Indicates the status of a property view.
 *
 * The {@link MetadataPropertyView} constructor always completes successfully. However,
 * it may not always reflect the actual content of the {@link FeatureTableProperty}, but
 * instead indicate that its {@link MetadataPropertyView::size} is 0. This enumeration
 * provides the reason.
 */
enum class MetadataPropertyViewStatus {
  /**
   * @brief This property view is valid and ready to use.
   */
  Valid,

  /**
   * @brief This property view does not exist in the FeatureTable.
   */
  InvalidPropertyNotExist,

  /**
   * @brief This property view does not have a correct type with what is
   * specified in {@link ClassProperty::type}.
   */
  InvalidTypeMismatch,

  /**
   * @brief This property view does not have a valid value buffer view index.
   */
  InvalidValueBufferViewIndex,

  /**
   * @brief This array property view does not have a valid array offset buffer
   * view index.
   */
  InvalidArrayOffsetBufferViewIndex,

  /**
   * @brief This string property view does not have a valid string offset buffer
   * view index.
   */
  InvalidStringOffsetBufferViewIndex,

  /**
   * @brief This property view has a valid value buffer view index, but buffer
   * view specifies an invalid buffer index
   */
  InvalidValueBufferIndex,

  /**
   * @brief This property view has a valid array string buffer view index, but
   * buffer view specifies an invalid buffer index
   */
  InvalidArrayOffsetBufferIndex,

  /**
   * @brief This property view has a valid string offset buffer view index, but
   * buffer view specifies an invalid buffer index
   */
  InvalidStringOffsetBufferIndex,

  /**
   * @brief This property view has buffer view's offset not aligned by 8 bytes
   */
  InvalidBufferViewNotAligned8Bytes,

  /**
   * @brief This property view has an out-of-bound buffer view
   */
  InvalidBufferViewOutOfBound,

  /**
   * @brief This property view has an invalid buffer view's length which is not
   * a multiple of the size of its type or offset type
   */
  InvalidBufferViewSizeNotDivisibleByTypeSize,

  /**
   * @brief This property view has an invalid buffer view's length which cannot
   * fit all the instances of the feature table
   */
  InvalidBufferViewSizeNotFitInstanceCount,

  /**
   * @brief This array property view has both component count and offset buffer
   * view
   */
  InvalidArrayComponentCountAndOffsetBufferCoexist,

  /**
   * @brief This array property view doesn't have either component count or
   * offset buffer view
   */
  InvalidArrayComponentCountOrOffsetBufferNotExist,

  /**
   * @brief This property view have an unknown offset type
   */
  InvalidOffsetType,

  /**
   * @brief This property view has offset values not sorted ascendingly
   */
  InvalidOffsetValuesNotSortedAscending,

  /**
   * @brief This property view has an offset point to an out of bound value
   */
  InvalidOffsetValuePointsToOutOfBoundBuffer
};

/**
 * @brief A view on the data of the FeatureTableProperty
 *
 * It provides utility to retrieve the actual data stored in the
 * {@link FeatureTableProperty::bufferView} like an array of elements.
 * Data of each instance can be accessed through the {@link get(int64_t instance)} method
 *
 * @param ElementType must be uin8_t, int8_t, uint16_t, int16_t,
 * uint32_t, int32_t, uint64_t, int64_t, float, double, bool, std::string_view,
 * and MetadataArrayView<T> with T must be one of the types mentioned above
 */
template <typename ElementType> class MetadataPropertyView {
public:
  /**
   * @brief Constructs a new instance viewing a non-existent property.
   */
  MetadataPropertyView()
      : _status{MetadataPropertyViewStatus::InvalidPropertyNotExist},
        _valueBuffer{},
        _arrayOffsetBuffer{},
        _stringOffsetBuffer{},
        _offsetType{},
        _offsetSize{},
        _componentCount{},
        _instanceCount{},
        _normalized{} {}

  /**
   * @brief Construct a new instance pointing to the data specified by
   * FeatureTableProperty
   * @param valueBuffer The raw buffer specified by {@link FeatureTableProperty::bufferView}
   * @param arrayOffsetBuffer The raw buffer specified by {@link FeatureTableProperty::arrayOffsetBufferView}
   * @param stringOffsetBuffer The raw buffer specified by {@link FeatureTableProperty::stringOffsetBufferView}
   * @param offsetType The offset type of the arrayOffsetBuffer and stringOffsetBuffer that is specified by {@link FeatureTableProperty::offsetType}
   * @param componentCount The number of elements for fixed array value which is specified by {@link FeatureTableProperty::componentCount}
   * @param instanceCount The number of instances specified by {@link FeatureTable::count}
   * @param normalized Whether this property has a normalized integer type.
   */
  MetadataPropertyView(
      MetadataPropertyViewStatus status,
      gsl::span<const std::byte> valueBuffer,
      gsl::span<const std::byte> arrayOffsetBuffer,
      gsl::span<const std::byte> stringOffsetBuffer,
      PropertyType offsetType,
      int64_t componentCount,
      int64_t instanceCount,
      bool normalized) noexcept
      : _status{status},
        _valueBuffer{valueBuffer},
        _arrayOffsetBuffer{arrayOffsetBuffer},
        _stringOffsetBuffer{stringOffsetBuffer},
        _offsetType{offsetType},
        _offsetSize{getOffsetSize(offsetType)},
        _componentCount{componentCount},
        _instanceCount{instanceCount},
        _normalized{normalized} {}

  /**
   * @brief Gets the status of this property view.
   *
   * Indicates whether the view accurately reflects the property's data, or
   * whether an error occurred.
   */
  MetadataPropertyViewStatus status() const noexcept { return _status; }

  /**
   * @brief Get the value of an instance of the FeatureTable.
   * @param instance The instance index
   * @return The value of the instance
   */
  ElementType get(int64_t instance) const noexcept {
    assert(
        _status == MetadataPropertyViewStatus::Valid &&
        "Check the status() first to make sure view is valid");
    assert(
        size() > 0 &&
        "Check the size() of the view to make sure it's not empty");
    assert(instance >= 0 && "instance index must be positive");

    if constexpr (IsMetadataNumeric<ElementType>::value) {
      return getNumeric(instance);
    }

    if constexpr (IsMetadataBoolean<ElementType>::value) {
      return getBoolean(instance);
    }

    if constexpr (IsMetadataString<ElementType>::value) {
      return getString(instance);
    }

    if constexpr (IsMetadataNumericArray<ElementType>::value) {
      return getNumericArray<typename MetadataArrayType<ElementType>::type>(
          instance);
    }

    if constexpr (IsMetadataBooleanArray<ElementType>::value) {
      return getBooleanArray(instance);
    }

    if constexpr (IsMetadataStringArray<ElementType>::value) {
      return getStringArray(instance);
    }
  }

  /**
   * @brief Get the number of instances in the FeatureTable
   * @return The number of instances in the FeatureTable
   */
  int64_t size() const noexcept { return _instanceCount; }

  /**
   * @brief Get the component count of this property. Only applicable when the
   * property is an array type.
   *
   * @return The component count of this property.
   */
  int64_t getComponentCount() const noexcept { return _componentCount; }

  /**
   * @brief Whether this property has a normalized integer type.
   *
   * @return Whether this property has a normalized integer type.
   */
  bool isNormalized() const noexcept { return _normalized; }

private:
  ElementType getNumeric(int64_t instance) const noexcept {
    return reinterpret_cast<const ElementType*>(_valueBuffer.data())[instance];
  }

  bool getBoolean(int64_t instance) const noexcept {
    const int64_t byteIndex = instance / 8;
    const int64_t bitIndex = instance % 8;
    const int bitValue =
        static_cast<int>(_valueBuffer[byteIndex] >> bitIndex) & 1;
    return bitValue == 1;
  }

  std::string_view getString(int64_t instance) const noexcept {
    const size_t currentOffset =
        getOffsetFromOffsetBuffer(instance, _stringOffsetBuffer, _offsetType);
    const size_t nextOffset = getOffsetFromOffsetBuffer(
        instance + 1,
        _stringOffsetBuffer,
        _offsetType);
    return std::string_view(
        reinterpret_cast<const char*>(_valueBuffer.data() + currentOffset),
        (nextOffset - currentOffset));
  }

  template <typename T>
  MetadataArrayView<T> getNumericArray(int64_t instance) const noexcept {
    if (_componentCount > 0) {
      const gsl::span<const std::byte> vals(
          _valueBuffer.data() + instance * _componentCount * sizeof(T),
          _componentCount * sizeof(T));
      return MetadataArrayView<T>{vals};
    }

    const size_t currentOffset =
        getOffsetFromOffsetBuffer(instance, _arrayOffsetBuffer, _offsetType);
    const size_t nextOffset = getOffsetFromOffsetBuffer(
        instance + 1,
        _arrayOffsetBuffer,
        _offsetType);
    const gsl::span<const std::byte> vals(
        _valueBuffer.data() + currentOffset,
        (nextOffset - currentOffset));
    return MetadataArrayView<T>{vals};
  }

  MetadataArrayView<std::string_view>
  getStringArray(int64_t instance) const noexcept {
    if (_componentCount > 0) {
      const gsl::span<const std::byte> offsetVals(
          _stringOffsetBuffer.data() + instance * _componentCount * _offsetSize,
          (_componentCount + 1) * _offsetSize);
      return MetadataArrayView<std::string_view>(
          _valueBuffer,
          offsetVals,
          _offsetType,
          _componentCount);
    }

    const size_t currentOffset =
        getOffsetFromOffsetBuffer(instance, _arrayOffsetBuffer, _offsetType);
    const size_t nextOffset = getOffsetFromOffsetBuffer(
        instance + 1,
        _arrayOffsetBuffer,
        _offsetType);
    const gsl::span<const std::byte> offsetVals(
        _stringOffsetBuffer.data() + currentOffset,
        (nextOffset - currentOffset + _offsetSize));
    return MetadataArrayView<std::string_view>(
        _valueBuffer,
        offsetVals,
        _offsetType,
        (nextOffset - currentOffset) / _offsetSize);
  }

  MetadataArrayView<bool> getBooleanArray(int64_t instance) const noexcept {
    if (_componentCount > 0) {
      const size_t offsetBits = _componentCount * instance;
      const size_t nextOffsetBits = _componentCount * (instance + 1);
      const gsl::span<const std::byte> buffer(
          _valueBuffer.data() + offsetBits / 8,
          (nextOffsetBits / 8 - offsetBits / 8 + 1));
      return MetadataArrayView<bool>(buffer, offsetBits % 8, _componentCount);
    }

    const size_t currentOffset =
        getOffsetFromOffsetBuffer(instance, _arrayOffsetBuffer, _offsetType);
    const size_t nextOffset = getOffsetFromOffsetBuffer(
        instance + 1,
        _arrayOffsetBuffer,
        _offsetType);

    const size_t totalBits = nextOffset - currentOffset;
    const gsl::span<const std::byte> buffer(
        _valueBuffer.data() + currentOffset / 8,
        (nextOffset / 8 - currentOffset / 8 + 1));
    return MetadataArrayView<bool>(buffer, currentOffset % 8, totalBits);
  }

  static int64_t getOffsetSize(PropertyType offsetType) noexcept {
    switch (offsetType) {
    case CesiumGltf::PropertyType::Uint8:
      return sizeof(uint8_t);
    case CesiumGltf::PropertyType::Uint16:
      return sizeof(uint16_t);
    case CesiumGltf::PropertyType::Uint32:
      return sizeof(uint32_t);
    case CesiumGltf::PropertyType::Uint64:
      return sizeof(uint64_t);
    default:
      return 0;
    }
  }

  static size_t getOffsetFromOffsetBuffer(
      size_t instance,
      const gsl::span<const std::byte>& offsetBuffer,
      PropertyType offsetType) noexcept {
    switch (offsetType) {
    case PropertyType::Uint8: {
      assert(instance < offsetBuffer.size() / sizeof(uint8_t));
      const uint8_t offset = *reinterpret_cast<const uint8_t*>(
          offsetBuffer.data() + instance * sizeof(uint8_t));
      return static_cast<size_t>(offset);
    }
    case PropertyType::Uint16: {
      assert(instance < offsetBuffer.size() / sizeof(uint16_t));
      const uint16_t offset = *reinterpret_cast<const uint16_t*>(
          offsetBuffer.data() + instance * sizeof(uint16_t));
      return static_cast<size_t>(offset);
    }
    case PropertyType::Uint32: {
      assert(instance < offsetBuffer.size() / sizeof(uint32_t));
      const uint32_t offset = *reinterpret_cast<const uint32_t*>(
          offsetBuffer.data() + instance * sizeof(uint32_t));
      return static_cast<size_t>(offset);
    }
    case PropertyType::Uint64: {
      assert(instance < offsetBuffer.size() / sizeof(uint64_t));
      const uint64_t offset = *reinterpret_cast<const uint64_t*>(
          offsetBuffer.data() + instance * sizeof(uint64_t));
      return static_cast<size_t>(offset);
    }
    default:
      assert(false && "Offset type has unknown type");
      return 0;
    }
  }

  MetadataPropertyViewStatus _status;
  gsl::span<const std::byte> _valueBuffer;
  gsl::span<const std::byte> _arrayOffsetBuffer;
  gsl::span<const std::byte> _stringOffsetBuffer;
  PropertyType _offsetType;
  int64_t _offsetSize;
  int64_t _componentCount;
  int64_t _instanceCount;
  bool _normalized;
};
} // namespace CesiumGltf


/*
 * 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 rendersysd3d11_8555fd57_19e9_4747_97b5_8d3bfb0fb50f_h
#define rendersysd3d11_8555fd57_19e9_4747_97b5_8d3bfb0fb50f_h

#include <gslib/type.h>
#include <ariel/rendersys.h>

__ariel_begin__

class rendersys_d3d11:
    public rendersys
{
public:
    rendersys_d3d11();
    virtual ~rendersys_d3d11();
    virtual bool setup(uint hwnd, const configs& cfg) override;
    virtual void destroy() override;
    virtual void setup_pipeline_state() override;
    virtual render_blob* compile_shader_from_file(const gchar* file, const gchar* entry, const gchar* sm, render_include* inc) override;
    virtual render_blob* compile_shader_from_memory(const char* src, int len, const gchar* name, const gchar* entry, const gchar* sm, render_include* inc) override;
    virtual vertex_shader* create_vertex_shader(const void* ptr, size_t len) override;
    virtual pixel_shader* create_pixel_shader(const void* ptr, size_t len) override;
    virtual compute_shader* create_compute_shader(const void* ptr, size_t len) override;
    virtual geometry_shader* create_geometry_shader(const void* ptr, size_t len) override;
    virtual hull_shader* create_hull_shader(const void* ptr, size_t len) override;
    virtual domain_shader* create_domain_shader(const void* ptr, size_t len) override;
    virtual vertex_format* create_vertex_format(const void* ptr, size_t len, vertex_format_desc vfdesc[], uint n) override;
    virtual vertex_buffer* create_vertex_buffer(uint stride, uint count, bool read, bool write, uint usage, const void* ptr) override;
    virtual index_buffer* create_index_buffer(uint count, bool read, bool write, uint usage, const void* ptr) override;
    virtual constant_buffer* create_constant_buffer(uint stride, bool read, bool write, const void* ptr) override;
    virtual shader_resource_view* create_shader_resource_view(render_resource* res) override;
    virtual depth_stencil_view* create_depth_stencil_view(render_resource* res) override;
    virtual unordered_access_view* create_unordered_access_view(render_resource* res) override;
    virtual sampler_state* create_sampler_state(sampler_state_filter filter) override;
    virtual texture2d* create_texture2d(const image& img, uint mips, uint usage, uint bindflags, uint cpuflags, uint miscflags) override;
    virtual texture2d* create_texture2d(int width, int height, uint format, uint mips, uint usage, uint bindflags, uint cpuflags, uint miscflags) override;
    virtual void load_with_mips(texture2d* tex, const image& img) override;
    virtual void update_buffer(void* buf, int size, const void* ptr) override;
    virtual void set_vertex_format(vertex_format* vfmt) override;
    virtual void set_vertex_buffer(vertex_buffer* vb, uint stride, uint offset) override;
    virtual void set_index_buffer(index_buffer* ib, uint offset) override;
    virtual void begin_render() override;
    virtual void end_render() override;
    virtual void set_render_option(render_option opt, uint val) override;
    virtual void set_vertex_shader(vertex_shader* vs) override;
    virtual void set_pixel_shader(pixel_shader* ps) override;
    virtual void set_geometry_shader(geometry_shader* gs) override;
    virtual void set_viewport(const viewport& vp) override;
    virtual void set_constant_buffer(uint slot, constant_buffer* cb, shader_type st) override;
    virtual void set_sampler_state(uint slot, sampler_state* sstate, shader_type st) override;
    virtual void set_shader_resource(uint slot, shader_resource_view* srv, shader_type st) override;
    virtual void draw(uint count, uint start) override;
    virtual void draw_indexed(uint count, uint start, int base) override;
    virtual void capture_screen(image& img, const rectf& rc, int buff_id) override;
    virtual void enable_alpha_blend(bool b) override;
    virtual void enable_depth(bool b) override;

protected:
    D3D_DRIVER_TYPE         _drvtype        = D3D_DRIVER_TYPE_NULL;
    D3D_FEATURE_LEVEL       _level          = D3D_FEATURE_LEVEL_11_0;
    render_device*          _device         = nullptr;
    render_context*         _context        = nullptr;
    render_swap_chain*      _swapchain      = nullptr;
    render_target_view*     _rtview         = nullptr;
    render_blend_state*     _blendstate     = nullptr;
    depth_stencil_view*     _dsview         = nullptr;
    render_raster_state*    _rasterstate    = nullptr;
    render_depth_state*     _depthstate     = nullptr;
    uint                    _msaa_x         = 0;
    bool                    _vsync          = false;
    bool                    _fullscreen     = false;
    bool                    _msaa           = false;

protected:
    void install_configs(const configs& cfg);

public:
    render_device* get_device() const { return _device; }
    render_context* get_immediate_context() const { return _context; }
};

template<class res_class>
inline render_resource* convert_to_resource(res_class* p)
{ return static_cast<render_resource*>(p); }

__ariel_end__

#endif


///////////////////////////////////////////////////////////////////////////////
//
// 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_STRING_SPAN_H
#define GSL_STRING_SPAN_H

#include <gsl/gsl_assert> // for Ensures, Expects
#include <gsl/gsl_util>   // for narrow_cast
#include <gsl/span>       // for operator!=, operator==, dynamic_extent
#include <gsl/pointers>   // for not_null

#include <algorithm> // for equal, lexicographical_compare
#include <array>     // for array
#include <cstddef>   // for ptrdiff_t, size_t, nullptr_t
#include <cstdint>   // for PTRDIFF_MAX
#include <cstring>
#include <string>      // for basic_string, allocator, char_traits
#include <type_traits> // for declval, is_convertible, enable_if_t, add_...

#ifdef _MSC_VER
#pragma warning(push)

// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
#pragma warning(disable : 26446) // TODO: bug in parser - attributes and templates
#pragma warning(disable : 26481) // TODO: suppress does not work inside templates sometimes

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

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

namespace gsl
{
//
// czstring and wzstring
//
// These are "tag" typedefs for C-style strings (i.e. null-terminated character arrays)
// that allow static analysis to help find bugs.
//
// There are no additional features/semantics that we can find a way to add inside the
// type system for these types that will not either incur significant runtime costs or
// (sometimes needlessly) break existing programs when introduced.
//

template <typename CharT, std::ptrdiff_t Extent = dynamic_extent>
using basic_zstring = CharT*;

template <std::ptrdiff_t Extent = dynamic_extent>
using czstring = basic_zstring<const char, Extent>;

template <std::ptrdiff_t Extent = dynamic_extent>
using cwzstring = basic_zstring<const wchar_t, Extent>;

template <std::ptrdiff_t Extent = dynamic_extent>
using cu16zstring = basic_zstring<const char16_t, Extent>;

template <std::ptrdiff_t Extent = dynamic_extent>
using cu32zstring = basic_zstring<const char32_t, Extent>;

template <std::ptrdiff_t Extent = dynamic_extent>
using zstring = basic_zstring<char, Extent>;

template <std::ptrdiff_t Extent = dynamic_extent>
using wzstring = basic_zstring<wchar_t, Extent>;

template <std::ptrdiff_t Extent = dynamic_extent>
using u16zstring = basic_zstring<char16_t, Extent>;

template <std::ptrdiff_t Extent = dynamic_extent>
using u32zstring = basic_zstring<char32_t, Extent>;

namespace details
{
    template <class CharT>
    std::ptrdiff_t string_length(const CharT* str, std::ptrdiff_t n)
    {
        if (str == nullptr || n <= 0) return 0;

        const span<const CharT> str_span{str, n};

        std::ptrdiff_t len = 0;
        while (len < n && str_span[len]) len++;

        return len;
    }
} // namespace details

//
// ensure_sentinel()
//
// Provides a way to obtain an span from a contiguous sequence
// that ends with a (non-inclusive) sentinel value.
//
// Will fail-fast if sentinel cannot be found before max elements are examined.
//
template <typename T, const T Sentinel>
span<T, dynamic_extent> ensure_sentinel(T* seq, std::ptrdiff_t max = PTRDIFF_MAX)
{
    Ensures(seq != nullptr);

    GSL_SUPPRESS(f.23) // NO-FORMAT: attribute // TODO: false positive // TODO: suppress does not work
    auto cur = seq;
    Ensures(cur != nullptr); // workaround for removing the warning

    GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute // TODO: suppress does not work
    while ((cur - seq) < max && *cur != Sentinel) ++cur;
    Ensures(*cur == Sentinel);
    return {seq, cur - seq};
}

//
// ensure_z - creates a span for a zero terminated strings.
// Will fail fast if a null-terminator cannot be found before
// the limit of size_type.
//
template <typename CharT>
span<CharT, dynamic_extent> ensure_z(CharT* const& sz, std::ptrdiff_t max = PTRDIFF_MAX)
{
    return ensure_sentinel<CharT, CharT(0)>(sz, max);
}

template <typename CharT, std::size_t N>
span<CharT, dynamic_extent> ensure_z(CharT (&sz)[N])
{
    return ensure_z(&sz[0], narrow_cast<std::ptrdiff_t>(N));
}

template <class Cont>
span<typename std::remove_pointer<typename Cont::pointer>::type, dynamic_extent>
ensure_z(Cont& cont)
{
    return ensure_z(cont.data(), narrow_cast<std::ptrdiff_t>(cont.size()));
}

template <typename CharT, std::ptrdiff_t>
class basic_string_span;

namespace details {
    template <typename T>
    struct is_basic_string_span_oracle : std::false_type
    {
    };

    template <typename CharT, std::ptrdiff_t Extent>
    struct is_basic_string_span_oracle<basic_string_span<CharT, Extent>> : std::true_type
    {
    };

    template <typename T>
    struct is_basic_string_span : is_basic_string_span_oracle<std::remove_cv_t<T>>
    {
    };
} // namespace details

//
// string_span and relatives
//
template <typename CharT, std::ptrdiff_t Extent = dynamic_extent>
class basic_string_span
{
public:
    using element_type = CharT;
    using pointer = std::add_pointer_t<element_type>;
    using reference = std::add_lvalue_reference_t<element_type>;
    using const_reference = std::add_lvalue_reference_t<std::add_const_t<element_type>>;
    using impl_type = span<element_type, Extent>;

    using index_type = typename impl_type::index_type;
    using iterator = typename impl_type::iterator;
    using const_iterator = typename impl_type::const_iterator;
    using reverse_iterator = typename impl_type::reverse_iterator;
    using const_reverse_iterator = typename impl_type::const_reverse_iterator;

    // default (empty)
    constexpr basic_string_span() noexcept = default;

    // copy
    constexpr basic_string_span(const basic_string_span& other) noexcept = default;

    // assign
    constexpr basic_string_span& operator=(const basic_string_span& other) noexcept = default;

    constexpr basic_string_span(pointer ptr, index_type length) : span_(ptr, length) {}
    constexpr basic_string_span(pointer firstElem, pointer lastElem) : span_(firstElem, lastElem) {}

    // From static arrays - if 0-terminated, remove 0 from the view
    // All other containers allow 0s within the length, so we do not remove them
    template <std::size_t N>
    constexpr basic_string_span(element_type (&arr)[N]) : span_(remove_z(arr))
    {}

    template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
    constexpr basic_string_span(std::array<ArrayElementType, N>& arr) noexcept : span_(arr)
    {}

    template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
    constexpr basic_string_span(const std::array<ArrayElementType, N>& arr) noexcept : span_(arr)
    {}

    // Container signature should work for basic_string after C++17 version exists
    template <class Traits, class Allocator>
    // GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute // TODO: parser bug
    constexpr basic_string_span(std::basic_string<element_type, Traits, Allocator>& str)
        : span_(&str[0], narrow_cast<std::ptrdiff_t>(str.length()))
    {}

    template <class Traits, class Allocator>
    constexpr basic_string_span(const std::basic_string<element_type, Traits, Allocator>& str)
        : span_(&str[0], str.length())
    {}

    // from containers. Containers must have a pointer type and data() function signatures
    template <class Container,
              class = std::enable_if_t<
                  !details::is_basic_string_span<Container>::value &&
                  std::is_convertible<typename Container::pointer, pointer>::value &&
                  std::is_convertible<typename Container::pointer,
                                      decltype(std::declval<Container>().data())>::value>>
    constexpr basic_string_span(Container& cont) : span_(cont)
    {}

    template <class Container,
              class = std::enable_if_t<
                  !details::is_basic_string_span<Container>::value &&
                  std::is_convertible<typename Container::pointer, pointer>::value &&
                  std::is_convertible<typename Container::pointer,
                                      decltype(std::declval<Container>().data())>::value>>
    constexpr basic_string_span(const Container& cont) : span_(cont)
    {}

    // from string_span
    template <
        class OtherValueType, std::ptrdiff_t OtherExtent,
        class = std::enable_if_t<std::is_convertible<
            typename basic_string_span<OtherValueType, OtherExtent>::impl_type, impl_type>::value>>
    constexpr basic_string_span(basic_string_span<OtherValueType, OtherExtent> other)
        : span_(other.data(), other.length())
    {}

    template <index_type Count>
    constexpr basic_string_span<element_type, Count> first() const
    {
        return {span_.template first<Count>()};
    }

    constexpr basic_string_span<element_type, dynamic_extent> first(index_type count) const
    {
        return {span_.first(count)};
    }

    template <index_type Count>
    constexpr basic_string_span<element_type, Count> last() const
    {
        return {span_.template last<Count>()};
    }

    constexpr basic_string_span<element_type, dynamic_extent> last(index_type count) const
    {
        return {span_.last(count)};
    }

    template <index_type Offset, index_type Count>
    constexpr basic_string_span<element_type, Count> subspan() const
    {
        return {span_.template subspan<Offset, Count>()};
    }

    constexpr basic_string_span<element_type, dynamic_extent>
    subspan(index_type offset, index_type count = dynamic_extent) const
    {
        return {span_.subspan(offset, count)};
    }

    constexpr reference operator[](index_type idx) const { return span_[idx]; }
    constexpr reference operator()(index_type idx) const { return span_[idx]; }

    constexpr pointer data() const { return span_.data(); }

    constexpr index_type length() const noexcept { return span_.size(); }
    constexpr index_type size() const noexcept { return span_.size(); }
    constexpr index_type size_bytes() const noexcept { return span_.size_bytes(); }
    constexpr index_type length_bytes() const noexcept { return span_.length_bytes(); }
    constexpr bool empty() const noexcept { return size() == 0; }

    constexpr iterator begin() const noexcept { return span_.begin(); }
    constexpr iterator end() const noexcept { return span_.end(); }

    constexpr const_iterator cbegin() const noexcept { return span_.cbegin(); }
    constexpr const_iterator cend() const noexcept { return span_.cend(); }

    constexpr reverse_iterator rbegin() const noexcept { return span_.rbegin(); }
    constexpr reverse_iterator rend() const noexcept { return span_.rend(); }

    constexpr const_reverse_iterator crbegin() const noexcept { return span_.crbegin(); }
    constexpr const_reverse_iterator crend() const noexcept { return span_.crend(); }

private:
    static impl_type remove_z(pointer const& sz, std::ptrdiff_t max)
    {
        return {sz, details::string_length(sz, max)};
    }

    template <std::size_t N>
    static impl_type remove_z(element_type (&sz)[N])
    {
        return remove_z(&sz[0], narrow_cast<std::ptrdiff_t>(N));
    }

    impl_type span_;
};

template <std::ptrdiff_t Extent = dynamic_extent>
using string_span = basic_string_span<char, Extent>;

template <std::ptrdiff_t Extent = dynamic_extent>
using cstring_span = basic_string_span<const char, Extent>;

template <std::ptrdiff_t Extent = dynamic_extent>
using wstring_span = basic_string_span<wchar_t, Extent>;

template <std::ptrdiff_t Extent = dynamic_extent>
using cwstring_span = basic_string_span<const wchar_t, Extent>;

template <std::ptrdiff_t Extent = dynamic_extent>
using u16string_span = basic_string_span<char16_t, Extent>;

template <std::ptrdiff_t Extent = dynamic_extent>
using cu16string_span = basic_string_span<const char16_t, Extent>;

template <std::ptrdiff_t Extent = dynamic_extent>
using u32string_span = basic_string_span<char32_t, Extent>;

template <std::ptrdiff_t Extent = dynamic_extent>
using cu32string_span = basic_string_span<const char32_t, Extent>;

//
// to_string() allow (explicit) conversions from string_span to string
//

template <typename CharT, std::ptrdiff_t Extent>
std::basic_string<typename std::remove_const<CharT>::type>
to_string(basic_string_span<CharT, Extent> view)
{
    return {view.data(), narrow_cast<std::size_t>(view.length())};
}

template <typename CharT, typename Traits = typename std::char_traits<CharT>,
          typename Allocator = std::allocator<CharT>, typename gCharT, std::ptrdiff_t Extent>
std::basic_string<CharT, Traits, Allocator> to_basic_string(basic_string_span<gCharT, Extent> view)
{
    return {view.data(), narrow_cast<std::size_t>(view.length())};
}

template <class ElementType, std::ptrdiff_t Extent>
basic_string_span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
as_bytes(basic_string_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>>
basic_string_span<byte, details::calculate_byte_size<ElementType, Extent>::value>
as_writeable_bytes(basic_string_span<ElementType, Extent> s) noexcept
{
    GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
    return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
}

// zero-terminated string span, used to convert
// zero-terminated spans to legacy strings
template <typename CharT, std::ptrdiff_t Extent = dynamic_extent>
class basic_zstring_span {
public:
    using value_type = CharT;
    using const_value_type = std::add_const_t<CharT>;

    using pointer = std::add_pointer_t<value_type>;
    using const_pointer = std::add_pointer_t<const_value_type>;

    using zstring_type = basic_zstring<value_type, Extent>;
    using const_zstring_type = basic_zstring<const_value_type, Extent>;

    using impl_type = span<value_type, Extent>;
    using string_span_type = basic_string_span<value_type, Extent>;

    constexpr basic_zstring_span(impl_type s) : span_(s)
    {
        // expects a zero-terminated span
        Expects(s[s.size() - 1] == '\0');
    }

    // copy
    constexpr basic_zstring_span(const basic_zstring_span& other) = default;

    // move
    constexpr basic_zstring_span(basic_zstring_span&& other) = default;

    // assign
    constexpr basic_zstring_span& operator=(const basic_zstring_span& other) = default;

    // move assign
    constexpr basic_zstring_span& operator=(basic_zstring_span&& other) = default;

    constexpr bool empty() const noexcept { return span_.size() == 0; }

    constexpr string_span_type as_string_span() const noexcept
    {
        const auto sz = span_.size();
        return {span_.data(), sz > 1 ? sz - 1 : 0};
    }
    constexpr string_span_type ensure_z() const { return gsl::ensure_z(span_); }

    constexpr const_zstring_type assume_z() const noexcept { return span_.data(); }

private:
    impl_type span_;
};

template <std::ptrdiff_t Max = dynamic_extent>
using zstring_span = basic_zstring_span<char, Max>;

template <std::ptrdiff_t Max = dynamic_extent>
using wzstring_span = basic_zstring_span<wchar_t, Max>;

template <std::ptrdiff_t Max = dynamic_extent>
using u16zstring_span = basic_zstring_span<char16_t, Max>;

template <std::ptrdiff_t Max = dynamic_extent>
using u32zstring_span = basic_zstring_span<char32_t, Max>;

template <std::ptrdiff_t Max = dynamic_extent>
using czstring_span = basic_zstring_span<const char, Max>;

template <std::ptrdiff_t Max = dynamic_extent>
using cwzstring_span = basic_zstring_span<const wchar_t, Max>;

template <std::ptrdiff_t Max = dynamic_extent>
using cu16zstring_span = basic_zstring_span<const char16_t, Max>;

template <std::ptrdiff_t Max = dynamic_extent>
using cu32zstring_span = basic_zstring_span<const char32_t, Max>;

// operator ==
template <class CharT, std::ptrdiff_t Extent, class T,
          class = std::enable_if_t<
              details::is_basic_string_span<T>::value ||
              std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>>>::value>>
bool operator==(const gsl::basic_string_span<CharT, Extent>& one, const T& other)
{
    const gsl::basic_string_span<std::add_const_t<CharT>> tmp(other);
    return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end());
}

template <class CharT, std::ptrdiff_t Extent, class T,
          class = std::enable_if_t<
              !details::is_basic_string_span<T>::value &&
              std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>>>::value>>
bool operator==(const T& one, const gsl::basic_string_span<CharT, Extent>& other)
{
    const gsl::basic_string_span<std::add_const_t<CharT>> tmp(one);
    return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end());
}

// operator !=
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
          typename = std::enable_if_t<std::is_convertible<
              T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
bool operator!=(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
    return !(one == other);
}

template <
    typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
    typename = std::enable_if_t<
        std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
        !gsl::details::is_basic_string_span<T>::value>>
bool operator!=(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
    return !(one == other);
}

// operator<
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
          typename = std::enable_if_t<std::is_convertible<
              T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
bool operator<(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
    const gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other);
    return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end());
}

template <
    typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
    typename = std::enable_if_t<
        std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
        !gsl::details::is_basic_string_span<T>::value>>
bool operator<(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
    gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one);
    return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end());
}

#ifndef _MSC_VER

// VS treats temp and const containers as convertible to basic_string_span,
// so the cases below are already covered by the previous operators

template <
    typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
    typename DataType = typename T::value_type,
    typename = std::enable_if_t<
        !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
        std::is_convertible<DataType*, CharT*>::value &&
        std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
                     DataType>::value>>
bool operator<(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
    gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other);
    return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end());
}

template <
    typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
    typename DataType = typename T::value_type,
    typename = std::enable_if_t<
        !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
        std::is_convertible<DataType*, CharT*>::value &&
        std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
                     DataType>::value>>
bool operator<(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
    gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one);
    return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end());
}
#endif

// operator <=
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
          typename = std::enable_if_t<std::is_convertible<
              T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
    return !(other < one);
}

template <
    typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
    typename = std::enable_if_t<
        std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
        !gsl::details::is_basic_string_span<T>::value>>
bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
    return !(other < one);
}

#ifndef _MSC_VER

// VS treats temp and const containers as convertible to basic_string_span,
// so the cases below are already covered by the previous operators

template <
    typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
    typename DataType = typename T::value_type,
    typename = std::enable_if_t<
        !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
        std::is_convertible<DataType*, CharT*>::value &&
        std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
                     DataType>::value>>
bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
    return !(other < one);
}

template <
    typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
    typename DataType = typename T::value_type,
    typename = std::enable_if_t<
        !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
        std::is_convertible<DataType*, CharT*>::value &&
        std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
                     DataType>::value>>
bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
    return !(other < one);
}
#endif

// operator>
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
          typename = std::enable_if_t<std::is_convertible<
              T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
    return other < one;
}

template <
    typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
    typename = std::enable_if_t<
        std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
        !gsl::details::is_basic_string_span<T>::value>>
bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
    return other < one;
}

#ifndef _MSC_VER

// VS treats temp and const containers as convertible to basic_string_span,
// so the cases below are already covered by the previous operators

template <
    typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
    typename DataType = typename T::value_type,
    typename = std::enable_if_t<
        !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
        std::is_convertible<DataType*, CharT*>::value &&
        std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
                     DataType>::value>>
bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
    return other < one;
}

template <
    typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
    typename DataType = typename T::value_type,
    typename = std::enable_if_t<
        !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
        std::is_convertible<DataType*, CharT*>::value &&
        std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
                     DataType>::value>>
bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
    return other < one;
}
#endif

// operator >=
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
          typename = std::enable_if_t<std::is_convertible<
              T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
    return !(one < other);
}

template <
    typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
    typename = std::enable_if_t<
        std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
        !gsl::details::is_basic_string_span<T>::value>>
bool operator>=(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
    return !(one < other);
}

#ifndef _MSC_VER

// VS treats temp and const containers as convertible to basic_string_span,
// so the cases below are already covered by the previous operators

template <
    typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
    typename DataType = typename T::value_type,
    typename = std::enable_if_t<
        !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
        std::is_convertible<DataType*, CharT*>::value &&
        std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
                     DataType>::value>>
bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other)
{
    return !(one < other);
}

template <
    typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
    typename DataType = typename T::value_type,
    typename = std::enable_if_t<
        !gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
        std::is_convertible<DataType*, CharT*>::value &&
        std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
                     DataType>::value>>
bool operator>=(const T& one, gsl::basic_string_span<CharT, Extent> other)
{
    return !(one < other);
}
#endif
} // namespace gsl

#ifdef _MSC_VER
#pragma warning(pop)

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

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

#endif // GSL_STRING_SPAN_H