<commit_before>/**************************************************************************
    copyright            : (C) 2007 by Lukáš Lalinský
    email                : lalinsky@gmail.com
 **************************************************************************/

/***************************************************************************
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License version   *
 *   2.1 as published by the Free Software Foundation.                     *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful, but   *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA         *
 *   02110-1301  USA                                                       *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#include <climits>

#include <tdebug.h>
#include <tstring.h>
#include "mp4atom.h"

using namespace TagLib;

const char *MP4::Atom::containers[11] = {
    "moov", "udta", "mdia", "meta", "ilst",
    "stbl", "minf", "moof", "traf", "trak",
    "stsd"
};

MP4::Atom::Atom(File *file)
{
  children.setAutoDelete(true);

  offset = file->tell();
  ByteVector header = file->readBlock(8);
  if(header.size() != 8) {
    // The atom header must be 8 bytes long, otherwise there is either
    // trailing garbage or the file is truncated
    debug("MP4: Couldn't read 8 bytes of data for atom header");
    length = 0;
    file->seek(0, File::End);
    return;
  }

  length = header.toUInt();

  if(length == 1) {
    const long long longLength = file->readBlock(8).toLongLong();
    if(sizeof(long) == sizeof(long long)) {
      length = static_cast<long>(longLength);
    }
    else {
      if(longLength <= LONG_MAX) {
        // The atom has a 64-bit length, but it's actually a 31-bit value
        length = static_cast<long>(longLength);
      }
      else {
        debug("MP4: 64-bit atoms are not supported");
        length = 0;
        file->seek(0, File::End);
        return;
      }
    }
  }
  if(length < 8) {
    debug("MP4: Invalid atom size");
    length = 0;
    file->seek(0, File::End);
    return;
  }

  name = header.mid(4, 4);

  for(int i = 0; i < numContainers; i++) {
    if(name == containers[i]) {
      if(name == "meta") {
        file->seek(4, File::Current);
      }
      else if(name == "stsd") {
        file->seek(8, File::Current);
      }
      while(file->tell() < offset + length) {
        MP4::Atom *child = new MP4::Atom(file);
        children.append(child);
        if(child->length == 0)
          return;
      }
      return;
    }
  }

  file->seek(offset + length);
}

MP4::Atom::~Atom()
{
}

MP4::Atom *
MP4::Atom::find(const char *name1, const char *name2, const char *name3, const char *name4)
{
  if(name1 == 0) {
    return this;
  }
  for(AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
    if((*it)->name == name1) {
      return (*it)->find(name2, name3, name4);
    }
  }
  return 0;
}

MP4::AtomList
MP4::Atom::findall(const char *name, bool recursive)
{
  MP4::AtomList result;
  for(AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
    if((*it)->name == name) {
      result.append(*it);
    }
    if(recursive) {
      result.append((*it)->findall(name, recursive));
    }
  }
  return result;
}

bool
MP4::Atom::path(MP4::AtomList &path, const char *name1, const char *name2, const char *name3)
{
  path.append(this);
  if(name1 == 0) {
    return true;
  }
  for(AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
    if((*it)->name == name1) {
      return (*it)->path(path, name2, name3);
    }
  }
  return false;
}

MP4::Atoms::Atoms(File *file)
{
  atoms.setAutoDelete(true);

  file->seek(0, File::End);
  long end = file->tell();
  file->seek(0);
  while(file->tell() + 8 <= end) {
    MP4::Atom *atom = new MP4::Atom(file);
    atoms.append(atom);
    if (atom->length == 0)
      break;
  }
}

MP4::Atoms::~Atoms()
{
}

MP4::Atom *
MP4::Atoms::find(const char *name1, const char *name2, const char *name3, const char *name4)
{
  for(AtomList::ConstIterator it = atoms.begin(); it != atoms.end(); ++it) {
    if((*it)->name == name1) {
      return (*it)->find(name2, name3, name4);
    }
  }
  return 0;
}

MP4::AtomList
MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const char *name4)
{
  MP4::AtomList path;
  for(AtomList::ConstIterator it = atoms.begin(); it != atoms.end(); ++it) {
    if((*it)->name == name1) {
      if(!(*it)->path(path, name2, name3, name4)) {
        path.clear();
      }
      return path;
    }
  }
  return path;
}
<commit_msg>Remove a useless branch.<commit_after>/**************************************************************************
    copyright            : (C) 2007 by Lukáš Lalinský
    email                : lalinsky@gmail.com
 **************************************************************************/

