<commit_before>/*!
 * Copyright 2015 by Contributors
 * \file data.cc
 */
#include <xgboost/data.h>
#include <xgboost/logging.h>
#include <dmlc/registry.h>
#include <cstring>
#include "./sparse_batch_page.h"
#include "./simple_dmatrix.h"
#include "./simple_csr_source.h"
#include "../common/common.h"
#include "../common/io.h"

#if DMLC_ENABLE_STD_THREAD
#include "./sparse_page_source.h"
#include "./sparse_page_dmatrix.h"
#endif

namespace dmlc {
DMLC_REGISTRY_ENABLE(::xgboost::data::SparsePageFormatReg);
}  // namespace dmlc

namespace xgboost {
// implementation of inline functions
void MetaInfo::Clear() {
  num_row = num_col = num_nonzero = 0;
  labels.clear();
  root_index.clear();
  group_ptr.clear();
  weights.clear();
  base_margin.clear();
}

void MetaInfo::SaveBinary(dmlc::Stream *fo) const {
  int version = kVersion;
  fo->Write(&version, sizeof(version));
  fo->Write(&num_row, sizeof(num_row));
  fo->Write(&num_col, sizeof(num_col));
  fo->Write(&num_nonzero, sizeof(num_nonzero));
  fo->Write(labels);
  fo->Write(group_ptr);
  fo->Write(weights);
  fo->Write(root_index);
  fo->Write(base_margin);
}

void MetaInfo::LoadBinary(dmlc::Stream *fi) {
  int version;
  CHECK(fi->Read(&version, sizeof(version)) == sizeof(version)) << "MetaInfo: invalid version";
  CHECK_EQ(version, kVersion) << "MetaInfo: invalid format";
  CHECK(fi->Read(&num_row, sizeof(num_row)) == sizeof(num_row)) << "MetaInfo: invalid format";
  CHECK(fi->Read(&num_col, sizeof(num_col)) == sizeof(num_col)) << "MetaInfo: invalid format";
  CHECK(fi->Read(&num_nonzero, sizeof(num_nonzero)) == sizeof(num_nonzero))
      << "MetaInfo: invalid format";
  CHECK(fi->Read(&labels)) <<  "MetaInfo: invalid format";
  CHECK(fi->Read(&group_ptr)) << "MetaInfo: invalid format";
  CHECK(fi->Read(&weights)) << "MetaInfo: invalid format";
  CHECK(fi->Read(&root_index)) << "MetaInfo: invalid format";
  CHECK(fi->Read(&base_margin)) << "MetaInfo: invalid format";
}

// try to load group information from file, if exists
inline bool MetaTryLoadGroup(const std::string& fname,
                             std::vector<unsigned>* group) {
  std::unique_ptr<dmlc::Stream> fi(dmlc::Stream::Create(fname.c_str(), "r", true));
  if (fi.get() == nullptr) return false;
  dmlc::istream is(fi.get());
  group->clear();
  group->push_back(0);
  unsigned nline;
  while (is >> nline) {
    group->push_back(group->back() + nline);
  }
  return true;
}

// try to load weight information from file, if exists
inline bool MetaTryLoadFloatInfo(const std::string& fname,
                                 std::vector<bst_float>* data) {
  std::unique_ptr<dmlc::Stream> fi(dmlc::Stream::Create(fname.c_str(), "r", true));
  if (fi.get() == nullptr) return false;
  dmlc::istream is(fi.get());
  data->clear();
  bst_float value;
  while (is >> value) {
    data->push_back(value);
  }
  return true;
}

// macro to dispatch according to specified pointer types
#define DISPATCH_CONST_PTR(dtype, old_ptr, cast_ptr, proc)              \
  switch (dtype) {                                                      \
    case kFloat32: {                                                    \
      const float* cast_ptr = reinterpret_cast<const float*>(old_ptr); proc; break; \
    }                                                                   \
    case kDouble: {                                                     \
      const double* cast_ptr = reinterpret_cast<const double*>(old_ptr); proc; break; \
    }                                                                   \
    case kUInt32: {                                                     \
      const uint32_t* cast_ptr = reinterpret_cast<const uint32_t*>(old_ptr); proc; break; \
    }                                                                   \
    case kUInt64: {                                                     \
      const uint64_t* cast_ptr = reinterpret_cast<const uint64_t*>(old_ptr); proc; break; \
    }                                                                   \
    default: LOG(FATAL) << "Unknown data type" << dtype;                \
  }                                                                     \

void MetaInfo::SetInfo(const char* key, const void* dptr, DataType dtype, size_t num) {
  if (!std::strcmp(key, "root_index")) {
    root_index.resize(num);
    DISPATCH_CONST_PTR(dtype, dptr, cast_dptr,
                       std::copy(cast_dptr, cast_dptr + num, root_index.begin()));
  } else if (!std::strcmp(key, "label")) {
    labels.resize(num);
    DISPATCH_CONST_PTR(dtype, dptr, cast_dptr,
                       std::copy(cast_dptr, cast_dptr + num, labels.begin()));
  } else if (!std::strcmp(key, "weight")) {
    weights.resize(num);
    DISPATCH_CONST_PTR(dtype, dptr, cast_dptr,
                       std::copy(cast_dptr, cast_dptr + num, weights.begin()));
  } else if (!std::strcmp(key, "base_margin")) {
    base_margin.resize(num);
    DISPATCH_CONST_PTR(dtype, dptr, cast_dptr,
                       std::copy(cast_dptr, cast_dptr + num, base_margin.begin()));
  } else if (!std::strcmp(key, "group")) {
    group_ptr.resize(num + 1);
    DISPATCH_CONST_PTR(dtype, dptr, cast_dptr,
                       std::copy(cast_dptr, cast_dptr + num, group_ptr.begin() + 1));
    group_ptr[0] = 0;
    for (size_t i = 1; i < group_ptr.size(); ++i) {
      group_ptr[i] = group_ptr[i - 1] + group_ptr[i];
    }
  }
}

DMatrix* DMatrix::Load(const std::string& uri,
                       bool silent,
                       bool load_row_split,
                       const std::string& file_format) {
  std::string fname, cache_file;
  size_t dlm_pos = uri.find('#');
  if (dlm_pos != std::string::npos) {
    cache_file = uri.substr(dlm_pos + 1, uri.length());
    fname = uri.substr(0, dlm_pos);
    CHECK_EQ(cache_file.find('#'), std::string::npos)
        << "Only one `#` is allowed in file path for cache file specification.";
    if (load_row_split) {
      std::ostringstream os;
      std::vector<std::string> cache_shards = common::Split(cache_file, ':');
      for (size_t i = 0; i < cache_shards.size(); ++i) {
        size_t pos = cache_shards[i].rfind('.');
        if (pos == std::string::npos) {
          os << cache_shards[i]
             << ".r" << rabit::GetRank()
             << "-" <<  rabit::GetWorldSize();
        } else {
          os << cache_shards[i].substr(0, pos)
             << ".r" << rabit::GetRank()
             << "-" <<  rabit::GetWorldSize()
             << cache_shards[i].substr(pos, cache_shards[i].length());
        }
        if (i + 1 != cache_shards.size()) os << ':';
      }
      cache_file = os.str();
    }
  } else {
    fname = uri;
  }
  int partid = 0, npart = 1;
  if (load_row_split) {
    partid = rabit::GetRank();
    npart = rabit::GetWorldSize();
  } else {
    // test option to load in part
    npart = dmlc::GetEnv("XGBOOST_TEST_NPART", 1);
  }

  if (npart != 1) {
    LOG(CONSOLE) << "Load part of data " << partid
                 << " of " << npart << " parts";
  }
  // legacy handling of binary data loading
  if (file_format == "auto" && npart == 1) {
    int magic;
    std::unique_ptr<dmlc::Stream> fi(dmlc::Stream::Create(fname.c_str(), "r", true));
    if (fi.get() != nullptr) {
      common::PeekableInStream is(fi.get());
      if (is.PeekRead(&magic, sizeof(magic)) == sizeof(magic) &&
          magic == data::SimpleCSRSource::kMagic) {
        std::unique_ptr<data::SimpleCSRSource> source(new data::SimpleCSRSource());
        source->LoadBinary(&is);
        DMatrix* dmat = DMatrix::Create(std::move(source), cache_file);
        if (!silent) {
          LOG(CONSOLE) << dmat->info().num_row << 'x' << dmat->info().num_col << " matrix with "
                       << dmat->info().num_nonzero << " entries loaded from " << uri;
        }
        return dmat;
      }
    }
  }

  std::string ftype = file_format;
  if (file_format == "auto") ftype = "libsvm";
  std::unique_ptr<dmlc::Parser<uint32_t> > parser(
      dmlc::Parser<uint32_t>::Create(fname.c_str(), partid, npart, file_format.c_str()));
  DMatrix* dmat = DMatrix::Create(parser.get(), cache_file);
  if (!silent) {
    LOG(CONSOLE) << dmat->info().num_row << 'x' << dmat->info().num_col << " matrix with "
                 << dmat->info().num_nonzero << " entries loaded from " << uri;
  }
  // backward compatiblity code.
  if (!load_row_split) {
    MetaInfo& info = dmat->info();
    if (MetaTryLoadGroup(fname + ".group", &info.group_ptr) && !silent) {
      LOG(CONSOLE) << info.group_ptr.size() - 1
                   << " groups are loaded from " << fname << ".group";
    }
    if (MetaTryLoadFloatInfo(fname + ".base_margin", &info.base_margin) && !silent) {
      LOG(CONSOLE) << info.base_margin.size()
                   << " base_margin are loaded from " << fname << ".base_margin";
    }
    if (MetaTryLoadFloatInfo(fname + ".weight", &info.weights) && !silent) {
      LOG(CONSOLE) << info.weights.size()
                   << " weights are loaded from " << fname << ".weight";
    }
  }
  return dmat;
}

DMatrix* DMatrix::Create(dmlc::Parser<uint32_t>* parser,
                         const std::string& cache_prefix) {
  if (cache_prefix.length() == 0) {
    std::unique_ptr<data::SimpleCSRSource> source(new data::SimpleCSRSource());
    source->CopyFrom(parser);
    return DMatrix::Create(std::move(source), cache_prefix);
  } else {
#if DMLC_ENABLE_STD_THREAD
    if (!data::SparsePageSource::CacheExist(cache_prefix)) {
      data::SparsePageSource::Create(parser, cache_prefix);
    }
    std::unique_ptr<data::SparsePageSource> source(new data::SparsePageSource(cache_prefix));
    return DMatrix::Create(std::move(source), cache_prefix);
#else
    LOG(FATAL) << "External memory is not enabled in mingw";
    return nullptr;
#endif
  }
}

void DMatrix::SaveToLocalFile(const std::string& fname) {
  data::SimpleCSRSource source;
  source.CopyFrom(this);
  std::unique_ptr<dmlc::Stream> fo(dmlc::Stream::Create(fname.c_str(), "w"));
  source.SaveBinary(fo.get());
}

DMatrix* DMatrix::Create(std::unique_ptr<DataSource>&& source,
                         const std::string& cache_prefix) {
  if (cache_prefix.length() == 0) {
    return new data::SimpleDMatrix(std::move(source));
  } else {
#if DMLC_ENABLE_STD_THREAD
    return new data::SparsePageDMatrix(std::move(source), cache_prefix);
#else
    LOG(FATAL) << "External memory is not enabled in mingw";
    return nullptr;
#endif
  }
}
}  // namespace xgboost

