/*==================BEGIN ASF AUTO-GENERATED DOCUMENTATION==================*/
/*
ABOUT EDITING THIS DOCUMENTATION:
If you wish to edit the documentation for this program, you need to
change the following defines. For the short ones (like
ASF_NAME_STRING) this is no big deal. However, for some of the longer
ones, such as ASF_COPYRIGHT_STRING, it can be a daunting task to get
all the newlines in correctly, etc. In order to help you with this
task, there is a tool, edit_man_header. The tool *only* works with
this portion of the code, so fear not. It will scan in defines of the
format #define ASF_<something>_STRING between the two auto-generated
documentation markers, format them for a text editor, run that editor,
allow you to edit the text in a clean manner, and then automatically
generate these defines, formatted appropriately. The only warning is
that any text between those two markers and not part of one of those
defines will not be preserved, and that all of this auto-generated
code will be at the top of the source file. Save yourself the time and
trouble, and use edit_man_header. :)
*/

#define ASF_NAME_STRING \
"asf_geocode"

#define ASF_USAGE_STRING \
"   "ASF_NAME_STRING" -p <projection name> <<projection parameters>>\n"\
"             [-force] [-resample-method <method>] [-height <height>]\n"\
"             [-datum <datum>] [-pixel-size <pixel size>] [-band <band_id | all>]\n"\
"             [-log <file>] [-write-proj-file <file>] [-read-proj-file <file>]\n"\
"             [-save-mapping] [-background <value>] [-quiet] [-license]\n"\
"             [-version] [-help]\n"\
"             <in_base_name> <out_base_name>\n"\
"\n"\
"   Use the -help option for more projection parameter controls.\n"

#define ASF_DESCRIPTION_STRING \
"     This program takes a map projected or an unprojected (ground\n"\
"     range) image in the ASF internal format and geocodes it,\n"\
"     i.e. swizzles it around into one of the standard projections used\n"\
"     for maps (universal transverse mercator, polar stereo, etc).  The\n"\
"     output is a new image in ASF internal format.\n"

#define ASF_INPUT_STRING \
"     Most of the \"options\" are actually required.  The specification\n"\
"     of a certain projection type implies that all the parameters\n"\
"     required to fully specify a projection of that type be included.\n"\
"\n"\
"     This must be an ASF internal format image base name.\n"

#define ASF_OUTPUT_STRING \
"     The base name of the geocoded image to produce.\n"

#define ASF_OPTIONS_STRING \
"%s"\
"\n"\
"     -save-mapping\n"\
"          Creates two additional files during geocoding.  One will contain\n"\
"          the line number from which the pixel was obtained from the\n"\
"          original file, the other the sample numbers.  Together, these\n"\
"          define the mapping of pixels performed by the geocoding.\n"\
"\n"\
"     -log <log file>\n"\
"          Output will be written to a specified log file.\n"\
"\n"\
"     -quiet\n"\
"          Supresses all non-essential output.\n"\
"\n"\
"     -license\n"\
"          Print copyright and license for this software then exit.\n"\
"\n"\
"     -version\n"\
"          Print version and copyright then exit.\n"\
"\n"\
"     -help\n"\
"          Print a help page and exit.\n"

#define ASF_EXAMPLES_STRING \
"     To map project an image with centerpoint at -147 degrees\n"\
"     longitude and average height 466 meters into universal transverse\n"\
"     mercator projection, with one pixel 50 meters on a side:\n"\
"\n"\
"     "ASF_NAME_STRING" -p utm --central-meridian -147.0 --height 466\n"\
"                 input_image output_image\n"\
"\n"\
"     To geocode one band within an image file, you specify the selected band\n"\
"     with the -band option, and the selected band MUST be one of which appears\n"\
"     in the list of available bands as noted in the 'bands' item found in the\n"\
"     'general' (first) block in the metadata file.  For example, if 'bands'\n"\
"     contains \"01,02,03,04\", then you could specify a band_id, e.g. \"-band 02\"\n"\
"     etc on the command line.  The same applies to band lists, such\n"\
"     as \"HH,HV,VH,VV\" or just \"03\" etc.\n"\
"\n"\
"     "ASF_NAME_STRING" -p utm -band HV file outfile_HV\n"

#define ASF_LIMITATIONS_STRING \
"     May fail badly if bad projection parameters are supplied for the\n"\
"     area in the image.\n"

#define ASF_SEE_ALSO_STRING \
"     asf_import, asf_export\n"

/*===================END ASF AUTO-GENERATED DOCUMENTATION===================*/
#include <asf_contact.h>
#include <asf_license.h>

// Standard libraries.
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Libraries from packages outside ASF.
#include <glib.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_spline.h>
#include <gsl/gsl_statistics_double.h>

// Libraries developed at ASF.
#include <asf.h>
#include <asf_nan.h>
#include <asf_meta.h>
#include <asf_raster.h>
#include "float_image.h"
#include <libasf_proj.h>
#include <spheroids.h>
#include <asf_contact.h>

// Headers used by this program.
#include "asf_geocode.h"

// Print minimalistic usage info & exit
static void print_usage(void)
{
  asfPrintStatus("\n"
      "Usage:\n"
      ASF_USAGE_STRING
      "\n");
  exit(EXIT_FAILURE);
}

// Print the help info & exit
static void print_help(void)
{
  asfPrintStatus(
      "\n"
      "Tool name:\n   " ASF_NAME_STRING "\n\n"
      "Usage:\n" ASF_USAGE_STRING "\n"
      "Description:\n" ASF_DESCRIPTION_STRING "\n"
      "Input:\n" ASF_INPUT_STRING "\n"
      "Output:\n"ASF_OUTPUT_STRING "\n"
      "Options:\n" ASF_OPTIONS_STRING "\n"
      "Examples:\n" ASF_EXAMPLES_STRING "\n"
      "Limitations:\n" ASF_LIMITATIONS_STRING "\n"
      "See also:\n" ASF_SEE_ALSO_STRING "\n"
      "Contact:\n" ASF_CONTACT_STRING "\n"
      "Version:\n   " SVN_REV " (part of " TOOL_SUITE_NAME " " MAPREADY_VERSION_STRING ")\n\n",
        geocode_projection_options_help());
  exit(EXIT_FAILURE);
}

// Main routine.
int
main (int argc, char **argv)
{
  int force_flag = FALSE;
  int debug_dump = FALSE;
  char band_id[256]="";
  char *in_base_name, *out_base_name;

  in_base_name = (char *) MALLOC(sizeof(char)*255);
  out_base_name = (char *) MALLOC(sizeof(char)*255);

  // Get the projection parameters from the command line.
  projection_type_t projection_type;
  // Terrain height to assume.  Defaults to 0 (no height correction)
  double average_height = 0.0;
  // Pixel size to use for output image, in projection coordinate
  // units.  This variable corresponds to a "private"
  // (i.e. undocumented, so users don't fiddle with it) option.
  // NOTE: Setting the pixel size to a negative number results in the
  // code to pick a pixel size from the metadata
  double pixel_size = -1;
  // Datum to use in the target projection
  datum_type_t datum;
  spheroid_type_t spheroid;
  // Method to use to resample images.
  resample_method_t resample_method;
  // Value to put in the region outside the image
  double background_val = 0.0;
  // Should we save the mapping files?
  int save_map_flag;

  if (detect_flag_options(argc, argv, "-help", "--help", "-h", NULL)) {
    print_help();
  }

  // Detect & Process logging arguments
  if ((logflag = detect_string_options(argc, argv, logFile,
                      "-log", "--log", NULL))) {
      fLog = fopen (logFile, "a");
      if ( fLog == NULL ) {
    // Couldn't open the log file, so just don't do logging.
    logflag = FALSE;
      }
  }
  quietflag = detect_flag_options(argc, argv, "-quiet", "--quiet", NULL);
  save_map_flag = extract_flag_options(&argc, &argv, "-save-mapping", "--save_mapping", NULL);

  handle_license_and_version_args(argc, argv, ASF_NAME_STRING);

  asfSplashScreen(argc, argv);

  project_parameters_t *pp
    = get_geocode_options (&argc, &argv, &projection_type, &average_height,
			   &pixel_size, &datum, &spheroid, &resample_method,
			   &force_flag, band_id);

  if (!pp && projection_type != LAT_LONG_PSEUDO_PROJECTION) {
      print_usage();
  }

  // The argument at which the filenames start
  int arg_num = 1;

  if (detect_flag_options(argc, argv, "-debug", NULL)) {
    debug_dump=TRUE;
    ++arg_num;
  }

  if (!extract_double_options(&argc, &argv, &background_val, "--background",
			      "-background", NULL)) {
    strcpy(in_base_name, argv[arg_num]);
    meta_parameters *meta = meta_read(in_base_name);
    background_val = meta->general->no_data;
    asfPrintStatus("Extracted no data value (%f) out of the metadata.\n",
		   meta->general->no_data);
    meta_free(meta);
  }
  if (ISNAN(background_val)) background_val = DEFAULT_NO_DATA_VALUE;

  // Get non-option command line arguments.
  if ( argc != 3 && !debug_dump ) {
    int ii;
    int bad_arg = FALSE;

    for (ii = 0; ii < argc; ++ii) {
      if (argv[ii][0] == '-') {
    bad_arg = TRUE;
    asfPrintStatus("Unrecognized argument: %s\n", argv[ii]);
      }
    }

    if (!bad_arg)
      fprintf (stderr, "Wrong number of arguments\n");

    print_usage ();
  }

  strcpy (in_base_name, argv[arg_num]);
  strcpy (out_base_name, argv[arg_num + 1]);

  // Strip .img and also check to make sure input and output
  // base names are not the same
  char *ext = findExt(in_base_name);
  if (ext && strncmp(ext, ".img", 4) == 0) *ext = '\0';
  ext = findExt(out_base_name);
  if (ext && strncmp(ext, ".img", 4) == 0) *ext = '\0';
  char msg[512];
  sprintf(msg,"Input and output basenames cannot be the same:\n"
      "    Input base name : %s\n"
          "    Output base name: %s\n",
      in_base_name, out_base_name);
  if (strcmp(in_base_name, out_base_name) == 0)
    asfPrintError(msg);

  // Call library function that does the actual work
  asf_geocode(pp, projection_type, force_flag, resample_method, average_height,
          datum, pixel_size, band_id, in_base_name, out_base_name,
              (float)background_val, save_map_flag);

  // Close Log, if needed
  if (logflag)
    FCLOSE (fLog);

  exit (EXIT_SUCCESS);
}