/***************************************************************************
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License version   *
 *   2.1 as published by the Free Software Foundation.                     *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful, but   *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA         *
 *   02110-1301  USA                                                       *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#include <climits>

#include <tdebug.h>
#include <tstring.h>
#include "mp4atom.h"

using namespace TagLib;

const char *MP4::Atom::containers[11] = {
    "moov", "udta", "mdia", "meta", "ilst",
    "stbl", "minf", "moof", "traf", "trak",
    "stsd"
};

MP4::Atom::Atom(File *file)
{
  children.setAutoDelete(true);

  offset = file->tell();
  ByteVector header = file->readBlock(8);
  if(header.size() != 8) {
    // The atom header must be 8 bytes long, otherwise there is either
    // trailing garbage or the file is truncated
    debug("MP4: Couldn't read 8 bytes of data for atom header");
    length = 0;
    file->seek(0, File::End);
    return;
  }

  length = header.toUInt();

  if(length == 1) {
    const long long longLength = file->readBlock(8).toLongLong();
    if(longLength <= LONG_MAX) {
      // The atom has a 64-bit length, but it's actually a 31-bit value or long is 64-bit.
      length = static_cast<long>(longLength);
    }
    else {
      debug("MP4: 64-bit atoms are not supported");
      length = 0;
      file->seek(0, File::End);
      return;
    }
  }
  if(length < 8) {
    debug("MP4: Invalid atom size");
    length = 0;
    file->seek(0, File::End);
    return;
  }

  name = header.mid(4, 4);

  for(int i = 0; i < numContainers; i++) {
    if(name == containers[i]) {
      if(name == "meta") {
        file->seek(4, File::Current);
      }
      else if(name == "stsd") {
        file->seek(8, File::Current);
      }
      while(file->tell() < offset + length) {
        MP4::Atom *child = new MP4::Atom(file);
        children.append(child);
        if(child->length == 0)
          return;
      }
      return;
    }
  }

  file->seek(offset + length);
}

MP4::Atom::~Atom()
{
}

MP4::Atom *
MP4::Atom::find(const char *name1, const char *name2, const char *name3, const char *name4)
{
  if(name1 == 0) {
    return this;
  }
  for(AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
    if((*it)->name == name1) {
      return (*it)->find(name2, name3, name4);
    }
  }
  return 0;
}

MP4::AtomList
MP4::Atom::findall(const char *name, bool recursive)
{
  MP4::AtomList result;
  for(AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
    if((*it)->name == name) {
      result.append(*it);
    }
    if(recursive) {
      result.append((*it)->findall(name, recursive));
    }
  }
  return result;
}

bool
MP4::Atom::path(MP4::AtomList &path, const char *name1, const char *name2, const char *name3)
{
  path.append(this);
  if(name1 == 0) {
    return true;
  }
  for(AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
    if((*it)->name == name1) {
      return (*it)->path(path, name2, name3);
    }
  }
  return false;
}

MP4::Atoms::Atoms(File *file)
{
  atoms.setAutoDelete(true);

  file->seek(0, File::End);
  long end = file->tell();
  file->seek(0);
  while(file->tell() + 8 <= end) {
    MP4::Atom *atom = new MP4::Atom(file);
    atoms.append(atom);
    if (atom->length == 0)
      break;
  }
}

MP4::Atoms::~Atoms()
{
}

MP4::Atom *
MP4::Atoms::find(const char *name1, const char *name2, const char *name3, const char *name4)
{
  for(AtomList::ConstIterator it = atoms.begin(); it != atoms.end(); ++it) {
    if((*it)->name == name1) {
      return (*it)->find(name2, name3, name4);
    }
  }
  return 0;
}

MP4::AtomList
MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const char *name4)
{
  MP4::AtomList path;
  for(AtomList::ConstIterator it = atoms.begin(); it != atoms.end(); ++it) {
    if((*it)->name == name1) {
      if(!(*it)->path(path, name2, name3, name4)) {
        path.clear();
      }
      return path;
    }
  }
  return path;
}
<|endoftext|>


<commit_before>#pragma once

#include <mapbox/geojsonvt/convert.hpp>
#include <mapbox/geojsonvt/tile.hpp>
#include <mapbox/geojsonvt/types.hpp>
#include <mapbox/geojsonvt/wrap.hpp>

#include <chrono>
#include <cmath>
#include <map>
#include <unordered_map>

namespace mapbox {
namespace geojsonvt {

using geometry = mapbox::geometry::geometry<double>;
using feature = mapbox::geometry::feature<double>;
using feature_collection = mapbox::geometry::feature_collection<double>;
using geometry_collection = mapbox::geometry::geometry_collection<double>;
using geojson = mapbox::util::variant<geometry, feature, feature_collection>;

struct ToFeatureCollection {
    feature_collection operator()(const feature_collection& value) const {
        return value;
    }
    feature_collection operator()(const feature& value) const {
        return { value };
    }
    feature_collection operator()(const geometry& value) const {
        return { { value } };
    }
};

struct TileOptions {
    // simplification tolerance (higher means simpler)
    double tolerance = 3;

    // tile extent
    uint16_t extent = 4096;

    // tile buffer on each side
    uint16_t buffer = 64;
};

struct Options : TileOptions {
    // max zoom to preserve detail on
    uint8_t maxZoom = 18;

    // max zoom in the tile index
    uint8_t indexMaxZoom = 5;

    // max number of points per tile in the tile index
    uint32_t indexMaxPoints = 100000;

    // whether to tile solid square tiles further
    bool solidChildren = false;
};

const Tile empty_tile{};

inline uint64_t toID(uint8_t z, uint32_t x, uint32_t y) {
    return (((1ull << z) * y + x) * 32) + z;
}

const Tile geoJSONToTile(const geojson& geojson_,
                         uint8_t z,
                         uint32_t x,
                         uint32_t y,
                         const TileOptions& options = TileOptions(),
                         bool wrap = false,
                         bool clip = false) {

    const auto features_ = geojson::visit(geojson_, ToFeatureCollection{});
    auto z2 = 1u << z;
    auto tolerance = (options.tolerance / options.extent) / z2;
    auto features = detail::convert(features_, tolerance);
    if (wrap) {
        features = detail::wrap(features, double(options.buffer) / options.extent);
    }
    if (clip) {
        const double p = options.buffer / options.extent;

        const auto left = detail::clip<0>(features, (x - p) / z2, (x + 1 + p) / z2, -1, 2);
        features = detail::clip<1>(left, (y - p) / z2, (y + 1 + p) / z2, -1, 2);
    }
    return detail::InternalTile({ features, z, x, y, options.extent, options.buffer, tolerance })
        .tile;
}

class GeoJSONVT {
public:
    const Options options;

    GeoJSONVT(const mapbox::geometry::feature_collection<double>& features_,
              const Options& options_ = Options())
        : options(options_) {

        const uint32_t z2 = 1u << options.maxZoom;

        auto converted = detail::convert(features_, (options.tolerance / options.extent) / z2);
        auto features = detail::wrap(converted, double(options.buffer) / options.extent);

        splitTile(features, 0, 0, 0);
    }

    GeoJSONVT(const geojson& geojson_, const Options& options_ = Options())
        : GeoJSONVT(geojson::visit(geojson_, ToFeatureCollection{}), options_) {
    }

    std::map<uint8_t, uint32_t> stats;
    uint32_t total = 0;

    const Tile& getTile(const uint8_t z, const uint32_t x_, const uint32_t y) {

        if (z > options.maxZoom)
            throw std::runtime_error("Requested zoom higher than maxZoom: " + std::to_string(z));

        const uint32_t z2 = 1u << z;
        const uint32_t x = ((x_ % z2) + z2) % z2; // wrap tile x coordinate
        const uint64_t id = toID(z, x, y);

        auto it = tiles.find(id);
        if (it != tiles.end())
            return it->second.tile;

        it = findParent(z, x, y);

        if (it == tiles.end())
            throw std::runtime_error("Parent tile not found");

        // if we found a parent tile containing the original geometry, we can drill down from it
        const auto& parent = it->second;

        // parent tile is a solid clipped square, return it instead since it's identical
        if (parent.is_solid)
            return parent.tile;

        // drill down parent tile up to the requested one
        splitTile(parent.source_features, parent.z, parent.x, parent.y, z, x, y);

        it = tiles.find(id);
        if (it != tiles.end())
            return it->second.tile;

        it = findParent(z, x, y);
        if (it == tiles.end())
            throw std::runtime_error("Parent tile not found");

        // drilling stopped because parent was a solid square; return it instead
        if (it->second.is_solid)
            return it->second.tile;

        // otherwise it was an empty tile
        return empty_tile;
    }

    const std::unordered_map<uint64_t, detail::InternalTile>& getInternalTiles() const {
        return tiles;
    }

private:
    std::unordered_map<uint64_t, detail::InternalTile> tiles;

    std::unordered_map<uint64_t, detail::InternalTile>::iterator
    findParent(const uint8_t z, const uint32_t x, const uint32_t y) {
        uint8_t z0 = z;
        uint32_t x0 = x;
        uint32_t y0 = y;

        const auto end = tiles.end();
        auto parent = end;

        while ((parent == end) && (z0 != 0)) {
            z0--;
            x0 = x0 / 2;
            y0 = y0 / 2;
            parent = tiles.find(toID(z0, x0, y0));
        }

        return parent;
    }

    void splitTile(const detail::vt_features& features,
                   const uint8_t z,
                   const uint32_t x,
                   const uint32_t y,
                   const uint8_t cz = 0,
                   const uint32_t cx = 0,
                   const uint32_t cy = 0) {

        const double z2 = 1u << z;
        const uint64_t id = toID(z, x, y);

        auto it = tiles.find(id);

        if (it == tiles.end()) {
            const double tolerance =
                (z == options.maxZoom ? 0 : options.tolerance / (z2 * options.extent));

            it = tiles
                     .emplace(id, detail::InternalTile{ features, z, x, y, options.extent,
                                                        options.buffer, tolerance })
                     .first;
            stats[z] = (stats.count(z) ? stats[z] + 1 : 1);
            total++;
            // printf("tile z%i-%i-%i\n", z, x, y);
        }

        auto& tile = it->second;

        if (features.empty())
            return;

        // stop tiling if the tile is solid clipped square
        if (!options.solidChildren && tile.is_solid)
            return;

        // if it's the first-pass tiling
        if (cz == 0u) {
            // stop tiling if we reached max zoom, or if the tile is too simple
            if (z == options.indexMaxZoom || tile.tile.num_points <= options.indexMaxPoints) {
                tile.source_features = features;
                return;
            }

        } else { // drilldown to a specific tile;
            // stop tiling if we reached base zoom
            if (z == options.maxZoom)
                return;

            // stop tiling if it's our target tile zoom
            if (z == cz) {
                tile.source_features = features;
                return;
            }

            // stop tiling if it's not an ancestor of the target tile
            const double m = 1u << (cz - z);
            if (x != static_cast<uint32_t>(std::floor(cx / m)) ||
                y != static_cast<uint32_t>(std::floor(cy / m))) {
                tile.source_features = features;
                return;
            }
        }

        const double p = 0.5 * options.buffer / options.extent;
        const auto& min = tile.bbox.min;
        const auto& max = tile.bbox.max;

        const auto left = detail::clip<0>(features, (x - p) / z2, (x + 0.5 + p) / z2, min.x, max.x);

        splitTile(detail::clip<1>(left, (y - p) / z2, (y + 0.5 + p) / z2, min.y, max.y), z + 1,
                  x * 2, y * 2, cz, cx, cy);
        splitTile(detail::clip<1>(left, (y + 0.5 - p) / z2, (y + 1 + p) / z2, min.y, max.y), z + 1,
                  x * 2, y * 2 + 1, cz, cx, cy);

        const auto right =
            detail::clip<0>(features, (x + 0.5 - p) / z2, (x + 1 + p) / z2, min.x, max.x);

        splitTile(detail::clip<1>(right, (y - p) / z2, (y + 0.5 + p) / z2, min.y, max.y), z + 1,
                  x * 2 + 1, y * 2, cz, cx, cy);
        splitTile(detail::clip<1>(right, (y + 0.5 - p) / z2, (y + 1 + p) / z2, min.y, max.y), z + 1,
                  x * 2 + 1, y * 2 + 1, cz, cx, cy);

        // if we sliced further down, no need to keep source geometry
        tile.source_features = {};
    }
};

} // namespace geojsonvt
} // namespace mapbox
<commit_msg>inline geoJSONToTile()<commit_after>#pragma once

#include <mapbox/geojsonvt/convert.hpp>
#include <mapbox/geojsonvt/tile.hpp>
#include <mapbox/geojsonvt/types.hpp>
#include <mapbox/geojsonvt/wrap.hpp>

#include <chrono>
#include <cmath>
#include <map>
#include <unordered_map>

namespace mapbox {
namespace geojsonvt {

using geometry = mapbox::geometry::geometry<double>;
using feature = mapbox::geometry::feature<double>;
using feature_collection = mapbox::geometry::feature_collection<double>;
using geometry_collection = mapbox::geometry::geometry_collection<double>;
using geojson = mapbox::util::variant<geometry, feature, feature_collection>;

struct ToFeatureCollection {
    feature_collection operator()(const feature_collection& value) const {
        return value;
    }
    feature_collection operator()(const feature& value) const {
        return { value };
    }
    feature_collection operator()(const geometry& value) const {
        return { { value } };
    }
};

struct TileOptions {
    // simplification tolerance (higher means simpler)
    double tolerance = 3;

    // tile extent
    uint16_t extent = 4096;

    // tile buffer on each side
    uint16_t buffer = 64;
};

struct Options : TileOptions {
    // max zoom to preserve detail on
    uint8_t maxZoom = 18;

    // max zoom in the tile index
    uint8_t indexMaxZoom = 5;

    // max number of points per tile in the tile index
    uint32_t indexMaxPoints = 100000;

    // whether to tile solid square tiles further
    bool solidChildren = false;
};

const Tile empty_tile{};

inline uint64_t toID(uint8_t z, uint32_t x, uint32_t y) {
    return (((1ull << z) * y + x) * 32) + z;
}

inline const Tile geoJSONToTile(const geojson& geojson_,
                         uint8_t z,
                         uint32_t x,
                         uint32_t y,
                         const TileOptions& options = TileOptions(),
                         bool wrap = false,
                         bool clip = false) {

    const auto features_ = geojson::visit(geojson_, ToFeatureCollection{});
    auto z2 = 1u << z;
    auto tolerance = (options.tolerance / options.extent) / z2;
    auto features = detail::convert(features_, tolerance);
    if (wrap) {
        features = detail::wrap(features, double(options.buffer) / options.extent);
    }
    if (clip) {
        const double p = options.buffer / options.extent;

        const auto left = detail::clip<0>(features, (x - p) / z2, (x + 1 + p) / z2, -1, 2);
        features = detail::clip<1>(left, (y - p) / z2, (y + 1 + p) / z2, -1, 2);
    }
    return detail::InternalTile({ features, z, x, y, options.extent, options.buffer, tolerance })
        .tile;
}

class GeoJSONVT {
public:
    const Options options;

    GeoJSONVT(const mapbox::geometry::feature_collection<double>& features_,
              const Options& options_ = Options())
        : options(options_) {

        const uint32_t z2 = 1u << options.maxZoom;

        auto converted = detail::convert(features_, (options.tolerance / options.extent) / z2);
        auto features = detail::wrap(converted, double(options.buffer) / options.extent);

        splitTile(features, 0, 0, 0);
    }

    GeoJSONVT(const geojson& geojson_, const Options& options_ = Options())
        : GeoJSONVT(geojson::visit(geojson_, ToFeatureCollection{}), options_) {
    }

    std::map<uint8_t, uint32_t> stats;
    uint32_t total = 0;

    const Tile& getTile(const uint8_t z, const uint32_t x_, const uint32_t y) {

        if (z > options.maxZoom)
            throw std::runtime_error("Requested zoom higher than maxZoom: " + std::to_string(z));

        const uint32_t z2 = 1u << z;
        const uint32_t x = ((x_ % z2) + z2) % z2; // wrap tile x coordinate
        const uint64_t id = toID(z, x, y);

        auto it = tiles.find(id);
        if (it != tiles.end())
            return it->second.tile;

        it = findParent(z, x, y);

        if (it == tiles.end())
            throw std::runtime_error("Parent tile not found");

        // if we found a parent tile containing the original geometry, we can drill down from it
        const auto& parent = it->second;

        // parent tile is a solid clipped square, return it instead since it's identical
        if (parent.is_solid)
            return parent.tile;

        // drill down parent tile up to the requested one
        splitTile(parent.source_features, parent.z, parent.x, parent.y, z, x, y);

        it = tiles.find(id);
        if (it != tiles.end())
            return it->second.tile;

        it = findParent(z, x, y);
        if (it == tiles.end())
            throw std::runtime_error("Parent tile not found");

        // drilling stopped because parent was a solid square; return it instead
        if (it->second.is_solid)
            return it->second.tile;

        // otherwise it was an empty tile
        return empty_tile;
    }

    const std::unordered_map<uint64_t, detail::InternalTile>& getInternalTiles() const {
        return tiles;
    }

private:
    std::unordered_map<uint64_t, detail::InternalTile> tiles;

    std::unordered_map<uint64_t, detail::InternalTile>::iterator
    findParent(const uint8_t z, const uint32_t x, const uint32_t y) {
        uint8_t z0 = z;
        uint32_t x0 = x;
        uint32_t y0 = y;

        const auto end = tiles.end();
        auto parent = end;

        while ((parent == end) && (z0 != 0)) {
            z0--;
            x0 = x0 / 2;
            y0 = y0 / 2;
            parent = tiles.find(toID(z0, x0, y0));
        }

        return parent;
    }

    void splitTile(const detail::vt_features& features,
                   const uint8_t z,
                   const uint32_t x,
                   const uint32_t y,
                   const uint8_t cz = 0,
                   const uint32_t cx = 0,
                   const uint32_t cy = 0) {

        const double z2 = 1u << z;
        const uint64_t id = toID(z, x, y);

        auto it = tiles.find(id);

        if (it == tiles.end()) {
            const double tolerance =
                (z == options.maxZoom ? 0 : options.tolerance / (z2 * options.extent));

            it = tiles
                     .emplace(id, detail::InternalTile{ features, z, x, y, options.extent,
                                                        options.buffer, tolerance })
                     .first;
            stats[z] = (stats.count(z) ? stats[z] + 1 : 1);
            total++;
            // printf("tile z%i-%i-%i\n", z, x, y);
        }

        auto& tile = it->second;

        if (features.empty())
            return;

        // stop tiling if the tile is solid clipped square
        if (!options.solidChildren && tile.is_solid)
            return;

        // if it's the first-pass tiling
        if (cz == 0u) {
            // stop tiling if we reached max zoom, or if the tile is too simple
            if (z == options.indexMaxZoom || tile.tile.num_points <= options.indexMaxPoints) {
                tile.source_features = features;
                return;
            }

        } else { // drilldown to a specific tile;
            // stop tiling if we reached base zoom
            if (z == options.maxZoom)
                return;

            // stop tiling if it's our target tile zoom
            if (z == cz) {
                tile.source_features = features;
                return;
            }

            // stop tiling if it's not an ancestor of the target tile
            const double m = 1u << (cz - z);
            if (x != static_cast<uint32_t>(std::floor(cx / m)) ||
                y != static_cast<uint32_t>(std::floor(cy / m))) {
                tile.source_features = features;
                return;
            }
        }

        const double p = 0.5 * options.buffer / options.extent;
        const auto& min = tile.bbox.min;
        const auto& max = tile.bbox.max;

        const auto left = detail::clip<0>(features, (x - p) / z2, (x + 0.5 + p) / z2, min.x, max.x);

        splitTile(detail::clip<1>(left, (y - p) / z2, (y + 0.5 + p) / z2, min.y, max.y), z + 1,
                  x * 2, y * 2, cz, cx, cy);
        splitTile(detail::clip<1>(left, (y + 0.5 - p) / z2, (y + 1 + p) / z2, min.y, max.y), z + 1,
                  x * 2, y * 2 + 1, cz, cx, cy);

        const auto right =
            detail::clip<0>(features, (x + 0.5 - p) / z2, (x + 1 + p) / z2, min.x, max.x);

        splitTile(detail::clip<1>(right, (y - p) / z2, (y + 0.5 + p) / z2, min.y, max.y), z + 1,
                  x * 2 + 1, y * 2, cz, cx, cy);
        splitTile(detail::clip<1>(right, (y + 0.5 - p) / z2, (y + 1 + p) / z2, min.y, max.y), z + 1,
                  x * 2 + 1, y * 2 + 1, cz, cx, cy);

        // if we sliced further down, no need to keep source geometry
        tile.source_features = {};
    }
};

} // namespace geojsonvt
} // namespace mapbox
<|endoftext|>


<commit_before>//============================================================================
// MCKL/include/mckl/core/memory.hpp
//----------------------------------------------------------------------------
// MCKL: Monte Carlo Kernel Library
//----------------------------------------------------------------------------
// Copyright (c) 2013-2017, Yan Zhou
// 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.
//
// 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 HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//============================================================================

#ifndef MCKL_CORE_MEMORY_HPP
#define MCKL_CORE_MEMORY_HPP

#include <mckl/internal/config.h>

#include <cstdlib>
#include <cstring>
#include <memory>
#include <new>
#include <vector>

#if MCKL_HAS_POSIX
#include <stdlib.h>
#endif

#if MCKL_HAS_JEMALLOC
#include <jemalloc/jemalloc.h>
#endif

#if MCKL_HAS_TBB
#include <tbb/scalable_allocator.h>
#endif

/// \brief The default alignment for scalar type
/// \ingroup Config
#ifndef MCKL_ALIGNMENT
#define MCKL_ALIGNMENT 32
#endif

/// \brief The minimum alignment for any type
/// \ingroup Config
#ifndef MCKL_MINIMUM_ALIGNMENT
#define MCKL_MINIMUM_ALIGNMENT 16
#endif

#if MCKL_ALIGNMENT < MCKL_MINIMUM_ALIGNMENT
#undef MCKL_ALIGNEMNT
#define MCKL_ALIGNMENT MCKL_MINIMUM_ALIGNMENT
#endif

/// \brief Default allocation type
/// \ingroup Config
#ifndef MCKL_MEMORY_TYPE
#if MCKL_USE_JEMALLOC
#define MCKL_MEMORY_TYPE ::mckl::MemoryJEM
#elif MCKL_USE_TBB_MALLOC
#define MCKL_MEMORY_TYPE ::mckl::MemoryTBB
#elif MCKL_HAS_POSIX
#define MCKL_MEMORY_TYPE ::mckl::MemorySYS
#else
#define MCKL_MEMORY_TYPE ::mckl::MemorySTD
#endif
#endif

namespace mckl {

namespace internal {

template <std::size_t Alignment, typename UIntType>
inline constexpr std::size_t alignment_round0(UIntType n)
{
    static_assert(Alignment != 0 && (Alignment & (Alignment - 1)) == 0,
        "**alignment_round0** used with Alignment other than a power of two "
        "positive integer");

    static_assert(Alignment >= sizeof(void *),
        "**alignment_round0** used with Alignment less than sizeof(void *)");

    static_assert(std::is_unsigned<UIntType>::value,
        "alignment_round0** used with UIntType other than unsigned integer "
        "types");

    constexpr std::size_t addn = Alignment - 1;
    constexpr std::size_t mask = ~addn;

    return (n + addn) & mask;
}

template <std::size_t Alignment, typename UIntType>
inline constexpr std::size_t alignment_round(UIntType n)
{
    return n == 0 ? Alignment : alignment_round0<Alignment>(n);
}

} // namespace mckl::internal

/// \brief Alignment of types
/// \ingroup Core
///
/// \details
/// * For scalar types, defined to the maximum of `MCKL_ALIGNMENT` and
/// `alignof(T)`
/// * For all other types, define to the maximum of `MCKL_MINIMUM_ALIGNMENT`
/// and `alignof(T)` as `value`.
template <typename T>
constexpr std::size_t AlignOf = std::integral_constant<std::size_t,
    std::is_scalar<T>::value ?
        (alignof(T) > MCKL_ALIGNMENT ? alignof(T) : MCKL_ALIGNMENT) :
        (alignof(T) > MCKL_MINIMUM_ALIGNMENT ? alignof(T) :
                                               MCKL_MINIMUM_ALIGNMENT)>::value;

/// \brief Memory allocation using the standard library
/// \ingroup Core
///
/// \tparam Alignment The alignment of the allocated memory
template <std::size_t Alignment>
class MemorySTD
{
    static_assert(Alignment != 0 && (Alignment & (Alignment - 1)) == 0,
        "**MemorySTD** used with Alignment other than a power of two positive "
        "integer");

    static_assert(Alignment >= sizeof(void *),
        "**MemorySTD** used with Alignment less than sizeof(void *)");

  public:
    static constexpr std::size_t alignment() { return Alignment; }

    static void *allocate(std::size_t n, const void * = nullptr) noexcept
    {
        const std::size_t m = internal::alignment_round0<Alignment>(
            n + sizeof(std::uintptr_t) + Alignment);
        if (m < n) {
            return nullptr;
        }

        std::uintptr_t *const address =
            static_cast<std::uintptr_t *>(std::malloc(m));
        if (address == nullptr) {
            return nullptr;
        }

        std::uintptr_t *const ptr = reinterpret_cast<std::uintptr_t *>(
            internal::alignment_round0<Alignment>(
                reinterpret_cast<std::uintptr_t>(address + 1)));
        ptr[-1] = reinterpret_cast<std::uintptr_t>(address);

        return static_cast<void *>(ptr);
    }

    static void deallocate(void *ptr, std::size_t = 0) noexcept
    {
        if (ptr != nullptr) {
            const std::uintptr_t address =
                static_cast<std::uintptr_t *>(ptr)[-1];
            std::free(reinterpret_cast<void *>(address));
        }
    }
}; // class MemorySTD

#if MCKL_HAS_POSIX

/// \brief Memory allocation using native system functions
/// \ingroup Core
///
/// \tparam Alignment The alignment of the allocated memory
template <std::size_t Alignment>
class MemorySYS
{
    static_assert(Alignment != 0 && (Alignment & (Alignment - 1)) == 0,
        "**MemorySYS** used with Alignment other than a power of two positive "
        "integer");

    static_assert(Alignment >= sizeof(void *),
        "**MemorySYS** used with Alignment less than sizeof(void *)");

  public:
    static constexpr std::size_t alignment() { return Alignment; }

    static void *allocate(std::size_t n, const void * = nullptr) noexcept
    {
        const std::size_t m = internal::alignment_round<Alignment>(n);

        if (m < n) {
            return nullptr;
        }

        void *ptr = nullptr;
        if (::posix_memalign(&ptr, Alignment, m) != 0) {
            ptr = nullptr;
        }

        return ptr;
    }

    static void deallocate(void *ptr, std::size_t = 0) noexcept
    {
        if (ptr != nullptr) {
            ::free(ptr);
        }
    }
}; // class MemorySYS

#endif // MCKL_HAS_POSIX

#if MCKL_HAS_JEMALLOC

/// \brief Memory allocation using jemalloc
/// \ingroup Core
///
/// \tparam Alignment The alignment of the allocated memory
template <std::size_t Alignment>
class MemoryJEM
{
    static_assert(Alignment != 0 && (Alignment & (Alignment - 1)) == 0,
        "**MemoryJEM** used with Alignment other than a power of two positive "
        "integer");

    static_assert(Alignment >= sizeof(void *),
        "**MemoryJEM** used with Alignment less than sizeof(void *)");

  public:
    static constexpr std::size_t alignment() { return Alignment; }

    static void *allocate(std::size_t n, const void * = nullptr) noexcept
    {
        const std::size_t m = internal::alignment_round<Alignment>(n);

        return m < n ? nullptr : ::aligned_alloc(Alignment, m);
    }

    static void deallocate(void *ptr, std::size_t = 0) noexcept
    {
        if (ptr != nullptr) {
            ::free(ptr);
        }
    }
}; // class MemoryJEM

#endif // MCKL_HAS_JEMALLOC

#if MCKL_HAS_TBB

/// \brief Memory allocation using Intel TBB
/// \ingroup Core
///
/// \tparam Alignment The alignment of the allocated memory
template <std::size_t Alignment>
class MemoryTBB
{
    static_assert(Alignment != 0 && (Alignment & (Alignment - 1)) == 0,
        "**MemoryTBB** used with Alignment other than a power of two positive "
        "integer");

    static_assert(Alignment >= sizeof(void *),
        "**MemoryTBB** used with Alignment less than sizeof(void *)");

  public:
    static constexpr std::size_t alignment() { return Alignment; }

    static void *allocate(std::size_t n, const void * = nullptr) noexcept
    {
        const std::size_t m = internal::alignment_round<Alignment>(n);

        return m < n ? nullptr : scalable_aligned_malloc(m, Alignment);
    }

    static void deallocate(void *ptr, std::size_t = 0) noexcept
    {
        if (ptr != nullptr) {
            scalable_aligned_free(ptr);
        }
    }
}; // class MemoryTBB

#endif // MCKL_HAS_TBB

/// \brief Default memory allocation policy
/// \ingroup Core
///
/// \tparam Alignment The alignment of the allocated memory
///
/// \details
/// This template is aliased to the configuration macro  `MCKL_MEMORY_TYPE`.
/// The default precedence is as the following,
/// * MemoryJEM
/// * MemoryTBB
/// * MemorySYS
/// * MemorySTD
template <std::size_t Alignment>
using Memory = MCKL_MEMORY_TYPE<Alignment>;

/// \brief Standard library compatible allocator with policies
/// \ingroup Core
///
/// \tparam T The value type
/// \tparam Mem The memory allocation policy
///
/// \sa Allocator<void, Mem>
/// \sa Allocator<const void, Mem>
/// \sa [std::allocator](http://en.cppreference.com/w/cpp/memory/allocator)
template <typename T, typename Mem = Memory<AlignOf<T>>>
class Allocator : public std::allocator<T>
{
  public:
    template <typename U>
    class rebind
    {
      public:
        using other = Allocator<U, Mem>;
    };

    Allocator() = default;

    template <typename U>
    Allocator(const Allocator<U, Mem> &other) noexcept
        : std::allocator<T>(static_cast<std::allocator<U>>(other))
    {
    }

    T *allocate(std::size_t n, const void *hint = nullptr)
    {
        const std::size_t m = n * sizeof(T);
        if (m < n) {
            throw std::bad_alloc();
        }

        T *ptr = static_cast<T *>(Mem::allocate(m, hint));
        if (ptr == nullptr) {
            throw std::bad_alloc();
        }

        return ptr;
    }

    void deallocate(T *ptr, std::size_t size = 0) noexcept(
        noexcept(Mem::deallocate(ptr, size)))
    {
        Mem::deallocate(ptr, size);
    }

    template <typename U>
    void construct(U *p)
    {
        construct_dispatch(p, std::is_scalar<U>());
    }

  private:
    template <typename U>
    void construct_dispatch(U *, std::true_type)
    {
    }

    template <typename U>
    void construct_dispatch(U *p, std::false_type)
    {
        ::new (static_cast<void *>(p)) U();
    }
}; // class Allocator

template <typename Mem>
class Allocator<void, Mem>
{
  public:
    using value_type = void;
    using pointer = void *;
    using const_pointer = const void *;
    using propagate_on_container_move_assignment = std::true_type;
    using is_always_equal = std::true_type;

    template <typename U>
    class rebind
    {
      public:
        using other = Allocator<U, Mem>;
    };
}; // class Allocator

template <typename Mem>
class Allocator<const void, Mem>
{
  public:
    using value_type = const void;
    using pointer = const void *;
    using const_pointer = const void *;
    using propagate_on_container_move_assignment = std::true_type;
    using is_always_equal = std::true_type;

    template <typename U>
    class rebind
    {
      public:
        using other = Allocator<U, Mem>;
    };
}; // class Allocator

/// \relates Allocator
template <typename T1, typename T2, typename Mem1, typename Mem2>
inline constexpr bool operator==(
    const Allocator<T1, Mem1> &, const Allocator<T2, Mem2> &)
{
    return std::is_same<Mem1, Mem2>::value;
}

/// \relates Allocator
template <typename T1, typename T2, typename Mem1, typename Mem2>
inline constexpr bool operator!=(
    const Allocator<T1, Mem1> &, const Allocator<T2, Mem2> &)
{
    return !std::is_same<Mem1, Mem2>::value;
}

/// \brief std::vector with Allocator as the default allocator
/// \ingroup Core
template <typename T, typename Alloc = Allocator<T>>
using Vector = std::vector<T, Alloc>;

} // namespace mckl

#endif // MCKL_CORE_MEMORY_HPP
<commit_msg>use tbb by default<commit_after>//============================================================================
// MCKL/include/mckl/core/memory.hpp
//----------------------------------------------------------------------------
// MCKL: Monte Carlo Kernel Library
//----------------------------------------------------------------------------
// Copyright (c) 2013-2017, Yan Zhou
// 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.
//
// 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 HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//============================================================================

#ifndef MCKL_CORE_MEMORY_HPP
#define MCKL_CORE_MEMORY_HPP

#include <mckl/internal/config.h>

#include <cstdlib>
#include <cstring>
#include <memory>
#include <new>
#include <vector>

#if MCKL_HAS_POSIX
#include <stdlib.h>
#endif

#if MCKL_HAS_JEMALLOC
#include <jemalloc/jemalloc.h>
#endif

#if MCKL_HAS_TBB
#include <tbb/scalable_allocator.h>
#endif

/// \brief The default alignment for scalar type
/// \ingroup Config
#ifndef MCKL_ALIGNMENT
#define MCKL_ALIGNMENT 32
#endif

/// \brief The minimum alignment for any type
/// \ingroup Config
#ifndef MCKL_MINIMUM_ALIGNMENT
#define MCKL_MINIMUM_ALIGNMENT 16
#endif

#if MCKL_ALIGNMENT < MCKL_MINIMUM_ALIGNMENT
#undef MCKL_ALIGNEMNT
#define MCKL_ALIGNMENT MCKL_MINIMUM_ALIGNMENT
#endif

/// \brief Default allocation type
/// \ingroup Config
#ifndef MCKL_MEMORY_TYPE
#if MCKL_USE_TBB_MALLOC
#define MCKL_MEMORY_TYPE ::mckl::MemoryTBB
#elif MCKL_USE_JEMALLOC
#define MCKL_MEMORY_TYPE ::mckl::MemoryJEM
#elif MCKL_HAS_POSIX
#define MCKL_MEMORY_TYPE ::mckl::MemorySYS
#else
#define MCKL_MEMORY_TYPE ::mckl::MemorySTD
#endif
#endif

namespace mckl {

namespace internal {

template <std::size_t Alignment, typename UIntType>
inline constexpr std::size_t alignment_round0(UIntType n)
{
    static_assert(Alignment != 0 && (Alignment & (Alignment - 1)) == 0,
        "**alignment_round0** used with Alignment other than a power of two "
        "positive integer");

    static_assert(Alignment >= sizeof(void *),
        "**alignment_round0** used with Alignment less than sizeof(void *)");

    static_assert(std::is_unsigned<UIntType>::value,
        "alignment_round0** used with UIntType other than unsigned integer "
        "types");

    constexpr std::size_t addn = Alignment - 1;
    constexpr std::size_t mask = ~addn;

    return (n + addn) & mask;
}

template <std::size_t Alignment, typename UIntType>
inline constexpr std::size_t alignment_round(UIntType n)
{
    return n == 0 ? Alignment : alignment_round0<Alignment>(n);
}

} // namespace mckl::internal

/// \brief Alignment of types
/// \ingroup Core
///
/// \details
/// * For scalar types, defined to the maximum of `MCKL_ALIGNMENT` and
/// `alignof(T)`
/// * For all other types, define to the maximum of `MCKL_MINIMUM_ALIGNMENT`
/// and `alignof(T)` as `value`.
template <typename T>
constexpr std::size_t AlignOf = std::integral_constant<std::size_t,
    std::is_scalar<T>::value ?
        (alignof(T) > MCKL_ALIGNMENT ? alignof(T) : MCKL_ALIGNMENT) :
        (alignof(T) > MCKL_MINIMUM_ALIGNMENT ? alignof(T) :
                                               MCKL_MINIMUM_ALIGNMENT)>::value;

/// \brief Memory allocation using the standard library
/// \ingroup Core
///
/// \tparam Alignment The alignment of the allocated memory
template <std::size_t Alignment>
class MemorySTD
{
    static_assert(Alignment != 0 && (Alignment & (Alignment - 1)) == 0,
        "**MemorySTD** used with Alignment other than a power of two positive "
        "integer");

    static_assert(Alignment >= sizeof(void *),
        "**MemorySTD** used with Alignment less than sizeof(void *)");

  public:
    static constexpr std::size_t alignment() { return Alignment; }

    static void *allocate(std::size_t n, const void * = nullptr) noexcept
    {
        const std::size_t m = internal::alignment_round0<Alignment>(
            n + sizeof(std::uintptr_t) + Alignment);
        if (m < n) {
            return nullptr;
        }

        std::uintptr_t *const address =
            static_cast<std::uintptr_t *>(std::malloc(m));
        if (address == nullptr) {
            return nullptr;
        }

        std::uintptr_t *const ptr = reinterpret_cast<std::uintptr_t *>(
            internal::alignment_round0<Alignment>(
                reinterpret_cast<std::uintptr_t>(address + 1)));
        ptr[-1] = reinterpret_cast<std::uintptr_t>(address);

        return static_cast<void *>(ptr);
    }

    static void deallocate(void *ptr, std::size_t = 0) noexcept
    {
        if (ptr != nullptr) {
            const std::uintptr_t address =
                static_cast<std::uintptr_t *>(ptr)[-1];
            std::free(reinterpret_cast<void *>(address));
        }
    }
}; // class MemorySTD

#if MCKL_HAS_POSIX

/// \brief Memory allocation using native system functions
/// \ingroup Core
///
/// \tparam Alignment The alignment of the allocated memory
template <std::size_t Alignment>
class MemorySYS
{
    static_assert(Alignment != 0 && (Alignment & (Alignment - 1)) == 0,
        "**MemorySYS** used with Alignment other than a power of two positive "
        "integer");

    static_assert(Alignment >= sizeof(void *),
        "**MemorySYS** used with Alignment less than sizeof(void *)");

  public:
    static constexpr std::size_t alignment() { return Alignment; }

    static void *allocate(std::size_t n, const void * = nullptr) noexcept
    {
        const std::size_t m = internal::alignment_round<Alignment>(n);

        if (m < n) {
            return nullptr;
        }

        void *ptr = nullptr;
        if (::posix_memalign(&ptr, Alignment, m) != 0) {
            ptr = nullptr;
        }

        return ptr;
    }

    static void deallocate(void *ptr, std::size_t = 0) noexcept
    {
        if (ptr != nullptr) {
            ::free(ptr);
        }
    }
}; // class MemorySYS

#endif // MCKL_HAS_POSIX

#if MCKL_HAS_JEMALLOC

/// \brief Memory allocation using jemalloc
/// \ingroup Core
///
/// \tparam Alignment The alignment of the allocated memory
template <std::size_t Alignment>
class MemoryJEM
{
    static_assert(Alignment != 0 && (Alignment & (Alignment - 1)) == 0,
        "**MemoryJEM** used with Alignment other than a power of two positive "
        "integer");

    static_assert(Alignment >= sizeof(void *),
        "**MemoryJEM** used with Alignment less than sizeof(void *)");

  public:
    static constexpr std::size_t alignment() { return Alignment; }

    static void *allocate(std::size_t n, const void * = nullptr) noexcept
    {
        const std::size_t m = internal::alignment_round<Alignment>(n);

        return m < n ? nullptr : ::aligned_alloc(Alignment, m);
    }

    static void deallocate(void *ptr, std::size_t = 0) noexcept
    {
        if (ptr != nullptr) {
            ::free(ptr);
        }
    }
}; // class MemoryJEM

#endif // MCKL_HAS_JEMALLOC

#if MCKL_HAS_TBB

/// \brief Memory allocation using Intel TBB
/// \ingroup Core
///
/// \tparam Alignment The alignment of the allocated memory
template <std::size_t Alignment>
class MemoryTBB
{
    static_assert(Alignment != 0 && (Alignment & (Alignment - 1)) == 0,
        "**MemoryTBB** used with Alignment other than a power of two positive "
        "integer");

    static_assert(Alignment >= sizeof(void *),
        "**MemoryTBB** used with Alignment less than sizeof(void *)");

  public:
    static constexpr std::size_t alignment() { return Alignment; }

    static void *allocate(std::size_t n, const void * = nullptr) noexcept
    {
        const std::size_t m = internal::alignment_round<Alignment>(n);

        return m < n ? nullptr : scalable_aligned_malloc(m, Alignment);
    }

    static void deallocate(void *ptr, std::size_t = 0) noexcept
    {
        if (ptr != nullptr) {
            scalable_aligned_free(ptr);
        }
    }
}; // class MemoryTBB

#endif // MCKL_HAS_TBB

/// \brief Default memory allocation policy
/// \ingroup Core
///
/// \tparam Alignment The alignment of the allocated memory
///
/// \details
/// This template is aliased to the configuration macro  `MCKL_MEMORY_TYPE`.
/// The default precedence is as the following,
/// * MemoryJEM
/// * MemoryTBB
/// * MemorySYS
/// * MemorySTD
template <std::size_t Alignment>
using Memory = MCKL_MEMORY_TYPE<Alignment>;

/// \brief Standard library compatible allocator with policies
/// \ingroup Core
///
/// \tparam T The value type
/// \tparam Mem The memory allocation policy
///
/// \sa Allocator<void, Mem>
/// \sa Allocator<const void, Mem>
/// \sa [std::allocator](http://en.cppreference.com/w/cpp/memory/allocator)
template <typename T, typename Mem = Memory<AlignOf<T>>>
class Allocator : public std::allocator<T>
{
  public:
    template <typename U>
    class rebind
    {
      public:
        using other = Allocator<U, Mem>;
    };

    Allocator() = default;

    template <typename U>
    Allocator(const Allocator<U, Mem> &other) noexcept
        : std::allocator<T>(static_cast<std::allocator<U>>(other))
    {
    }

    T *allocate(std::size_t n, const void *hint = nullptr)
    {
        const std::size_t m = n * sizeof(T);
        if (m < n) {
            throw std::bad_alloc();
        }

        T *ptr = static_cast<T *>(Mem::allocate(m, hint));
        if (ptr == nullptr) {
            throw std::bad_alloc();
        }

        return ptr;
    }

    void deallocate(T *ptr, std::size_t size = 0) noexcept(
        noexcept(Mem::deallocate(ptr, size)))
    {
        Mem::deallocate(ptr, size);
    }

    template <typename U>
    void construct(U *p)
    {
        construct_dispatch(p, std::is_scalar<U>());
    }

  private:
    template <typename U>
    void construct_dispatch(U *, std::true_type)
    {
    }

    template <typename U>
    void construct_dispatch(U *p, std::false_type)
    {
        ::new (static_cast<void *>(p)) U();
    }
}; // class Allocator

template <typename Mem>
class Allocator<void, Mem>
{
  public:
    using value_type = void;
    using pointer = void *;
    using const_pointer = const void *;
    using propagate_on_container_move_assignment = std::true_type;
    using is_always_equal = std::true_type;

    template <typename U>
    class rebind
    {
      public:
        using other = Allocator<U, Mem>;
    };
}; // class Allocator

template <typename Mem>
class Allocator<const void, Mem>
{
  public:
    using value_type = const void;
    using pointer = const void *;
    using const_pointer = const void *;
    using propagate_on_container_move_assignment = std::true_type;
    using is_always_equal = std::true_type;

    template <typename U>
    class rebind
    {
      public:
        using other = Allocator<U, Mem>;
    };
}; // class Allocator

/// \relates Allocator
template <typename T1, typename T2, typename Mem1, typename Mem2>
inline constexpr bool operator==(
    const Allocator<T1, Mem1> &, const Allocator<T2, Mem2> &)
{
    return std::is_same<Mem1, Mem2>::value;
}

/// \relates Allocator
template <typename T1, typename T2, typename Mem1, typename Mem2>
inline constexpr bool operator!=(
    const Allocator<T1, Mem1> &, const Allocator<T2, Mem2> &)
{
    return !std::is_same<Mem1, Mem2>::value;
}

/// \brief std::vector with Allocator as the default allocator
/// \ingroup Core
template <typename T, typename Alloc = Allocator<T>>
using Vector = std::vector<T, Alloc>;

} // namespace mckl

#endif // MCKL_CORE_MEMORY_HPP
<|endoftext|>


<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#ifndef NIX_CHECKS_H
#define NIX_CHECKS_H

#include <boost/optional.hpp>
#include <boost/any.hpp>
#include <nix/util/util.hpp>
#include <nix/valid/helper.hpp>

#include <nix/base/IDimensions.hpp>

#include <nix/types.hpp>

namespace nix {
namespace valid {

    /**
     * @brief Check if later given not greater than initally defined value.
     *
     * One Check struct that checks whether the given value is not greater
     * than the initially given other value, both of which have to be
     * convertible to double.
     */
    struct notGreater {
        const double value;

        template<typename T>
        notGreater(T value) : value(static_cast<double>(value)) {}

        template<typename T2>
        bool operator()(const T2 &val) const {
            return !(static_cast<double>(val) > value);
        }
    };

    /**
     * @brief Check if later given greater than initally defined value.
     *
     * One Check struct that checks whether the given value is greater than
     * the initially given other value, both of which have to be
     * convertible to double.
     */
    struct isGreater {
        const double value;

        template<typename T>
        isGreater(T value) : value(static_cast<double>(value)) {}

        template<typename T2>
        bool operator()(const T2 &val) const {
            return static_cast<double>(val) > value;
        }
    };

    /**
     * @brief Check if later given not smaller than initally defined value.
     *
     * One Check struct that checks whether the given value is not smaller
     * than the initially given other value, both of which have to be
     * convertible to double.
     */
    struct notSmaller {
        const double value;

        template<typename T>
        notSmaller(T value) : value(static_cast<double>(value)) {}

        template<typename T2>
        bool operator()(const T2 &val) const {
            return !(static_cast<double>(val) < value);
        }
    };

    /**
     * @brief Check if later given smaller than initally defined value.
     *
     * One Check struct that checks whether the given value is smaller than
     * the initially given other value, both of which have to be
     * convertible to double.
     */
    struct isSmaller {
        const double value;

        template<typename T>
        isSmaller(T value) : value(static_cast<double>(value)) {}

        template<typename T2>
        bool operator()(const T2 &val) const {
            return static_cast<double>(val) < value;
        }
    };

    /**
     * @brief Check for un-equality of initally defined and later given value.
     *
     * One Check struct that checks whether the given value is not equal
     * to the initially given other value.
     */
    template<typename T>
    struct notEqual {
        const T value;

        notEqual(T value) : value(value) {}

        template<typename T2>
        bool operator()(const T2 &val) const {
            return value != val;
        }
    };

    /**
     * @brief Check for equality of initally defined and later given value.
     *
     * One Check struct that checks whether the given value is equal to
     * the initially given other value.
     */
    template<typename T>
    struct isEqual {
        const T value;

        isEqual(T value) : value(value) {}

        template<typename T2>
        bool operator()(const T2 &val) const {
            return value == val;
        }
    };
    // needed because: for bizarre reasons bool converts to int when compared to boost::optional
    template<>
    struct isEqual<bool> {
        const bool value;

        isEqual(bool value) : value(value) {}

        template<typename T2>
        bool operator()(const T2 &val) const {
            return value ? !!val : !val;
        }
    };

    /**
     * @brief Check if given value casts to boolean true
     *
     * One Check struct that checks whether the given value casts to true
     * or to false.
     * T can be: boost::optional, boost::none, nix-entity
     * and any basic type.
     */
    struct notFalse {
        // WARNING: enum will convert via int, which means 0 = false !
        template<typename T>
        bool operator()(const T &val) const {
            return !!val;
        }
    };

    /**
     * @brief Check if given value casts to boolean false
     *
     * One Check struct that checks whether the given value casts to false
     * or to true.
     * T can be: boost::optional, boost::none, nix-entity
     * and any basic type.
     */
    struct isFalse {
        // WARNING: enum will convert via int, which means 0 = false !
        template<typename T>
        bool operator()(const T &val) const {
            return !val;
        }
    };

    /**
     * @brief Check if given class/struct returns "empty() == false"
     *
     * One Check struct that checks whether the given value is not empty
     * or is empty.
     * T can be: any STL container.
     */
    struct notEmpty {
        template<typename T>
        bool operator()(const T &val) const {
            return !(val.empty());
        }
    };

    /**
     * @brief Check if given class/struct returns "empty() == true"
     *
     * One Check struct that checks whether the given value is empty or
     * not.
     * T can be: any STL container.
     */
    struct isEmpty {
        template<typename T>
        bool operator()(const T &val) const {
            return val.empty();
        }
    };

    /**
     * @brief Check if given class represents valid SI unit string(s)
     *
     * Base struct to be inherited by the {@link isValidUnit}, {@link
     * isAtomicUnit}, {@link isCompoundUnit}. Not viable on its own!
     */
    struct isUnit {
        typedef std::function<bool(std::string)> TPRED;

        virtual bool operator()(const std::string &u) const = 0;

        bool operator()(const boost::optional<std::string> &u) const {
            // note: relying on short-curcuiting here
            return u && (*this)(*u);
        }

        bool operator()(const std::vector<std::string> &u, TPRED obj) const {
            // if test succeeds find_if_not will not find anything & return it == end
            return std::find_if_not(u.begin(), u.end(), obj) == u.end();
        }
    };

    /**
     * @brief Check if given class represents valid SI unit string(s)
     *
     * One Check struct that checks whether the given string(s) represent(s)
     * a valid atomic or compound SI unit.
     * Parameter can be of type boost optional (containing nothing or
     * string) or of type string or a vector of strings.
     */
    struct isValidUnit : public isUnit {
        bool operator()(const std::string &u) const {
            return (util::isSIUnit(u) || util::isCompoundSIUnit(u));
        }
        bool operator()(const boost::optional<std::string> &u) const {
            return isUnit::operator()(u);
        }
        bool operator()(const std::vector<std::string> &u) const {
            return isUnit::operator()(u, *this);
        }
    };

    /**
     * @brief Check if given class represents valid atomic SI unit string(s)
     *
     * One Check struct that checks whether the given string(s) represent(s)
     * a valid atomic SI unit.
     * Parameter can be of type boost optional (containing nothing or
     * string) or of type string or a vector of strings.
     */
    struct isAtomicUnit : public isUnit {
        bool operator()(const std::string &u) const {
            return util::isSIUnit(u);
        }
        bool operator()(const boost::optional<std::string> &u) const {
            return isUnit::operator()(u);
        }
        bool operator()(const std::vector<std::string> &u) const {
            return isUnit::operator()(u, *this);
        }
    };

    /**
     * @brief Check if given class represents valid compound SI unit string(s)
     *
     * One Check struct that checks whether the given string(s) represent(s)
     * a valid compound SI unit.
     * Parameter can be of type boost optional (containing nothing or
     * string) or of type string or a vector of strings.
     */
    struct isCompoundUnit : public isUnit {
        bool operator()(const std::string &u) const {
            return util::isCompoundSIUnit(u);
        }
        bool operator()(const boost::optional<std::string> &u) const {
            return isUnit::operator()(u);
        }
        bool operator()(const std::vector<std::string> &u) const {
            return isUnit::operator()(u, *this);
        }
    };

    /**
     * @brief Check if given value can be regarded as being set
     *
     * One Check struct that checks whether the given value can be
     * considered set, by applying {@link notFalse} and {@link notEmpty}
     * checks. Value thus is set if: STL cotnainer not empty OR
     * bool is true OR boost optional is set OR number is not 0.
     * Parameter can be of above types or even boost none_t.
     * NOTE: use this if you don't know wheter a type has and "empty"
     * method.
     */
    struct isSet {
        template<typename T>
        bool operator()(const T &val) const {
            typedef typename std::conditional<hasEmpty<T>::value, notEmpty, notFalse>::type subCheck;
            return subCheck(val);
        }
    };

    /**
     * @brief Check if given container is sorted using std::is_sorted
     *
     * One Check struct that checks whether the given container is sorted
     * according to std::is_sorted. Thus supports types that are
     * supported by std::is_sorted.
     */
    struct isSorted {
        template<typename T>
        bool operator()(const T &container) const {
            return std::is_sorted(container.begin(), container.end());
        }
    };

    /**
     * @brief Check if given DataArray has given dimensionality
     *
     * One Check struct that checks whether the given DataArray entity
     * has a dimensionality of the given uint value by getting its'
     * NDSize class via the "dataExtent" method and checking its' size
     * via "size" the method.
     */
    struct NIXAPI dimEquals {
        const size_t &value;

        dimEquals(const size_t &value) : value(value) {}

        bool operator()(const DataArray &array) const;
    };

    /**
     * @brief Check if given DataArrays' dimensions all have units where given units vector has
     *
     * One Check struct that checks whether the given referenced
     * DataArrays' dimensions all have units defined where the tag has.
     * (where the tag has means at the same index in the tag's units
     * vector as the dimension index in the referenced DataArray)
     * Therefore it takes all non-SetDimension dimensions of all given
     * references and checks whether the dimension has a unit set if the
     * tag has. If a dimension is a SetDimension the test counts as
     * passed. Thus in the end the test counts as passed if all non-
     * SetDimension dimensions have units set where the tag has and
     * have no units set where the tag has not. It counts as failed
     * immediately if number of dimensions differs from number of units
     * in given unit vector.
     */
    struct NIXAPI tagRefsHaveUnits {
        const std::vector<std::string> &units;

        tagRefsHaveUnits(const std::vector<std::string> &units) : units(units) {}

        bool operator()(const std::vector<DataArray> &references) const;
    };

    /**
     * @brief Check if given units match given referenced DataArrays' units
     *
     * One Check struct that checks whether the given units (vector of
     * strings) match the given referenced DataArrays' (vector of
     * DataArray references) units. Therefore it takes all non-
     * SetDimension dimensions of all given references and checks
     * whether the dimension has a unit convertible to the unit with the
     * same index in the given units vector. If a dimension is a
     * SetDimension the test counts as passed. Thus in the end the test
     * counts as passed if all non-SetDimension dimensions have units
     * set that are convertible where the units vector has a unit set
     * and all dims have no unit set where the units vector has not.
     * The test counts as failed immediately if the number of dimensions
     * in a DataArray differs the number of units in the units vector.
     */
    struct NIXAPI tagUnitsMatchRefsUnits {
        const std::vector<std::string> &units;

        tagUnitsMatchRefsUnits(const std::vector<std::string> &units) : units(units) {}

        bool operator()(const std::vector<DataArray> &references) const;
    };

    /**
     * @brief Check if given number of positions and extents matches
     *
     * One Check struct that checks whether the given number of
     * positions matches the given number of extents. It is irrelevant
     * which gets passed at construction time and which via operator().
     */
    struct NIXAPI extentsMatchPositions {
        const boost::any extents;

        extentsMatchPositions(const DataArray &extents) : extents(extents) {}

        extentsMatchPositions(const std::vector<double> &extents) : extents(extents) {}

        bool operator()(const DataArray &positions) const;
        bool operator()(const std::vector<double> &positions) const;
    };

    /**
     * @brief Check if number of extents (along 2nd dim) match number of references' data dims
     *
     * One Check struct that checks whether the given number of
     * extents (if DataArray: size along 2nd dimensions of extents
     * DataArray; if vector: size of vector) matches the data's
     * dimensionality in each of the given referenced DataArrays.
     */
    struct NIXAPI extentsMatchRefs {
        const std::vector<DataArray> &refs;

        extentsMatchRefs(const std::vector<DataArray> &refs) : refs(refs) {}

        bool operator()(const DataArray &extents) const;
        bool operator()(const std::vector<double> &extents) const;
    };

    /**
     * @brief Check if number of positions (along 2nd dim) match number of references' data dims
     *
     * One Check struct that checks whether the given number of
     * positions (if DataArray: size along 2nd dimensions of positions
     * DataArray; if vector: size of vector) matches the data's
     * dimensionality in each of the given referenced DataArrays.
     * Note: this is just an alias for extentsMatchRefs wich does the
     * same thing.
     */
    struct NIXAPI positionsMatchRefs {
        const std::vector<DataArray> &refs;

        positionsMatchRefs(const std::vector<DataArray> &refs) : refs(refs) {}

        bool operator()(const DataArray &positions) const;
        bool operator()(const std::vector<double> &positions) const;
    };

    /**
     * @brief Check if range dimension specifics ticks match data
     *
     * One Check struct that checks whether the dimensions of type
     * "Range" in the given dimensions vector have ticks that match
     * the given DataArray's data: number of ticks == number of entries
     * along the corresponding dimension in the data.
     */
    struct NIXAPI dimTicksMatchData {
        const DataArray &data;

        dimTicksMatchData(const DataArray &data) : data(data) {}

        bool operator()(const std::vector<Dimension> &dims) const;
    };

    /**
     * @brief Check if set dimension specifics labels match data
     *
     * One Check struct that checks whether the dimensions of type
     * "Set" in the given dimensions vector have labels that match
     * the given DataArray's data: number of labels == number of entries
     * along the corresponding dimension in the data.
     */
    struct NIXAPI dimLabelsMatchData {
        const DataArray &data;

        dimLabelsMatchData(const DataArray &data) : data(data) {}

        bool operator()(const std::vector<Dimension> &dims) const;
    };

} // namespace valid
} // namespace nix

