<commit_before>#include <cstring>

#include "../uri/parse-query.hh"
#include "../uri/percent-encoding.hh"
#include "../stream/buffer.hh"
#include "request-reader.hh"

namespace mimosa
{
  namespace http
  {
    RequestReader::RequestReader(stream::Stream::Ptr stream,
                                 runtime::Time       read_timeout)
      : stream_(stream),
        bytes_left_(0),
        parsed_form_(false),
        form_(),
        read_timeout_(read_timeout)
    {
    }

    void
    RequestReader::clear()
    {
      bytes_left_ = 0;
      parsed_form_ = false;
      form_.clear();
    }

    bool
    RequestReader::prepare()
    {
      if (contentLength() < 0)
        return false;
      bytes_left_ = contentLength();
      return true;
    }

    int64_t
    RequestReader::write(const char * /*data*/, uint64_t /*nbytes*/, runtime::Time /*timeout*/)
    {
      assert(false && "invalid operation");
      return -1;
    }

    int64_t
    RequestReader::read(char * data, uint64_t nbytes, runtime::Time timeout)
    {
      uint64_t can_read = nbytes <= bytes_left_ ? nbytes : bytes_left_;
      int64_t rbytes = stream_->read(data, can_read, timeout);
      if (rbytes > 0)
        bytes_left_ -= rbytes;
      return rbytes;
    }

    bool
    RequestReader::flush(runtime::Time timeout)
    {
      stream::Buffer buffer;
      while (bytes_left_ > 0)
        if (read(buffer.data(), buffer.size(), timeout) <= 0)
          return false;
      return true;
    }

    container::kvs &
    RequestReader::form()
    {
      if (parsed_form_)
        return form_;

      if (!::strcasecmp(contentType().c_str(), "application/x-www-form-urlencoded"))
      {
        parsed_form_ = true;
        stream::Buffer buffer(contentLength());
        int64_t total_rbytes = 0;

        while (total_rbytes < contentLength())
        {
          auto rbytes = stream_->read(buffer.data(), contentLength() - total_rbytes, 0);
          if (rbytes <= 0)
            return form_;
          total_rbytes += rbytes;
        }

        std::string decoded;
        uri::percentDecode(buffer.data(), buffer.size(), &decoded, uri::kRfc2396);
        uri::parseQuery(decoded.data(), decoded.size(), &form_);
      }

      return form_;
    }
  }
}
<commit_msg>http: better RequestReader::flush()<commit_after>#include <cstring>

#include "../uri/parse-query.hh"
#include "../uri/percent-encoding.hh"
#include "../stream/buffer.hh"
#include "request-reader.hh"

namespace mimosa
{
  namespace http
  {
    RequestReader::RequestReader(stream::Stream::Ptr stream,
                                 runtime::Time       read_timeout)
      : stream_(stream),
        bytes_left_(0),
        parsed_form_(false),
        form_(),
        read_timeout_(read_timeout)
    {
    }

    void
    RequestReader::clear()
    {
      bytes_left_ = 0;
      parsed_form_ = false;
      form_.clear();
    }

    bool
    RequestReader::prepare()
    {
      if (contentLength() < 0)
        return false;
      bytes_left_ = contentLength();
      return true;
    }

    int64_t
    RequestReader::write(const char * /*data*/, uint64_t /*nbytes*/, runtime::Time /*timeout*/)
    {
      assert(false && "invalid operation");
      return -1;
    }

    int64_t
    RequestReader::read(char * data, uint64_t nbytes, runtime::Time timeout)
    {
      uint64_t can_read = nbytes <= bytes_left_ ? nbytes : bytes_left_;
      int64_t rbytes = stream_->read(data, can_read, timeout);
      if (rbytes > 0)
        bytes_left_ -= rbytes;
      return rbytes;
    }

    bool
    RequestReader::flush(runtime::Time timeout)
    {
      if (bytes_left_ < 0)
        return true;

      stream::Buffer buffer(bytes_left_);
      while (bytes_left_ > 0)
        if (read(buffer.data(), buffer.size(), timeout) <= 0)
          return false;
      return true;
    }

    container::kvs &
    RequestReader::form()
    {
      if (parsed_form_)
        return form_;

      if (!::strcasecmp(contentType().c_str(), "application/x-www-form-urlencoded"))
      {
        parsed_form_ = true;
        stream::Buffer buffer(contentLength());
        int64_t total_rbytes = 0;

        while (total_rbytes < contentLength())
        {
          auto rbytes = stream_->read(buffer.data(), contentLength() - total_rbytes, 0);
          if (rbytes <= 0)
            return form_;
          total_rbytes += rbytes;
        }

        std::string decoded;
        uri::percentDecode(buffer.data(), buffer.size(), &decoded, uri::kRfc2396);
        uri::parseQuery(decoded.data(), decoded.size(), &form_);
      }

      return form_;
    }
  }
}
<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
// Copyright (c) 2014 Francois Beaune, The appleseedhq Organization
//
// 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.
//

// Interface header.
#include "latlongmapenvironmentedf.h"

// appleseed.renderer headers.
#include "renderer/global/globallogger.h"
#include "renderer/global/globaltypes.h"
#include "renderer/kernel/lighting/imageimportancesampler.h"
#include "renderer/kernel/texturing/texturecache.h"
#include "renderer/kernel/texturing/texturestore.h"
#include "renderer/modeling/environmentedf/environmentedf.h"
#include "renderer/modeling/environmentedf/sphericalcoordinates.h"
#include "renderer/modeling/input/inputarray.h"
#include "renderer/modeling/input/inputevaluator.h"
#include "renderer/modeling/input/source.h"
#include "renderer/modeling/input/texturesource.h"
#include "renderer/modeling/project/project.h"
#include "renderer/modeling/scene/scene.h"
#include "renderer/modeling/scene/textureinstance.h"
#include "renderer/modeling/texture/texture.h"
#include "renderer/utility/paramarray.h"

// appleseed.foundation headers.
#include "foundation/image/canvasproperties.h"
#include "foundation/image/color.h"
#include "foundation/image/colorspace.h"
#include "foundation/math/sampling.h"
#include "foundation/math/scalar.h"
#include "foundation/math/vector.h"
#include "foundation/platform/compiler.h"
#include "foundation/platform/types.h"
#include "foundation/utility/containers/dictionary.h"
#include "foundation/utility/job/abortswitch.h"

// Standard headers.
#include <cassert>
#include <cmath>
#include <cstddef>
#include <memory>

using namespace foundation;
using namespace std;

namespace renderer
{

namespace
{
    //
    // Latitude-longitude environment map EDF.
    //
    // Reference:
    //
    //   http://www.cs.virginia.edu/~gfx/courses/2007/ImageSynthesis/assignments/envsample.pdf
    //
    // Light probes:
    //
    //   http://gl.ict.usc.edu/Data/HighResProbes/
    //   http://www.cs.kuleuven.be/~graphics/index.php/environment-maps
    //

    struct Payload
    {
        uint32      m_x;
        Color3f     m_color;
    };

    typedef ImageImportanceSampler<Payload, double> ImageImportanceSamplerType;

    class ImageSampler
    {
      public:
        ImageSampler(
            TextureCache&   texture_cache,
            const Source*   radiance_source,
            const Source*   multiplier_source,
            const size_t    width,
            const size_t    height,
            const double    u_shift,
            const double    v_shift)
          : m_texture_cache(texture_cache)
          , m_radiance_source(radiance_source)
          , m_multiplier_source(multiplier_source)
          , m_rcp_width(1.0 / width)
          , m_rcp_height(1.0 / height)
          , m_u_shift(u_shift)
          , m_v_shift(v_shift)
        {
        }

        void sample(const size_t x, const size_t y, Payload& payload, double& importance)
        {
            payload.m_x = static_cast<uint32>(x);

            if (m_radiance_source == 0)
            {
                payload.m_color.set(0.0f);
                importance = 0.0;
                return;
            }

            const Vector2d uv(
                (x + 0.5) * m_rcp_width + m_u_shift,
                1.0 - (y + 0.5) * m_rcp_height + m_v_shift);

            m_radiance_source->evaluate(m_texture_cache, uv, payload.m_color);

            double multiplier;
            m_multiplier_source->evaluate(m_texture_cache, uv, multiplier);
            payload.m_color *= static_cast<float>(multiplier);

            importance = static_cast<double>(luminance(payload.m_color));
        }

      private:
        TextureCache&   m_texture_cache;
        const Source*   m_radiance_source;
        const Source*   m_multiplier_source;
        const double    m_rcp_width;
        const double    m_rcp_height;
        const double    m_u_shift;
        const double    m_v_shift;
    };

