/**
 * VGMTrans (c) - 2002-2021
 * Licensed under the zlib license
 * See the included LICENSE for more information
 */

#pragma once

#include <vector>
#include <fluidsynth.h>
#include <gsl-lite.hpp>
#include <QObject>
#include <QString>

class VGMColl;

class MusicPlayer : public QObject {
  Q_OBJECT
public:
  static auto &the() {
    static MusicPlayer instance;
    return instance;
  }

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

  ~MusicPlayer();

  /**
   * Toggles the status of the player
   * @returns true if the player is playing
   */
  bool toggle();
  /**
   * Stops the player (unloads resources)
   */
  void stop();
  /**
   * Moves the player position
   * @param position relative to song start
   */
  void seek(int position);

  /**
   * Returns the title of the song currently playing
   * @return the song title
   */
  [[nodiscard]] QString songTitle() const;

  /**
   * Loads a VGMColl for playback
   * @param collection
   * @return true if data was loaded correctly
   */
  bool playCollection(VGMColl *collection);

  /**
   * Checks whether the player is playing
   * @return true if playing
   */
  [[nodiscard]] bool playing() const;
  /**
   * The number of MIDI ticks elapsed since the player was started
   * @return number of ticks relative to song start
   */
  [[nodiscard]] int elapsedTicks() const;
  /**
   * The total number of MIDI ticks in the song
   * @return total ticks in the song
   */
  [[nodiscard]] int totalTicks() const;

  /**
   * Gets all the audio driver the player supports
   * @return the driver list
   */
  [[nodiscard]] std::vector<const char *> getAvailableDrivers() const;
  /**
   * Changes the current audio driver and restarts playing
   * @param driver_name
   * @return true if the driver changed
   */
  bool setAudioDriver(const char *driver_name);

  /**
   * Checks the value of a setting of the player corresponds to the passed value
   * @param setting
   * @param value
   * @return true if the value matches
   */
  [[nodiscard]] bool checkSetting(const char *setting, const char *value) const;
  /**
   * Sets a parameter of the player to the corrisponding passed value
   * @param setting
   * @param value
   */
  void updateSetting(const char *setting, const char *value);

signals:
  void statusChange(bool playing);
  void playbackPositionChanged(int current, int max);

private:
  MusicPlayer();

  fluid_settings_t *m_settings = nullptr;
  fluid_synth_t *m_synth = nullptr;
  fluid_audio_driver_t *m_active_driver = nullptr;
  fluid_player_t *m_active_player = nullptr;
  VGMColl *m_active_coll = nullptr;

  void makeSettings();
  void makeSynth();
  void makePlayer();
};


#pragma once

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

namespace Library
{
	class DepthStencilStates final
	{
	public:
		inline static winrt::com_ptr<ID3D11DepthStencilState> DefaultDepthCulling;
		inline static winrt::com_ptr<ID3D11DepthStencilState> NoDepthCulling;

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

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


#pragma once

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

namespace Library
{
	class RasterizerStates final
	{
	public:
		inline static winrt::com_ptr<ID3D11RasterizerState> BackCulling;
		inline static winrt::com_ptr<ID3D11RasterizerState> FrontCulling;
		inline static winrt::com_ptr<ID3D11RasterizerState> DisabledCulling;
		inline static winrt::com_ptr<ID3D11RasterizerState> Wireframe;

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

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


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

#include <gslib/config.h>
#include <gslib/std.h>

__gslib_begin__

class resvdir
{
public:
    resvdir(const gchar* path);
    resvdir(const gchar* dir, const gchar* file);
    const gchar* get_dir() const { return _dir.c_str(); }
    const gchar* get_file() const { return _file.c_str(); }
    const gchar* get_postfix() const;
    const gchar* get_path(string& path) const;

public:
    static bool is_valid_path(const gchar* path);
    static bool is_valid_dir(const gchar* dir);
    static const gchar* get_root(const gchar* path);
    static const gchar* get_next_node(const gchar* path);

protected:
    string      _dir;
    string      _file;
};

typedef unsigned char res;

class resnode
{
public:
    struct hash
    {
        size_t operator()(const resnode& that) const
        { return string_hash(that._key); }
    };
    struct equal_to
    {
        bool operator()(const resnode& r1, const resnode& r2) const
        { return string_hash(r1._key) == string_hash(r2._key); }
    };
    typedef unordered_set<resnode, hash, equal_to> resset;
    typedef resset::iterator iterator;
    typedef resset::const_iterator const_iterator;
    typedef void (*fndestroy)(res*, int);

public:
    resnode();
    resnode(const gchar* key);
    resnode(const resnode& that) { assign(const_cast<resnode&>(that)); }
    ~resnode() { destroy(); }
    void set_destroy(fndestroy del) { _del = del; }
    void set_resource(res* ptr, int len) { _res = ptr; _len = len; }
    res* get_resource() const { return _res; }
    const gchar* get_key() const { return _key.size() ? _key.c_str() : 0; }
    void destroy();
    void assign(resnode& that);
    bool operator<(const resnode& that) const { return _key < that._key; }
    iterator begin() { return _subs.begin(); }
    const_iterator begin() const { return _subs.end(); }
    iterator end() { return _subs.end(); }
    const_iterator end() const { return _subs.end(); }
    resnode* add(const gchar* key, res* ptr = 0, int len = 0);
    resnode* add(resnode* node);
    resnode* find(const gchar* key);
    const resnode* find(const gchar* key) const;

protected:
    string      _key;
    res*        _res;
    int         _len;
    fndestroy   _del;
    resset      _subs;
};

class respack
{
public:
    typedef resnode::resset resset;
    typedef resnode::iterator iterator;
    typedef resnode::const_iterator const_iterator;
    typedef resnode::fndestroy fndestroy;

public:
    respack(): _root(_t(":")) {}
    resnode* get_root() { return &_root; }
    const resnode* get_root() const { return &_root; }
    resnode* add(const gchar* path) { return add(resvdir(path)); }
    resnode* add(const resvdir& vdir) { return add(get_root(), resvdir::get_root(vdir.get_dir()), vdir.get_file()); }
    resnode* add(resnode* node, const gchar* dir, const gchar* file);
    resnode* find(const gchar* path) { return find(get_root(), resvdir::get_root(path)); }
    resnode* find(resnode* node, const gchar* path);
    const resnode* find(const gchar* path) const { return find(get_root(), resvdir::get_root(path)); }
    const resnode* find(const resnode* node, const gchar* path) const;
    resnode* reg(const gchar* path, res* ptr, int len, fndestroy del = 0)
    {
        if(resnode* node = add(path)) {
            node->set_resource(ptr, len);
            node->set_destroy(del);
            return node;
        }
        return 0;
    }

protected:
    resnode     _root;
};

extern respack* get_default_respack();

__gslib_end__

#endif


#ifndef __GSL_VERSION_H__
#define __GSL_VERSION_H__

#include <gsl/gsl_types.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

#define GSL_VERSION "2.2.1"
#define GSL_MAJOR_VERSION 2
#define GSL_MINOR_VERSION 2

GSL_VAR const char * gsl_version;

__END_DECLS

#endif /* __GSL_VERSION_H__ */


/*
  Copyright [2017-2021] [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 _API_KVSTORE_H_
#define _API_KVSTORE_H_

#include <api/components.h>
#include <api/registrar_memory_direct.h>
#include <common/byte.h>
#include <common/byte_span.h>
#include <common/errors.h> /* ERROR_BASE */
#include <common/string_view.h>
#include <common/time.h>
#include <gsl/span>
#include <sys/uio.h> /* iovec */

#include <cinttypes> /* PRIx64 */
#include <cstdlib>
#include <functional>
#include <map>
#include <list>
#include <mutex>
#include <vector>

namespace nupm
{
  struct region_descriptor;
}

/* print format for the pool type */
#define PRIxIKVSTORE_POOL_T PRIx64

namespace component
{

#define DECLARE_OPAQUE_TYPE(NAME) \
  struct Opaque_##NAME {          \
    virtual ~Opaque_##NAME() {}   \
  }

/**
 * Key-value interface for pluggable backend (e.g. mapstore, hstore, hstore-cc)
 */
class KVStore : public Registrar_memory_direct {

protected:
  ~KVStore() {}
 private:
  DECLARE_OPAQUE_TYPE(lock_handle);
  template <typename E, typename ... Args>
    static E error_value(
      E e, Args && ...
    ) { return e; }