#endif // NIX_CHECKS_H
<commit_msg>checks.hpp: insert missing virtual keyword<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#ifndef NIX_CHECKS_H
#define NIX_CHECKS_H

#include <boost/optional.hpp>
#include <boost/any.hpp>
#include <nix/util/util.hpp>
#include <nix/valid/helper.hpp>

#include <nix/base/IDimensions.hpp>

#include <nix/types.hpp>

namespace nix {
namespace valid {

    /**
     * @brief Check if later given not greater than initally defined value.
     *
     * One Check struct that checks whether the given value is not greater
     * than the initially given other value, both of which have to be
     * convertible to double.
     */
    struct notGreater {
        const double value;

        template<typename T>
        notGreater(T value) : value(static_cast<double>(value)) {}

        template<typename T2>
        bool operator()(const T2 &val) const {
            return !(static_cast<double>(val) > value);
        }
    };

    /**
     * @brief Check if later given greater than initally defined value.
     *
     * One Check struct that checks whether the given value is greater than
     * the initially given other value, both of which have to be
     * convertible to double.
     */
    struct isGreater {
        const double value;

        template<typename T>
        isGreater(T value) : value(static_cast<double>(value)) {}

        template<typename T2>
        bool operator()(const T2 &val) const {
            return static_cast<double>(val) > value;
        }
    };