    const char* Model = "latlong_map_environment_edf";

    class LatLongMapEnvironmentEDF
      : public EnvironmentEDF
    {
      public:
        LatLongMapEnvironmentEDF(
            const char*         name,
            const ParamArray&   params)
          : EnvironmentEDF(name, params)
          , m_importance_map_width(0)
          , m_importance_map_height(0)
          , m_probability_scale(0.0)
        {
            m_inputs.declare("radiance", InputFormatSpectralIlluminance);
            m_inputs.declare("radiance_multiplier", InputFormatScalar, "1.0");

            m_u_shift = m_params.get_optional<double>("horizontal_shift", 0.0) / 360.0;
            m_v_shift = m_params.get_optional<double>("vertical_shift", 0.0) / 360.0;
        }

        virtual void release() APPLESEED_OVERRIDE
        {
            delete this;
        }

        virtual const char* get_model() const APPLESEED_OVERRIDE
        {
            return Model;
        }

        virtual bool on_frame_begin(
            const Project&      project,
            IAbortSwitch*       abort_switch) APPLESEED_OVERRIDE
        {
            if (!EnvironmentEDF::on_frame_begin(project, abort_switch))
                return false;

            check_non_zero_emission("radiance", "radiance_multiplier");

            if (m_importance_sampler.get() == 0)
                build_importance_map(*project.get_scene(), abort_switch);

            return true;
        }

        virtual void sample(
            InputEvaluator&     input_evaluator,
            const Vector2d&     s,
            Vector3d&           outgoing,
            Spectrum&           value,
            double&             probability) const APPLESEED_OVERRIDE
        {
            // Sample the importance map.
            Payload payload;
            size_t y;
            double prob_xy;
            m_importance_sampler->sample(s, payload, y, prob_xy);

            // Compute the coordinates in [0,1]^2 of the sample.
            const double u = (payload.m_x + 0.5) * m_rcp_importance_map_width;
            const double v = (y + 0.5) * m_rcp_importance_map_height;

            // Compute the world space emission direction.
            double theta, phi;
            unit_square_to_angles(u, v, theta, phi);
            outgoing = Vector3d::unit_vector(theta, phi);

            // Return the emitted radiance.
            value = payload.m_color;

            // Compute the probability density of this direction.
            probability = prob_xy * m_probability_scale / sin(theta);
        }

        virtual void evaluate(
            InputEvaluator&     input_evaluator,
            const Vector3d&     outgoing,
            Spectrum&           value) const APPLESEED_OVERRIDE
        {
            assert(is_normalized(outgoing));

            double theta, phi;
            unit_vector_to_angles(outgoing, theta, phi);

            double u, v;
            angles_to_unit_square(theta, phi, u, v);

            lookup_environment_map(input_evaluator, u, v, value);
        }

        virtual void evaluate(
            InputEvaluator&     input_evaluator,
            const Vector3d&     outgoing,
            Spectrum&           value,
            double&             probability) const APPLESEED_OVERRIDE
        {
            assert(is_normalized(outgoing));

            double theta, phi;
            unit_vector_to_angles(outgoing, theta, phi);

            double u, v;
            angles_to_unit_square(theta, phi, u, v);

            lookup_environment_map(input_evaluator, u, v, value);

            probability = compute_pdf(u, v, theta);
        }

        virtual double evaluate_pdf(
            InputEvaluator&     input_evaluator,
            const Vector3d&     outgoing) const APPLESEED_OVERRIDE
        {
            assert(is_normalized(outgoing));

            double theta, phi;
            unit_vector_to_angles(outgoing, theta, phi);

            double u, v;
            angles_to_unit_square(theta, phi, u, v);

            return compute_pdf(u, v, theta);
        }

      private:
        APPLESEED_DECLARE_INPUT_VALUES(InputValues)
        {
            Spectrum    m_radiance;             // emitted radiance in W.m^-2.sr^-1
            double      m_radiance_multiplier;  // emitted radiance multiplier
        };

        double  m_u_shift;
        double  m_v_shift;

        size_t  m_importance_map_width;
        size_t  m_importance_map_height;

        double  m_rcp_importance_map_width;
        double  m_rcp_importance_map_height;
        double  m_probability_scale;

        auto_ptr<ImageImportanceSamplerType>    m_importance_sampler;

        void build_importance_map(const Scene& scene, IAbortSwitch*abort_switch)
        {
            const Source* radiance_source = m_inputs.source("radiance");
            assert(radiance_source);

            if (dynamic_cast<const TextureSource*>(radiance_source))
            {
                const TextureSource* texture_source = static_cast<const TextureSource*>(radiance_source);
                const TextureInstance& texture_instance = texture_source->get_texture_instance();
                const CanvasProperties& texture_props = texture_instance.get_texture().properties();

                m_importance_map_width = texture_props.m_canvas_width;
                m_importance_map_height = texture_props.m_canvas_height;
            }
            else
            {
                RENDERER_LOG_ERROR(
                    "while building importance map for environment edf \"%s\": a texture instance "
                    "must be bound to the \"radiance\" input.",
                    get_name());

                m_importance_map_width = 1;
                m_importance_map_height = 1;
            }

            m_rcp_importance_map_width = 1.0 / m_importance_map_width;
            m_rcp_importance_map_height = 1.0 / m_importance_map_height;

            const size_t texel_count = m_importance_map_width * m_importance_map_height;
            m_probability_scale = texel_count / (2.0 * Pi * Pi);

            TextureStore texture_store(scene);
            TextureCache texture_cache(texture_store);
            ImageSampler sampler(
                texture_cache,
                radiance_source,
                m_inputs.source("radiance_multiplier"),
                m_importance_map_width,
                m_importance_map_height,
                m_u_shift,
                m_v_shift);

            m_importance_sampler.reset(
                new ImageImportanceSamplerType(
                    m_importance_map_width,
                    m_importance_map_height));

            RENDERER_LOG_INFO(
                "building " FMT_SIZE_T "x" FMT_SIZE_T " importance map "
                "for environment edf \"%s\"...",
                m_importance_map_width,
                m_importance_map_height,
                get_name());

            m_importance_sampler->rebuild(sampler, abort_switch);

            if (is_aborted(abort_switch))
                m_importance_sampler.reset();
            else
            {
                RENDERER_LOG_INFO(
                    "built importance map for environment edf \"%s\".",
                    get_name());
            }
        }

        void lookup_environment_map(
            InputEvaluator&     input_evaluator,
            const double        u,
            const double        v,
            Spectrum&           value) const
        {
            const Vector2d uv(u + m_u_shift, 1.0 - v + m_v_shift);

            const InputValues* values =
                input_evaluator.evaluate<InputValues>(m_inputs, uv);

            value = values->m_radiance;
            value *= static_cast<float>(values->m_radiance_multiplier);
        }

        double compute_pdf(
            const double        u,
            const double        v,
            const double        theta) const
        {
            // Compute the probability density of this sample in the importance map.
            const size_t x = truncate<size_t>(m_importance_map_width * u);
            const size_t y = truncate<size_t>(m_importance_map_height * v);
            const double prob_xy = m_importance_sampler->get_pdf(x, y);

            // Compute the probability density of the emission direction.
            return prob_xy * m_probability_scale / sin(theta);
        }
    };
}

//
// LatLongMapEnvironmentEDFFactory class implementation.
//

const char* LatLongMapEnvironmentEDFFactory::get_model() const
{
    return Model;
}

const char* LatLongMapEnvironmentEDFFactory::get_human_readable_model() const
{
    return "Latitude-Longitude Map Environment EDF";
}

DictionaryArray LatLongMapEnvironmentEDFFactory::get_input_metadata() const
{
    DictionaryArray metadata;

    metadata.push_back(
        Dictionary()
            .insert("name", "radiance")
            .insert("label", "Radiance")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary()
                    .insert("texture_instance", "Textures"))
            .insert("use", "required")
            .insert("default", "1.0"));

    metadata.push_back(
        Dictionary()
            .insert("name", "radiance_multiplier")
            .insert("label", "Radiance Multiplier")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary().insert("texture_instance", "Textures"))
            .insert("use", "optional")
            .insert("default", "1.0"));

    metadata.push_back(
        Dictionary()
            .insert("name", "horizontal_shift")
            .insert("label", "Horizontal Shift")
            .insert("type", "numeric")
            .insert("min_value", "-360.0")
            .insert("max_value", "360.0")
            .insert("default", "0.0")
            .insert("use", "optional"));

    metadata.push_back(
        Dictionary()
            .insert("name", "vertical_shift")
            .insert("label", "Vertical Shift")
            .insert("type", "numeric")
            .insert("min_value", "-360.0")
            .insert("max_value", "360.0")
            .insert("default", "0.0")
            .insert("use", "optional"));

    return metadata;
}