#ifndef __GSL_VERSION_H__
#define __GSL_VERSION_H__

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

#include <gsl/gsl_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.4"
#define GSL_MAJOR_VERSION 2
#define GSL_MINOR_VERSION 4

GSL_VAR const char * gsl_version;

__END_DECLS

#endif /* __GSL_VERSION_H__ */


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

#ifndef __GSL_MATRIX_UCHAR_H__
#define __GSL_MATRIX_UCHAR_H__

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

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

__BEGIN_DECLS

typedef struct
{
  size_t size1;
  size_t size2;
  size_t tda;
  unsigned char * data;
  gsl_block_uchar * block;
  int owner;
} gsl_matrix_uchar;

typedef struct
{
  gsl_matrix_uchar matrix;
} _gsl_matrix_uchar_view;

typedef _gsl_matrix_uchar_view gsl_matrix_uchar_view;

typedef struct
{
  gsl_matrix_uchar matrix;
} _gsl_matrix_uchar_const_view;

typedef const _gsl_matrix_uchar_const_view gsl_matrix_uchar_const_view;

/* Allocation */

gsl_matrix_uchar *
gsl_matrix_uchar_alloc (const size_t n1, const size_t n2);

gsl_matrix_uchar *
gsl_matrix_uchar_calloc (const size_t n1, const size_t n2);

gsl_matrix_uchar *
gsl_matrix_uchar_alloc_from_block (gsl_block_uchar * b,
                                   const size_t offset,
                                   const size_t n1,
                                   const size_t n2,
                                   const size_t d2);

gsl_matrix_uchar *
gsl_matrix_uchar_alloc_from_matrix (gsl_matrix_uchar * m,
                                    const size_t k1,
                                    const size_t k2,
                                    const size_t n1,
                                    const size_t n2);

gsl_vector_uchar *
gsl_vector_uchar_alloc_row_from_matrix (gsl_matrix_uchar * m,
                                        const size_t i);

gsl_vector_uchar *
gsl_vector_uchar_alloc_col_from_matrix (gsl_matrix_uchar * m,
                                        const size_t j);

void gsl_matrix_uchar_free (gsl_matrix_uchar * m);

/* Views */

_gsl_matrix_uchar_view
gsl_matrix_uchar_submatrix (gsl_matrix_uchar * m,
                            const size_t i, const size_t j,
                            const size_t n1, const size_t n2);

_gsl_vector_uchar_view
gsl_matrix_uchar_row (gsl_matrix_uchar * m, const size_t i);

_gsl_vector_uchar_view
gsl_matrix_uchar_column (gsl_matrix_uchar * m, const size_t j);

_gsl_vector_uchar_view
gsl_matrix_uchar_diagonal (gsl_matrix_uchar * m);

_gsl_vector_uchar_view
gsl_matrix_uchar_subdiagonal (gsl_matrix_uchar * m, const size_t k);

_gsl_vector_uchar_view
gsl_matrix_uchar_superdiagonal (gsl_matrix_uchar * m, const size_t k);

_gsl_matrix_uchar_view
gsl_matrix_uchar_view_array (unsigned char * base,
                             const size_t n1,
                             const size_t n2);

_gsl_matrix_uchar_view
gsl_matrix_uchar_view_array_with_tda (unsigned char * base,
                                      const size_t n1,
                                      const size_t n2,
                                      const size_t tda);

_gsl_matrix_uchar_view
gsl_matrix_uchar_view_vector (gsl_vector_uchar * v,
                              const size_t n1,
                              const size_t n2);

_gsl_matrix_uchar_view
gsl_matrix_uchar_view_vector_with_tda (gsl_vector_uchar * v,
                                       const size_t n1,
                                       const size_t n2,
                                       const size_t tda);

_gsl_matrix_uchar_const_view
gsl_matrix_uchar_const_submatrix (const gsl_matrix_uchar * m,
                                  const size_t i, const size_t j,
                                  const size_t n1, const size_t n2);

_gsl_vector_uchar_const_view
gsl_matrix_uchar_const_row (const gsl_matrix_uchar * m,
                            const size_t i);

_gsl_vector_uchar_const_view
gsl_matrix_uchar_const_column (const gsl_matrix_uchar * m,
                               const size_t j);

_gsl_vector_uchar_const_view
gsl_matrix_uchar_const_diagonal (const gsl_matrix_uchar * m);

_gsl_vector_uchar_const_view
gsl_matrix_uchar_const_subdiagonal (const gsl_matrix_uchar * m,
                                    const size_t k);

_gsl_vector_uchar_const_view
gsl_matrix_uchar_const_superdiagonal (const gsl_matrix_uchar * m,
                                      const size_t k);

_gsl_matrix_uchar_const_view
gsl_matrix_uchar_const_view_array (const unsigned char * base,
                                   const size_t n1,
                                   const size_t n2);

_gsl_matrix_uchar_const_view
gsl_matrix_uchar_const_view_array_with_tda (const unsigned char * base,
                                            const size_t n1,
                                            const size_t n2,
                                            const size_t tda);

_gsl_matrix_uchar_const_view
gsl_matrix_uchar_const_view_vector (const gsl_vector_uchar * v,
                                    const size_t n1,
                                    const size_t n2);

_gsl_matrix_uchar_const_view
gsl_matrix_uchar_const_view_vector_with_tda (const gsl_vector_uchar * v,
                                             const size_t n1,
                                             const size_t n2,
                                             const size_t tda);

/* Operations */

unsigned char   gsl_matrix_uchar_get(const gsl_matrix_uchar * m, const size_t i, const size_t j);
void    gsl_matrix_uchar_set(gsl_matrix_uchar * m, const size_t i, const size_t j, const unsigned char x);

unsigned char * gsl_matrix_uchar_ptr(gsl_matrix_uchar * m, const size_t i, const size_t j);
const unsigned char * gsl_matrix_uchar_const_ptr(const gsl_matrix_uchar * m, const size_t i, const size_t j);

void gsl_matrix_uchar_set_zero (gsl_matrix_uchar * m);
void gsl_matrix_uchar_set_identity (gsl_matrix_uchar * m);
void gsl_matrix_uchar_set_all (gsl_matrix_uchar * m, unsigned char x);

int gsl_matrix_uchar_fread (FILE * stream, gsl_matrix_uchar * m) ;
int gsl_matrix_uchar_fwrite (FILE * stream, const gsl_matrix_uchar * m) ;
int gsl_matrix_uchar_fscanf (FILE * stream, gsl_matrix_uchar * m);
int gsl_matrix_uchar_fprintf (FILE * stream, const gsl_matrix_uchar * m, const char * format);

int gsl_matrix_uchar_memcpy(gsl_matrix_uchar * dest, const gsl_matrix_uchar * src);
int gsl_matrix_uchar_swap(gsl_matrix_uchar * m1, gsl_matrix_uchar * m2);

int gsl_matrix_uchar_swap_rows(gsl_matrix_uchar * m, const size_t i, const size_t j);
int gsl_matrix_uchar_swap_columns(gsl_matrix_uchar * m, const size_t i, const size_t j);
int gsl_matrix_uchar_swap_rowcol(gsl_matrix_uchar * m, const size_t i, const size_t j);
int gsl_matrix_uchar_transpose (gsl_matrix_uchar * m);
int gsl_matrix_uchar_transpose_memcpy (gsl_matrix_uchar * dest, const gsl_matrix_uchar * src);

unsigned char gsl_matrix_uchar_max (const gsl_matrix_uchar * m);
unsigned char gsl_matrix_uchar_min (const gsl_matrix_uchar * m);
void gsl_matrix_uchar_minmax (const gsl_matrix_uchar * m, unsigned char * min_out, unsigned char * max_out);

void gsl_matrix_uchar_max_index (const gsl_matrix_uchar * m, size_t * imax, size_t *jmax);
void gsl_matrix_uchar_min_index (const gsl_matrix_uchar * m, size_t * imin, size_t *jmin);
void gsl_matrix_uchar_minmax_index (const gsl_matrix_uchar * m, size_t * imin, size_t * jmin, size_t * imax, size_t * jmax);

int gsl_matrix_uchar_isnull (const gsl_matrix_uchar * m);
int gsl_matrix_uchar_ispos (const gsl_matrix_uchar * m);
int gsl_matrix_uchar_isneg (const gsl_matrix_uchar * m);

int gsl_matrix_uchar_add (gsl_matrix_uchar * a, const gsl_matrix_uchar * b);
int gsl_matrix_uchar_sub (gsl_matrix_uchar * a, const gsl_matrix_uchar * b);
int gsl_matrix_uchar_mul_elements (gsl_matrix_uchar * a, const gsl_matrix_uchar * b);
int gsl_matrix_uchar_div_elements (gsl_matrix_uchar * a, const gsl_matrix_uchar * b);
int gsl_matrix_uchar_scale (gsl_matrix_uchar * a, const double x);
int gsl_matrix_uchar_add_constant (gsl_matrix_uchar * a, const double x);
int gsl_matrix_uchar_add_diagonal (gsl_matrix_uchar * a, const double x);

/***********************************************************************/
/* The functions below are obsolete                                    */
/***********************************************************************/
int gsl_matrix_uchar_get_row(gsl_vector_uchar * v, const gsl_matrix_uchar * m, const size_t i);
int gsl_matrix_uchar_get_col(gsl_vector_uchar * v, const gsl_matrix_uchar * m, const size_t j);
int gsl_matrix_uchar_set_row(gsl_matrix_uchar * m, const size_t i, const gsl_vector_uchar * v);
int gsl_matrix_uchar_set_col(gsl_matrix_uchar * m, const size_t j, const gsl_vector_uchar * v);

/* inline functions if you are using GCC */

#ifdef HAVE_INLINE
extern inline
unsigned char
gsl_matrix_uchar_get(const gsl_matrix_uchar * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (i >= m->size1)
    {
      GSL_ERROR_VAL("first index out of range", GSL_EINVAL, 0) ;
    }
  else if (j >= m->size2)
    {
      GSL_ERROR_VAL("second index out of range", GSL_EINVAL, 0) ;
    }
#endif
  return m->data[i * m->tda + j] ;
}

extern inline
void
gsl_matrix_uchar_set(gsl_matrix_uchar * m, const size_t i, const size_t j, const unsigned char x)
{
#if GSL_RANGE_CHECK
  if (i >= m->size1)
    {
      GSL_ERROR_VOID("first index out of range", GSL_EINVAL) ;
    }
  else if (j >= m->size2)
    {
      GSL_ERROR_VOID("second index out of range", GSL_EINVAL) ;
    }
#endif
  m->data[i * m->tda + j] = x ;
}

