/*
 * This file is part of the ProVANT simulator project.
 * Licensed under the terms of the MIT open source license. More details at
 * https://github.com/Guiraffo/ProVANT-Simulator/blob/master/LICENSE.md
 */
/**
 * @file sdf_parser.h
 * @brief This file contains the declaration of the SDFParser class.
 *
 * @author Júnio Eduardo de Morais Aquino
 */

#ifndef PROVANT_SDF_READER_H
#define PROVANT_SDF_READER_H

#include <sdf/sdf.hh>

#include <gsl/gsl>

#include "sdf_status.h"

/**
 * @brief The SDFParser class is a helper class to read properties from a SDF
 * Element object.
 *
 * This class is specially usefull during the loading of Gazebo plugins where
 * is necessary to read parameters from the plugin SDF description.
 *
 * A SDF (Simulation Description Format) Element, is a specialized XML element
 * that may contain attributes and child elements, as any other XML element
 * can.
 *
 * Gazebo provides a SDF Reader, but many times it has a confusing syntax and
 * very lax documentation, which is very hard to understand and discourages the
 * usage of the SDF class to read its own elements.
 *
 * As there were many instances in the ProVANT Simulator source code that
 * users and developers were using the now depreacted XMLRead class to read the
 * values of SDF elements, this class was designed as a substitution for the
 * XMLRead class, that wraps the methods provided by gazebo into well documented
 * and tested methods.
 *
 * So far, this class provides methods to check the existence, and returns the
 * string values of attributes and elements. In the future, it is very likely
 * that this class will also contain methods to read the values of elements in
 * other types, checking for adequate conversion and validity.
 *
 * @todo It turns out that is really hard to create SDF elements in memory
 * in order to do the testing of this class, so by now THIS CLASS IS UNTESTED!
 * It is imperative that we develop tests for this class. The tests are not
 * hard to create, the problem is that it creating SDF descriptions in memory
 * throws a series of undocumented errors and leads the test executable to a
 * segmentation fault, rendering the test procedure unfeasible.
 */
class SDFParser
{
public:
  /**
   * @brief Construct a new SDFParser object and initializes the SDF pointer.
   *
   * @param sdf SDF element to read data from.
   */
  SDFParser(sdf::ElementPtr sdf);
  /**
   * @brief Destroy the SDFParser object.
   * Releases the shared pointer to the SDF element.
   */
  virtual ~SDFParser();

  /**
   * @brief Get the SDF ptr from which this class reads data from.
   * @return sdf::ElementPtr
   */
  virtual sdf::ElementPtr GetElementPtr() const;

  /**
   * @brief Checks if the SDF contain an attribute with the specified name.
   *
   * Attributes are data specific to a element, that are usually strings.
   * For example, the following XML element:
   * @code{.xml}
   * <test type="example">
   *  <other_data/>
   * </test>
   * @endcode
   *
   * Contains an attribute named type and with value example.
   *
   * Usage example:
   * Suppose a plugin SDF description as follows:
   * @code{.xml}
   * <plugin name="example" filename="provant_simulator_step_plugin">
   *  <plugin_data/>
   * </plugin>
   * @endcode
   *
   * Assuming this plugin was read, the following code has res=true, because
   * the plugin contains an attribute "name".
   * @code{.cpp}
   * SDFParser reader(_sdf);
   * bool res = reader.HasAttribute("name");
   * @endcode
   *
   * And the following code results in res=false, because the plugin does not
   * contain an attribute "type".
   * @code{.cpp}
   * SDFParser reader(_sdf);
   * bool res = reader.HasAttribute("type");
   * @endcode
   *
   * @param name
   * @return true If the SDF element contains an attribute with the specified
   * name.
   * @return false Otherwise.
   */
  virtual bool HasAttribute(const std::string& name) const;
  /**
   * @brief Checks if the SDF has an element with the specified name.
   *
   * Usage example:
   * Suppose a plugin SDF description as follows:
   * @code{.xml}
   * <plugin name="example" filename="provant_simulator_step_plugin">
   *  <plugin_data/>
   * </plugin>
   * @endcode
   *
   * Assuming this plugin was read, the following code has res=true, because
   * the plugin contains an element "plugin_data".
   * @code{.cpp}
   * SDFParser reader(_sdf);
   * bool res = reader.HasElement("plugin_data");
   * @endcode
   *
   * And the following code results in res=false, because the plugin does not
   * contain an attribute "type".
   * @code{.cpp}
   * SDFParser reader(_sdf);
   * bool res = reader.HasElement("type");
   * @endcode
   *
   * @param name Name of the element to look for.
   * @return true If the SDF contains an element with the specified name.
   * @return false Otherwise.
   */
  virtual bool HasElement(const std::string& name) const;

  /**
   * @brief Get an attribute value.
   *
   * This checks if an attribute with the specified value exists, and if it
   * exists, copies its value to the value parameter.
   *
   * If the attribute does not exists, or any other occurs, an SDFStatus with an
   * error and a message describing the problem is returned, and the value is
   * left emtpy.
   *
   * @param name Name of the attribute to return.
   * @param value Buffer string that will contain the value of the attribute with the specified name.
   * @return SDFStatus that informs the status of the operation. If the
   * attribute is found and returned, a OkStatus object is returned, in the case
   * the attribute does not exist an AttributeNotFoundError object is returned,
   * containing an error status and a message informing the problem.
   */
  virtual SDFStatus GetAttributeValue(const std::string& name, gsl::not_null<std::string*> value) const noexcept;
  /**
   * @brief Get an attribute value.
   *
   * This method checks if an attribute with the specified name exists, and if
   * it exists, returns its value.
   *
   * @param name Name of the attribute to locate.
   * @return std::string Value of the attribute.
   * @throw AttributeNotFoundError If an attribute with the specifed name does
   * not exist.
   */
  virtual std::string GetAttributeValue(const std::string& name) const;
  /**
   * @brief Get the text value of a SDF element.
   *
   * Check if an element with the specified name exists, and if it exists,
   * copies its value to the value parameter.
   *
   * If an element with the specified name does not exist, or any other
   * error occurs, the value string is left empty, and a SDFStatus error is
   * returned with a message identifying the problem.
   *
   * @param name Name of the element to read the value.
   * @param value Buffer string that will contain the value of the element
   * @return SDFStatus that informs the status of the operation. If at least one
   * element with the specified name exists, a OkStatus object is returned.
   * In case an error occurs, an object identifying the problem is returned
   * with an errors status and a message describing the problem.
   */
  virtual SDFStatus GetElementText(const std::string& name, gsl::not_null<std::string*> value) const noexcept;
  /**
   * @brief Get the text value of a SDF element.
   *
   * Check if an element with the specified name exists, and return is value.
   *
   * @sa GetElementText(const std::string& name, std::string* value)
   *
   * @param name Name of the element to read the value.
   * @return std::string Content of the element.
   * @throw ElementNotFoundError if the element cannot be found as a child of
   * the SDF element this class reads from.
   */
  virtual std::string GetElementText(const std::string& name) const;

  /**
   * @brief Get the value of a boolean SDF element.
   *
   * The valid options are:
   * For true elements: true in any case combination, or 1.
   * For false elements: false in any case combinatation, or 0.
   *
   * @sa GetElementBool(const std::string&)
   *
   * @param name Name of the element to read.
   * @param value Content of the element.
   * @return SDFStatus Status of the parse operation. If the element was found
   * and had a valid value, an OKStatus is returned, otherwise an object
   * containing and error status and error message is returned.
   */
  virtual SDFStatus GetElementBool(const std::string& name, gsl::not_null<bool*> value) const noexcept;
  /**
   * @brief Get the value of a boolean SDF element.
   *
   * The valid options are:
   * For true elements: true in any case combination, or 1.
   * For false elements: false in any case combinatation, or 0.
   *
   * @sa GetElementBool(const std::string&, gsl::not_null<int*>)
   *
   * @param name Name of the element to read.
   * @return Value of the element.
   * @throw SDFStatus exception in case the element is not found or has
   * invalid content, ie. content that cannot be parsed as a boolean.
   */
  virtual bool GetElementBool(const std::string& name) const;

  /**
   * @brief Get the value of a int SDF element.
   *
   * This method can read integer values in the binary (0b), octal (0), decimal
   * (no prefix), or hexadecimal (0x) formats, identified by their prefixes.
   * It can also parse signed values with either a - or + signal.
   *
   * @sa GetElementInt(const std::string&)
   *
   * @param name Name of the element to read.
   * @param value Value of the element.
   * @return SDFStatus Status of the parse operation. If the element was found
   * and had a valid value, an OKStatus is returned, otherwise an object
   * containing and error status and error message is returned.
   */
  virtual SDFStatus GetElementInt(const std::string& name, gsl::not_null<int*> value) const noexcept;
  /**
   * @brief Get the value of a int SDF element.
   *
   * This method can read integer values in the binary (0b), octal (0), decimal
   * (no prefix), or hexadecimal (0x) bases, identified by their prefixes.
   * It can also parse signed values with either a - or + signal.
   *
   * @sa GetElementInt(const std::string&, gsl::not_null<int*>)
   *
   * @param name Name of the element to read.
   * @return int Value of the element.
   * @throw SDFStatus exception in case the element is not found or has
   * invalid content, ie. content that cannot be parsed as an integer such as
   * string, or if the value of the element is beyond the current platform limits
   * for an integer value.
   */
  virtual int GetElementInt(const std::string& name) const;

  /**
   * @brief Get the value of an unsigned int SDF element.
   *
   * This method can read unsigned integer values in the binary (0b), octal(0),
   * decimal (no prefix) or hexadecimal (0x) bases.
   * In case this methods find a signed integer, it returns an error.
   *
   * @sa GetElementUnsignedInt(const std::string&)
   *
   * @param name Name of the element to read.
   * @param value Value of the element.
   * @return SDFStatus Status of the parse operation. If the element was found
   * and had a valid value, an OKStatus is returned, otherwise an object
   * containing and error status and error message is returned.
   */
  virtual SDFStatus GetElementUnsignedInt(const std::string& name, gsl::not_null<unsigned int*> value) const noexcept;
  /**
   * @brief Get the value of an unsigned int SDF element.
   *
   * This method can read unsigned integer values in the binary (0b), octal(0),
   * decimal (no prefix) or hexadecimal (0x) bases.
   * In case this methods find a signed integer, it throws an exception.
   *
   * @sa GetElementUnsignedInt(const std::string&, gsl::not_null<unsigned int*>)
   *
   * @param name Name of the element to read.
   * @return unsigned int Value of the element.
   * @throws SDFStatus exception in case the element is not found or has
   * invalid content, ie. content that cannot be parsed as an integer such as
   * string, if the value is signed, or if the value is beyond the limits of an
   * unsigned integer for the current platform.
   */
  virtual unsigned int GetElementUnsignedInt(const std::string& name) const;

