<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef BENG_PROXY_FILE_ADDRESS_HXX
#define BENG_PROXY_FILE_ADDRESS_HXX

#include "spawn/ChildOptions.hxx"
#include "util/ConstBuffer.hxx"

#include "util/Compiler.h"

class AllocatorPtr;
class MatchInfo;
struct DelegateAddress;

/**
 * The address of a local static file.
 */
struct FileAddress {
    const char *path;
    const char *deflated = nullptr;
    const char *gzipped = nullptr;

    const char *content_type = nullptr;

    ConstBuffer<void> content_type_lookup = nullptr;

    const char *document_root = nullptr;

    /**
     * The value of #TRANSLATE_EXPAND_PATH.  Only used by the
     * translation cache.
     */
    const char *expand_path = nullptr;

    /**
     * The value of #TRANSLATE_EXPAND_DOCUMENT_ROOT.  Only used by the
     * translation cache.
     */
    const char *expand_document_root = nullptr;

    DelegateAddress *delegate = nullptr;

    bool auto_gzipped = false;

    /**
     * @param _path the new path pointer (taken as-is, no deep copy)
     */
    constexpr FileAddress(const char *_path) noexcept
        :path(_path)
    {
    }

    FileAddress(AllocatorPtr alloc, const FileAddress &src) noexcept;

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

    gcc_pure
    bool HasQueryString() const noexcept {
        return false;
    }

    /**
     * Throws std::runtime_error on error.
     */
    void Check() const;

    gcc_pure
    bool IsValidBase() const noexcept;

    FileAddress *SaveBase(AllocatorPtr alloc,
                          const char *suffix) const noexcept;
    FileAddress *LoadBase(AllocatorPtr alloc,
                          const char *suffix) const noexcept;

    /**
     * Does this address need to be expanded with Expand()?
     */
    gcc_pure
    bool IsExpandable() const noexcept;

    /**
     * Throws std::runtime_error on error.
     */
    void Expand(AllocatorPtr alloc, const MatchInfo &match_info);
};

#endif
<commit_msg>file_address: make constructor explicit<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef BENG_PROXY_FILE_ADDRESS_HXX
#define BENG_PROXY_FILE_ADDRESS_HXX

#include "spawn/ChildOptions.hxx"
#include "util/ConstBuffer.hxx"

#include "util/Compiler.h"

class AllocatorPtr;
class MatchInfo;
struct DelegateAddress;

/**
 * The address of a local static file.
 */
struct FileAddress {
    const char *path;
    const char *deflated = nullptr;
    const char *gzipped = nullptr;

    const char *content_type = nullptr;

    ConstBuffer<void> content_type_lookup = nullptr;

    const char *document_root = nullptr;

    /**
     * The value of #TRANSLATE_EXPAND_PATH.  Only used by the
     * translation cache.
     */
    const char *expand_path = nullptr;

    /**
     * The value of #TRANSLATE_EXPAND_DOCUMENT_ROOT.  Only used by the
     * translation cache.
     */
    const char *expand_document_root = nullptr;

    DelegateAddress *delegate = nullptr;

    bool auto_gzipped = false;

    /**
     * @param _path the new path pointer (taken as-is, no deep copy)
     */
    explicit constexpr FileAddress(const char *_path) noexcept
        :path(_path)
    {
    }

    FileAddress(AllocatorPtr alloc, const FileAddress &src) noexcept;

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

    gcc_pure
    bool HasQueryString() const noexcept {
        return false;
    }

    /**
     * Throws std::runtime_error on error.
     */
    void Check() const;

    gcc_pure
    bool IsValidBase() const noexcept;

    FileAddress *SaveBase(AllocatorPtr alloc,
                          const char *suffix) const noexcept;
    FileAddress *LoadBase(AllocatorPtr alloc,
                          const char *suffix) const noexcept;

    /**
     * Does this address need to be expanded with Expand()?
     */
    gcc_pure
    bool IsExpandable() const noexcept;

    /**
     * Throws std::runtime_error on error.
     */
    void Expand(AllocatorPtr alloc, const MatchInfo &match_info);
};

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "file_headers.hxx"
#include "static_headers.hxx"
#include "GrowingBuffer.hxx"
#include "header_writer.hxx"
#include "request.hxx"
#include "http_server/Request.hxx"
#include "http_headers.hxx"
#include "translation/Vary.hxx"
#include "http/List.hxx"
#include "http/Date.hxx"
#include "util/DecimalFormat.h"

#include <attr/xattr.h>

#include <assert.h>
#include <stdlib.h>
#include <sys/stat.h>

gcc_pure
static std::chrono::seconds
read_xattr_max_age(int fd)
{
    assert(fd >= 0);

    char buffer[32];
    ssize_t nbytes = fgetxattr(fd, "user.MaxAge",
                               buffer, sizeof(buffer) - 1);
    if (nbytes <= 0)
        return std::chrono::seconds::zero();

    buffer[nbytes] = 0;

    char *endptr;
    unsigned long max_age = strtoul(buffer, &endptr, 10);
    if (*endptr != 0)
        return std::chrono::seconds::zero();

    return std::chrono::seconds(max_age);
}

static void
generate_expires(GrowingBuffer &headers,
                 std::chrono::system_clock::duration max_age)
{
    constexpr std::chrono::system_clock::duration max_max_age =
        std::chrono::hours(365 * 24);
    if (max_age > max_max_age)
        /* limit max_age to approximately one year */
        max_age = max_max_age;

    /* generate an "Expires" response header */
    header_write(headers, "expires",
                 http_date_format(std::chrono::system_clock::now() + max_age));
}

static bool
ReadETag(int fd, char *buffer, size_t size) noexcept
{
    assert(fd >= 0);
    assert(size > 4);

    const auto nbytes = fgetxattr(fd, "user.ETag", buffer + 1, size - 3);
    if (nbytes <= 0)
        return false;

    assert((size_t)nbytes < size);

    buffer[0] = '"';
    buffer[nbytes + 1] = '"';
    buffer[nbytes + 2] = 0;
    return true;
}

static void
MakeETag(GrowingBuffer &headers, int fd, const struct stat &st)
{
    char buffer[512];

    if (fd < 0 || !ReadETag(fd, buffer, sizeof(buffer)))
        static_etag(buffer, st);

    header_write(headers, "etag", buffer);
}

static void
file_cache_headers(GrowingBuffer &headers,
                   int fd, const struct stat &st,
                   std::chrono::seconds max_age)
{
    MakeETag(headers, fd, st);

    if (max_age == std::chrono::seconds::zero() && fd >= 0)
        max_age = read_xattr_max_age(fd);

    if (max_age > std::chrono::seconds::zero())
        generate_expires(headers, max_age);
}

/**
 * Verifies the If-Range request header (RFC 2616 14.27).
 */
static bool
check_if_range(const char *if_range, const struct stat &st)
{
    if (if_range == nullptr)
        return true;

    const auto t = http_date_parse(if_range);
    if (t != std::chrono::system_clock::from_time_t(-1))
        return std::chrono::system_clock::from_time_t(st.st_mtime) == t;

    char etag[64];
    static_etag(etag, st);
    return strcmp(if_range, etag) == 0;
}

bool
file_evaluate_request(Request &request2,
                      int fd, const struct stat &st,
                      struct file_request &file_request)
{
    const auto &request = request2.request;
    const auto &request_headers = request.headers;
    const auto &tr = *request2.translate.response;
    bool ignore_if_modified_since = false;

    if (tr.status == 0 && request.method == HTTP_METHOD_GET &&
        !request2.IsTransformationEnabled()) {
        const char *p = request_headers.Get("range");

        if (p != nullptr &&
            check_if_range(request_headers.Get("if-range"), st))
            file_request.range.ParseRangeHeader(p);
    }

    if (!request2.IsTransformationEnabled()) {
        const char *p = request_headers.Get("if-match");
        if (p != nullptr && strcmp(p, "*") != 0) {
            char buffer[64];
            static_etag(buffer, st);

            if (!http_list_contains(p, buffer)) {
                response_dispatch(request2, HTTP_STATUS_PRECONDITION_FAILED,
                                  HttpHeaders(request2.pool), nullptr);
                return false;
            }
        }

        p = request_headers.Get("if-none-match");
        if (p != nullptr && strcmp(p, "*") == 0) {
            response_dispatch(request2, HTTP_STATUS_PRECONDITION_FAILED,
                              HttpHeaders(request2.pool), nullptr);
            return false;
        }

        if (p != nullptr) {
            char buffer[64];
            static_etag(buffer, st);

            if (http_list_contains(p, buffer)) {
                response_dispatch(request2, HTTP_STATUS_PRECONDITION_FAILED,
                                  HttpHeaders(request2.pool), nullptr);
                return false;
            }

            /* RFC 2616 14.26: "If none of the entity tags match, then
               the server MAY perform the requested method as if the
               If-None-Match header field did not exist, but MUST also
               ignore any If-Modified-Since header field(s) in the
               request." */
            ignore_if_modified_since = true;
        }
    }

    if (!request2.IsProcessorEnabled()) {
        const char *p = ignore_if_modified_since
            ? nullptr
            : request_headers.Get("if-modified-since");
        if (p != nullptr) {
            const auto t = http_date_parse(p);
            if (t != std::chrono::system_clock::from_time_t(-1) &&
                std::chrono::system_clock::from_time_t(st.st_mtime) <= t) {
                HttpHeaders headers(request2.pool);
                auto &headers2 = headers.GetBuffer();

                file_cache_headers(headers2, fd, st, tr.expires_relative);

                write_translation_vary_header(headers2, tr);

                response_dispatch(request2, HTTP_STATUS_NOT_MODIFIED,
                                  std::move(headers), nullptr);
                return false;
            }
        }

        p = request_headers.Get("if-unmodified-since");
        if (p != nullptr) {
            const auto t = http_date_parse(p);
            if (t != std::chrono::system_clock::from_time_t(-1) &&
                std::chrono::system_clock::from_time_t(st.st_mtime) > t) {
                response_dispatch(request2, HTTP_STATUS_PRECONDITION_FAILED,
                                  HttpHeaders(request2.pool), nullptr);
                return false;
            }
        }
    }

