/******************************************************************************
*                                                             \  ___  /       *
*                                                               /   \         *
* Edison Design Group C++ Header Files                       - | \^/ | -      *
*                                                               \   /         *
*                                                             /  | |  \       *
* Copyright 2022-2024 Edison Design Group Inc.                   [_]          *
*                                                                             *
******************************************************************************/
/*
Redistribution and use in source and binary forms are permitted
provided that the above copyright notice and this paragraph are
duplicated in all source code forms.  The name of Edison Design
Group, Inc. may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
Any use of this software is at the user's own risk.
*/
/*
meta -- Include file for std::meta facilities

This is an experimental header approximating support for facilities as
described in the C++ committee's paper P2996.
*/
#ifndef __META_STDH
#define __META_STDH

#include <initializer_list>
#include <new>
#include <optional>
#include <string_view>
#include <vector>

namespace std {

  constexpr void __report_constexpr_value(long long) {
    /* Handled by interpreter. */
  }

  constexpr void __report_constexpr_value(char const*) {
    /* Handled by interpreter. */
  }

  namespace meta {
    using info = decltype(^::);

    struct __infovec {
      consteval __infovec(long __cap)
        : __infos(new info[__cap]), __cap(__cap), __n(0) {}
      consteval __infovec(__infovec const &__src)
        : __infos(new info[__src.__n]), __cap(__src.__n), __n(__src.__n)
        {
          for (long __k = 0; __k<__src.__n; ++__k) {
            std::construct_at(&this->__infos[__k], __src.__infos[__k]);
          }
        }
      consteval __infovec(__infovec &&__src)
        : __infos(__src.__infos), __cap(__src.__cap), __n(__src.__n)
        { __src.__infos = nullptr; __src.__cap = 0; __src.__n = 0; }
      consteval __infovec(initializer_list<info>  __ili)
        : __infos(new info[__ili.size()]),
          __cap(__ili.size()), __n(__ili.size())
        {
          info  *__pi = this->__infos;
          for (info __i: __ili) *__pi++ = __i;
        }
      consteval __infovec(std::vector<info> const &__src)
        : __infos(new info[__src.size()]),
          __cap(__src.size()), __n(__src.size())
        {
          info  *__pi = this->__infos;
          for (info __i: __src) *__pi++ = __i;
        }
      constexpr ~__infovec() { delete[] this->__infos; }
      consteval info const& operator[](long __i) const
        { return this->__infos[__i]; }
      consteval info& operator[](long __i) { return this->__infos[__i]; }
      consteval decltype(sizeof(0)) size() const { return this->__n; }
      consteval long ssize() const { return this->__n; }
      consteval info const* begin() const { return this->__infos; }
      consteval info* begin() { return this->__infos; }
      consteval info const* end() const { return this->__infos+this->__n; }
      consteval info* end() { return this->__infos+this->__n; }
      consteval void push_back(info __i)
        {
          if (this->__n == this->__cap) __grow();
          std::construct_at(&this->__infos[this->__n++], __i);
        }
    private:
      info *__infos;
      long __cap, __n;
      consteval void __grow()
        {
          long __new_cap = this->__cap;
          __new_cap = __new_cap<2 ? 2 : __new_cap+__new_cap/2+1;
          info *__new_infos = new info[__new_cap];
          for (int __k = 0; __k<this->__n; ++__k) {
            std::construct_at(&__new_infos[__k], this->__infos[__k]);
          }
          delete[] this->__infos;
          this->__infos = __new_infos;
          this->__cap = __new_cap;
        }
    };


    using  __refl_ptrdiff = decltype((int*)2-(int*)1);

    template<typename __T>
    consteval info make_constexpr_array(__T*, __refl_ptrdiff) {
      return ^::;  /* Dummy return.  Handled by interpreter. */
    }

    using __str = std::string_view;

    consteval __str name_of(info) {
      return __str("", 0);  /* Dummy return.  Handled by interpreter. */
    }

    consteval __infovec members__impl(info) {
      return __infovec(0);  /* Dummy return.  Handled by interpreter. */
    }

    template<typename ... Filters>
    consteval std::vector<info> members_of(info r, Filters ... filters) {
      __infovec v = members__impl(r);
      std::vector<info> result{};
      for (info m: v) {
        if ((filters(m) && ...)) result.push_back(m);
      }
      return result;
    }

    consteval __infovec static_data_members__impl(info) {
      return __infovec(0);  /* Dummy return.  Handled by interpreter. */
    }