auto_release_ptr<EnvironmentEDF> LatLongMapEnvironmentEDFFactory::create(
    const char*         name,
    const ParamArray&   params) const
{
    return
        auto_release_ptr<EnvironmentEDF>(
            new LatLongMapEnvironmentEDF(name, params));
}

}   // namespace renderer
<commit_msg>small performance optimization.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
// Copyright (c) 2014 Francois Beaune, The appleseedhq Organization
//
// 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.
//

// Interface header.
#include "latlongmapenvironmentedf.h"

// appleseed.renderer headers.
#include "renderer/global/globallogger.h"
#include "renderer/global/globaltypes.h"
#include "renderer/kernel/lighting/imageimportancesampler.h"
#include "renderer/kernel/texturing/texturecache.h"
#include "renderer/kernel/texturing/texturestore.h"
#include "renderer/modeling/environmentedf/environmentedf.h"
#include "renderer/modeling/environmentedf/sphericalcoordinates.h"
#include "renderer/modeling/input/inputarray.h"
#include "renderer/modeling/input/inputevaluator.h"
#include "renderer/modeling/input/source.h"
#include "renderer/modeling/input/texturesource.h"
#include "renderer/modeling/project/project.h"
#include "renderer/modeling/scene/scene.h"
#include "renderer/modeling/scene/textureinstance.h"
#include "renderer/modeling/texture/texture.h"
#include "renderer/utility/paramarray.h"

// appleseed.foundation headers.
#include "foundation/image/canvasproperties.h"
#include "foundation/image/color.h"
#include "foundation/image/colorspace.h"
#include "foundation/math/sampling.h"
#include "foundation/math/scalar.h"
#include "foundation/math/vector.h"
#include "foundation/platform/compiler.h"
#include "foundation/platform/types.h"
#include "foundation/utility/containers/dictionary.h"
#include "foundation/utility/job/abortswitch.h"

// Standard headers.
#include <cassert>
#include <cmath>
#include <cstddef>
#include <memory>

using namespace foundation;
using namespace std;

namespace renderer
{

namespace
{
    //
    // Latitude-longitude environment map EDF.
    //
    // Reference:
    //
    //   http://www.cs.virginia.edu/~gfx/courses/2007/ImageSynthesis/assignments/envsample.pdf
    //
    // Light probes:
    //
    //   http://gl.ict.usc.edu/Data/HighResProbes/
    //   http://www.cs.kuleuven.be/~graphics/index.php/environment-maps
    //

    struct Payload
    {
        uint32  m_x;
        Color3f m_color;
    };

    typedef ImageImportanceSampler<Payload, double> ImageImportanceSamplerType;

    class ImageSampler
    {
      public:
        ImageSampler(
            TextureCache&   texture_cache,
            const Source*   radiance_source,
            const Source*   multiplier_source,
            const size_t    width,
            const size_t    height,
            const double    u_shift,
            const double    v_shift)
          : m_texture_cache(texture_cache)
          , m_radiance_source(radiance_source)
          , m_multiplier_source(multiplier_source)
          , m_rcp_width(1.0 / width)
          , m_rcp_height(1.0 / height)
          , m_u_shift(u_shift)
          , m_v_shift(v_shift)
        {
        }

        void sample(const size_t x, const size_t y, Payload& payload, double& importance)
        {
            payload.m_x = static_cast<uint32>(x);

            if (m_radiance_source == 0)
            {
                payload.m_color.set(0.0f);
                importance = 0.0;
                return;
            }

            const Vector2d uv(
                (x + 0.5) * m_rcp_width + m_u_shift,
                1.0 - (y + 0.5) * m_rcp_height + m_v_shift);

            m_radiance_source->evaluate(m_texture_cache, uv, payload.m_color);

            double multiplier;
            m_multiplier_source->evaluate(m_texture_cache, uv, multiplier);
            payload.m_color *= static_cast<float>(multiplier);

            importance = static_cast<double>(luminance(payload.m_color));
        }

      private:
        TextureCache&   m_texture_cache;
        const Source*   m_radiance_source;
        const Source*   m_multiplier_source;
        const double    m_rcp_width;
        const double    m_rcp_height;
        const double    m_u_shift;
        const double    m_v_shift;
    };

    const char* Model = "latlong_map_environment_edf";

    class LatLongMapEnvironmentEDF
      : public EnvironmentEDF
    {
      public:
        LatLongMapEnvironmentEDF(
            const char*         name,
            const ParamArray&   params)
          : EnvironmentEDF(name, params)
          , m_importance_map_width(0)
          , m_importance_map_height(0)
          , m_probability_scale(0.0)
        {
            m_inputs.declare("radiance", InputFormatSpectralIlluminance);
            m_inputs.declare("radiance_multiplier", InputFormatScalar, "1.0");

            m_u_shift = m_params.get_optional<double>("horizontal_shift", 0.0) / 360.0;
            m_v_shift = m_params.get_optional<double>("vertical_shift", 0.0) / 360.0;
        }

        virtual void release() APPLESEED_OVERRIDE
        {
            delete this;
        }

        virtual const char* get_model() const APPLESEED_OVERRIDE
        {
            return Model;
        }

        virtual bool on_frame_begin(
            const Project&      project,
            IAbortSwitch*       abort_switch) APPLESEED_OVERRIDE
        {
            if (!EnvironmentEDF::on_frame_begin(project, abort_switch))
                return false;

            check_non_zero_emission("radiance", "radiance_multiplier");

            if (m_importance_sampler.get() == 0)
                build_importance_map(*project.get_scene(), abort_switch);

            return true;
        }

        virtual void sample(
            InputEvaluator&     input_evaluator,
            const Vector2d&     s,
            Vector3d&           outgoing,
            Spectrum&           value,
            double&             probability) const APPLESEED_OVERRIDE
        {
            // Sample the importance map.
            Payload payload;
            size_t y;
            double prob_xy;
            m_importance_sampler->sample(s, payload, y, prob_xy);

            // Compute the coordinates in [0,1]^2 of the sample.
            const double u = (payload.m_x + 0.5) * m_rcp_importance_map_width;
            const double v = (y + 0.5) * m_rcp_importance_map_height;

            // Compute the world space emission direction.
            double theta, phi;
            unit_square_to_angles(u, v, theta, phi);
            const double cos_theta = cos(theta);
            const double sin_theta = sin(theta);
            const double cos_phi = cos(phi);
            const double sin_phi = sin(phi);
            outgoing = Vector3d::unit_vector(cos_theta, sin_theta, cos_phi, sin_phi);

            // Return the emitted radiance.
            value = payload.m_color;

            // Compute the probability density of this direction.
            probability = prob_xy * m_probability_scale / sin_theta;
        }

        virtual void evaluate(
            InputEvaluator&     input_evaluator,
            const Vector3d&     outgoing,
            Spectrum&           value) const APPLESEED_OVERRIDE
        {
            assert(is_normalized(outgoing));

            double theta, phi;
            unit_vector_to_angles(outgoing, theta, phi);

            double u, v;
            angles_to_unit_square(theta, phi, u, v);

            lookup_environment_map(input_evaluator, u, v, value);
        }

        virtual void evaluate(
            InputEvaluator&     input_evaluator,
            const Vector3d&     outgoing,
            Spectrum&           value,
            double&             probability) const APPLESEED_OVERRIDE
        {
            assert(is_normalized(outgoing));

            double theta, phi;
            unit_vector_to_angles(outgoing, theta, phi);

            double u, v;
            angles_to_unit_square(theta, phi, u, v);

            lookup_environment_map(input_evaluator, u, v, value);

            probability = compute_pdf(u, v, theta);
        }

        virtual double evaluate_pdf(
            InputEvaluator&     input_evaluator,
            const Vector3d&     outgoing) const APPLESEED_OVERRIDE
        {
            assert(is_normalized(outgoing));

            double theta, phi;
            unit_vector_to_angles(outgoing, theta, phi);

            double u, v;
            angles_to_unit_square(theta, phi, u, v);

            return compute_pdf(u, v, theta);
        }

      private:
        APPLESEED_DECLARE_INPUT_VALUES(InputValues)
        {
            Spectrum    m_radiance;             // emitted radiance in W.m^-2.sr^-1
            double      m_radiance_multiplier;  // emitted radiance multiplier
        };

        double  m_u_shift;
        double  m_v_shift;

        size_t  m_importance_map_width;
        size_t  m_importance_map_height;

        double  m_rcp_importance_map_width;
        double  m_rcp_importance_map_height;
        double  m_probability_scale;

        auto_ptr<ImageImportanceSamplerType>    m_importance_sampler;

        void build_importance_map(const Scene& scene, IAbortSwitch*abort_switch)
        {
            const Source* radiance_source = m_inputs.source("radiance");
            assert(radiance_source);

            if (dynamic_cast<const TextureSource*>(radiance_source))
            {
                const TextureSource* texture_source = static_cast<const TextureSource*>(radiance_source);
                const TextureInstance& texture_instance = texture_source->get_texture_instance();
                const CanvasProperties& texture_props = texture_instance.get_texture().properties();

                m_importance_map_width = texture_props.m_canvas_width;
                m_importance_map_height = texture_props.m_canvas_height;
            }
            else
            {
                RENDERER_LOG_ERROR(
                    "while building importance map for environment edf \"%s\": a texture instance "
                    "must be bound to the \"radiance\" input.",
                    get_name());

                m_importance_map_width = 1;
                m_importance_map_height = 1;
            }

            m_rcp_importance_map_width = 1.0 / m_importance_map_width;
            m_rcp_importance_map_height = 1.0 / m_importance_map_height;

            const size_t texel_count = m_importance_map_width * m_importance_map_height;
            m_probability_scale = texel_count / (2.0 * Pi * Pi);

            TextureStore texture_store(scene);
            TextureCache texture_cache(texture_store);
            ImageSampler sampler(
                texture_cache,
                radiance_source,
                m_inputs.source("radiance_multiplier"),
                m_importance_map_width,
                m_importance_map_height,
                m_u_shift,
                m_v_shift);

            m_importance_sampler.reset(
                new ImageImportanceSamplerType(
                    m_importance_map_width,
                    m_importance_map_height));

            RENDERER_LOG_INFO(
                "building " FMT_SIZE_T "x" FMT_SIZE_T " importance map "
                "for environment edf \"%s\"...",
                m_importance_map_width,
                m_importance_map_height,
                get_name());

            m_importance_sampler->rebuild(sampler, abort_switch);

            if (is_aborted(abort_switch))
                m_importance_sampler.reset();
            else
            {
                RENDERER_LOG_INFO(
                    "built importance map for environment edf \"%s\".",
                    get_name());
            }
        }

        void lookup_environment_map(
            InputEvaluator&     input_evaluator,
            const double        u,
            const double        v,
            Spectrum&           value) const
        {
            const Vector2d uv(u + m_u_shift, 1.0 - v + m_v_shift);

            const InputValues* values =
                input_evaluator.evaluate<InputValues>(m_inputs, uv);

            value = values->m_radiance;
            value *= static_cast<float>(values->m_radiance_multiplier);
        }

        double compute_pdf(
            const double        u,
            const double        v,
            const double        theta) const
        {
            // Compute the probability density of this sample in the importance map.
            const size_t x = truncate<size_t>(m_importance_map_width * u);
            const size_t y = truncate<size_t>(m_importance_map_height * v);
            const double prob_xy = m_importance_sampler->get_pdf(x, y);

            // Compute the probability density of the emission direction.
            return prob_xy * m_probability_scale / sin(theta);
        }
    };
}

//
// LatLongMapEnvironmentEDFFactory class implementation.
//

const char* LatLongMapEnvironmentEDFFactory::get_model() const
{
    return Model;
}

const char* LatLongMapEnvironmentEDFFactory::get_human_readable_model() const
{
    return "Latitude-Longitude Map Environment EDF";
}

DictionaryArray LatLongMapEnvironmentEDFFactory::get_input_metadata() const
{
    DictionaryArray metadata;

    metadata.push_back(
        Dictionary()
            .insert("name", "radiance")
            .insert("label", "Radiance")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary()
                    .insert("texture_instance", "Textures"))
            .insert("use", "required")
            .insert("default", "1.0"));