    return true;
}

void
file_response_headers(GrowingBuffer &headers,
                      const char *override_content_type,
                      int fd, const struct stat &st,
                      std::chrono::seconds expires_relative,
                      bool processor_enabled, bool processor_first)
{
    if (!processor_first && fd >= 0)
        file_cache_headers(headers, fd, st, expires_relative);
    else {
        char etag[64];
        static_etag(etag, st);
        header_write(headers, "etag", etag);

        if (expires_relative > std::chrono::seconds::zero())
            generate_expires(headers, expires_relative);
    }

    if (override_content_type != nullptr) {
        /* content type override from the translation server */
        header_write(headers, "content-type", override_content_type);
    } else {
        char content_type[256];
        if (load_xattr_content_type(content_type, sizeof(content_type), fd)) {
            header_write(headers, "content-type", content_type);
        } else {
            header_write(headers, "content-type", "application/octet-stream");
        }
    }

#ifndef NO_LAST_MODIFIED_HEADER
    if (!processor_enabled)
        header_write(headers, "last-modified",
                     http_date_format(std::chrono::system_clock::from_time_t(st.st_mtime)));
#endif
}
<commit_msg>file_headers: move code to DispatchNotModified()<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "file_headers.hxx"
#include "static_headers.hxx"
#include "GrowingBuffer.hxx"
#include "header_writer.hxx"
#include "request.hxx"
#include "http_server/Request.hxx"
#include "http_headers.hxx"
#include "translation/Vary.hxx"
#include "http/List.hxx"
#include "http/Date.hxx"
#include "util/DecimalFormat.h"

#include <attr/xattr.h>

#include <assert.h>
#include <stdlib.h>
#include <sys/stat.h>

gcc_pure
static std::chrono::seconds
read_xattr_max_age(int fd)
{
    assert(fd >= 0);

    char buffer[32];
    ssize_t nbytes = fgetxattr(fd, "user.MaxAge",
                               buffer, sizeof(buffer) - 1);
    if (nbytes <= 0)
        return std::chrono::seconds::zero();

    buffer[nbytes] = 0;

    char *endptr;
    unsigned long max_age = strtoul(buffer, &endptr, 10);
    if (*endptr != 0)
        return std::chrono::seconds::zero();

    return std::chrono::seconds(max_age);
}

static void
generate_expires(GrowingBuffer &headers,
                 std::chrono::system_clock::duration max_age)
{
    constexpr std::chrono::system_clock::duration max_max_age =
        std::chrono::hours(365 * 24);
    if (max_age > max_max_age)
        /* limit max_age to approximately one year */
        max_age = max_max_age;

    /* generate an "Expires" response header */
    header_write(headers, "expires",
                 http_date_format(std::chrono::system_clock::now() + max_age));
}

static bool
ReadETag(int fd, char *buffer, size_t size) noexcept
{
    assert(fd >= 0);
    assert(size > 4);

    const auto nbytes = fgetxattr(fd, "user.ETag", buffer + 1, size - 3);
    if (nbytes <= 0)
        return false;

    assert((size_t)nbytes < size);

    buffer[0] = '"';
    buffer[nbytes + 1] = '"';
    buffer[nbytes + 2] = 0;
    return true;
}

static void
MakeETag(GrowingBuffer &headers, int fd, const struct stat &st)
{
    char buffer[512];

    if (fd < 0 || !ReadETag(fd, buffer, sizeof(buffer)))
        static_etag(buffer, st);

    header_write(headers, "etag", buffer);
}

static void
file_cache_headers(GrowingBuffer &headers,
                   int fd, const struct stat &st,
                   std::chrono::seconds max_age)
{
    MakeETag(headers, fd, st);

    if (max_age == std::chrono::seconds::zero() && fd >= 0)
        max_age = read_xattr_max_age(fd);

    if (max_age > std::chrono::seconds::zero())
        generate_expires(headers, max_age);
}

/**
 * Verifies the If-Range request header (RFC 2616 14.27).
 */
static bool
check_if_range(const char *if_range, const struct stat &st)
{
    if (if_range == nullptr)
        return true;

    const auto t = http_date_parse(if_range);
    if (t != std::chrono::system_clock::from_time_t(-1))
        return std::chrono::system_clock::from_time_t(st.st_mtime) == t;

    char etag[64];
    static_etag(etag, st);
    return strcmp(if_range, etag) == 0;
}

/**
 * Generate a "304 Not Modified" response.
 */
static void
DispatchNotModified(Request &request2, const TranslateResponse &tr,
                    int fd, const struct stat &st)
{
    HttpHeaders headers(request2.pool);
    auto &headers2 = headers.GetBuffer();

    file_cache_headers(headers2, fd, st, tr.expires_relative);

    write_translation_vary_header(headers2, tr);

    response_dispatch(request2, HTTP_STATUS_NOT_MODIFIED,
                      std::move(headers), nullptr);
}

bool
file_evaluate_request(Request &request2,
                      int fd, const struct stat &st,
                      struct file_request &file_request)
{
    const auto &request = request2.request;
    const auto &request_headers = request.headers;
    const auto &tr = *request2.translate.response;
    bool ignore_if_modified_since = false;

    if (tr.status == 0 && request.method == HTTP_METHOD_GET &&
        !request2.IsTransformationEnabled()) {
        const char *p = request_headers.Get("range");

        if (p != nullptr &&
            check_if_range(request_headers.Get("if-range"), st))
            file_request.range.ParseRangeHeader(p);
    }

    if (!request2.IsTransformationEnabled()) {
        const char *p = request_headers.Get("if-match");
        if (p != nullptr && strcmp(p, "*") != 0) {
            char buffer[64];
            static_etag(buffer, st);

            if (!http_list_contains(p, buffer)) {
                response_dispatch(request2, HTTP_STATUS_PRECONDITION_FAILED,
                                  HttpHeaders(request2.pool), nullptr);
                return false;
            }
        }

        p = request_headers.Get("if-none-match");
        if (p != nullptr && strcmp(p, "*") == 0) {
            response_dispatch(request2, HTTP_STATUS_PRECONDITION_FAILED,
                              HttpHeaders(request2.pool), nullptr);
            return false;
        }

        if (p != nullptr) {
            char buffer[64];
            static_etag(buffer, st);

            if (http_list_contains(p, buffer)) {
                response_dispatch(request2, HTTP_STATUS_PRECONDITION_FAILED,
                                  HttpHeaders(request2.pool), nullptr);
                return false;
            }

            /* RFC 2616 14.26: "If none of the entity tags match, then
               the server MAY perform the requested method as if the
               If-None-Match header field did not exist, but MUST also
               ignore any If-Modified-Since header field(s) in the
               request." */
            ignore_if_modified_since = true;
        }
    }

    if (!request2.IsProcessorEnabled()) {
        const char *p = ignore_if_modified_since
            ? nullptr
            : request_headers.Get("if-modified-since");
        if (p != nullptr) {
            const auto t = http_date_parse(p);
            if (t != std::chrono::system_clock::from_time_t(-1) &&
                std::chrono::system_clock::from_time_t(st.st_mtime) <= t) {
                DispatchNotModified(request2, tr, fd, st);
                return false;
            }
        }

        p = request_headers.Get("if-unmodified-since");
        if (p != nullptr) {
            const auto t = http_date_parse(p);
            if (t != std::chrono::system_clock::from_time_t(-1) &&
                std::chrono::system_clock::from_time_t(st.st_mtime) > t) {
                response_dispatch(request2, HTTP_STATUS_PRECONDITION_FAILED,
                                  HttpHeaders(request2.pool), nullptr);
                return false;
            }
        }
    }

    return true;
}