    /**
     * @brief Check if later given not smaller than initally defined value.
     *
     * One Check struct that checks whether the given value is not smaller
     * than the initially given other value, both of which have to be
     * convertible to double.
     */
    struct notSmaller {
        const double value;

        template<typename T>
        notSmaller(T value) : value(static_cast<double>(value)) {}

        template<typename T2>
        bool operator()(const T2 &val) const {
            return !(static_cast<double>(val) < value);
        }
    };

    /**
     * @brief Check if later given smaller than initally defined value.
     *
     * One Check struct that checks whether the given value is smaller than
     * the initially given other value, both of which have to be
     * convertible to double.
     */
    struct isSmaller {
        const double value;

        template<typename T>
        isSmaller(T value) : value(static_cast<double>(value)) {}

        template<typename T2>
        bool operator()(const T2 &val) const {
            return static_cast<double>(val) < value;
        }
    };

    /**
     * @brief Check for un-equality of initally defined and later given value.
     *
     * One Check struct that checks whether the given value is not equal
     * to the initially given other value.
     */
    template<typename T>
    struct notEqual {
        const T value;

        notEqual(T value) : value(value) {}

        template<typename T2>
        bool operator()(const T2 &val) const {
            return value != val;
        }
    };

    /**
     * @brief Check for equality of initally defined and later given value.
     *
     * One Check struct that checks whether the given value is equal to
     * the initially given other value.
     */
    template<typename T>
    struct isEqual {
        const T value;

