<commit_before>/** @file

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

#include "tscore/ink_config.h"
#include "tscore/ink_defs.h"
#include "tscore/BufferWriter.h"

#include "ts/ts.h"

#include <string>
#include <string_view>
#include <unordered_map>

#define PLUGIN_NAME "remap_stats"
#define DEBUG_TAG PLUGIN_NAME

#define MAX_STAT_LENGTH (1 << 8)

struct config_t {
  bool post_remap_host;
  int txn_slot;
  TSStatPersistence persist_type;
  TSMutex stat_creation_mutex;
};

// From "core".... sigh, but we need it for now at least.
extern int max_records_entries;

static void
stat_add(const char *name, TSMgmtInt amount, TSStatPersistence persist_type, TSMutex create_mutex)
{
  int stat_id = -1;
  static thread_local std::unordered_map<std::string, int> hash;

  if (unlikely(hash.find(name) == hash.cend())) {
    // This is an unlikely path because we most likely have the stat cached
    // so this mutex won't be much overhead and it fixes a race condition
    // in the RecCore. Hopefully this can be removed in the future.
    TSMutexLock(create_mutex);
    if (TS_ERROR == TSStatFindName(name, &stat_id)) {
      stat_id = TSStatCreate(name, TS_RECORDDATATYPE_INT, persist_type, TS_STAT_SYNC_SUM);
      if (stat_id == TS_ERROR) {
        TSDebug(DEBUG_TAG, "Error creating stat_name: %s", name);
      } else {
        TSDebug(DEBUG_TAG, "Created stat_name: %s stat_id: %d", name, stat_id);
      }
    }
    TSMutexUnlock(create_mutex);

    if (stat_id >= 0) {
      hash.emplace(name, stat_id);
      TSDebug(DEBUG_TAG, "Cached stat_name: %s stat_id: %d", name, stat_id);
    }
  } else {
    stat_id = hash.at(name);
  }

  if (likely(stat_id >= 0)) {
    TSStatIntIncrement(stat_id, amount);
  } else {
    TSDebug(DEBUG_TAG, "stat error! stat_name: %s stat_id: %d", name, stat_id);
  }
}

static char *
get_effective_host(TSHttpTxn txn)
{
  char *effective_url, *tmp;
  const char *host;
  int len;
  TSMBuffer buf;
  TSMLoc url_loc;

  buf = TSMBufferCreate();
  if (TS_SUCCESS != TSUrlCreate(buf, &url_loc)) {
    TSDebug(DEBUG_TAG, "unable to create url");
    TSMBufferDestroy(buf);
    return NULL;
  }
  tmp = effective_url = TSHttpTxnEffectiveUrlStringGet(txn, &len);
  TSUrlParse(buf, url_loc, (const char **)(&tmp), (const char *)(effective_url + len));
  TSfree(effective_url);
  host = TSUrlHostGet(buf, url_loc, &len);
  tmp  = TSstrndup(host, len);
  TSHandleMLocRelease(buf, TS_NULL_MLOC, url_loc);
  TSMBufferDestroy(buf);
  return tmp;
}

static int
handle_read_req_hdr(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
{
  TSHttpTxn txn = (TSHttpTxn)edata;
  config_t *config;
  void *txnd;

  config = static_cast<config_t *>(TSContDataGet(cont));
  txnd   = (void *)get_effective_host(txn); // low bit left 0 because we do not know that remap succeeded yet
  TSHttpTxnArgSet(txn, config->txn_slot, txnd);

  TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
  TSDebug(DEBUG_TAG, "Read Req Handler Finished");
  return 0;
}

static int
handle_post_remap(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
{
  TSHttpTxn txn = static_cast<TSHttpTxn>(edata);
  config_t *config;
  void *txnd = (void *)0x01; // low bit 1 because we are post remap and thus success

  config = static_cast<config_t *>(TSContDataGet(cont));

  if (config->post_remap_host) {
    TSHttpTxnArgSet(txn, config->txn_slot, txnd);
  } else {
    txnd = (void *)((uintptr_t)txnd | (uintptr_t)TSHttpTxnArgGet(txn, config->txn_slot)); // We need the hostname pre-remap
    TSHttpTxnArgSet(txn, config->txn_slot, txnd);
  }

  TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
  TSDebug(DEBUG_TAG, "Post Remap Handler Finished");
  return 0;
}

static void
create_stat_name(ts::LocalBufferWriter<MAX_STAT_LENGTH> &stat_name, std::string_view h, std::string_view b)
{
  stat_name.reset().reduce(1);
  stat_name.print("plugin.{}.{}.{}", PLUGIN_NAME, h, b);
  stat_name.extend(1).write('\0');
}

static int
handle_txn_close(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
{
  TSHttpTxn txn = static_cast<TSHttpTxn>(edata);
  config_t *config;
  void *txnd;
  int status_code = 0;
  TSMBuffer buf;
  TSMLoc hdr_loc;
  uint64_t out_bytes, in_bytes;
  std::string_view remap, hostname;
  std::string_view unknown("unknown");
  ts::LocalBufferWriter<MAX_STAT_LENGTH> stat_name;

  config = static_cast<config_t *>(TSContDataGet(cont));
  txnd   = TSHttpTxnArgGet(txn, config->txn_slot);

  hostname = std::string_view(reinterpret_cast<char *>(reinterpret_cast<uintptr_t>(txnd) & ~0x01)); // Get hostname

  if (txnd) {
    if (reinterpret_cast<uintptr_t>(txnd) & 0x01) // remap succeeded?
    {
      if (!config->post_remap_host) {
        remap = hostname;
      } else {
        remap = get_effective_host(txn);
      }

      if (remap.empty()) {
        remap = unknown;
      }

      in_bytes = TSHttpTxnClientReqHdrBytesGet(txn);
      in_bytes += TSHttpTxnClientReqBodyBytesGet(txn);

      create_stat_name(stat_name, remap, "in_bytes");
      stat_add(stat_name.data(), static_cast<TSMgmtInt>(in_bytes), config->persist_type, config->stat_creation_mutex);

      out_bytes = TSHttpTxnClientRespHdrBytesGet(txn);
      out_bytes += TSHttpTxnClientRespBodyBytesGet(txn);

      create_stat_name(stat_name, remap, "out_bytes");
      stat_add(stat_name.data(), static_cast<TSMgmtInt>(out_bytes), config->persist_type, config->stat_creation_mutex);

      if (TSHttpTxnClientRespGet(txn, &buf, &hdr_loc) == TS_SUCCESS) {
        status_code = static_cast<int>(TSHttpHdrStatusGet(buf, hdr_loc));
        TSHandleMLocRelease(buf, TS_NULL_MLOC, hdr_loc);

        if (status_code < 200) {
          create_stat_name(stat_name, remap, "status_other");
        } else if (status_code <= 299) {
          create_stat_name(stat_name, remap, "status_2xx");
        } else if (status_code <= 399) {
          create_stat_name(stat_name, remap, "status_3xx");
        } else if (status_code <= 499) {
          create_stat_name(stat_name, remap, "status_4xx");
        } else if (status_code <= 599) {
          create_stat_name(stat_name, remap, "status_5xx");
        } else {
          create_stat_name(stat_name, remap, "status_other");
        }

        stat_add(stat_name.data(), 1, config->persist_type, config->stat_creation_mutex);
      } else {
        create_stat_name(stat_name, remap, "status_unknown");
        stat_add(stat_name.data(), 1, config->persist_type, config->stat_creation_mutex);
      }
    }
  }

  TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
  TSDebug(DEBUG_TAG, "Handler Finished");
  return 0;
}

void
TSPluginInit(int argc, const char *argv[])
{
  TSPluginRegistrationInfo info;
  TSCont pre_remap_cont, post_remap_cont, global_cont;

  info.plugin_name   = PLUGIN_NAME;
  info.vendor_name   = "Apache Software Foundation";
  info.support_email = "dev@trafficserver.apache.org";

  if (TSPluginRegister(&info) != TS_SUCCESS) {
    TSError("[remap_stats] Plugin registration failed");

    return;
  } else {
    TSDebug(DEBUG_TAG, "Plugin registration succeeded");
  }

  auto config                 = new config_t;
  config->post_remap_host     = false;
  config->persist_type        = TS_STAT_NON_PERSISTENT;
  config->stat_creation_mutex = TSMutexCreate();

  if (argc > 1) {
    // Argument parser
    for (auto i = 0; i < argc; i++) {
      const std::string arg(argv[i]);
      if (arg == "-P" || arg == "--post-remap-host") {
        config->post_remap_host = true;
        TSDebug(DEBUG_TAG, "Using post remap hostname");
      } else if (arg == "-p" || arg == "--persistent") {
        config->persist_type = TS_STAT_PERSISTENT;
        TSDebug(DEBUG_TAG, "Using persistent stats");
      }
    }
  }

  TSHttpTxnArgIndexReserve(PLUGIN_NAME, "txn data", &(config->txn_slot));

  if (!config->post_remap_host) {
    pre_remap_cont = TSContCreate(handle_read_req_hdr, NULL);
    TSContDataSet(pre_remap_cont, static_cast<void *>(config));
    TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, pre_remap_cont);
  }

  post_remap_cont = TSContCreate(handle_post_remap, NULL);
  TSContDataSet(post_remap_cont, static_cast<void *>(config));
  TSHttpHookAdd(TS_HTTP_POST_REMAP_HOOK, post_remap_cont);

  global_cont = TSContCreate(handle_txn_close, NULL);
  TSContDataSet(global_cont, static_cast<void *>(config));
  TSHttpHookAdd(TS_HTTP_TXN_CLOSE_HOOK, global_cont);

  TSDebug(DEBUG_TAG, "Init complete");
}
<commit_msg>remap_stats: Fix BufferWriter usage error.<commit_after>/** @file

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

#include "tscore/ink_config.h"
#include "tscore/ink_defs.h"
#include "tscore/BufferWriter.h"

#include "ts/ts.h"

#include <string>
#include <string_view>
#include <unordered_map>

#define PLUGIN_NAME "remap_stats"
#define DEBUG_TAG PLUGIN_NAME

#define MAX_STAT_LENGTH (1 << 8)

struct config_t {
  bool post_remap_host;
  int txn_slot;
  TSStatPersistence persist_type;
  TSMutex stat_creation_mutex;
};

// From "core".... sigh, but we need it for now at least.
extern int max_records_entries;

static void
stat_add(const char *name, TSMgmtInt amount, TSStatPersistence persist_type, TSMutex create_mutex)
{
  int stat_id = -1;
  static thread_local std::unordered_map<std::string, int> hash;

  if (unlikely(hash.find(name) == hash.cend())) {
    // This is an unlikely path because we most likely have the stat cached
    // so this mutex won't be much overhead and it fixes a race condition
    // in the RecCore. Hopefully this can be removed in the future.
    TSMutexLock(create_mutex);
    if (TS_ERROR == TSStatFindName(name, &stat_id)) {
      stat_id = TSStatCreate(name, TS_RECORDDATATYPE_INT, persist_type, TS_STAT_SYNC_SUM);
      if (stat_id == TS_ERROR) {
        TSDebug(DEBUG_TAG, "Error creating stat_name: %s", name);
      } else {
        TSDebug(DEBUG_TAG, "Created stat_name: %s stat_id: %d", name, stat_id);
      }
    }
    TSMutexUnlock(create_mutex);

    if (stat_id >= 0) {
      hash.emplace(name, stat_id);
      TSDebug(DEBUG_TAG, "Cached stat_name: %s stat_id: %d", name, stat_id);
    }
  } else {
    stat_id = hash.at(name);
  }

  if (likely(stat_id >= 0)) {
    TSStatIntIncrement(stat_id, amount);
  } else {
    TSDebug(DEBUG_TAG, "stat error! stat_name: %s stat_id: %d", name, stat_id);
  }
}

static char *
get_effective_host(TSHttpTxn txn)
{
  char *effective_url, *tmp;
  const char *host;
  int len;
  TSMBuffer buf;
  TSMLoc url_loc;

  buf = TSMBufferCreate();
  if (TS_SUCCESS != TSUrlCreate(buf, &url_loc)) {
    TSDebug(DEBUG_TAG, "unable to create url");
    TSMBufferDestroy(buf);
    return NULL;
  }
  tmp = effective_url = TSHttpTxnEffectiveUrlStringGet(txn, &len);
  TSUrlParse(buf, url_loc, (const char **)(&tmp), (const char *)(effective_url + len));
  TSfree(effective_url);
  host = TSUrlHostGet(buf, url_loc, &len);
  tmp  = TSstrndup(host, len);
  TSHandleMLocRelease(buf, TS_NULL_MLOC, url_loc);
  TSMBufferDestroy(buf);
  return tmp;
}

static int
handle_read_req_hdr(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
{
  TSHttpTxn txn = (TSHttpTxn)edata;
  config_t *config;
  void *txnd;

  config = static_cast<config_t *>(TSContDataGet(cont));
  txnd   = (void *)get_effective_host(txn); // low bit left 0 because we do not know that remap succeeded yet
  TSHttpTxnArgSet(txn, config->txn_slot, txnd);

  TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
  TSDebug(DEBUG_TAG, "Read Req Handler Finished");
  return 0;
}

static int
handle_post_remap(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
{
  TSHttpTxn txn = static_cast<TSHttpTxn>(edata);
  config_t *config;
  void *txnd = (void *)0x01; // low bit 1 because we are post remap and thus success

  config = static_cast<config_t *>(TSContDataGet(cont));

  if (config->post_remap_host) {
    TSHttpTxnArgSet(txn, config->txn_slot, txnd);
  } else {
    txnd = (void *)((uintptr_t)txnd | (uintptr_t)TSHttpTxnArgGet(txn, config->txn_slot)); // We need the hostname pre-remap
    TSHttpTxnArgSet(txn, config->txn_slot, txnd);
  }

  TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
  TSDebug(DEBUG_TAG, "Post Remap Handler Finished");
  return 0;
}

static void
create_stat_name(ts::FixedBufferWriter &stat_name, std::string_view h, std::string_view b)
{
  stat_name.reset().clip(1);
  stat_name.print("plugin.{}.{}.{}", PLUGIN_NAME, h, b);
  stat_name.extend(1).write('\0');
}

static int
handle_txn_close(TSCont cont, TSEvent event ATS_UNUSED, void *edata)
{
  TSHttpTxn txn = static_cast<TSHttpTxn>(edata);
  config_t *config;
  void *txnd;
  int status_code = 0;
  TSMBuffer buf;
  TSMLoc hdr_loc;
  uint64_t out_bytes, in_bytes;
  std::string_view remap, hostname;
  std::string_view unknown("unknown");
  ts::LocalBufferWriter<MAX_STAT_LENGTH> stat_name;

  config = static_cast<config_t *>(TSContDataGet(cont));
  txnd   = TSHttpTxnArgGet(txn, config->txn_slot);

  hostname = std::string_view(reinterpret_cast<char *>(reinterpret_cast<uintptr_t>(txnd) & ~0x01)); // Get hostname

  if (txnd) {
    if (reinterpret_cast<uintptr_t>(txnd) & 0x01) // remap succeeded?
    {
      if (!config->post_remap_host) {
        remap = hostname;
      } else {
        remap = get_effective_host(txn);
      }

      if (remap.empty()) {
        remap = unknown;
      }

      in_bytes = TSHttpTxnClientReqHdrBytesGet(txn);
      in_bytes += TSHttpTxnClientReqBodyBytesGet(txn);

      create_stat_name(stat_name, remap, "in_bytes");
      stat_add(stat_name.data(), static_cast<TSMgmtInt>(in_bytes), config->persist_type, config->stat_creation_mutex);

      out_bytes = TSHttpTxnClientRespHdrBytesGet(txn);
      out_bytes += TSHttpTxnClientRespBodyBytesGet(txn);

      create_stat_name(stat_name, remap, "out_bytes");
      stat_add(stat_name.data(), static_cast<TSMgmtInt>(out_bytes), config->persist_type, config->stat_creation_mutex);

      if (TSHttpTxnClientRespGet(txn, &buf, &hdr_loc) == TS_SUCCESS) {
        status_code = static_cast<int>(TSHttpHdrStatusGet(buf, hdr_loc));
        TSHandleMLocRelease(buf, TS_NULL_MLOC, hdr_loc);

        if (status_code < 200) {
          create_stat_name(stat_name, remap, "status_other");
        } else if (status_code <= 299) {
          create_stat_name(stat_name, remap, "status_2xx");
        } else if (status_code <= 399) {
          create_stat_name(stat_name, remap, "status_3xx");
        } else if (status_code <= 499) {
          create_stat_name(stat_name, remap, "status_4xx");
        } else if (status_code <= 599) {
          create_stat_name(stat_name, remap, "status_5xx");
        } else {
          create_stat_name(stat_name, remap, "status_other");
        }

        stat_add(stat_name.data(), 1, config->persist_type, config->stat_creation_mutex);
      } else {
        create_stat_name(stat_name, remap, "status_unknown");
        stat_add(stat_name.data(), 1, config->persist_type, config->stat_creation_mutex);
      }
    }
  }

  TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
  TSDebug(DEBUG_TAG, "Handler Finished");
  return 0;
}

void
TSPluginInit(int argc, const char *argv[])
{
  TSPluginRegistrationInfo info;
  TSCont pre_remap_cont, post_remap_cont, global_cont;

  info.plugin_name   = PLUGIN_NAME;
  info.vendor_name   = "Apache Software Foundation";
  info.support_email = "dev@trafficserver.apache.org";

  if (TSPluginRegister(&info) != TS_SUCCESS) {
    TSError("[remap_stats] Plugin registration failed");

    return;
  } else {
    TSDebug(DEBUG_TAG, "Plugin registration succeeded");
  }

  auto config                 = new config_t;
  config->post_remap_host     = false;
  config->persist_type        = TS_STAT_NON_PERSISTENT;
  config->stat_creation_mutex = TSMutexCreate();

  if (argc > 1) {
    // Argument parser
    for (auto i = 0; i < argc; i++) {
      const std::string arg(argv[i]);
      if (arg == "-P" || arg == "--post-remap-host") {
        config->post_remap_host = true;
        TSDebug(DEBUG_TAG, "Using post remap hostname");
      } else if (arg == "-p" || arg == "--persistent") {
        config->persist_type = TS_STAT_PERSISTENT;
        TSDebug(DEBUG_TAG, "Using persistent stats");
      }
    }
  }

  TSHttpTxnArgIndexReserve(PLUGIN_NAME, "txn data", &(config->txn_slot));

  if (!config->post_remap_host) {
    pre_remap_cont = TSContCreate(handle_read_req_hdr, NULL);
    TSContDataSet(pre_remap_cont, static_cast<void *>(config));
    TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, pre_remap_cont);
  }

  post_remap_cont = TSContCreate(handle_post_remap, NULL);
  TSContDataSet(post_remap_cont, static_cast<void *>(config));
  TSHttpHookAdd(TS_HTTP_POST_REMAP_HOOK, post_remap_cont);

  global_cont = TSContCreate(handle_txn_close, NULL);
  TSContDataSet(global_cont, static_cast<void *>(config));
  TSHttpHookAdd(TS_HTTP_TXN_CLOSE_HOOK, global_cont);

  TSDebug(DEBUG_TAG, "Init complete");
}
<|endoftext|>


<commit_before>// lock_ios.cpp - Per-stream synchronization.
// Copyright 2016 by David Krauss.
// This source is released under the MIT license, http://opensource.org/licenses/MIT

#include "lock_ios.h"

#include <cassert>
#include <ios>
#include <stdexcept>
#include <system_error>

namespace s6_lock_ios {

namespace {
int ios_index() {
    static int value = std::ios_base::xalloc();
    return value;
}

bool good( std::ios_base const & s )
#ifdef _LIBCPP_VERSION
    { return s.good(); }
#else
    { return true; }
#endif
}

std::ios_base & mutex_init_own( std::ios_base & s ) {
    assert ( good( s ) && "mutex_init_own called on bad stream." );

    void *& ptr = s.pword( ios_index() );
    if ( ptr ) return s;

    s.register_callback( + []( std::ios_base::event e, std::ios_base & s, int ) {
        void *& ptr = s.pword( ios_index() );
        if ( e == std::ios_base::erase_event ) {
            // When the stream is terminated, destroy the mutex.
            delete static_cast< std::recursive_mutex * >( ptr );
            ptr = nullptr; // Do not double delete after copyfmt.

        } else if ( e == std::ios_base::copyfmt_event ) {
            ptr = nullptr; // Do not copy mutex access.
            // Note, copyfmt does not copy rdbuf or otherwise promote races.
        }
    }, 0 );

#ifdef _LIBCPP_VERSION
    try {
        if ( ! good( s ) ) throw std::bad_alloc{}; // pword or register_callback failed.
        ptr = new std::recursive_mutex; // Throw std::bad_alloc or std::system_error.
    } catch (...) {
        s.setf( std::ios_base::badbit );
    }
#else
    ptr = new std::recursive_mutex;
    // Can't detect pword or register_callback failure; can't set badbit.
#endif

    return s;
}

std::ios_base & mutex_init( std::ios_base & s ) {
    static std::mutex critical;
    std::lock_guard< std::mutex > guard( critical );

    if ( ! s.pword( ios_index() ) ) {
        mutex_init_own( s );
    }
    return s;
}

namespace impl {
void manip::acquire( std::ios_base & s ) const {
    /*  Accessing pword here assumes that the implementation modifies nothing while
        retrieving a preexisting entry. */
    if ( void * ptr = s.pword( ios_index() ) ) {
        l = ios_lock( * static_cast< std::recursive_mutex * >( ptr ) );
    } else {
        // Imitate error handling of unique_lock::lock.
        throw std::system_error( std::make_error_code( std::errc::operation_not_permitted ), "shared stream is missing a mutex" );
    }
}
}
}
<commit_msg>Do not swallow exceptions.<commit_after>// lock_ios.cpp - Per-stream synchronization.
// Copyright 2016 by David Krauss.
// This source is released under the MIT license, http://opensource.org/licenses/MIT