  /**
   * @brief Get the value of a single precision (float) SDF Element.
   *
   * This method can read real values as single precision floating point values
   * (float). It is also possible to read floats specified in the hexadecimal
   * format with the 0x prefix.
   *
   * @sa GetElementFloat(const std::string&)
   *
   * @param name Name of the element to read.
   * @param value Value of the element.
   * @return SDFStatus Status of the parse operation. If the element was found
   * and had a valid value, an OKStatus is returned, otherwise an object
   * containing and error status and error message is returned.
   */
  virtual SDFStatus GetElementFloat(const std::string& name, gsl::not_null<float*> value) const noexcept;
  /**
   * @brief Get the value of a single precision (float) SDF Element.
   *
   * This method can read real values as single precision floating point values
   * (float). It is also possible to read floats specified in the hexadecimal
   * format with the 0x prefix.
   *
   * @sa GetElementFloat(const std::string&, gsl::not_null<float*>)
   *
   * @param name Name of the element to read.
   * @return float Value of the element.
   * @throws SDFStatus exception in case the element is not found or has
   * invalid content, ie. content that cannot be parsed as a float or is beyond
   * the limits of a float for the current platform.
   */
  virtual float GetElementFloat(const std::string& name) const;

  /**
   * @brief Get the value of a double precision floating point (double) SDF Element.
   *
   * This method can read real values as double precision floating point values
   * (double). It is also possible to read doubles specified in the hexadecimal
   * format with the 0x prefix.
   *
   * @sa GetElementDouble(const std::string&)
   *
   * @param name Name of the element to read.
   * @param value Value of the element.
   * @return SDFStatus Status of the parse operation. If the element was found
   * and had a valid value, an OKStatus is returned, otherwise an object
   * containing and error status and error message is returned.
   */
  virtual SDFStatus GetElementDouble(const std::string& name, gsl::not_null<double*> value) const noexcept;
  /**
   * @brief Get the value of a double precision floating point (double) SDF Element.
   *
   * This method can read real values as double precision floating point values
   * (double). It is also possible to read doubles specified in the hexadecimal
   * format with the 0x prefix.
   *
   * @sa GetElementDouble(const std::string&, gsl::not_null<double*>)
   *
   * @param name Name of the element to read.
   * @return double Value of the element.
   * @throws SDFStatus exception in case the element is not found or has
   * invalid content, ie. content that cannot be parsed as a double or is beyond
   * the limits of a double for the current platform.
   */
  virtual double GetElementDouble(const std::string& name) const;

private:
  //! Stores the pointer of the SDF from which this class reads the values of attributes and elements.
  sdf::ElementPtr _sdf;
};

#endif  // PROVANT_SDF_READER_H


#pragma once

#include "Cesium3DTilesSelection/BoundingVolume.h"
#include "Cesium3DTilesSelection/Library.h"
#include "Cesium3DTilesSelection/Tile.h"
#include "Cesium3DTilesSelection/TileContext.h"
#include "Cesium3DTilesSelection/TileID.h"
#include "Cesium3DTilesSelection/TileRefine.h"
#include "Cesium3DTilesSelection/TilesetOptions.h"

#include <gsl/span>
#include <spdlog/fwd.h>

#include <cstddef>
#include <memory>

namespace Cesium3DTilesSelection {
/**
 * @brief The information that is passed to a {@link TileContentLoader} to
 * create a {@link TileContentLoadResult}.
 *
 * For many types of tile content, only the `data` field is required. The other
 * members are used for content that can generate child tiles, like external
 * tilesets or composite tiles. These members are usually initialized from
 * the corresponding members of the {@link Tile} that the content belongs to.
 */
struct CESIUM3DTILESSELECTION_API TileContentLoadInput {

  /**
   * @brief Creates a new, uninitialized instance for the given tile.
   *
   * The `data`, `contentType` and `url` will have default values,
   * and have to be initialized before this instance is passed to
   * one of the loader functions.
   *
   * @param pLogger The logger that will be used
   * @param tile The {@link Tile} that the content belongs to
   */
  TileContentLoadInput(
      const std::shared_ptr<spdlog::logger> pLogger,
      const Tile& tile);

  /**
   * @brief Creates a new instance for the given tile.
   *
   * @param pLogger The logger that will be used
   * @param data The actual data that the tile content will be created from
   * @param contentType The content type, if the data was received via a
   * network response
   * @param url The URL that the data was loaded from
   * @param tile The {@link Tile} that the content belongs to
   */
  TileContentLoadInput(
      const std::shared_ptr<spdlog::logger> pLogger,
      const gsl::span<const std::byte>& data,
      const std::string& contentType,
      const std::string& url,
      const Tile& tile);

  /**
   * @brief Creates a new instance.
   *
   * For many types of tile content, only the `data` field is required. The
   * other parameters are used for content that can generate child tiles, like
   * external tilesets or composite tiles.
   *
   * @param pLogger The logger that will be used
   * @param data The actual data that the tile content will be created from
   * @param contentType The content type, if the data was received via a
   * network response
   * @param url The URL that the data was loaded from
   * @param tileID The {@link TileID}
   * @param tileBoundingVolume The tile {@link BoundingVolume}
   * @param tileContentBoundingVolume The tile content {@link BoundingVolume}
   * @param tileRefine The {@link TileRefine} strategy
   * @param tileGeometricError The geometric error of the tile
   * @param tileTransform The tile transform
   */
  TileContentLoadInput(
      const std::shared_ptr<spdlog::logger> pLogger,
      const gsl::span<const std::byte>& data,
      const std::string& contentType,
      const std::string& url,
      const TileID& tileID,
      const BoundingVolume& tileBoundingVolume,
      const std::optional<BoundingVolume>& tileContentBoundingVolume,
      TileRefine tileRefine,
      double tileGeometricError,
      const glm::dmat4& tileTransform,
      const TilesetContentOptions& contentOptions);

  /**
   * @brief The logger that receives details of loading errors and warnings.
   */
  std::shared_ptr<spdlog::logger> pLogger;

  /**
   * @brief The raw input data.
   *
   * The {@link TileContentFactory} will try to determine the type of the
   * data using the first four bytes (i.e. the "magic header"). If this
   * does not succeed, it will try to determine the type based on the
   * `contentType` field.
   */
  gsl::span<const std::byte> data;

  /**
   * @brief The content type.
   *
   * If the data was obtained via a HTTP response, then this will be
   * the `Content-Type` of that response. The {@link TileContentFactory}
   * will try to interpret the data based on this content type.
   *
   * If the data was not directly obtained from an HTTP response, then
   * this may be the empty string.
   */
  std::string contentType;

  /**
   * @brief The source URL.
   */
  std::string url;

  /**
   * @brief The {@link TileID}.
   */
  TileID tileID;

  /**
   * @brief The tile {@link BoundingVolume}.
   */
  BoundingVolume tileBoundingVolume;

  /**
   * @brief Tile content {@link BoundingVolume}.
   */
  std::optional<BoundingVolume> tileContentBoundingVolume;

  /**
   * @brief The {@link TileRefine}.
   */
  TileRefine tileRefine;

  /**
   * @brief The geometric error.
   */
  double tileGeometricError;

  /**
   * @brief The tile transform
   */
  glm::dmat4 tileTransform;

  /**
   * @brief Options for parsing content and creating Gltf models.
   */
  TilesetContentOptions contentOptions;
};
} // namespace Cesium3DTilesSelection


#pragma once
#include <ntdll.h>
#include <gsl/span>
#include <gsl/span_ext>
#include "module.h"

namespace pe
{
  class module;

  class segment : public IMAGE_SECTION_HEADER
  {
  public:
    segment() = delete;

    const class module *module() const;
    class module *module();
    std::string_view name() const;
    gsl::span<uint8_t> as_bytes();
    gsl::span<const uint8_t> as_bytes() const;
    bool contains_code() const;
    bool contains_initialized_data() const;
    bool contains_uninitialized_data() const;
    uint32_t relocation_count() const;
    bool discardable() const;
    bool not_cached() const;
    bool not_paged() const;
    bool shared() const;
    bool executable() const;
    bool readable() const;
    bool writable() const;
  };
}

#include "segment.inl"


#pragma once

#ifndef __linux__
#error We only support Linux
#endif

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#ifdef __FAAS_CPP_WORKER
#if !defined(__FAAS_USED_IN_BINDING) && !defined(__FAAS_CPP_WORKER_SRC)
#error Need the source file to have __FAAS_USED_IN_BINDING defined
#endif
#endif

#ifdef __FAAS_NODE_ADDON
#if !defined(__FAAS_USED_IN_BINDING) && !defined(__FAAS_NODE_ADDON_SRC)
#error Need the source file to have __FAAS_USED_IN_BINDING defined
#endif
#define __FAAS_CXX_NO_EXCEPTIONS
#endif

#ifdef __FAAS_PYTHON_BINDING
#if !defined(__FAAS_USED_IN_BINDING) && !defined(__FAAS_PYTHON_BINDING_SRC)
#error Need the source file to have __FAAS_USED_IN_BINDING defined
#endif
#include <Python.h>
#if PY_VERSION_HEX < 0x03070000
#error FaaS Python binding requires Python 3.7+
#endif
#endif

// C includes
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>

// C++ includes
#include <limits>
#include <atomic>
#include <memory>
#include <utility>
#include <optional>
#include <sstream>
#include <string>
#include <string_view>
#include <functional>
#include <algorithm>

// STL containers
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#ifdef __FAAS_CPP_WORKER
#include <mutex>
#endif

// fmtlib
#define FMT_HEADER_ONLY
#include <fmt/core.h>
#include <fmt/format.h>

// Guidelines Support Library (GSL)
#include <gsl/gsl>

#include "base/diagnostic.h"

#ifdef __FAAS_SRC
#define __FAAS_HAVE_ABSL
#endif

#if defined(__FAAS_HAVE_ABSL) && !defined(__FAAS_USED_IN_BINDING)

// Will not include common absl headers in source files
// with __FAAS_USED_IN_BINDING defined

__BEGIN_THIRD_PARTY_HEADERS

#include <absl/base/call_once.h>
#include <absl/flags/flag.h>
#include <absl/time/time.h>
#include <absl/time/clock.h>
#include <absl/strings/str_cat.h>
#include <absl/strings/match.h>
#include <absl/strings/strip.h>
#include <absl/strings/str_split.h>
#include <absl/strings/numbers.h>
#include <absl/strings/ascii.h>
#include <absl/random/random.h>
#include <absl/random/distributions.h>
#include <absl/container/flat_hash_map.h>
#include <absl/container/flat_hash_set.h>
#include <absl/container/fixed_array.h>
#include <absl/container/inlined_vector.h>
#include <absl/synchronization/mutex.h>
#include <absl/synchronization/notification.h>
#include <absl/functional/bind_front.h>
#include <absl/algorithm/container.h>

__END_THIRD_PARTY_HEADERS

#endif  // defined(__FAAS_HAVE_ABSL) && !defined(__FAAS_USED_IN_BINDING)