 public:
  DECLARE_OPAQUE_TYPE(memory_region); /* Buffer_manager::buffer_t need this */
  DECLARE_OPAQUE_TYPE(key);
  DECLARE_OPAQUE_TYPE(pool_iterator);

 public:
  using pool_t          = uint64_t;
  // using memory_handle_t = Opaque_memory_region*;
  using key_t           = Opaque_key*;
  using pool_lock_t     = Opaque_lock_handle*;
  using pool_iterator_t = Opaque_pool_iterator*;
  using byte            = common::byte;

 template <typename C>
    using basic_string_view = common::basic_string_view<C>;
  using string_view = common::string_view;
  using string_view_byte = basic_string_view<byte>;
  using string_view_key = string_view_byte;
  using string_view_value = string_view_byte;

  static constexpr memory_handle_t HANDLE_NONE = nullptr; /* old name */
  static constexpr memory_handle_t MEMORY_HANDLE_NONE = nullptr; /* better name */
  static constexpr key_t           KEY_NONE    = nullptr;

  struct Addr {
    explicit Addr(addr_t addr_) : addr(addr_) {}
    Addr() = delete;
    addr_t addr;
  };

  enum {
    THREAD_MODEL_UNSAFE,
    THREAD_MODEL_SINGLE_PER_POOL,
    THREAD_MODEL_RWLOCK_PER_POOL,
    THREAD_MODEL_MULTI_PER_POOL,
  };

  using flags_t = std::uint32_t ;
  static constexpr flags_t FLAGS_NONE          = 0x0;
  static constexpr flags_t FLAGS_READ_ONLY     = 0x1; /* lock read-only */
  static constexpr flags_t FLAGS_SET_SIZE      = 0x2;
  static constexpr flags_t FLAGS_CREATE_ONLY   = 0x4;  /* only succeed if no existing k-v pair exist */
  static constexpr flags_t FLAGS_DONT_STOMP    = 0x8;  /* do not overwrite existing k-v pair */
  static constexpr flags_t FLAGS_NO_RESIZE     = 0x10; /* if size < existing size, do not resize */
  static constexpr flags_t FLAGS_MAX_VALUE     = 0x10;

  using unlock_flags_t = std::uint32_t;
  static constexpr unlock_flags_t UNLOCK_FLAGS_NONE = 0x0;
  static constexpr unlock_flags_t UNLOCK_FLAGS_FLUSH = 0x1; /* indicates for PM backends to flush */

  static constexpr pool_t POOL_ERROR = 0;

  enum class Capability {
    POOL_DELETE_CHECK, /*< checks if pool is open before allowing delete */
    RWLOCK_PER_POOL,   /*< pools are locked with RW-lock */
    POOL_THREAD_SAFE,  /*< pools can be shared across multiple client threads */
    WRITE_TIMESTAMPS,  /*< support for write timestamping */
  };

  enum class Op_type {
    WRITE, /* copy bytes into memory region */
    ZERO,  /* zero the memory region */
    INCREMENT_UINT64,
    CAS_UINT64,
  };

  enum Attribute : std::uint32_t {
    VALUE_LEN                = 1, /* length of a value associated with key */
    COUNT                    = 2, /* number of objects */
    CRC32                    = 3, /* get CRC32 of a value */
    AUTO_HASHTABLE_EXPANSION = 4, /* set to true if the hash table should expand */
    PERCENT_USED             = 5, /* get percent used pool capacity at current size */
    WRITE_EPOCH_TIME         = 6, /* epoch time at which the key-value pair was last
                                     written or locked with STORE_LOCK_WRITE */
    MEMORY_TYPE              = 7, /* type of memory */
    MEMORY_SIZE              = 8, /* size of pool or store in bytes */
    NUMA_MASK                = 9, /* mask of first 64 numa nodes eligible for mapstore allocation */
  };

  enum {
    MEMORY_TYPE_DRAM        = 0x1,
    MEMORY_TYPE_PMEM_DEVDAX = 0x2,
    MEMORY_TYPE_PMEM_FSDAX  = 0x3,
    MEMORY_TYPE_UNKNOWN     = 0xFF,
  };

  enum lock_type_t {
    STORE_LOCK_NONE  = 0,
    STORE_LOCK_READ  = 1,
    STORE_LOCK_WRITE = 2,
  };

  enum {
    /* see common/errors.h */
    S_MORE           = 2,
    E_KEY_EXISTS     = E_ERROR_BASE - 1,
    E_KEY_NOT_FOUND  = E_ERROR_BASE - 2,
    E_POOL_NOT_FOUND = E_ERROR_BASE - 3,
    E_BAD_ALIGNMENT  = E_ERROR_BASE - 4,
    E_TOO_LARGE      = E_ERROR_BASE - 5, /* -55 */
    E_ALREADY_OPEN   = E_ERROR_BASE - 6,
  };

  std::string strerro(int e)
  {
    static std::map<int, std::string> errs {
      { S_MORE, "MORE" }
      , { E_KEY_EXISTS, "E_KEY_EXISTS" }
      , { E_KEY_NOT_FOUND, "E_KEY_NOT_FOUND" }
      , { E_POOL_NOT_FOUND, "E_POOL_NOT_FOUND" }
      , { E_BAD_ALIGNMENT, "E_BAD_ALIGNMENT" }
      , { E_TOO_LARGE, "E_TOO_LARGE" }
      , { E_ALREADY_OPEN, "E_ALREADY_OPEN" }
    };
    auto it = errs.find(e);
    return it == errs.end() ? ( "non-IKVStore error " + std::to_string(e) ) : it->second;
  }

  class Operation {
    Op_type _type;
    size_t  _offset;

   protected:
    Operation(Op_type type, size_t offset) : _type(type), _offset(offset) {}

   public:
    Op_type type() const noexcept { return _type; }
    size_t  offset() const noexcept { return _offset; }
  };

  class Operation_sized : public Operation {
    size_t _len;