#include "lock_ios.h"

#include <cassert>
#include <ios>
#include <stdexcept>
#include <system_error>

namespace s6_lock_ios {

namespace {
int ios_index() {
    static int value = std::ios_base::xalloc();
    return value;
}

bool good( std::ios_base const & s )
#ifdef _LIBCPP_VERSION
    { return s.good(); }
#else
    { return true; }
#endif
}

std::ios_base & mutex_init_own( std::ios_base & s ) {
    assert ( good( s ) && "mutex_init_own called on bad stream." );

    void *& ptr = s.pword( ios_index() );
    if ( ptr ) return s;

    s.register_callback( + []( std::ios_base::event e, std::ios_base & s, int ) {
        void *& ptr = s.pword( ios_index() );
        if ( e == std::ios_base::erase_event ) {
            // When the stream is terminated, destroy the mutex.
            delete static_cast< std::recursive_mutex * >( ptr );
            ptr = nullptr; // Do not double delete after copyfmt.

        } else if ( e == std::ios_base::copyfmt_event ) {
            ptr = nullptr; // Do not copy mutex access.
            // Note, copyfmt does not copy rdbuf or otherwise promote races.
        }
    }, 0 );

#ifdef _LIBCPP_VERSION
    try {
        if ( ! good( s ) ) throw std::bad_alloc{}; // pword or register_callback failed.
        ptr = new std::recursive_mutex; // Throw std::bad_alloc or std::system_error.
    } catch (...) {
        s.setf( std::ios_base::badbit );
        throw;
    }
#else
    ptr = new std::recursive_mutex;
    // Can't detect pword or register_callback failure; can't set badbit.
#endif

    return s;
}

std::ios_base & mutex_init( std::ios_base & s ) {
    static std::mutex critical;
    std::lock_guard< std::mutex > guard( critical );

    if ( ! s.pword( ios_index() ) ) {
        mutex_init_own( s );
    }
    return s;
}

namespace impl {
void manip::acquire( std::ios_base & s ) const {
    /*  Accessing pword here assumes that the implementation modifies nothing while
        retrieving a preexisting entry. */
    if ( void * ptr = s.pword( ios_index() ) ) {
        l = ios_lock( * static_cast< std::recursive_mutex * >( ptr ) );
    } else {
        // Imitate error handling of unique_lock::lock.
        throw std::system_error( std::make_error_code( std::errc::operation_not_permitted ), "shared stream is missing a mutex" );
    }
}
}
}
<|endoftext|>