namespace xgboost {
namespace data {
SparsePage::Format* SparsePage::Format::Create(const std::string& name) {
  auto *e = ::dmlc::Registry< ::xgboost::data::SparsePageFormatReg>::Get()->Find(name);
  if (e == nullptr) {
    LOG(FATAL) << "Unknown format type " << name;
  }
  return (e->body)();
}

std::pair<std::string, std::string>
SparsePage::Format::DecideFormat(const std::string& cache_prefix) {
  size_t pos = cache_prefix.rfind(".fmt-");

  if (pos != std::string::npos) {
    std::string fmt = cache_prefix.substr(pos + 5, cache_prefix.length());
    size_t cpos = fmt.rfind('-');
    if (cpos != std::string::npos) {
      return std::make_pair(fmt.substr(0, cpos), fmt.substr(cpos + 1, fmt.length()));
    } else {
      return std::make_pair(fmt, fmt);
    }
  } else {
    std::string raw = "raw";
    return std::make_pair(raw, raw);
  }
}

// List of files that will be force linked in static links.
DMLC_REGISTRY_LINK_TAG(sparse_page_raw_format);
}  // namespace data
}  // namespace xgboost
<commit_msg>data.cc: Remove redundant ftype variable<commit_after>/*!
 * Copyright 2015 by Contributors
 * \file data.cc
 */
#include <xgboost/data.h>
#include <xgboost/logging.h>
#include <dmlc/registry.h>
#include <cstring>
#include "./sparse_batch_page.h"
#include "./simple_dmatrix.h"
#include "./simple_csr_source.h"
#include "../common/common.h"
#include "../common/io.h"

#if DMLC_ENABLE_STD_THREAD
#include "./sparse_page_source.h"
#include "./sparse_page_dmatrix.h"
#endif

namespace dmlc {
DMLC_REGISTRY_ENABLE(::xgboost::data::SparsePageFormatReg);
}  // namespace dmlc

namespace xgboost {
// implementation of inline functions
void MetaInfo::Clear() {
  num_row = num_col = num_nonzero = 0;
  labels.clear();
  root_index.clear();
  group_ptr.clear();
  weights.clear();
  base_margin.clear();
}

void MetaInfo::SaveBinary(dmlc::Stream *fo) const {
  int version = kVersion;
  fo->Write(&version, sizeof(version));
  fo->Write(&num_row, sizeof(num_row));
  fo->Write(&num_col, sizeof(num_col));
  fo->Write(&num_nonzero, sizeof(num_nonzero));
  fo->Write(labels);
  fo->Write(group_ptr);
  fo->Write(weights);
  fo->Write(root_index);
  fo->Write(base_margin);
}

void MetaInfo::LoadBinary(dmlc::Stream *fi) {
  int version;
  CHECK(fi->Read(&version, sizeof(version)) == sizeof(version)) << "MetaInfo: invalid version";
  CHECK_EQ(version, kVersion) << "MetaInfo: invalid format";
  CHECK(fi->Read(&num_row, sizeof(num_row)) == sizeof(num_row)) << "MetaInfo: invalid format";
  CHECK(fi->Read(&num_col, sizeof(num_col)) == sizeof(num_col)) << "MetaInfo: invalid format";
  CHECK(fi->Read(&num_nonzero, sizeof(num_nonzero)) == sizeof(num_nonzero))
      << "MetaInfo: invalid format";
  CHECK(fi->Read(&labels)) <<  "MetaInfo: invalid format";
  CHECK(fi->Read(&group_ptr)) << "MetaInfo: invalid format";
  CHECK(fi->Read(&weights)) << "MetaInfo: invalid format";
  CHECK(fi->Read(&root_index)) << "MetaInfo: invalid format";
  CHECK(fi->Read(&base_margin)) << "MetaInfo: invalid format";
}

// try to load group information from file, if exists
inline bool MetaTryLoadGroup(const std::string& fname,
                             std::vector<unsigned>* group) {
  std::unique_ptr<dmlc::Stream> fi(dmlc::Stream::Create(fname.c_str(), "r", true));
  if (fi.get() == nullptr) return false;
  dmlc::istream is(fi.get());
  group->clear();
  group->push_back(0);
  unsigned nline;
  while (is >> nline) {
    group->push_back(group->back() + nline);
  }
  return true;
}

// try to load weight information from file, if exists
inline bool MetaTryLoadFloatInfo(const std::string& fname,
                                 std::vector<bst_float>* data) {
  std::unique_ptr<dmlc::Stream> fi(dmlc::Stream::Create(fname.c_str(), "r", true));
  if (fi.get() == nullptr) return false;
  dmlc::istream is(fi.get());
  data->clear();
  bst_float value;
  while (is >> value) {
    data->push_back(value);
  }
  return true;
}

// macro to dispatch according to specified pointer types
#define DISPATCH_CONST_PTR(dtype, old_ptr, cast_ptr, proc)              \
  switch (dtype) {                                                      \
    case kFloat32: {                                                    \
      const float* cast_ptr = reinterpret_cast<const float*>(old_ptr); proc; break; \
    }                                                                   \
    case kDouble: {                                                     \
      const double* cast_ptr = reinterpret_cast<const double*>(old_ptr); proc; break; \
    }                                                                   \
    case kUInt32: {                                                     \
      const uint32_t* cast_ptr = reinterpret_cast<const uint32_t*>(old_ptr); proc; break; \
    }                                                                   \
    case kUInt64: {                                                     \
      const uint64_t* cast_ptr = reinterpret_cast<const uint64_t*>(old_ptr); proc; break; \
    }                                                                   \
    default: LOG(FATAL) << "Unknown data type" << dtype;                \
  }                                                                     \

void MetaInfo::SetInfo(const char* key, const void* dptr, DataType dtype, size_t num) {
  if (!std::strcmp(key, "root_index")) {
    root_index.resize(num);
    DISPATCH_CONST_PTR(dtype, dptr, cast_dptr,
                       std::copy(cast_dptr, cast_dptr + num, root_index.begin()));
  } else if (!std::strcmp(key, "label")) {
    labels.resize(num);
    DISPATCH_CONST_PTR(dtype, dptr, cast_dptr,
                       std::copy(cast_dptr, cast_dptr + num, labels.begin()));
  } else if (!std::strcmp(key, "weight")) {
    weights.resize(num);
    DISPATCH_CONST_PTR(dtype, dptr, cast_dptr,
                       std::copy(cast_dptr, cast_dptr + num, weights.begin()));
  } else if (!std::strcmp(key, "base_margin")) {
    base_margin.resize(num);
    DISPATCH_CONST_PTR(dtype, dptr, cast_dptr,
                       std::copy(cast_dptr, cast_dptr + num, base_margin.begin()));
  } else if (!std::strcmp(key, "group")) {
    group_ptr.resize(num + 1);
    DISPATCH_CONST_PTR(dtype, dptr, cast_dptr,
                       std::copy(cast_dptr, cast_dptr + num, group_ptr.begin() + 1));
    group_ptr[0] = 0;
    for (size_t i = 1; i < group_ptr.size(); ++i) {
      group_ptr[i] = group_ptr[i - 1] + group_ptr[i];
    }
  }
}

DMatrix* DMatrix::Load(const std::string& uri,
                       bool silent,
                       bool load_row_split,
                       const std::string& file_format) {
  std::string fname, cache_file;
  size_t dlm_pos = uri.find('#');
  if (dlm_pos != std::string::npos) {
    cache_file = uri.substr(dlm_pos + 1, uri.length());
    fname = uri.substr(0, dlm_pos);
    CHECK_EQ(cache_file.find('#'), std::string::npos)
        << "Only one `#` is allowed in file path for cache file specification.";
    if (load_row_split) {
      std::ostringstream os;
      std::vector<std::string> cache_shards = common::Split(cache_file, ':');
      for (size_t i = 0; i < cache_shards.size(); ++i) {
        size_t pos = cache_shards[i].rfind('.');
        if (pos == std::string::npos) {
          os << cache_shards[i]
             << ".r" << rabit::GetRank()
             << "-" <<  rabit::GetWorldSize();
        } else {
          os << cache_shards[i].substr(0, pos)
             << ".r" << rabit::GetRank()
             << "-" <<  rabit::GetWorldSize()
             << cache_shards[i].substr(pos, cache_shards[i].length());
        }
        if (i + 1 != cache_shards.size()) os << ':';
      }
      cache_file = os.str();
    }
  } else {
    fname = uri;
  }
  int partid = 0, npart = 1;
  if (load_row_split) {
    partid = rabit::GetRank();
    npart = rabit::GetWorldSize();
  } else {
    // test option to load in part
    npart = dmlc::GetEnv("XGBOOST_TEST_NPART", 1);
  }

  if (npart != 1) {
    LOG(CONSOLE) << "Load part of data " << partid
                 << " of " << npart << " parts";
  }
  // legacy handling of binary data loading
  if (file_format == "auto" && npart == 1) {
    int magic;
    std::unique_ptr<dmlc::Stream> fi(dmlc::Stream::Create(fname.c_str(), "r", true));
    if (fi.get() != nullptr) {
      common::PeekableInStream is(fi.get());
      if (is.PeekRead(&magic, sizeof(magic)) == sizeof(magic) &&
          magic == data::SimpleCSRSource::kMagic) {
        std::unique_ptr<data::SimpleCSRSource> source(new data::SimpleCSRSource());
        source->LoadBinary(&is);
        DMatrix* dmat = DMatrix::Create(std::move(source), cache_file);
        if (!silent) {
          LOG(CONSOLE) << dmat->info().num_row << 'x' << dmat->info().num_col << " matrix with "
                       << dmat->info().num_nonzero << " entries loaded from " << uri;
        }
        return dmat;
      }
    }
  }

  std::unique_ptr<dmlc::Parser<uint32_t> > parser(
      dmlc::Parser<uint32_t>::Create(fname.c_str(), partid, npart, file_format.c_str()));
  DMatrix* dmat = DMatrix::Create(parser.get(), cache_file);
  if (!silent) {
    LOG(CONSOLE) << dmat->info().num_row << 'x' << dmat->info().num_col << " matrix with "
                 << dmat->info().num_nonzero << " entries loaded from " << uri;
  }
  // backward compatiblity code.
  if (!load_row_split) {
    MetaInfo& info = dmat->info();
    if (MetaTryLoadGroup(fname + ".group", &info.group_ptr) && !silent) {
      LOG(CONSOLE) << info.group_ptr.size() - 1
                   << " groups are loaded from " << fname << ".group";
    }
    if (MetaTryLoadFloatInfo(fname + ".base_margin", &info.base_margin) && !silent) {
      LOG(CONSOLE) << info.base_margin.size()
                   << " base_margin are loaded from " << fname << ".base_margin";
    }
    if (MetaTryLoadFloatInfo(fname + ".weight", &info.weights) && !silent) {
      LOG(CONSOLE) << info.weights.size()
                   << " weights are loaded from " << fname << ".weight";
    }
  }
  return dmat;
}

DMatrix* DMatrix::Create(dmlc::Parser<uint32_t>* parser,
                         const std::string& cache_prefix) {
  if (cache_prefix.length() == 0) {
    std::unique_ptr<data::SimpleCSRSource> source(new data::SimpleCSRSource());
    source->CopyFrom(parser);
    return DMatrix::Create(std::move(source), cache_prefix);
  } else {
#if DMLC_ENABLE_STD_THREAD
    if (!data::SparsePageSource::CacheExist(cache_prefix)) {
      data::SparsePageSource::Create(parser, cache_prefix);
    }
    std::unique_ptr<data::SparsePageSource> source(new data::SparsePageSource(cache_prefix));
    return DMatrix::Create(std::move(source), cache_prefix);
#else
    LOG(FATAL) << "External memory is not enabled in mingw";
    return nullptr;
#endif
  }
}

void DMatrix::SaveToLocalFile(const std::string& fname) {
  data::SimpleCSRSource source;
  source.CopyFrom(this);
  std::unique_ptr<dmlc::Stream> fo(dmlc::Stream::Create(fname.c_str(), "w"));
  source.SaveBinary(fo.get());
}

DMatrix* DMatrix::Create(std::unique_ptr<DataSource>&& source,
                         const std::string& cache_prefix) {
  if (cache_prefix.length() == 0) {
    return new data::SimpleDMatrix(std::move(source));
  } else {
#if DMLC_ENABLE_STD_THREAD
    return new data::SparsePageDMatrix(std::move(source), cache_prefix);
#else
    LOG(FATAL) << "External memory is not enabled in mingw";
    return nullptr;
#endif
  }
}
}  // namespace xgboost