extern inline
unsigned char *
gsl_matrix_uchar_ptr(gsl_matrix_uchar * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (i >= m->size1)
    {
      GSL_ERROR_NULL("first index out of range", GSL_EINVAL) ;
    }
  else if (j >= m->size2)
    {
      GSL_ERROR_NULL("second index out of range", GSL_EINVAL) ;
    }
#endif
  return (unsigned char *) (m->data + (i * m->tda + j)) ;
}

extern inline
const unsigned char *
gsl_matrix_uchar_const_ptr(const gsl_matrix_uchar * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (i >= m->size1)
    {
      GSL_ERROR_NULL("first index out of range", GSL_EINVAL) ;
    }
  else if (j >= m->size2)
    {
      GSL_ERROR_NULL("second index out of range", GSL_EINVAL) ;
    }
#endif
  return (const unsigned char *) (m->data + (i * m->tda + j)) ;
}

#endif

__END_DECLS

#endif /* __GSL_MATRIX_UCHAR_H__ */


#pragma once

#include "type_traits.h"

#include <gsl/gsl>

#include <system_error>
#include <variant>

namespace arcana
{
    template<typename Type>
    struct is_expected;

    template<typename T, typename E>
    class basic_expected;

    namespace internal
    {
        template<typename T>
        struct expected_error_traits;

        template<>
        struct expected_error_traits<std::error_code>
        {
            template<typename ErrorT>
            using is_convertible = std::bool_constant<
                std::is_error_code_enum<std::decay_t<ErrorT>>::value ||
                std::is_error_condition_enum<std::decay_t<ErrorT>>::value
            >;

            template<typename ErrorT>
            using enable_conversion = std::enable_if<
                is_convertible<ErrorT>::value
            >;

            template<typename ErrorT>
            static std::error_code convert(ErrorT errorEnum)
            {
                using std::make_error_code;

                return make_error_code(errorEnum);
            }
        };

        template<>
        struct expected_error_traits<std::exception_ptr>
        {
            template<typename ErrorT>
            using enable_conversion = std::enable_if<
                std::is_same<std::error_code, ErrorT>::value || // support conversion from error_codes
                expected_error_traits<std::error_code>::template is_convertible<ErrorT>::value // and also enumerations that are error codes
            >;

            static std::exception_ptr convert(std::error_code code)
            {
                return std::make_exception_ptr(std::system_error(code));
            }

            template<typename ErrorT, typename = typename expected_error_traits<std::error_code>::template enable_conversion<ErrorT>::type>
            static std::exception_ptr convert(ErrorT errorEnum)
            {
                return convert(
                    expected_error_traits<std::error_code>::convert(errorEnum));
            }
        };
    }

    class bad_expected_access : public std::exception
    {
    public:
        const char* what() const override
        {
            return "tried accessing value()/error() of an expected when it wasn't set";
        }
    };

    template<typename E>
    class unexpected
    {
    public:
        unexpected() = delete;

        constexpr explicit unexpected(const E& e)
            : m_e{ e }
        {}

        constexpr explicit unexpected(E&& e)
            : m_e{ std::move(e) }
        {}

        constexpr const E& value() const &
        {
            return m_e;
        }

        constexpr E& value() &
        {
            return m_e;
        }

        constexpr E&& value() &&
        {
            return std::move(m_e);
        }
    private:
        E m_e;
    };

    template<typename T>
    inline auto make_unexpected(T&& error)
    {
        return unexpected<std::decay_t<T>>{std::forward<T>(error)};
    }

    template<typename T, typename E>
    class basic_expected
    {
        using traits = internal::expected_error_traits<E>;

        template<typename E2,
            typename = typename traits::template enable_conversion<E2>::type>
        std::variant<E, T> convert_variant(const basic_expected<T, E2>& exp)
        {
            if (exp.has_error())
                return { traits::convert(exp.error()) };
            else
                return { exp.value() };
        }
    public:
        using value_type = T;
        using error_type = E;

        basic_expected(const value_type& value)
            : m_data{ value }
        {}

        basic_expected(value_type&& value)
            : m_data{ std::move(value) }
        {}

        template<typename ErrorT,
            typename = typename traits::template enable_conversion<ErrorT>::type>
        basic_expected(const unexpected<ErrorT>& errorEnum)
            : m_data{ traits::convert(errorEnum.value()) }
        {}

        basic_expected(const unexpected<error_type>& ec)
            : m_data{ ec.value() }
        {
            GSL_CONTRACT_CHECK("you should never build an basic_expected<T,E> with a non-error", static_cast<bool>(error()));
        }

        basic_expected(unexpected<error_type>&& ec)
            : m_data{ std::move(ec).value() }
        {
            GSL_CONTRACT_CHECK("you should never build an basic_expected<T,E> with a non-error", static_cast<bool>(error()));
        }

        template<typename ErrorT,
            typename = typename traits::template enable_conversion<ErrorT>::type>
        basic_expected(const basic_expected<value_type, ErrorT>& other)
            : m_data{ convert_variant(other) }
        {}

        template<typename ErrorT,
            typename = typename traits::template enable_conversion<ErrorT>::type>
        basic_expected& operator=(const basic_expected<value_type, ErrorT>& other)
        {
            m_data = convert_variant(other);
        }

        //
        // Returns the expected value or throws bad_expected_access if it is in an error state.
        //
        const value_type& value() const
        {
            return const_cast<basic_expected*>(this)->value();
        }

        value_type& value()
        {
            auto val = std::get_if<value_type>(&m_data);
            if (val == nullptr)
            {
                throw bad_expected_access();
            }
            return *val;
        }

        //
        // Returns the value contained or the default passed in if the expected is in an error state.
        //
        template<typename U>
        value_type value_or(U&& def) const
        {
            if (!has_value())
            {
                return std::forward<U>(def);
            }

            return value();
        }

        //
        // Returns the error or throws bad_expected_access if it is not in an error state.
        //
        const error_type& error() const
        {
            auto err = std::get_if<error_type>(&m_data);
            if (err == nullptr)
            {
                throw bad_expected_access();
            }
            return *err;
        }

        //
        // Returns whether or not the expected contains a value.
        //
        bool has_value() const noexcept
        {
            return std::holds_alternative<value_type>(m_data);
        }

        //
        // Returns whether or not the expected is in an error state.
        //
        bool has_error() const noexcept
        {
            return std::holds_alternative<error_type>(m_data);
        }

        //
        // Converts to true if the value is valid.
        //
        explicit operator bool() const noexcept
        {
            return has_value();
        }

        //
        // Shorthand access operators
        //
        const value_type& operator*() const
        {
            return value();
        }

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

        //
        // Shorthand access operators
        //
        const value_type* operator->() const
        {
            return &value();
        }

        value_type* operator->()
        {
            return &value();
        }

    private:
        std::variant<error_type, value_type> m_data;
    };

    template<typename E>
    class basic_expected<void, E>
    {
    public:
        using value_type = void;
        using error_type = E;

        using traits = internal::expected_error_traits<error_type>;

        template<typename ErrorT,
            typename = typename traits::template enable_conversion<ErrorT>::type>
        basic_expected(const unexpected<ErrorT>& errorEnum)
            : m_error{ traits::convert(errorEnum.value()) }
        {}

        basic_expected(const unexpected<error_type>& ec)
            : m_error{ ec.value() }
        {
            GSL_CONTRACT_CHECK("you should never build an basic_expected<T,E> with a non-error", static_cast<bool>(error()));
        }

        basic_expected(unexpected<error_type>&& ec)
            : m_error{ std::move(ec).value() }
        {
            GSL_CONTRACT_CHECK("you should never build an basic_expected<T,E> with a non-error", static_cast<bool>(error()));
        }

        template<typename ErrorT,
            typename = typename traits::template enable_conversion<ErrorT>::type>
        basic_expected(const basic_expected<value_type, ErrorT>& other)
            : m_error{ other.has_error() ? traits::convert(other.error()) : nullptr }
        {}

        template<typename ErrorT,
            typename = typename traits::template enable_conversion<ErrorT>::type>
        basic_expected& operator=(const basic_expected<value_type, ErrorT>& other)
        {
            m_error = other.has_error() ? traits::convert(other.error()) : nullptr;
        }

        //
        // Returns the error, throws bad_expected_access if it is not in an error state
        //
        const error_type& error() const
        {
            if (!has_error())
            {
                throw bad_expected_access();
            }
            return m_error;
        }

        //
        // Returns whether or not the expected is in an error state.
        //
        bool has_error() const noexcept
        {
            return static_cast<bool>(m_error);
        }

        //
        // Converts to true if the value is valid.
        //
        explicit operator bool() const noexcept
        {
            return !has_error();
        }

        //
        // Creates an expected<void> that doesn't have an error
        //
        static basic_expected make_valid()
        {
            return basic_expected{};
        }

    private:
        basic_expected() = default;

        error_type m_error;
    };

    template<typename Type>
    struct is_expected : public std::false_type
    {};

    template<typename Type, typename Error>
    struct is_expected<basic_expected<Type, Error>> : public std::true_type
    {};

    template<typename ResultT, typename ErrorT>
    struct as_expected
    {
        using type = basic_expected<ResultT, ErrorT>;
        using value_type = typename type::value_type;
        using error_type = typename type::error_type;
    };

    template<typename ResultT, typename ErrorT, typename DesiredErrorT>
    struct as_expected<basic_expected<ResultT, ErrorT>, DesiredErrorT>
    {
        static_assert(std::is_same<ErrorT, DesiredErrorT>::value, "the error type of the expected and the desired error type don't match");

        using type = basic_expected<ResultT, ErrorT>;
        using value_type = typename type::value_type;
        using error_type = typename type::error_type;
    };

    template<typename ResultT, typename ErrorT>
    using expected = basic_expected<ResultT, ErrorT>;

    template<typename ErrorT>
    struct error_priority;

    template<>
    struct error_priority<std::error_code> : std::integral_constant<int, 0>
    {
        using type = std::error_code;
    };

    template<>
    struct error_priority<std::exception_ptr> : std::integral_constant<int, 1>
    {
        using type = std::exception_ptr;
    };

    template<typename Left, typename Right>
    struct largest_error
    {
        using type = typename typename largest_integral_constant<error_priority<Left>, error_priority<Right>>::type::type;
    };

    namespace internal
    {
        template<typename Expected, typename OrType, bool IsExpected>
        struct expected_error_or_impl
        {
            using type = OrType;
        };

        template<typename Expected, typename OrType>
        struct expected_error_or_impl<Expected, OrType, true>
        {
            using type = typename Expected::error_type;
        };
    }