void
file_response_headers(GrowingBuffer &headers,
                      const char *override_content_type,
                      int fd, const struct stat &st,
                      std::chrono::seconds expires_relative,
                      bool processor_enabled, bool processor_first)
{
    if (!processor_first && fd >= 0)
        file_cache_headers(headers, fd, st, expires_relative);
    else {
        char etag[64];
        static_etag(etag, st);
        header_write(headers, "etag", etag);

        if (expires_relative > std::chrono::seconds::zero())
            generate_expires(headers, expires_relative);
    }

    if (override_content_type != nullptr) {
        /* content type override from the translation server */
        header_write(headers, "content-type", override_content_type);
    } else {
        char content_type[256];
        if (load_xattr_content_type(content_type, sizeof(content_type), fd)) {
            header_write(headers, "content-type", content_type);
        } else {
            header_write(headers, "content-type", "application/octet-stream");
        }
    }

#ifndef NO_LAST_MODIFIED_HEADER
    if (!processor_enabled)
        header_write(headers, "last-modified",
                     http_date_format(std::chrono::system_clock::from_time_t(st.st_mtime)));
#endif
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageAccumulate.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$
  Thanks:    Thanks to C. Charles Law who developed this class.

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/

#include "vtkImageAccumulate.h"
#include <math.h>
#include <stdlib.h>
#include "vtkObjectFactory.h"

//----------------------------------------------------------------------------
vtkImageAccumulate* vtkImageAccumulate::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkImageAccumulate");
  if(ret)
    {
    return (vtkImageAccumulate*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkImageAccumulate;
}

//----------------------------------------------------------------------------
// Constructor sets default values
vtkImageAccumulate::vtkImageAccumulate()
{
  int idx;

  for (idx = 0; idx < 3; ++idx)
    {
    this->ComponentSpacing[idx] = 1.0;
    this->ComponentOrigin[idx] = 0.0;
    this->ComponentExtent[idx*2] = 0;
    this->ComponentExtent[idx*2+1] = 0;
    }
  this->ComponentExtent[1] = 255;

  this->ReverseStencil = 0;

  this->Min[0] = this->Min[1] = this->Min[2] = 0.0;
  this->Max[0] = this->Max[1] = this->Max[2] = 0.0;
  this->Mean[0] = this->Mean[1] = this->Mean[2] = 0.0;
  this->VoxelCount = 0;
}

//----------------------------------------------------------------------------
vtkImageAccumulate::~vtkImageAccumulate()
{
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::SetComponentExtent(int extent[6])
{
  int idx, modified = 0;

  for (idx = 0; idx < 6; ++idx)
    {
    if (this->ComponentExtent[idx] != extent[idx])
      {
      this->ComponentExtent[idx] = extent[idx];
      this->Modified();
      }
    }
  if (modified)
    {
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::SetComponentExtent(int minX, int maxX,
                                            int minY, int maxY,
                                            int minZ, int maxZ)
{
  int extent[6];

  extent[0] = minX;  extent[1] = maxX;
  extent[2] = minY;  extent[3] = maxY;
  extent[4] = minZ;  extent[5] = maxZ;
  this->SetComponentExtent(extent);
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::GetComponentExtent(int extent[6])
{
  int idx;

  for (idx = 0; idx < 6; ++idx)
    {
    extent[idx] = this->ComponentExtent[idx];
    }
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::SetStencil(vtkImageStencilData *stencil)
{
  this->vtkProcessObject::SetNthInput(1, stencil);
}

//----------------------------------------------------------------------------
vtkImageStencilData *vtkImageAccumulate::GetStencil()
{
  if (this->NumberOfInputs < 2)
    {
    return NULL;
    }
  else
    {
    return (vtkImageStencilData *)(this->Inputs[1]);
    }
}

//----------------------------------------------------------------------------
// This templated function executes the filter for any type of data.
template <class T>
static void vtkImageAccumulateExecute(vtkImageAccumulate *self,
				      vtkImageData *inData, T *inPtr,
				      vtkImageData *outData, int *outPtr,
				      double Min[3],
				      double Max[3],
				      double Mean[3],
				      long int *VoxelCount)
{
  int idX, idY, idZ, idxC;
  int r1, r2, cr1, cr2, iter, rval;
  int pmin0, pmax0, min0, max0, min1, max1, min2, max2;
  int inInc0, inInc1, inInc2;
  T *tempPtr;
  int *outPtrC;
  int numC, outIdx, *outExtent, *outIncs;
  float *origin, *spacing;
  unsigned long count = 0;
  unsigned long target;

  // variables used to compute statistics (filter handles max 3 components)
  double sum[3];
  sum[0] = sum[1] = sum[2] = 0.0;
  Min[0] = Min[1] = Min[2] = VTK_DOUBLE_MAX;
  Max[0] = Max[1] = Max[2] = VTK_DOUBLE_MIN;
  *VoxelCount = 0;

  vtkImageStencilData *stencil = self->GetStencil();

  // Zero count in every bin
  outData->GetExtent(min0, max0, min1, max1, min2, max2);
  memset((void *)outPtr, 0,
         (max0-min0+1)*(max1-min1+1)*(max2-min2+1)*sizeof(int));

  // Get information to march through data
  numC = inData->GetNumberOfScalarComponents();
  inData->GetUpdateExtent(min0, max0, min1, max1, min2, max2);
  inData->GetIncrements(inInc0, inInc1, inInc2);
  outExtent = outData->GetExtent();
  outIncs = outData->GetIncrements();
  origin = outData->GetOrigin();
  spacing = outData->GetSpacing();

  target = (unsigned long)((max2 - min2 + 1)*(max1 - min1 +1)/50.0);
  target++;

  // Loop through input pixels
  for (idZ = min2; idZ <= max2; idZ++)
    {
    for (idY = min1; idY <= max1; idY++)
      {
      if (!(count%target))
	{
        self->UpdateProgress(count/(50.0*target));
	}
      count++;

      // loop over stencil sub-extents
      iter = 0;
      cr1 = min0;
      rval = 1;
      while (rval)
	{
	rval = 0;
	r1 = max0 + 1;
	r2 = max0;
	if (stencil)
	  { // get sub extent [r1,r2]
	  rval = stencil->GetNextExtent(r1, r2, min0, max0, idY, idZ, iter);
	  }
	// sub extents [cr1,cr2] are the complement of sub extents [r1,r2]
	cr2 = r1 - 1;

	pmin0 = cr1;
	pmax0 = cr2;
	// check whether to use [r1,r2] or its complement [cr1,cr2]
	if (stencil && !self->GetReverseStencil())
	  {
	  if (rval == 0)
	    {
	    break;
	    }
	  pmin0 = r1;
	  pmax0 = r2;
	  }
	// set up cr1 for next iteration
	cr1 = r2 + 1;

	// set up pointer for sub extent
	tempPtr = inPtr + (inInc2*(idZ - min2) +
			   inInc1*(idY - min1) +
			   numC*(pmin0 - min0));

	// accumulate over the sub extent
	for (idX = pmin0; idX <= pmax0; idX++)
	  {
	  // find the bin for this pixel.
	  outPtrC = outPtr;
	  for (idxC = 0; idxC < numC; ++idxC)
	    {
	    // Gather statistics
	    sum[idxC]+= *tempPtr;
	    if (*tempPtr > Max[idxC])
	      {
	      Max[idxC] = *tempPtr;
	      }
	    else if (*tempPtr < Min[idxC])
	      {
	      Min[idxC] = *tempPtr;
	      }
	    (*VoxelCount)++;
	    // compute the index
	    outIdx = (int) floor((((double)*tempPtr++ - origin[idxC])
				  / spacing[idxC]));
	    if (outIdx < outExtent[idxC*2] || outIdx > outExtent[idxC*2+1])
	      {
	      // Out of bin range
	      outPtrC = NULL;
	      break;
	      }
	    outPtrC += (outIdx - outExtent[idxC*2]) * outIncs[idxC];
	    }
	  if (outPtrC)
	    {
	    ++(*outPtrC);
	    }
	  }
        }
      }
    }

  if (*VoxelCount) // avoid the div0
    {
    Mean[0] = sum[0] / (double)*VoxelCount;
    Mean[1] = sum[1] / (double)*VoxelCount;
    Mean[2] = sum[2] / (double)*VoxelCount;
    }
  else
    {
    Mean[0] = Mean[1] = Mean[2] = 0.0;
    }

}

//----------------------------------------------------------------------------
// This method is passed a input and output Data, and executes the filter
// algorithm to fill the output from the input.
// It just executes a switch statement to call the correct function for
// the Datas data types.
void vtkImageAccumulate::ExecuteData(vtkDataObject *vtkNotUsed(out))
{
  void *inPtr;
  void *outPtr;
  vtkImageData *inData = this->GetInput();
  vtkImageData *outData = this->GetOutput();

  vtkDebugMacro(<<"Executing image accumulate");

  // We need to allocate our own scalars since we are overriding
  // the superclasses "Execute()" method.
  outData->SetExtent(outData->GetWholeExtent());
  outData->AllocateScalars();

  inPtr = inData->GetScalarPointerForExtent(inData->GetUpdateExtent());
  outPtr = outData->GetScalarPointer();

  // Components turned into x, y and z
  if (this->GetInput()->GetNumberOfScalarComponents() > 3)
    {
    vtkErrorMacro("This filter can handle upto 3 components");
    return;
    }

  // this filter expects that output is type int.
  if (outData->GetScalarType() != VTK_INT)
    {
    vtkErrorMacro(<< "Execute: out ScalarType " << outData->GetScalarType()
                  << " must be int\n");
    return;
    }

  switch (inData->GetScalarType())
    {
    vtkTemplateMacro9(vtkImageAccumulateExecute, this,
                      inData, (VTK_TT *)(inPtr),
                      outData, (int *)(outPtr),
		      this->Min, this->Max,
		      this->Mean, &this->VoxelCount);
    default:
      vtkErrorMacro(<< "Execute: Unknown ScalarType");
      return;
    }
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::ExecuteInformation(vtkImageData *input,
                                            vtkImageData *output)
{
  output->SetWholeExtent(this->ComponentExtent);
  output->SetOrigin(this->ComponentOrigin);
  output->SetSpacing(this->ComponentSpacing);
  output->SetNumberOfScalarComponents(1);
  output->SetScalarType(VTK_INT);

  // need to set the spacing and origin of the stencil to match the output
  vtkImageStencilData *stencil = this->GetStencil();
  if (stencil)
    {
    stencil->SetSpacing(input->GetSpacing());
    stencil->SetOrigin(input->GetOrigin());
    }
}

//----------------------------------------------------------------------------
// Get ALL of the input.
void vtkImageAccumulate::ComputeInputUpdateExtent(int inExt[6],
                                                  int outExt[6])
{
  int *wholeExtent;

  outExt = outExt;
  wholeExtent = this->GetInput()->GetWholeExtent();
  memcpy(inExt, wholeExtent, 6*sizeof(int));
}

void vtkImageAccumulate::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkImageToImageFilter::PrintSelf(os,indent);

  os << indent << "Mean: " << this->Mean << "\n";
  os << indent << "Min: " << this->Min << "\n";
  os << indent << "Max: " << this->Max << "\n";
  os << indent << "VoxelCount: " << this->VoxelCount << "\n";
  os << indent << "Stencil: " << this->GetStencil() << "\n";
  os << indent << "ReverseStencil: " << (this->ReverseStencil ?
		                         "On\n" : "Off\n");

  os << indent << "ComponentOrigin: ( "
     << this->ComponentOrigin[0] << ", "
     << this->ComponentOrigin[1] << ", "
     << this->ComponentOrigin[2] << " )\n";

  os << indent << "ComponentSpacing: ( "
     << this->ComponentSpacing[0] << ", "
     << this->ComponentSpacing[1] << ", "
     << this->ComponentSpacing[2] << " )\n";

  os << indent << "ComponentExtent: ( "
     << this->ComponentExtent[0] << "," << this->ComponentExtent[1] << " "
     << this->ComponentExtent[2] << "," << this->ComponentExtent[3] << " "
     << this->ComponentExtent[4] << "," << this->ComponentExtent[5] << " }\n";
}

<commit_msg>ENH: simplify reversal of stencil, also some 'progress' stuff was missing<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageAccumulate.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$
  Thanks:    Thanks to C. Charles Law who developed this class.

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/

#include "vtkImageAccumulate.h"
#include <math.h>
#include <stdlib.h>
#include "vtkObjectFactory.h"

//----------------------------------------------------------------------------
vtkImageAccumulate* vtkImageAccumulate::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkImageAccumulate");
  if(ret)
    {
    return (vtkImageAccumulate*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkImageAccumulate;
}

//----------------------------------------------------------------------------
// Constructor sets default values
vtkImageAccumulate::vtkImageAccumulate()
{
  int idx;

  for (idx = 0; idx < 3; ++idx)
    {
    this->ComponentSpacing[idx] = 1.0;
    this->ComponentOrigin[idx] = 0.0;
    this->ComponentExtent[idx*2] = 0;
    this->ComponentExtent[idx*2+1] = 0;
    }
  this->ComponentExtent[1] = 255;

  this->ReverseStencil = 0;

  this->Min[0] = this->Min[1] = this->Min[2] = 0.0;
  this->Max[0] = this->Max[1] = this->Max[2] = 0.0;
  this->Mean[0] = this->Mean[1] = this->Mean[2] = 0.0;
  this->VoxelCount = 0;
}

//----------------------------------------------------------------------------
vtkImageAccumulate::~vtkImageAccumulate()
{
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::SetComponentExtent(int extent[6])
{
  int idx, modified = 0;

  for (idx = 0; idx < 6; ++idx)
    {
    if (this->ComponentExtent[idx] != extent[idx])
      {
      this->ComponentExtent[idx] = extent[idx];
      this->Modified();
      }
    }
  if (modified)
    {
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::SetComponentExtent(int minX, int maxX,
                                            int minY, int maxY,
                                            int minZ, int maxZ)
{
  int extent[6];

  extent[0] = minX;  extent[1] = maxX;
  extent[2] = minY;  extent[3] = maxY;
  extent[4] = minZ;  extent[5] = maxZ;
  this->SetComponentExtent(extent);
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::GetComponentExtent(int extent[6])
{
  int idx;

  for (idx = 0; idx < 6; ++idx)
    {
    extent[idx] = this->ComponentExtent[idx];
    }
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::SetStencil(vtkImageStencilData *stencil)
{
  this->vtkProcessObject::SetNthInput(1, stencil);
}

//----------------------------------------------------------------------------
vtkImageStencilData *vtkImageAccumulate::GetStencil()
{
  if (this->NumberOfInputs < 2)
    {
    return NULL;
    }
  else
    {
    return (vtkImageStencilData *)(this->Inputs[1]);
    }
}

//----------------------------------------------------------------------------
// This templated function executes the filter for any type of data.
template <class T>
static void vtkImageAccumulateExecute(vtkImageAccumulate *self,
				      vtkImageData *inData, T *inPtr,
				      vtkImageData *outData, int *outPtr,
				      double Min[3],
				      double Max[3],
				      double Mean[3],
				      long int *VoxelCount)
{
  int idX, idY, idZ, idxC;
  int iter, pmin0, pmax0, min0, max0, min1, max1, min2, max2;
  int inInc0, inInc1, inInc2;
  T *tempPtr;
  int *outPtrC;
  int numC, outIdx, *outExtent, *outIncs;
  float *origin, *spacing;
  unsigned long count = 0;
  unsigned long target;

  // variables used to compute statistics (filter handles max 3 components)
  double sum[3];
  sum[0] = sum[1] = sum[2] = 0.0;
  Min[0] = Min[1] = Min[2] = VTK_DOUBLE_MAX;
  Max[0] = Max[1] = Max[2] = VTK_DOUBLE_MIN;
  *VoxelCount = 0;

  vtkImageStencilData *stencil = self->GetStencil();

  // Zero count in every bin
  outData->GetExtent(min0, max0, min1, max1, min2, max2);
  memset((void *)outPtr, 0,
         (max0-min0+1)*(max1-min1+1)*(max2-min2+1)*sizeof(int));

  // Get information to march through data
  numC = inData->GetNumberOfScalarComponents();
  inData->GetUpdateExtent(min0, max0, min1, max1, min2, max2);
  inData->GetIncrements(inInc0, inInc1, inInc2);
  outExtent = outData->GetExtent();
  outIncs = outData->GetIncrements();
  origin = outData->GetOrigin();
  spacing = outData->GetSpacing();

  target = (unsigned long)((max2 - min2 + 1)*(max1 - min1 +1)/50.0);
  target++;

  // Loop through input pixels
  for (idZ = min2; idZ <= max2; idZ++)
    {
    for (idY = min1; idY <= max1; idY++)
      {
      if (!(count%target))
	{
        self->UpdateProgress(count/(50.0*target));
	}
      count++;

      // loop over stencil sub-extents
      iter = 0;
      if (self->GetReverseStencil())
	{ // flag that we want the complementary extents
 	iter = -1;
	}

      pmin0 = min0;
      pmax0 = max0;
      while ((stencil != 0 &&
	      stencil->GetNextExtent(pmin0,pmax0,min0,max0,idY,idZ,iter)) ||
	     (stencil == 0 && iter++ == 0))
	{
	// set up pointer for sub extent
	tempPtr = inPtr + (inInc2*(idZ - min2) +
			   inInc1*(idY - min1) +
			   numC*(pmin0 - min0));

	// accumulate over the sub extent
	for (idX = pmin0; idX <= pmax0; idX++)
	  {
	  // find the bin for this pixel.
	  outPtrC = outPtr;
	  for (idxC = 0; idxC < numC; ++idxC)
	    {
	    // Gather statistics
	    sum[idxC]+= *tempPtr;
	    if (*tempPtr > Max[idxC])
	      {
	      Max[idxC] = *tempPtr;
	      }
	    else if (*tempPtr < Min[idxC])
	      {
	      Min[idxC] = *tempPtr;
	      }
	    (*VoxelCount)++;
	    // compute the index
	    outIdx = (int) floor((((double)*tempPtr++ - origin[idxC])
				  / spacing[idxC]));
	    if (outIdx < outExtent[idxC*2] || outIdx > outExtent[idxC*2+1])
	      {
	      // Out of bin range
	      outPtrC = NULL;
	      break;
	      }
	    outPtrC += (outIdx - outExtent[idxC*2]) * outIncs[idxC];
	    }
	  if (outPtrC)
	    {
	    ++(*outPtrC);
	    }
	  }
        }
      }
    }

  if (*VoxelCount) // avoid the div0
    {
    Mean[0] = sum[0] / (double)*VoxelCount;
    Mean[1] = sum[1] / (double)*VoxelCount;
    Mean[2] = sum[2] / (double)*VoxelCount;
    }
  else
    {
    Mean[0] = Mean[1] = Mean[2] = 0.0;
    }

}

//----------------------------------------------------------------------------
// This method is passed a input and output Data, and executes the filter
// algorithm to fill the output from the input.
// It just executes a switch statement to call the correct function for
// the Datas data types.
void vtkImageAccumulate::ExecuteData(vtkDataObject *vtkNotUsed(out))
{
  void *inPtr;
  void *outPtr;
  vtkImageData *inData = this->GetInput();
  vtkImageData *outData = this->GetOutput();

  vtkDebugMacro(<<"Executing image accumulate");

  // We need to allocate our own scalars since we are overriding
  // the superclasses "Execute()" method.
  outData->SetExtent(outData->GetWholeExtent());
  outData->AllocateScalars();

  inPtr = inData->GetScalarPointerForExtent(inData->GetUpdateExtent());
  outPtr = outData->GetScalarPointer();

  // Components turned into x, y and z
  if (this->GetInput()->GetNumberOfScalarComponents() > 3)
    {
    vtkErrorMacro("This filter can handle upto 3 components");
    return;
    }

  // this filter expects that output is type int.
  if (outData->GetScalarType() != VTK_INT)
    {
    vtkErrorMacro(<< "Execute: out ScalarType " << outData->GetScalarType()
                  << " must be int\n");
    return;
    }

  switch (inData->GetScalarType())
    {
    vtkTemplateMacro9(vtkImageAccumulateExecute, this,
                      inData, (VTK_TT *)(inPtr),
                      outData, (int *)(outPtr),
		      this->Min, this->Max,
		      this->Mean, &this->VoxelCount);
    default:
      vtkErrorMacro(<< "Execute: Unknown ScalarType");
      return;
    }
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::ExecuteInformation(vtkImageData *input,
                                            vtkImageData *output)
{
  output->SetWholeExtent(this->ComponentExtent);
  output->SetOrigin(this->ComponentOrigin);
  output->SetSpacing(this->ComponentSpacing);
  output->SetNumberOfScalarComponents(1);
  output->SetScalarType(VTK_INT);

  // need to set the spacing and origin of the stencil to match the output
  vtkImageStencilData *stencil = this->GetStencil();
  if (stencil)
    {
    stencil->SetSpacing(input->GetSpacing());
    stencil->SetOrigin(input->GetOrigin());
    }
}

//----------------------------------------------------------------------------
// Get ALL of the input.
void vtkImageAccumulate::ComputeInputUpdateExtent(int inExt[6],
                                                  int outExt[6])
{
  int *wholeExtent;

  outExt = outExt;
  wholeExtent = this->GetInput()->GetWholeExtent();
  memcpy(inExt, wholeExtent, 6*sizeof(int));
}

void vtkImageAccumulate::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkImageToImageFilter::PrintSelf(os,indent);

  os << indent << "Mean: " << this->Mean << "\n";
  os << indent << "Min: " << this->Min << "\n";
  os << indent << "Max: " << this->Max << "\n";
  os << indent << "VoxelCount: " << this->VoxelCount << "\n";
  os << indent << "Stencil: " << this->GetStencil() << "\n";
  os << indent << "ReverseStencil: " << (this->ReverseStencil ?
		                         "On\n" : "Off\n");

  os << indent << "ComponentOrigin: ( "
     << this->ComponentOrigin[0] << ", "
     << this->ComponentOrigin[1] << ", "
     << this->ComponentOrigin[2] << " )\n";

  os << indent << "ComponentSpacing: ( "
     << this->ComponentSpacing[0] << ", "
     << this->ComponentSpacing[1] << ", "
     << this->ComponentSpacing[2] << " )\n";

  os << indent << "ComponentExtent: ( "
     << this->ComponentExtent[0] << "," << this->ComponentExtent[1] << " "
     << this->ComponentExtent[2] << "," << this->ComponentExtent[3] << " "
     << this->ComponentExtent[4] << "," << this->ComponentExtent[5] << " }\n";
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014-2016 Kartik Kumar, Dinamica Srl (me@kartikkumar.com)
 * Distributed under the MIT License.
 * See accompanying file LICENSE.md or copy at http://opensource.org/licenses/MIT
 */

#ifndef D2D_LAMBERT_SCANNER_HPP
#define D2D_LAMBERT_SCANNER_HPP

#include <string>

#include <keplerian_toolbox.h>

#include <libsgp4/DateTime.h>

#include <rapidjson/document.h>

#include <SQLiteCpp/SQLiteCpp.h>

namespace d2d
{

//! Execute lambert_scanner.
/*!
 * Executes lambert_scanner application mode that performs a grid search to compute \f$\Delta V\f$
 * for debris-to-debris transfers. The transfers are modelled as conic sections. The Lambert
 * targeter employed is based on Izzo (2014), implemented in PyKEP (Izzo, 2012).
 *
 * The results obtained from the grid search are stored in a SQLite database, containing the
 * following table:
 *
 *	- "lambert_scanner_results": contains all Lambert transfers computed during grid search
 *
 * @param[in] config User-defined configuration options (extracted from JSON input file)
 */
void executeLambertScanner( const rapidjson::Document& config );

//! lambert_scanner input.
/*!
 * Data struct containing all valid lambert_scanner input parameters. This struct is populated by
 * the checkLambertScannerInput() function and can be used to execute the lambert_scanner
 * application mode.
 *
 * @sa checkLambertScannerInput, executeLambertScanner
 */
struct LambertScannerInput
{
public:

    //! Construct data struct.
    /*!
     * Constructs data struct based on verified input parameters.
     *
     * @sa checkLambertScannerInput, executeLambertScanner
     * @param[in] aCatalogPath          Path to TLE catalog
     * @param[in] aDatabasePath         Path to SQLite database
     * @param[in] aDepartureEpoch       Departure epoch for all transfers
     * @param[in] aTimeOfFlightMinimum  Minimum time-of-flight [s]
     * @param[in] aTimeOfFlightMaximum  Maximum time-of-flight [s]
     * @param[in] someTimeOfFlightSteps Number of steps to take in time-of-flight grid
     * @param[in] aTimeOfFlightStepSize Time-of-flight step size (derived parameter) [s]
     * @param[in] progradeFlag          Flag indicating if prograde transfer should be computed
     *                                  (false = retrograde)
     * @param[in] aRevolutionsMaximum   Maximum number of revolutions
     * @param[in] aShortlistLength      Number of transfers to include in shortlist
     * @param[in] aShortlistPath        Path to shortlist file
     */
    LambertScannerInput( const std::string& aCatalogPath,
                         const std::string& aDatabasePath,
                         const DateTime&    aDepartureEpoch,
                         const double       aTimeOfFlightMinimum,
                         const double       aTimeOfFlightMaximum,
                         const double       someTimeOfFlightSteps,
                         const double       aTimeOfFlightStepSize,
                         const bool         progradeFlag,
                         const int          aRevolutionsMaximum,
                         const int          aShortlistLength,
                         const std::string& aShortlistPath )
        : catalogPath( aCatalogPath ),
          databasePath( aDatabasePath ),
          departureEpoch( aDepartureEpoch ),
          timeOfFlightMinimum( aTimeOfFlightMinimum ),
          timeOfFlightMaximum( aTimeOfFlightMaximum ),
          timeOfFlightSteps( someTimeOfFlightSteps ),
          timeOfFlightStepSize( aTimeOfFlightStepSize ),
          isPrograde( progradeFlag ),
          revolutionsMaximum( aRevolutionsMaximum ),
          shortlistLength( aShortlistLength ),
          shortlistPath( aShortlistPath )
    { }

    //! Path to TLE catalog.
    const std::string catalogPath;

    //! Path to SQLite database to store output.
    const std::string databasePath;

    //! Departure epoch.
    const DateTime departureEpoch;

    //! Minimum time-of-flight [s].
    const double timeOfFlightMinimum;

    //! Maximum time-of-flight [s].
    const double timeOfFlightMaximum;

    //! Number of time-of-flight steps.
    const double timeOfFlightSteps;

    //! Time-of-flight step size [s].
    const double timeOfFlightStepSize;

    //! Flag indicating if transfers are prograde. False indicates retrograde.
    const bool isPrograde;

    //! Maximum number of revolutions (N) for transfer. Number of revolutions is 2*N+1.
    const int revolutionsMaximum;

    //! Number of entries (lowest transfer \f$\Delta V\f$) to include in shortlist.
    const int shortlistLength;

    //! Path to shortlist file.
    const std::string shortlistPath;

protected:

private:
};

//! Check lambert_scanner input parameters.
/*!
 * Checks that all inputs for the lambert_scanner application mode are valid. If not, an error is
 * thrown with a short description of the problem. If all inputs are valid, a data struct
 * containing all the inputs is returned, which is subsequently used to execute lambert_scanner
 * and related functions.
 *
 * @sa executeLambertScanner, LambertScannerInput
 * @param[in] config User-defined configuration options (extracted from JSON input file)
 * @return           Struct containing all valid input to execute lambert_scanner
 */
LambertScannerInput checkLambertScannerInput( const rapidjson::Document& config );

//! Create lambert_scanner table.
/*!
 * Creates lambert_scanner table in SQLite database used to store results obtaned from running
 * the lambert_scanner application mode.
 *
 * @sa executeLambertScanner
 * @param[in] database SQLite database handle
 */
void createLambertScannerTable( SQLite::Database& database );

//! Write transfer shortlist to file.
/*!
 * Writes shortlist of debris-to-debris Lambert transfers to file. The shortlist is based on the
 * requested number of transfers with the lowest transfer \f$\Delta V\f$, retrieved by sorting the
 * transfers in the SQLite database.
 *
 * @sa executeLambertScanner, createLambertScannerTable
 * @param[in] database        SQLite database handle
 * @param[in] shortlistNumber Number of entries to include in shortlist (if it exceeds number of
 *                            entries in database table, the whole table is written to file)
 * @param[in] shortlistPath   Path to shortlist file
 */
void writeTransferShortlist( SQLite::Database& database,
                             const int shortlistNumber,
                             const std::string& shortlistPath );

} // namespace d2d

/*!
 * Izzo, D. (2014) Revisiting Lambert's problem, http://arxiv.org/abs/1403.2705.
 * Izzo, D. (2012) PyGMO and PyKEP: open source tools for massively parallel optimization in
 * 	astrodynamics (the case of interplanetary trajectory optimization). Proceed. Fifth
 *  International Conf. Astrodynam. Tools and Techniques, ESA/ESTEC, The Netherlands.
 */

#endif // D2D_LAMBERT_SCANNER_HPP
<commit_msg>Update Doxygen short description for Lambert scanner input struct.<commit_after>/*
 * Copyright (c) 2014-2016 Kartik Kumar, Dinamica Srl (me@kartikkumar.com)
 * Distributed under the MIT License.
 * See accompanying file LICENSE.md or copy at http://opensource.org/licenses/MIT
 */

#ifndef D2D_LAMBERT_SCANNER_HPP
#define D2D_LAMBERT_SCANNER_HPP

#include <string>

#include <keplerian_toolbox.h>

#include <libsgp4/DateTime.h>

#include <rapidjson/document.h>

#include <SQLiteCpp/SQLiteCpp.h>

namespace d2d
{

//! Execute lambert_scanner.
/*!
 * Executes lambert_scanner application mode that performs a grid search to compute \f$\Delta V\f$
 * for debris-to-debris transfers. The transfers are modelled as conic sections. The Lambert
 * targeter employed is based on Izzo (2014), implemented in PyKEP (Izzo, 2012).
 *
 * The results obtained from the grid search are stored in a SQLite database, containing the
 * following table:
 *
 *	- "lambert_scanner_results": contains all Lambert transfers computed during grid search
 *
 * @param[in] config User-defined configuration options (extracted from JSON input file)
 */
void executeLambertScanner( const rapidjson::Document& config );

//! Input for lambert_scanner application mode.
/*!
 * Data struct containing all valid lambert_scanner input parameters. This struct is populated by
 * the checkLambertScannerInput() function and can be used to execute the lambert_scanner
 * application mode.
 *
 * @sa checkLambertScannerInput, executeLambertScanner
 */
struct LambertScannerInput
{
public:

    //! Construct data struct.
    /*!
     * Constructs data struct based on verified input parameters.
     *
     * @sa checkLambertScannerInput, executeLambertScanner
     * @param[in] aCatalogPath          Path to TLE catalog
     * @param[in] aDatabasePath         Path to SQLite database
     * @param[in] aDepartureEpoch       Departure epoch for all transfers
     * @param[in] aTimeOfFlightMinimum  Minimum time-of-flight [s]
     * @param[in] aTimeOfFlightMaximum  Maximum time-of-flight [s]
     * @param[in] someTimeOfFlightSteps Number of steps to take in time-of-flight grid
     * @param[in] aTimeOfFlightStepSize Time-of-flight step size (derived parameter) [s]
     * @param[in] progradeFlag          Flag indicating if prograde transfer should be computed
     *                                  (false = retrograde)
     * @param[in] aRevolutionsMaximum   Maximum number of revolutions
     * @param[in] aShortlistLength      Number of transfers to include in shortlist
     * @param[in] aShortlistPath        Path to shortlist file
     */
    LambertScannerInput( const std::string& aCatalogPath,
                         const std::string& aDatabasePath,
                         const DateTime&    aDepartureEpoch,
                         const double       aTimeOfFlightMinimum,
                         const double       aTimeOfFlightMaximum,
                         const double       someTimeOfFlightSteps,
                         const double       aTimeOfFlightStepSize,
                         const bool         progradeFlag,
                         const int          aRevolutionsMaximum,
                         const int          aShortlistLength,
                         const std::string& aShortlistPath )
        : catalogPath( aCatalogPath ),
          databasePath( aDatabasePath ),
          departureEpoch( aDepartureEpoch ),
          timeOfFlightMinimum( aTimeOfFlightMinimum ),
          timeOfFlightMaximum( aTimeOfFlightMaximum ),
          timeOfFlightSteps( someTimeOfFlightSteps ),
          timeOfFlightStepSize( aTimeOfFlightStepSize ),
          isPrograde( progradeFlag ),
          revolutionsMaximum( aRevolutionsMaximum ),
          shortlistLength( aShortlistLength ),
          shortlistPath( aShortlistPath )
    { }

    //! Path to TLE catalog.
    const std::string catalogPath;

    //! Path to SQLite database to store output.
    const std::string databasePath;

    //! Departure epoch.
    const DateTime departureEpoch;

    //! Minimum time-of-flight [s].
    const double timeOfFlightMinimum;

    //! Maximum time-of-flight [s].
    const double timeOfFlightMaximum;

    //! Number of time-of-flight steps.
    const double timeOfFlightSteps;

    //! Time-of-flight step size [s].
    const double timeOfFlightStepSize;

    //! Flag indicating if transfers are prograde. False indicates retrograde.
    const bool isPrograde;

    //! Maximum number of revolutions (N) for transfer. Number of revolutions is 2*N+1.
    const int revolutionsMaximum;

    //! Number of entries (lowest transfer \f$\Delta V\f$) to include in shortlist.
    const int shortlistLength;

    //! Path to shortlist file.
    const std::string shortlistPath;

protected:

private:
};

//! Check lambert_scanner input parameters.
/*!
 * Checks that all inputs for the lambert_scanner application mode are valid. If not, an error is
 * thrown with a short description of the problem. If all inputs are valid, a data struct
 * containing all the inputs is returned, which is subsequently used to execute lambert_scanner
 * and related functions.
 *
 * @sa executeLambertScanner, LambertScannerInput
 * @param[in] config User-defined configuration options (extracted from JSON input file)
 * @return           Struct containing all valid input to execute lambert_scanner
 */
LambertScannerInput checkLambertScannerInput( const rapidjson::Document& config );

//! Create lambert_scanner table.
/*!
 * Creates lambert_scanner table in SQLite database used to store results obtaned from running
 * the lambert_scanner application mode.
 *
 * @sa executeLambertScanner
 * @param[in] database SQLite database handle
 */
void createLambertScannerTable( SQLite::Database& database );

//! Write transfer shortlist to file.
/*!
 * Writes shortlist of debris-to-debris Lambert transfers to file. The shortlist is based on the
 * requested number of transfers with the lowest transfer \f$\Delta V\f$, retrieved by sorting the
 * transfers in the SQLite database.
 *
 * @sa executeLambertScanner, createLambertScannerTable
 * @param[in] database        SQLite database handle
 * @param[in] shortlistNumber Number of entries to include in shortlist (if it exceeds number of
 *                            entries in database table, the whole table is written to file)
 * @param[in] shortlistPath   Path to shortlist file
 */
void writeTransferShortlist( SQLite::Database& database,
                             const int shortlistNumber,
                             const std::string& shortlistPath );

} // namespace d2d

/*!
 * Izzo, D. (2014) Revisiting Lambert's problem, http://arxiv.org/abs/1403.2705.
 * Izzo, D. (2012) PyGMO and PyKEP: open source tools for massively parallel optimization in
 * 	astrodynamics (the case of interplanetary trajectory optimization). Proceed. Fifth
 *  International Conf. Astrodynam. Tools and Techniques, ESA/ESTEC, The Netherlands.
 */

#endif // D2D_LAMBERT_SCANNER_HPP
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <cstring>
#include <string>
#include <vector>
#include <iomanip>
#include <cmath>
#include <list>
#include <bitset>

using namespace std;

#define ll long long
#define lson l,mid,id<<1
#define rson mid+1,r,id<<1|1

typedef pair<int, int>pii;
typedef pair<ll, ll>pll;
typedef pair<double, double>pdd;

const double eps = 1e-6;
const ll  LINF = 0x3f3f3f3f3f3f3f3fLL;
const int INF = 0x3f3f3f3f;
const double FINF = 1e18;

#define x first
#define y second

#define REP(i,j,k) for(int i =(j);i<=(k);i++)
#define REPD(i,j,k) for(int i =(j);i>=(k);i--)
#define print(x) cout<<(x)<<endl;
#define IOS ios::sync_with_stdio(0);cin.tie(0);

int dpa[1005],dpb[1005];
int c[1005];
int fa[1005];
int fb[1005];

int n,f;
int p1,p2;

int mina=INF,minb=INF;
void Init(){
	cin>>n>>f>>p1>>p2;
	REP(i,1,n){
		cin>>c[i];
	}

	REP(i,1,n){
		cin>>fa[i];
		mina=min(mina,fa[i]);
	}

	REP(i,1,n){
		cin>>fb[i];
		minb=min(minb,fb[i]);
	}

	memset(dpa , 0 ,sizeof dpa);
	memset(dpb , 0, sizeof dpb);
	return ;
}

void Solve(){
	int ansa,ansb;
	REP(i,mina,f)
	{
		REP(j,1,n){
			if(i>=fa[j]){
				dpa[i]=max(dpa[i],dpa[i-fa[j]]+c[j]);
			}
		}

		if(dpa[i]>=p1){
			ansa=i;
			break;
		}
	}

	REP(i,minb,f){
		REP(j,1,n){
			if(i>=fb[j]){
				dpb[i]=max(dpb[i],dpb[i-fb[j]]+c[j]);
			}
		}
		if(dpb[i]>=p2){
			ansb=i;
			break;
		}
	}

	if(ansa+ansb<=f){
		print(1);
	}else{
		print(0);
	}

	return ;
}

int main(){

	freopen("uoj10680.in","r",stdin);

	int t;
	scanf("%d",&t);
	while(t--)
	Init(),Solve();
	return 0;
}<commit_msg>update uoj10680<commit_after>#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <cstring>
#include <string>
#include <vector>
#include <iomanip>
#include <cmath>
#include <list>
#include <bitset>

using namespace std;

#define ll long long
#define lson l,mid,id<<1
#define rson mid+1,r,id<<1|1

typedef pair<int, int>pii;
typedef pair<ll, ll>pll;
typedef pair<double, double>pdd;

const double eps = 1e-6;
const ll  LINF = 0x3f3f3f3f3f3f3f3fLL;
const int INF = 0x3f3f3f3f;
const double FINF = 1e18;

#define x first
#define y second

#define REP(i,j,k) for(int i =(j);i<=(k);i++)
#define REPD(i,j,k) for(int i =(j);i>=(k);i--)
#define print(x) cout<<(x)<<endl;
#define IOS ios::sync_with_stdio(0);cin.tie(0);

int dpa[1005],dpb[1005];
int c[1005];
int fa[1005];
int fb[1005];

int n,f;
int p1,p2;

int mina=INF,minb=INF;
void Init(){
	cin>>n>>f>>p1>>p2;
	REP(i,1,n){
		cin>>c[i];
	}

	REP(i,1,n){
		cin>>fa[i];
		mina=min(mina,fa[i]);
	}

	REP(i,1,n){
		cin>>fb[i];
		minb=min(minb,fb[i]);
	}

	memset(dpa , 0 ,sizeof dpa);
	memset(dpb , 0, sizeof dpb);
	return ;
}

void Solve(){
	int ansa,ansb;
	REP(i,mina,f)
	{
		REP(j,1,n){
			if(i>=fa[j]){
				dpa[i]=max(dpa[i],dpa[i-fa[j]]+c[j]);
			}
		}

		if(dpa[i]>=p1){
			ansa=i;
			break;
		}
	}

	REP(i,minb,f){
		REP(j,1,n){
			if(i>=fb[j]){
				dpb[i]=max(dpb[i],dpb[i-fb[j]]+c[j]);
			}
		}
		if(dpb[i]>=p2){
			ansb=i;
			break;
		}
	}

	if(ansa+ansb<=f){
		print(1);
	}else{
		print(0);
	}

	return ;
}

int main(){
#ifdef LOCAL
	freopen("uoj10680.in","r",stdin);
#endif
	int t;
	scanf("%d",&t);
	while(t--)
	Init(),Solve();
	return 0;
}<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_VALUE_TYPES_HPP
#define MAPNIK_VALUE_TYPES_HPP

// mapnik
#include <mapnik/config.hpp>

// icu
#include <unicode/uversion.h> // for U_NAMESPACE_QUALIFIER

// stl
#include <type_traits>
#include <iosfwd>
#include <cstddef>

namespace U_ICU_NAMESPACE {
    class UnicodeString;
}

namespace mapnik  {

#ifdef BIGINT
//using value_integer = boost::long_long_type;
using value_integer = long long;
#else
using value_integer = int;
#endif

using value_double = double;
using value_unicode_string = U_NAMESPACE_QUALIFIER UnicodeString;
using value_bool = bool;

struct MAPNIK_DECL value_null
{
    bool operator==(value_null const&) const
    {
        return true;
    }

    template <typename T>
    bool operator==(T const&) const
    {
        return false;
    }

    bool operator!=(value_null const&) const
    {
        return false;
    }

    template <typename T>
    bool operator!=(T const&) const
    {
        return true;
    }

    template <typename T>
    value_null operator+ (T const&) const
    {
        return *this;
    }

    template <typename T>
    value_null operator- (T const&) const
    {
        return *this;
    }

    template <typename T>
    value_null operator* (T const&) const
    {
        return *this;
    }

    template <typename T>
    value_null operator/ (T const&) const
    {
        return *this;
    }

    template <typename T>
    value_null operator% (T const&) const
    {
        return *this;
    }
};

inline std::size_t hash_value(value_null const&)
{
    return 0;
}

template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, value_null const& v)
{
    return out;
}

inline std::istream& operator>> ( std::istream & s, value_null & )
{
    return s;
}

namespace detail {
// to mapnik::value_type conversions traits
template <typename T>
struct is_value_bool
{
    bool value = std::is_same<T, bool>::value;
};

template <typename T>
struct is_value_integer
{
    bool value = std::is_integral<T>::value && !std::is_same<T, bool>::value;
};

template <typename T>
struct is_value_double
{
    bool value = std::is_floating_point<T>::value;
};

template <typename T>
struct is_value_unicode_string
{
    bool value = std::is_same<T,mapnik::value_unicode_string>::value;
};

template <typename T>
struct is_value_string
{
    bool value = std::is_same<T,std::string>::value;
};

template <typename T>
struct is_value_null
{
    bool value = std::is_same<T, value_null>::value;
};

template <typename T, class Enable = void>
struct mapnik_value_type
{
    using type = T;
};

// value_null
template <typename T>
struct mapnik_value_type<T, typename std::enable_if<detail::is_value_null<T>::value>::type>
{
    using type = mapnik::value_null;
};

// value_bool
template <typename T>
struct mapnik_value_type<T, typename std::enable_if<detail::is_value_bool<T>::value>::type>
{
    using type = mapnik::value_bool;
};

// value_integer
template <typename T>
struct mapnik_value_type<T, typename std::enable_if<detail::is_value_integer<T>::value>::type>
{
    using type = mapnik::value_integer;
};

// value_double
template <typename T>
struct mapnik_value_type<T, typename std::enable_if<detail::is_value_double<T>::value>::type>
{
    using type = mapnik::value_double;
};

// value_unicode_string
template <typename T>
struct mapnik_value_type<T, typename std::enable_if<detail::is_value_unicode_string<T>::value>::type>
{
    using type = mapnik::value_unicode_string;
};

} // namespace detail

} // namespace mapnik

#endif // MAPNIK_VALUE_TYPES_HPP
<commit_msg>fix compile with gcc<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_VALUE_TYPES_HPP
#define MAPNIK_VALUE_TYPES_HPP

// mapnik
#include <mapnik/config.hpp>

// icu
#include <unicode/uversion.h> // for U_NAMESPACE_QUALIFIER

// stl
#include <type_traits>
#include <iosfwd>
#include <cstddef>

namespace U_ICU_NAMESPACE {
    class UnicodeString;
}

namespace mapnik  {

#ifdef BIGINT
//using value_integer = boost::long_long_type;
using value_integer = long long;
#else
using value_integer = int;
#endif

using value_double = double;
using value_unicode_string = U_NAMESPACE_QUALIFIER UnicodeString;
using value_bool = bool;

struct MAPNIK_DECL value_null
{
    bool operator==(value_null const&) const
    {
        return true;
    }

    template <typename T>
    bool operator==(T const&) const
    {
        return false;
    }

    bool operator!=(value_null const&) const
    {
        return false;
    }

    template <typename T>
    bool operator!=(T const&) const
    {
        return true;
    }

    template <typename T>
    value_null operator+ (T const&) const
    {
        return *this;
    }

    template <typename T>
    value_null operator- (T const&) const
    {
        return *this;
    }

    template <typename T>
    value_null operator* (T const&) const
    {
        return *this;
    }

    template <typename T>
    value_null operator/ (T const&) const
    {
        return *this;
    }

    template <typename T>
    value_null operator% (T const&) const
    {
        return *this;
    }
};

inline std::size_t hash_value(value_null const&)
{
    return 0;
}

template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, value_null const& v)
{
    return out;
}

inline std::istream& operator>> ( std::istream & s, value_null & )
{
    return s;
}

namespace detail {
// to mapnik::value_type conversions traits
template <typename T>
struct is_value_bool
{
    constexpr static bool value = std::is_same<T, bool>::value;
};

template <typename T>
struct is_value_integer
{
    constexpr static bool value = std::is_integral<T>::value && !std::is_same<T, bool>::value;
};

template <typename T>
struct is_value_double
{
    constexpr static bool value = std::is_floating_point<T>::value;
};

template <typename T>
struct is_value_unicode_string
{
    constexpr static bool value = std::is_same<T, typename mapnik::value_unicode_string>::value;
};

template <typename T>
struct is_value_string
{
    constexpr static bool value = std::is_same<T, typename std::string>::value;
};

template <typename T>
struct is_value_null
{
    constexpr static bool value = std::is_same<T, typename mapnik::value_null>::value;
};

template <typename T, class Enable = void>
struct mapnik_value_type
{
    using type = T;
};

// value_null
template <typename T>
struct mapnik_value_type<T, typename std::enable_if<detail::is_value_null<T>::value>::type>
{
    using type = mapnik::value_null;
};

// value_bool
template <typename T>
struct mapnik_value_type<T, typename std::enable_if<detail::is_value_bool<T>::value>::type>
{
    using type = mapnik::value_bool;
};

// value_integer
template <typename T>
struct mapnik_value_type<T, typename std::enable_if<detail::is_value_integer<T>::value>::type>
{
    using type = mapnik::value_integer;
};

// value_double
template <typename T>
struct mapnik_value_type<T, typename std::enable_if<detail::is_value_double<T>::value>::type>
{
    using type = mapnik::value_double;
};

// value_unicode_string
template <typename T>
struct mapnik_value_type<T, typename std::enable_if<detail::is_value_unicode_string<T>::value>::type>
{
    using type = mapnik::value_unicode_string;
};

} // namespace detail

} // namespace mapnik

#endif // MAPNIK_VALUE_TYPES_HPP
<|endoftext|>


<commit_before>/**
 *	\file
 */

#pragma once

#include "bases.hpp"
#include "type_name.hpp"
#include <string>
#include <type_traits>
#include <typeindex>
#include <unordered_set>
#include <utility>

namespace module_loader {

/**
 *	A convenience base class for implementing
 *	\ref object or \ref offer.
 *
 *	\tparam T
 *		The type being represented or offered.
 *	\tparam Base
 *		\ref object or \ref offer.
 */
template <typename T, typename Base>
class base : public Base {
template <typename, typename>
friend class base;
public:
	using provides_type = typename Base::provides_type;
private:
	std::string name_;
	provides_type provides_;
	static constexpr bool is_nothrow = std::is_same<T,void>::value &&
		std::is_nothrow_default_constructible<provides_type>::value &&
		std::is_nothrow_move_constructible<provides_type>::value;
	static provides_type get_provides (std::true_type) noexcept(is_nothrow) {
		return provides_type{};
	}
	static provides_type get_provides (std::false_type) {
		return public_unambiguous_bases<T>();
	}
	static provides_type get_provides () noexcept(is_nothrow) {
		return get_provides(typename std::is_same<T,void>::type{});
	}
public:
	base ()
		:	name_(type_name<T>()),
			provides_(get_provides())
	{	}
	template <typename U, typename V>
	explicit base (base<U,V> & other) noexcept(
		std::is_nothrow_default_constructible<std::string>::value &&
		std::is_nothrow_default_constructible<provides_type>::value &&
		std::is_nothrow_default_constructible<Base>::value
	) {
		using std::swap;
		swap(name_,other.name_);
		swap(provides_,other.provides_);
	}
	explicit base (std::string name) noexcept(is_nothrow && std::is_nothrow_move_constructible<std::string>::value)
		:	name_(std::move(name)),
			provides_(get_provides())
	{	}
	virtual const std::string & name () const noexcept override {
		return name_;
	}
	virtual const provides_type & provides () const noexcept override {
		return provides_;
	}
};

}
<commit_msg>module_loader::base - Copy<commit_after>/**
 *	\file
 */

#pragma once

#include "bases.hpp"
#include "type_name.hpp"
#include <string>
#include <type_traits>
#include <typeindex>
#include <unordered_set>
#include <utility>

namespace module_loader {

/**
 *	A convenience base class for implementing
 *	\ref object or \ref offer.
 *
 *	\tparam T
 *		The type being represented or offered.
 *	\tparam Base
 *		\ref object or \ref offer.
 */
template <typename T, typename Base>
class base : public Base {
public:
	using provides_type = typename Base::provides_type;
private:
	std::string name_;
	provides_type provides_;
	static constexpr bool is_nothrow = std::is_same<T,void>::value &&
		std::is_nothrow_default_constructible<provides_type>::value &&
		std::is_nothrow_move_constructible<provides_type>::value;
	static provides_type get_provides (std::true_type) noexcept(is_nothrow) {
		return provides_type{};
	}
	static provides_type get_provides (std::false_type) {
		return public_unambiguous_bases<T>();
	}
	static provides_type get_provides () noexcept(is_nothrow) {
		return get_provides(typename std::is_same<T,void>::type{});
	}
public:
	base ()
		:	name_(type_name<T>()),
			provides_(get_provides())
	{	}
	template <typename U, typename V>
	explicit base (base<U,V> & other)
		:	name_(other.name()),
			provides_(get_provides())
	{	}
	explicit base (std::string name) noexcept(is_nothrow && std::is_nothrow_move_constructible<std::string>::value)
		:	name_(std::move(name)),
			provides_(get_provides())
	{	}
	virtual const std::string & name () const noexcept override {
		return name_;
	}
	virtual const provides_type & provides () const noexcept override {
		return provides_;
	}
};

}
<|endoftext|>


<commit_before>#ifndef _NEVIL_ARENA_SWITCH_HPP_
#define _NEVIL_ARENA_SWITCH_HPP_

#include "nevil/arena/object.hpp"

namespace nevil
{
  class switch_object : public object
  {
  public:
    switch_object();
    switch_object(int x, int y, double size_x, double size_y, double height,
      const Enki::Color &off_color=Enki::Color(0.4, 0.0, 1.0),
      const Enki::Color &on_color=Enki::Color(0.7, 1.0, 1.0));
    virtual ~switch_object();
    void turn_on();
    void turn_off();
  };
}

#endif // _NEVIL_ARENA_SWITCH_HPP_<commit_msg>changed red value of the on switch<commit_after>#ifndef _NEVIL_ARENA_SWITCH_HPP_
#define _NEVIL_ARENA_SWITCH_HPP_

#include "nevil/arena/object.hpp"

namespace nevil
{
  class switch_object : public object
  {
  public:
    switch_object();
    switch_object(int x, int y, double size_x, double size_y, double height,
      const Enki::Color &off_color=Enki::Color(0.4, 0.0, 1.0),
      const Enki::Color &on_color=Enki::Color(0.9, 1.0, 1.0));
    virtual ~switch_object();
    void turn_on();
    void turn_off();
  };
}

#endif // _NEVIL_ARENA_SWITCH_HPP_<|endoftext|>


<commit_before>#ifndef __SGE_ASSET_MANAGER_HPP
#define __SGE_ASSET_MANAGER_HPP

#include <sge/assets/locator.hpp>
#include <sge/assets/loader.hpp>
#include <sge/assets/asset.hpp>
#include <sge/assets/cache.hpp>

#include <unordered_map>
#include <iostream>
#include <memory>
#include <string>
#include <vector>

namespace sge
{
    class AssetManager
    {
        private:
            std::vector<std::shared_ptr<AssetLocator>> locators;
            std::unordered_map<std::string, std::shared_ptr<AssetLoader>> loaders;

            AssetCache cache;

        public:
            void register_locator(std::shared_ptr<AssetLocator> locator);
            void register_loader(std::shared_ptr<AssetLoader> loader, const std::vector<std::string> &extensions);

            void unload(BaseAsset *asset);

            template <typename A, typename D>
            std::shared_ptr<A> load(const D &assetdesc)
            {
                static_assert(std::is_base_of<BaseAsset, A>::value, "Supplied asset type does not inherit from Asset");
                static_assert(std::is_base_of<AssetDescriptor, D>::value, "Supplied descriptor type does not inherit from AssetDescriptor");

                auto passetdesc = std::make_shared<D>(assetdesc);
                std::shared_ptr<A> asset = nullptr;

                if (cache.find(passetdesc) == cache.end())
                {
                    SDL_RWops *input = nullptr;

                    for (auto &locator : locators)
                    {
                        try
                        {
                            input = locator->locate(passetdesc->name());
                        }
                        catch (const AssetLocatorError &e)
                        {
                            std::cerr << "[AssetLocatorError] " << e.what() << std::endl;
                            input = nullptr;
                        }

                        if (input != nullptr)
                        {
                            break;
                        }
                    }

                    if (input != nullptr)
                    {
                        if (loaders.find(passetdesc->extension()) != loaders.end())
                        {
                            auto loader = loaders[passetdesc->extension()];

                            asset = std::shared_ptr<A>(
                                new A(loader, passetdesc),
                                [&](A *ptr_asset)
                                {
                                    BaseAsset *ptr_basset = static_cast<BaseAsset *>(ptr_asset);
                                    unload(ptr_basset);
                                }
                            );

                            try
                            {
                                loader->load(asset, input);
                            }
                            catch (const AssetLoaderError &e)
                            {
                                std::cerr << "[AssetLoaderError] " << e.what() << std::endl;
                                asset.reset();
                            }

                            if (asset != nullptr)
                            {
                                cache[passetdesc] = std::static_pointer_cast<BaseAsset>(asset);
                            }
                        }
                        else
                        {
                            std::cerr << "[AssetLoaderError] No loader found for extension: " << passetdesc->extension() << std::endl;
                        }
                    }
                    else
                    {
                        std::cerr << "[AssetLocatorError] Request asset not found by any locator: " << passetdesc->name() << std::endl;
                    }
                }
                else
                {
                    asset = std::static_pointer_cast<A>(cache[passetdesc].lock());
                }

                return asset;
            }
    };
}

#endif /* __SGE_ASSET_MANAGER_HPP */
<commit_msg>make AssetManager::unload() private<commit_after>#ifndef __SGE_ASSET_MANAGER_HPP
#define __SGE_ASSET_MANAGER_HPP

#include <sge/assets/locator.hpp>
#include <sge/assets/loader.hpp>
#include <sge/assets/asset.hpp>
#include <sge/assets/cache.hpp>

#include <unordered_map>
#include <iostream>
#include <memory>
#include <string>
#include <vector>

namespace sge
{
    class AssetManager
    {
        private:
            std::vector<std::shared_ptr<AssetLocator>> locators;
            std::unordered_map<std::string, std::shared_ptr<AssetLoader>> loaders;

            AssetCache cache;

        public:
            void register_locator(std::shared_ptr<AssetLocator> locator);
            void register_loader(std::shared_ptr<AssetLoader> loader, const std::vector<std::string> &extensions);

            template <typename A, typename D>
            std::shared_ptr<A> load(const D &assetdesc)
            {
                static_assert(std::is_base_of<BaseAsset, A>::value, "Supplied asset type does not inherit from Asset");
                static_assert(std::is_base_of<AssetDescriptor, D>::value, "Supplied descriptor type does not inherit from AssetDescriptor");

                auto passetdesc = std::make_shared<D>(assetdesc);
                std::shared_ptr<A> asset = nullptr;

                if (cache.find(passetdesc) == cache.end())
                {
                    SDL_RWops *input = nullptr;

                    for (auto &locator : locators)
                    {
                        try
                        {
                            input = locator->locate(passetdesc->name());
                        }
                        catch (const AssetLocatorError &e)
                        {
                            std::cerr << "[AssetLocatorError] " << e.what() << std::endl;
                            input = nullptr;
                        }

                        if (input != nullptr)
                        {
                            break;
                        }
                    }

                    if (input != nullptr)
                    {
                        if (loaders.find(passetdesc->extension()) != loaders.end())
                        {
                            auto loader = loaders[passetdesc->extension()];

                            asset = std::shared_ptr<A>(
                                new A(loader, passetdesc),
                                [&](A *ptr_asset)
                                {
                                    BaseAsset *ptr_basset = static_cast<BaseAsset *>(ptr_asset);
                                    unload(ptr_basset);
                                }
                            );

                            try
                            {
                                loader->load(asset, input);
                            }
                            catch (const AssetLoaderError &e)
                            {
                                std::cerr << "[AssetLoaderError] " << e.what() << std::endl;
                                asset.reset();
                            }

                            if (asset != nullptr)
                            {
                                cache[passetdesc] = std::static_pointer_cast<BaseAsset>(asset);
                            }
                        }
                        else
                        {
                            std::cerr << "[AssetLoaderError] No loader found for extension: " << passetdesc->extension() << std::endl;
                        }
                    }
                    else
                    {
                        std::cerr << "[AssetLocatorError] Request asset not found by any locator: " << passetdesc->name() << std::endl;
                    }
                }
                else
                {
                    asset = std::static_pointer_cast<A>(cache[passetdesc].lock());
                }

                return asset;
            }

        private:
            void unload(BaseAsset *asset);
    };
}

#endif /* __SGE_ASSET_MANAGER_HPP */
<|endoftext|>