#include "base/macro.h"
#include "base/logging.h"
#include "base/std_span.h"


/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2017-Present Couchbase, Inc.
 *
 *   Use of this software is governed by the Business Source License included
 *   in the file licenses/BSL-Couchbase.txt.  As of the Change Date specified
 *   in that file, in accordance with the Business Source License, use of this
 *   software will be governed by the Apache License, Version 2.0, included in
 *   the file licenses/APL2.txt.
 */
#pragma once

#include <mcbp/protocol/opcode.h>
#include <mcbp/protocol/request.h>
#include <mcbp/protocol/response.h>
#include <mcbp/protocol/status.h>

#include <gsl/gsl-lite.hpp>

namespace cb::mcbp {

/**
 * FrameBuilder allows you to build up a request / response frame in
 * a provided memory area. It provides helper methods which makes sure
 * that the fields is formatted in the correct byte order etc.
 *
 * The frame looks like:
 *
 *
 *     Byte/     0       |       1       |       2       |       3       |
 *        /              |               |               |               |
 *       |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
 *       +---------------+---------------+---------------+---------------+
 *      0| Magic         |               | Framing extras| Key Length    |
 *       +---------------+---------------+---------------+---------------+
 *      4| Extras length |               |                               |
 *       +---------------+---------------+---------------+---------------+
 *      8| Total body length                                             |
 *       +---------------+---------------+---------------+---------------+
 *     12|                                                               |
 *       +---------------+---------------+---------------+---------------+
 *     16|                                                               |
 *       |                                                               |
 *       +---------------+---------------+---------------+---------------+
 *     24| Optional section containing framing extras Max 255 bytes      |
 *       +---------------------------------------------------------------+
 *       | Optional section containing command extras                    |
 *       +---------------------------------------------------------------+
 *       | Optional section containing the key                           |
 *       +---------------------------------------------------------------+
 *       | Optional section containing the value.                        |
 *       | The size of the value is the total body length minus the      |
 *       | size of the optional framing extras, extras and key.          |
 *       +---------------------------------------------------------------+
 *
 */
template <typename T>
class FrameBuilder {
public:
    explicit FrameBuilder(cb::char_buffer backing, bool initialized = false)
        : FrameBuilder(
                  {reinterpret_cast<uint8_t*>(backing.data()), backing.size()},
                  initialized) {
    }

    explicit FrameBuilder(cb::byte_buffer backing, bool initialized = false)
        : buffer(backing) {
        checkSize(sizeof(T));
        if (!initialized) {
            std::fill(backing.begin(), backing.begin() + sizeof(T), 0);
        }
    }

    T* getFrame() {
        return reinterpret_cast<T*>(buffer.data());
    }

    void setMagic(Magic magic) {
        getFrame()->setMagic(magic);
    }

    void setOpcode(ClientOpcode opcode) {
        getFrame()->setOpcode(opcode);
    }

    void setOpcode(ServerOpcode opcode) {
        getFrame()->setOpcode(opcode);
    }

    void setDatatype(Datatype datatype) {
        getFrame()->setDatatype(datatype);
    }

    void setVBucket(Vbid value) {
        getFrame()->setVBucket(value);
    }

    void setOpaque(uint32_t opaque) {
        getFrame()->setOpaque(opaque);
    }

    void setCas(uint64_t val) {
        getFrame()->setCas(val);
    }

    /**
     * Insert/replace the Framing extras section and move the rest of the
     * sections to their new locations.
     */
    void setFramingExtras(cb::const_byte_buffer val) {
        if (!is_alternative_encoding(getFrame()->getMagic())) {
            throw std::logic_error(
                    R"(setFramingExtras: Magic needs to be one of the alternative packet encodings)");
        }
        auto* req = getFrame();
        auto existing = req->getFramingExtras();
        // can we fit the data?
        checkSize(existing.size(), val.size());
        moveAndInsert(existing, val, req->getBodylen() - existing.size());
        req->setFramingExtraslen(gsl::narrow<uint8_t>(val.size()));
    }

    /**
     * Insert/replace the Extras section and move the rest of the sections
     * to their new locations.
     */
    void setExtras(cb::const_byte_buffer val) {
        auto* req = getFrame();
        auto existing = req->getExtdata();
        checkSize(existing.size(), val.size());
        auto move_size = req->getKey().size() + req->getValue().size();
        moveAndInsert(existing, val, move_size);
        req->setExtlen(gsl::narrow<uint8_t>(val.size()));
    }
    void setExtras(std::string_view val) {
        setExtras({reinterpret_cast<const uint8_t*>(val.data()), val.size()});
    }

    /**
     * Insert/replace the Key section and move the value section to the new
     * location.
     */
    void setKey(cb::const_byte_buffer val) {
        auto* req = getFrame();
        auto existing = req->getKey();
        checkSize(existing.size(), val.size());
        moveAndInsert(existing, val, req->getValue().size());
        req->setKeylen(gsl::narrow<uint16_t>(val.size()));
    }

    void setKey(std::string_view val) {
        setKey({reinterpret_cast<const uint8_t*>(val.data()), val.size()});
    }

    /**
     * Insert/replace the value section.
     */
    void setValue(cb::const_byte_buffer val) {
        auto* req = getFrame();
        auto existing = req->getValue();
        checkSize(existing.size(), val.size());
        moveAndInsert(existing, val, 0);
    }

    void setValue(std::string_view val) {
        setValue({reinterpret_cast<const uint8_t*>(val.data()), val.size()});
    }

    /**
     * Try to validate the underlying packet
     */
    void validate() {
        getFrame()->isValid();
    }

protected:
    /**
     * check that the requested size fits into the buffer
     *
     * @param size The total requested size (including header)
     */
    void checkSize(size_t size) {
        if (size > buffer.size()) {
            throw std::logic_error(
                    "FrameBuilder::checkSize: too big to fit in buffer");
        }
    }

    /**
     * check if there is room in the buffer to replace the field with
     * one with a different size
     *
     * @param oldfield
     * @param newfield
     */
    void checkSize(size_t oldfield, size_t newfield) {
        checkSize(sizeof(T) + getFrame()->getBodylen() - oldfield + newfield);
    }

    /**
     * Move the rest of the packet to the new location and insert the
     * new value
     */
    void moveAndInsert(cb::byte_buffer existing,
                       cb::const_byte_buffer value,
                       size_t size) {
        auto* location = existing.data();
        if (size > 0 && existing.size() != value.size()) {
            // we need to move the data following this entry to a different
            // location.
            memmove(location + value.size(), location + existing.size(), size);
        }
        std::copy(value.begin(), value.end(), location);
        auto* req = getFrame();
        // Update the total length
        req->setBodylen(gsl::narrow<uint32_t>(req->getBodylen() -
                                              existing.size() + value.size()));
    }

    cb::byte_buffer buffer;
};

/**
 * Specialized class to build a Request
 */
class RequestBuilder : public FrameBuilder<Request> {
public:
    explicit RequestBuilder(cb::char_buffer backing, bool initialized = false)
        : RequestBuilder(
                  {reinterpret_cast<uint8_t*>(backing.data()), backing.size()},
                  initialized) {
    }
    explicit RequestBuilder(cb::byte_buffer backing, bool initialized = false)
        : FrameBuilder<Request>(backing, initialized) {
    }
    void setVbucket(Vbid vbucket) {
        getFrame()->setVBucket(vbucket);
    }
};

/**
 * Specialized class to build a response
 */
class ResponseBuilder : public FrameBuilder<Response> {
public:
    explicit ResponseBuilder(cb::char_buffer backing, bool initialized = false)
        : ResponseBuilder(
                  {reinterpret_cast<uint8_t*>(backing.data()), backing.size()},
                  initialized) {
    }
    explicit ResponseBuilder(cb::byte_buffer backing, bool initialized = false)
        : FrameBuilder<Response>(backing, initialized) {
    }
    void setStatus(Status status) {
        getFrame()->setStatus(status);
    }
};

} // namespace cb::mcbp


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

namespace chino::io
{
enum class std_handles
{
    in,
    out,
    err
};

enum class create_disposition
{
    create_always = 2,
    create_new = 1,
    open_always = 4,
    open_existing = 3,
    truncate_existing = 5
};

result<void, error_code> alloc_console() noexcept;
handle_t get_std_handle(std_handles type) noexcept;

result<handle_t, error_code> open(const insert_lookup_object_options &options, create_disposition create_disp = create_disposition::open_existing) noexcept;
result<size_t, error_code> read(handle_t file, gsl::span<gsl::byte> buffer) noexcept;
result<void, error_code> write(handle_t file, gsl::span<const gsl::byte> buffer) noexcept;
result<void, error_code> close(handle_t file) noexcept;
}


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

namespace chino::arch
{
// No asynchronous interrupt is supported by this target
// Only save callee saved registers in context
struct win32_thread_context
{
    uintptr_t rbx;
    uintptr_t rbp;
    uintptr_t rdi;
    uintptr_t rsi;
    uintptr_t rsp;
    uintptr_t r12;
    uintptr_t r13;
    uintptr_t r14;
    uintptr_t r15;
    uintptr_t reserved0;

    __m128 xmm6;
    __m128 xmm7;
    __m128 xmm8;
    __m128 xmm9;
    __m128 xmm10;
    __m128 xmm11;
    __m128 xmm12;
    __m128 xmm13;
    __m128 xmm14;
    __m128 xmm15;

    uintptr_t stack_low;
    uintptr_t stack_high;
};

using thread_context_t = win32_thread_context;

struct win32_arch
{
    static constexpr size_t ALLOCATE_ALIGNMENT = 16;

    static uint32_t current_processor() noexcept { return 0; }
    static void yield_processor() noexcept;

    static uintptr_t disable_irq() noexcept;
    static void restore_irq(uintptr_t state) noexcept;

    static void init_thread_context(thread_context_t &context, gsl::span<uintptr_t> stack, kernel::thread_thunk_t start, void *arg0, void *arg1) noexcept;
    [[noreturn]] static void start_schedule(thread_context_t &context) noexcept;
    static void yield(thread_context_t &old_context, thread_context_t &new_context) noexcept;

    static void init_stack_check() noexcept;
};

using arch_t = win32_arch;
}


/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2017 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
#pragma once

#include <mcbp/protocol/dcp_stream_end_status.h>
#include <mcbp/protocol/status.h>
#include <memcached/dcp_stream_id.h>
#include <memcached/engine_error.h>
#include <memcached/types.h>
#include <memcached/vbucket.h>
#include <memcached/visibility.h>
#include <gsl/gsl>

struct DocKey;

namespace cb::durability {
class Requirements;
enum class Level : uint8_t;
} // namespace cb::durability

namespace cb::mcbp {
class Response;
}

namespace mcbp::systemevent {
enum class id : uint32_t;
enum class version : uint8_t;
} // namespace mcbp::systemevent

class DcpConnHandlerIface {
public:
    virtual ~DcpConnHandlerIface() = default;
};