   protected:
    Operation_sized(Op_type type, size_t offset_, size_t len) : Operation(type, offset_), _len(len) {}

   public:
    size_t size() const noexcept { return _len; }
  };

  class Operation_write : public Operation_sized {
    const void* _data;

   public:
    Operation_write(size_t offset, size_t len, const void* data)
        : Operation_sized(Op_type::WRITE, offset, len), _data(data)
    {
    }
    const void* data() const noexcept { return _data; }
  };

  class Operation_zero : public Operation_sized {

   public:
    Operation_zero(size_t offset, size_t len)
        : Operation_sized(Op_type::ZERO, offset, len)
    {
    }
  };

  /**
   * Determine thread safety of the component
   * Check capability of component
   *
   * @param cap Capability type
   *
   * @return THREAD_MODEL_XXXX
   */
  virtual int thread_safety() const = 0;

  /**
   * Check capability of component
   *
   * @param cap Capability type
   *
   * @return THREAD_MODEL_XXXX
   */
  virtual int get_capability(Capability cap) const { return error_value(-1, cap); }

  /**
   * Create an object pool. If the pool exists and the FLAGS_CREATE_ONLY
   * is not provided, then the existing pool will be opened.  If
   * FLAGS_CREATE_ONLY is specified and the pool exists, POOL ERROR will be
   * returned.
   *
   * @param pool_name Unique pool name
   * @param size Size of pool in bytes (for keys,values and metadata)
   * @param flags Creation flags
   * @param expected_obj_count Expected maximum object count (optimization)
   * @param base Optional base address
   *
   * @return Pool handle or POOL_ERROR
   */
  virtual pool_t create_pool(const std::string& pool_name,
                             const size_t       size,
                             flags_t            flags              = 0,
                             uint64_t           expected_obj_count = 0,
                             const Addr         base_addr = Addr{0})
  {
    PERR("create_pool not implemented");
    return error_value(POOL_ERROR, pool_name, size, flags, expected_obj_count, base_addr);
  }

  virtual pool_t create_pool(const std::string& path,
                             const std::string& name,
                             const size_t       size,
                             flags_t            flags              = 0,
                             uint64_t           expected_obj_count = 0,
                             const Addr         base_addr_unused = Addr{0}) __attribute__((deprecated))
  {
    return create_pool(path + name, size, flags, expected_obj_count, base_addr_unused);
  }

  /**
   * Open an existing pool.
   *
   * @param name Name of object pool
   * @param flags Optional flags e.g., FLAGS_READ_ONLY
   * @param base Optional base address
   *
   * @return Pool handle or POOL_ERROR if pool cannot be opened, or flags
   * unsupported
   */
  virtual pool_t open_pool(const std::string& pool_name,
                           flags_t flags = 0,
                           const Addr base_addr_unused = Addr{0})
  {
    return error_value(POOL_ERROR, pool_name, flags, base_addr_unused);
  }

  virtual pool_t open_pool(const std::string& path,
                           const std::string& name,
                           flags_t flags = 0,
                           const Addr base_addr_unused = Addr{0}) __attribute__((deprecated))
  {
    return open_pool(path + name, flags, base_addr_unused);
  }

  /**
   * Close pool handle
   *
   * @param pool Pool handle
   *
   * @return S_OK on success, E_POOL_NOT_FOUND, E_ALREADY_OPEN if pool cannot be
   * closed due to open session.
   */
  virtual status_t close_pool(pool_t pool) = 0;

  /**
   * Delete an existing pool
   *
   * @param name Name of object pool
   *
   * @return S_OK on success, E_POOL_NOT_FOUND, E_ALREADY_OPEN if pool cannot be
   * deleted
   */
  virtual status_t delete_pool(const std::string& name) = 0;

  /**
   * Get a list of pool names
   *
   * @param inout_pool_names [inout] List of pool names
   *
   * @return S_OK or E_NOT_IMPL;
   */
  virtual status_t get_pool_names(std::list<std::string>& inout_pool_names) = 0;

  /**
   * Get mapped memory regions for pool.  This is used for pre-registration with
   * DMA engines.
   *
   * @param pool Pool handle
   * @param out_regions Backing file name (if any), Mapped memory regions
   *
   * @return S_OK on success or E_POOL_NOT_FOUND.  Components that do not
   * support this return E_NOT_SUPPORTED.
   */
  virtual status_t get_pool_regions(const pool_t pool, nupm::region_descriptor & out_regions)
  {
    return error_value(E_NOT_SUPPORTED, pool, out_regions); /* not supported in FileStore */
  }

  /**
   * Dynamically expand a pool.  Typically, this will add to the regions
   * belonging to a pool.
   *
   * @param pool Pool handle
   * @param increment_size Size in bytes to expand by
   * @param reconfigured_size [out] new size of pool
   *
   * @return S_OK on success or E_POOL_NOT_FOUND. Components that do not support
   * this return E_NOT_SUPPORTED (e.g. MCAS client)
   */
  virtual status_t grow_pool(const pool_t pool,
                             const size_t increment_size,
                             size_t& reconfigured_size)
  {
    PERR("grow_pool: not supported");
    return error_value(E_NOT_SUPPORTED, pool, increment_size, reconfigured_size);
  }

  /**
   * Write or overwrite an object value. If there already exists an
   * object with matching key, then it should be replaced
   * (i.e. reallocated) or overwritten.
   *
   * @param pool Pool handle
   * @param key Object key
   * @param value Value data
   * @param value_len Size of value in bytes
   *
   * @return S_OK or E_POOL_NOT_FOUND, E_KEY_EXISTS
   */
  virtual status_t put(const pool_t       pool,
                       const std::string& key,
                       const void*        value,
                       const size_t       value_len,
                       flags_t            flags = FLAGS_NONE)
  {
    return error_value(E_NOT_SUPPORTED, pool, key, value, value_len, flags);
  }

  /**
   * Zero-copy put operation.  If there does not exist an object
   * with matching key, then an error E_KEY_EXISTS should be returned.
   *
   * @param pool Pool handle
   * @param key Object key
   * @param value Value
   * @param value_len Value length in bytes
   * @param handle Memory registration handle
   * @param flags Optional flags
   *
   * @return S_OK or E_POOL_NOT_FOUND, E_KEY_EXISTS
   */
  virtual status_t put_direct(const pool_t   pool,
                              const std::string&    key,
                              gsl::span<const common::const_byte_span> values,
                              gsl::span<const memory_handle_t> handles = gsl::span<const memory_handle_t>(),
                              flags_t        flags  = FLAGS_NONE)
  {
    return error_value(E_NOT_SUPPORTED, pool, key, values, handles, flags);
  }

 /**
   * Zero-copy put operation (see exceptions above).
   *
   * @param pool Pool handle
   * @param key Object key
   * @param value Value
   * @param value_len Value length in bytes
   * @param handle Memory registration handle
   * @param flags Optional flags
   *
   * @return S_OK or error code
   */
  virtual status_t put_direct(const pool_t   pool,
                              const std::string&    key,
                              const void*           value,
                              const size_t          value_len,
                              const memory_handle_t handle = MEMORY_HANDLE_NONE,
                              flags_t        flags  = FLAGS_NONE)
  {
    return put_direct(
      pool
      , key
      , std::array<const common::const_byte_span,1>{common::make_const_byte_span(value, value_len)}
      , std::array<memory_handle_t,1>{handle}
      , flags
    );
  }