    metadata.push_back(
        Dictionary()
            .insert("name", "radiance_multiplier")
            .insert("label", "Radiance Multiplier")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary().insert("texture_instance", "Textures"))
            .insert("use", "optional")
            .insert("default", "1.0"));

    metadata.push_back(
        Dictionary()
            .insert("name", "horizontal_shift")
            .insert("label", "Horizontal Shift")
            .insert("type", "numeric")
            .insert("min_value", "-360.0")
            .insert("max_value", "360.0")
            .insert("default", "0.0")
            .insert("use", "optional"));

    metadata.push_back(
        Dictionary()
            .insert("name", "vertical_shift")
            .insert("label", "Vertical Shift")
            .insert("type", "numeric")
            .insert("min_value", "-360.0")
            .insert("max_value", "360.0")
            .insert("default", "0.0")
            .insert("use", "optional"));

    return metadata;
}

auto_release_ptr<EnvironmentEDF> LatLongMapEnvironmentEDFFactory::create(
    const char*         name,
    const ParamArray&   params) const
{
    return
        auto_release_ptr<EnvironmentEDF>(
            new LatLongMapEnvironmentEDF(name, params));
}

}   // namespace renderer
<|endoftext|>


<commit_before><commit_msg>Fix loss scaling when running ORTTrainer with BERT under mixed-precision mode (#6932)<commit_after><|endoftext|>


<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2015 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/base/ring_buffer.h"

#include <algorithm>
#include <cstring>

namespace xe {

RingBuffer::RingBuffer(uint8_t* buffer, size_t capacity)
    : buffer_(buffer), capacity_(capacity) {}

RingBuffer::ReadRange RingBuffer::BeginRead(size_t count) {
  count = std::min(count, capacity_);
  if (!count) {
    return {0};
  }
  if (read_offset_ + count < capacity_) {
    return {buffer_ + read_offset_, count, nullptr, 0};
  } else {
    size_t left_half = capacity_ - read_offset_;
    size_t right_half = count - left_half;
    return {buffer_ + read_offset_, left_half, buffer_, right_half};
  }
}

void RingBuffer::EndRead(ReadRange read_range) {
  if (read_range.second_length) {
    read_offset_ = read_range.second_length;
  } else {
    read_offset_ += read_range.first_length;
  }
}

size_t RingBuffer::Read(uint8_t* buffer, size_t count) {
  count = std::min(count, capacity_);
  if (!count) {
    return 0;
  }

  if (read_offset_ + count < capacity_) {
    std::memcpy(buffer, buffer_ + read_offset_, count);
    read_offset_ += count;
  } else {
    size_t left_half = capacity_ - read_offset_;
    size_t right_half = count - left_half;
    std::memcpy(buffer, buffer_ + read_offset_, left_half);
    std::memcpy(buffer + left_half, buffer_, right_half);
    read_offset_ = right_half;
  }

  return count;
}

size_t RingBuffer::Write(const uint8_t* buffer, size_t count) {
  count = std::min(count, capacity_);
  if (!count) {
    return 0;
  }

  if (write_offset_ + count < capacity_) {
    std::memcpy(buffer_ + write_offset_, buffer, count);
    write_offset_ += count;
  } else {
    size_t left_half = capacity_ - write_offset_;
    size_t right_half = count - left_half;
    std::memcpy(buffer_ + write_offset_, buffer, left_half);
    std::memcpy(buffer_, buffer + left_half, right_half);
    write_offset_ = right_half;
  }

  return count;
}

}  // namespace xe
<commit_msg>Fix RingBuffer::EndRead not detecting a split read (where second length == 0)<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2015 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/base/ring_buffer.h"

#include <algorithm>
#include <cstring>

namespace xe {

RingBuffer::RingBuffer(uint8_t* buffer, size_t capacity)
    : buffer_(buffer), capacity_(capacity) {}

RingBuffer::ReadRange RingBuffer::BeginRead(size_t count) {
  count = std::min(count, capacity_);
  if (!count) {
    return {0};
  }
  if (read_offset_ + count < capacity_) {
    return {buffer_ + read_offset_, count, nullptr, 0};
  } else {
    size_t left_half = capacity_ - read_offset_;
    size_t right_half = count - left_half;
    return {buffer_ + read_offset_, left_half, buffer_, right_half};
  }
}

void RingBuffer::EndRead(ReadRange read_range) {
  if (read_range.second) {
    read_offset_ = read_range.second_length;
  } else {
    read_offset_ += read_range.first_length;
  }
}

size_t RingBuffer::Read(uint8_t* buffer, size_t count) {
  count = std::min(count, capacity_);
  if (!count) {
    return 0;
  }

  if (read_offset_ + count < capacity_) {
    std::memcpy(buffer, buffer_ + read_offset_, count);
    read_offset_ += count;
  } else {
    size_t left_half = capacity_ - read_offset_;
    size_t right_half = count - left_half;
    std::memcpy(buffer, buffer_ + read_offset_, left_half);
    std::memcpy(buffer + left_half, buffer_, right_half);
    read_offset_ = right_half;
  }

  return count;
}

size_t RingBuffer::Write(const uint8_t* buffer, size_t count) {
  count = std::min(count, capacity_);
  if (!count) {
    return 0;
  }

  if (write_offset_ + count < capacity_) {
    std::memcpy(buffer_ + write_offset_, buffer, count);
    write_offset_ += count;
  } else {
    size_t left_half = capacity_ - write_offset_;
    size_t right_half = count - left_half;
    std::memcpy(buffer_ + write_offset_, buffer, left_half);
    std::memcpy(buffer_, buffer + left_half, right_half);
    write_offset_ = right_half;
  }

  return count;
}

}  // namespace xe
<|endoftext|>


<commit_before>/**
 * @file AddingImages.cpp
 * @brief Simple linear blender ( dst = alpha*src1 + beta*src2 )
 * @author OpenCV team
 */

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>

using namespace cv;

/**
 * @function main
 * @brief Main function
 */
int main( void )
{
   double alpha = 0.5; double beta; double input;

   Mat src1, src2, dst;

   /// Ask the user enter alpha
   std::cout<<" Simple Linear Blender "<<std::endl;
   std::cout<<"-----------------------"<<std::endl;
   std::cout<<"* Enter alpha [0-1]: ";
   std::cin>>input;

   // We use the alpha provided by the user if it is between 0 and 1
   if( alpha >= 0 && alpha <= 1 )
     { alpha = input; }

   //![load]
   /// Read images ( both have to be of the same size and type )
   src1 = imread("../data/LinuxLogo.jpg");
   src2 = imread("../data/WindowsLogo.jpg");
   //![load]

   if( src1.empty() ) { std::cout<< "Error loading src1"<<std::endl; return -1; }
   if( src2.empty() ) { std::cout<< "Error loading src2"<<std::endl; return -1; }

   //![blend_images]
   beta = ( 1.0 - alpha );
   addWeighted( src1, alpha, src2, beta, 0.0, dst);
   //![blend_images]

   //![display]
   imshow( "Linear Blend", dst );
   waitKey(0);
   //![display]

   return 0;
}
<commit_msg>Update AddingImages.cpp<commit_after>/**
 * @file AddingImages.cpp
 * @brief Simple linear blender ( dst = alpha*src1 + beta*src2 )
 * @author OpenCV team
 */

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>

using namespace cv;

/**
 * @function main
 * @brief Main function
 */
int main( void )
{
   double alpha = 0.5; double beta; double input;

   Mat src1, src2, dst;

   /// Ask the user enter alpha
   std::cout<<" Simple Linear Blender "<<std::endl;
   std::cout<<"-----------------------"<<std::endl;
   std::cout<<"* Enter alpha [0-1]: ";
   std::cin>>input;

   // We use the alpha provided by the user if it is between 0 and 1
   if( input >= 0 && input <= 1 )
     { alpha = input; }

   //![load]
   /// Read images ( both have to be of the same size and type )
   src1 = imread("../data/LinuxLogo.jpg");
   src2 = imread("../data/WindowsLogo.jpg");
   //![load]

   if( src1.empty() ) { std::cout<< "Error loading src1"<<std::endl; return -1; }
   if( src2.empty() ) { std::cout<< "Error loading src2"<<std::endl; return -1; }

   //![blend_images]
   beta = ( 1.0 - alpha );
   addWeighted( src1, alpha, src2, beta, 0.0, dst);
   //![blend_images]

   //![display]
   imshow( "Linear Blend", dst );
   waitKey(0);
   //![display]

   return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************/
/*  gdnative.cpp                                                         */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                    http://www.godotengine.org                         */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* 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.                */
/*************************************************************************/
#include "gdnative.h"

#include "global_constants.h"
#include "io/file_access_encrypted.h"
#include "os/file_access.h"
#include "os/os.h"
#include "project_settings.h"

#include "scene/main/scene_tree.h"

const String init_symbol = "godot_gdnative_init";
const String terminate_symbol = "godot_gdnative_terminate";

String GDNativeLibrary::platform_names[NUM_PLATFORMS] = {
	"X11_32bit",
	"X11_64bit",
	"Windows_32bit",
	"Windows_64bit",
	"OSX",

	"Android",
	"iOS",

	"WebAssembly"
};
String GDNativeLibrary::platform_lib_ext[NUM_PLATFORMS] = {
	"so",
	"so",
	"dll",
	"dll",
	"dylib",

	"so",
	"dylib",

	"wasm"
};

// TODO(karroffel): make this actually do something lol.
GDNativeLibrary::Platform GDNativeLibrary::current_platform = X11_64BIT;

GDNativeLibrary::GDNativeLibrary()
	: library_paths() {
}

GDNativeLibrary::~GDNativeLibrary() {
}

void GDNativeLibrary::_bind_methods() {
	ClassDB::bind_method(D_METHOD("set_library_path", "platform", "path"), &GDNativeLibrary::set_library_path);
	ClassDB::bind_method(D_METHOD("get_library_path", "platform"), &GDNativeLibrary::get_library_path);
}

bool GDNativeLibrary::_set(const StringName &p_name, const Variant &p_value) {
	String name = p_name;
	if (name.begins_with("platform/")) {
		set_library_path(name.get_slice("/", 1), p_value);
		return true;
	}
	return false;
}

bool GDNativeLibrary::_get(const StringName &p_name, Variant &r_ret) const {
	String name = p_name;
	if (name.begins_with("platform/")) {
		r_ret = get_library_path(name.get_slice("/", 1));
		return true;
	}
	return false;
}

void GDNativeLibrary::_get_property_list(List<PropertyInfo> *p_list) const {
	for (int i = 0; i < NUM_PLATFORMS; i++) {
		p_list->push_back(PropertyInfo(Variant::STRING,
				"platform/" + platform_names[i],
				PROPERTY_HINT_FILE,
				"*." + platform_lib_ext[i]));
	}
}

void GDNativeLibrary::set_library_path(StringName p_platform, String p_path) {
	int i;
	for (i = 0; i <= NUM_PLATFORMS; i++) {
		if (i == NUM_PLATFORMS) break;
		if (platform_names[i] == p_platform) {
			break;
		}
	}

	if (i == NUM_PLATFORMS) {
		ERR_EXPLAIN(String("No such platform: ") + p_platform);
		ERR_FAIL();
	}

	library_paths[i] = p_path;
}

String GDNativeLibrary::get_library_path(StringName p_platform) const {
	int i;
	for (i = 0; i <= NUM_PLATFORMS; i++) {
		if (i == NUM_PLATFORMS) break;
		if (platform_names[i] == p_platform) {
			break;
		}
	}

	if (i == NUM_PLATFORMS) {
		ERR_EXPLAIN(String("No such platform: ") + p_platform);
		ERR_FAIL_V("");
	}

	return library_paths[i];
}

String GDNativeLibrary::get_active_library_path() const {
	return library_paths[GDNativeLibrary::current_platform];
}

GDNative::GDNative() {
	initialized = false;
	native_handle = NULL;
}

GDNative::~GDNative() {
	// TODO(karroffel): implement ALL the things!
}

extern "C" void _api_anchor();

void GDNative::_compile_dummy_for_api() {
	_api_anchor();
}

void GDNative::_bind_methods() {
	ClassDB::bind_method(D_METHOD("set_library", "library:GDNativeLibrary"), &GDNative::set_library);
	ClassDB::bind_method(D_METHOD("get_library:GDNativeLibrary"), &GDNative::get_library);

	ClassDB::bind_method(D_METHOD("initialize"), &GDNative::initialize);
	ClassDB::bind_method(D_METHOD("terminate"), &GDNative::terminate);

	// TODO(karroffel): get_native_(raw_)call_types binding?

	// TODO(karroffel): make this a varargs function?
	ClassDB::bind_method(D_METHOD("call_native:Variant", "procedure_name", "arguments:Array"), &GDNative::call_native);

	ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library");
}

void GDNative::set_library(Ref<GDNativeLibrary> p_library) {
	library = p_library;
}

Ref<GDNativeLibrary> GDNative::get_library() {
	return library;
}

bool GDNative::initialize() {
	if (library.is_null()) {
		ERR_PRINT("No library set, can't initialize GDNative object");
		return false;
	}

	String lib_path = library->get_active_library_path();
	if (lib_path.empty()) {
		ERR_PRINT("No library set for this platform");
		return false;
	}

	String path = ProjectSettings::get_singleton()->globalize_path(lib_path);
	Error err = OS::get_singleton()->open_dynamic_library(path, native_handle);
	if (err != OK) {
		return false;
	}

	void *library_init;
	err = OS::get_singleton()->get_dynamic_library_symbol_handle(
			native_handle,
			init_symbol,
			library_init);

	if (err || !library_init) {
		return false;
	}

	godot_gdnative_init_fn library_init_fpointer;
	library_init_fpointer = (godot_gdnative_init_fn)library_init;

	godot_gdnative_init_options options;

	options.in_editor = SceneTree::get_singleton()->is_editor_hint();
	options.core_api_hash = ClassDB::get_api_hash(ClassDB::API_CORE);
	options.editor_api_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR);
	options.no_api_hash = ClassDB::get_api_hash(ClassDB::API_NONE);

	library_init_fpointer(&options);

	return true;
}

bool GDNative::terminate() {

	if (native_handle == NULL) {
		ERR_PRINT("No valid library handle, can't terminate GDNative object");
		return false;
	}

	Error error = OK;
	void *library_terminate;
	error = OS::get_singleton()->get_dynamic_library_symbol_handle(
			native_handle,
			terminate_symbol,
			library_terminate);
	if (error) {
		OS::get_singleton()->close_dynamic_library(native_handle);
		native_handle = NULL;
		return true;
	}

	godot_gdnative_terminate_fn library_terminate_pointer;
	library_terminate_pointer = (godot_gdnative_terminate_fn)library_terminate;

	// TODO(karroffel): remove this? Should be part of NativeScript, not
	// GDNative IMO
	godot_gdnative_terminate_options options;
	options.in_editor = SceneTree::get_singleton()->is_editor_hint();

	library_terminate_pointer(&options);

	// GDNativeScriptLanguage::get_singleton()->initialized_libraries.erase(p_native_lib->path);

	OS::get_singleton()->close_dynamic_library(native_handle);
	native_handle = NULL;

	return false;
}

void GDNativeCallRegistry::register_native_call_type(StringName p_call_type, native_call_cb p_callback) {
	native_calls.insert(p_call_type, p_callback);
}

void GDNativeCallRegistry::register_native_raw_call_type(StringName p_raw_call_type, native_raw_call_cb p_callback) {
	native_raw_calls.insert(p_raw_call_type, p_callback);
}

Vector<StringName> GDNativeCallRegistry::get_native_call_types() {
	Vector<StringName> call_types;
	call_types.resize(native_calls.size());

	size_t idx = 0;
	for (Map<StringName, native_call_cb>::Element *E = native_calls.front(); E; E = E->next(), idx++) {
		call_types[idx] = E->key();
	}

	return call_types;
}

Vector<StringName> GDNativeCallRegistry::get_native_raw_call_types() {
	Vector<StringName> call_types;
	call_types.resize(native_raw_calls.size());

	size_t idx = 0;
	for (Map<StringName, native_raw_call_cb>::Element *E = native_raw_calls.front(); E; E = E->next(), idx++) {
		call_types[idx] = E->key();
	}

	return call_types;
}

Variant GDNative::call_native(StringName p_native_call_type, StringName p_procedure_name, Array p_arguments) {

	Map<StringName, native_call_cb>::Element *E = GDNativeCallRegistry::singleton->native_calls.find(p_native_call_type);
	if (!E) {
		ERR_PRINT((String("No handler for native call type \"" + p_native_call_type) + "\" found").utf8().get_data());
		return Variant();
	}

	String procedure_name = p_procedure_name;
	godot_variant result = E->get()(native_handle, (godot_string *)&procedure_name, (godot_array *)&p_arguments);

	return *(Variant *)&result;
}

void GDNative::call_native_raw(StringName p_raw_call_type, StringName p_procedure_name, void *data, int num_args, void **args, void *r_return) {

	Map<StringName, native_raw_call_cb>::Element *E = GDNativeCallRegistry::singleton->native_raw_calls.find(p_raw_call_type);
	if (!E) {
		ERR_PRINT((String("No handler for native raw call type \"" + p_raw_call_type) + "\" found").utf8().get_data());
		return;
	}

	String procedure_name = p_procedure_name;
	E->get()(native_handle, (godot_string *)&procedure_name, data, num_args, args, r_return);
}
<commit_msg>[GDNative] basic OS detection<commit_after>/*************************************************************************/
/*  gdnative.cpp                                                         */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                    http://www.godotengine.org                         */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* 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.                */
/*************************************************************************/
#include "gdnative.h"

#include "global_constants.h"
#include "io/file_access_encrypted.h"
#include "os/file_access.h"
#include "os/os.h"
#include "project_settings.h"

#include "scene/main/scene_tree.h"

const String init_symbol = "godot_gdnative_init";
const String terminate_symbol = "godot_gdnative_terminate";

String GDNativeLibrary::platform_names[NUM_PLATFORMS] = {
	"X11_32bit",
	"X11_64bit",
	"Windows_32bit",
	"Windows_64bit",
	"OSX",

	"Android",
	"iOS",

	"WebAssembly"
};
String GDNativeLibrary::platform_lib_ext[NUM_PLATFORMS] = {
	"so",
	"so",
	"dll",
	"dll",
	"dylib",

	"so",
	"dylib",

	"wasm"
};

// TODO(karroffel): make this actually do the right thing.
GDNativeLibrary::Platform GDNativeLibrary::current_platform =
#if defined(X11_ENABLED)
		X11_64BIT;
#elif defined(WINDOWS_ENABLED)
		WINDOWS_64BIT;
#elif defined(OSX_ENABLED)
		OSX;
#else
		X11_64BIT; // need a sensible default..
#endif

GDNativeLibrary::GDNativeLibrary()
	: library_paths() {
}

GDNativeLibrary::~GDNativeLibrary() {
}

void GDNativeLibrary::_bind_methods() {
	ClassDB::bind_method(D_METHOD("set_library_path", "platform", "path"), &GDNativeLibrary::set_library_path);
	ClassDB::bind_method(D_METHOD("get_library_path", "platform"), &GDNativeLibrary::get_library_path);
}

bool GDNativeLibrary::_set(const StringName &p_name, const Variant &p_value) {
	String name = p_name;
	if (name.begins_with("platform/")) {
		set_library_path(name.get_slice("/", 1), p_value);
		return true;
	}
	return false;
}

bool GDNativeLibrary::_get(const StringName &p_name, Variant &r_ret) const {
	String name = p_name;
	if (name.begins_with("platform/")) {
		r_ret = get_library_path(name.get_slice("/", 1));
		return true;
	}
	return false;
}

void GDNativeLibrary::_get_property_list(List<PropertyInfo> *p_list) const {
	for (int i = 0; i < NUM_PLATFORMS; i++) {
		p_list->push_back(PropertyInfo(Variant::STRING,
				"platform/" + platform_names[i],
				PROPERTY_HINT_FILE,
				"*." + platform_lib_ext[i]));
	}
}

void GDNativeLibrary::set_library_path(StringName p_platform, String p_path) {
	int i;
	for (i = 0; i <= NUM_PLATFORMS; i++) {
		if (i == NUM_PLATFORMS) break;
		if (platform_names[i] == p_platform) {
			break;
		}
	}

	if (i == NUM_PLATFORMS) {
		ERR_EXPLAIN(String("No such platform: ") + p_platform);
		ERR_FAIL();
	}

	library_paths[i] = p_path;
}

String GDNativeLibrary::get_library_path(StringName p_platform) const {
	int i;
	for (i = 0; i <= NUM_PLATFORMS; i++) {
		if (i == NUM_PLATFORMS) break;
		if (platform_names[i] == p_platform) {
			break;
		}
	}

	if (i == NUM_PLATFORMS) {
		ERR_EXPLAIN(String("No such platform: ") + p_platform);
		ERR_FAIL_V("");
	}

	return library_paths[i];
}

String GDNativeLibrary::get_active_library_path() const {
	return library_paths[GDNativeLibrary::current_platform];
}

GDNative::GDNative() {
	initialized = false;
	native_handle = NULL;
}

GDNative::~GDNative() {
	// TODO(karroffel): implement ALL the things!
}

extern "C" void _api_anchor();

void GDNative::_compile_dummy_for_api() {
	_api_anchor();
}

void GDNative::_bind_methods() {
	ClassDB::bind_method(D_METHOD("set_library", "library:GDNativeLibrary"), &GDNative::set_library);
	ClassDB::bind_method(D_METHOD("get_library:GDNativeLibrary"), &GDNative::get_library);

	ClassDB::bind_method(D_METHOD("initialize"), &GDNative::initialize);
	ClassDB::bind_method(D_METHOD("terminate"), &GDNative::terminate);

	// TODO(karroffel): get_native_(raw_)call_types binding?

	// TODO(karroffel): make this a varargs function?
	ClassDB::bind_method(D_METHOD("call_native:Variant", "procedure_name", "arguments:Array"), &GDNative::call_native);

	ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library");
}

void GDNative::set_library(Ref<GDNativeLibrary> p_library) {
	library = p_library;
}

Ref<GDNativeLibrary> GDNative::get_library() {
	return library;
}

bool GDNative::initialize() {
	if (library.is_null()) {
		ERR_PRINT("No library set, can't initialize GDNative object");
		return false;
	}

	String lib_path = library->get_active_library_path();
	if (lib_path.empty()) {
		ERR_PRINT("No library set for this platform");
		return false;
	}

	String path = ProjectSettings::get_singleton()->globalize_path(lib_path);
	Error err = OS::get_singleton()->open_dynamic_library(path, native_handle);
	if (err != OK) {
		return false;
	}

	void *library_init;
	err = OS::get_singleton()->get_dynamic_library_symbol_handle(
			native_handle,
			init_symbol,
			library_init);

	if (err || !library_init) {
		return false;
	}

	godot_gdnative_init_fn library_init_fpointer;
	library_init_fpointer = (godot_gdnative_init_fn)library_init;

	godot_gdnative_init_options options;

	options.in_editor = SceneTree::get_singleton()->is_editor_hint();
	options.core_api_hash = ClassDB::get_api_hash(ClassDB::API_CORE);
	options.editor_api_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR);
	options.no_api_hash = ClassDB::get_api_hash(ClassDB::API_NONE);

	library_init_fpointer(&options);

	return true;
}