    template<typename Expected, typename OrType>
    struct expected_error_or : public internal::expected_error_or_impl<Expected, OrType, is_expected<Expected>::value>
    {};
}


/*
 * VGMTrans (c) 2002-2019
 * Licensed under the zlib license,
 * refer to the included LICENSE.txt file
 */

#pragma once

#include <string>
#include <sstream>
#include <cassert>
#include <cmath>
#include <cstring>
#include <iomanip>
#include <climits>
#include <algorithm>
#include <vector>
#include <gsl-lite.hpp>

#include "helper.h"

#define VERSION "1.0.3"

/* Type aliases to save some typing */
using size_t = std::size_t;

using s8 = std::int8_t;
using s16 = std::int16_t;
using s32 = std::int32_t;
using s64 = std::int64_t;
using sptr = std::intptr_t;

using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using uptr = std::uintptr_t;

std::string removeExtFromPath(const std::string &s);

std::string StringToUpper(std::string myString);
std::string StringToLower(std::string myString);

uint32_t StringToHex(const std::string &str);

std::string ConvertToSafeFileName(const std::string &str);

inline int CountBytesOfVal(uint8_t *buf, uint32_t numBytes, uint8_t val) {
    int count = 0;
    for (uint32_t i = 0; i < numBytes; i++)
        if (buf[i] == val)
            count++;
    return count;
}

struct SizeOffsetPair {
    uint32_t size;
    uint32_t offset;

    SizeOffsetPair() : size(0), offset(0) {}

    SizeOffsetPair(uint32_t offset_, uint32_t size_) : size(size_), offset(offset_) {}
};

char *GetFileWithBase(const char *f, const char *newfile);

std::vector<char> zdecompress(gsl::span<const char> data);
std::vector<char> zdecompress(std::vector<char> &data);


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

#ifndef __GSL_VECTOR_UCHAR_H__
#define __GSL_VECTOR_UCHAR_H__

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

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

__BEGIN_DECLS

typedef struct
{
  size_t size;
  size_t stride;
  unsigned char *data;
  gsl_block_uchar *block;
  int owner;
}
gsl_vector_uchar;

typedef struct
{
  gsl_vector_uchar vector;
} _gsl_vector_uchar_view;

typedef _gsl_vector_uchar_view gsl_vector_uchar_view;

typedef struct
{
  gsl_vector_uchar vector;
} _gsl_vector_uchar_const_view;

typedef const _gsl_vector_uchar_const_view gsl_vector_uchar_const_view;

/* Allocation */

gsl_vector_uchar *gsl_vector_uchar_alloc (const size_t n);
gsl_vector_uchar *gsl_vector_uchar_calloc (const size_t n);

gsl_vector_uchar *gsl_vector_uchar_alloc_from_block (gsl_block_uchar * b,
                                                     const size_t offset,
                                                     const size_t n,
                                                     const size_t stride);

gsl_vector_uchar *gsl_vector_uchar_alloc_from_vector (gsl_vector_uchar * v,
                                                      const size_t offset,
                                                      const size_t n,
                                                      const size_t stride);

void gsl_vector_uchar_free (gsl_vector_uchar * v);

/* Views */

_gsl_vector_uchar_view
gsl_vector_uchar_view_array (unsigned char *v, size_t n);

_gsl_vector_uchar_view
gsl_vector_uchar_view_array_with_stride (unsigned char *base,
                                         size_t stride,
                                         size_t n);

_gsl_vector_uchar_const_view
gsl_vector_uchar_const_view_array (const unsigned char *v, size_t n);

_gsl_vector_uchar_const_view
gsl_vector_uchar_const_view_array_with_stride (const unsigned char *base,
                                               size_t stride,
                                               size_t n);

_gsl_vector_uchar_view
gsl_vector_uchar_subvector (gsl_vector_uchar *v,
                            size_t i,
                            size_t n);

_gsl_vector_uchar_view
gsl_vector_uchar_subvector_with_stride (gsl_vector_uchar *v,
                                        size_t i,
                                        size_t stride,
                                        size_t n);

_gsl_vector_uchar_const_view
gsl_vector_uchar_const_subvector (const gsl_vector_uchar *v,
                                  size_t i,
                                  size_t n);

_gsl_vector_uchar_const_view
gsl_vector_uchar_const_subvector_with_stride (const gsl_vector_uchar *v,
                                              size_t i,
                                              size_t stride,
                                              size_t n);

/* Operations */

unsigned char gsl_vector_uchar_get (const gsl_vector_uchar * v, const size_t i);
void gsl_vector_uchar_set (gsl_vector_uchar * v, const size_t i, unsigned char x);

unsigned char *gsl_vector_uchar_ptr (gsl_vector_uchar * v, const size_t i);
const unsigned char *gsl_vector_uchar_const_ptr (const gsl_vector_uchar * v, const size_t i);

void gsl_vector_uchar_set_zero (gsl_vector_uchar * v);
void gsl_vector_uchar_set_all (gsl_vector_uchar * v, unsigned char x);
int gsl_vector_uchar_set_basis (gsl_vector_uchar * v, size_t i);

int gsl_vector_uchar_fread (FILE * stream, gsl_vector_uchar * v);
int gsl_vector_uchar_fwrite (FILE * stream, const gsl_vector_uchar * v);
int gsl_vector_uchar_fscanf (FILE * stream, gsl_vector_uchar * v);
int gsl_vector_uchar_fprintf (FILE * stream, const gsl_vector_uchar * v,
                              const char *format);

int gsl_vector_uchar_memcpy (gsl_vector_uchar * dest, const gsl_vector_uchar * src);

int gsl_vector_uchar_reverse (gsl_vector_uchar * v);

int gsl_vector_uchar_swap (gsl_vector_uchar * v, gsl_vector_uchar * w);
int gsl_vector_uchar_swap_elements (gsl_vector_uchar * v, const size_t i, const size_t j);

unsigned char gsl_vector_uchar_max (const gsl_vector_uchar * v);
unsigned char gsl_vector_uchar_min (const gsl_vector_uchar * v);
void gsl_vector_uchar_minmax (const gsl_vector_uchar * v, unsigned char * min_out, unsigned char * max_out);

size_t gsl_vector_uchar_max_index (const gsl_vector_uchar * v);
size_t gsl_vector_uchar_min_index (const gsl_vector_uchar * v);
void gsl_vector_uchar_minmax_index (const gsl_vector_uchar * v, size_t * imin, size_t * imax);

int gsl_vector_uchar_add (gsl_vector_uchar * a, const gsl_vector_uchar * b);
int gsl_vector_uchar_sub (gsl_vector_uchar * a, const gsl_vector_uchar * b);
int gsl_vector_uchar_mul (gsl_vector_uchar * a, const gsl_vector_uchar * b);
int gsl_vector_uchar_div (gsl_vector_uchar * a, const gsl_vector_uchar * b);
int gsl_vector_uchar_scale (gsl_vector_uchar * a, const double x);
int gsl_vector_uchar_add_constant (gsl_vector_uchar * a, const double x);

int gsl_vector_uchar_isnull (const gsl_vector_uchar * v);

#ifdef HAVE_INLINE

extern inline
unsigned char
gsl_vector_uchar_get (const gsl_vector_uchar * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (i >= v->size)
    {
      GSL_ERROR_VAL ("index out of range", GSL_EINVAL, 0);
    }
#endif
  return v->data[i * v->stride];
}

extern inline
void
gsl_vector_uchar_set (gsl_vector_uchar * v, const size_t i, unsigned char x)
{
#if GSL_RANGE_CHECK
  if (i >= v->size)
    {
      GSL_ERROR_VOID ("index out of range", GSL_EINVAL);
    }
#endif
  v->data[i * v->stride] = x;
}

extern inline
unsigned char *
gsl_vector_uchar_ptr (gsl_vector_uchar * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (i >= v->size)
    {
      GSL_ERROR_NULL ("index out of range", GSL_EINVAL);
    }
#endif
  return (unsigned char *) (v->data + i * v->stride);
}

extern inline
const unsigned char *
gsl_vector_uchar_const_ptr (const gsl_vector_uchar * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (i >= v->size)
    {
      GSL_ERROR_NULL ("index out of range", GSL_EINVAL);
    }
#endif
  return (const unsigned char *) (v->data + i * v->stride);
}

#endif /* HAVE_INLINE */

__END_DECLS

#endif /* __GSL_VECTOR_UCHAR_H__ */


#ifndef TTT_UTIL_FONTCACHE_H
#define TTT_UTIL_FONTCACHE_H

#include <SDL_ttf.h>

#include <gsl/pointers>
#include <gsl/util>

#include <vector>
#include <memory>
#include <string_view>

namespace ttt::gfx
{
	// A class for caching fonts for reuse.
	class FontCache final
	{
	public:
		using SizeType = gsl::index;

		TTF_Font  *load(std::string_view path, int size, int index = 0);
		void unload(SizeType index) noexcept;
		void erase(SizeType index) noexcept;
		void clear() noexcept;

		[[nodiscard]] TTF_Font *at(SizeType index) const noexcept;
		[[nodiscard]] TTF_Font *operator [](SizeType index) const noexcept;

		[[nodiscard]] SizeType getSize() const noexcept;
		[[nodiscard]] SizeType getMaxSize() const noexcept;

	private:
		std::vector<std::unique_ptr<TTF_Font, decltype(&TTF_CloseFont)>> fonts;
	};

	inline void FontCache::unload(SizeType index) noexcept { gsl::at(fonts, index).reset(); }
	inline void FontCache::erase(SizeType index) noexcept { fonts.erase(fonts.cbegin() + index); }
	inline void FontCache::clear() noexcept { fonts.clear(); }

	inline TTF_Font *FontCache::at(SizeType index) const noexcept { return gsl::at(fonts, index).get(); }
	inline TTF_Font *FontCache::operator [](SizeType index) const noexcept { return gsl::at(fonts, index).get(); }

	inline FontCache::SizeType FontCache::getSize() const noexcept { return fonts.size(); }
	inline FontCache::SizeType FontCache::getMaxSize() const noexcept { return fonts.max_size(); }
}

#endif


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

#ifndef PEMC_EXECUTABLE_MODEL_ABSTRACT_MODEL_H_
#define PEMC_EXECUTABLE_MODEL_ABSTRACT_MODEL_H_

#include <vector>
#include <gsl/span>
#include <gsl/gsl_byte>
#include <cstdint>
#include <atomic>
#include <stack>
#include <limits>
#include <functional>