/**
 * The message producers are used by the engine's DCP producer
 * to add messages into the DCP stream.  Please look at the full
 * DCP documentation to figure out the real meaning for all of the
 * messages.
 */
struct DcpMessageProducersIface {
    virtual ~DcpMessageProducersIface() = default;

    virtual ENGINE_ERROR_CODE get_failover_log(uint32_t opaque,
                                               Vbid vbucket) = 0;

    virtual ENGINE_ERROR_CODE stream_req(uint32_t opaque,
                                         Vbid vbucket,
                                         uint32_t flags,
                                         uint64_t start_seqno,
                                         uint64_t end_seqno,
                                         uint64_t vbucket_uuid,
                                         uint64_t snap_start_seqno,
                                         uint64_t snap_end_seqno,
                                         const std::string& request_value) = 0;

    virtual ENGINE_ERROR_CODE add_stream_rsp(uint32_t opaque,
                                             uint32_t stream_opaque,
                                             cb::mcbp::Status status) = 0;

    virtual ENGINE_ERROR_CODE marker_rsp(uint32_t opaque,
                                         cb::mcbp::Status status) = 0;

    virtual ENGINE_ERROR_CODE set_vbucket_state_rsp(
            uint32_t opaque, cb::mcbp::Status status) = 0;

    /**
     * Send a Stream End message
     *
     * @param opaque this is the opaque requested by the consumer
     *               in the Stream Request message
     * @param vbucket the vbucket id the message belong to
     * @param status the reason for the stream end.
     *              0 = success
     *              1+ = Something happened on the vbucket causing
     *                   us to abort it.
     * @param sid The stream-ID the end applies to (can be 0 for none)
     *
     * @return ENGINE_SUCCESS upon success
     *         ENGINE_EWOULDBLOCK if no data is available
     *         ENGINE_* for errors
     */
    virtual ENGINE_ERROR_CODE stream_end(uint32_t opaque,
                                         Vbid vbucket,
                                         cb::mcbp::DcpStreamEndStatus status,
                                         cb::mcbp::DcpStreamId sid) = 0;

    /**
     * Send a marker
     *
     * @param opaque this is the opaque requested by the consumer
     *               in the Stream Request message
     * @param vbucket the vbucket id the message belong to
     * @param start_seqno start of the snapshot range
     * @param end_seqno end of the snapshot range
     * @param flags snapshot marker flags (DISK/MEMORY/CHK/ACK).
     * @param highCompletedSeqno the SyncRepl high completed seqno
     * @param maxVisibleSeqno highest committed seqno (ignores prepare/abort)
     * @param timestamp for the data in the snapshot marker (only valid for
     *                  disk type and represents the disk commit time)
     * @param sid The stream-ID the marker applies to (can be 0 for none)
     *
     * @return ENGINE_SUCCESS upon success
     */
    virtual ENGINE_ERROR_CODE marker(uint32_t opaque,
                                     Vbid vbucket,
                                     uint64_t start_seqno,
                                     uint64_t end_seqno,
                                     uint32_t flags,
                                     std::optional<uint64_t> highCompletedSeqno,
                                     std::optional<uint64_t> maxVisibleSeqno,
                                     std::optional<uint64_t> timestamp,
                                     cb::mcbp::DcpStreamId sid) = 0;

    /**
     * Send a Mutation
     *
     * @param opaque this is the opaque requested by the consumer
     *               in the Stream Request message
     * @param itm the item to send.
     * @param vbucket the vbucket id the message belong to
     * @param by_seqno
     * @param rev_seqno
     * @param lock_time
     * @param nru the nru field used by ep-engine (may safely be ignored)
     * @param sid The stream-ID the mutation applies to (can be 0 for none)
     *
     * @return ENGINE_SUCCESS upon success
     */
    virtual ENGINE_ERROR_CODE mutation(uint32_t opaque,
                                       cb::unique_item_ptr itm,
                                       Vbid vbucket,
                                       uint64_t by_seqno,
                                       uint64_t rev_seqno,
                                       uint32_t lock_time,
                                       uint8_t nru,
                                       cb::mcbp::DcpStreamId sid) = 0;

    /**
     * Send a deletion
     *
     * @param opaque this is the opaque requested by the consumer
     *               in the Stream Request message
     * @param itm the item to send.
     * @param by_seqno
     * @param rev_seqno
     * @param sid The stream-ID the deletion applies to (can be 0 for none)
     *
     * @return ENGINE_SUCCESS upon success
     */
    virtual ENGINE_ERROR_CODE deletion(uint32_t opaque,
                                       cb::unique_item_ptr itm,
                                       Vbid vbucket,
                                       uint64_t by_seqno,
                                       uint64_t rev_seqno,
                                       cb::mcbp::DcpStreamId sid) = 0;

    /**
     * Send a deletion with delete_time or collections (or both)
     *
     * @param opaque this is the opaque requested by the consumer
     *               in the Stream Request message
     * @param itm the item to send.
     * @param vbucket the vbucket id the message belong to
     * @param by_seqno
     * @param rev_seqno
     * @param delete_time the time of the deletion (tombstone creation time)
     * @param sid The stream-ID the deletion applies to (can be 0 for none)
     *
     * @return ENGINE_SUCCESS upon success
     */
    virtual ENGINE_ERROR_CODE deletion_v2(uint32_t opaque,
                                          cb::unique_item_ptr itm,
                                          Vbid vbucket,
                                          uint64_t by_seqno,
                                          uint64_t rev_seqno,
                                          uint32_t delete_time,
                                          cb::mcbp::DcpStreamId sid) = 0;

    /**
     * Send an expiration
     *
     * @param opaque this is the opaque requested by the consumer
     *               in the Stream Request message
     * @param itm the item to send.
     * @param by_seqno
     * @param rev_seqno
     * @param delete_time the time of the deletion (tombstone creation time)
     * @param sid The stream-ID the expiration applies to (can be 0 for none)
     *
     * @return ENGINE_SUCCESS upon success
     */
    virtual ENGINE_ERROR_CODE expiration(uint32_t opaque,
                                         cb::unique_item_ptr itm,
                                         Vbid vbucket,
                                         uint64_t by_seqno,
                                         uint64_t rev_seqno,
                                         uint32_t delete_time,
                                         cb::mcbp::DcpStreamId sid) = 0;

    /**
     * Send a state transition for a vbucket
     *
     * @param opaque this is the opaque requested by the consumer
     *               in the Stream Request message
     * @param vbucket the vbucket id the message belong to
     * @param state the new state
     *
     * @return ENGINE_SUCCESS upon success
     */
    virtual ENGINE_ERROR_CODE set_vbucket_state(uint32_t opaque,
                                                Vbid vbucket,
                                                vbucket_state_t state) = 0;

    /**
     * Send a noop
     *
     * @param opaque what to use as the opaque in the buffer
     *
     * @return ENGINE_SUCCESS upon success
     */
    virtual ENGINE_ERROR_CODE noop(uint32_t opaque) = 0;

    /**
     * Send a buffer acknowledgment
     *
     * @param opaque this is the opaque requested by the consumer
     *               in the Stream Request message
     * @param vbucket the vbucket id the message belong to
     * @param buffer_bytes the amount of bytes processed
     *
     * @return ENGINE_SUCCESS upon success
     */
    virtual ENGINE_ERROR_CODE buffer_acknowledgement(uint32_t opaque,
                                                     Vbid vbucket,
                                                     uint32_t buffer_bytes) = 0;

    /**
     * Send a control message to the other end
     *
     * @param opaque what to use as the opaque in the buffer
     * @param key the identifier for the property to set
     * @param value The value for the property (the layout of the
     *              value is defined for the key)
     *
     * @return ENGINE_SUCCESS upon success
     */
    virtual ENGINE_ERROR_CODE control(uint32_t opaque,
                                      std::string_view key,
                                      std::string_view value) = 0;

    /**
     * Send a system event message to the other end
     *
     * @param cookie passed on the cookie provided by step
     * @param opaque what to use as the opaque in the buffer
     * @param vbucket the vbucket the event applies to
     * @param bySeqno the sequence number of the event
     * @param version A version value defining the eventData format
     * @param key the system event's key data
     * @param eventData the system event's specific data
     * @param sid The stream-ID the event applies to (can be 0 for none)
     *
     * @return ENGINE_SUCCESS upon success
     */
    virtual ENGINE_ERROR_CODE system_event(uint32_t opaque,
                                           Vbid vbucket,
                                           mcbp::systemevent::id event,
                                           uint64_t bySeqno,
                                           mcbp::systemevent::version version,
                                           cb::const_byte_buffer key,
                                           cb::const_byte_buffer eventData,
                                           cb::mcbp::DcpStreamId sid) = 0;

    /*
     * Send a GetErrorMap message to the other end
     *
     * @param opaque The opaque to send over
     * @param version The version of the error map
     *
     * @return ENGINE_SUCCESS upon success
     */
    virtual ENGINE_ERROR_CODE get_error_map(uint32_t opaque,
                                            uint16_t version) = 0;

    /**
     * See mutation for a description of the parameters except for:
     *
     * @param deleted Are we storing a deletion operation?
     * @param durability the durability specification for this item
     */
    virtual ENGINE_ERROR_CODE prepare(uint32_t opaque,
                                      cb::unique_item_ptr itm,
                                      Vbid vbucket,
                                      uint64_t by_seqno,
                                      uint64_t rev_seqno,
                                      uint32_t lock_time,
                                      uint8_t nru,
                                      DocumentState document_state,
                                      cb::durability::Level level) = 0;

    /**
     * Send a seqno ack message
     *
     * It serves to inform KV-Engine active nodes that the replica has
     * successfully received and prepared to memory/disk all DCP_PREPARE
     * messages up to the specified seqno.
     *
     * @param opaque identifying stream
     * @param vbucket the vbucket the seqno ack is for
     * @param prepared_seqno The seqno the replica has prepared up to.
     */
    virtual ENGINE_ERROR_CODE seqno_acknowledged(uint32_t opaque,
                                                 Vbid vbucket,
                                                 uint64_t prepared_seqno) = 0;

    /**
     * Send a commit message:
     *
     * This is sent from the DCP Producer to the DCP Consumer.
     * It is only sent to DCP replicas, not GSI, FTS etc. It serves to inform
     * KV-Engine replicas of a committed Sync Write
     *
     * @param opaque
     * @param vbucket the vbucket the event applies to
     * @param key The key of the committed mutation.
     * @param prepare_seqno The seqno of the prepare that we are committing.
     * @param commit_seqno The sequence number to commit this mutation at.
     * @return
     */
    virtual ENGINE_ERROR_CODE commit(uint32_t opaque,
                                     Vbid vbucket,
                                     const DocKey& key,
                                     uint64_t prepare_seqno,
                                     uint64_t commit_seqno) = 0;
    /**
     * Send an abort message:
     *
     * This is sent from the DCP Producer to the DCP Consumer.
     */
    virtual ENGINE_ERROR_CODE abort(uint32_t opaque,
                                    Vbid vbucket,
                                    const DocKey& key,
                                    uint64_t prepared_seqno,
                                    uint64_t abort_seqno) = 0;
    /**
     * Send an OSO snapshot marker to from server to client
     */
    virtual ENGINE_ERROR_CODE oso_snapshot(uint32_t opaque,
                                           Vbid vbucket,
                                           uint32_t flags,
                                           cb::mcbp::DcpStreamId sid) = 0;