namespace xgboost {
namespace data {
SparsePage::Format* SparsePage::Format::Create(const std::string& name) {
  auto *e = ::dmlc::Registry< ::xgboost::data::SparsePageFormatReg>::Get()->Find(name);
  if (e == nullptr) {
    LOG(FATAL) << "Unknown format type " << name;
  }
  return (e->body)();
}

std::pair<std::string, std::string>
SparsePage::Format::DecideFormat(const std::string& cache_prefix) {
  size_t pos = cache_prefix.rfind(".fmt-");

  if (pos != std::string::npos) {
    std::string fmt = cache_prefix.substr(pos + 5, cache_prefix.length());
    size_t cpos = fmt.rfind('-');
    if (cpos != std::string::npos) {
      return std::make_pair(fmt.substr(0, cpos), fmt.substr(cpos + 1, fmt.length()));
    } else {
      return std::make_pair(fmt, fmt);
    }
  } else {
    std::string raw = "raw";
    return std::make_pair(raw, raw);
  }
}

// List of files that will be force linked in static links.
DMLC_REGISTRY_LINK_TAG(sparse_page_raw_format);
}  // namespace data
}  // namespace xgboost
<|endoftext|>


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

#include "download.h"

#include "error.h"
#include "settings.h"
#include "utils.h"
#include "winsparkle-version.h"

#include <string>
#include <windows.h>
#include <wininet.h>

namespace winsparkle
{

/*--------------------------------------------------------------------------*
                                helpers
 *--------------------------------------------------------------------------*/

namespace
{

struct InetHandle
{
    InetHandle(HINTERNET handle = 0) : m_handle(handle), m_callback(NULL) {}

    ~InetHandle()
    {
        Close();
    }

    InetHandle& operator=(HINTERNET handle)
    {
        Close();
        m_handle = handle;
        return *this;
    }

    void SetStatusCallback(INTERNET_STATUS_CALLBACK callback)
    {
        m_callback = callback;
        InternetSetStatusCallback(m_handle, m_callback);
    }

    void Close()
    {
        if (m_handle)
        {
            if (m_callback)
                InternetSetStatusCallback(m_handle, NULL);
            InternetCloseHandle(m_handle);
            m_handle = NULL;
        }
    }

    operator HINTERNET() const { return m_handle; }