  /**
   * Resize memory for a value
   *
   * @param pool Pool handle
   * @param key Object key (should be unlocked)
   * @param new_size New size of value in bytes (can be more or less)
   *
   * @return S_OK on success, E_BAD_ALIGNMENT, E_POOL_NOT_FOUND,
   * E_KEY_NOT_FOUND, E_TOO_LARGE, E_ALREADY(?)
   */
  virtual status_t resize_value(const pool_t       pool,
                                const std::string& key,
                                const size_t       new_size,
                                const size_t       alignment)
  {
    return error_value(E_NOT_SUPPORTED, pool, key, new_size, alignment);
  }

  /**
   * Read an object value
   *
   * @param pool Pool handle
   * @param key Object key
   * @param out_value Value data (if null, component will allocate memory)
   * @param out_value_len Size of value in bytes
   *
   * @return S_OK or E_POOL_NOT_FOUND, E_KEY_NOT_FOUND if key not found
   */
  virtual status_t get(const pool_t       pool,
                       const std::string& key,
                       void*&             out_value, /* release with free_memory() API */
                       size_t&            out_value_len) = 0;

  /**
   * Read an object value directly into client-provided memory.
   *
   * @param pool Pool handle
   * @param key Object key
   * @param out_value Client provided buffer for value
   * @param out_value_len [in] size of value memory in bytes [out] size of value
   * @param handle Memory registration handle
   *
   * @return S_OK, S_MORE if only a portion of value is read,
   * E_BAD_ALIGNMENT on invalid alignment, E_POOL_NOT_FOUND, E_KEY_NOT_FOUND, or other
   * error code
   *
   * Note: S_MORE is reduncant, it could have been inferred from S_OK and
   * out_value_len [in] < out_value_len [out].
   */
  virtual status_t get_direct(pool_t             pool,
                              const std::string& key,
                              void*              out_value,
                              size_t&            out_value_len,
                              memory_handle_t    handle = HANDLE_NONE)
  {
    return error_value(E_NOT_SUPPORTED, pool, key, out_value, out_value_len, handle);
  }

  /**
   * Get attribute for key or pool (see enum Attribute)
   *
   * @param pool Pool handle
   * @param attr Attribute to retrieve
   * @param out_value Vector of attribute values
   * @param key [optional] Key
   *
   * @return S_OK on success, E_POOL_NOT_FOUND, E_INVALID_ARG, E_KEY_NOT_FOUND
   */
  virtual status_t get_attribute(pool_t                 pool,
                                 Attribute              attr,
                                 std::vector<uint64_t>& out_value,
                                 const std::string*     key = nullptr) = 0;

  /**
   * Atomically (crash-consistent for pmem) swap keys (K,V)(K',V') -->
   * (K,V')(K',V).  Before calling this API, both KV-pairs must be
   * unlocked.
   *
   * @param pool Pool handle
   * @param key0 First key
   * @param key1 Second key
   *
   * @return S_OK on success, E_POOL_NOT_FOUND, E_KEY_NOT_FOUND, E_LOCKED
   * (unable to take both locks)
   */
  virtual status_t swap_keys(const pool_t pool,
                             const std::string key0,
                             const std::string key1)
  {
    return error_value(E_NOT_SUPPORTED, pool, key0, key1);
  }

  /**
   * Set attribute on a pool.
   *
   * @param pool Pool handle
   * @param attr Attribute to set
   * @param value Vector of values to set (for boolean 0=false, 1=true)
   * @param key [optional] key
   *
   * @return S_OK, E_INVALID_ARG (e.g. key==nullptr), E_POOL_NOT_FOUND
   */
  virtual status_t set_attribute(const pool_t                 pool,
                                 const Attribute              attr,
                                 const std::vector<uint64_t>& value,
                                 const std::string*           key = nullptr)
  {
    return error_value(E_NOT_SUPPORTED, pool, attr, value, key);
  }

  /**
   * Allocate memory for zero copy DMA
   *
   * @param vaddr [out] allocated memory buffer
   * @param len [in] length of memory buffer in bytes
   * @param handle memory handle
   *
   */
  virtual status_t allocate_direct_memory(void*& vaddr,
                                          size_t len,
                                          memory_handle_t& handle)
  {
    return error_value(E_NOT_SUPPORTED, vaddr, len, handle);
  }

  /**
   * Free memory for zero copy DMA
   *
   * @param handle handle to memory region to free
   *
   * @return S_OK on success
   */
  virtual status_t free_direct_memory(memory_handle_t handle)
  {
    return error_value(E_NOT_SUPPORTED, handle);
  }

  /**
   * Register memory for zero copy DMA
   *
   * @param vaddr Appropriately aligned memory buffer
   *
   * @return Memory handle or NULL on not supported.
   */

  memory_handle_t register_direct_memory(common::const_byte_span bytes) override
  {
    return error_value(nullptr, bytes);
  }

  using Registrar_memory_direct::register_direct_memory;

  /**
   * Direct memory regions should be unregistered before the memory is released
   * on the client side.
   *
   * @param handle (as returned by register_direct_memory) of region to deregister.
   *
   * @return S_OK on success
   */
  status_t unregister_direct_memory(memory_handle_t handle) override
  {
    return error_value(E_NOT_SUPPORTED, handle);
  }

  /**
   * Take a lock on an object. If the object does not exist and inout_value_len
   * is non-zero, create it with value space according to out_value_len (this
   * is very important for mcas context). If the object does not exist and
   * inout_value_len is zero, return E_KEY_NOT_FOUND.
   *
   * @param pool Pool handle
   * @param key Key
   * @param type STORE_LOCK_READ | STORE_LOCK_WRITE
   * @param out_value [out] Pointer to data
   * @param inout_value_len [in-out] Size of data in bytes
   * @param alignment [in] Alignment of new value space in bytes.
   * @param out_key [out]  Handle to key for unlock
   * @param out_key_ptr [out]  Optional request for key-string pointer (set to
   * nullptr if not required)
   *
   * @return S_OK, S_CREATED_OK (if created on demand), E_KEY_NOT_FOUND,
   * E_LOCKED (already locked), E_INVAL (e.g., no key & no length),
   * E_TOO_LARGE (cannot allocate space for lock), E_NOT_SUPPORTED
   * if unable to take lock or other error
   */
  virtual status_t lock(const pool_t       pool,
                        const std::string& key,
                        const lock_type_t  type,
                        void*&             out_value,
                        size_t&            inout_value_len,
                        size_t             alignment,
                        key_t&             out_key_handle,
                        const char**       out_key_ptr = nullptr)
  {
    return error_value(E_NOT_SUPPORTED, pool, key, type, out_value, inout_value_len, alignment,
                       out_key_handle, out_key_ptr);
  }

  /**
   * Unlock a key-value pair
   *
   * @param pool Pool handle
   * @param key_handle Handle (opaque) for key used to unlock
   * @param flags Optional unlock flags, UNLOCK_FLAGS_FLUSH
   *
   * @return S_OK, S_MORE (for async), E_INVAL or other error
   */
  virtual status_t unlock(const pool_t pool,
                          const key_t key_handle,
                          const unlock_flags_t flags = UNLOCK_FLAGS_NONE)
  {
    return error_value(E_NOT_SUPPORTED, pool, key_handle, flags);
  }