<commit_before>// Copyright 2008, Google Inc.
// 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 the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// 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 COPYRIGHT
// OWNER 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.
//
// Author: wan@google.com (Zhanyong Wan)

#include <gtest/internal/gtest-port.h>

#include <limits.h>
#ifdef GTEST_HAS_DEATH_TEST
#include <regex.h>
#endif  // GTEST_HAS_DEATH_TEST
#include <stdlib.h>
#include <stdio.h>

#include <gtest/gtest-spi.h>
#include <gtest/gtest-message.h>
#include <gtest/internal/gtest-string.h>

namespace testing {
namespace internal {

#ifdef GTEST_HAS_DEATH_TEST

// Implements RE.  Currently only needed for death tests.

RE::~RE() {
  regfree(&regex_);
  free(const_cast<char*>(pattern_));
}

// Returns true iff str contains regular expression re.
bool RE::PartialMatch(const char* str, const RE& re) {
  if (!re.is_valid_) return false;

  regmatch_t match;
  return regexec(&re.regex_, str, 1, &match, 0) == 0;
}

// Initializes an RE from its string representation.
void RE::Init(const char* regex) {
  pattern_ = strdup(regex);
  is_valid_ = regcomp(&regex_, regex, REG_EXTENDED) == 0;
  EXPECT_TRUE(is_valid_)
      << "Regular expression \"" << regex
      << "\" is not a valid POSIX Extended regular expression.";
}

#endif  // GTEST_HAS_DEATH_TEST

// Logs a message at the given severity level.
void GTestLog(GTestLogSeverity severity, const char* file,
              int line, const char* msg) {
  const char* const marker =
      severity == GTEST_INFO ?    "[  INFO ]" :
      severity == GTEST_WARNING ? "[WARNING]" :
      severity == GTEST_ERROR ?   "[ ERROR ]" : "[ FATAL ]";
  fprintf(stderr, "\n%s %s:%d: %s\n", marker, file, line, msg);
  if (severity == GTEST_FATAL) {
    abort();
  }
}

#ifdef GTEST_HAS_DEATH_TEST

// Defines the stderr capturer.

class CapturedStderr {
 public:
  // The ctor redirects stderr to a temporary file.
  CapturedStderr() {
    uncaptured_fd_ = dup(STDERR_FILENO);

    char name_template[] = "captured_stderr.XXXXXX";
    const int captured_fd = mkstemp(name_template);
    filename_ = name_template;
    fflush(NULL);
    dup2(captured_fd, STDERR_FILENO);
    close(captured_fd);
  }

  ~CapturedStderr() {
    remove(filename_.c_str());
  }

  // Stops redirecting stderr.
  void StopCapture() {
    // Restores the original stream.
    fflush(NULL);
    dup2(uncaptured_fd_, STDERR_FILENO);
    close(uncaptured_fd_);
    uncaptured_fd_ = -1;
  }

  // Returns the name of the temporary file holding the stderr output.
  // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
  // can use it here.
  ::std::string filename() const { return filename_; }

 private:
  int uncaptured_fd_;
  ::std::string filename_;
};

static CapturedStderr* g_captured_stderr = NULL;

// Returns the size (in bytes) of a file.
static size_t GetFileSize(FILE * file) {
  fseek(file, 0, SEEK_END);
  return static_cast<size_t>(ftell(file));
}

// Reads the entire content of a file as a string.
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can
// use it here.
static ::std::string ReadEntireFile(FILE * file) {
  const size_t file_size = GetFileSize(file);
  char* const buffer = new char[file_size];

  size_t bytes_last_read = 0;  // # of bytes read in the last fread()
  size_t bytes_read = 0;       // # of bytes read so far

  fseek(file, 0, SEEK_SET);

  // Keeps reading the file until we cannot read further or the
  // pre-determined file size is reached.
  do {
    bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
    bytes_read += bytes_last_read;
  } while (bytes_last_read > 0 && bytes_read < file_size);

  const ::std::string content(buffer, buffer+bytes_read);
  delete[] buffer;

  return content;
}

// Starts capturing stderr.
void CaptureStderr() {
  if (g_captured_stderr != NULL) {
    GTEST_LOG(FATAL, "Only one stderr capturer can exist at one time.");
  }
  g_captured_stderr = new CapturedStderr;
}

// Stops capturing stderr and returns the captured string.
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can
// use it here.
::std::string GetCapturedStderr() {
  g_captured_stderr->StopCapture();
  FILE* const file = fopen(g_captured_stderr->filename().c_str(), "r");
  const ::std::string content = ReadEntireFile(file);
  fclose(file);

  delete g_captured_stderr;
  g_captured_stderr = NULL;

  return content;
}

// A copy of all command line arguments.  Set by InitGoogleTest().
::std::vector<String> g_argvs;

// Returns the command line as a vector of strings.
const ::std::vector<String>& GetArgvs() { return g_argvs; }

#endif  // GTEST_HAS_DEATH_TEST

// Returns the name of the environment variable corresponding to the
// given flag.  For example, FlagToEnvVar("foo") will return
// "GTEST_FOO" in the open-source version.
static String FlagToEnvVar(const char* flag) {
  const String full_flag = (Message() << GTEST_FLAG_PREFIX << flag).GetString();

  Message env_var;
  for (int i = 0; i != full_flag.GetLength(); i++) {
    env_var << static_cast<char>(toupper(full_flag.c_str()[i]));
  }

  return env_var.GetString();
}

// Reads and returns the Boolean environment variable corresponding to
// the given flag; if it's not set, returns default_value.
//
// The value is considered true iff it's not "0".
bool BoolFromGTestEnv(const char* flag, bool default_value) {
  const String env_var = FlagToEnvVar(flag);
  const char* const string_value = GetEnv(env_var.c_str());
  return string_value == NULL ?
      default_value : strcmp(string_value, "0") != 0;
}

// Parses 'str' for a 32-bit signed integer.  If successful, writes
// the result to *value and returns true; otherwise leaves *value
// unchanged and returns false.
bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
  // Parses the environment variable as a decimal integer.
  char* end = NULL;
  const long long_value = strtol(str, &end, 10);  // NOLINT

  // Has strtol() consumed all characters in the string?
  if (*end != '\0') {
    // No - an invalid character was encountered.
    Message msg;
    msg << "WARNING: " << src_text
        << " is expected to be a 32-bit integer, but actually"
        << " has value \"" << str << "\".\n";
    printf("%s", msg.GetString().c_str());
    fflush(stdout);
    return false;
  }

  // Is the parsed value in the range of an Int32?
  const Int32 result = static_cast<Int32>(long_value);
  if (long_value == LONG_MAX || long_value == LONG_MIN ||
      // The parsed value overflows as a long.  (strtol() returns
      // LONG_MAX or LONG_MIN when the input overflows.)
      result != long_value
      // The parsed value overflows as an Int32.
      ) {
    Message msg;
    msg << "WARNING: " << src_text
        << " is expected to be a 32-bit integer, but actually"
        << " has value " << str << ", which overflows.\n";
    printf("%s", msg.GetString().c_str());
    fflush(stdout);
    return false;
  }

  *value = result;
  return true;
}

// Reads and returns a 32-bit integer stored in the environment
// variable corresponding to the given flag; if it isn't set or
// doesn't represent a valid 32-bit integer, returns default_value.
Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
  const String env_var = FlagToEnvVar(flag);
  const char* const string_value = GetEnv(env_var.c_str());
  if (string_value == NULL) {
    // The environment variable is not set.
    return default_value;
  }

  Int32 result = default_value;
  if (!ParseInt32(Message() << "Environment variable " << env_var,
                  string_value, &result)) {
    printf("The default value %s is used.\n",
           (Message() << default_value).GetString().c_str());
    fflush(stdout);
    return default_value;
  }

  return result;
}

// Reads and returns the string environment variable corresponding to
// the given flag; if it's not set, returns default_value.
const char* StringFromGTestEnv(const char* flag, const char* default_value) {
  const String env_var = FlagToEnvVar(flag);
  const char* const value = GetEnv(env_var.c_str());
  return value == NULL ? default_value : value;
}

}  // namespace internal
}  // namespace testing
<commit_msg>Makes death tests create temporary files in /tmp instead of the current folder.<commit_after>// Copyright 2008, Google Inc.
// 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 the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// 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 COPYRIGHT
// OWNER 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.
//
// Author: wan@google.com (Zhanyong Wan)

#include <gtest/internal/gtest-port.h>

#include <limits.h>
#ifdef GTEST_HAS_DEATH_TEST
#include <regex.h>
#endif  // GTEST_HAS_DEATH_TEST
#include <stdlib.h>
#include <stdio.h>

#include <gtest/gtest-spi.h>
#include <gtest/gtest-message.h>
#include <gtest/internal/gtest-string.h>

namespace testing {
namespace internal {

#ifdef GTEST_HAS_DEATH_TEST

// Implements RE.  Currently only needed for death tests.

RE::~RE() {
  regfree(&regex_);
  free(const_cast<char*>(pattern_));
}

// Returns true iff str contains regular expression re.
bool RE::PartialMatch(const char* str, const RE& re) {
  if (!re.is_valid_) return false;

  regmatch_t match;
  return regexec(&re.regex_, str, 1, &match, 0) == 0;
}

// Initializes an RE from its string representation.
void RE::Init(const char* regex) {
  pattern_ = strdup(regex);
  is_valid_ = regcomp(&regex_, regex, REG_EXTENDED) == 0;
  EXPECT_TRUE(is_valid_)
      << "Regular expression \"" << regex
      << "\" is not a valid POSIX Extended regular expression.";
}

#endif  // GTEST_HAS_DEATH_TEST

// Logs a message at the given severity level.
void GTestLog(GTestLogSeverity severity, const char* file,
              int line, const char* msg) {
  const char* const marker =
      severity == GTEST_INFO ?    "[  INFO ]" :
      severity == GTEST_WARNING ? "[WARNING]" :
      severity == GTEST_ERROR ?   "[ ERROR ]" : "[ FATAL ]";
  fprintf(stderr, "\n%s %s:%d: %s\n", marker, file, line, msg);
  if (severity == GTEST_FATAL) {
    abort();
  }
}

#ifdef GTEST_HAS_DEATH_TEST

// Defines the stderr capturer.

class CapturedStderr {
 public:
  // The ctor redirects stderr to a temporary file.
  CapturedStderr() {
    uncaptured_fd_ = dup(STDERR_FILENO);

    // There's no guarantee that a test has write access to the
    // current directory, so we create the temporary file in the /tmp
    // directory instead.
    char name_template[] = "/tmp/captured_stderr.XXXXXX";
    const int captured_fd = mkstemp(name_template);
    filename_ = name_template;
    fflush(NULL);
    dup2(captured_fd, STDERR_FILENO);
    close(captured_fd);
  }