    HINTERNET m_handle;
    INTERNET_STATUS_CALLBACK m_callback;
};

std::wstring MakeUserAgent()
{
    std::wstring userAgent =
        Settings::GetAppName() + L"/" + Settings::GetAppVersion() +
        L" WinSparkle/" + AnsiToWide(WIN_SPARKLE_VERSION_STRING);

#ifdef _WIN64
    userAgent += L" (Win64)";
#else
    // If we're running a 32bit process, check if we're on 64bit Windows OS:
    auto f_IsWow64Process = LOAD_DYNAMIC_FUNC(IsWow64Process, kernel32);
    if( f_IsWow64Process )
    {
        BOOL wow64 = FALSE;
        f_IsWow64Process(GetCurrentProcess(), &wow64);
        if ( wow64 )
            userAgent += L" (WOW64)";
    }

#endif

    return userAgent;
}

bool GetHttpHeader(HINTERNET handle, DWORD whatToGet, DWORD& output)
{
    DWORD outputSize = sizeof(output);
    DWORD headerIndex = 0;
    return HttpQueryInfoA
           (
               handle,
               whatToGet | HTTP_QUERY_FLAG_NUMBER,
               &output,
               &outputSize,
               &headerIndex
           ) == TRUE;
}

std::wstring GetURLFileName(const char *url)
{
    const char *lastSlash = strrchr(url, '/');
    const std::string fn(lastSlash ? lastSlash + 1 : url);
    return AnsiToWide(fn);
}

struct DownloadCallbackContext
{
    DownloadCallbackContext(InetHandle *conn_) : conn(conn_) {}
    InetHandle *conn;
    Event eventRequestComplete;
};

void CALLBACK DownloadInternetStatusCallback(_In_ HINTERNET hInternet,
                                             _In_ DWORD_PTR dwContext,
                                             _In_ DWORD     dwInternetStatus,
                                             _In_ LPVOID    lpvStatusInformation,
                                             _In_ DWORD     dwStatusInformationLength)
{
    DownloadCallbackContext *context = (DownloadCallbackContext*)dwContext;
    INTERNET_ASYNC_RESULT *res = (INTERNET_ASYNC_RESULT*)lpvStatusInformation;

    switch (dwInternetStatus)
    {
        case INTERNET_STATUS_HANDLE_CREATED:
            context->conn->m_handle = (HINTERNET)(res->dwResult);
            break;

        case INTERNET_STATUS_REQUEST_COMPLETE:
            context->eventRequestComplete.Signal();
            break;

        case INTERNET_STATUS_CONNECTION_CLOSED:
            context->conn->Close();
            break;
    }
}

void WaitUntilSignaledWithTerminationCheck(Event& event, Thread *thread)
{
    for (;;)
    {
        if (thread)
            thread->CheckShouldTerminate();
        if (event.WaitUntilSignaled(100))
            return;
    }
}

} // anonymous namespace

/*--------------------------------------------------------------------------*
                                public functions
 *--------------------------------------------------------------------------*/

void DownloadFile(const std::string& url, IDownloadSink *sink, Thread *onThread, int flags)
{
    char url_path[2048];
    URL_COMPONENTSA urlc;
    memset(&urlc, 0, sizeof(urlc));
    urlc.dwStructSize = sizeof(urlc);
    urlc.lpszUrlPath = url_path;
    urlc.dwUrlPathLength = sizeof(url_path);

    if ( !InternetCrackUrlA(url.c_str(), 0, ICU_DECODE, &urlc) )
        throw Win32Exception();

    InetHandle inet = InternetOpen
                      (
                          MakeUserAgent().c_str(),
                          INTERNET_OPEN_TYPE_PRECONFIG,
                          NULL, // lpszProxyName
                          NULL, // lpszProxyBypass
                          INTERNET_FLAG_ASYNC // dwFlags
                      );
    if ( !inet )
        throw Win32Exception();

    DWORD dwFlags = 0;
    if ( flags & Download_NoCached )
        dwFlags |= INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD;
    if ( urlc.nScheme == INTERNET_SCHEME_HTTPS )
        dwFlags |= INTERNET_FLAG_SECURE;

    InetHandle conn;

    DownloadCallbackContext context(&conn);
    inet.SetStatusCallback(&DownloadInternetStatusCallback);

    HINTERNET conn_raw = InternetOpenUrlA
                         (
                             inet,
                             url.c_str(),
                             NULL, // lpszHeaders
                             -1,   // dwHeadersLength
                             dwFlags,
                             (DWORD_PTR)&context  // dwContext
                         );
    // InternetOpenUrl() may return NULL handle and then fill it in asynchronously from
    // DownloadInternetStatusCallback. We must make sure we don't overwrite the handle
    // in that case, or throw an error.
    if (conn_raw)
    {
        conn = conn_raw;
    }
    else
    {
        if (GetLastError() != ERROR_IO_PENDING)
            throw Win32Exception();
    }

    WaitUntilSignaledWithTerminationCheck(context.eventRequestComplete, onThread);

    // Check returned status code - we need to detect 404 instead of
    // downloading the human-readable 404 page:
    DWORD statusCode;
    if ( GetHttpHeader(conn, HTTP_QUERY_STATUS_CODE, statusCode) && statusCode >= 400 )
    {
        throw std::runtime_error("Update file not found on the server.");
    }

    // Get content length if possible:
    DWORD contentLength;
    if ( GetHttpHeader(conn, HTTP_QUERY_CONTENT_LENGTH, contentLength) )
        sink->SetLength(contentLength);

    // Get filename fron Content-Disposition, if available
    char contentDisposition[512];
    DWORD cdSize = 512;
    bool filename_set = false;
    if ( HttpQueryInfoA(conn, HTTP_QUERY_CONTENT_DISPOSITION, contentDisposition, &cdSize, NULL) )
    {
        char *ptr = strstr(contentDisposition, "filename=");
        if ( ptr )
        {
            char c_filename[512];
            ptr += 9;
            while ( *ptr == ' ' )
                ptr++;

            bool quoted = false;
            if ( *ptr == '"' || *ptr == '\'')
            {
                quoted = true;
                ptr++;
            }

            char *ptr2 = c_filename;
            while ( *ptr != ';' && *ptr != 0)
                *ptr2++ = *ptr++;

            if ( quoted )
                *(ptr2 - 1) = 0;
            else
                *ptr2 = 0;

            sink->SetFilename(AnsiToWide(c_filename));
            filename_set = true;
        }
    }

    if ( !filename_set )
    {
        DWORD ousize = 0;
        InternetQueryOptionA(conn, INTERNET_OPTION_URL, NULL, &ousize);
        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
        {
            DataBuffer<char> optionurl(ousize);
            if ( InternetQueryOptionA(conn, INTERNET_OPTION_URL, optionurl, &ousize) )
                sink->SetFilename(GetURLFileName(optionurl));
            else
                sink->SetFilename(GetURLFileName(urlc.lpszUrlPath));
        }
        else
        {
            sink->SetFilename(GetURLFileName(urlc.lpszUrlPath));
        }
    }

    // Download the data:
    char buffer[10240];
    for ( ;; )
    {
        INTERNET_BUFFERS ibuf = { 0 };
        ibuf.dwStructSize = sizeof(ibuf);
        ibuf.lpvBuffer = buffer;
        ibuf.dwBufferLength = sizeof(buffer);

        if (!InternetReadFileEx(conn, &ibuf, IRF_ASYNC | IRF_NO_WAIT, NULL))
        {
            if (GetLastError() != ERROR_IO_PENDING)
                throw Win32Exception();

            WaitUntilSignaledWithTerminationCheck(context.eventRequestComplete, onThread);
            continue;
        }

        if (ibuf.dwBufferLength == 0)
        {
            // This check is required in case the INTERNET_STATUS_CONNECTION_CLOSED event was
            // received (and the handle was closed) during the call to InternetReadFileEx()
            if (!conn)
                throw Win32Exception();
            else
                break; // all of the file was downloaded
        }

        sink->Add(ibuf.lpvBuffer, ibuf.dwBufferLength);
    }
}

} // namespace winsparkle
<commit_msg>Remove query string from URL filename (#133)<commit_after>/*
 *  This file is part of WinSparkle (https://winsparkle.org)
 *
 *  Copyright (C) 2009-2017 Vaclav Slavik
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 *
 */

#include "download.h"

#include "error.h"
#include "settings.h"
#include "utils.h"
#include "winsparkle-version.h"

#include <string>
#include <windows.h>
#include <wininet.h>

namespace winsparkle
{

/*--------------------------------------------------------------------------*
                                helpers
 *--------------------------------------------------------------------------*/

namespace
{

struct InetHandle
{
    InetHandle(HINTERNET handle = 0) : m_handle(handle), m_callback(NULL) {}

    ~InetHandle()
    {
        Close();
    }

    InetHandle& operator=(HINTERNET handle)
    {
        Close();
        m_handle = handle;
        return *this;
    }

    void SetStatusCallback(INTERNET_STATUS_CALLBACK callback)
    {
        m_callback = callback;
        InternetSetStatusCallback(m_handle, m_callback);
    }

    void Close()
    {
        if (m_handle)
        {
            if (m_callback)
                InternetSetStatusCallback(m_handle, NULL);
            InternetCloseHandle(m_handle);
            m_handle = NULL;
        }
    }

    operator HINTERNET() const { return m_handle; }

    HINTERNET m_handle;
    INTERNET_STATUS_CALLBACK m_callback;
};

std::wstring MakeUserAgent()
{
    std::wstring userAgent =
        Settings::GetAppName() + L"/" + Settings::GetAppVersion() +
        L" WinSparkle/" + AnsiToWide(WIN_SPARKLE_VERSION_STRING);

#ifdef _WIN64
    userAgent += L" (Win64)";
#else
    // If we're running a 32bit process, check if we're on 64bit Windows OS:
    auto f_IsWow64Process = LOAD_DYNAMIC_FUNC(IsWow64Process, kernel32);
    if( f_IsWow64Process )
    {
        BOOL wow64 = FALSE;
        f_IsWow64Process(GetCurrentProcess(), &wow64);
        if ( wow64 )
            userAgent += L" (WOW64)";
    }

#endif

    return userAgent;
}

bool GetHttpHeader(HINTERNET handle, DWORD whatToGet, DWORD& output)
{
    DWORD outputSize = sizeof(output);
    DWORD headerIndex = 0;
    return HttpQueryInfoA
           (
               handle,
               whatToGet | HTTP_QUERY_FLAG_NUMBER,
               &output,
               &outputSize,
               &headerIndex
           ) == TRUE;
}

std::wstring GetURLFileName(const char *url)
{
    const char *lastSlash = strrchr(url, '/');
    std::string fn(lastSlash ? lastSlash + 1 : url);
    if (fn.find_first_of('?') != std::string::npos)
        fn = fn.substr(0, fn.find_first_of('?'));
    return AnsiToWide(fn);
}

struct DownloadCallbackContext
{
    DownloadCallbackContext(InetHandle *conn_) : conn(conn_) {}
    InetHandle *conn;
    Event eventRequestComplete;
};

void CALLBACK DownloadInternetStatusCallback(_In_ HINTERNET hInternet,
                                             _In_ DWORD_PTR dwContext,
                                             _In_ DWORD     dwInternetStatus,
                                             _In_ LPVOID    lpvStatusInformation,
                                             _In_ DWORD     dwStatusInformationLength)
{
    DownloadCallbackContext *context = (DownloadCallbackContext*)dwContext;
    INTERNET_ASYNC_RESULT *res = (INTERNET_ASYNC_RESULT*)lpvStatusInformation;

    switch (dwInternetStatus)
    {
        case INTERNET_STATUS_HANDLE_CREATED:
            context->conn->m_handle = (HINTERNET)(res->dwResult);
            break;

        case INTERNET_STATUS_REQUEST_COMPLETE:
            context->eventRequestComplete.Signal();
            break;

        case INTERNET_STATUS_CONNECTION_CLOSED:
            context->conn->Close();
            break;
    }
}

void WaitUntilSignaledWithTerminationCheck(Event& event, Thread *thread)
{
    for (;;)
    {
        if (thread)
            thread->CheckShouldTerminate();
        if (event.WaitUntilSignaled(100))
            return;
    }
}

} // anonymous namespace

/*--------------------------------------------------------------------------*
                                public functions
 *--------------------------------------------------------------------------*/

void DownloadFile(const std::string& url, IDownloadSink *sink, Thread *onThread, int flags)
{
    char url_path[2048];
    URL_COMPONENTSA urlc;
    memset(&urlc, 0, sizeof(urlc));
    urlc.dwStructSize = sizeof(urlc);
    urlc.lpszUrlPath = url_path;
    urlc.dwUrlPathLength = sizeof(url_path);

    if ( !InternetCrackUrlA(url.c_str(), 0, ICU_DECODE, &urlc) )
        throw Win32Exception();

    InetHandle inet = InternetOpen
                      (
                          MakeUserAgent().c_str(),
                          INTERNET_OPEN_TYPE_PRECONFIG,
                          NULL, // lpszProxyName
                          NULL, // lpszProxyBypass
                          INTERNET_FLAG_ASYNC // dwFlags
                      );
    if ( !inet )
        throw Win32Exception();

    DWORD dwFlags = 0;
    if ( flags & Download_NoCached )
        dwFlags |= INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD;
    if ( urlc.nScheme == INTERNET_SCHEME_HTTPS )
        dwFlags |= INTERNET_FLAG_SECURE;

    InetHandle conn;

    DownloadCallbackContext context(&conn);
    inet.SetStatusCallback(&DownloadInternetStatusCallback);

    HINTERNET conn_raw = InternetOpenUrlA
                         (
                             inet,
                             url.c_str(),
                             NULL, // lpszHeaders
                             -1,   // dwHeadersLength
                             dwFlags,
                             (DWORD_PTR)&context  // dwContext
                         );
    // InternetOpenUrl() may return NULL handle and then fill it in asynchronously from
    // DownloadInternetStatusCallback. We must make sure we don't overwrite the handle
    // in that case, or throw an error.
    if (conn_raw)
    {
        conn = conn_raw;
    }
    else
    {
        if (GetLastError() != ERROR_IO_PENDING)
            throw Win32Exception();
    }

    WaitUntilSignaledWithTerminationCheck(context.eventRequestComplete, onThread);

    // Check returned status code - we need to detect 404 instead of
    // downloading the human-readable 404 page:
    DWORD statusCode;
    if ( GetHttpHeader(conn, HTTP_QUERY_STATUS_CODE, statusCode) && statusCode >= 400 )
    {
        throw std::runtime_error("Update file not found on the server.");
    }

    // Get content length if possible:
    DWORD contentLength;
    if ( GetHttpHeader(conn, HTTP_QUERY_CONTENT_LENGTH, contentLength) )
        sink->SetLength(contentLength);

    // Get filename fron Content-Disposition, if available
    char contentDisposition[512];
    DWORD cdSize = 512;
    bool filename_set = false;
    if ( HttpQueryInfoA(conn, HTTP_QUERY_CONTENT_DISPOSITION, contentDisposition, &cdSize, NULL) )
    {
        char *ptr = strstr(contentDisposition, "filename=");
        if ( ptr )
        {
            char c_filename[512];
            ptr += 9;
            while ( *ptr == ' ' )
                ptr++;

            bool quoted = false;
            if ( *ptr == '"' || *ptr == '\'')
            {
                quoted = true;
                ptr++;
            }

            char *ptr2 = c_filename;
            while ( *ptr != ';' && *ptr != 0)
                *ptr2++ = *ptr++;

            if ( quoted )
                *(ptr2 - 1) = 0;
            else
                *ptr2 = 0;

            sink->SetFilename(AnsiToWide(c_filename));
            filename_set = true;
        }
    }

    if ( !filename_set )
    {
        DWORD ousize = 0;
        InternetQueryOptionA(conn, INTERNET_OPTION_URL, NULL, &ousize);
        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
        {
            DataBuffer<char> optionurl(ousize);
            if ( InternetQueryOptionA(conn, INTERNET_OPTION_URL, optionurl, &ousize) )
                sink->SetFilename(GetURLFileName(optionurl));
            else
                sink->SetFilename(GetURLFileName(urlc.lpszUrlPath));
        }
        else
        {
            sink->SetFilename(GetURLFileName(urlc.lpszUrlPath));
        }
    }

    // Download the data:
    char buffer[10240];
    for ( ;; )
    {
        INTERNET_BUFFERS ibuf = { 0 };
        ibuf.dwStructSize = sizeof(ibuf);
        ibuf.lpvBuffer = buffer;
        ibuf.dwBufferLength = sizeof(buffer);

        if (!InternetReadFileEx(conn, &ibuf, IRF_ASYNC | IRF_NO_WAIT, NULL))
        {
            if (GetLastError() != ERROR_IO_PENDING)
                throw Win32Exception();

            WaitUntilSignaledWithTerminationCheck(context.eventRequestComplete, onThread);
            continue;
        }

        if (ibuf.dwBufferLength == 0)
        {
            // This check is required in case the INTERNET_STATUS_CONNECTION_CLOSED event was
            // received (and the handle was closed) during the call to InternetReadFileEx()
            if (!conn)
                throw Win32Exception();
            else
                break; // all of the file was downloaded
        }

        sink->Add(ibuf.lpvBuffer, ibuf.dwBufferLength);
    }
}

} // namespace winsparkle
<|endoftext|>


<commit_before>#include "function.h"
#include "math/epsilon.h"

namespace nano
{
        function_t::function_t(const char* name,
                const tensor_size_t size, const tensor_size_t min_size, const tensor_size_t max_size,
                const convexity convex,
                const scalar_t domain) :
                m_name(name),
                m_size(size), m_min_size(min_size), m_max_size(max_size),
                m_convex(convex),
                m_domain(domain),
                m_fcalls(0), m_stoch_fcalls(0),
                m_gcalls(0), m_stoch_gcalls(0)
        {
        }

        scalar_t function_t::eval(const vector_t& x, vector_t* gx) const
        {
                assert(x.size() == size());

                m_fcalls ++;
                if (gx)
                {
                        m_gcalls ++;
                        gx->resize(size());
                }

                return vgrad(x, gx);
        }

        scalar_t function_t::stoch_eval(const vector_t& x, vector_t* gx) const
        {
                assert(x.size() == size());

                m_stoch_fcalls ++;
                if (gx)
                {
                        m_stoch_gcalls ++;
                        gx->resize(size());
                }

                return stoch_vgrad(x, gx);
        }

        scalar_t function_t::grad_accuracy(const vector_t& x) const
        {
                assert(x.size() == size());

                const auto n = size();

                vector_t gx(n);
                vector_t gx_approx(n);
                vector_t xp = x, xn = x;

                // analytical gradient
                const auto fx = vgrad(x, &gx);

                // finite-difference approximated gradient
                //      see "Numerical optimization", Nocedal & Wright, 2nd edition, p.197
                const auto finite_difference = [&] (const scalar_t dx)
                {
                        for (auto i = 0; i < n; i ++)
                        {
                                xp = x; xp(i) += dx;
                                xn = x; xn(i) -= dx;

                                const auto dfi = vgrad(xp, nullptr) - vgrad(xn, nullptr);
                                const auto dxi = xp(i) - xn(i);
                                gx_approx(i) = dfi / dxi;
                        }

                        return (gx - gx_approx).lpNorm<Eigen::Infinity>() / (1 + std::fabs(fx));
                };

                // we're trying various scaling factors of {u^(2/3), u^(1/2), u^(1/3)}
                scalar_t best_approx = std::numeric_limits<scalar_t>::max();
                for (const scalar_t dp : {1, 2, 4, 8})
                {
                        best_approx = std::min(best_approx, finite_difference(epsilon1<scalar_t>() / 10 * dp));
                        best_approx = std::min(best_approx, finite_difference(epsilon2<scalar_t>() / 10 * dp));
                        best_approx = std::min(best_approx, finite_difference(epsilon3<scalar_t>() / 10 * dp));
                }

                return best_approx;
        }

        bool function_t::is_convex(const vector_t& x1, const vector_t& x2, const int steps) const
        {
                assert(steps > 2);
                assert(x1.size() == size());
                assert(x2.size() == size());

                const auto f1 = vgrad(x1, nullptr);
                assert(std::isfinite(f1));

                const auto f2 = vgrad(x2, nullptr);
                assert(std::isfinite(f2));

                for (int step = 1; step < steps; step ++)
                {
                        const auto t1 = scalar_t(step) / scalar_t(steps);
                        const auto t2 = scalar_t(1) - t1;

                        const auto ft = vgrad(t1 * x1 + t2 * x2, nullptr);
                        if (std::isfinite(ft) && ft > (1 + epsilon0<scalar_t>()) * (t1 * f1 + t2 * f2))
                        {
                                return false;
                        }
                }

                return true;
        }

        size_t function_t::fcalls() const
        {
                return m_fcalls + m_stoch_fcalls / stoch_ratio();
        }

        size_t function_t::gcalls() const
        {
                return m_gcalls + m_stoch_gcalls / stoch_ratio();
        }

        string_t function_t::name() const
        {
                return string_t(m_name) + "[" + std::to_string(size()) + "D]";
        }

        bool function_t::is_valid(const vector_t& x) const
        {
                return x.lpNorm<Eigen::Infinity>() < m_domain;
        }
}
<commit_msg>fix warning (gcc)<commit_after>#include "function.h"
#include "math/epsilon.h"

namespace nano
{
        function_t::function_t(const char* name,
                const tensor_size_t size, const tensor_size_t min_size, const tensor_size_t max_size,
                const convexity convex,
                const scalar_t domain) :
                m_name(name),
                m_size(size), m_min_size(min_size), m_max_size(max_size),
                m_convex(convex),
                m_domain(domain),
                m_fcalls(0), m_stoch_fcalls(0),
                m_gcalls(0), m_stoch_gcalls(0)
        {
        }

        scalar_t function_t::eval(const vector_t& x, vector_t* gx) const
        {
                assert(x.size() == size());

                m_fcalls ++;
                if (gx)
                {
                        m_gcalls ++;
                        gx->resize(size());
                }

                return vgrad(x, gx);
        }

        scalar_t function_t::stoch_eval(const vector_t& x, vector_t* gx) const
        {
                assert(x.size() == size());

                m_stoch_fcalls ++;
                if (gx)
                {
                        m_stoch_gcalls ++;
                        gx->resize(size());
                }

                return stoch_vgrad(x, gx);
        }

        scalar_t function_t::grad_accuracy(const vector_t& x) const
        {
                assert(x.size() == size());

                const auto n = size();

                vector_t gx(n);
                vector_t gx_approx(n);
                vector_t xp = x, xn = x;

                // analytical gradient
                const auto fx = vgrad(x, &gx);

                // finite-difference approximated gradient
                //      see "Numerical optimization", Nocedal & Wright, 2nd edition, p.197
                const auto finite_difference = [&] (const scalar_t dx)
                {
                        for (auto i = 0; i < n; i ++)
                        {
                                xp = x; xp(i) += dx;
                                xn = x; xn(i) -= dx;

                                const auto dfi = vgrad(xp, nullptr) - vgrad(xn, nullptr);
                                const auto dxi = xp(i) - xn(i);
                                gx_approx(i) = dfi / dxi;
                        }

                        return (gx - gx_approx).lpNorm<Eigen::Infinity>() / (1 + std::fabs(fx));
                };

                // we're trying various scaling factors of {u^(2/3), u^(1/2), u^(1/3)}
                scalar_t best_approx = std::numeric_limits<scalar_t>::max();
                for (const auto dp : {scalar_t(1), scalar_t(2), scalar_t(4), scalar_t(8)})
                {
                        best_approx = std::min(best_approx, finite_difference(epsilon1<scalar_t>() / 10 * dp));
                        best_approx = std::min(best_approx, finite_difference(epsilon2<scalar_t>() / 10 * dp));
                        best_approx = std::min(best_approx, finite_difference(epsilon3<scalar_t>() / 10 * dp));
                }

                return best_approx;
        }

        bool function_t::is_convex(const vector_t& x1, const vector_t& x2, const int steps) const
        {
                assert(steps > 2);
                assert(x1.size() == size());
                assert(x2.size() == size());

                const auto f1 = vgrad(x1, nullptr);
                assert(std::isfinite(f1));

                const auto f2 = vgrad(x2, nullptr);
                assert(std::isfinite(f2));

                for (int step = 1; step < steps; step ++)
                {
                        const auto t1 = scalar_t(step) / scalar_t(steps);
                        const auto t2 = scalar_t(1) - t1;

                        const auto ft = vgrad(t1 * x1 + t2 * x2, nullptr);
                        if (std::isfinite(ft) && ft > (1 + epsilon0<scalar_t>()) * (t1 * f1 + t2 * f2))
                        {
                                return false;
                        }
                }

                return true;
        }

        size_t function_t::fcalls() const
        {
                return m_fcalls + m_stoch_fcalls / stoch_ratio();
        }

        size_t function_t::gcalls() const
        {
                return m_gcalls + m_stoch_gcalls / stoch_ratio();
        }

        string_t function_t::name() const
        {
                return string_t(m_name) + "[" + std::to_string(size()) + "D]";
        }

        bool function_t::is_valid(const vector_t& x) const
        {
                return x.lpNorm<Eigen::Infinity>() < m_domain;
        }
}
<|endoftext|>


<commit_before>/* function.tcc                                 -*- C++ -*-
   Rémi Attab (remi.attab@gmail.com), 27 Mar 2014
   FreeBSD-style copyright and disclaimer apply

   template implementation for Function Functions
*/

#include "reflect.h"
#pragma once

namespace reflect {

/******************************************************************************/
/* REFLECT FUNCTION                                                           */
/******************************************************************************/

template<typename Fn>
Argument reflectReturn()
{
    typedef typename GetReturnValue<Fn>::type Ret;
    return Argument::make<Ret>();
}

/** Note that we have to use TypeVector otherwise if we're dealing purely with
    types then we'd need to define the base case like so:

        template<> void reflectArgs() {}

    The compiler will interpret this as a template specialization for function
    which it will refuse to allow. If we omit then template<> then the compiler
    doesn't recognize it as a valid overload for a call to:

        reflectArgs<>();

    So we instead have to rely on type deduction using a phony TypeVector
    parameter which allows us to write the base case as:

        void reflectArgs(TypeVector<>) {}

    C++ uses dark corner case. It's super effective!
*/
inline void reflectArguments(std::vector<Argument>&, TypeVector<>) {}

template<typename Arg, typename... Rest>
void reflectArguments(std::vector<Argument>& args, TypeVector<Arg, Rest...>)
{
    args.push_back(Argument::make<Arg>());
    reflectArguments(args, TypeVector<Rest...>());
}

template<typename Fn>
std::vector<Argument> reflectArguments()
{
    typedef typename GetArguments<Fn>::type Args;

    std::vector<Argument> args;
    reflectArguments(args, Args());
    return args;
}

inline void reflectArguments(std::vector<Argument>&) {}

template<typename... Rest>
void reflectArguments(
        std::vector<Argument>& args, Value& value, Rest&&... rest)
{
    args.emplace_back(value.argument());
    reflectArguments(args, std::forward<Rest>(rest)...);
}

template<typename... Rest>
void reflectArguments(
        std::vector<Argument>& args, Value&& value, Rest&&... rest)
{
    args.emplace_back(value.argument());
    reflectArguments(args, std::forward<Rest>(rest)...);
}

template<typename Arg, typename... Rest>
void reflectArguments(std::vector<Argument>& args, Arg&& arg, Rest&&... rest)
{
    args.emplace_back(Argument::make(std::forward<Arg>(arg)));
    reflectArguments(args, std::forward<Rest>(rest)...);
}

template<typename... Args>
std::vector<Argument> reflectArguments(Args&&... args)
{
    std::vector<Argument> result;
    reflectArguments(result, std::forward<Args>(args)...);
    return result;
}

/******************************************************************************/
/* FUNCTION                                                                   */
/******************************************************************************/

template<typename Fn>
Function::
Function(std::string name, Fn fn) :
    name_(std::move(name))
{
    initFn(makeFunction(std::move(fn)));
}

template<typename Ret, typename... Args>
void
Function::
initFn(std::function<Ret(Args...)> rawFn)
{
    auto typedFn = makeValueFunction(std::move(rawFn));

    // std::function is stored as a single pointer (memory allocation are used
    // to handle spill overs) which means it's "safe" to cast it to VoidFn and
    // back. The original type can always be recovered before we make the calll.
    fn = *reinterpret_cast<VoidFn*>(&typedFn);

    ret = reflectReturn<Ret(Args...)>();
    args = reflectArguments<Ret(Args...)>();
}

template<typename Fn>
Match
Function::
test() const
{
    auto otherRet = reflectReturn<Fn>();
    auto otherArgs = reflectArguments<Fn>();

    return combine(
            testReturn(otherRet, ret),
            testArguments(otherArgs, args));
}

template<typename Ret, typename... Args>
Match
Function::
testParams(Args&&... args) const
{
    auto otherRet = reflectReturn<Ret(Args...)>();
    auto otherArgs = reflectArguments(std::forward<Args>(args)...);

    return combine(
            testReturn(otherRet, ret),
            testArguments(otherArgs, this->args));
}

template<typename Ret, typename... Args>
Ret
Function::
call(Args&&... args) const
{
    if (testParams<Ret>(std::forward<Args>(args)...) == Match::None) {
        reflectError("<%s> is not convertible to <%s>",
                signature<Ret(Args...)>(), signature(*this));
    }

    typedef typename MakeStdValueFunction<Args...>::type Fn;
    const auto& typedFn = *reinterpret_cast<const Fn*>(&fn);

    Value ret = typedFn(cast<Value>(std::forward<Args>(args))...);
    return retCast<Ret>(ret);
}

} // reflect
<commit_msg>Added missing reflectArguments overload.<commit_after>/* function.tcc                                 -*- C++ -*-
   Rémi Attab (remi.attab@gmail.com), 27 Mar 2014
   FreeBSD-style copyright and disclaimer apply

   template implementation for Function Functions
*/

#include "reflect.h"
#pragma once

namespace reflect {

/******************************************************************************/
/* REFLECT FUNCTION                                                           */
/******************************************************************************/

template<typename Fn>
Argument reflectReturn()
{
    typedef typename GetReturnValue<Fn>::type Ret;
    return Argument::make<Ret>();
}

/** Note that we have to use TypeVector otherwise if we're dealing purely with
    types then we'd need to define the base case like so:

        template<> void reflectArgs() {}

    The compiler will interpret this as a template specialization for function
    which it will refuse to allow. If we omit then template<> then the compiler
    doesn't recognize it as a valid overload for a call to:

        reflectArgs<>();

    So we instead have to rely on type deduction using a phony TypeVector
    parameter which allows us to write the base case as:

        void reflectArgs(TypeVector<>) {}

    C++ uses dark corner case. It's super effective!
*/
inline void reflectArguments(std::vector<Argument>&, TypeVector<>) {}

template<typename Arg, typename... Rest>
void reflectArguments(std::vector<Argument>& args, TypeVector<Arg, Rest...>)
{
    args.push_back(Argument::make<Arg>());
    reflectArguments(args, TypeVector<Rest...>());
}

template<typename Fn>
std::vector<Argument> reflectArguments()
{
    typedef typename GetArguments<Fn>::type Args;

    std::vector<Argument> args;
    reflectArguments(args, Args());
    return args;
}

/******************************************************************************/
/* REFLECT ARGUMENTS                                                          */
/******************************************************************************/

inline void reflectArguments(std::vector<Argument>&) {}

template<typename... Rest>
void reflectArguments(
        std::vector<Argument>& args, Value& value, Rest&&... rest)
{
    args.emplace_back(value.argument());
    reflectArguments(args, std::forward<Rest>(rest)...);
}

template<typename... Rest>
void reflectArguments(
        std::vector<Argument>& args, const Value& value, Rest&&... rest)
{
    args.emplace_back(value.argument());
    reflectArguments(args, std::forward<Rest>(rest)...);
}

template<typename... Rest>
void reflectArguments(
        std::vector<Argument>& args, Value&& value, Rest&&... rest)
{
    args.emplace_back(value.argument());
    reflectArguments(args, std::forward<Rest>(rest)...);
}

template<typename Arg, typename... Rest>
void reflectArguments(std::vector<Argument>& args, Arg&& arg, Rest&&... rest)
{
    args.emplace_back(Argument::make(std::forward<Arg>(arg)));
    reflectArguments(args, std::forward<Rest>(rest)...);
}

template<typename... Args>
std::vector<Argument> reflectArguments(Args&&... args)
{
    std::vector<Argument> result;
    reflectArguments(result, std::forward<Args>(args)...);
    return result;
}

/******************************************************************************/
/* FUNCTION                                                                   */
/******************************************************************************/

template<typename Fn>
Function::
Function(std::string name, Fn fn) :
    name_(std::move(name))
{
    initFn(makeFunction(std::move(fn)));
}

template<typename Ret, typename... Args>
void
Function::
initFn(std::function<Ret(Args...)> rawFn)
{
    auto typedFn = makeValueFunction(std::move(rawFn));

    // std::function is stored as a single pointer (memory allocation are used
    // to handle spill overs) which means it's "safe" to cast it to VoidFn and
    // back. The original type can always be recovered before we make the calll.
    fn = *reinterpret_cast<VoidFn*>(&typedFn);

    ret = reflectReturn<Ret(Args...)>();
    args = reflectArguments<Ret(Args...)>();
}

template<typename Fn>
Match
Function::
test() const
{
    auto otherRet = reflectReturn<Fn>();
    auto otherArgs = reflectArguments<Fn>();

    return combine(
            testReturn(otherRet, ret),
            testArguments(otherArgs, args));
}

template<typename Ret, typename... Args>
Match
Function::
testParams(Args&&... args) const
{
    auto otherRet = reflectReturn<Ret(Args...)>();
    auto otherArgs = reflectArguments(std::forward<Args>(args)...);

    return combine(
            testReturn(otherRet, ret),
            testArguments(otherArgs, this->args));
}

template<typename Ret, typename... Args>
Ret
Function::
call(Args&&... args) const
{
    if (testParams<Ret>(std::forward<Args>(args)...) == Match::None) {
        reflectError("<%s> is not convertible to <%s>",
                signature<Ret(Args...)>(), signature(*this));
    }

    typedef typename MakeStdValueFunction<Args...>::type Fn;
    const auto& typedFn = *reinterpret_cast<const Fn*>(&fn);

    Value ret = typedFn(cast<Value>(std::forward<Args>(args))...);
    return retCast<Ret>(ret);
}

} // reflect
<|endoftext|>


<commit_before>
#include <SFML/Graphics.hpp>

#include <iostream>

#include "engine/game-manager.h"
#include "structures/tower.h"
#include "tilemaps/map.h"
#include "units/enemy-unit.h"
#include "game/ingame-ui.h"
#include "levels/level.h"

int main(int argc, char const *argv[]) {
  sf::Vector2u window_size(GameManager::GetWindowSize());
  sf::RenderWindow window(sf::VideoMode(window_size.x, window_size.y),
                          "Lord of the Orb",
                          sf::Style::None);

  auto instances = GameManager::GetInstancesManager();

  auto resources = GameManager::GetResourcesManager();
  if (!resources->Load()) {
    std::cerr << "Cannot load game resources!" << std::endl;
    return 1;
  }

  auto map = new Map();

  if (!map->Load("assets/tilemaps/level_1.map")) {
    std::cerr << "Cannot load tilemap" << std::endl;
    return 1;
  }
  instances->AddInstance(map);

  auto tower = new Tower();
  tower->Load();
  tower->set_position(sf::Vector2u(7, 5));
  instances->AddInstance(tower);

  auto level = new Level(1);
  level->Load();

  auto ui = new InGameUI();
  ui->Load();
  instances->AddInstance(ui);

  GameManager::GetMapController()->Load();
  GameManager::GetPlayerController()->Load();

  sf::Clock clock;

  while (window.isOpen()) {
    GameManager::GetEventsManager()->EventsLoop(&window);

    sf::Time elapsed = clock.restart();
    instances->Step(elapsed);

    window.clear(sf::Color::Black);

    instances->Draw(&window);

    window.display();
  }

  return 0;
}
<commit_msg>Step controllers<commit_after>
#include <SFML/Graphics.hpp>

#include <iostream>

#include "engine/game-manager.h"
#include "structures/tower.h"
#include "tilemaps/map.h"
#include "units/enemy-unit.h"
#include "game/ingame-ui.h"
#include "levels/level.h"

int main(int argc, char const *argv[]) {
  sf::Vector2u window_size(GameManager::GetWindowSize());
  sf::RenderWindow window(sf::VideoMode(window_size.x, window_size.y),
                          "Lord of the Orb",
                          sf::Style::None);

  auto instances = GameManager::GetInstancesManager();

  auto resources = GameManager::GetResourcesManager();
  if (!resources->Load()) {
    std::cerr << "Cannot load game resources!" << std::endl;
    return 1;
  }

  auto map = new Map();

  if (!map->Load("assets/tilemaps/level_1.map")) {
    std::cerr << "Cannot load tilemap" << std::endl;
    return 1;
  }
  instances->AddInstance(map);

  auto tower = new Tower();
  tower->Load();
  tower->set_position(sf::Vector2u(7, 5));
  instances->AddInstance(tower);

  auto level = new Level(1);
  level->Load();

  auto ui = new InGameUI();
  ui->Load();
  instances->AddInstance(ui);

  auto map = GameManager::GetMapController();
  auto player = GameManager::GetPlayerController();
  player->Load();

  sf::Clock clock;

  while (window.isOpen()) {
    GameManager::GetEventsManager()->EventsLoop(&window);

    sf::Time elapsed = clock.restart();

    map->Step(elapsed);
    player->Step(elapsed);
    instances->Step(elapsed);

    window.clear(sf::Color::Black);

    instances->Draw(&window);

    window.display();
  }

  return 0;
}
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2022 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes

// Local includes
// #include "libmesh/point.h"

// ------------------------------------------------------------
// Point class member functions
// unsigned int Point::key() const
// {
//   unsigned int tempx,tempy,tempz;

//   int i,j=2,cnt=0;
//   unsigned int index[3];
//   const Real deg = 1.e12;

//   tempx = static_cast<unsigned int>(((*this)(0)*deg));
//   tempy = static_cast<unsigned int>(((*this)(1)*deg));
//   tempz = static_cast<unsigned int>(((*t!his)(2)*deg));

//   index[0]=0;
//   index[1]=0;
//   index[2]=0;

//   for (i=sizeof(unsigned int)*8-1;i>=0;i--)
//     {
//       index[j] += (tempx >> i) & 01;
//       index[j]  = index[j] << 01;

//       if (( cnt % (sizeof(unsigned int)*8) == 0) && (cnt !=0 ) )
// {
//   cnt = 0;
//   j--;
// }
//       else
// cnt++;

//       index[j] += (tempy >> i) & 01;
//       index[j]  = index[j] << 01;

//       if (( cnt % (sizeof(unsigned int)*8) == 0) && (cnt !=0 ) )
// {
//   cnt = 0;
//   j--;
// }
//       else
// cnt++;

//       index[j] += (tempz >> i) & 01;
//       index[j]  = index[j] << 01;

//       if (( cnt % (sizeof(unsigned int)*8) == 0) && (cnt !=0 ) )
// {
//   cnt = 0;
//   j--;
// }
//       else
// cnt++;
//     }

//   return index[2];
// }
<commit_msg>static_assert(is_trivially_copyable<Point>)<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2022 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// Local includes
#include "libmesh/point.h"

// C++ includes
#include <type_traits> // std::is_trivially_copyable

static_assert(std::is_trivially_copyable<libMesh::TypeVector<libMesh::Point>>::value,
              "Someone made Point non-TriviallyCopyable");

// ------------------------------------------------------------
// Point class member functions
// unsigned int Point::key() const
// {
//   unsigned int tempx,tempy,tempz;

//   int i,j=2,cnt=0;
//   unsigned int index[3];
//   const Real deg = 1.e12;

//   tempx = static_cast<unsigned int>(((*this)(0)*deg));
//   tempy = static_cast<unsigned int>(((*this)(1)*deg));
//   tempz = static_cast<unsigned int>(((*t!his)(2)*deg));

//   index[0]=0;
//   index[1]=0;
//   index[2]=0;

//   for (i=sizeof(unsigned int)*8-1;i>=0;i--)
//     {
//       index[j] += (tempx >> i) & 01;
//       index[j]  = index[j] << 01;

//       if (( cnt % (sizeof(unsigned int)*8) == 0) && (cnt !=0 ) )
// {
//   cnt = 0;
//   j--;
// }
//       else
// cnt++;

//       index[j] += (tempy >> i) & 01;
//       index[j]  = index[j] << 01;

//       if (( cnt % (sizeof(unsigned int)*8) == 0) && (cnt !=0 ) )
// {
//   cnt = 0;
//   j--;
// }
//       else
// cnt++;

//       index[j] += (tempz >> i) & 01;
//       index[j]  = index[j] << 01;

//       if (( cnt % (sizeof(unsigned int)*8) == 0) && (cnt !=0 ) )
// {
//   cnt = 0;
//   j--;
// }
//       else
// cnt++;
//     }

//   return index[2];
// }
<|endoftext|>


<commit_before>//== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*--
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines BasicObjCFoundationChecks, a class that encapsulates
//  a set of simple checks to run on Objective-C code using Apple's Foundation
//  classes.
//
//===----------------------------------------------------------------------===//

#include "BasicObjCFoundationChecks.h"

#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
#include "clang/Analysis/PathSensitive/ValueState.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ASTContext.h"
#include "llvm/Support/Compiler.h"

#include <vector>
#include <sstream>

using namespace clang;

static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
  Expr* Receiver = ME->getReceiver();

  if (!Receiver)
    return NULL;

  QualType X = Receiver->getType();

  if (X->isPointerType()) {
    Type* TP = X.getTypePtr();
    const PointerType* T = TP->getAsPointerType();
    return dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
  }

  // FIXME: Support ObjCQualifiedIdType?
  return NULL;
}

static const char* GetReceiverNameType(ObjCMessageExpr* ME) {
  ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
  return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName()
                      : NULL;
}

namespace {

class VISIBILITY_HIDDEN NilArg : public BugTypeCacheLocation {
public:
  virtual ~NilArg() {}

  virtual const char* getName() const {
    return "nil argument";
  }

  class Report : public BugReport {
    std::string Msg;
    const char* s;
    SourceRange R;
  public:

    Report(NilArg& Desc, ExplodedNode<ValueState>* N,
           ObjCMessageExpr* ME, unsigned Arg)
      : BugReport(Desc, N) {

      Expr* E = ME->getArg(Arg);
      R = E->getSourceRange();

      std::ostringstream os;

      os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
      << ME->getSelector().getName() << "' cannot be nil.";

      Msg = os.str();
      s = Msg.c_str();
    }

    virtual ~Report() {}

    virtual const char* getDescription() const { return s; }

    virtual void getRanges(BugReporter& BR,
                           const SourceRange*& B, const SourceRange*& E) {
      B = &R;
      E = B+1;
    }
  };
};

class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
  NilArg Desc;
  ASTContext &Ctx;
  ValueStateManager* VMgr;

  typedef std::vector<BugReport*> ErrorsTy;
  ErrorsTy Errors;

  RVal GetRVal(ValueState* St, Expr* E) { return VMgr->GetRVal(St, E); }

  bool isNSString(ObjCInterfaceType* T, const char* suffix);
  bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);

  void Warn(NodeTy* N, Expr* E, const std::string& s);
  void WarnNilArg(NodeTy* N, Expr* E);

  bool CheckNilArg(NodeTy* N, unsigned Arg);

public:
  BasicObjCFoundationChecks(ASTContext& ctx, ValueStateManager* vmgr)
    : Ctx(ctx), VMgr(vmgr) {}

  virtual ~BasicObjCFoundationChecks() {
    for (ErrorsTy::iterator I = Errors.begin(), E = Errors.end(); I!=E; ++I)
      delete *I;
  }

  virtual bool Audit(ExplodedNode<ValueState>* N);

  virtual void EmitWarnings(BugReporter& BR);

private:

  void AddError(BugReport* R) {
    Errors.push_back(R);
  }

  void WarnNilArg(NodeTy* N, ObjCMessageExpr* ME, unsigned Arg) {
    AddError(new NilArg::Report(Desc, N, ME, Arg));
  }
};

} // end anonymous namespace