  /**
   * Update an existing value by applying a series of operations.
   * Together the set of operations make up an atomic transaction.
   * If the operation requires a result the operation type may provide
   * a method to accept the result. No operation currently requires
   * a result, but compare and swap probably would.
   *
   * @param pool Pool handle
   * @param key Object key
   * @param op_vector Operation vector
   * @param take_lock Set to true for automatic locking of object
   *
   * @return S_OK or error code
   */
  virtual status_t atomic_update(const pool_t                   pool,
                                 const std::string&             key,
                                 const std::vector<Operation*>& op_vector,
                                 bool                           take_lock = true)
  {
    return error_value(E_NOT_SUPPORTED, pool, key, op_vector, take_lock);
  }

  /**
   * Erase an object
   *
   * @param pool Pool handle
   * @param key Object key
   *
   * @return S_OK or error code (e.g. E_LOCKED)
   */
  virtual status_t erase(pool_t pool, const std::string& key) = 0;

  /**
   * Return number of objects in the pool
   *
   * @param pool Pool handle
   *
   * @return Number of objects
   */
  virtual size_t count(pool_t pool) = 0;

  /**
   * Apply functor to all objects in the pool
   *
   * @param pool Pool handle
   * @param function Functor to apply
   *
   * @return S_OK, E_POOL_NOT_FOUND
   */
  virtual status_t map(const pool_t pool,
                       std::function<int(const void* key,
                                         const size_t key_len,
                                         const void* value,
                                         const size_t value_len)> function)
  {
    return error_value(E_NOT_SUPPORTED, pool, function);
  }

  /**
   * Apply functor to all objects in the pool according
   * to given time constraints
   *
   * @param pool Pool handle
   * @param function Functor to apply (not in time order). If
   *                 functor returns < 0, then map aborts
   * @param t_begin Time must be after or equal. If set to zero, no constraint.
   * @param t_end Time must be before or equal. If set to zero, no constraint.
   *
   * @return S_OK, E_POOL_NOT_FOUND
   */
  virtual status_t map(const pool_t pool,
                       std::function<int(const void*              key,
                                         const size_t             key_len,
                                         const void*              value,
                                         const size_t             value_len,
                                         const common::tsc_time_t timestamp)> function,
                       const common::epoch_time_t t_begin,
                       const common::epoch_time_t t_end)
  {
    return error_value(E_NOT_SUPPORTED, pool, function, t_begin, t_end);
  }

  /**
   * Apply functor to all keys only. Useful for file_store (now deprecated)
   *
   * @param pool Pool handle
   * @param function Functor
   *
   * @return S_OK, E_POOL_NOT_FOUND
   */
  virtual status_t map_keys(const pool_t pool, std::function<int(const std::string& key)> function)
  {
    return error_value(E_NOT_SUPPORTED, pool, function);
  }

  /*
     auto iter = open_pool_iterator(pool);

     while(deref_pool_iterator(iter, ref, true) == S_OK)
       process_record(ref);

     close_pool_iterator(iter);
  */

  struct pool_reference_t {
  public:
    pool_reference_t()
      : key(nullptr), key_len(0), value(nullptr), value_len(0), timestamp() {}

    const void*          key;
    size_t               key_len;
    const void*          value;
    size_t               value_len;
    common::epoch_time_t timestamp; /* zero if not supported */

    inline std::string get_key() const {
      std::string k(static_cast<const char*>(key), key_len);
      return k;
    }

  };

  /**
   * Open pool iterator to iterate over objects in pool.
   *
   * @param pool Pool handle
   *
   * @return Pool iterator or nullptr
   */
  virtual pool_iterator_t open_pool_iterator(const pool_t pool)
  {
    return error_value(nullptr, pool);
  }

  /**
   * Deference pool iterator position and optionally increment
   *
   * @param pool Pool handle
   * @param iter Pool iterator
   * @param t_begin Time must be after or equal. If set to zero, no constraint.
   * @param t_end Time must be before or equal. If set to zero, no constraint.
   * @param ref [out] Output reference record
   * @param ref [out] Set to true if within time bounds
   * @param increment Move iterator forward one position
   *
   * @return S_OK on success and valid reference, E_INVAL (bad iterator),
   *   E_OUT_OF_BOUNDS (when attempting to dereference out of bounds)
   *   E_ITERATOR_DISTURBED (when writes have been made since last iteration)
   */
  virtual status_t deref_pool_iterator(const pool_t       pool,
                                       pool_iterator_t    iter,
                                       const common::epoch_time_t t_begin,
                                       const common::epoch_time_t t_end,
                                       pool_reference_t&  ref,
                                       bool&              time_match,
                                       bool               increment = true)
  {
    /* Not sure of the difference between "not supported" and "not implemented",
     * but they are separated codes.
     */
    return error_value(E_NOT_IMPL, pool, iter, t_begin, t_end, ref, time_match, increment);
  }

  /**
   * Unlock pool, release iterator and associated resources
   *
   * @param pool Pool handle
   * @param iter Pool iterator
   *
   * @return S_OK on success, E_INVAL (bad iterator)
   */
  virtual status_t close_pool_iterator(const pool_t pool,
                                       pool_iterator_t iter)
  {
    return error_value(E_NOT_IMPL, pool, iter);
  }

  /**
   * Free server-side allocated memory
   *
   * @param p Pointer to memory allocated through a get call
   *
   * @return S_OK on success
   */
  virtual status_t free_memory(void* p)
  {
    ::free(p);
    return S_OK;
  }

  /**
   * Allocate memory from pool
   *
   * @param pool Pool handle
   * @param size Size in bytes
   * @param alignment Alignment hint in bytes, 0 if no alignment is needed
   * @param out_addr Pointer to allocated region
   *
   * @return S_OK on success, E_BAD_ALIGNMENT, E_POOL_NOT_FOUND, E_NOT_SUPPORTED
   */
  virtual status_t allocate_pool_memory(const pool_t pool,
                                        const size_t size,
                                        const size_t alignment_hint,
                                        void*&       out_addr)
  {
    return error_value(E_NOT_SUPPORTED, pool, size, alignment_hint, out_addr);
  }

  /**
   * Free memory from pool
   *
   * @param pool Pool handle
   * @param addr Address of memory to free
   * @param size Size in bytes of allocation; if provided this accelerates
   * release
   *
   * @return S_OK on success, E_INVAL, E_POOL_NOT_FOUND, E_NOT_SUPPORTED
   */
  virtual status_t free_pool_memory(pool_t pool, const void* addr, size_t size = 0)
  {
    return error_value(E_NOT_SUPPORTED, pool, addr, size);
  }

  /**
   * Flush memory from pool
   *
   * @param pool Pool handle
   * @param addr Address of memory to flush
   * @param size Size in bytes to flush
   *
   * @return S_OK on success, E_INVAL, E_POOL_NOT_FOUND, E_NOT_SUPPORTED
   */
  virtual status_t flush_pool_memory(pool_t pool, const void* addr, size_t size)
  {
    return error_value(E_NOT_SUPPORTED, pool, addr, size);
  }