#include "pemc/basic/tsc_index.h"
#include "pemc/basic/label.h"
#include "pemc/basic/model_capacity.h"
#include "pemc/basic/probability.h"
#include "pemc/basic/raw_memory.h"
#include "pemc/formula/formula.h"
#include "pemc/generic_traverser/i_transitions_calculator.h"
#include "pemc/generic_traverser/i_pre_state_storage_modifier.h"
#include "pemc/generic_traverser/i_post_state_storage_modifier.h"
#include "pemc/executable_model/i_choice_resolver.h"

namespace pemc {

  class AbstractModel {
  protected:
      IChoiceResolver* choiceResolver = nullptr;
      std::vector<std::function<bool()>> formulaEvaluators;
  public:
      AbstractModel() {}
      virtual ~AbstractModel() {}

      //AbstractModel(const AbstractModel&) = delete;

      void setChoiceResolver(IChoiceResolver* _choiceResolver);

      virtual void serialize(gsl::span<gsl::byte> position) {}

      virtual void deserialize(gsl::span<gsl::byte> position) {}

      virtual void setFormulasForLabel(const std::vector<std::shared_ptr<Formula>>& _formulas) {}

      Label calculateLabel();

      size_t choose(const gsl::span<Probability>& choices);

      size_t choose(size_t numberOfChoices);

      virtual void resetToInitialState() {}

      virtual void step() {}

      virtual int32_t getStateVectorSize() {return 0;}
  };

}

#endif  // PEMC_EXECUTABLE_MODEL_ABSTRACT_MODEL_H_


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

#ifndef __GSL_MATRIX_USHORT_H__
#define __GSL_MATRIX_USHORT_H__

#include <stdlib.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_vector_ushort.h>

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

__BEGIN_DECLS

typedef struct
{
  size_t size1;
  size_t size2;
  size_t tda;
  unsigned short * data;
  gsl_block_ushort * block;
  int owner;
} gsl_matrix_ushort;

typedef struct
{
  gsl_matrix_ushort matrix;
} _gsl_matrix_ushort_view;

typedef _gsl_matrix_ushort_view gsl_matrix_ushort_view;

typedef struct
{
  gsl_matrix_ushort matrix;
} _gsl_matrix_ushort_const_view;

typedef const _gsl_matrix_ushort_const_view gsl_matrix_ushort_const_view;

/* Allocation */

gsl_matrix_ushort *
gsl_matrix_ushort_alloc (const size_t n1, const size_t n2);

gsl_matrix_ushort *
gsl_matrix_ushort_calloc (const size_t n1, const size_t n2);

gsl_matrix_ushort *
gsl_matrix_ushort_alloc_from_block (gsl_block_ushort * b,
                                   const size_t offset,
                                   const size_t n1,
                                   const size_t n2,
                                   const size_t d2);

gsl_matrix_ushort *
gsl_matrix_ushort_alloc_from_matrix (gsl_matrix_ushort * m,
                                    const size_t k1,
                                    const size_t k2,
                                    const size_t n1,
                                    const size_t n2);

gsl_vector_ushort *
gsl_vector_ushort_alloc_row_from_matrix (gsl_matrix_ushort * m,
                                        const size_t i);

gsl_vector_ushort *
gsl_vector_ushort_alloc_col_from_matrix (gsl_matrix_ushort * m,
                                        const size_t j);

void gsl_matrix_ushort_free (gsl_matrix_ushort * m);

/* Views */

_gsl_matrix_ushort_view
gsl_matrix_ushort_submatrix (gsl_matrix_ushort * m,
                            const size_t i, const size_t j,
                            const size_t n1, const size_t n2);

_gsl_vector_ushort_view
gsl_matrix_ushort_row (gsl_matrix_ushort * m, const size_t i);

_gsl_vector_ushort_view
gsl_matrix_ushort_column (gsl_matrix_ushort * m, const size_t j);

_gsl_vector_ushort_view
gsl_matrix_ushort_diagonal (gsl_matrix_ushort * m);

_gsl_vector_ushort_view
gsl_matrix_ushort_subdiagonal (gsl_matrix_ushort * m, const size_t k);

_gsl_vector_ushort_view
gsl_matrix_ushort_superdiagonal (gsl_matrix_ushort * m, const size_t k);

_gsl_matrix_ushort_view
gsl_matrix_ushort_view_array (unsigned short * base,
                             const size_t n1,
                             const size_t n2);

_gsl_matrix_ushort_view
gsl_matrix_ushort_view_array_with_tda (unsigned short * base,
                                      const size_t n1,
                                      const size_t n2,
                                      const size_t tda);

_gsl_matrix_ushort_view
gsl_matrix_ushort_view_vector (gsl_vector_ushort * v,
                              const size_t n1,
                              const size_t n2);

_gsl_matrix_ushort_view
gsl_matrix_ushort_view_vector_with_tda (gsl_vector_ushort * v,
                                       const size_t n1,
                                       const size_t n2,
                                       const size_t tda);

_gsl_matrix_ushort_const_view
gsl_matrix_ushort_const_submatrix (const gsl_matrix_ushort * m,
                                  const size_t i, const size_t j,
                                  const size_t n1, const size_t n2);

_gsl_vector_ushort_const_view
gsl_matrix_ushort_const_row (const gsl_matrix_ushort * m,
                            const size_t i);

_gsl_vector_ushort_const_view
gsl_matrix_ushort_const_column (const gsl_matrix_ushort * m,
                               const size_t j);

_gsl_vector_ushort_const_view
gsl_matrix_ushort_const_diagonal (const gsl_matrix_ushort * m);

_gsl_vector_ushort_const_view
gsl_matrix_ushort_const_subdiagonal (const gsl_matrix_ushort * m,
                                    const size_t k);

_gsl_vector_ushort_const_view
gsl_matrix_ushort_const_superdiagonal (const gsl_matrix_ushort * m,
                                      const size_t k);

_gsl_matrix_ushort_const_view
gsl_matrix_ushort_const_view_array (const unsigned short * base,
                                   const size_t n1,
                                   const size_t n2);

_gsl_matrix_ushort_const_view
gsl_matrix_ushort_const_view_array_with_tda (const unsigned short * base,
                                            const size_t n1,
                                            const size_t n2,
                                            const size_t tda);

_gsl_matrix_ushort_const_view
gsl_matrix_ushort_const_view_vector (const gsl_vector_ushort * v,
                                    const size_t n1,
                                    const size_t n2);

_gsl_matrix_ushort_const_view
gsl_matrix_ushort_const_view_vector_with_tda (const gsl_vector_ushort * v,
                                             const size_t n1,
                                             const size_t n2,
                                             const size_t tda);

/* Operations */

unsigned short   gsl_matrix_ushort_get(const gsl_matrix_ushort * m, const size_t i, const size_t j);
void    gsl_matrix_ushort_set(gsl_matrix_ushort * m, const size_t i, const size_t j, const unsigned short x);

unsigned short * gsl_matrix_ushort_ptr(gsl_matrix_ushort * m, const size_t i, const size_t j);
const unsigned short * gsl_matrix_ushort_const_ptr(const gsl_matrix_ushort * m, const size_t i, const size_t j);

void gsl_matrix_ushort_set_zero (gsl_matrix_ushort * m);
void gsl_matrix_ushort_set_identity (gsl_matrix_ushort * m);
void gsl_matrix_ushort_set_all (gsl_matrix_ushort * m, unsigned short x);

int gsl_matrix_ushort_fread (FILE * stream, gsl_matrix_ushort * m) ;
int gsl_matrix_ushort_fwrite (FILE * stream, const gsl_matrix_ushort * m) ;
int gsl_matrix_ushort_fscanf (FILE * stream, gsl_matrix_ushort * m);
int gsl_matrix_ushort_fprintf (FILE * stream, const gsl_matrix_ushort * m, const char * format);

int gsl_matrix_ushort_memcpy(gsl_matrix_ushort * dest, const gsl_matrix_ushort * src);
int gsl_matrix_ushort_swap(gsl_matrix_ushort * m1, const gsl_matrix_ushort * m2);

int gsl_matrix_ushort_swap_rows(gsl_matrix_ushort * m, const size_t i, const size_t j);
int gsl_matrix_ushort_swap_columns(gsl_matrix_ushort * m, const size_t i, const size_t j);
int gsl_matrix_ushort_swap_rowcol(gsl_matrix_ushort * m, const size_t i, const size_t j);
int gsl_matrix_ushort_transpose (gsl_matrix_ushort * m);
int gsl_matrix_ushort_transpose_memcpy (gsl_matrix_ushort * dest, const gsl_matrix_ushort * src);

unsigned short gsl_matrix_ushort_max (const gsl_matrix_ushort * m);
unsigned short gsl_matrix_ushort_min (const gsl_matrix_ushort * m);
void gsl_matrix_ushort_minmax (const gsl_matrix_ushort * m, unsigned short * min_out, unsigned short * max_out);

void gsl_matrix_ushort_max_index (const gsl_matrix_ushort * m, size_t * imax, size_t *jmax);
void gsl_matrix_ushort_min_index (const gsl_matrix_ushort * m, size_t * imin, size_t *jmin);
void gsl_matrix_ushort_minmax_index (const gsl_matrix_ushort * m, size_t * imin, size_t * jmin, size_t * imax, size_t * jmax);

int gsl_matrix_ushort_isnull (const gsl_matrix_ushort * m);

int gsl_matrix_ushort_add (gsl_matrix_ushort * a, const gsl_matrix_ushort * b);
int gsl_matrix_ushort_sub (gsl_matrix_ushort * a, const gsl_matrix_ushort * b);
int gsl_matrix_ushort_mul_elements (gsl_matrix_ushort * a, const gsl_matrix_ushort * b);
int gsl_matrix_ushort_div_elements (gsl_matrix_ushort * a, const gsl_matrix_ushort * b);
int gsl_matrix_ushort_scale (gsl_matrix_ushort * a, const double x);
int gsl_matrix_ushort_add_constant (gsl_matrix_ushort * a, const double x);

/***********************************************************************/
/* The functions below are obsolete                                    */
/***********************************************************************/
int gsl_matrix_ushort_get_row(gsl_vector_ushort * v, const gsl_matrix_ushort * m, const size_t i);
int gsl_matrix_ushort_get_col(gsl_vector_ushort * v, const gsl_matrix_ushort * m, const size_t j);
int gsl_matrix_ushort_set_row(gsl_matrix_ushort * m, const size_t i, const gsl_vector_ushort * v);
int gsl_matrix_ushort_set_col(gsl_matrix_ushort * m, const size_t j, const gsl_vector_ushort * v);