GRSimpleAPICheck*
clang::CreateBasicObjCFoundationChecks(ASTContext& Ctx,
                                       ValueStateManager* VMgr) {

  return new BasicObjCFoundationChecks(Ctx, VMgr);
}

bool BasicObjCFoundationChecks::Audit(ExplodedNode<ValueState>* N) {

  ObjCMessageExpr* ME =
    cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());

  ObjCInterfaceType* ReceiverType = GetReceiverType(ME);

  if (!ReceiverType)
    return NULL;

  const char* name = ReceiverType->getDecl()->getIdentifier()->getName();

  if (!name)
    return false;

  if (name[0] != 'N' || name[1] != 'S')
    return false;

  name += 2;

  // FIXME: Make all of this faster.

  if (isNSString(ReceiverType, name))
    return AuditNSString(N, ME);

  return false;
}

static inline bool isNil(RVal X) {
  return isa<lval::ConcreteInt>(X);
}

//===----------------------------------------------------------------------===//
// Error reporting.
//===----------------------------------------------------------------------===//

void BasicObjCFoundationChecks::EmitWarnings(BugReporter& BR) {

  for (ErrorsTy::iterator I=Errors.begin(), E=Errors.end(); I!=E; ++I)
    BR.EmitWarning(**I);
}

bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) {
  ObjCMessageExpr* ME =
    cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());

  Expr * E = ME->getArg(Arg);

  if (isNil(GetRVal(N->getState(), E))) {
    WarnNilArg(N, ME, Arg);
    return true;
  }

  return false;
}