    consteval std::vector<info> static_data_members_of(info r) {
      __infovec v = static_data_members__impl(r);
      return std::vector<info>(v.begin(), v.end());
    }

    consteval __infovec nonstatic_data_members__impl(info) {
      return __infovec(0);  /* Dummy return.  Handled by interpreter. */
    }

    consteval std::vector<info> nonstatic_data_members_of(info r) {
      __infovec v = nonstatic_data_members__impl(r);
      return std::vector<info>(v.begin(), v.end());
    }

    consteval __infovec bases__impl(info) {
      return __infovec(0);  /* Dummy return.  Handled by interpreter. */
    }

    consteval std::vector<info> bases_of(info r) {
      __infovec v = bases__impl(r);
      return std::vector<info>(v.begin(), v.end());
    }

    consteval __infovec subobjects__impl(info) {
      return __infovec(0);  /* Dummy return.  Handled by interpreter. */
    }

    consteval std::vector<info> subobjects_of(info r) {
      __infovec v = subobjects__impl(r);
      return std::vector<info>(v.begin(), v.end());
    }

    consteval __infovec enumerators__impl(info) {
      return __infovec(0);  /* Dummy return.  Handled by interpreter. */
    }

    consteval std::vector<info> enumerators_of(info r) {
      __infovec v = enumerators__impl(r);
      return std::vector<info>(v.begin(), v.end());
    }

    consteval __infovec parameters__impl(info) {
      return __infovec(0);  /* Dummy return.  Handled by interpreter. */
    }

    consteval std::vector<info> parameters_of(info r) {
      __infovec v = parameters__impl(r);
      return std::vector<info>(v.begin(), v.end());
    }

    consteval info substitute__impl(info, __infovec) {
      return ^::;  /* Dummy return.  Handled by interpreter. */
    }

    consteval info substitute(info r, std::vector<info> v) {
      return substitute__impl(r, v);
    }

    template<typename T>
    consteval info reflect_value(T) {
      return ^::;  /* Dummy return.  Handled by interpreter. */
    }