  /**
   * Perform control invocation on component
   *
   * @param command String representation of command (component-interpreted)
   *
   * @return S_OK on success or error otherwise
   */
  virtual status_t ioctl(const std::string& command) { return error_value(E_NOT_SUPPORTED, command); }

  /**
   * Debug routine
   *
   * @param pool Pool handle
   * @param cmd Debug command
   * @param arg Parameter for debug operation
   */
  virtual void debug(pool_t pool, unsigned cmd, uint64_t arg) = 0;
};

}  // namespace component
#endif


#ifndef parser_496ce533_26fe_412b_8db6_e61b852be838_h
#define parser_496ce533_26fe_412b_8db6_e61b852be838_h

#include <rathen\config.h>
#include <rathen\basis.h>
#include <gslib\tree.h>

__rathen_begin__

class __gs_novtable ps_obj:
    public object
{
public:
    enum
    {
        pt_root,
        pt_block,
        pt_value,
        pt_expression,
        pt_operator,
        pt_function,
        pt_calling,
        pt_if_statement,
        pt_loop_statement,
        pt_go_statement,
        pt_stop_statement,
        pt_exit_statement,
        pt_variable,
        pt_constant,
    };

    enum
    {
        vt_string,
        vt_integer,
        vt_float,
    };

public:
    ps_obj() { _parent = 0; }
    ps_obj(ps_obj* parent) { _parent = parent; }
    ps_obj* get_parent() const { return _parent; }

public:
    virtual ~ps_obj() {}
    virtual bool is_anonymous() const = 0;

protected:
    ps_obj*         _parent;
};

struct ps_trait_pass {};
struct ps_trait_hold {};

template<uint tag, bool anony, class ph_trait, class bsc = ps_obj>
class ps_proto:
    public bsc
{
public:
    ps_proto();
    ps_proto(ps_obj* parent);
    bool is_holder() const override;
    uint get_tag() const override;
    bool is_anonymous() const override;
};

template<uint tag, bool anony, class bsc>
class ps_proto<tag, anony, ps_trait_pass, bsc>:
    public bsc
{
public:
    ps_proto() {}
    ps_proto(ps_obj* parent): bsc(parent) {}
    bool is_holder() const override { return false; }
    uint get_tag() const override { return tag; }
    bool is_anonymous() const override { return anony; }
};

template<uint tag, bool anony, class bsc>
class ps_proto<tag, anony, ps_trait_hold, bsc>:
    public bsc
{
public:
    ps_proto() {}
    ps_proto(ps_obj* parent): bsc(parent) {}
    bool is_holder() const override { return true; }
    uint get_tag() const override { return tag; }
    bool is_anonymous() const override { return anony; }

public:
    virtual void add_indexing(object* obj) { _indexing.add_value(obj); }
    virtual indexing& get_indexing() { return _indexing; }

protected:
    indexing        _indexing;

public:
    object* find_object(const gchar* name) { return _indexing.find_value(name); }
    const object* find_object(const gchar* name) const { return _indexing.find_value(name); }
};

template<class mc, class pc>
class ps_join:
    public mc,
    public pc
{
public:
    ps_join() {}
    ps_join(ps_obj* parent): mc(parent) {}
};

class ps_comp_value
{
public:
    ps_comp_value() { _type = 0, _global = false, _ref = false; }
    void set_type(type* ty) { _type = ty; }
    void set_global(bool g) { _global = g; }
    void set_ref(bool r) { _ref = r; }
    type* get_type() const { return _type; }
    bool is_complex() const { return _type->is_complex(); }
    bool is_global() const { return _global; }
    bool is_ref() const { return _ref; }

protected:
    type*           _type;
    bool            _global;
    bool            _ref;
};

class ps_comp_operator
{
public:
    ps_comp_operator() { _opr = 0; }
    void set_opr(const oprnode* opr) { _opr = opr; }
    void set_opr(const oprinfo& opr) { _opr = opr_manager::get_singleton_ptr()->get_operator(opr); }
    const oprnode* get_opr_info() const { return _opr; }
    bool is_unary() const { return _opr->unary; }
    int get_priority() const { return _opr->prior; }
    const gchar* get_opr_name() const { return _opr->opr; }

protected:
    const oprnode*  _opr;
};

class ps_comp_variable
{
public:
    ps_comp_variable() { _value = 0; }
    void set_value(ps_obj* value) { _value = value; }
    ps_obj* get_value() const { return _value; }

protected:
    ps_obj*         _value;
};

class ps_comp_constant
{
public:
    union vdif
    {
        int         i;
        real32      r;
        int64       i64;
        real        r64;
    };

public:
    ps_comp_constant() {}
    void set_string(const gchar* str) { _cvtag = ps_obj::vt_string, _vstr = str; }
    void set_integer(int i) { _cvtag = ps_obj::vt_integer, _value.i = i; }
    void set_float(real32 r) { _cvtag = ps_obj::vt_float, _value.r = r; }
    uint get_value_tag() const { return _cvtag; }
    const string& get_string() const { return _vstr; }
    int get_integer() const { return _value.i; }
    real32 get_float() const { return _value.r; }

protected:
    uint            _cvtag;
    string          _vstr;
    vdif            _value;
};

class ps_comp_function
{
public:
    ps_comp_function() { _rety = 0, _parent = 0, _retr = false; }
    void set_retv_type(type* ty) { _rety = ty; }
    void set_retv_ref(bool tr) { _retr = tr; }
    type* get_retv_type() const { return _rety; }
    bool get_retv_ref() const { return _retr; }
    void set_parent(ps_obj* obj) { _parent = obj; }
    ps_obj* get_parent() const { return _parent; }
    bool is_top_level() const { return _parent->get_tag() == ps_obj::pt_root; }

protected:
    type*           _rety;
    bool            _retr;
    ps_obj*         _parent;
};

class ps_comp_statement
{
public:
    ps_comp_statement() { _condition = 0, _block = 0; }
    void set_condition(ps_obj* condition) { _condition = condition; }
    void set_block(ps_obj* block) { _block = block; }
    ps_obj* get_condition() const { return _condition; }
    ps_obj* get_block() const { return _block; }

protected:
    ps_obj*         _condition;
    ps_obj*         _block;
};

class ps_comp_if_statement:
    public ps_comp_statement
{
public:
    ps_comp_if_statement() { _prevbr = _nextbr = _lastbr = 0; }
    void set_prev_branch(ps_obj* branch) { _prevbr = branch; }
    void set_next_branch(ps_obj* branch) { _nextbr = branch; }
    void set_last_branch(ps_obj* branch) { _lastbr = branch; }
    ps_obj* get_prev_branch() const { return _prevbr; }
    ps_obj* get_next_branch() const { return _nextbr; }
    ps_obj* get_last_branch() const { return _lastbr; }

protected:
    ps_obj*         _prevbr;
    ps_obj*         _nextbr;
    ps_obj*         _lastbr;
};

class ps_comp_loop_statement:
    public ps_comp_statement
{
};

class ps_comp_exit_statement
{
public:
    ps_comp_exit_statement() { _conclusion = 0; }
    void set_conclusion(ps_obj* conclusion) { _conclusion = conclusion; }
    ps_obj* get_conclusion() const { return _conclusion; }

protected:
    ps_obj*         _conclusion;
};

typedef ps_proto<ps_obj::pt_root, true, ps_trait_hold> ps_root;
typedef ps_proto<ps_obj::pt_block, true, ps_trait_hold> ps_block;
typedef ps_proto<ps_obj::pt_value, false, ps_trait_pass, ps_join<ps_obj, ps_comp_value> > ps_value;
typedef ps_proto<ps_obj::pt_expression, true, ps_trait_pass> ps_expression;
typedef ps_proto<ps_obj::pt_operator, true, ps_trait_pass, ps_join<ps_obj, ps_comp_operator> > ps_operator;
typedef ps_proto<ps_obj::pt_function, false, ps_trait_hold, ps_join<ps_obj, ps_comp_function> > ps_function;
typedef ps_proto<ps_obj::pt_calling, true, ps_trait_pass> ps_calling;
typedef ps_proto<ps_obj::pt_go_statement, true, ps_trait_pass> ps_go_statement;
typedef ps_proto<ps_obj::pt_stop_statement, true, ps_trait_pass> ps_stop_statement;
typedef ps_proto<ps_obj::pt_if_statement, true, ps_trait_pass, ps_join<ps_obj, ps_comp_if_statement> > ps_if_statement;
typedef ps_proto<ps_obj::pt_loop_statement, true, ps_trait_pass, ps_join<ps_obj, ps_comp_loop_statement> > ps_loop_statement;
typedef ps_proto<ps_obj::pt_exit_statement, true, ps_trait_pass, ps_join<ps_obj, ps_comp_exit_statement> > ps_exit_statement;
typedef ps_proto<ps_obj::pt_variable, false, ps_trait_pass, ps_join<ps_obj, ps_comp_variable> > ps_variable;
typedef ps_proto<ps_obj::pt_constant, false, ps_trait_pass, ps_join<ps_obj, ps_comp_constant> > ps_constant;

class parser:
    private tree<ps_obj, _treenode_wrapper<ps_obj> >
{
public:
    typedef _treenode_wrapper<ps_obj> wrapper;
    typedef ps_obj value;
    typedef tree<ps_obj, wrapper> superref;
    typedef superref::iterator iterator;
    typedef superref::const_iterator const_iterator;

public:
    parser() { insert<ps_root>(iterator()); }
    const gchar* get_name() const;
    void set_root(const gchar* name);
    template<class _cst>
    iterator insert(iterator i) { return superref::insert_tail<_cst>(i); }
    template<class _cst>
    iterator birth(iterator i) { return superref::birth_tail<_cst>(i); }

public:
    using superref::clear;
    using superref::erase;
    using superref::get_root;
    using superref::for_each;
    using superref::detach;
    using superref::attach;
    using superref::debug_check;

public:
    iterator find(iterator i, const gchar* name);
};

__rathen_end__

#endif


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

#ifndef SQ_INCLUDE_GUARD_system_linux_SqPrimitiveTypeSchemaImpl_h_
#define SQ_INCLUDE_GUARD_system_linux_SqPrimitiveTypeSchemaImpl_h_

#include "core/typeutil.h"
#include "system/SqPrimitiveTypeSchema.gen.h"
#include "system/schema.h"

#include <gsl/gsl>

namespace sq::system::linux {

class SqPrimitiveTypeSchemaImpl
    : public SqPrimitiveTypeSchema<SqPrimitiveTypeSchemaImpl> {
public:
  explicit SqPrimitiveTypeSchemaImpl(
      const PrimitiveTypeSchema &primitive_type_schema);

  SQ_ND Result get_name() const;
  SQ_ND Result get_doc() const;

  SQ_ND Primitive to_primitive() const override;

private:
  gsl::not_null<const PrimitiveTypeSchema *> primitive_type_schema_;
};

} // namespace sq::system::linux

#endif // SQ_INCLUDE_GUARD_system_linux_SqPrimitiveTypeSchemaImpl_h_


//          Copyright Jean Pierre Cimalando 2019.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE.md or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#pragma once
#include <gsl/gsl>
#include <string>

std::string get_home_directory();
std::string get_current_directory();
bool is_path_absolute(gsl::cstring_span path);
bool is_path_separator(char32_t character);
void append_path_separator(std::string &path);
std::string normalize_path_separators(gsl::cstring_span path);
std::string make_path_canonical(gsl::cstring_span path);
std::string expand_path_tilde(gsl::cstring_span path);
gsl::cstring_span path_file_name(gsl::cstring_span path);
gsl::cstring_span path_directory(gsl::cstring_span path);

std::string get_display_path(gsl::cstring_span path);

#if defined(_WIN32)
std::string known_folder_path(int csidl, std::error_code &ec);
std::string known_folder_path(int csidl);
#endif


// Distributed under MIT License, see LICENSE file
// (c) 2018 Zbigniew Skowron, zbychs@gmail.com

#pragma once

#include "text_buffer.h"
#include "text_parser.h"
#include "text_renderer.h"
#include "geometry.h"

#include <string>
#include <vector>
#include <iostream>

#include <gsl/span>

namespace terminal_editor {

/// This class describes position in a TextBuffer.
/// Positions are logically between characters.
struct GraphemePosition : Position {
    int screenColumn; ///< Column on the screen (zero indexed).