  ~CapturedStderr() {
    remove(filename_.c_str());
  }

  // Stops redirecting stderr.
  void StopCapture() {
    // Restores the original stream.
    fflush(NULL);
    dup2(uncaptured_fd_, STDERR_FILENO);
    close(uncaptured_fd_);
    uncaptured_fd_ = -1;
  }

  // Returns the name of the temporary file holding the stderr output.
  // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
  // can use it here.
  ::std::string filename() const { return filename_; }

 private:
  int uncaptured_fd_;
  ::std::string filename_;
};

static CapturedStderr* g_captured_stderr = NULL;

// Returns the size (in bytes) of a file.
static size_t GetFileSize(FILE * file) {
  fseek(file, 0, SEEK_END);
  return static_cast<size_t>(ftell(file));
}

// Reads the entire content of a file as a string.
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can
// use it here.
static ::std::string ReadEntireFile(FILE * file) {
  const size_t file_size = GetFileSize(file);
  char* const buffer = new char[file_size];

  size_t bytes_last_read = 0;  // # of bytes read in the last fread()
  size_t bytes_read = 0;       // # of bytes read so far

  fseek(file, 0, SEEK_SET);

  // Keeps reading the file until we cannot read further or the
  // pre-determined file size is reached.
  do {
    bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
    bytes_read += bytes_last_read;
  } while (bytes_last_read > 0 && bytes_read < file_size);

  const ::std::string content(buffer, buffer+bytes_read);
  delete[] buffer;

  return content;
}

// Starts capturing stderr.
void CaptureStderr() {
  if (g_captured_stderr != NULL) {
    GTEST_LOG(FATAL, "Only one stderr capturer can exist at one time.");
  }
  g_captured_stderr = new CapturedStderr;
}

// Stops capturing stderr and returns the captured string.
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can
// use it here.
::std::string GetCapturedStderr() {
  g_captured_stderr->StopCapture();
  FILE* const file = fopen(g_captured_stderr->filename().c_str(), "r");
  const ::std::string content = ReadEntireFile(file);
  fclose(file);

  delete g_captured_stderr;
  g_captured_stderr = NULL;

  return content;
}

// A copy of all command line arguments.  Set by InitGoogleTest().
::std::vector<String> g_argvs;

// Returns the command line as a vector of strings.
const ::std::vector<String>& GetArgvs() { return g_argvs; }

#endif  // GTEST_HAS_DEATH_TEST

// Returns the name of the environment variable corresponding to the
// given flag.  For example, FlagToEnvVar("foo") will return
// "GTEST_FOO" in the open-source version.
static String FlagToEnvVar(const char* flag) {
  const String full_flag = (Message() << GTEST_FLAG_PREFIX << flag).GetString();

  Message env_var;
  for (int i = 0; i != full_flag.GetLength(); i++) {
    env_var << static_cast<char>(toupper(full_flag.c_str()[i]));
  }

  return env_var.GetString();
}

// Reads and returns the Boolean environment variable corresponding to
// the given flag; if it's not set, returns default_value.
//
// The value is considered true iff it's not "0".
bool BoolFromGTestEnv(const char* flag, bool default_value) {
  const String env_var = FlagToEnvVar(flag);
  const char* const string_value = GetEnv(env_var.c_str());
  return string_value == NULL ?
      default_value : strcmp(string_value, "0") != 0;
}

// Parses 'str' for a 32-bit signed integer.  If successful, writes
// the result to *value and returns true; otherwise leaves *value
// unchanged and returns false.
bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
  // Parses the environment variable as a decimal integer.
  char* end = NULL;
  const long long_value = strtol(str, &end, 10);  // NOLINT

  // Has strtol() consumed all characters in the string?
  if (*end != '\0') {
    // No - an invalid character was encountered.
    Message msg;
    msg << "WARNING: " << src_text
        << " is expected to be a 32-bit integer, but actually"
        << " has value \"" << str << "\".\n";
    printf("%s", msg.GetString().c_str());
    fflush(stdout);
    return false;
  }

  // Is the parsed value in the range of an Int32?
  const Int32 result = static_cast<Int32>(long_value);
  if (long_value == LONG_MAX || long_value == LONG_MIN ||
      // The parsed value overflows as a long.  (strtol() returns
      // LONG_MAX or LONG_MIN when the input overflows.)
      result != long_value
      // The parsed value overflows as an Int32.
      ) {
    Message msg;
    msg << "WARNING: " << src_text
        << " is expected to be a 32-bit integer, but actually"
        << " has value " << str << ", which overflows.\n";
    printf("%s", msg.GetString().c_str());
    fflush(stdout);
    return false;
  }

  *value = result;
  return true;
}

// Reads and returns a 32-bit integer stored in the environment
// variable corresponding to the given flag; if it isn't set or
// doesn't represent a valid 32-bit integer, returns default_value.
Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
  const String env_var = FlagToEnvVar(flag);
  const char* const string_value = GetEnv(env_var.c_str());
  if (string_value == NULL) {
    // The environment variable is not set.
    return default_value;
  }

  Int32 result = default_value;
  if (!ParseInt32(Message() << "Environment variable " << env_var,
                  string_value, &result)) {
    printf("The default value %s is used.\n",
           (Message() << default_value).GetString().c_str());
    fflush(stdout);
    return default_value;
  }

  return result;
}

// Reads and returns the string environment variable corresponding to
// the given flag; if it's not set, returns default_value.
const char* StringFromGTestEnv(const char* flag, const char* default_value) {
  const String env_var = FlagToEnvVar(flag);
  const char* const value = GetEnv(env_var.c_str());
  return value == NULL ? default_value : value;
}

}  // namespace internal
}  // namespace testing
<|endoftext|>


<commit_before>#include "ClassWrapper.h"
#include "JavaClassUtils.h"
#include "JavaExceptionUtils.h"
#include "JniWeakGlobalRef.h"
#include <string.h>

namespace spotify {
namespace jni {

ClassWrapper::~ClassWrapper() {
  // TODO: Delete mappings
}

bool ClassWrapper::isInitialized() const {
  return _clazz.get() != NULL;
}

const char* ClassWrapper::getSimpleName() const {
  const char* lastSlash = strrchr(getCanonicalName(), '/');
  return lastSlash != NULL ? lastSlash + 1 : getCanonicalName();
}

void ClassWrapper::merge(const ClassWrapper *globalInstance) {
  _clazz = globalInstance->_clazz;
  _methods = globalInstance->_methods;
  _fields = globalInstance->_fields;
  _constructor = globalInstance->_constructor;
}

bool ClassWrapper::persist(JNIEnv *env, jobject javaThis) {
  if (isPersisted()) {
    jlong resultPtr = reinterpret_cast<jlong>(this);
    env->SetLongField(javaThis, getField(PERSIST_FIELD_NAME), resultPtr);
    return true;
  }
  return false;
}

bool ClassWrapper::isPersisted() const {
  // TODO: Need test for this
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalStateException,
      "Cannot call isPersisted without class info (forgot to merge?)");
    return false;
  }

  // We expect the persisted field to be cached, otherwise searching for persisted
  // fields in non-persisted classes will throw java.lang.NoSuchField exception. :(
  const std::string key(PERSIST_FIELD_NAME);
  FieldMap::const_iterator mapFindIter = _fields.find(key);
  return mapFindIter != _fields.end();
}

ClassWrapper* ClassWrapper::getPersistedInstance(JNIEnv *env, jobject javaThis) const {
  if (isPersisted()) {
    jlong resultPtr = env->GetLongField(javaThis, getField(PERSIST_FIELD_NAME));
    return reinterpret_cast<ClassWrapper*>(resultPtr);
  } else {
    return NULL;
  }
}

void ClassWrapper::destroy(JNIEnv *env, jobject javaThis) {
  if (isPersisted()) {
    jfieldID persistField = getField(PERSIST_FIELD_NAME);
    jlong resultPtr = env->GetLongField(javaThis, persistField);
    ClassWrapper *instance = reinterpret_cast<ClassWrapper*>(resultPtr);
    if (instance != NULL) {
      delete instance;
      env->SetLongField(javaThis, persistField, 0);
    }
  }
}

void ClassWrapper::setJavaObject(JNIEnv *env, jobject javaThis) {
  // Set up field mappings, if this has not already been done
  if (_field_mappings.empty()) {
    mapFields();
  }

  FieldMap::iterator iter;
  for (iter = _fields.begin(); iter != _fields.end(); ++iter) {
    std::string key = iter->first;
    jfieldID field = iter->second;
    FieldMapping *mapping = _field_mappings[key]; // TODO: Should use getter here, if not null will be inserted
    if (field != NULL && mapping != NULL) {
      if (TYPE_EQUALS(mapping->type, kTypeInt)) {
        int *address = static_cast<int*>(mapping->address);
        *address = env->GetIntField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeFloat)) {
        float *address = static_cast<float*>(mapping->address);
        *address = env->GetFloatField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeString)) {
        jstring string = (jstring)env->GetObjectField(javaThis, field);
        JavaString *address = static_cast<JavaString*>(mapping->address);
        address->setValue(env, string);
      } else {
        // TODO throw
      }
    }
  }
}

jobject ClassWrapper::toJavaObject(JNIEnv *env) {
  if (_constructor == NULL) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Cannot call toJavaObject without a constructor");
    return NULL;
  } else if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Cannot call toJavaObject without registering class info");
    return NULL;
  }

  // Set up field mappings, if this has not already been done
  if (_field_mappings.empty()) {
    mapFields();
  }

  // Create a new Java argument with the default constructor
  // TODO: It would be nice to remove the requirement for a no-arg ctor
  // However, I'm not really sure how to do that without cluttering the interface.
  // Maybe provide an extra argument to setClass()? However, then we would lack
  // the corresponding arguments we'd want to pass in here.
  JniWeakGlobalRef<jobject> result = env->NewObject(_clazz.get(), _constructor);
  FieldMap::iterator iter;
  for (iter = _fields.begin(); iter != _fields.end(); ++iter) {
    std::string key = iter->first;
    jfieldID field = iter->second;
    FieldMapping *mapping = getFieldMapping(key);
    if (field != NULL && mapping != NULL) {
      if (TYPE_EQUALS(mapping->type, kTypeInt)) {
        int *address = static_cast<int*>(mapping->address);
        env->SetIntField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeFloat)) {
        float *address = static_cast<float*>(mapping->address);
        env->SetFloatField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeString)) {
        JavaString *address = static_cast<JavaString*>(mapping->address);
        JniLocalRef<jstring> string = address->getJavaString(env);
        env->SetObjectField(result, field, string.get());
      } else {
        // TODO throw
      }
    }
  }

  // Persist the current object address to the Java instance
  persist(env, result);
  return result.leak();
}

JniGlobalRef<jclass> ClassWrapper::getClass() const {
  return _clazz;
}

jmethodID ClassWrapper::getMethod(const char *method_name) const {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalStateException,
      "Cannot call getMethod without class info (forgot to merge?)");
    return NULL;
  }

  const std::string key(method_name);
  MethodMap::const_iterator mapFindIter = _methods.find(key);
  if (mapFindIter == _methods.end()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalArgumentException,
      "Method '%s' is not cached in class '%s'", method_name, getCanonicalName());
    return NULL;
  }

  return mapFindIter->second;
}