extern int gsl_check_range ;

/* inline functions if you are using GCC */

#ifdef HAVE_INLINE
extern inline
unsigned short
gsl_matrix_ushort_get(const gsl_matrix_ushort * m, const size_t i, const size_t j)
{
#ifndef GSL_RANGE_CHECK_OFF
  if (i >= m->size1)
    {
      GSL_ERROR_VAL("first index out of range", GSL_EINVAL, 0) ;
    }
  else if (j >= m->size2)
    {
      GSL_ERROR_VAL("second index out of range", GSL_EINVAL, 0) ;
    }
#endif
  return m->data[i * m->tda + j] ;
}

extern inline
void
gsl_matrix_ushort_set(gsl_matrix_ushort * m, const size_t i, const size_t j, const unsigned short x)
{
#ifndef GSL_RANGE_CHECK_OFF
  if (i >= m->size1)
    {
      GSL_ERROR_VOID("first index out of range", GSL_EINVAL) ;
    }
  else if (j >= m->size2)
    {
      GSL_ERROR_VOID("second index out of range", GSL_EINVAL) ;
    }
#endif
  m->data[i * m->tda + j] = x ;
}

extern inline
unsigned short *
gsl_matrix_ushort_ptr(gsl_matrix_ushort * m, const size_t i, const size_t j)
{
#ifndef GSL_RANGE_CHECK_OFF
  if (i >= m->size1)
    {
      GSL_ERROR_NULL("first index out of range", GSL_EINVAL) ;
    }
  else if (j >= m->size2)
    {
      GSL_ERROR_NULL("second index out of range", GSL_EINVAL) ;
    }
#endif
  return (unsigned short *) (m->data + (i * m->tda + j)) ;
}

extern inline
const unsigned short *
gsl_matrix_ushort_const_ptr(const gsl_matrix_ushort * m, const size_t i, const size_t j)
{
#ifndef GSL_RANGE_CHECK_OFF
  if (i >= m->size1)
    {
      GSL_ERROR_NULL("first index out of range", GSL_EINVAL) ;
    }
  else if (j >= m->size2)
    {
      GSL_ERROR_NULL("second index out of range", GSL_EINVAL) ;
    }
#endif
  return (const unsigned short *) (m->data + (i * m->tda + j)) ;
}

#endif

__END_DECLS

#endif /* __GSL_MATRIX_USHORT_H__ */


#pragma once

#include <functional>
#include <gsl/gsl_util>
#include <vector>

struct Executor;
namespace detail {
Executor*& get_current_executor_holder();
}

struct Executor {
  using WorkQueue = std::vector<std::function<void()>>;

  void add_work(std::function<void()> fn) {
    work_.emplace_back(std::move(fn));
  }

  void execute() {
    const auto cleanup                    = gsl::finally([&] { //
      detail::get_current_executor_holder() = nullptr;
    });
    detail::get_current_executor_holder() = this;

    while (not work_.empty()) {
      auto pending_work = WorkQueue{};
      swap(pending_work, work_);
      for (auto&& fn : pending_work) {
        fn();
      }
    }
  }

  WorkQueue work_;
};

inline Executor& get_current_executor() {
  return *detail::get_current_executor_holder();
}


#pragma once

#define QT_IS_BROKEN
#define QAPPLICATION_CLASS QApplication // for SingleApplication

// Windows
#include <Windows.h>
#include <SetupAPI.h>

#include <winioctl.h>
#include <BluetoothAPIs.h>
#include <Bthioctl.h>

#include <Dbt.h>
#include <Hidsdi.h>
#include <shellapi.h>
#include <Xinput.h>

// STL
#include <array>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <deque>
#include <functional>
#include <iomanip>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <sstream>
#include <string>
#include <thread>
#include <unordered_map>

// Qt
#include <QDialog>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtWidgets>

#include <singleapplication.h>

// GSL
#include <gsl/span>

// better-enums
#include <enum.h>

// fmt
#include <fmt/format.h>

// libhid
#include <hid_handle.h>
#include <hid_instance.h>
#include <hid_util.h>

// ViGEm
#include <ViGEm/Client.h>
#include <ViGEm/Common.h>
#include <ViGEm/km/BusShared.h>

#include "MapCache.h"
#include "average.h"
#include "AxisOptions.h"
#include "Bluetooth.h"
#include "busenum.h"
#include "ConnectionType.h"
#include "DeviceIdleOptions.h"
#include "DeviceProfile.h"
#include "DeviceProfileCache.h"
#include "DevicePropertiesDialog.h"
#include "DeviceSettings.h"
#include "DeviceSettingsCommon.h"
#include "Ds4AutoLightColor.h"
#include "Ds4Color.h"
#include "Ds4Device.h"
#include "Ds4DeviceManager.h"
#include "Ds4Input.h"
#include "Ds4InputData.h"
#include "Ds4ItemModel.h"
#include "Ds4LightOptions.h"
#include "Ds4Output.h"
#include "Ds4TouchRegion.h"
#include "enums.h"
#include "Event.h"
#include "gmath.h"
#include "InputMap.h"
#include "InputSimulator.h"
#include "JsonData.h"
#include "KeyboardSimulator.h"
#include "Latency.h"
#include "lock.h"
#include "Logger.h"
#include "MainWindow.h"
#include "MouseSimulator.h"
#include "pathutil.h"
#include "Pressable.h"
#include "ProfileEditorDialog.h"
#include "program.h"
#include "Settings.h"
#include "Stopwatch.h"
#include "stringutil.h"
#include "Trackball.h"
#include "Vector2.h"
#include "Vector3.h"
#include "XInputGamepad.h"


#ifndef VEC_WRAPPER_H
#define VEC_WRAPPER_H

#include <atomic>

#include <gsl/gsl_vector.h>

class Vector {
public:
    Vector(); // null

    Vector(gsl_vector *wrap);
    Vector(const size_t length);
    Vector(const Vector& copy);
    virtual ~Vector();

    gsl_vector *get() const;
    void set(gsl_vector *newVector);
    void reset(gsl_vector *newVector);

    void reset(const size_t length);

    explicit operator bool() const;

    Vector &operator =(const Vector& copy);
    void operator *=(const Vector& other);
    double operator [](const size_t i) const;
    double& operator [](const size_t i);

    void coords();
    void uncoords();
    void basis(size_t i);

private:
    gsl_vector *m_vec;

    std::atomic<unsigned int> m_delCount;
};

#endif // VEC_WRAPPER_H


#pragma once

#include <cassert>
#include <exception>
#include <functional>
#include <set>
#include <map>

#include <nod/nod.hpp>

#include <gsl-lite/gsl-lite.hpp>

#include "mutils/time/profiler.h"

#include "threadpool/threadpool.h"

#include "nodegraph/model/node.h"
#include "nodegraph/model/pin.h"

namespace NodeGraph
{

// A collection of nodes that can be computed
class Graph
{
public:
    Graph();
    virtual ~Graph();
    virtual void Clear();

    // Use this method to create nodes and add them to the m_graph
    template <typename T, typename... Args>
    T* CreateNode(Args&&... args)
    {
        PreModify();

        auto pNode = new T(*this, std::forward<Args>(args)...);
        nodes.insert(pNode);
        m_displayNodes.insert(pNode);
        m_mapIdToNode[pNode->GetId()] = pNode;

        PostModify();
        return pNode;
    }

    void DestroyNode(Node* pNode);

    bool IsType(Node& node, ctti::type_id_t type) const;

    template <class T>
    std::set<T*> Find(ctti::type_id_t type) const
    {
        std::set<T*> found;
        for (auto& pNode : nodes)
        {
            if (IsType(*pNode, type))
            {
                found.insert(static_cast<T*>(pNode));
            }
        }
        return found;
    }

    template <class T>
    std::set<T*> Find(const std::vector<ctti::type_id_t>& nodeTypes) const
    {
        std::set<T*> found;
        for (auto& t : nodeTypes)
        {
            auto f = Find<T>(t);
            found.insert(f.begin(), f.end());
        }
        return found;
    }

    void Visit(Node& node, PinDir dir, ParameterType type, std::function<bool(Node&)> fn);

    // Get the list of pins that could be on the UI
    virtual std::vector<Pin*> GetControlSurface() const;

    virtual void Compute(const std::set<Node*>& nodes, int64_t numTicks);

    const std::set<Node*>& GetNodes() const
    {
        return nodes;
    }

    const std::set<Node*>& GetDisplayNodes() const
    {
        return m_displayNodes;
    }
    void SetDisplayNodes(const std::set<Node*>& nodes)
    {
        m_displayNodes = nodes;
    }

    const std::set<Node*>& GetOutputNodes() const
    {
        return m_outputNodes;
    }
    void SetOutputNodes(const std::set<Node*>& nodes)
    {
        m_outputNodes = nodes;
    }

    void PreModify()
    {
        if (m_modifyTracker == 0)
        {
            sigBeginModify(this);
        }

        m_modifyTracker++;
    }

    void PostModify()
    {
        assert(m_modifyTracker > 0);
        m_modifyTracker--;
        if (m_modifyTracker == 0)
        {
            sigEndModify(this);
        }
    }

    void SetName(const std::string& name);
    std::string Name() const;

    // Called to notify that this graph is about to be destroyed
    void NotifyDestroy(Graph* pGraph);

    const std::map<uint64_t, Node*>& GetNodesById() const
    {
        return m_mapIdToNode;
    }

    // Signals
    nod::signal<void(Graph*)> sigBeginModify;
    nod::signal<void(Graph*)> sigEndModify;
    nod::signal<void(Graph*)> sigDestroy;

protected:
    uint32_t m_modifyTracker = 0;

    std::map<uint64_t, Node*> m_mapIdToNode;

    std::set<Node*> nodes;
    std::set<Node*> m_displayNodes;
    std::set<Node*> m_outputNodes;

    uint64_t currentGeneration = 1;
    std::string m_strName;
}; // Graph

} // namespace NodeGraph


#pragma once
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cfloat>

#include <algorithm>
#include <vector>
#include <memory>
#include <stdexcept>
#include <map>

#include <hip/hip_runtime.h>
#include <hiprand_kernel.h>
#include <gsl/gsl_assert.h>
#include <nonstd/byte.hpp>
#include <nonstd/expected.hpp>
#include <nonstd/optional.hpp>
#include <nonstd/span.hpp>
#include <nonstd/ring_span.hpp>
#include <nonstd/string_view.hpp>
#include <nonstd/variant.hpp>
#include <nonstd/value_ptr.hpp>

#include "kernel_config.h"
#include "logger.h"
#include "math.h"