    GraphemePosition() : screenColumn(0) {}
    GraphemePosition(Position position, int screenColumn) : Position(position), screenColumn(screenColumn) {}

    friend std::ostream& operator<<(std::ostream& os, GraphemePosition graphemePosition) {
        return os << "GraphemePosition{" << graphemePosition.row << ", " << graphemePosition.column << ", scrCol=" << graphemePosition.screenColumn << "}";
    }
};

/// This class is an editable container of lines of graphemes.
/// @note By screen coordinates below we mean coordinates that take into account rendered sizes of graphemes in screen cells, but not window position or text offset inside a window.
/// @note This is a very straighforward implementation. It is not efficient.
class GraphemeBuffer {
private:
    TextBuffer& m_textBuffer;
    std::vector<std::vector<Grapheme>> renderedLines; ///< Will always have at least one line.

public:
    GraphemeBuffer(TextBuffer& textBuffer);

    /// Empty virtual destructor.
    virtual ~GraphemeBuffer() {
    }

    /// Replaces contents of this text buffer with contents of given file.
    /// @param fileName     Name of file to load.
    virtual void loadFile(const std::string& fileName);

    /// Returns number of lines in this text buffer.
    /// @note It will always be 1 + number of LF's in file.
    int getNumberOfLines() const;

    /// Returns length of the longest line, on screen.
    int getLongestLineLength() const;

    /// Returns contents of given line.
    /// If row is less than zero or greater than number of lines - 1, empty span is returned.
    /// Span is valid only until next edit on the buffer.
    /// @param row          Row to return (zero indexed).
    gsl::span<const Grapheme> getLine(int row) const;