//===----------------------------------------------------------------------===//
// NSString checking.
//===----------------------------------------------------------------------===//

bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
                                           const char* suffix) {

  return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
}

bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N,
                                              ObjCMessageExpr* ME) {

  Selector S = ME->getSelector();

  if (S.isUnarySelector())
    return false;

  // FIXME: This is going to be really slow doing these checks with
  //  lexical comparisons.

  std::string name = S.getName();
  assert (!name.empty());
  const char* cstr = &name[0];
  unsigned len = name.size();

  switch (len) {
    default:
      break;
    case 8:
      if (!strcmp(cstr, "compare:"))
        return CheckNilArg(N, 0);

      break;

    case 15:
      // FIXME: Checking for initWithFormat: will not work in most cases
      //  yet because [NSString alloc] returns id, not NSString*.  We will
      //  need support for tracking expected-type information in the analyzer
      //  to find these errors.
      if (!strcmp(cstr, "initWithFormat:"))
        return CheckNilArg(N, 0);

      break;

    case 16:
      if (!strcmp(cstr, "compare:options:"))
        return CheckNilArg(N, 0);

      break;

    case 22:
      if (!strcmp(cstr, "compare:options:range:"))
        return CheckNilArg(N, 0);

      break;

    case 23:

      if (!strcmp(cstr, "caseInsensitiveCompare:"))
        return CheckNilArg(N, 0);

      break;

    case 29:
      if (!strcmp(cstr, "compare:options:range:locale:"))
        return CheckNilArg(N, 0);

      break;

    case 37:
    if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:"))
      return CheckNilArg(N, 0);

    break;
  }

  return false;
}
<commit_msg>fix warning with gcc 4.1 (ptr to bool convertion)<commit_after>//== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*--
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines BasicObjCFoundationChecks, a class that encapsulates
//  a set of simple checks to run on Objective-C code using Apple's Foundation
//  classes.
//
//===----------------------------------------------------------------------===//