using nonstd::variant;
using nonstd::value_ptr;
using nonstd::make_value;
using nonstd::ring_span;
using nonstd::expected;
using nonstd::make_unexpected;
using nonstd::optional;
using nonstd::nullopt;
using nonstd::make_optional;
using nonstd::byte;
using nonstd::to_integer;
using nonstd::to_byte;
using nonstd::to_string;
using nonstd::string_view;
using nonstd::span;
using nonstd::make_span;
using bytearray = std::vector<byte>;

#define HIP_ASSERT(x) (Ensures((x)==hipSuccess))

struct hip_free_deleter {
    void operator()(void *p) const noexcept { hipFree(p); }
};

template<typename T>
using host_unique_ptr = std::unique_ptr<T, hip_free_deleter>;

template<class T> struct _host_unique_if {
    typedef void _single_object;
};

template<class T> struct _host_unique_if<T[]> {
    typedef host_unique_ptr<T[]> _unknown_bound;
};

template<class T, std::size_t N> struct _host_unique_if<T[N]> {
    typedef void _known_bound;
};

template<class T, class... Args>
typename _host_unique_if<T>::_single_object
hip_alloc_managed_unique(Args&&... args) = delete;

template<class T>
typename _host_unique_if<T>::_unknown_bound
hip_alloc_managed_unique(std::size_t n) {
    typedef typename std::remove_extent<T>::type U;
    T *tmp;
    HIP_ASSERT(hipMallocManaged(&tmp, n * sizeof(U)));
    return host_unique_ptr<T>(reinterpret_cast<U*>(tmp));
}

template<class T, class... Args>
typename _host_unique_if<T>::_known_bound
hip_alloc_managed_unique(Args&&...) = delete;


// Copyright 2021 atframework
// Created by owent on 2020-08-18

#pragma once

#include <gsl/select-gsl.h>

#include <config/atframe_utils_build_feature.h>
#include <config/compiler_features.h>

#include <design_pattern/nomovable.h>
#include <design_pattern/noncopyable.h>

#include <random/random_generator.h>

#include "atframe/atapp_conf.h"

namespace atapp {
struct LIBATAPP_MACRO_API_HEAD_ONLY etcd_discovery_action_t {
  enum type {
    EN_NAT_UNKNOWN = 0,
    EN_NAT_PUT,
    EN_NAT_DELETE,
  };
};

class etcd_discovery_node {
 public:
  using on_destroy_fn_t = std::function<void(etcd_discovery_node &)>;
  using ptr_t = std::shared_ptr<etcd_discovery_node>;

  UTIL_DESIGN_PATTERN_NOCOPYABLE(etcd_discovery_node)
  UTIL_DESIGN_PATTERN_NOMOVABLE(etcd_discovery_node)

 public:
  LIBATAPP_MACRO_API etcd_discovery_node();
  LIBATAPP_MACRO_API ~etcd_discovery_node();

  UTIL_FORCEINLINE const atapp::protocol::atapp_discovery &get_discovery_info() const { return node_info_; }
  LIBATAPP_MACRO_API void copy_from(const atapp::protocol::atapp_discovery &input);

  UTIL_FORCEINLINE const std::pair<uint64_t, uint64_t> &get_name_hash() const { return name_hash_; }

  UTIL_FORCEINLINE void set_private_data_ptr(void *input) { private_data_ptr_ = input; }
  UTIL_FORCEINLINE void *get_private_data_ptr() const { return private_data_ptr_; }
  UTIL_FORCEINLINE void set_private_data_u64(uint64_t input) { private_data_u64_ = input; }
  UTIL_FORCEINLINE uint64_t get_private_data_u64() const { return private_data_u64_; }
  UTIL_FORCEINLINE void set_private_data_i64(int64_t input) { private_data_i64_ = input; }
  UTIL_FORCEINLINE int64_t get_private_data_i64() const { return private_data_i64_; }
  UTIL_FORCEINLINE void set_private_data_uptr(uintptr_t input) { private_data_uptr_ = input; }
  UTIL_FORCEINLINE uintptr_t get_private_data_uptr() const { return private_data_uptr_; }
  UTIL_FORCEINLINE void set_private_data_iptr(intptr_t input) { private_data_iptr_ = input; }
  UTIL_FORCEINLINE intptr_t get_private_data_iptr() const { return private_data_iptr_; }

  LIBATAPP_MACRO_API void set_on_destroy(on_destroy_fn_t fn);
  LIBATAPP_MACRO_API const on_destroy_fn_t &get_on_destroy() const;
  LIBATAPP_MACRO_API void reset_on_destroy();

  LIBATAPP_MACRO_API const atapp::protocol::atapp_gateway &next_ingress_gateway() const;
  LIBATAPP_MACRO_API int32_t get_ingress_size() const;

 private:
  atapp::protocol::atapp_discovery node_info_;
  std::pair<uint64_t, uint64_t> name_hash_;
  union {
    void *private_data_ptr_;
    uint64_t private_data_u64_;
    int64_t private_data_i64_;
    uintptr_t private_data_uptr_;
    intptr_t private_data_iptr_;
  };
  on_destroy_fn_t on_destroy_fn_;
  mutable int32_t ingress_index_;
  mutable atapp::protocol::atapp_gateway ingress_for_listen_;
};

class etcd_discovery_set {
 public:
  using node_by_name_t = std::unordered_map<std::string, etcd_discovery_node::ptr_t>;
  using node_by_id_t = std::unordered_map<uint64_t, etcd_discovery_node::ptr_t>;
  using ptr_t = std::shared_ptr<etcd_discovery_set>;

  struct node_hash_t {
    enum { HASH_POINT_PER_INS = 80 };

    etcd_discovery_node::ptr_t node;
    std::pair<uint64_t, uint64_t> hash_code;
  };

  UTIL_DESIGN_PATTERN_NOCOPYABLE(etcd_discovery_set)
  UTIL_DESIGN_PATTERN_NOMOVABLE(etcd_discovery_set)
 public:
  LIBATAPP_MACRO_API etcd_discovery_set();
  LIBATAPP_MACRO_API ~etcd_discovery_set();

  LIBATAPP_MACRO_API bool empty() const;

  LIBATAPP_MACRO_API etcd_discovery_node::ptr_t get_node_by_id(uint64_t id) const;
  LIBATAPP_MACRO_API etcd_discovery_node::ptr_t get_node_by_name(gsl::string_view name) const;

  LIBATAPP_MACRO_API etcd_discovery_node::ptr_t get_node_by_consistent_hash(const void *buf, size_t bufsz) const;
  LIBATAPP_MACRO_API etcd_discovery_node::ptr_t get_node_by_consistent_hash(uint64_t key) const;
  LIBATAPP_MACRO_API etcd_discovery_node::ptr_t get_node_by_consistent_hash(int64_t key) const;
  LIBATAPP_MACRO_API etcd_discovery_node::ptr_t get_node_by_consistent_hash(gsl::string_view key) const;

  LIBATAPP_MACRO_API etcd_discovery_node::ptr_t get_node_by_random() const;
  LIBATAPP_MACRO_API etcd_discovery_node::ptr_t get_node_by_round_robin() const;

  LIBATAPP_MACRO_API const std::vector<etcd_discovery_node::ptr_t> &get_sorted_nodes() const;
  LIBATAPP_MACRO_API std::vector<etcd_discovery_node::ptr_t>::const_iterator lower_bound_sorted_nodes(
      uint64_t id, gsl::string_view name) const;
  LIBATAPP_MACRO_API std::vector<etcd_discovery_node::ptr_t>::const_iterator upper_bound_sorted_nodes(
      uint64_t id, gsl::string_view name) const;

  LIBATAPP_MACRO_API void add_node(const etcd_discovery_node::ptr_t &node);
  LIBATAPP_MACRO_API void remove_node(const etcd_discovery_node::ptr_t &node);
  LIBATAPP_MACRO_API void remove_node(uint64_t id);
  LIBATAPP_MACRO_API void remove_node(gsl::string_view name);

 private:
  void rebuild_cache() const;
  void clear_cache() const;

 private:
  node_by_name_t node_by_name_;
  node_by_id_t node_by_id_;

  mutable std::vector<node_hash_t> hashing_cache_;
  mutable std::vector<etcd_discovery_node::ptr_t> round_robin_cache_;
  mutable util::random::xoshiro256_starstar random_generator_;
  mutable size_t round_robin_index_;
};
}  // namespace atapp


// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once
#include <iosfwd>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <gsl/gsl>
#include "onnxruntime_config.h"

namespace onnxruntime {
#ifdef __GNUC__
#pragma GCC diagnostic push
#ifdef HAS_NULL_DEREFERENCE
#pragma GCC diagnostic ignored "-Wnull-dereference"
#endif
#endif
class TensorShape {
  // We use negative numbers for unknown symbolic dimension. Each negative
  // number represents a unique symbolic dimension.
 public:
  TensorShape() = default;

  TensorShape(const TensorShape& other) : TensorShape(other.GetDims()) {}
  TensorShape& operator=(const TensorShape& other);

  TensorShape(TensorShape&& other) { operator=(std::move(other)); }
  TensorShape& operator=(TensorShape&& other);

  TensorShape(gsl::span<const int64_t> dims);
  TensorShape(const std::vector<int64_t>& dims) : TensorShape(gsl::make_span(dims)) {}
  TensorShape(const std::initializer_list<int64_t>& dims) : TensorShape(gsl::make_span(dims)) {}
  TensorShape(const int64_t* dimension_sizes, size_t dimension_count) : TensorShape(gsl::span<const int64_t>(dimension_sizes, dimension_count)) {}
  TensorShape(const std::vector<int64_t>& dims, size_t start, size_t end) : TensorShape(gsl::span<const int64_t>(&dims[start], end - start)) {}

  // Create a TensorShape that points to an existing buffer internally. As no copy is made, 'data' must remain valid for the life of the TensorShape
  static const TensorShape FromExistingBuffer(const std::vector<int64_t>& data) {
    return TensorShape(External{}, gsl::span<int64_t>(const_cast<int64_t*>(data.data()), data.size()));
  }

  /**
     Return the dimension specified by <idx>.
  */
  int64_t operator[](size_t idx) const { return values_[idx]; }
  int64_t& operator[](size_t idx) { return values_[idx]; }

  bool operator==(const TensorShape& other) const noexcept { return GetDims() == other.GetDims(); }
  bool operator!=(const TensorShape& other) const noexcept { return GetDims() != other.GetDims(); }

  size_t NumDimensions() const noexcept {
    return values_.size();
  }