bool GDNative::terminate() {

	if (native_handle == NULL) {
		ERR_PRINT("No valid library handle, can't terminate GDNative object");
		return false;
	}

	Error error = OK;
	void *library_terminate;
	error = OS::get_singleton()->get_dynamic_library_symbol_handle(
			native_handle,
			terminate_symbol,
			library_terminate);
	if (error) {
		OS::get_singleton()->close_dynamic_library(native_handle);
		native_handle = NULL;
		return true;
	}

	godot_gdnative_terminate_fn library_terminate_pointer;
	library_terminate_pointer = (godot_gdnative_terminate_fn)library_terminate;

	// TODO(karroffel): remove this? Should be part of NativeScript, not
	// GDNative IMO
	godot_gdnative_terminate_options options;
	options.in_editor = SceneTree::get_singleton()->is_editor_hint();

	library_terminate_pointer(&options);

	// GDNativeScriptLanguage::get_singleton()->initialized_libraries.erase(p_native_lib->path);

	OS::get_singleton()->close_dynamic_library(native_handle);
	native_handle = NULL;

	return false;
}

void GDNativeCallRegistry::register_native_call_type(StringName p_call_type, native_call_cb p_callback) {
	native_calls.insert(p_call_type, p_callback);
}

void GDNativeCallRegistry::register_native_raw_call_type(StringName p_raw_call_type, native_raw_call_cb p_callback) {
	native_raw_calls.insert(p_raw_call_type, p_callback);
}