        isEqual(T value) : value(value) {}

        template<typename T2>
        bool operator()(const T2 &val) const {
            return value == val;
        }
    };
    // needed because: for bizarre reasons bool converts to int when compared to boost::optional
    template<>
    struct isEqual<bool> {
        const bool value;

        isEqual(bool value) : value(value) {}

        template<typename T2>
        bool operator()(const T2 &val) const {
            return value ? !!val : !val;
        }
    };

    /**
     * @brief Check if given value casts to boolean true
     *
     * One Check struct that checks whether the given value casts to true
     * or to false.
     * T can be: boost::optional, boost::none, nix-entity
     * and any basic type.
     */
    struct notFalse {
        // WARNING: enum will convert via int, which means 0 = false !
        template<typename T>
        bool operator()(const T &val) const {
            return !!val;
        }
    };

    /**
     * @brief Check if given value casts to boolean false
     *
     * One Check struct that checks whether the given value casts to false
     * or to true.
     * T can be: boost::optional, boost::none, nix-entity
     * and any basic type.
     */
    struct isFalse {
        // WARNING: enum will convert via int, which means 0 = false !
        template<typename T>
        bool operator()(const T &val) const {
            return !val;
        }
    };

    /**
     * @brief Check if given class/struct returns "empty() == false"
     *
     * One Check struct that checks whether the given value is not empty
     * or is empty.
     * T can be: any STL container.
     */
    struct notEmpty {
        template<typename T>
        bool operator()(const T &val) const {
            return !(val.empty());
        }
    };