jfieldID ClassWrapper::getField(const char* field_name) const {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalStateException,
      "Cannot call getField without class info (forgot to merge?)");
    return NULL;
  }

  const std::string key(field_name);
  FieldMap::const_iterator mapFindIter = _fields.find(key);
  if (mapFindIter == _fields.end()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalArgumentException,
      "Field '%s' is not cached in class '%s'", field_name, getCanonicalName());
    return NULL;
  }

  return mapFindIter->second;
}

void ClassWrapper::setClass(JNIEnv *env) {
  _clazz.set(env->FindClass(getCanonicalName()));
  JavaExceptionUtils::checkException(env);
  std::string signature;
  JavaClassUtils::makeSignature(signature, kTypeVoid, NULL);
  _constructor = env->GetMethodID(_clazz.get(), "<init>", signature.c_str());
}

void ClassWrapper::cacheMethod(JNIEnv *env, const char* method_name, const char* return_type, ...) {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Attempt to call cacheMethod without having set class info");
    return;
  }

  va_list arguments;
  va_start(arguments, return_type);
  std::string signature;
  JavaClassUtils::makeSignatureWithList(signature, return_type, arguments);
  va_end(arguments);

  jmethodID method = env->GetMethodID(_clazz.get(), method_name, signature.c_str());
  JavaExceptionUtils::checkException(env);
  if (method != NULL) {
    _methods[method_name] = method;
  }
}

void ClassWrapper::cacheField(JNIEnv *env, const char *field_name, const char *field_type) {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Attempt to call cacheField without having set class info");
    return;
  }

  jfieldID field = env->GetFieldID(_clazz.get(), field_name, field_type);
  JavaExceptionUtils::checkException(env);
  if (field != NULL) {
    _fields[field_name] = field;
  }
}

void ClassWrapper::mapField(const char *field_name, const char *field_type, void *field_ptr) {
  FieldMapping *mapping = new FieldMapping;
  mapping->type = field_type;
  mapping->address = field_ptr;
  _field_mappings[field_name] = mapping;
}

FieldMapping* ClassWrapper::getFieldMapping(const std::string &key) const {
  std::map<std::string, FieldMapping*>::const_iterator findMapIter = _field_mappings.find(key);
  return findMapIter != _field_mappings.end() ? findMapIter->second : NULL;
}

void ClassWrapper::addNativeMethod(const char *method_name, void *function, const char *return_type, ...) {
  JNINativeMethod nativeMethod;
  nativeMethod.name = const_cast<char*>(method_name);
  nativeMethod.fnPtr = function;

  va_list arguments;
  va_start(arguments, return_type);
  std::string signature;
  JavaClassUtils::makeSignatureWithList(signature, return_type, arguments);
  nativeMethod.signature = const_cast<char*>(strdup(signature.c_str()));
  va_end(arguments);

  _jni_methods.push_back(nativeMethod);
}

bool ClassWrapper::registerNativeMethods(JNIEnv *env) {
  if (_jni_methods.empty()) {
    return false;
  }

  if (!isInitialized()) {
    JavaExceptionUtils::throwRuntimeException(env, "Could not find cached class for %s", getCanonicalName());
    return false;
  }

  return (env->RegisterNatives(_clazz.get(), &_jni_methods[0], (jint)_jni_methods.size()) < 0);
}

} // namespace jni
} // namespace spotify
<commit_msg>Fix compile error on *nix<commit_after>#include "ClassWrapper.h"
#include "JavaClassUtils.h"
#include "JavaExceptionUtils.h"
#include "JniWeakGlobalRef.h"
#include <string.h>

namespace spotify {
namespace jni {

ClassWrapper::~ClassWrapper() {
  // TODO: Delete mappings
}

bool ClassWrapper::isInitialized() const {
  return _clazz.get() != NULL;
}

const char* ClassWrapper::getSimpleName() const {
  const char* lastSlash = strrchr(getCanonicalName(), '/');
  return lastSlash != NULL ? lastSlash + 1 : getCanonicalName();
}

void ClassWrapper::merge(const ClassWrapper *globalInstance) {
  _clazz = globalInstance->_clazz;
  _methods = globalInstance->_methods;
  _fields = globalInstance->_fields;
  _constructor = globalInstance->_constructor;
}

bool ClassWrapper::persist(JNIEnv *env, jobject javaThis) {
  if (isPersisted()) {
    jlong resultPtr = reinterpret_cast<jlong>(this);
    env->SetLongField(javaThis, getField(PERSIST_FIELD_NAME), resultPtr);
    return true;
  }
  return false;
}

bool ClassWrapper::isPersisted() const {
  // TODO: Need test for this
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalStateException,
      "Cannot call isPersisted without class info (forgot to merge?)");
    return false;
  }

  // We expect the persisted field to be cached, otherwise searching for persisted
  // fields in non-persisted classes will throw java.lang.NoSuchField exception. :(
  const std::string key(PERSIST_FIELD_NAME);
  FieldMap::const_iterator mapFindIter = _fields.find(key);
  return mapFindIter != _fields.end();
}

ClassWrapper* ClassWrapper::getPersistedInstance(JNIEnv *env, jobject javaThis) const {
  if (isPersisted()) {
    jlong resultPtr = env->GetLongField(javaThis, getField(PERSIST_FIELD_NAME));
    return reinterpret_cast<ClassWrapper*>(resultPtr);
  } else {
    return NULL;
  }
}

void ClassWrapper::destroy(JNIEnv *env, jobject javaThis) {
  if (isPersisted()) {
    jfieldID persistField = getField(PERSIST_FIELD_NAME);
    jlong resultPtr = env->GetLongField(javaThis, persistField);
    ClassWrapper *instance = reinterpret_cast<ClassWrapper*>(resultPtr);
    if (instance != NULL) {
      delete instance;
      env->SetLongField(javaThis, persistField, 0);
    }
  }
}

void ClassWrapper::setJavaObject(JNIEnv *env, jobject javaThis) {
  // Set up field mappings, if this has not already been done
  if (_field_mappings.empty()) {
    mapFields();
  }

  FieldMap::iterator iter;
  for (iter = _fields.begin(); iter != _fields.end(); ++iter) {
    std::string key = iter->first;
    jfieldID field = iter->second;
    FieldMapping *mapping = _field_mappings[key]; // TODO: Should use getter here, if not null will be inserted
    if (field != NULL && mapping != NULL) {
      if (TYPE_EQUALS(mapping->type, kTypeInt)) {
        int *address = static_cast<int*>(mapping->address);
        *address = env->GetIntField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeFloat)) {
        float *address = static_cast<float*>(mapping->address);
        *address = env->GetFloatField(javaThis, field);
      } else if (TYPE_EQUALS(mapping->type, kTypeString)) {
        jstring string = (jstring)env->GetObjectField(javaThis, field);
        JavaString *address = static_cast<JavaString*>(mapping->address);
        address->setValue(env, string);
      } else {
        // TODO throw
      }
    }
  }
}

jobject ClassWrapper::toJavaObject(JNIEnv *env) {
  if (_constructor == NULL) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Cannot call toJavaObject without a constructor");
    return NULL;
  } else if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Cannot call toJavaObject without registering class info");
    return NULL;
  }

  // Set up field mappings, if this has not already been done
  if (_field_mappings.empty()) {
    mapFields();
  }

  // Create a new Java argument with the default constructor
  // TODO: It would be nice to remove the requirement for a no-arg ctor
  // However, I'm not really sure how to do that without cluttering the interface.
  // Maybe provide an extra argument to setClass()? However, then we would lack
  // the corresponding arguments we'd want to pass in here.
  JniWeakGlobalRef<jobject> result;
  result.set(env->NewObject(_clazz.get(), _constructor));

  FieldMap::iterator iter;
  for (iter = _fields.begin(); iter != _fields.end(); ++iter) {
    std::string key = iter->first;
    jfieldID field = iter->second;
    FieldMapping *mapping = getFieldMapping(key);
    if (field != NULL && mapping != NULL) {
      if (TYPE_EQUALS(mapping->type, kTypeInt)) {
        int *address = static_cast<int*>(mapping->address);
        env->SetIntField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeFloat)) {
        float *address = static_cast<float*>(mapping->address);
        env->SetFloatField(result, field, *address);
      } else if (TYPE_EQUALS(mapping->type, kTypeString)) {
        JavaString *address = static_cast<JavaString*>(mapping->address);
        JniLocalRef<jstring> string = address->getJavaString(env);
        env->SetObjectField(result, field, string.get());
      } else {
        // TODO throw
      }
    }
  }

  // Persist the current object address to the Java instance
  persist(env, result);
  return result.leak();
}

JniGlobalRef<jclass> ClassWrapper::getClass() const {
  return _clazz;
}

jmethodID ClassWrapper::getMethod(const char *method_name) const {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalStateException,
      "Cannot call getMethod without class info (forgot to merge?)");
    return NULL;
  }

  const std::string key(method_name);
  MethodMap::const_iterator mapFindIter = _methods.find(key);
  if (mapFindIter == _methods.end()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalArgumentException,
      "Method '%s' is not cached in class '%s'", method_name, getCanonicalName());
    return NULL;
  }

  return mapFindIter->second;
}

jfieldID ClassWrapper::getField(const char* field_name) const {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalStateException,
      "Cannot call getField without class info (forgot to merge?)");
    return NULL;
  }

  const std::string key(field_name);
  FieldMap::const_iterator mapFindIter = _fields.find(key);
  if (mapFindIter == _fields.end()) {
    JavaExceptionUtils::throwExceptionOfType(JavaThreadUtils::getEnvForCurrentThread(),
      kTypeIllegalArgumentException,
      "Field '%s' is not cached in class '%s'", field_name, getCanonicalName());
    return NULL;
  }

  return mapFindIter->second;
}

void ClassWrapper::setClass(JNIEnv *env) {
  _clazz.set(env->FindClass(getCanonicalName()));
  JavaExceptionUtils::checkException(env);
  std::string signature;
  JavaClassUtils::makeSignature(signature, kTypeVoid, NULL);
  _constructor = env->GetMethodID(_clazz.get(), "<init>", signature.c_str());
}

void ClassWrapper::cacheMethod(JNIEnv *env, const char* method_name, const char* return_type, ...) {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Attempt to call cacheMethod without having set class info");
    return;
  }

  va_list arguments;
  va_start(arguments, return_type);
  std::string signature;
  JavaClassUtils::makeSignatureWithList(signature, return_type, arguments);
  va_end(arguments);

  jmethodID method = env->GetMethodID(_clazz.get(), method_name, signature.c_str());
  JavaExceptionUtils::checkException(env);
  if (method != NULL) {
    _methods[method_name] = method;
  }
}

void ClassWrapper::cacheField(JNIEnv *env, const char *field_name, const char *field_type) {
  if (!isInitialized()) {
    JavaExceptionUtils::throwExceptionOfType(env, kTypeIllegalStateException,
      "Attempt to call cacheField without having set class info");
    return;
  }

  jfieldID field = env->GetFieldID(_clazz.get(), field_name, field_type);
  JavaExceptionUtils::checkException(env);
  if (field != NULL) {
    _fields[field_name] = field;
  }
}

void ClassWrapper::mapField(const char *field_name, const char *field_type, void *field_ptr) {
  FieldMapping *mapping = new FieldMapping;
  mapping->type = field_type;
  mapping->address = field_ptr;
  _field_mappings[field_name] = mapping;
}

FieldMapping* ClassWrapper::getFieldMapping(const std::string &key) const {
  std::map<std::string, FieldMapping*>::const_iterator findMapIter = _field_mappings.find(key);
  return findMapIter != _field_mappings.end() ? findMapIter->second : NULL;
}