#include "BasicObjCFoundationChecks.h"

#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
#include "clang/Analysis/PathSensitive/ValueState.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ASTContext.h"
#include "llvm/Support/Compiler.h"

#include <vector>
#include <sstream>

using namespace clang;

static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
  Expr* Receiver = ME->getReceiver();

  if (!Receiver)
    return NULL;

  QualType X = Receiver->getType();

  if (X->isPointerType()) {
    Type* TP = X.getTypePtr();
    const PointerType* T = TP->getAsPointerType();
    return dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
  }

  // FIXME: Support ObjCQualifiedIdType?
  return NULL;
}

static const char* GetReceiverNameType(ObjCMessageExpr* ME) {
  ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
  return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName()
                      : NULL;
}

namespace {

class VISIBILITY_HIDDEN NilArg : public BugTypeCacheLocation {
public:
  virtual ~NilArg() {}

  virtual const char* getName() const {
    return "nil argument";
  }

  class Report : public BugReport {
    std::string Msg;
    const char* s;
    SourceRange R;
  public:

    Report(NilArg& Desc, ExplodedNode<ValueState>* N,
           ObjCMessageExpr* ME, unsigned Arg)
      : BugReport(Desc, N) {

      Expr* E = ME->getArg(Arg);
      R = E->getSourceRange();

      std::ostringstream os;

      os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
      << ME->getSelector().getName() << "' cannot be nil.";

      Msg = os.str();
      s = Msg.c_str();
    }