    virtual ENGINE_ERROR_CODE seqno_advanced(uint32_t opaque,
                                             Vbid vbucket,
                                             uint64_t seqno,
                                             cb::mcbp::DcpStreamId sid) = 0;
};

using dcp_add_failover_log = std::function<ENGINE_ERROR_CODE(
        const std::vector<vbucket_failover_t>&)>;

struct MEMCACHED_PUBLIC_CLASS DcpIface {
    /**
     * Called from the memcached core for a DCP connection to allow it to
     * inject new messages on the stream.
     *
     * @param cookie a unique handle the engine should pass on to the
     *               message producers
     * @param producers functions the client may use to add messages to
     *                  the DCP stream
     *
     * @return The appropriate error code returned from the message
     *         producerif it failed, or:
     *         ENGINE_SUCCESS if the engine don't have more messages
     *                        to send at this moment
     */
    virtual ENGINE_ERROR_CODE step(gsl::not_null<const void*> cookie,
                                   DcpMessageProducersIface& producers) = 0;

    /**
     * Called from the memcached core to open a new DCP connection.
     *
     * @param cookie a unique handle the engine should pass on to the
     *               message producers (typically representing the memcached
     *               connection).
     * @param opaque what to use as the opaque for this DCP connection.
     * @param seqno Unused
     * @param flags bitfield of flags to specify what to open. See DCP_OPEN_XXX
     * @param name Identifier for this connection. Note that the name must be
     *             unique; attempting to (re)connect with a name already in use
     *             will disconnect the existing connection.
     * @param value An optional JSON value specifying extra information about
     *              the connection to be opened.
     * @return ENGINE_SUCCESS if the DCP connection was successfully opened,
     *         otherwise error code indicating reason for the failure.
     */
    virtual ENGINE_ERROR_CODE open(gsl::not_null<const void*> cookie,
                                   uint32_t opaque,
                                   uint32_t seqno,
                                   uint32_t flags,
                                   std::string_view name,
                                   std::string_view value = {}) = 0;

    /**
     * Called from the memcached core to add a vBucket stream to the set of
     * connected streams.
     *
     * @param cookie a unique handle the engine should pass on to the
     *               message producers (typically representing the memcached
     *               connection).
     * @param opaque what to use as the opaque for this DCP connection.
     * @param vbucket The vBucket to stream.
     * @param flags bitfield of flags to specify what to open. See
     *              DCP_ADD_STREAM_FLAG_XXX
     * @return ENGINE_SUCCESS if the DCP stream was successfully opened,
     *         otherwise error code indicating reason for the failure.
     */
    virtual ENGINE_ERROR_CODE add_stream(gsl::not_null<const void*> cookie,
                                         uint32_t opaque,
                                         Vbid vbucket,
                                         uint32_t flags) = 0;

    /**
     * Called from the memcached core to close a vBucket stream to the set of
     * connected streams.
     *
     * @param cookie a unique handle the engine should pass on to the
     *               message producers (typically representing the memcached
     *               connection).
     * @param opaque what to use as the opaque for this DCP connection.
     * @param vbucket The vBucket to close.
     * @param sid The id of the stream to close (can be 0/none)
     * @return
     */
    virtual ENGINE_ERROR_CODE close_stream(gsl::not_null<const void*> cookie,
                                           uint32_t opaque,
                                           Vbid vbucket,
                                           cb::mcbp::DcpStreamId sid) = 0;

    /**
     * Callback to the engine that a Stream Request message was received
     */
    virtual ENGINE_ERROR_CODE stream_req(
            gsl::not_null<const void*> cookie,
            uint32_t flags,
            uint32_t opaque,
            Vbid vbucket,
            uint64_t start_seqno,
            uint64_t end_seqno,
            uint64_t vbucket_uuid,
            uint64_t snap_start_seqno,
            uint64_t snap_end_seqno,
            uint64_t* rollback_seqno,
            dcp_add_failover_log callback,
            std::optional<std::string_view> json) = 0;

    /**
     * Callback to the engine that a get failover log message was received
     */
    virtual ENGINE_ERROR_CODE get_failover_log(
            gsl::not_null<const void*> cookie,
            uint32_t opaque,
            Vbid vbucket,
            dcp_add_failover_log callback) = 0;

    /**
     * Callback to the engine that a stream end message was received
     */
    virtual ENGINE_ERROR_CODE stream_end(
            gsl::not_null<const void*> cookie,
            uint32_t opaque,
            Vbid vbucket,
            cb::mcbp::DcpStreamEndStatus status) = 0;

    /**
     * Callback to the engine that a snapshot marker message was received
     */
    virtual ENGINE_ERROR_CODE snapshot_marker(
            gsl::not_null<const void*> cookie,
            uint32_t opaque,
            Vbid vbucket,
            uint64_t start_seqno,
            uint64_t end_seqno,
            uint32_t flags,
            std::optional<uint64_t> high_completed_seqno,
            std::optional<uint64_t> max_visible_seqno) = 0;

    /**
     * Callback to the engine that a mutation message was received
     *
     * @param cookie The cookie representing the connection
     * @param opaque The opaque field in the message (identifying the stream)
     * @param key The documents key
     * @param value The value to store
     * @param priv_bytes The number of bytes in the value which should be
     *                   allocated from the privileged pool
     * @param datatype The datatype for the incomming item
     * @param cas The documents CAS value
     * @param vbucket The vbucket identifier for the document
     * @param flags The user specified flags
     * @param by_seqno The sequence number in the vbucket
     * @param rev_seqno The revision number for the item
     * @param expiration When the document expire
     * @param lock_time The lock time for the document
     * @param meta The documents meta
     * @param nru The engine's NRU value
     * @return Standard engine error code.
     */
    virtual ENGINE_ERROR_CODE mutation(gsl::not_null<const void*> cookie,
                                       uint32_t opaque,
                                       const DocKey& key,
                                       cb::const_byte_buffer value,
                                       size_t priv_bytes,
                                       uint8_t datatype,
                                       uint64_t cas,
                                       Vbid vbucket,
                                       uint32_t flags,
                                       uint64_t by_seqno,
                                       uint64_t rev_seqno,
                                       uint32_t expiration,
                                       uint32_t lock_time,
                                       cb::const_byte_buffer meta,
                                       uint8_t nru) = 0;

    /**
     * Callback to the engine that a deletion message was received
     *
     * @param cookie The cookie representing the connection
     * @param opaque The opaque field in the message (identifying the stream)
     * @param key The documents key
     * @param value The value to store
     * @param priv_bytes The number of bytes in the value which should be
     *                   allocated from the privileged pool
     * @param datatype The datatype for the incomming item
     * @param cas The documents CAS value
     * @param vbucket The vbucket identifier for the document
     * @param by_seqno The sequence number in the vbucket
     * @param rev_seqno The revision number for the item
     * @param meta The documents meta
     * @return Standard engine error code.
     */
    virtual ENGINE_ERROR_CODE deletion(gsl::not_null<const void*> cookie,
                                       uint32_t opaque,
                                       const DocKey& key,
                                       cb::const_byte_buffer value,
                                       size_t priv_bytes,
                                       uint8_t datatype,
                                       uint64_t cas,
                                       Vbid vbucket,
                                       uint64_t by_seqno,
                                       uint64_t rev_seqno,
                                       cb::const_byte_buffer meta) = 0;

    /**
     * Callback to the engine that a deletion_v2 message was received
     *
     * @param cookie The cookie representing the connection
     * @param opaque The opaque field in the message (identifying the stream)
     * @param key The documents key
     * @param value The value to store
     * @param priv_bytes The number of bytes in the value which should be
     *                   allocated from the privileged pool
     * @param datatype The datatype for the incomming item
     * @param cas The documents CAS value
     * @param vbucket The vbucket identifier for the document
     * @param by_seqno The sequence number in the vbucket
     * @param rev_seqno The revision number for the item
     * @param delete_time The time of the delete
     * @return Standard engine error code.
     */
    virtual ENGINE_ERROR_CODE deletion_v2(gsl::not_null<const void*> cookie,
                                          uint32_t opaque,
                                          const DocKey& key,
                                          cb::const_byte_buffer value,
                                          size_t priv_bytes,
                                          uint8_t datatype,
                                          uint64_t cas,
                                          Vbid vbucket,
                                          uint64_t by_seqno,
                                          uint64_t rev_seqno,
                                          uint32_t delete_time) {
        return ENGINE_ENOTSUP;
    }

    /**
     * Callback to the engine that an expiration message was received
     *
     * @param cookie The cookie representing the connection
     * @param opaque The opaque field in the message (identifying the stream)
     * @param key The documents key
     * @param value The value to store
     * @param priv_bytes The number of bytes in the value which should be
     *                   allocated from the privileged pool
     * @param datatype The datatype for the incomming item
     * @param cas The documents CAS value
     * @param vbucket The vbucket identifier for the document
     * @param by_seqno The sequence number in the vbucket
     * @param rev_seqno The revision number for the item
     * @param meta The documents meta
     * @return Standard engine error code.
     */
    virtual ENGINE_ERROR_CODE expiration(gsl::not_null<const void*> cookie,
                                         uint32_t opaque,
                                         const DocKey& key,
                                         cb::const_byte_buffer value,
                                         size_t priv_bytes,
                                         uint8_t datatype,
                                         uint64_t cas,
                                         Vbid vbucket,
                                         uint64_t by_seqno,
                                         uint64_t rev_seqno,
                                         uint32_t deleteTime) = 0;

    /**
     * Callback to the engine that a set vbucket state message was received
     */
    virtual ENGINE_ERROR_CODE set_vbucket_state(
            gsl::not_null<const void*> cookie,
            uint32_t opaque,
            Vbid vbucket,
            vbucket_state_t state) = 0;

    /**
     * Callback to the engine that a NOOP message was received
     */
    virtual ENGINE_ERROR_CODE noop(gsl::not_null<const void*> cookie,
                                   uint32_t opaque) = 0;

    /**
     * Callback to the engine that a buffer_ack message was received
     */
    virtual ENGINE_ERROR_CODE buffer_acknowledgement(
            gsl::not_null<const void*> cookie,
            uint32_t opaque,
            Vbid vbucket,
            uint32_t buffer_bytes) = 0;

    /**
     * Callback to the engine that a Control message was received.
     *
     * @param cookie The cookie representing the connection
     * @param opaque The opaque field in the message (identifying the stream)
     * @param key The control message name
     * @param value The control message value
     * @return Standard engine error code.
     */
    virtual ENGINE_ERROR_CODE control(gsl::not_null<const void*> cookie,
                                      uint32_t opaque,
                                      std::string_view key,
                                      std::string_view value) = 0;