    template<typename T>
    consteval T value_of(info) {
      return T{};  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool test_type(info templ, info type) {
      return value_of<bool>(substitute__impl(templ, {type}));
    }

    consteval bool test_types(info templ, std::vector<info> types) {
      return value_of<bool>(substitute__impl(templ, types));
    }

    consteval bool is_type(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_alias(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_incomplete_type(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_template(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_function_template(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_variable_template(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_class_template(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_alias_template(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_concept(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_constant(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_variable(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_function(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_function_parameter(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_explicit_object_parameter(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_namespace(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_nsdm(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_base(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_constructor(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_destructor(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_special_member(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_public(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_protected(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_private(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_accessible(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_static_member(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_virtual(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_deleted(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_defaulted(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_explicit(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_override(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_pure_virtual(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool is_bit_field(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool has_static_storage_duration(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool has_internal_linkage(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool has_c_varargs(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool has_default_argument(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool has_consistent_name(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval bool has_template_arguments(info) {
      return false;  /* Dummy return.  Handled by interpreter. */
    }

    consteval __infovec template_arguments__impl(info) {
      return __infovec(0);  /* Dummy return.  Handled by interpreter. */
    }

    consteval std::vector<info> template_arguments_of(info r) {
      __infovec v = template_arguments__impl(r);
      return std::vector<info>(v.begin(), v.end());
    }

    consteval info template_of(info) {
      return ^::;  /* Dummy return.  Handled by interpreter. */
    }

    consteval info type_of(info) {
      return ^::;  /* Dummy return.  Handled by interpreter. */
    }

    consteval info return_type_of(info) {
      return ^::;  /* Dummy return.  Handled by interpreter. */
    }

    consteval info parent_of(info) {
      return ^::;  /* Dummy return.  Handled by interpreter. */
    }

    consteval info dealias(info) {
      return ^::;  /* Dummy return.  Handled by interpreter. */
    }

    consteval std::size_t size_of(info entity) {
      return 0;  /* Dummy return.  Handled by interpreter. */
    }

    consteval std::size_t offset_of(info entity) {
      return 0;  /* Dummy return.  Handled by interpreter. */
    }

    consteval std::size_t bit_size_of(info entity) {
      return 0;  /* Dummy return.  Handled by interpreter. */
    }

    consteval std::size_t bit_offset_of(info entity) {
      return 0;  /* Dummy return.  Handled by interpreter. */
    }

    consteval std::size_t alignment_of(info entity) {
      return 0;  /* Dummy return.  Handled by interpreter. */
    }


    struct nsdm_options {
      std::optional<__str> name;
      std::optional<int> alignment;
      std::optional<int> bit_width;
    };

    struct nsdm_description {
      constexpr nsdm_description(info type, nsdm_options options = {})
        : type(type)
        , name(nullptr)
        , alignment(0)
        , bit_width(0) {
        if (options.name.has_value()) {
          auto view = options.name.value();
          auto data = view.data();
          auto size = view.size();
          auto name = new char[size+1];
          int k = 0;
          do {  // This is consteval: Don't worry about bounds checking.
            name[k] = data[k];
          } while (data[k++]);
          this->name = name;
        }
        if (options.alignment.has_value()) {
          this->alignment = options.alignment.value();
        }
        if (options.bit_width.has_value()) {
          this->bit_width = options.bit_width.value();
        }
      }

      constexpr nsdm_description(nsdm_description const &orig)
        : type(orig.type)
        , name(orig.name)
        , alignment(orig.alignment)
        , bit_width(orig.bit_width) {
        if (orig.name) {
          auto n = __builtin_strlen(orig.name)+1;
          this->name = new char[n];
          __builtin_memcpy(this->name, orig.name, n);
        }
      }

      constexpr nsdm_description(nsdm_description &&orig)
        : type(orig.type)
        , name(orig.name)
        , alignment(orig.alignment)
        , bit_width(orig.bit_width) {
        orig.name = nullptr;
      }

      constexpr ~nsdm_description() {
        if (this->name) delete[] this->name;
      }
      void operator==(nsdm_description const&) = delete;
      void operator==(nsdm_description &&) = delete;
    private:
      info type;
      char *name;
      std::size_t alignment;
      std::size_t bit_width;
    };

    consteval auto make_nsdm_description(info type,
                                         nsdm_options options = {}) {
      return nsdm_description(type, options);
    }


    consteval void __define_class(info type,
                                  int  n_fields,
                                  nsdm_description *field_info) {
      /* Handled by interpreter. */
    };

    consteval info define_class(info  type,
                                std::vector<nsdm_description> fields) {
      __define_class(type, fields.size(), fields.data());
      return type;
    }

    consteval info metacall__impl(info, __infovec) {
      return ^::;  /* Dummy return.  Handled by interpreter. */
    }

    consteval info reflect_invoke(info r, std::vector<info> v) {
      return metacall__impl(r, v);
    }

    [[deprecated("metacall has been renamed to reflect_invoke")]]
    consteval info metacall(info r, std::vector<info> v) {
      return metacall__impl(r, v);
    }

    /* Alternatives to P1306 expansion statements.
       Example usage:
          expand_over([] consteval { return nonstatic_data_members_of(^S); },
                      []<std::meta::info r> {
                        printf("%s\n", name_of(r).data());
                      });
       and
          [:expand(nonstatic_data_members_of(^S)):] >>
          []<auto r> {
            printf("%s\n", name_of(r).data());
          };
    */
    namespace __impl {
      template<typename F, auto ... vals>
      constexpr void expander(F f) {
        (f.template operator()<vals>(), ...);
      }

      template<typename F, typename R>
      consteval std::meta::info substitute_expander(R make_range) {
        auto vals = make_range();
        std::meta::__infovec args{ ^F };
        for (auto val : vals) {
          args.push_back(std::meta::reflect_value(val));
        }
        return substitute__impl(^expander, args);
      }
    }  // namespace __impl

    template<typename F, typename R>
    constexpr void expand_over(R make_range, F body = {}) {
      [:__impl::substitute_expander<F>(make_range):](body);
    }

    namespace __impl {
      template<auto ... vals>
      struct replicator_type {
        template<typename F>
          constexpr void operator>>(F body) const {
            (body.template operator()<vals>(), ...);
          }
      };
      template<auto ... vals>
      replicator_type<vals...> replicator = {};
    }  // namespace __impl

    template<typename R>
    consteval auto const expand(R range) {
      std::vector<std::meta::info> args;
      for (auto r: range) args.push_back(reflect_value(r));
      return substitute(^__impl::replicator, args);
    }
  }
}


#endif  /* ifndef __META_STDH */

/******************************************************************************
*                                                             \  ___  /       *
*                                                               /   \         *
* Edison Design Group C++ Header Files                       - | \^/ | -      *
*                                                               \   /         *
*                                                             /  | |  \       *
* Copyright 2022-2024 Edison Design Group Inc.                   [_]          *
*                                                                             *
******************************************************************************/