    virtual ~Report() {}

    virtual const char* getDescription() const { return s; }

    virtual void getRanges(BugReporter& BR,
                           const SourceRange*& B, const SourceRange*& E) {
      B = &R;
      E = B+1;
    }
  };
};

class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
  NilArg Desc;
  ASTContext &Ctx;
  ValueStateManager* VMgr;

  typedef std::vector<BugReport*> ErrorsTy;
  ErrorsTy Errors;

  RVal GetRVal(ValueState* St, Expr* E) { return VMgr->GetRVal(St, E); }

  bool isNSString(ObjCInterfaceType* T, const char* suffix);
  bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);

  void Warn(NodeTy* N, Expr* E, const std::string& s);
  void WarnNilArg(NodeTy* N, Expr* E);

  bool CheckNilArg(NodeTy* N, unsigned Arg);

public:
  BasicObjCFoundationChecks(ASTContext& ctx, ValueStateManager* vmgr)
    : Ctx(ctx), VMgr(vmgr) {}

  virtual ~BasicObjCFoundationChecks() {
    for (ErrorsTy::iterator I = Errors.begin(), E = Errors.end(); I!=E; ++I)
      delete *I;
  }

  virtual bool Audit(ExplodedNode<ValueState>* N);

  virtual void EmitWarnings(BugReporter& BR);

private:

  void AddError(BugReport* R) {
    Errors.push_back(R);
  }

  void WarnNilArg(NodeTy* N, ObjCMessageExpr* ME, unsigned Arg) {
    AddError(new NilArg::Report(Desc, N, ME, Arg));
  }
};

} // end anonymous namespace

GRSimpleAPICheck*
clang::CreateBasicObjCFoundationChecks(ASTContext& Ctx,
                                       ValueStateManager* VMgr) {

  return new BasicObjCFoundationChecks(Ctx, VMgr);
}

bool BasicObjCFoundationChecks::Audit(ExplodedNode<ValueState>* N) {

  ObjCMessageExpr* ME =
    cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());

  ObjCInterfaceType* ReceiverType = GetReceiverType(ME);

  if (!ReceiverType)
    return false;

  const char* name = ReceiverType->getDecl()->getIdentifier()->getName();

  if (!name)
    return false;

  if (name[0] != 'N' || name[1] != 'S')
    return false;

  name += 2;

  // FIXME: Make all of this faster.

  if (isNSString(ReceiverType, name))
    return AuditNSString(N, ME);

  return false;
}

static inline bool isNil(RVal X) {
  return isa<lval::ConcreteInt>(X);
}

//===----------------------------------------------------------------------===//
// Error reporting.
//===----------------------------------------------------------------------===//

void BasicObjCFoundationChecks::EmitWarnings(BugReporter& BR) {

  for (ErrorsTy::iterator I=Errors.begin(), E=Errors.end(); I!=E; ++I)
    BR.EmitWarning(**I);
}

bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) {
  ObjCMessageExpr* ME =
    cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());

  Expr * E = ME->getArg(Arg);

  if (isNil(GetRVal(N->getState(), E))) {
    WarnNilArg(N, ME, Arg);
    return true;
  }

  return false;
}

//===----------------------------------------------------------------------===//
// NSString checking.
//===----------------------------------------------------------------------===//

bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
                                           const char* suffix) {

  return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
}

bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N,
                                              ObjCMessageExpr* ME) {

  Selector S = ME->getSelector();

  if (S.isUnarySelector())
    return false;

  // FIXME: This is going to be really slow doing these checks with
  //  lexical comparisons.

  std::string name = S.getName();
  assert (!name.empty());
  const char* cstr = &name[0];
  unsigned len = name.size();

  switch (len) {
    default:
      break;
    case 8:
      if (!strcmp(cstr, "compare:"))
        return CheckNilArg(N, 0);

      break;

    case 15:
      // FIXME: Checking for initWithFormat: will not work in most cases
      //  yet because [NSString alloc] returns id, not NSString*.  We will
      //  need support for tracking expected-type information in the analyzer
      //  to find these errors.
      if (!strcmp(cstr, "initWithFormat:"))
        return CheckNilArg(N, 0);

      break;

    case 16:
      if (!strcmp(cstr, "compare:options:"))
        return CheckNilArg(N, 0);

      break;

    case 22:
      if (!strcmp(cstr, "compare:options:range:"))
        return CheckNilArg(N, 0);

      break;

    case 23:

      if (!strcmp(cstr, "caseInsensitiveCompare:"))
        return CheckNilArg(N, 0);

      break;

    case 29:
      if (!strcmp(cstr, "compare:options:range:locale:"))
        return CheckNilArg(N, 0);

      break;

    case 37:
    if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:"))
      return CheckNilArg(N, 0);

    break;
  }

  return false;
}
<|endoftext|>