    /**
     * @brief Check if given class/struct returns "empty() == true"
     *
     * One Check struct that checks whether the given value is empty or
     * not.
     * T can be: any STL container.
     */
    struct isEmpty {
        template<typename T>
        bool operator()(const T &val) const {
            return val.empty();
        }
    };

    /**
     * @brief Check if given class represents valid SI unit string(s)
     *
     * Base struct to be inherited by the {@link isValidUnit}, {@link
     * isAtomicUnit}, {@link isCompoundUnit}. Not viable on its own!
     */
    struct isUnit {
        typedef std::function<bool(std::string)> TPRED;

        virtual bool operator()(const std::string &u) const = 0;

        virtual bool operator()(const boost::optional<std::string> &u) const {
            // note: relying on short-curcuiting here
            return u && (*this)(*u);
        }

        virtual bool operator()(const std::vector<std::string> &u, TPRED obj) const {
            // if test succeeds find_if_not will not find anything & return it == end
            return std::find_if_not(u.begin(), u.end(), obj) == u.end();
        }
    };

    /**
     * @brief Check if given class represents valid SI unit string(s)
     *
     * One Check struct that checks whether the given string(s) represent(s)
     * a valid atomic or compound SI unit.
     * Parameter can be of type boost optional (containing nothing or
     * string) or of type string or a vector of strings.
     */
    struct isValidUnit : public isUnit {