void ClassWrapper::addNativeMethod(const char *method_name, void *function, const char *return_type, ...) {
  JNINativeMethod nativeMethod;
  nativeMethod.name = const_cast<char*>(method_name);
  nativeMethod.fnPtr = function;

  va_list arguments;
  va_start(arguments, return_type);
  std::string signature;
  JavaClassUtils::makeSignatureWithList(signature, return_type, arguments);
  nativeMethod.signature = const_cast<char*>(strdup(signature.c_str()));
  va_end(arguments);

  _jni_methods.push_back(nativeMethod);
}

bool ClassWrapper::registerNativeMethods(JNIEnv *env) {
  if (_jni_methods.empty()) {
    return false;
  }

  if (!isInitialized()) {
    JavaExceptionUtils::throwRuntimeException(env, "Could not find cached class for %s", getCanonicalName());
    return false;
  }

  return (env->RegisterNatives(_clazz.get(), &_jni_methods[0], (jint)_jni_methods.size()) < 0);
}

} // namespace jni
} // namespace spotify
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// class T0 walk correction      Alla Maevskaya alla@inr.ru 20.11.2007        //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include "AliT0CalibWalk.h"
#include "AliLog.h"

#include <TObjArray.h>
#include <TGraph.h>
#include <TFile.h>
#include <TH2F.h>
#include <TMath.h>
#include <TSystem.h>
#include <Riostream.h>
#include <TSpectrum.h>
#include <TProfile.h>
#include <TF1.h>

ClassImp(AliT0CalibWalk)

//________________________________________________________________
  AliT0CalibWalk::AliT0CalibWalk():   TNamed(),
				      fWalk(0),
				      fAmpLEDRec(0),
				      fQTC(0),
				      fAmpLED(0)
{
  //
}

//________________________________________________________________
AliT0CalibWalk::AliT0CalibWalk(const char* name):TNamed(),
				      fWalk(0),
				      fAmpLEDRec(0),				  				      fQTC(0),
				      fAmpLED(0)

{
  TString namst = "Calib_";
  namst += name;
  SetName(namst.Data());
  SetTitle(namst.Data());

}

//________________________________________________________________
AliT0CalibWalk::AliT0CalibWalk(const AliT0CalibWalk& calibda) :
  TNamed(calibda),
  fWalk(0),
  fAmpLEDRec(0),
  fQTC(0),
  fAmpLED(0)

{
// copy constructor
  SetName(calibda.GetName());
  SetTitle(calibda.GetName());

}

//________________________________________________________________
AliT0CalibWalk &AliT0CalibWalk::operator =(const AliT0CalibWalk& calibda)
{
// assignment operator
  SetName(calibda.GetName());
  SetTitle(calibda.GetName());

  return *this;
}

//________________________________________________________________
AliT0CalibWalk::~AliT0CalibWalk()
{
  //
}
//________________________________________________________________

Bool_t AliT0CalibWalk::MakeWalkCorrGraph(const char *laserFile)
{
  //make walk corerction for preprocessor
  Int_t npeaks = 20;
  Int_t sigma=3;
  Bool_t down=false;
  Int_t index[20];
  Bool_t ok=true;
  Float_t   mips[20];
  Int_t nfound=0;

  gFile = TFile::Open(laserFile);
  if(!gFile) {
    AliError("No input laser data found ");
  }
  else
    {
      //      gFile->ls();
      TH1F* hAmp = (TH1F*) gFile->Get("hAmpLaser");
      Int_t nmips=0;
      for (Int_t ibin=0; ibin<2000; ibin++) {
	Float_t bincont = hAmp->GetBinContent(ibin);
	if(bincont>0){
	  mips[nmips] = hAmp->GetXaxis()->GetBinCenter(ibin);
	  cout<<ibin<<" bincont "<<bincont<<" amp "<< mips[nmips]<<endl;
	  nmips++;
	}
      }

      if (nmips<17) {
	ok=false;
	return ok;
      }

      Float_t x1[50], y1[50];
      Float_t x2[50], xx2[50],y2[50];
      Float_t xx1[50],yy1[50], xx[50];

      Float_t cfd0[24];
      Int_t startim = 0;

      for (Int_t ii=0; ii<nmips; ii++)
	x1[ii] = y1[ii] = x2[ii] = y2[ii] = 0;

      for (Int_t i=0; i<24; i++)
	{
	  for (Int_t im=startim; im<nmips; im++)
	    {
	      TString cfd = Form("hCFD%i_%i",i+1,im+1);
	      TString qtc = Form("hQTC%i_%i",i+1,im+1);
	      TString led = Form("hLED%i_%i",i+1,im+1);

	      TH1F *hCFD = (TH1F*) gFile->Get(cfd.Data()) ;
	      TH1F *hLED = (TH1F*) gFile->Get(led.Data());
	      TH1F *hQTC = (TH1F*) gFile->Get(qtc.Data()) ;
	      hCFD->SetDirectory(0);
	      hQTC->SetDirectory(0);
	      hLED->SetDirectory(0);
	      if(!hCFD )
 	      	AliWarning(Form(" no CFD data in LASER DA for channel %i for amplitude %f MIPs",i,mips[im]));
	      if(!hQTC )
 	      	AliWarning(Form(" no QTC correction data in LASER DA for channel %i for amplitude %f MIPs",i,mips[im]));
	      if(!hLED)
	      	AliWarning(Form(" no LED correction data in LASER DA for channel %i for amplitude %f MIPs",i,mips[im]));

	      if(hCFD )	{
		TSpectrum *s = new TSpectrum(2*npeaks,1);
		nfound = s->Search(hCFD,sigma," ",0.1);
		if(nfound!=0){
		  Float_t *xpeak = s->GetPositionX();
		  TMath::Sort(nfound, xpeak, index,down);
		  Float_t xp = xpeak[index[0]];
		  Double_t hmax = xp+3*sigma;
		  Double_t hmin = xp-3*sigma;
		  hCFD->GetXaxis()->SetRangeUser(hmin-10,hmax+10);
		}
		else
		  {
		    hCFD->Rebin(2);
		    TSpectrum *s1 = new TSpectrum(2*npeaks,1);
		    nfound = s1->Search(hCFD,sigma," ",0.1);
		    if(nfound!=0){
		      Float_t *xpeak = s1->GetPositionX();
		      TMath::Sort(nfound, xpeak, index,down);
		      Float_t xp = xpeak[index[0]];
		      Double_t hmax = xp+3*sigma;
		      Double_t hmin = xp-3*sigma;
		      hCFD->GetXaxis()->SetRangeUser(hmin-10,hmax+10);
		    }
		    else
		      {
			ok=false;
			printf("no peak in CFD spectrum for PMT %i amplitude %i\n",i,im);
			return ok;
		      }

		  }

		if (im == 0) cfd0[i] = hCFD->GetMean();
		y1[im] =  hCFD->GetMean() - cfd0[i];
	      }
	      if( hQTC) {
		x1[im] = hQTC->GetMean();
		if( x1[im] == 0) {
		  ok=false;
		  printf("no peak in QTC signal for PMT %i amplitude %i\n",i,im);
		  return ok;
		  }
	      }

	      if( hLED){
		TSpectrum *s = new TSpectrum(2*npeaks,1);
		nfound = s->Search(hLED,sigma," ",0.1);
		if(nfound!=0){
		  Float_t *xpeak = s->GetPositionX();
		  TMath::Sort(nfound, xpeak, index,down);
		  Float_t xp = xpeak[index[0]];
		  Double_t hmax = xp+10*sigma;
		  Double_t hmin = xp-10*sigma;
		  hLED->GetXaxis()->SetRangeUser(hmin-10,hmax+10);
		}
		else
		  {
		    ok=false;
		    printf("no peak in LED spectrum for PMT %i amplitude %i\n",i,im);
		    return ok;
		  }
		x2[im] = hLED->GetMean();
		xx2[im] = x2[nmips-im-1];
	      }
	      xx[im]=mips[im];

	      if (hQTC) delete  hQTC;
	      if (hCFD) delete  hCFD;
	      if (hLED) delete  hLED;
	    }

	  for (Int_t imi=0; imi<nmips; imi++)
	    {
	      yy1[imi] = Float_t (mips[nmips-imi-1]);
	      xx1[imi] = x2[nmips-imi-1];
	      //	      cout<<" LED rev "<<i<<" "<<imi<<" "<<xx1[imi]<<" "<< yy1[imi]<<"nmips-imi-1 = "<< nmips-imi-1<<endl;
	    }

	  if(i==0) cout<<"Making graphs..."<<endl;

	  /*

	  Float_t x1[50], y1[50];
	  Float_t x2[50], xx2[50],y2[50];
	  Float_t xx1[50],yy1[50], xx[50];

	  Int_t nmips=20;
	  for (Int_t i=0; i<24; i++)
	  {

	  for (Int_t im=0; im<nmips; im++)
	  {
	  x1[im]=xx[im]=500+im*200;
	  y1[im]=0;
	  x2[im]=xx1[im]=yy1[im]=260+20*im;
	  }
	  */
       TGraph *grwalkqtc = new TGraph (nmips,x1,y1);
      grwalkqtc->SetTitle(Form("PMT%i",i));
      TGraph *grwalkled = new TGraph (nmips,x2,y1);
      grwalkled->SetTitle(Form("PMT%i",i));
      fWalk.AddAtAndExpand(grwalkqtc,i);
      fAmpLEDRec.AddAtAndExpand(grwalkled,i);
      //	  cout<<" add walk "<<i<<endl;

      //fit amplitude graphs to make comparison wth new one
      TGraph *grampled = new TGraph (nmips,xx1,yy1);
      TGraph *grqtc = new TGraph (nmips,x1,xx);
      fQTC.AddAtAndExpand(grqtc,i);
      fAmpLED.AddAtAndExpand(grampled,i);
      //	  cout<<" add amp "<<i<<endl;

      if(i==23)
	cout<<"Graphs created..."<<endl;
	}
    } //if gFile exits

  return ok;
}

<commit_msg>some coverity defects fixed<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// class T0 walk correction      Alla Maevskaya alla@inr.ru 20.11.2007        //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include "AliT0CalibWalk.h"
#include "AliLog.h"

#include <TObjArray.h>
#include <TGraph.h>
#include <TFile.h>
#include <TH2F.h>
#include <TMath.h>
#include <TSystem.h>
#include <Riostream.h>
#include <TSpectrum.h>
#include <TProfile.h>
#include <TF1.h>

ClassImp(AliT0CalibWalk)

//________________________________________________________________
  AliT0CalibWalk::AliT0CalibWalk():   TNamed(),
				      fWalk(0),
				      fAmpLEDRec(0),
				      fQTC(0),
				      fAmpLED(0)
{
  //
}

//________________________________________________________________
AliT0CalibWalk::AliT0CalibWalk(const char* name):TNamed(),
				      fWalk(0),
				      fAmpLEDRec(0),				  				      fQTC(0),
				      fAmpLED(0)

{
  TString namst = "Calib_";
  namst += name;
  SetName(namst.Data());
  SetTitle(namst.Data());

}

//________________________________________________________________
AliT0CalibWalk::AliT0CalibWalk(const AliT0CalibWalk& calibda) :
  TNamed(calibda),
  fWalk(0),
  fAmpLEDRec(0),
  fQTC(0),
  fAmpLED(0)

{
// copy constructor
  SetName(calibda.GetName());
  SetTitle(calibda.GetName());

}

//________________________________________________________________
AliT0CalibWalk &AliT0CalibWalk::operator =(const AliT0CalibWalk& calibda)
{
// assignment operator
  SetName(calibda.GetName());
  SetTitle(calibda.GetName());

  return *this;
}

//________________________________________________________________
AliT0CalibWalk::~AliT0CalibWalk()
{
  //
}
//________________________________________________________________