Vector<StringName> GDNativeCallRegistry::get_native_call_types() {
	Vector<StringName> call_types;
	call_types.resize(native_calls.size());

	size_t idx = 0;
	for (Map<StringName, native_call_cb>::Element *E = native_calls.front(); E; E = E->next(), idx++) {
		call_types[idx] = E->key();
	}

	return call_types;
}

Vector<StringName> GDNativeCallRegistry::get_native_raw_call_types() {
	Vector<StringName> call_types;
	call_types.resize(native_raw_calls.size());

	size_t idx = 0;
	for (Map<StringName, native_raw_call_cb>::Element *E = native_raw_calls.front(); E; E = E->next(), idx++) {
		call_types[idx] = E->key();
	}

	return call_types;
}

Variant GDNative::call_native(StringName p_native_call_type, StringName p_procedure_name, Array p_arguments) {

	Map<StringName, native_call_cb>::Element *E = GDNativeCallRegistry::singleton->native_calls.find(p_native_call_type);
	if (!E) {
		ERR_PRINT((String("No handler for native call type \"" + p_native_call_type) + "\" found").utf8().get_data());
		return Variant();
	}

	String procedure_name = p_procedure_name;
	godot_variant result = E->get()(native_handle, (godot_string *)&procedure_name, (godot_array *)&p_arguments);

	return *(Variant *)&result;
}