    /// Returns part of given line from colStart (inclusive) to colEnd (exclusive).
    /// colStart and colEnd are first clamped to the range 0 (inclusive) to line length (inclusive).
    /// Span is valid only until next edit on the buffer.
    /// @param row          Row to return (zero indexed).
    /// @param colStart     First grapheme to return (zero indexed).
    /// @param colEnd       One past last grapheme to return (zero indexed).
    gsl::span<const Grapheme> getLineRange(int row, int colStart, int colEnd) const;

    /// Returns Point that corresponds to screen coordinates of given Position.
    /// @param Position     Position of a grapheme (can be one past end of line).
    /// @return Point in screen coordinates of first cell of the grapheme.
    [[nodiscard]]
    Point positionToPoint(Position position);

    /// Returns Position that corresponds to given Point in screen coordinates.
    /// @note If point row is outside of row bounds, it is clamped to valid range.
    /// @note If point is after the line end, returns position one past end of line.
    /// @note If point is before the line start, returns position of first grapheme in line.
    /// @param point    Point in screen coordinates.
    /// @param after    If point is not on first screen cell of a grapheme, return position after a grapheme.
    ///                 Otherwise return position of grapheme under point.
    /// @return Position of grapheme under point (can be one past end of line).
    ///         Returned Position is clamped to valid line row/column.
    [[nodiscard]]
    Position pointToPosition(Point point, bool after);

    /// Inserts given text into this grapheme buffer.
    /// position is first clamped to a valid range.
    /// @param position     Position to insert into.
    /// @param text         Text to insert. May contain new lines. Doesn't have to be valid UTF-8.
    /// @returns Position of the end of inserted text in the new grapheme buffer.
    virtual Position insertText(Position position, const std::string& text);

    /// Deletes text between two positions: from startPosition (inclusive) to endPosition (exclusive).
    /// positions are first clamped to valid range.
    /// positions can be on different lines.
    /// If startPosition is past endPosition no characters are removed.
    /// @param startPosition    Start position. This is first position that will be removed.
    /// @param endPosition      End position. This is first position that will not be removed.
    /// @returns Characters removed (including newlines).
    virtual std::string deleteText(Position startPosition, Position endPosition);

    /// Clamps position to a valid range, so:
    /// - row is clamped to range from 0 to number of lines (inclusive),
    /// - column is clamped to range from 0 to line length (inclusive).
    [[nodiscard]]
    Position clampPosition(Position position) const;

protected:
    /// Maps grapheme position to position in underlying text buffer.
    [[nodiscard]]
    Position positionToTextPosition(Position position) const;

    /// Maps position in underlying text buffer to grapheme position.
    /// @param after    If position is not on first byte of a grapheme, return position after a grapheme.
    ///                 Otherwise return position of grapheme with given byte.
    [[nodiscard]]
    Position textPositionToPosition(Position textPosition, bool after) const;

    /// Re-renders all lines based on TextBuffer.
    /// renderedLines is re-initialized.
    void rerenderAllLines();

    /// Re-renders given line.
    void rerenderLine(int row);
};

} // namespace terminal_editor


#pragma once

#if __has_include(<span>) && (__cplusplus > 201703L)
#include <span>
#else
#include <gsl/span>
namespace std {
template <class T, std::size_t Extent = gsl::dynamic_extent>
using span = gsl::span<T, Extent>;
}
#endif


#pragma once
#include "iparam.h"
#include "configaccess.h"
#include "optioninfo.h"
#include "format.h"
#include "streamreader.h"
#include <gsl/gsl>
#include <cmdlime/errors.h>
#include <cmdlime/customnames.h>
#include <sstream>
#include <optional>
#include <memory>
#include <functional>

namespace cmdlime::detail{

template<typename T>
class Param : public IParam{
public:
    Param(std::string name,
          std::string shortName,
          std::string type,
          std::function<T&()> paramGetter)
        : info_(std::move(name), std::move(shortName), std::move(type))
        , paramGetter_(std::move(paramGetter))
    {
    }

    void setDefaultValue(const T& value)
    {
        hasValue_ = true;
        defaultValue_ = value;
    }

    OptionInfo& info() override
    {
        return info_;
    }

    const OptionInfo& info() const override
    {
        return info_;
    }

private:
    bool read(const std::string& data) override
    {
        auto stream = std::stringstream{data};
        if (!readFromStream(stream, paramGetter_()))
            return false;
        hasValue_ = true;
        return true;
    }

    bool hasValue() const override
    {
        return hasValue_;
    }

    bool isOptional() const override
    {
        return defaultValue_.has_value();
    }

    std::string defaultValue() const override
    {
        if (!defaultValue_.has_value())
            return {};
        auto stream = std::stringstream{};
        stream << defaultValue_.value();
        return stream.str();
    }

private:
    OptionInfo info_;
    std::function<T&()> paramGetter_;
    std::optional<T> defaultValue_;
    bool hasValue_ = false;
};

template <>
inline bool Param<std::string>::read(const std::string& data)
{
    paramGetter_() = data;
    hasValue_ = true;
    return true;
}

template<typename T, typename TConfig>
class ParamCreator{
    using NameProvider = typename Format<ConfigAccess<TConfig>::format()>::nameProvider;
public:
    ParamCreator(TConfig& cfg,
                 const std::string& varName,
                 const std::string& type,
                 std::function<T&()> paramGetter)
        : cfg_(cfg)
    {
        Expects(!varName.empty());
        Expects(!type.empty());
        param_ = std::make_unique<Param<T>>(NameProvider::name(varName),
                                            NameProvider::shortName(varName),
                                            NameProvider::valueName(type),
                                            std::move(paramGetter));
    }

    ParamCreator<T, TConfig>& operator<<(const std::string& info)
    {
        param_->info().addDescription(info);
        return *this;
    }

    ParamCreator<T, TConfig>& operator<<(const Name& customName)
    {
        param_->info().resetName(customName.value());
        return *this;
    }

    ParamCreator<T, TConfig>& operator<<(const ShortName& customName)
    {
        static_assert(Format<ConfigAccess<TConfig>::format()>::shortNamesEnabled,
                      "Current command line format doesn't support short names");
        param_->info().resetShortName(customName.value());
        return *this;
    }

    ParamCreator<T, TConfig>& operator<<(const WithoutShortName&)
    {
        static_assert(Format<ConfigAccess<TConfig>::format()>::shortNamesEnabled,
                      "Current command line format doesn't support short names");
        param_->info().resetShortName({});
        return *this;
    }

    ParamCreator<T, TConfig>& operator<<(const ValueName& valueName)
    {
        param_->info().resetValueName(valueName.value());
        return *this;
    }

    ParamCreator<T, TConfig>& operator()(T defaultValue = {})
    {
        defaultValue_ = std::move(defaultValue);
        param_->setDefaultValue(defaultValue_);
        return *this;
    }

    operator T()
    {
        ConfigAccess<TConfig>{cfg_}.addParam(std::move(param_));
        return defaultValue_;
    }

private:
    std::unique_ptr<Param<T>> param_;
    T defaultValue_;
    TConfig& cfg_;
};

template <typename T, typename TConfig>
ParamCreator<T, TConfig> makeParamCreator(TConfig& cfg,
                                          const std::string& varName,
                                          const std::string& type,
                                          std::function<T&()> paramGetter)
{
    return ParamCreator<T, TConfig>{cfg, varName, type, std::move(paramGetter)};
}

}