Bool_t AliT0CalibWalk::MakeWalkCorrGraph(const char *laserFile)
{
  //make walk corerction for preprocessor
  Float_t sigma, xp, cfdmean, qtmean, ledmean;
  Bool_t ok=true;
  Float_t   mips[50];

  gFile = TFile::Open(laserFile);
  if(!gFile) {
    AliError("No input laser data found ");
  }
  else
    {
      //      gFile->ls();
      TH1F* hAmp = (TH1F*) gFile->Get("hAmpLaser");
      Int_t nmips=0;
      for (Int_t ibin=0; ibin<2000; ibin++) {
	Float_t bincont = hAmp->GetBinContent(ibin);
	if(bincont>0){
	  mips[nmips] = hAmp->GetXaxis()->GetBinCenter(ibin);
	  cout<<ibin<<" bincont "<<bincont<<" amp "<< mips[nmips]<<endl;
	  nmips++;
	}
      }

      if (nmips<17) {
	ok=false;
	return ok;
      }

      Float_t x1[50], y1[50];
      Float_t x2[50], xx2[50],y2[50];
      Float_t xx1[50],yy1[50], xx[50];

      Float_t cfd0[24];
      Int_t startim = 0;

      for (Int_t ii=0; ii<nmips; ii++)
	x1[ii] = y1[ii] = x2[ii] = y2[ii] = 0;

      for (Int_t i=0; i<24; i++)
	{
	  for (Int_t im=startim; im<nmips; im++)
	    {
	      TString cfd = Form("hCFD%i_%i",i+1,im+1);
	      TString qtc = Form("hQTC%i_%i",i+1,im+1);
	      TString led = Form("hLED%i_%i",i+1,im+1);

	      TH1F *hCFD = (TH1F*) gFile->Get(cfd.Data()) ;
	      TH1F *hLED = (TH1F*) gFile->Get(led.Data());
	      TH1F *hQTC = (TH1F*) gFile->Get(qtc.Data()) ;
	      //	      hCFD->SetDirectory(0);
	      //	      hQTC->SetDirectory(0);
	      //	      hLED->SetDirectory(0);
	      if(!hCFD )
 	      	AliWarning(Form(" no CFD data in LASER DA for channel %i for amplitude %f MIPs",i,mips[im]));
	      if(!hQTC )
 	      	AliWarning(Form(" no QTC correction data in LASER DA for channel %i for amplitude %f MIPs",i,mips[im]));
	      if(!hLED)
	      	AliWarning(Form(" no LED correction data in LASER DA for channel %i for amplitude %f MIPs",i,mips[im]));

	      if(hCFD && hCFD->GetEntries()>500) {
		GetMeanAndSigma(hCFD, xp, sigma);
		}
	      else
		{
		  ok=false;
		  printf("no peak in CFD spectrum for PMT %i amplitude %i\n",i,im);
		  return ok;
		}

	      if (hCFD->GetRMS() < 1.5) cfdmean = hCFD->GetMean();
	      else cfdmean=xp;
	      if (im == 0) cfd0[i] = cfdmean;
		y1[im] =  cfdmean - cfd0[i];

		if(hQTC && hQTC->GetEntries()>500) {
		  GetMeanAndSigma(hQTC, qtmean, sigma);

		  x1[im] = qtmean;
		  if( x1[im] == 0) {
		    ok=false;
		    printf("no peak in QTC signal for PMT %i amplitude %i\n",i,im);
		    return ok;
		  }
		}

		if( hLED && hLED->GetEntries()>500) {
		  GetMeanAndSigma(hLED, ledmean, sigma);
		}
		else
		  {
		    ok=false;
		    printf("no peak in LED spectrum for PMT %i amplitude %i\n",i,im);
		    return ok;
		  }
		x2[im] = ledmean;
		xx2[im] = x2[nmips-im-1];

		xx[im]=mips[im];
		if (hQTC) delete  hQTC;
		if (hCFD) delete  hCFD;
		if (hLED) delete  hLED;

	    }

	  for (Int_t imi=0; imi<nmips; imi++)
	    {
	      yy1[imi] = Float_t (mips[nmips-imi-1]);
	      xx1[imi] = x2[nmips-imi-1];
	      //	      cout<<" LED rev "<<i<<" "<<imi<<" "<<xx1[imi]<<" "<< yy1[imi]<<"nmips-imi-1 = "<< nmips-imi-1<<endl;
	    }

	  if(i==0) cout<<"Making graphs..."<<endl;

	  /*

	  Float_t x1[50], y1[50];
	  Float_t x2[50], xx2[50],y2[50];
	  Float_t xx1[50],yy1[50], xx[50];

	  Int_t nmips=20;
	  for (Int_t i=0; i<24; i++)
	  {

	  for (Int_t im=0; im<nmips; im++)
	  {
	  x1[im]=xx[im]=500+im*200;
	  y1[im]=0;
	  x2[im]=xx1[im]=yy1[im]=260+20*im;
	  }
	  */
       TGraph *grwalkqtc = new TGraph (nmips,x1,y1);
      grwalkqtc->SetTitle(Form("PMT%i",i));
      TGraph *grwalkled = new TGraph (nmips,x2,y1);
      grwalkled->SetTitle(Form("PMT%i",i));
      fWalk.AddAtAndExpand(grwalkqtc,i);
      fAmpLEDRec.AddAtAndExpand(grwalkled,i);
      //	  cout<<" add walk "<<i<<endl;

      //fit amplitude graphs to make comparison wth new one
      TGraph *grampled = new TGraph (nmips,xx1,yy1);
      TGraph *grqtc = new TGraph (nmips,x1,xx);
      fQTC.AddAtAndExpand(grqtc,i);
      fAmpLED.AddAtAndExpand(grampled,i);
      //	  cout<<" add amp "<<i<<endl;

      if(i==23)
	cout<<"Graphs created..."<<endl;
	}
    } //if gFile exits

  return ok;
}

void AliT0CalibWalk::GetMeanAndSigma(TH1F* hist, Float_t &mean, Float_t &sigma)
{

  const double window = 5.;  //fit window
  double norm  = hist->Integral();  // normalize to one count
  hist->Scale(1./norm);

  double meanEstimate, sigmaEstimate;
  int maxBin;
  maxBin        =  hist->GetMaximumBin(); //position of maximum
  meanEstimate  =  hist->GetBinCenter( maxBin); // mean of gaussian sitting in maximum
  sigmaEstimate = hist->GetRMS();
  TF1* fit= new TF1("fit","gaus", meanEstimate - window*sigmaEstimate, meanEstimate + window*sigmaEstimate);
  fit->SetParameters(hist->GetBinContent(maxBin), meanEstimate, sigmaEstimate);
  hist->Fit("fit","RQ","Q");

  mean  = (Float_t) fit->GetParameter(1);
  sigma = (Float_t) fit->GetParameter(2);

  delete fit;
}

<|endoftext|>


<commit_before><commit_msg>App: [skip ci] replace plain C API with PyCXX to avoid memory leaks<commit_after><|endoftext|>


<commit_before>#pragma once
#include <mutex>
#include <iosfwd>
#include <sstream>
#include <cctype>
#include "But/Log/Backend/toString.hpp"
#include "But/Log/Backend/trimNonPrintable.hpp"
#include "Foreign.hpp"

namespace But
{
namespace Log
{
namespace Destination
{

class Stream: public Foreign
{
protected:
  explicit Stream(std::ostream& os): os_{&os} { }

private:
  void logImpl(Backend::Entry e) override
  {
    std::stringstream ss;
    toStreamFormat( ss, std::move(e) );
    const std::lock_guard<std::mutex> lock(mutex_);
    (*os_) << ss.rdbuf();
  }

  void reloadImpl() override
  {
    const std::lock_guard<std::mutex> lock(mutex_);
    reloadImplUnderLock();
  }

  void flushImpl() override
  {
    const std::lock_guard<std::mutex> lock(mutex_);
    (*os_) << std::flush;
  }

  virtual void reloadImplUnderLock() = 0;

  virtual void toStreamFormat(std::ostream& os, Backend::Entry&& e)
  {
    for(auto& f: e)
      os << Backend::trimNonPrintable( std::move(f).value() );
    os << std::endl;
  }

  std::mutex mutex_;
  std::ostream* os_;
};

}
}
}
<commit_msg>Stream's methods are now final<commit_after>#pragma once
#include <mutex>
#include <iosfwd>
#include <sstream>
#include <cctype>
#include "But/Log/Backend/toString.hpp"
#include "But/Log/Backend/trimNonPrintable.hpp"
#include "Foreign.hpp"

namespace But
{
namespace Log
{
namespace Destination
{

class Stream: public Foreign
{
protected:
  explicit Stream(std::ostream& os): os_{&os} { }

private:
  void logImpl(Backend::Entry e) override final
  {
    std::stringstream ss;
    toStreamFormat( ss, std::move(e) );
    const std::lock_guard<std::mutex> lock(mutex_);
    (*os_) << ss.rdbuf();
  }

  void reloadImpl() override final
  {
    const std::lock_guard<std::mutex> lock(mutex_);
    reloadImplUnderLock();
  }

  void flushImpl() override final
  {
    const std::lock_guard<std::mutex> lock(mutex_);
    (*os_) << std::flush;
  }

  virtual void reloadImplUnderLock() = 0;

  virtual void toStreamFormat(std::ostream& os, Backend::Entry&& e)
  {
    for(auto& f: e)
      os << Backend::trimNonPrintable( std::move(f).value() );
    os << std::endl;
  }

  std::mutex mutex_;
  std::ostream* os_;
};

}
}
}
<|endoftext|>


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

#include "Vector2f.h"

TEST(Vector2fTest, VectorAddition) {
	Vector2f v1(0, 0);
	Vector2f v2(1, 2);
	Vector2f v3(3, 4);

	Vector2f result = v1 + v1;
	EXPECT_FLOAT_EQ(0.0f, result.x);
	EXPECT_FLOAT_EQ(0.0f, result.y);

	result = v2 + v1;
	EXPECT_FLOAT_EQ(v2.x, result.x);
	EXPECT_FLOAT_EQ(v2.y, result.y);

	result = v2 + v3;
	EXPECT_FLOAT_EQ(4.0f, result.x);
	EXPECT_FLOAT_EQ(6.0f, result.y);
}<commit_msg>Test failing unit test<commit_after>
#include <gtest/gtest.h>

#include "Vector2f.h"

TEST(Vector2fTest, VectorAddition) {
	Vector2f v1(0, 0);
	Vector2f v2(1, 2);
	Vector2f v3(3, 4);

	Vector2f result = v1 + v1;
	EXPECT_FLOAT_EQ(0.0f, result.x);
	EXPECT_FLOAT_EQ(0.0f, result.y);

	result = v2 + v1;
	EXPECT_FLOAT_EQ(v2.x, result.x);
	EXPECT_FLOAT_EQ(v2.y, result.y);

	result = v2 + v3;
	EXPECT_FLOAT_EQ(4.0f, result.x);
	EXPECT_FLOAT_EQ(6.0f, result.y);
	// TEST
	EXPECT_FLOAT_EQ(7.0f, result.y);
}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 ETH Zurich.
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached LICENSE file.
 * If you do not find this file, copies can be found by writing to:
 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
 */

#ifndef __SHL_ARRAY_REPLICATED_BACKEND
#define __SHL_ARRAY_REPLICATED_BACKEND

/**
 * \brief allocates the arrays
 */
template<class T>
int shl_array_replicated<T>::alloc(void)
{

    if (!shl_array<T>::do_alloc())
        return 0;

    this->print();

    assert(!this->alloc_done);

    rep_array = (T**) shl__malloc_replicated(this->size * sizeof(T),
                                              &num_replicas, &this->pagesize,
                                              this->get_options(),
                                              &this->meminfo);
    if (this->rep_array == NULL) {
        return -1;
    }

    this->alloc_done = true;

    return 0;
}