void GDNative::call_native_raw(StringName p_raw_call_type, StringName p_procedure_name, void *data, int num_args, void **args, void *r_return) {

	Map<StringName, native_raw_call_cb>::Element *E = GDNativeCallRegistry::singleton->native_raw_calls.find(p_raw_call_type);
	if (!E) {
		ERR_PRINT((String("No handler for native raw call type \"" + p_raw_call_type) + "\" found").utf8().get_data());
		return;
	}

	String procedure_name = p_procedure_name;
	E->get()(native_handle, (godot_string *)&procedure_name, data, num_args, args, r_return);
}
<|endoftext|>


<commit_before>#/** \ingroup kernel
* \{
*
* \file kernel/memory_map.hpp
* \brief This file defines the memory map used by the
*        kernel as well as some auxilliary types.
*/

#ifndef H_kernel_memory
#define H_kernel_memory

#include <common/types.hpp>

#include "dynarray.hpp"
#include "debug.hpp"
#include "constants.hpp"

#include <memory_resource>
#include <algorithm>

namespace UtopiaOS
{
    namespace kernel
    {
        /** \enum memory_type
         * \brief Analogous to the UEFI memory type
         *        but contains only types the kernel
         *        actually knows about.
         */
        enum class memory_type : common::uint32
        {
            general_purpose,
            unusable
        };

        /** \struct memory_request
         * \brief Encapsulates a memory requirement
         */
        struct memory_request
        {
            common::uint64 size;
            common::un alignment;
        };

        /** \brief Aligns a pointer to a given alignment.
         * \param[in] ptr The pointer to align
         * \param[in] alignment The alignment to meet
         * \returns An aligned pointer or 0 if the pointer
         *          could not be aligned.
         *
         * The aligned pointer is guaranteed to point to
         * an address not smaller than the original pointer.
         * It is guaranteed that there is no other aligned
         * address in the range [\a ptr, \a return-value].
         * If the pointer cannot be aligned, i.e it points
         * to an address so large that the next aligned
         * address would not fit into the data type,
         * 0 is returned.
         *
         * \warning If \a alignment is not a power of two,
         *          the behaviour is undefined!
         */
        static inline common::uintptr align( common::uintptr ptr, common::un alignment )
        {
            static_assert( sizeof(common::uintptr) >= sizeof(common::un),
                          "This implementation cannot guarantee to work." );
            debug_assert( (alignment % 2) == 0, "alignment has to be a power of two" );

            common::un mask = alignment - 1; // ...0000011111...
            common::un diff = (ptr & mask);

            if( diff == 0 )
                return ptr;

            return (ptr + alignment - diff);
        }

        /** \struct memory_descriptor
         * \brief Analogous to a UEFI memory descriptor,
         *        but usable by the kernel. It also has
         *        a well-defined size.
         */
        struct memory_descriptor
        {
            memory_type type;
            common::uint64 physical_start;
            common::uint64 virtual_start;
            common::uint64 number_of_pages;

            /** \brief Construct a kernel-usable memory
             *         descriptor from a UEFI one.
             */
            memory_descriptor( const UEFI::memory_descriptor_v1 &uefi_desc );

            /** \brief Checks whether
            bool can_meet_request( const memory_request &request ) const
            {
                static_assert( sizeof(common::uintptr) >= sizeof(common::un),
                              "This implementation cannot guarantee to work." );
                if( type != memory_type::general_purpose )
                    return false;

                auto aligned_address = align( virtual_start, request.alignment );
                common::uintptr request_end = aligned_address + request.size;

                if( (request_end - virtual_start) / pagesize <= number_of_pages )
                    return true;

                return false;
            }
        };

        /** \class memory_map
         * \brief The memory map used by the kernel
         * \tparam Allocator The type of allocator to use
         *
         * It has some sanity guarantees that UEFI lacks, like:
         * - fixed size of descriptors that is known compile-time
         * - no overlaps
         * - The memory descriptors always describe regions that
         *   are as large as possible, with lower ones always being
         *   full in a case of ambiguity.
         */
        template<class Allocator>
        class memory_map
        {
        public:
            using allocator_type = Allocator;
        private:
            using desc_array = dynarray<memory_descriptor, allocator_type>;
            desc_array descriptors;

            /** \brief Convert a uefi memory map to a
             *         kernel-usable one.
             * \param[in] uefi_map The UEFI memory map
             * \param[in] The allocator to use
             * \returns An array of descriptors with the guarantee
             *          that they do not overlap.
             */
            static desc_array
            convert_from_uefi( const UEFI::memory_map &uefi_map, allocator_type &&alloc )
            {
                desc_array stage1_descriptors( uefi_map.cbegin_v1(),
                                              uefi_map.cend_v1(),
                                              std::forward<allocator_type>( alloc ) );

                /** \todo Now remedy all possible overlaps and
                 *        any unnecessary fragmentation
                 */
            }
        public:
            /** \brief Returns a memory_request that when fulfilled
             *         will suffice to convert a UEFI memory map
             *         to a kernel-usable one.
             * \param[in] uefi_map The UEFI memory map
             * \returns The memory_request
             */
            static memory_request maximum_conversion_requirement( const UEFI::memory_map &uefi_map )
            {
                return memory_request{ uefi_map.number_of_descriptors * sizeof(memory_descriptor),
                    alignof(memory_descriptor) };
            }

            /** \brief Returns a memory_request that when fulfilled
             *         will suffice to copy the memory map.
             * \returns The memory_request
             */
            memory_request copy_requirement( void ) const
            {
                return memory_request{ descriptors.size() * sizeof(memory_descriptor),
                    alignof(memory_descriptor) };
            }

            /** \brief Constructs a kernel-usable memory map
             *         from a UEFI memory map.
             * \param[in] uefi_map The UEFI memory map
             * \param[in] alloc The allocator used to copy the
             *                  memory map. It has to be able to
             *                  allocate at least what is returned
             *                  by \a maximum_conversion_requirement.
             */
            memory_map( const UEFI::memory_map &uefi_map, allocator_type &&alloc )
            : descriptors( convert_from_uefi( uefi_map,
                                             std::forward<allocator_type>( alloc ) ) )
            {}

            /** \brief Returns a const iterator to the begin of
             *         the memory descriptor range.
             * \returns A const iterator to the begin of
             *          the memory descriptor range
             */
            typename desc_array::const_iterator cbegin( void ) const
            { return descriptors.cbegin(); }

            /** \brief Returns a const iterator to the end of
             *         the memory descriptor range.
             * \returns A const iterator to the end of
             *          the memory descriptor range
             */
            typename desc_array::const_iterator cend( void ) const
            { return descriptors.cend(); }
        };
    }
}

#endif

/** \} */
<commit_msg>Fixed incomplete comment (doxygen documentation).<commit_after>#/** \ingroup kernel
* \{
*
* \file kernel/memory_map.hpp
* \brief This file defines the memory map used by the
*        kernel as well as some auxilliary types.
*/

#ifndef H_kernel_memory
#define H_kernel_memory

#include <common/types.hpp>

#include "dynarray.hpp"
#include "debug.hpp"
#include "constants.hpp"

#include <memory_resource>
#include <algorithm>

namespace UtopiaOS
{
    namespace kernel
    {
        /** \enum memory_type
         * \brief Analogous to the UEFI memory type
         *        but contains only types the kernel
         *        actually knows about.
         */
        enum class memory_type : common::uint32
        {
            general_purpose,
            unusable
        };

        /** \struct memory_request
         * \brief Encapsulates a memory requirement
         */
        struct memory_request
        {
            common::uint64 size;
            common::un alignment;
        };

        /** \brief Aligns a pointer to a given alignment.
         * \param[in] ptr The pointer to align
         * \param[in] alignment The alignment to meet
         * \returns An aligned pointer or 0 if the pointer
         *          could not be aligned.
         *
         * The aligned pointer is guaranteed to point to
         * an address not smaller than the original pointer.
         * It is guaranteed that there is no other aligned
         * address in the range [\a ptr, \a return-value].
         * If the pointer cannot be aligned, i.e it points
         * to an address so large that the next aligned
         * address would not fit into the data type,
         * 0 is returned.
         *
         * \warning If \a alignment is not a power of two,
         *          the behaviour is undefined!
         */
        static inline common::uintptr align( common::uintptr ptr, common::un alignment )
        {
            static_assert( sizeof(common::uintptr) >= sizeof(common::un),
                          "This implementation cannot guarantee to work." );
            debug_assert( (alignment % 2) == 0, "alignment has to be a power of two" );

            common::un mask = alignment - 1; // ...0000011111...
            common::un diff = (ptr & mask);

            if( diff == 0 )
                return ptr;

            return (ptr + alignment - diff);
        }

        /** \struct memory_descriptor
         * \brief Analogous to a UEFI memory descriptor,
         *        but usable by the kernel. It also has
         *        a well-defined size.
         */
        struct memory_descriptor
        {
            memory_type type;
            common::uint64 physical_start;
            common::uint64 virtual_start;
            common::uint64 number_of_pages;

            /** \brief Construct a kernel-usable memory
             *         descriptor from a UEFI one.
             */
            memory_descriptor( const UEFI::memory_descriptor_v1 &uefi_desc );

            /** \brief Checks whether the memory described by
             *         the memory descriptor can be used to
             *         fulfil a memory request.
             * \returns \a true if the request can be fulfilled
             *          and \a false otherwise.
             */
            bool can_meet_request( const memory_request &request ) const
            {
                static_assert( sizeof(common::uintptr) >= sizeof(common::un),
                              "This implementation cannot guarantee to work." );
                if( type != memory_type::general_purpose )
                    return false;

                auto aligned_address = align( virtual_start, request.alignment );
                common::uintptr request_end = aligned_address + request.size;

                if( (request_end - virtual_start) / pagesize <= number_of_pages )
                    return true;

                return false;
            }
        };

        /** \class memory_map
         * \brief The memory map used by the kernel
         * \tparam Allocator The type of allocator to use
         *
         * It has some sanity guarantees that UEFI lacks, like:
         * - fixed size of descriptors that is known compile-time
         * - no overlaps
         * - The memory descriptors always describe regions that
         *   are as large as possible, with lower ones always being
         *   full in a case of ambiguity.
         */
        template<class Allocator>
        class memory_map
        {
        public:
            using allocator_type = Allocator;
        private:
            using desc_array = dynarray<memory_descriptor, allocator_type>;
            desc_array descriptors;

            /** \brief Convert a uefi memory map to a
             *         kernel-usable one.
             * \param[in] uefi_map The UEFI memory map
             * \param[in] The allocator to use
             * \returns An array of descriptors with the guarantee
             *          that they do not overlap.
             */
            static desc_array
            convert_from_uefi( const UEFI::memory_map &uefi_map, allocator_type &&alloc )
            {
                desc_array stage1_descriptors( uefi_map.cbegin_v1(),
                                              uefi_map.cend_v1(),
                                              std::forward<allocator_type>( alloc ) );

                /** \todo Now remedy all possible overlaps and
                 *        any unnecessary fragmentation
                 */
            }
        public:
            /** \brief Returns a memory_request that when fulfilled
             *         will suffice to convert a UEFI memory map
             *         to a kernel-usable one.
             * \param[in] uefi_map The UEFI memory map
             * \returns The memory_request
             */
            static memory_request maximum_conversion_requirement( const UEFI::memory_map &uefi_map )
            {
                return memory_request{ uefi_map.number_of_descriptors * sizeof(memory_descriptor),
                    alignof(memory_descriptor) };
            }

            /** \brief Returns a memory_request that when fulfilled
             *         will suffice to copy the memory map.
             * \returns The memory_request
             */
            memory_request copy_requirement( void ) const
            {
                return memory_request{ descriptors.size() * sizeof(memory_descriptor),
                    alignof(memory_descriptor) };
            }

            /** \brief Constructs a kernel-usable memory map
             *         from a UEFI memory map.
             * \param[in] uefi_map The UEFI memory map
             * \param[in] alloc The allocator used to copy the
             *                  memory map. It has to be able to
             *                  allocate at least what is returned
             *                  by \a maximum_conversion_requirement.
             */
            memory_map( const UEFI::memory_map &uefi_map, allocator_type &&alloc )
            : descriptors( convert_from_uefi( uefi_map,
                                             std::forward<allocator_type>( alloc ) ) )
            {}

            /** \brief Returns a const iterator to the begin of
             *         the memory descriptor range.
             * \returns A const iterator to the begin of
             *          the memory descriptor range
             */
            typename desc_array::const_iterator cbegin( void ) const
            { return descriptors.cbegin(); }

            /** \brief Returns a const iterator to the end of
             *         the memory descriptor range.
             * \returns A const iterator to the end of
             *          the memory descriptor range
             */
            typename desc_array::const_iterator cend( void ) const
            { return descriptors.cend(); }
        };
    }
}

#endif

/** \} */
<|endoftext|>