  /**
     Copy dims into an array with given size
  */
  void CopyDims(int64_t* dims, size_t num_dims) const {
    memcpy(dims, values_.begin(), sizeof(int64_t) * std::min(num_dims, NumDimensions()));
  }

  /**
     Copy dims from a specific start dim into an array with given size
     `start_dim` is expected to be in the inclusive range [0, NumDimensions() - 1]
     and this function does no checks to ensure that
  */
  void CopyDims(int64_t* dims, size_t start_dim, size_t num_dims) const {
    memcpy(dims, values_.begin() + start_dim, sizeof(int64_t) * std::min(num_dims, NumDimensions() - start_dim));
  }

  /**
     Return underlying vector representation.
  */
  gsl::span<const int64_t> GetDims() const { return values_; }
  std::vector<int64_t> GetDimsAsVector() const { return std::vector<int64_t>(values_.begin(), values_.end()); }

  /**
   * Return the total number of elements. Returns 1 for an empty (rank 0) TensorShape.
   *
   * May return -1
   */
  int64_t Size() const;

  /**
     Return the total number of elements up to the specified dimension.
     If the dimension interval is empty (dimension == 0), return 1.
     @param dimension Return size up to this dimension. Value must be between 0 and this->NumDimensions(), inclusive.
  */
  int64_t SizeToDimension(size_t dimension) const;

  /**
     Return the total number of elements from the specified dimension to the end of the tensor shape.
     If the dimension interval is empty (dimension == this->NumDimensions()), return 1.
     @param dimension Return size from this dimension to the end. Value must be between 0 and this->NumDimensions(),
                      inclusive.
  */
  int64_t SizeFromDimension(size_t dimension) const;

  /**
     Return a new TensorShape of the dimensions from dimstart to dimend.
  */
  TensorShape Slice(size_t dimstart, size_t dimend) const;

  /**
     Return a new TensorShape of the dimensions from dimstart to end.
  */
  TensorShape Slice(size_t dimstart) const { return Slice(dimstart, values_.size()); }

  /**
     output dimensions nicely formatted
  */
  std::string ToString() const;

  /**
     Calculate size between start and end.
     Assumes start and end are between 0 and this->NumDimensions(), inclusive, and that
     start < end.
  */
  int64_t SizeHelper(size_t start, size_t end) const;

  /**
     empty shape or 1D shape (1) is regarded as scalar tensor
  */
  bool IsScalar() const {
    size_t len = values_.size();
    return len == 0 || (len == 1 && values_[0] == 1);
  }

 private:

  struct External {};
  TensorShape(External, gsl::span<int64_t> buffer) : values_{buffer} {}

  void Allocate(size_t size);

  gsl::span<int64_t> values_;
  int64_t small_buffer_[5];
  std::unique_ptr<int64_t[]> allocated_buffer_;

  friend struct ProviderHostImpl; // So that the shared provider interface can access Allocate
};
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
// operator<< to nicely output to a stream
std::ostream& operator<<(std::ostream& out, const TensorShape& shape);

}  // namespace onnxruntime


// This file is part of playd.
// playd is licensed under the MIT licence: see LICENSE.txt.

/**
 * @file
 * Declaration of the Basic_audio, Null_audio and Audio classes.
 * @see audio/audio.cpp
 */

#ifndef PLAYD_AUDIO_H
#define PLAYD_AUDIO_H

#include <chrono>
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#undef max
#include <gsl/gsl>

#include "../response.h"
#include "sink.h"
#include "source.h"

namespace Playd::Audio
{
/**
 * An audio item.
 *
 * Audio abstractly represents an audio item that can be played, stopped,
 * and queried for its position and path (or equivalent).
 *
 * Audio is a virtual interface implemented concretely by PipeAudio, and
 * also by mock implementations for testing purposes.
 *
 * @see PipeAudio
 */
class Audio
{
public:
	/// Enumeration of possible states for Audio.
	using State = Sink::State;

	/// Virtual, empty destructor for Audio.
	virtual ~Audio() = default;

	//
	// Control interface
	//

	/**
	 * Performs an update cycle on this Audio.
	 *
	 * Depending on the Audio implementation, this may do actions such as
	 * performing a decoding round, checking for end-of-file, transferring
	 * frames, and so on.
	 *
	 * @return The state of the Audio after updating.
	 * @see State
	 */
	virtual State Update() = 0;

	/**
	 * Sets whether this Audio should be playing or not.
	 * @param playing True for playing; false for stopped.
	 * @exception NoAudioError if the current state is NONE.
	 */
	virtual void SetPlaying(bool playing) = 0;

	/**
	 * Attempts to seek to the given position.
	 * @param position The position to seek to, in microseconds.
	 * @exception NoAudioError if the current state is NONE.
	 * @see Position
	 */
	virtual void SetPosition(std::chrono::microseconds position) = 0;

	//
	// Property access
	//

	/**
	 * This Audio's current file.
	 * @return The filename of this current file.
	 * @exception NoAudioError if the current state is NONE.
	 */
	virtual std::string_view File() const = 0;

	/**
	 * The state of this Audio.
	 * @return this Audio's current state.
	 */
	virtual State CurrentState() const = 0;

	/**
	 * This Audio's current position.
	 *
	 * As this may be executing whilst the playing callback is running,
	 * do not expect it to be highly accurate.
	 *
	 * @return The current position, in microseconds.
	 * @exception NoAudioError if the current state is NONE.
	 * @see Seek
	 */
	virtual std::chrono::microseconds Position() const = 0;

	/**
	 * This Audio's length.
	 *
	 * @return The length, in microseconds.
	 * @exception NoAudioError if the current state is NONE.
	 * @see Seek
	 */
	virtual std::chrono::microseconds Length() const = 0;
};

/**
 * A dummy Audio implementation representing a lack of file.
 *
 * NoAudio throws exceptions if any attempt is made to change, start, or stop
 * the audio, and returns Audio::State::NONE during any attempt to Update.
 * If asked to emit the audio file, NoAudio does nothing.
 *
 * @see Audio
 */
class NullAudio : public Audio
{
public:
	Audio::State Update() override;

	Audio::State CurrentState() const override;

	// The following all raise an exception:

	void SetPlaying(bool playing) override;

	void SetPosition(std::chrono::microseconds position) override;

	std::chrono::microseconds Position() const override;

	std::chrono::microseconds Length() const override;

	std::string_view File() const override;
};

/**
 * A concrete implementation of Audio as a 'pipe'.
 *
 * Basic_audio is comprised of a 'source', which decodes frames from a
 * file, and a 'sink', which plays out the decoded frames.  Updating
 * consists of shifting frames from the source to the sink.
 *
 * @see Audio
 * @see Sink
 * @see Source
 */
class BasicAudio : public Audio
{
public:
	/**
	 * Constructs audio from a source and a sink.
	 * @param src The source of decoded audio frames.
	 * @param sink The target of decoded audio frames.
	 * @see AudioSystem::Load
	 */
	BasicAudio(std::unique_ptr<Source> src, std::unique_ptr<Sink> sink);

	Audio::State Update() override;

	std::string_view File() const override;

	void SetPlaying(bool playing) override;

	Audio::State CurrentState() const override;

	void SetPosition(std::chrono::microseconds position) override;

	std::chrono::microseconds Position() const override;

	std::chrono::microseconds Length() const override;

private:
	/// The source of audio data.
	std::unique_ptr<Source> src;

	/// The sink to which audio data is sent.
	std::unique_ptr<Sink> sink;

	/// The current decoded frame.
	Source::DecodeVector frame;

	/// A span representing the unclaimed part of the decoded frame.
	gsl::span<const std::byte> frame_span;

	/// Clears the current frame and its iterator.
	void ClearFrame();

	/**
	 * Decodes a new frame, if the current frame is empty.
	 * @return True if more frames are available to decode; false
	 *   otherwise.
	 */
	bool DecodeIfFrameEmpty();

	/**
	 * Returns whether the current frame has been finished.
	 * If this is true, then either the frame is empty, or all of the
	 * samples in the frame have been fed to the ringbuffer.
	 * @return True if the frame is finished; false otherwise.
	 */
	bool FrameFinished() const;

	/// Transfers as much of the current frame as possible to the sink.
	void TransferFrame();
};

} // namespace Playd::Audio

#endif // PLAYD_AUDIO_H


#ifndef TTT_UTIL_TEXTURECACHE_H
#define TTT_UTIL_TEXTURECACHE_H

#include <SDL_render.h>

#include <gsl/pointers>
#include <gsl/util>

#include <vector>
#include <memory>
#include <string_view>

namespace ttt::gfx
{
	// A class for caching textures for reuse.
	class TextureCache final
	{
	public:
		using SizeType = gsl::index;

		SDL_Texture *load(std::string_view path, gsl::not_null<SDL_Renderer *> renderer);
		void unload(SizeType index) noexcept;
		void erase(SizeType index) noexcept;
		void clear() noexcept;

		[[nodiscard]] SDL_Texture *at(SizeType index) const noexcept;
		[[nodiscard]] SDL_Texture *operator [](SizeType index) const noexcept;

		[[nodiscard]] SizeType getSize() const noexcept;
		[[nodiscard]] SizeType getMaxSize() const noexcept;

	private:
		std::vector<std::unique_ptr<SDL_Texture, decltype(&SDL_DestroyTexture)>> textures;
	};

	inline void TextureCache::unload(SizeType index) noexcept { gsl::at(textures, index).reset(); }
	inline void TextureCache::erase(SizeType index) noexcept { textures.erase(textures.cbegin() + index); }
	inline void TextureCache::clear() noexcept { textures.clear(); }

	inline SDL_Texture *TextureCache::at(SizeType index) const noexcept { return gsl::at(textures, index).get(); }
	inline SDL_Texture *TextureCache::operator [](SizeType index) const noexcept { return gsl::at(textures, index).get(); }

	inline TextureCache::SizeType TextureCache::getSize() const noexcept { return textures.size(); }
	inline TextureCache::SizeType TextureCache::getMaxSize() const noexcept { return textures.max_size(); }
}

#endif


#define PyGSL_NUMERIC
#define PyGSL_NUMARRAY
#include "numeric_numarray.h"
#include <gsl/gsl_errno.h>
#include <pygsl/general_helpers.h>

static int
cp_numeric_ptrs(void)
{
     return GSL_SUCCESS;
}

static int
cp_numarray_ptrs(void)
{
     return GSL_SUCCESS;
}

void
initnumx(void)
{
     init_pygsl();
     cp_numeric_ptrs();
     cp_numarray_ptrs();
}