template<class T>
void shl_array_replicated<T>::copy_from(T* src)
{
    if (!shl_array<T>::do_copy_in())
        return;

    assert(shl_array<T>::alloc_done);

    printf("shl_array_replicated[%s]: Copying to %d replicas\n",
           shl_base_array::name, num_replicas);

#if 0
    shl__memcpy_dma(src, this->meminfo, 0, sizeof(T) * this->size);
#else
    for (int j = 0; j < num_replicas; j++) {
        for (unsigned int i = 0; i < shl_array<T>::size; i++) {
            rep_array[j][i] = src[i];
        }
    }
#endif
}

#endif /* __SHL_ARRAY */
<commit_msg>adding DMA copy to replicated array<commit_after>/*
 * Copyright (c) 2014 ETH Zurich.
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached LICENSE file.
 * If you do not find this file, copies can be found by writing to:
 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
 */

#ifndef __SHL_ARRAY_REPLICATED_BACKEND
#define __SHL_ARRAY_REPLICATED_BACKEND

/**
 * \brief allocates the arrays
 */
template<class T>
int shl_array_replicated<T>::alloc(void)
{

    if (!shl_array<T>::do_alloc())
        return 0;

    this->print();

    assert(!this->alloc_done);

    rep_array = (T**) shl__malloc_replicated(this->size * sizeof(T),
                                              &num_replicas, &this->pagesize,
                                              this->get_options(),
                                              &this->meminfo);
    if (this->rep_array == NULL) {
        return -1;
    }

    this->alloc_done = true;

    return 0;
}

template<class T>
void shl_array_replicated<T>::copy_from(T* src)
{
    if (!shl_array<T>::do_copy_in())
        return;

    assert(shl_array<T>::alloc_done);

    printf("shl_array_replicated[%s]: Copying to %d replicas\n",
           shl_base_array::name, num_replicas);

    int copied = 0;

    if (this->meminfo) {
        copied = shl__memcpy_dma_from(src, this->meminfo, 0, sizeof(T)*this->size);
    }

    if (copied == 0) {
        printf("shl_array_replicated[%s]: falling back to manual copy\n",
               this->name);
        for (int j = 0; j < num_replicas; j++) {
            for (unsigned int i = 0; i < shl_array<T>::size; i++) {
                rep_array[j][i] = src[i];
            }
        }
    }
}

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


<commit_before>#include "RDom.h"

// to avoid compiler confusion, python.hpp must be include before Halide headers
#include <boost/python.hpp>
#include "add_operators.h"

#include "../../src/RDom.h"

#include <string>

void defineRDom()
{

    /*

    class RDom(object):
        """
        A multi-dimensional domain over which to iterate. Used when
        defining functions as reductions. See apps/bilateral_grid.py for an
        example of a reduction.

        Constructors::

          RDom(Expr min, Expr extent, name="")                             -- 1D reduction
          RDom(Expr min0, Expr extent0, Expr min1, Expr extent1, name="")  -- 2D reduction
          (Similar for 3D and 4D reductions)
          RDom(Buffer|ImageParam)                    -- Iterate over all points in the domain

        The following global functions can be used for inline reductions::

            minimum, maximum, product, sum
        """
        def __new__(cls, *args):
            args = [wrap(x) if not isinstance(x,str) else x for x in args]
            return RDomType(*args)

        def defined(self):
            """
            Check if reduction domain is non-NULL.
            """

        def same_as(self, other):
            """
            Check if two reduction domains are the same.
            """

        def dimensions(self):
            """
            Number of dimensions.
            """

        x = property(doc="Access dimension 1 of reduction domain.")
        y = property(doc="Access dimension 2 of reduction domain.")
        z = property(doc="Access dimension 3 of reduction domain.")
        w = property(doc="Access dimension 4 of reduction domain.")

      */
    return;
}
<commit_msg>Starting work on RDom<commit_after>#include "RDom.h"

// to avoid compiler confusion, python.hpp must be include before Halide headers
#include <boost/python.hpp>
#include "add_operators.h"

#include "../../src/RDom.h"

#include <string>

void defineRDom()
{

    using Halide::RDom;
    using Halide::RVar;
    namespace h = Halide;
    namespace p = boost::python;
    using p::self;

//    p::class_<RVar>("RVar",
//                          "An Image parameter to a halide pipeline. E.g., the input image. \n"
//                          "Constructor:: \n"
//                          "  ImageParam(Type t, int dims, name="") \n"
//                          "The image can be indexed via I[x], I[y,x], etc, which gives a Halide Expr. Supports most of \n"
//                          "the methods of Image.",
//                          p::init<h::Type, int, std::string>(p::args("t", "dims", "name"))
//                          )
//            .def(p::init<h::Type, int>(p::args("t", "dims")))
//            .def("name",
//                 &ImageParam::name,
//                 boost::python::return_value_policy<boost::python:: copy_const_reference>(),
//                 "Get name of ImageParam.")
//            .def("set", &ImageParam::set, p::arg("b"),
//                 "Bind a Buffer, Image, numpy array, or PIL image. Only relevant for jitting.")
//            .def("get", &ImageParam::get,
//                 "Get the Buffer that is bound. Only relevant for jitting.");

//    class RVar(object):
//        """
//        A reduction variable represents a single dimension of a reduction
//        domain (RDom). Don't construct them directly, instead construct an
//        RDom, and use fields .x, .y, .z, .w to get at the variables. For
//        single-dimensional reduction domains, you can just cast a
//        single-dimensional RDom to an RVar.
//        """
//        def __new__(cls, *args):
//            return RVarType(*args)

//        def min(self):
//            """
//            The minimum value that this variable will take on.
//            """

//        def extent(self):
//            """
//            The number that this variable will take on. The maximum value
//            of this variable will be min() + extent() - 1.
//            """

//        def name(self):
//            """
//            The name of this reduction variable.
//            """

//    /** A reduction variable represents a single dimension of a reduction
//     * domain (RDom). Don't construct them directly, instead construct an
//     * RDom, and use RDom::operator[] to get at the variables. For
//     * single-dimensional reduction domains, you can just cast a
//     * single-dimensional RDom to an RVar. */
//    class RVar {
//        std::string _name;
//        Internal::ReductionDomain _domain;
//        int _index;

//        const Internal::ReductionVariable &_var() const {
//            return _domain.domain().at(_index);
//        }

//    public:
//        /** An empty reduction variable. */
//        RVar() : _name(Internal::make_entity_name(this, "Halide::RVar", 'r')) {}

//        /** Construct an RVar with the given name */
//        explicit RVar(const std::string &n) : _name(n) {
//            // Make sure we don't get a unique name with the same name as
//            // this later:
//            Internal::unique_name(n, false);
//        }

//        /** Construct a reduction variable with the given name and
//         * bounds. Must be a member of the given reduction domain. */
//        RVar(Internal::ReductionDomain domain, int index) :
//            _domain(domain), _index(index) {
//        }

//        /** The minimum value that this variable will take on */
//        EXPORT Expr min() const;

//        /** The number that this variable will take on. The maximum value
//         * of this variable will be min() + extent() - 1 */
//        EXPORT Expr extent() const;

//        /** The reduction domain this is associated with. */
//        EXPORT Internal::ReductionDomain domain() const {return _domain;}

//        /** The name of this reduction variable */
//        EXPORT const std::string &name() const;

//        /** Reduction variables can be used as expressions. */
//        EXPORT operator Expr() const;
//    };

//    p::class_<RDom>("RDom",
//                          "An Image parameter to a halide pipeline. E.g., the input image. \n"
//                          "Constructor:: \n"
//                          "  ImageParam(Type t, int dims, name="") \n"
//                          "The image can be indexed via I[x], I[y,x], etc, which gives a Halide Expr. Supports most of \n"
//                          "the methods of Image.",
//                          p::init<h::Type, int, std::string>(p::args("t", "dims", "name"))
//                          )
//            .def(p::init<h::Type, int>(p::args("t", "dims")))
//            .def("name",
//                 &ImageParam::name,
//                 boost::python::return_value_policy<boost::python:: copy_const_reference>(),
//                 "Get name of ImageParam.")
//            .def("set", &ImageParam::set, p::arg("b"),
//                 "Bind a Buffer, Image, numpy array, or PIL image. Only relevant for jitting.")
//            .def("get", &ImageParam::get,
//                 "Get the Buffer that is bound. Only relevant for jitting.");

//    class RDom(object):
//        """
//        A multi-dimensional domain over which to iterate. Used when
//        defining functions as reductions. See apps/bilateral_grid.py for an
//        example of a reduction.

//        Constructors::

//          RDom(Expr min, Expr extent, name="")                             -- 1D reduction
//          RDom(Expr min0, Expr extent0, Expr min1, Expr extent1, name="")  -- 2D reduction
//          (Similar for 3D and 4D reductions)
//          RDom(Buffer|ImageParam)                    -- Iterate over all points in the domain

//        The following global functions can be used for inline reductions::

//            minimum, maximum, product, sum
//        """
//        def __new__(cls, *args):
//            args = [wrap(x) if not isinstance(x,str) else x for x in args]
//            return RDomType(*args)

//        def defined(self):
//            """
//            Check if reduction domain is non-NULL.
//            """

//        def same_as(self, other):
//            """
//            Check if two reduction domains are the same.
//            """

//        def dimensions(self):
//            """
//            Number of dimensions.
//            """

//        x = property(doc="Access dimension 1 of reduction domain.")
//        y = property(doc="Access dimension 2 of reduction domain.")
//        z = property(doc="Access dimension 3 of reduction domain.")
//        w = property(doc="Access dimension 4 of reduction domain.")

//    /** Construct an undefined reduction domain. */
//    EXPORT RDom() {}

//    /** Construct a multi-dimensional reduction domain with the given name. If the name
//     * is left blank, a unique one is auto-generated. */
//    // @{
//    NO_INLINE RDom(const std::vector<std::pair<Expr, Expr>> &ranges, std::string name = "") {
//        initialize_from_ranges(ranges, name);
//    }

//    template <typename... Args>
//    NO_INLINE RDom(Expr min, Expr extent, Args... args) {
//        // This should really just be a delegating constructor, but I couldn't make
//        // that work with variadic template unpacking in visual studio 2013
//        std::vector<std::pair<Expr, Expr>> ranges;
//        initialize_from_ranges(ranges, min, extent, args...);
//    }
//    // @}

//    /** Construct a reduction domain that iterates over all points in
//     * a given Buffer, Image, or ImageParam. Has the same
//     * dimensionality as the argument. */
//    // @{
//    EXPORT RDom(Buffer);
//    EXPORT RDom(ImageParam);
//    // @}

//    /** Construct a reduction domain that wraps an Internal ReductionDomain object. */
//    EXPORT RDom(Internal::ReductionDomain d);

//    /** Get at the internal reduction domain object that this wraps. */
//    Internal::ReductionDomain domain() const {return dom;}

//    /** Check if this reduction domain is non-NULL */
//    bool defined() const {return dom.defined();}

//    /** Compare two reduction domains for equality of reference */
//    bool same_as(const RDom &other) const {return dom.same_as(other.dom);}

//    /** Get the dimensionality of a reduction domain */
//    EXPORT int dimensions() const;

//    /** Get at one of the dimensions of the reduction domain */
//    EXPORT RVar operator[](int) const;

//    /** Single-dimensional reduction domains can be used as RVars directly. */
//    EXPORT operator RVar() const;

//    /** Single-dimensional reduction domains can be also be used as Exprs directly. */
//    EXPORT operator Expr() const;

//    /** Direct access to the first four dimensions of the reduction
//     * domain. Some of these variables may be undefined if the
//     * reduction domain has fewer than four dimensions. */
//    // @{
//    RVar x, y, z, w;
//    // @}

    return;
}
<|endoftext|>