        bool operator()(const std::string &u) const {
            return (util::isSIUnit(u) || util::isCompoundSIUnit(u));
        }

        bool operator()(const boost::optional<std::string> &u) const {
            return isUnit::operator()(u);
        }

        bool operator()(const std::vector<std::string> &u) const {
            return isUnit::operator()(u, *this);
        }
    };

    /**
     * @brief Check if given class represents valid atomic SI unit string(s)
     *
     * One Check struct that checks whether the given string(s) represent(s)
     * a valid atomic SI unit.
     * Parameter can be of type boost optional (containing nothing or
     * string) or of type string or a vector of strings.
     */
    struct isAtomicUnit : public isUnit {

        bool operator()(const std::string &u) const {
            return util::isSIUnit(u);
        }

        bool operator()(const boost::optional<std::string> &u) const {
            return isUnit::operator()(u);
        }

        bool operator()(const std::vector<std::string> &u) const {
            return isUnit::operator()(u, *this);
        }
    };

    /**
     * @brief Check if given class represents valid compound SI unit string(s)
     *
     * One Check struct that checks whether the given string(s) represent(s)
     * a valid compound SI unit.
     * Parameter can be of type boost optional (containing nothing or
     * string) or of type string or a vector of strings.
     */
    struct isCompoundUnit : public isUnit {

        bool operator()(const std::string &u) const {
            return util::isCompoundSIUnit(u);
        }

        bool operator()(const boost::optional<std::string> &u) const {
            return isUnit::operator()(u);
        }

        bool operator()(const std::vector<std::string> &u) const {
            return isUnit::operator()(u, *this);
        }
    };

    /**
     * @brief Check if given value can be regarded as being set
     *
     * One Check struct that checks whether the given value can be
     * considered set, by applying {@link notFalse} and {@link notEmpty}
     * checks. Value thus is set if: STL cotnainer not empty OR
     * bool is true OR boost optional is set OR number is not 0.
     * Parameter can be of above types or even boost none_t.
     * NOTE: use this if you don't know wheter a type has and "empty"
     * method.
     */
    struct isSet {
        template<typename T>
        bool operator()(const T &val) const {
            typedef typename std::conditional<hasEmpty<T>::value, notEmpty, notFalse>::type subCheck;
            return subCheck(val);
        }
    };

    /**
     * @brief Check if given container is sorted using std::is_sorted
     *
     * One Check struct that checks whether the given container is sorted
     * according to std::is_sorted. Thus supports types that are
     * supported by std::is_sorted.
     */
    struct isSorted {
        template<typename T>
        bool operator()(const T &container) const {
            return std::is_sorted(container.begin(), container.end());
        }
    };

    /**
     * @brief Check if given DataArray has given dimensionality
     *
     * One Check struct that checks whether the given DataArray entity
     * has a dimensionality of the given uint value by getting its'
     * NDSize class via the "dataExtent" method and checking its' size
     * via "size" the method.
     */
    struct NIXAPI dimEquals {
        const size_t &value;