    /**
     * Callback to the engine that a response message has been received.
     * @param cookie The cookie representing the connection
     * @param response The response which the server received.
     * @return Standard engine error code.
     */
    virtual ENGINE_ERROR_CODE response_handler(
            gsl::not_null<const void*> cookie,
            const cb::mcbp::Response& response) = 0;

    /**
     * Callback to the engine that a system event message was received.
     *
     * @param cookie The cookie representing the connection
     * @param opaque The opaque field in the message (identifying the stream)
     * @param vbucket The vbucket identifier for this event.
     * @param event The type of system event.
     * @param bySeqno Sequence number of event.
     * @param version The version of system event (defines the eventData format)
     * @param key The event name .
     * @param eventData The event value.
     * @return Standard engine error code.
     */
    virtual ENGINE_ERROR_CODE system_event(gsl::not_null<const void*> cookie,
                                           uint32_t opaque,
                                           Vbid vbucket,
                                           mcbp::systemevent::id event,
                                           uint64_t bySeqno,
                                           mcbp::systemevent::version version,
                                           cb::const_byte_buffer key,
                                           cb::const_byte_buffer eventData) = 0;

    /**
     * Called by the core when it receives a DCP PREPARE message over the
     * wire.
     *
     * See mutation for a description of the parameters except for:
     *
     * @param deleted Are we storing a deletion operation?
     * @param durability the durability specification for this item
     */
    virtual ENGINE_ERROR_CODE prepare(gsl::not_null<const void*> cookie,
                                      uint32_t opaque,
                                      const DocKey& key,
                                      cb::const_byte_buffer value,
                                      size_t priv_bytes,
                                      uint8_t datatype,
                                      uint64_t cas,
                                      Vbid vbucket,
                                      uint32_t flags,
                                      uint64_t by_seqno,
                                      uint64_t rev_seqno,
                                      uint32_t expiration,
                                      uint32_t lock_time,
                                      uint8_t nru,
                                      DocumentState document_state,
                                      cb::durability::Level level) = 0;

    /**
     * Called by the core when it receives a DCP SEQNO ACK message over the
     * wire.
     *
     * It serves to inform KV-Engine active nodes that the replica has
     * successfully received and prepared all DCP_PREPARE messages up to the
     * specified seqno.
     *
     * @param cookie connection to send it over
     * @param opaque identifying stream
     * @param vbucket The vbucket which is being acknowledged.
     * @param prepared_seqno The seqno the replica has prepared up to.
     */
    virtual ENGINE_ERROR_CODE seqno_acknowledged(
            gsl::not_null<const void*> cookie,
            uint32_t opaque,
            Vbid vbucket,
            uint64_t prepared_seqno) = 0;

    /**
     * Called by the core when it receives a DCP COMMIT message over the
     * wire.
     *
     * This is sent from the DCP Producer to the DCP Consumer.
     * It is only sent to DCP replicas, not GSI, FTS etc. It serves to inform
     * KV-Engine replicas of a committed Sync Write
     */
    virtual ENGINE_ERROR_CODE commit(gsl::not_null<const void*> cookie,
                                     uint32_t opaque,
                                     Vbid vbucket,
                                     const DocKey& key,
                                     uint64_t prepared_seqno,
                                     uint64_t commit_seqno) = 0;
    /**
     * Called by the core when it receives a DCP ABORT message over the
     * wire.
     *
     * This is sent from the DCP Producer to the DCP Consumer.
     */
    virtual ENGINE_ERROR_CODE abort(gsl::not_null<const void*> cookie,
                                    uint32_t opaque,
                                    Vbid vbucket,
                                    const DocKey& key,
                                    uint64_t prepared_seqno,
                                    uint64_t abort_seqno) = 0;
};


#ifndef FUNCTION_ANY_FUNCTION_H
#define FUNCTION_ANY_FUNCTION_H

#include "wasm_base.h"
#include "wasm_value.h"
#include "function/CFunction.h"
#include <gsl/gsl>

namespace wasm {

struct AnyFunction:
	private std::variant<
		std::monostate,
		gsl::not_null<WasmFunction* const*>,
		CFunction
	>
{
	using null_function_alt = std::monostate;
	using wasm_function_alt = gsl::not_null<WasmFunction* const*>;
	using c_function_alt = CFunction;
	using variant_type = std::variant<
		null_function_alt,
		wasm_function_alt,
		c_function_alt
	>;

	using variant_type::variant_type;

	AnyFunction() = default;

	AnyFunction(const AnyFunction&) = default;
	AnyFunction(AnyFunction&&) = default;

	AnyFunction& operator=(const AnyFunction&) = default;
	AnyFunction& operator=(AnyFunction&&) = default;

	void emplace_wasm_function(gsl::not_null<wasm_function_alt> func)
	{ as_variant.emplace<wasm_function_alt>(func); }

	void emplace_c_function(CFunction cfunc)
	{ as_variant().emplace<c_function_alt>(std::move(cfunc)); }

	void emplace_null_function()
	{ as_variant().emplace<null_function_type>(std::monostate{}); }

	bool is_wasm_function() const
	{ return std::holds_alternative<wasm_function_alt>(as_variant()); }

	bool is_c_function() const
	{ return std::holds_alternative<c_function_alt>(as_variant()); }

	bool is_null() const
	{ return std::holds_alternative<std::monostate>(as_variant()); }

	const WasmFunction* get_wasm_function() const
	{
		auto f = std::get<wasm_function_alt>(as_variant());
		return *f;
	}

	WasmFunction* get_wasm_function()
	{ return const_cast<WasmFunction*>(get_wasm_function()); }

	c_function_type get_c_function() const
	{ return std::get<c_function_alt>(as_variant()); }

private:
	variant_type& as_variant()
	{ return static_cast<variant_type&>(*this); }

	const variant_type& as_variant() const
	{ return static_cast<const variant_type&>(*this); }

};

} /* namespace wasm */

#endif /* FUNCTION_ANY_FUNCTION_H */


#pragma once

#include <gsl/gsl>
#include "halley/utils/utils.h"
#include "halley/data_structures/vector.h"
#include "halley/file/path.h"
#include "halley/data_structures/maybe.h"

namespace Halley {
	class String;
	class Path;

	class FileSystem
	{
	public:
		static bool exists(const Path& p);
		static bool createDir(const Path& p);
		static bool createParentDir(const Path& p);

		static int64_t getLastWriteTime(const Path& p);
		static bool isFile(const Path& p);
		static bool isDirectory(const Path& p);

		static void copyFile(const Path& src, const Path& dst);
		static bool remove(const Path& path);

		static void writeFile(const Path& path, gsl::span<const gsl::byte> data);
		static void writeFile(const Path& path, const Bytes& data);
		static void writeFile(const Path& path, const String& data);
		static Bytes readFile(const Path& path);

		static Vector<Path> enumerateDirectory(const Path& path);

		static Path getRelative(const Path& path, const Path& parentPath);
		static Path getAbsolute(const Path& path);

		static size_t fileSize(const Path& path);

		static Path getTemporaryPath();

		static int runCommand(const String& command);
	};

	class ScopedTemporaryFile final {
	public:
		ScopedTemporaryFile();
		ScopedTemporaryFile(const String& extension);
		~ScopedTemporaryFile();

		ScopedTemporaryFile(const ScopedTemporaryFile& other) = delete;
		ScopedTemporaryFile(ScopedTemporaryFile&& other) noexcept;
		ScopedTemporaryFile& operator=(const ScopedTemporaryFile& other) = delete;
		ScopedTemporaryFile& operator=(ScopedTemporaryFile&& other) noexcept;

		const Path& getPath() const;

	private:
		std::optional<Path> path;
	};
}


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

#pragma once

#ifndef error_e0b666c0_4caa_4710_bb62_0f8a9d0e579e_h
#define error_e0b666c0_4caa_4710_bb62_0f8a9d0e579e_h

#include <gslib/type.h>

__gslib_begin__

struct errinfo
{
    gchar*      desc;
    gchar*      file;
    int         line;
    void*       user;
};

typedef void* (*error_dump)(void*);
gs_export extern void* error_dump_callstack(void*);

gs_export extern void _set_error(const gchar* desc, error_dump dump, void* user, const gchar* file, int line);
gs_export extern void _set_last_error(const gchar* desc, error_dump dump, void* user, const gchar* file, int line);
gs_export extern void pop_error();
gs_export extern errinfo* get_last_error();
gs_export extern void reset_error();

#ifndef swsc_char
#define swsc_char(x) _t(x)
#endif

#ifdef set_error
#undef set_error
#endif
#define set_error(desc, ...) do { \
    assert(!desc); \
    string str; \
    str.format(desc, __VA_ARGS__); \
    _set_error(str.c_str(), 0, 0, swsc_char(__FILE__), __LINE__); \
} while(0)

#ifdef set_last_error
#undef set_last_error
#endif
#define set_last_error(desc, ...) do { \
    assert(!desc); \
    string str; \
    str.format(desc, _VA_ARGS__); \
    _set_last_error(str.c_str(), 0, 0, swsc_char(__FILE__), __LINE__); \
} while(0)

//gs_export extern void dumperr_file(void);
gs_export extern void trace_hold(const gchar* fmt, ...);
gs_export extern void _trace_to_clipboard();

#ifdef _GS_TRACE_TO_CLIPBOARD
#define trace(fmt, ...) do { trace_hold(fmt, __VA_ARGS__); } while(0)
#define trace_to_clipboard _trace_to_clipboard
#elif defined (DEBUG) || defined (_DEBUG)
gs_export extern void trace(const gchar* fmt, ...);
gs_export extern void trace_all(const gchar* str);
#define trace_to_clipboard __noop
#else
#define trace(fmt, ...) __noop
#define trace_all __noop;
#define trace_to_clipboard __noop
#endif

/* beep an alarm */
gs_export extern void sound_alarm();

__gslib_end__

#endif


#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "boost_coroutine/http_client.h"
#include "callback/http_client.h"
#include "coroutine_ts/http_client.h"
#include "sync/http_client.h"
#include "task/http_client.h"
#include "threaded/http_client.h"

#include "executor.h"

#include <boost/algorithm/string.hpp>

#include <gsl/gsl_util>

#if 1
static inline auto log_msg = std::stringstream{};
#else
static inline auto& log_msg = std::cerr;
#endif

static HttpResponse request_get_impl(std::string_view uri) {
  if (uri == "/file1") {
    return Redirect{"/newplaceoffile1"};
  }
  if (uri == "/newplaceoffile1") {
    return Redirect{"/file2"};
  }
  if (uri == "/file2") {
    return Content{"content1"};
  }
  if (uri == "/file3") {
    return Content{"content2"};
  }
  if (boost::algorithm::starts_with(uri, "/extremeredirect")) {
    std::vector<std::string> parts;
    boost::algorithm::split(parts, uri, [](char c) { return c == '/'; });
    if (parts.size() == 2) {
      return Redirect{std::string{uri} + "/1"};
    }
    if (parts.size() == 3) {
      auto num = std::stol(parts[2]);
      if (num < 4) {
        return Redirect{"/extremeredirect/" + std::to_string(num + 1)};
      }
    }
    return Content{"finally here"};
  }
  return Content{""};
}

namespace synchronous {
class ConcreteHttpClient : public HttpClient {
public:
  HttpResponse request_get(std::string_view uri) override {
    log_msg << "request " << uri << "..." << std::endl;
    auto out
      = gsl::finally([&] { log_msg << "...request " << uri << std::endl; });
    return request_get_impl(uri);
  }
};
}

namespace threaded {
class ConcreteHttpClient : public HttpClient {
public:
  HttpResponse request_get(std::string_view uri) override {
    log_msg << "request " << uri << "..." << std::endl;
    auto out
      = gsl::finally([&] { log_msg << "...request " << uri << std::endl; });
    return request_get_impl(uri);
  }
};
}

namespace callback {

class ConcreteHttpClient : public HttpClient {
public:
  void request_get(const std::string&                       uri,
                   const std::function<void(HttpResponse)>& cb) override {
    log_msg << "request " << uri << "..." << std::endl;
    auto handle = [uri]() -> HttpResponse { return request_get_impl(uri); };
    get_current_executor().add_work([=] {
      log_msg << "...request " << uri << std::endl;
      get_current_executor().add_work([=] { cb(handle()); });
    });
  }
};
}

namespace task_based {

class ConcreteHttpClient : public HttpClient {
public:
  task<HttpResponse> request_get(const std::string& uri) override {
    log_msg << "request " << uri << "..." << std::endl;
    const auto handle
      = [uri]() -> HttpResponse { return request_get_impl(uri); };

    auto fut = make_task<HttpResponse>();
    get_current_executor().add_work([=] {
      log_msg << "...request " << uri << std::endl;

      fut->set_result(handle());
    });
    return fut;
  }
};
}

namespace boost_coroutine {

class ConcreteHttpClient : public HttpClient {
public:
  task<HttpResponse> request_get(const std::string& uri) override {
    log_msg << "request " << uri << "..." << std::endl;
    const auto handle = [=]() -> HttpResponse { return request_get_impl(uri); };

    auto fut = make_task<HttpResponse>();
    get_current_executor().add_work([=] {
      log_msg << "...request " << uri << std::endl;
      fut->set_result(handle());
    });
    return fut;
  }
};
}

namespace coroutines_ts {

class ConcreteHttpClient : public HttpClient {
public:
  task<HttpResponse> request_get(const std::string& uri) override {
    log_msg << "request " << uri << "..." << std::endl;
    const auto handle = [=]() -> HttpResponse { return request_get_impl(uri); };

    auto fut = make_task<HttpResponse>();
    get_current_executor().add_work([=] {
      log_msg << "...request " << uri << std::endl;
      fut->set_result(handle());
    });
    return fut;
  }
};
}


#pragma once

#include "macros.h"

#include <gsl/span>

#include <array>
#include <optional>
#include <string>

namespace linkollector::win {

enum class activity { url, text };

constexpr std::string_view activity_delimiter = "\uedfd";

constexpr std::array<std::byte, activity_delimiter.size()>
    activity_delimiter_bin = []() {
        std::array<std::byte, activity_delimiter.size()> delim = {};
        for (std::size_t i = 0; i < activity_delimiter.size(); ++i) {
            delim.at(i) = static_cast<std::byte>(activity_delimiter[i]);
        }
        return delim;
    }();

[[nodiscard]] std::string activity_to_string(activity activity_) noexcept;

[[nodiscard]] std::wstring activity_to_wstring(activity activity_) noexcept;

[[nodiscard]] std::optional<activity>
activity_from_string(std::string_view activity_) noexcept;

std::optional<std::pair<activity, std::string>>
deserialize(gsl::span<std::byte> msg) noexcept;

} // namespace linkollector::win


/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2018-Present Couchbase, Inc.
 *
 *   Use of this software is governed by the Business Source License included
 *   in the file licenses/BSL-Couchbase.txt.  As of the Change Date specified
 *   in that file, in accordance with the Business Source License, use of this
 *   software will be governed by the Apache License, Version 2.0, included in
 *   the file licenses/APL2.txt.
 */
#pragma once

#include <gsl/gsl-lite.hpp>
#include <nlohmann/json.hpp>
#include <platform/dirutils.h>
#include <vector>

class Event;

/**
 * The Module class represents the configuration for a single module.
 * See ../README.md for more information.
 */
class Module {
public:
    Module() = delete;
    Module(const nlohmann::json& json,
           const std::string& srcRoot,
           const std::string& objRoot);

    void createHeaderFile();

    /**
     * The name of the module
     */
    std::string name;
    /**
     * The lowest identifier for the audit events in this module. All
     * audit descriptor defined for this module MUST be within the range
     * [start, start + max_events_per_module]
     */
    int64_t start;
    /**
     * The name of the file containing the audit descriptors for this
     * module.
     */
    std::string file;
    /**
     * The JSON data describing the audit descriptors for this module
     */
    nlohmann::json json;
    /**
     * Is this module enterprise only?
     */
    bool enterprise = false;

    /**
     * If present this is the name of a C headerfile to generate with
     * #defines for all audit identifiers for the module.
     */
    std::string header;

    /**
     * A list of all of the events defined for this module
     */
    std::vector<std::unique_ptr<Event>> events;

protected:
    /**
     * Add the event to the list of events for the module
     *
     * @param event the event to add
     * @throws std::invalid_argument if the event is outside the legal range
     *                               for the module
     */
    void addEvent(std::unique_ptr<Event> event);

    /// Parse the event descriptor file and add all of the events into
    /// the list of events
    void parseEventDescriptorFile();
};


/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2018 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
#pragma once

#include <gsl/gsl-lite.hpp>
#include <nlohmann/json.hpp>
#include <platform/dirutils.h>
#include <vector>

class Event;

/**
 * The Module class represents the configuration for a single module.
 * See ../README.md for more information.
 */
class Module {
public:
    Module() = delete;
    Module(const nlohmann::json& json,
           const std::string& srcRoot,
           const std::string& objRoot);

    void createHeaderFile();

    /**
     * The name of the module
     */
    std::string name;
    /**
     * The lowest identifier for the audit events in this module. All
     * audit descriptor defined for this module MUST be within the range
     * [start, start + max_events_per_module]
     */
    int64_t start;
    /**
     * The name of the file containing the audit descriptors for this
     * module.
     */
    std::string file;
    /**
     * The JSON data describing the audit descriptors for this module
     */
    nlohmann::json json;
    /**
     * Is this module enterprise only?
     */
    bool enterprise = false;

    /**
     * If present this is the name of a C headerfile to generate with
     * #defines for all audit identifiers for the module.
     */
    std::string header;

    /**
     * A list of all of the events defined for this module
     */
    std::vector<std::unique_ptr<Event>> events;

protected:
    /**
     * Add the event to the list of events for the module
     *
     * @param event the event to add
     * @throws std::invalid_argument if the event is outside the legal range
     *                               for the module
     */
    void addEvent(std::unique_ptr<Event> event);

    /// Parse the event descriptor file and add all of the events into
    /// the list of events
    void parseEventDescriptorFile();
};


/*
 * This module must not depend on any other as it is needed during the startup
 * of pygsl.
 */
#include <Python.h>
#include <gsl/gsl_errno.h>
#include <pygsl/errorno.h>

static int
add_errno(PyObject * dict, int num, char * name)
{
     PyObject * item;

     item = PyInt_FromLong(num);
     if(item == NULL){
	  fprintf(stderr, "Failed to generate PyInt with value %d for errno %s\n",
		  num, name);
	  return -1;
     }
     if(PyDict_SetItemString(dict, name, item) == -1){
	  fprintf(stderr, "Failed to add PyInt %p with value %d to dict %p for errno %s\n",
		  (void *) item, num, (void *) dict, name);
	  return -1;
     }
     return 0;
}
#define ADD_ERRNO(ERRNO, ERRNOSTR) if(add_errno(dict, ERRNO, ERRNOSTR) != 0) goto fail

static PyMethodDef errornoMethods[] = {
     {NULL, NULL, 0, NULL}
};

DL_EXPORT(void) initerrno(void)
{
     PyObject *dict=NULL, *m=NULL;

     m = Py_InitModule("errno", errornoMethods);
     assert(m);

     dict = PyModule_GetDict(m);
     if(!dict)
	  goto fail;

     ADD_ERRNO(GSL_SUCCESS , "GSL_SUCCESS" );
     ADD_ERRNO(GSL_FAILURE , "GSL_FAILURE" );
     ADD_ERRNO(GSL_CONTINUE, "GSL_CONTINUE");
     ADD_ERRNO(GSL_EDOM    , "GSL_EDOM"    );
     ADD_ERRNO(GSL_ERANGE  , "GSL_ERANGE"  );
     ADD_ERRNO(GSL_EFAULT  , "GSL_EFAULT"  );
     ADD_ERRNO(GSL_EINVAL  , "GSL_EINVAL"  );
     ADD_ERRNO(GSL_EFAILED , "GSL_EFAILED" );
     ADD_ERRNO(GSL_EFACTOR , "GSL_EFACTOR" );
     ADD_ERRNO(GSL_ESANITY , "GSL_ESANITY" );
     ADD_ERRNO(GSL_ENOMEM  , "GSL_ENOMEM"  );
     ADD_ERRNO(GSL_EBADFUNC, "GSL_EBADFUNC");
     ADD_ERRNO(GSL_ERUNAWAY, "GSL_ERUNAWAY");
     ADD_ERRNO(GSL_EMAXITER, "GSL_EMAXITER");
     ADD_ERRNO(GSL_EZERODIV, "GSL_EZERODIV");
     ADD_ERRNO(GSL_EBADTOL , "GSL_EBADTOL" );
     ADD_ERRNO(GSL_ETOL    , "GSL_ETOL"    );
     ADD_ERRNO(GSL_EUNDRFLW, "GSL_EUNDRFLW");
     ADD_ERRNO(GSL_EOVRFLW , "GSL_EOVRFLW" );
     ADD_ERRNO(GSL_ELOSS   , "GSL_ELOSS"   );
     ADD_ERRNO(GSL_EROUND  , "GSL_EROUND"  );
     ADD_ERRNO(GSL_EBADLEN , "GSL_EBADLEN" );
     ADD_ERRNO(GSL_ENOTSQR , "GSL_ENOTSQR" );
     ADD_ERRNO(GSL_ESING   , "GSL_ESING"   );
     ADD_ERRNO(GSL_EDIVERGE, "GSL_EDIVERGE");
     ADD_ERRNO(GSL_EUNSUP  , "GSL_EUNSUP"  );
     ADD_ERRNO(GSL_EUNIMPL , "GSL_EUNIMPL" );
     ADD_ERRNO(GSL_ECACHE  , "GSL_ECACHE"  );
     ADD_ERRNO(GSL_ETABLE  , "GSL_ETABLE"  );
     ADD_ERRNO(GSL_ENOPROG , "GSL_ENOPROG" );
     ADD_ERRNO(GSL_ENOPROGJ, "GSL_ENOPROGJ");
     ADD_ERRNO(GSL_ETOLF   , "GSL_ETOLF"   );
     ADD_ERRNO(GSL_ETOLX   , "GSL_ETOLX"   );
     ADD_ERRNO(GSL_ETOLG   , "GSL_ETOLG"   );
     ADD_ERRNO(GSL_EOF     , "GSL_EOF"     );
     ADD_ERRNO(PyGSL_ESTRIDE, "PyGSL_ESTRIDE");

     return;
 fail:
     fprintf(stderr, "Initialisation of module errorno failed!\n");
     return;
}