        dimEquals(const size_t &value) : value(value) {}

        bool operator()(const DataArray &array) const;
    };

    /**
     * @brief Check if given DataArrays' dimensions all have units where given units vector has
     *
     * One Check struct that checks whether the given referenced
     * DataArrays' dimensions all have units defined where the tag has.
     * (where the tag has means at the same index in the tag's units
     * vector as the dimension index in the referenced DataArray)
     * Therefore it takes all non-SetDimension dimensions of all given
     * references and checks whether the dimension has a unit set if the
     * tag has. If a dimension is a SetDimension the test counts as
     * passed. Thus in the end the test counts as passed if all non-
     * SetDimension dimensions have units set where the tag has and
     * have no units set where the tag has not. It counts as failed
     * immediately if number of dimensions differs from number of units
     * in given unit vector.
     */
    struct NIXAPI tagRefsHaveUnits {
        const std::vector<std::string> &units;

        tagRefsHaveUnits(const std::vector<std::string> &units) : units(units) {}

        bool operator()(const std::vector<DataArray> &references) const;
    };

    /**
     * @brief Check if given units match given referenced DataArrays' units
     *
     * One Check struct that checks whether the given units (vector of
     * strings) match the given referenced DataArrays' (vector of
     * DataArray references) units. Therefore it takes all non-
     * SetDimension dimensions of all given references and checks
     * whether the dimension has a unit convertible to the unit with the
     * same index in the given units vector. If a dimension is a
     * SetDimension the test counts as passed. Thus in the end the test
     * counts as passed if all non-SetDimension dimensions have units
     * set that are convertible where the units vector has a unit set
     * and all dims have no unit set where the units vector has not.
     * The test counts as failed immediately if the number of dimensions
     * in a DataArray differs the number of units in the units vector.
     */
    struct NIXAPI tagUnitsMatchRefsUnits {
        const std::vector<std::string> &units;

        tagUnitsMatchRefsUnits(const std::vector<std::string> &units) : units(units) {}

        bool operator()(const std::vector<DataArray> &references) const;
    };

    /**
     * @brief Check if given number of positions and extents matches
     *
     * One Check struct that checks whether the given number of
     * positions matches the given number of extents. It is irrelevant
     * which gets passed at construction time and which via operator().
     */
    struct NIXAPI extentsMatchPositions {
        const boost::any extents;

        extentsMatchPositions(const DataArray &extents) : extents(extents) {}

        extentsMatchPositions(const std::vector<double> &extents) : extents(extents) {}

        bool operator()(const DataArray &positions) const;
        bool operator()(const std::vector<double> &positions) const;
    };

    /**
     * @brief Check if number of extents (along 2nd dim) match number of references' data dims
     *
     * One Check struct that checks whether the given number of
     * extents (if DataArray: size along 2nd dimensions of extents
     * DataArray; if vector: size of vector) matches the data's
     * dimensionality in each of the given referenced DataArrays.
     */
    struct NIXAPI extentsMatchRefs {
        const std::vector<DataArray> &refs;

        extentsMatchRefs(const std::vector<DataArray> &refs) : refs(refs) {}

        bool operator()(const DataArray &extents) const;
        bool operator()(const std::vector<double> &extents) const;
    };

    /**
     * @brief Check if number of positions (along 2nd dim) match number of references' data dims
     *
     * One Check struct that checks whether the given number of
     * positions (if DataArray: size along 2nd dimensions of positions
     * DataArray; if vector: size of vector) matches the data's
     * dimensionality in each of the given referenced DataArrays.
     * Note: this is just an alias for extentsMatchRefs wich does the
     * same thing.
     */
    struct NIXAPI positionsMatchRefs {
        const std::vector<DataArray> &refs;

        positionsMatchRefs(const std::vector<DataArray> &refs) : refs(refs) {}

        bool operator()(const DataArray &positions) const;
        bool operator()(const std::vector<double> &positions) const;
    };

    /**
     * @brief Check if range dimension specifics ticks match data
     *
     * One Check struct that checks whether the dimensions of type
     * "Range" in the given dimensions vector have ticks that match
     * the given DataArray's data: number of ticks == number of entries
     * along the corresponding dimension in the data.
     */
    struct NIXAPI dimTicksMatchData {
        const DataArray &data;

        dimTicksMatchData(const DataArray &data) : data(data) {}

        bool operator()(const std::vector<Dimension> &dims) const;
    };

    /**
     * @brief Check if set dimension specifics labels match data
     *
     * One Check struct that checks whether the dimensions of type
     * "Set" in the given dimensions vector have labels that match
     * the given DataArray's data: number of labels == number of entries
     * along the corresponding dimension in the data.
     */
    struct NIXAPI dimLabelsMatchData {
        const DataArray &data;

        dimLabelsMatchData(const DataArray &data) : data(data) {}

        bool operator()(const std::vector<Dimension> &dims) const;
    };

} // namespace valid
} // namespace nix

#endif // NIX_CHECKS_H
<|endoftext|>


<commit_before>#include "log.hpp"
#include "application.hpp"

#ifdef OPENBFME_PLATFORM_WINDOWS
#include <Windows.h>
#endif

namespace OpenBFME {

namespace Log {

namespace {
struct Output{
    OutputLevel level;
    FILE* fp;

    Output(OutputLevel l, FILE* f) : level(l), fp(f) {}
};

std::vector<Output> logOutputs;
}

void initLog(const string &filename, bool verbose, bool silent){
    Log::OutputLevel maxLevel = silent ? Log::Error : verbose ? Log::Debug : Log::Info;

    logOutputs.push_back(Log::Output(maxLevel, stdout));

    FILE* file = fopen(filename.c_str(), "w");
    if(file != nullptr){
        logOutputs.push_back(Log::Output(maxLevel, file));
    }
}

void shutdownLog() {
    for(Log::Output output : logOutputs)
        if(output.fp != stdout && output.fp != stderr)
            fclose(output.fp);

    logOutputs.clear();
}

void print(const string& str, OutputLevel level){
    Application* app = Application::getApplication();

    if(app != nullptr){
        const char* type;

#ifdef OPENBFME_PLATFORM_WINDOWS
#define SET_COLOR(color) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
        const WORD BLANK  = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
        const WORD RED    = FOREGROUND_RED | FOREGROUND_INTENSITY;
        const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
#else
#define SET_COLOR(color) fputs(color, stdout)
        const char* BLANK   = "\033[0m";
        const char* RED     = "\033[22;31m";
        const char* YELLOW  = "\033[01;33m";
#endif

        switch (level) {
        case Error:
            type = "ERROR";
            SET_COLOR(RED);
            break;
        case Warning:
            type = "WARNING";
            SET_COLOR(YELLOW);
            break;
        case Debug:
            type = "DEBUG";
            break;
        case Info:
        default:
            type = "INFO";
            break;
        }

        using namespace std::chrono;

        /* Make the timestamp string. */
        auto current = app->getRunningTime<microseconds>();

        string timestamp = format("[%02i:%02i.%06i] %s: ",
                                  duration_cast<minutes>(current).count(),
                                  duration_cast<seconds>(current).count() % 60,
                                  current.count() % 1000000,
                                  type);

        /* Write the string to every relevant output. */
        for(Output output : logOutputs){
            if(output.fp != nullptr && output.level >= level){
                fputs(timestamp.c_str(), output.fp);
                fputs(str.c_str(), output.fp);
                fputc('\n', output.fp);
                fflush(output.fp);
            }
        }

        SET_COLOR(BLANK);
    }
}

}

}
<commit_msg>Don't need "Log::" in log.cpp functions.<commit_after>#include "log.hpp"
#include "application.hpp"

#ifdef OPENBFME_PLATFORM_WINDOWS
#include <Windows.h>
#endif

namespace OpenBFME {

namespace Log {

namespace {
struct Output{
    OutputLevel level;
    FILE* fp;

    Output(OutputLevel l, FILE* f) : level(l), fp(f) {}
};

std::vector<Output> logOutputs;
}

void initLog(const string &filename, bool verbose, bool silent){
    OutputLevel maxLevel = silent ? Error : verbose ? Debug : Info;

    logOutputs.push_back(Output(maxLevel, stdout));

    FILE* file = fopen(filename.c_str(), "w");
    if(file != nullptr){
        logOutputs.push_back(Output(maxLevel, file));
    }
}

void shutdownLog() {
    for(Output& output : logOutputs)
        if(output.fp != stdout && output.fp != stderr)
            fclose(output.fp);

    logOutputs.clear();
}

void print(const string& str, OutputLevel level){
    Application* app = Application::getApplication();

    if(app != nullptr){
        const char* type;

#ifdef OPENBFME_PLATFORM_WINDOWS
#define SET_COLOR(color) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
        const WORD BLANK  = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
        const WORD RED    = FOREGROUND_RED | FOREGROUND_INTENSITY;
        const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
#else
#define SET_COLOR(color) fputs(color, stdout)
        const char* BLANK   = "\033[0m";
        const char* RED     = "\033[22;31m";
        const char* YELLOW  = "\033[01;33m";
#endif

        switch (level) {
        case Error:
            type = "ERROR";
            SET_COLOR(RED);
            break;
        case Warning:
            type = "WARNING";
            SET_COLOR(YELLOW);
            break;
        case Debug:
            type = "DEBUG";
            break;
        case Info:
        default:
            type = "INFO";
            break;
        }

        using namespace std::chrono;

        /* Make the timestamp string. */
        auto current = app->getRunningTime<microseconds>();

        string timestamp = format("[%02i:%02i.%06i] %s: ",
                                  duration_cast<minutes>(current).count(),
                                  duration_cast<seconds>(current).count() % 60,
                                  current.count() % 1000000,
                                  type);

        /* Write the string to every relevant output. */
        for(Output& output : logOutputs){
            if(output.fp != nullptr && output.level >= level){
                fputs(timestamp.c_str(), output.fp);
                fputs(str.c_str(), output.fp);
                fputc('\n', output.fp);
                fflush(output.fp);
            }
        }

        SET_COLOR(BLANK);
    }
}

}

}
<|endoftext|>