#pragma once
#include <autograph/Core/Types.h>
#include <gsl/span>
#include <gsl/string_span>

namespace ag
{
	// until a standard solution appears
	using gsl::span;
	using gsl::string_span;
}


#ifndef THREADEDNESS_INCLUDE
#define THREADEDNESS_INCLUDE

#include <string>

#include <gsl/string_span>

#include "config/commandLineOptions.h"
#include "config/fleetingOptionsInterface.h"
#include "config/variablesMap.h"
#include "core/task.h"

namespace execHelper::plugins {
using Jobs = config::Jobs_t;

const gsl::czstring<> JOBS_KEY = "jobs";

/**
 * \brief Extends the functionality to include the _jobs_ config parameter and processes this parameter, using the --jobs flag
 */
struct JobsLong {
    /**
     * Adds the variables for this functionality to the given variables map
     *
     * @param[in] options       The fleeting options to take into account
     * @param[out] variables    The variables map to add the variables to
     */
    static void
    getVariables(config::VariablesMap& variables,
                 const config::FleetingOptionsInterface& options) noexcept;

    /**
     * Applies the given variables to the task
     *
     * @param[in] variables The variables map to use
     * @param[out] task The task with the given variables map applied to it
     */
    inline static void apply(core::Task& task,
                             const config::VariablesMap& variables) noexcept {
        task.append(
            {"--jobs", std::to_string(*(variables.get<Jobs>(JOBS_KEY)))});
    }
};

/**
 * \brief Extends the functionality to include the _jobs_ config parameter and processes this parameter, using the -j flag
 */
struct JobsShort {
    /*! @copydoc JobsLong::getVariables(config::VariablesMap&, const config::FleetingOptionsInterface&)
     */
    inline static void
    getVariables(config::VariablesMap& variables,
                 const config::FleetingOptionsInterface& options) noexcept {
        JobsLong::getVariables(variables, options);
    }

    /*! @copydoc JobsLong::apply(core::Task&, const config::VariablesMap&)
     */
    inline static void apply(core::Task& task,
                             const config::VariablesMap& variables) noexcept {
        task.append({"-j", std::to_string(*(variables.get<Jobs>(JOBS_KEY)))});
    }
};

} // namespace execHelper::plugins

#endif /* THREADEDNESS_INCLUDE */


#pragma once

#include <gsl/gsl>

#include <boost/noncopyable.hpp>

namespace hash_calculator
{

class FileMapper : private boost::noncopyable
{
public:
    FileMapper(int fd, size_t startPosition, size_t maxBufsize);
    ~FileMapper();

    void* getPtr(size_t currentPosition, size_t offset) const;
    void mapping();
    void remapping(size_t startPosition, size_t offset);

private:
    int m_fd;
    size_t m_startPosition;
    size_t m_maxBufsize;
    void* m_ptr;
};

} // hash_calculator


#pragma once
/*
 * (C) Copyright 2020 UCAR
 *
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 */
/// \file Copying.h
/// \brief Generic copying facility
/// \note Feature is under development. This is a placeholder header file.

#include <algorithm>
#include <gsl/gsl-lite.hpp>
#include <memory>
#include <set>
#include <utility>
#include <vector>

#include "ioda/Group.h"
#include "ioda/defs.h"

namespace ioda {
class Group;
class Has_Variables;

class ObjectSelection;
struct ScaleMapping;

/// \todo This function is not yet complete.
///   It exists in its present form to provide the guts for
///   a timing test. Do not use.
/// \brief Generic data copying function
/// \param from contains the objects that we are copying
/// \param to contains the destination(s) of the copy
/// \param scale_map contains settings regarding how dimension scales
///   are propagated
IODA_DL void copy(const ObjectSelection& from, ObjectSelection& to, const ScaleMapping& scale_map);

/// \brief Allows you to select objects for a copy operation
class IODA_DL ObjectSelection {
  // friend IODA_DL void copy(const ObjectSelection&, ObjectSelection&, const ScaleMapping&);
public:
  Group g_;
  bool recurse_ = false;

public:
  ~ObjectSelection();
  ObjectSelection();
  ObjectSelection(const Group& g, bool recurse = true);
  /*
  ObjectSelection(const Variable& v) : ObjectSelection() { insert(v); }
  ObjectSelection(const std::vector<Variable>& v) : ObjectSelection() { insert(v); }
  ObjectSelection(const Has_Variables& v) : ObjectSelection() { insert(v); }
  ObjectSelection(const Group& g, const std::vector<std::string>& v) : ObjectSelection() {
  insert(g,v); }

  void insert(const ObjectSelection&);
  void insert(const Variable&);
  void insert(const std::vector<Variable>&);
  void insert(const Has_Variables&);
  void insert(const Group&, const std::vector<std::string>&);
  void insert(const Group&, bool recurse = true);

  ObjectSelection operator+(const ObjectSelection&) const;
  ObjectSelection operator+(const Variable&) const;
  ObjectSelection operator+(const std::vector<Variable>&) const;
  ObjectSelection operator+(const Has_Variables&) const;
  // Group insertions need to be wrapped by an ObjectSelection.

  ObjectSelection& operator+=(const ObjectSelection&);
  ObjectSelection& operator+=(const Variable&);
  ObjectSelection& operator+=(const std::vector<Variable>&);
  ObjectSelection& operator+=(const Has_Variables&);
  */
};

/// \brief Settings for how to remap dimension scales
struct IODA_DL ScaleMapping {
public:
  ~ScaleMapping();

  std::vector<std::pair<Variable, Variable>> map_from_to;
  std::vector<Variable> map_new;
  bool autocreate = false;
};

}  // namespace ioda


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

#ifndef SQ_INCLUDE_GUARD_core_Token_h_
#define SQ_INCLUDE_GUARD_core_Token_h_

#include "Token.fwd.h"

#include "core/typeutil.h"

#include <gsl/gsl>
#include <iosfwd>
#include <regex>
#include <string_view>
#include <vector>

namespace sq {

enum class TokenKind : int {
  BoolFalse,
  BoolTrue,
  Colon,
  Comma,
  Dot,
  DQString,
  Eof,
  Equals,
  Float,
  GreaterThan,
  GreaterThanOrEqualTo,
  Identifier,
  Integer,
  LBrace,
  LBracket,
  LessThan,
  LessThanOrEqualTo,
  LParen,
  RBrace,
  RBracket,
  RParen
};

class Token {
public:
  /**
   * Create a Token object.
   *
   * @param query the full query string in which the token was found.
   * @param pos the character position within the query at which the token
   *        was found.
   * @param len the length, in characters, of the token.
   * @param kind the kind of the token.
   */
  Token(std::string_view query, gsl::index pos, gsl::index len,
        TokenKind kind) noexcept;

  /**
   * Get the full query string in which the token was found.
   */
  SQ_ND std::string_view query() const noexcept;

  /**
   * Get the character position within the query at which the token was
   * found.
   */
  SQ_ND gsl::index pos() const noexcept;

  /**
   * Get the length, in characters, of the token.
   */
  SQ_ND gsl::index len() const noexcept;

  /**
   * Get a std::string_view pointing to the characters of the token.
   */
  SQ_ND std::string_view view() const noexcept;

  /**
   * Get the kind of the token.
   */
  SQ_ND TokenKind kind() const noexcept;

private:
  std::string_view query_;
  gsl::index pos_;
  gsl::index len_;
  TokenKind kind_;
};

std::ostream &operator<<(std::ostream &os, TokenKind kind);

/**
 * Print information about a token.
 *
 * The text printed includes information about the position of the token in the
 * input query, not just the characters that make up the token.
 */
std::ostream &operator<<(std::ostream &os, const Token &token);

} // namespace sq

#endif // SQ_INCLUDE_GUARD_core_Token_h_


#if !defined(XEOL_H_INCLUDED)
#define XEOL_H_INCLUDED

#include "FileEnumerator.h"
#include "Utils.h"

#include <filesystem>
#include <gsl/gsl>
#include <iosfwd>
#include <string>

class Xeol
{
public:
	static int usage(::std::ostream& strm, const ::std::string& progName,
		const char* pMsg);

	Xeol(::gsl::span<const char*const> args);
	int run() const;

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

PRIVATE_EXCEPT_IN_TEST:
	/// \brief EolType contains the enum constants that indicate the type of
	/// end-of-line for a text file.
	enum class EolType
	{
		INDETERMINATE, ///< File contains no ends-of-line
		MIXED, ///< Inconsistent end-of-line convention, may be binary
		DOS, ///< End-of-line is "\r\n"
		MACINTOSH, ///< End-of-line is "\r" (now archaic)
		UNIX ///< End-of-line is "\n"
	};

	using Path = ::std::filesystem::path;

	void queryFile(const Path& p) const;
	void translateFile(const Path& p) const;
	static char getIndicatorLetter(EolType eolType);
	static ::std::string toEolString(EolType eolType);
	static ::std::string displayPath(const Path& p);

	/// \brief Scans the input file, counts the end-of-line types, and
	/// optionally translates the ends-of-line into the provided stream.
	///
	/// If pOut is null, then the method simply counts the end-of-line types and
	/// returns the corresponding EolType constant.  In this case, the
	/// targetEolType parameter is ignored.
	///
	/// If pOut is not null, then the method additionally translates the file
	/// into *pOut.  In this case, targetEolType must be one of DOS, MACINTOSH,
	/// or UNIX.
	static EolType scanFile(::std::istream& in,
		/* out */ size_t& numDosEols, /* out */ size_t& numMacEols,
		/* out */ size_t& numUnixEols, /* out */ size_t& totalEols,
		::std::ostream* pOut = nullptr, EolType targetEolType = EolType::INDETERMINATE);

	static void replaceOriginalFileWithTemp(const Path& originalPath,
		const Path& tempPath);

	bool				m_isInQueryMode;
	EolType			m_targetEolType;
	bool				m_forceTranslation;
	FileEnumerator	m_fileEnumerator;
};

#endif // XEOL_H_INCLUDED