<commit_before>#include <string>

#include "envoy/stats/stats_macros.h"

#include "common/stats/isolated_store_impl.h"

#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "gtest/gtest.h"

namespace Envoy {
namespace Stats {

class StatsIsolatedStoreImplTest : public testing::Test {
protected:
  StatsIsolatedStoreImplTest() : pool_(store_.symbolTable()) {}
  ~StatsIsolatedStoreImplTest() override {
    pool_.clear();
    EXPECT_EQ(0, store_.symbolTable().numSymbols());
  }

  StatName makeStatName(absl::string_view name) { return pool_.add(name); }

  IsolatedStoreImpl store_;
  StatNamePool pool_;
};

TEST_F(StatsIsolatedStoreImplTest, All) {
  ScopePtr scope1 = store_.createScope("scope1.");
  Counter& c1 = store_.counter("c1");
  Counter& c2 = scope1->counter("c2");
  EXPECT_EQ("c1", c1.name());
  EXPECT_EQ("scope1.c2", c2.name());
  EXPECT_EQ("c1", c1.tagExtractedName());
  EXPECT_EQ("scope1.c2", c2.tagExtractedName());
  EXPECT_EQ(0, c1.tags().size());
  EXPECT_EQ(0, c1.tags().size());

  Gauge& g1 = store_.gauge("g1");
  Gauge& g2 = scope1->gauge("g2");
  EXPECT_EQ("g1", g1.name());
  EXPECT_EQ("scope1.g2", g2.name());
  EXPECT_EQ("g1", g1.tagExtractedName());
  EXPECT_EQ("scope1.g2", g2.tagExtractedName());
  EXPECT_EQ(0, g1.tags().size());
  EXPECT_EQ(0, g2.tags().size());

  Histogram& h1 = store_.histogram("h1");
  EXPECT_TRUE(h1.used()); // hardcoded in impl to be true always.
  Histogram& h2 = scope1->histogram("h2");
  scope1->deliverHistogramToSinks(h2, 0);
  EXPECT_EQ("h1", h1.name());
  EXPECT_EQ("scope1.h2", h2.name());
  EXPECT_EQ("h1", h1.tagExtractedName());
  EXPECT_EQ("scope1.h2", h2.tagExtractedName());
  EXPECT_EQ(0, h1.tags().size());
  EXPECT_EQ(0, h2.tags().size());
  h1.recordValue(200);
  h2.recordValue(200);

  ScopePtr scope2 = scope1->createScope("foo.");
  EXPECT_EQ("scope1.foo.bar", scope2->counter("bar").name());

  // Validate that we sanitize away bad characters in the stats prefix.
  ScopePtr scope3 = scope1->createScope(std::string("foo:\0:.", 7));
  EXPECT_EQ("scope1.foo___.bar", scope3->counter("bar").name());

  EXPECT_EQ(4UL, store_.counters().size());
  EXPECT_EQ(2UL, store_.gauges().size());
}

TEST_F(StatsIsolatedStoreImplTest, AllWithSymbolTable) {
  ScopePtr scope1 = store_.createScope("scope1.");
  Counter& c1 = store_.counterFromStatName(makeStatName("c1"));
  Counter& c2 = scope1->counterFromStatName(makeStatName("c2"));
  EXPECT_EQ("c1", c1.name());
  EXPECT_EQ("scope1.c2", c2.name());
  EXPECT_EQ("c1", c1.tagExtractedName());
  EXPECT_EQ("scope1.c2", c2.tagExtractedName());
  EXPECT_EQ(0, c1.tags().size());
  EXPECT_EQ(0, c1.tags().size());

  Gauge& g1 = store_.gaugeFromStatName(makeStatName("g1"));
  Gauge& g2 = scope1->gaugeFromStatName(makeStatName("g2"));
  EXPECT_EQ("g1", g1.name());
  EXPECT_EQ("scope1.g2", g2.name());
  EXPECT_EQ("g1", g1.tagExtractedName());
  EXPECT_EQ("scope1.g2", g2.tagExtractedName());
  EXPECT_EQ(0, g1.tags().size());
  EXPECT_EQ(0, g1.tags().size());

  Histogram& h1 = store_.histogramFromStatName(makeStatName("h1"));
  Histogram& h2 = scope1->histogramFromStatName(makeStatName("h2"));
  scope1->deliverHistogramToSinks(h2, 0);
  EXPECT_EQ("h1", h1.name());
  EXPECT_EQ("scope1.h2", h2.name());
  EXPECT_EQ("h1", h1.tagExtractedName());
  EXPECT_EQ("scope1.h2", h2.tagExtractedName());
  EXPECT_EQ(0, h1.tags().size());
  EXPECT_EQ(0, h2.tags().size());
  h1.recordValue(200);
  h2.recordValue(200);

  ScopePtr scope2 = scope1->createScope("foo.");
  EXPECT_EQ("scope1.foo.bar", scope2->counterFromStatName(makeStatName("bar")).name());

  // Validate that we sanitize away bad characters in the stats prefix.
  ScopePtr scope3 = scope1->createScope(std::string("foo:\0:.", 7));
  EXPECT_EQ("scope1.foo___.bar", scope3->counter("bar").name());

  EXPECT_EQ(4UL, store_.counters().size());
  EXPECT_EQ(2UL, store_.gauges().size());
}

TEST_F(StatsIsolatedStoreImplTest, ConstSymtabAccessor) {
  ScopePtr scope = store_.createScope("scope.");
  const Scope& cscope = *scope;
  const SymbolTable& const_symbol_table = cscope.constSymbolTable();
  SymbolTable& symbol_table = scope->symbolTable();
  EXPECT_EQ(&const_symbol_table, &symbol_table);
}

TEST_F(StatsIsolatedStoreImplTest, LongStatName) {
  const std::string long_string(128, 'A');

  ScopePtr scope = store_.createScope("scope.");
  Counter& counter = scope->counter(long_string);
  EXPECT_EQ(absl::StrCat("scope.", long_string), counter.name());
}

/**
 * Test stats macros. @see stats_macros.h
 */
// clang-format off
#define ALL_TEST_STATS(COUNTER, GAUGE, HISTOGRAM)                                                  \
  COUNTER  (test_counter)                                                                          \
  GAUGE    (test_gauge)                                                                            \
  HISTOGRAM(test_histogram)
// clang-format on

struct TestStats {
  ALL_TEST_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT, GENERATE_HISTOGRAM_STRUCT)
};

TEST_F(StatsIsolatedStoreImplTest, StatsMacros) {
  TestStats test_stats{ALL_TEST_STATS(POOL_COUNTER_PREFIX(store_, "test."),
                                      POOL_GAUGE_PREFIX(store_, "test."),
                                      POOL_HISTOGRAM_PREFIX(store_, "test."))};

  Counter& counter = test_stats.test_counter_;
  EXPECT_EQ("test.test_counter", counter.name());

  Gauge& gauge = test_stats.test_gauge_;
  EXPECT_EQ("test.test_gauge", gauge.name());

  Histogram& histogram = test_stats.test_histogram_;
  EXPECT_EQ("test.test_histogram", histogram.name());
}

TEST_F(StatsIsolatedStoreImplTest, NullImplCoverage) {
  NullCounterImpl c(store_.symbolTable());
  EXPECT_EQ(0, c.latch());
  NullGaugeImpl g(store_.symbolTable());
  g.setShouldImport(true);
  EXPECT_EQ(absl::nullopt, g.cachedShouldImport());
}

} // namespace Stats
} // namespace Envoy
<commit_msg>test: Add coverage for IsolatedStoreImpl::find* (#7043)<commit_after>#include <string>

#include "envoy/stats/stats_macros.h"

#include "common/stats/isolated_store_impl.h"

#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "gtest/gtest.h"

namespace Envoy {
namespace Stats {

class StatsIsolatedStoreImplTest : public testing::Test {
protected:
  StatsIsolatedStoreImplTest() : pool_(store_.symbolTable()) {}
  ~StatsIsolatedStoreImplTest() override {
    pool_.clear();
    EXPECT_EQ(0, store_.symbolTable().numSymbols());
  }

  StatName makeStatName(absl::string_view name) { return pool_.add(name); }

  IsolatedStoreImpl store_;
  StatNamePool pool_;
};

TEST_F(StatsIsolatedStoreImplTest, All) {
  ScopePtr scope1 = store_.createScope("scope1.");
  Counter& c1 = store_.counter("c1");
  Counter& c2 = scope1->counter("c2");
  EXPECT_EQ("c1", c1.name());
  EXPECT_EQ("scope1.c2", c2.name());
  EXPECT_EQ("c1", c1.tagExtractedName());
  EXPECT_EQ("scope1.c2", c2.tagExtractedName());
  EXPECT_EQ(0, c1.tags().size());
  EXPECT_EQ(0, c1.tags().size());

  StatNameManagedStorage c1_name("c1", store_.symbolTable());
  c1.add(100);
  auto found_counter = store_.findCounter(c1_name.statName());
  ASSERT_TRUE(found_counter.has_value());
  EXPECT_EQ(&c1, &found_counter->get());
  EXPECT_EQ(100, found_counter->get().value());
  c1.add(100);
  EXPECT_EQ(200, found_counter->get().value());

  Gauge& g1 = store_.gauge("g1");
  Gauge& g2 = scope1->gauge("g2");
  EXPECT_EQ("g1", g1.name());
  EXPECT_EQ("scope1.g2", g2.name());
  EXPECT_EQ("g1", g1.tagExtractedName());
  EXPECT_EQ("scope1.g2", g2.tagExtractedName());
  EXPECT_EQ(0, g1.tags().size());
  EXPECT_EQ(0, g2.tags().size());

  StatNameManagedStorage g1_name("g1", store_.symbolTable());
  g1.set(100);
  auto found_gauge = store_.findGauge(g1_name.statName());
  ASSERT_TRUE(found_gauge.has_value());
  EXPECT_EQ(&g1, &found_gauge->get());
  EXPECT_EQ(100, found_gauge->get().value());
  g1.set(0);
  EXPECT_EQ(0, found_gauge->get().value());

  Histogram& h1 = store_.histogram("h1");
  EXPECT_TRUE(h1.used()); // hardcoded in impl to be true always.
  Histogram& h2 = scope1->histogram("h2");
  scope1->deliverHistogramToSinks(h2, 0);
  EXPECT_EQ("h1", h1.name());
  EXPECT_EQ("scope1.h2", h2.name());
  EXPECT_EQ("h1", h1.tagExtractedName());
  EXPECT_EQ("scope1.h2", h2.tagExtractedName());
  EXPECT_EQ(0, h1.tags().size());
  EXPECT_EQ(0, h2.tags().size());
  h1.recordValue(200);
  h2.recordValue(200);

  StatNameManagedStorage h1_name("h1", store_.symbolTable());
  auto found_histogram = store_.findHistogram(h1_name.statName());
  ASSERT_TRUE(found_histogram.has_value());
  EXPECT_EQ(&h1, &found_histogram->get());

  ScopePtr scope2 = scope1->createScope("foo.");
  EXPECT_EQ("scope1.foo.bar", scope2->counter("bar").name());

  // Validate that we sanitize away bad characters in the stats prefix.
  ScopePtr scope3 = scope1->createScope(std::string("foo:\0:.", 7));
  EXPECT_EQ("scope1.foo___.bar", scope3->counter("bar").name());

  EXPECT_EQ(4UL, store_.counters().size());
  EXPECT_EQ(2UL, store_.gauges().size());

  StatNameManagedStorage nonexistent_name("nonexistent", store_.symbolTable());
  EXPECT_EQ(store_.findCounter(nonexistent_name.statName()), absl::nullopt);
  EXPECT_EQ(store_.findGauge(nonexistent_name.statName()), absl::nullopt);
  EXPECT_EQ(store_.findHistogram(nonexistent_name.statName()), absl::nullopt);
}

TEST_F(StatsIsolatedStoreImplTest, AllWithSymbolTable) {
  ScopePtr scope1 = store_.createScope("scope1.");
  Counter& c1 = store_.counterFromStatName(makeStatName("c1"));
  Counter& c2 = scope1->counterFromStatName(makeStatName("c2"));
  EXPECT_EQ("c1", c1.name());
  EXPECT_EQ("scope1.c2", c2.name());
  EXPECT_EQ("c1", c1.tagExtractedName());
  EXPECT_EQ("scope1.c2", c2.tagExtractedName());
  EXPECT_EQ(0, c1.tags().size());
  EXPECT_EQ(0, c1.tags().size());

  Gauge& g1 = store_.gaugeFromStatName(makeStatName("g1"));
  Gauge& g2 = scope1->gaugeFromStatName(makeStatName("g2"));
  EXPECT_EQ("g1", g1.name());
  EXPECT_EQ("scope1.g2", g2.name());
  EXPECT_EQ("g1", g1.tagExtractedName());
  EXPECT_EQ("scope1.g2", g2.tagExtractedName());
  EXPECT_EQ(0, g1.tags().size());
  EXPECT_EQ(0, g1.tags().size());

  Histogram& h1 = store_.histogramFromStatName(makeStatName("h1"));
  Histogram& h2 = scope1->histogramFromStatName(makeStatName("h2"));
  scope1->deliverHistogramToSinks(h2, 0);
  EXPECT_EQ("h1", h1.name());
  EXPECT_EQ("scope1.h2", h2.name());
  EXPECT_EQ("h1", h1.tagExtractedName());
  EXPECT_EQ("scope1.h2", h2.tagExtractedName());
  EXPECT_EQ(0, h1.tags().size());
  EXPECT_EQ(0, h2.tags().size());
  h1.recordValue(200);
  h2.recordValue(200);

  ScopePtr scope2 = scope1->createScope("foo.");
  EXPECT_EQ("scope1.foo.bar", scope2->counterFromStatName(makeStatName("bar")).name());

  // Validate that we sanitize away bad characters in the stats prefix.
  ScopePtr scope3 = scope1->createScope(std::string("foo:\0:.", 7));
  EXPECT_EQ("scope1.foo___.bar", scope3->counter("bar").name());

  EXPECT_EQ(4UL, store_.counters().size());
  EXPECT_EQ(2UL, store_.gauges().size());
}

TEST_F(StatsIsolatedStoreImplTest, ConstSymtabAccessor) {
  ScopePtr scope = store_.createScope("scope.");
  const Scope& cscope = *scope;
  const SymbolTable& const_symbol_table = cscope.constSymbolTable();
  SymbolTable& symbol_table = scope->symbolTable();
  EXPECT_EQ(&const_symbol_table, &symbol_table);
}

TEST_F(StatsIsolatedStoreImplTest, LongStatName) {
  const std::string long_string(128, 'A');

  ScopePtr scope = store_.createScope("scope.");
  Counter& counter = scope->counter(long_string);
  EXPECT_EQ(absl::StrCat("scope.", long_string), counter.name());
}

/**
 * Test stats macros. @see stats_macros.h
 */
// clang-format off
#define ALL_TEST_STATS(COUNTER, GAUGE, HISTOGRAM)                                                  \
  COUNTER  (test_counter)                                                                          \
  GAUGE    (test_gauge)                                                                            \
  HISTOGRAM(test_histogram)
// clang-format on

struct TestStats {
  ALL_TEST_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT, GENERATE_HISTOGRAM_STRUCT)
};

TEST_F(StatsIsolatedStoreImplTest, StatsMacros) {
  TestStats test_stats{ALL_TEST_STATS(POOL_COUNTER_PREFIX(store_, "test."),
                                      POOL_GAUGE_PREFIX(store_, "test."),
                                      POOL_HISTOGRAM_PREFIX(store_, "test."))};

  Counter& counter = test_stats.test_counter_;
  EXPECT_EQ("test.test_counter", counter.name());

  Gauge& gauge = test_stats.test_gauge_;
  EXPECT_EQ("test.test_gauge", gauge.name());

  Histogram& histogram = test_stats.test_histogram_;
  EXPECT_EQ("test.test_histogram", histogram.name());
}

TEST_F(StatsIsolatedStoreImplTest, NullImplCoverage) {
  NullCounterImpl c(store_.symbolTable());
  EXPECT_EQ(0, c.latch());
  NullGaugeImpl g(store_.symbolTable());
  g.setShouldImport(true);
  EXPECT_EQ(absl::nullopt, g.cachedShouldImport());
}

} // namespace Stats
} // namespace Envoy
<|endoftext|>


<commit_before>/******************************************************************************
* Copyright (c) 2013, Bradley J Chambers (brad.chambers@gmail.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include <boost/test/unit_test.hpp>
#include <boost/cstdint.hpp>

#include <boost/uuid/uuid_io.hpp>

#include <pdal/PointBuffer.hpp>
#include <pdal/drivers/buffer/Reader.hpp>
#include <pdal/drivers/text/Writer.hpp>

#include <iostream>

#include "Support.hpp"

#ifdef PDAL_COMPILER_GCC
#pragma GCC diagnostic ignored "-Wfloat-equal"
#pragma GCC diagnostic ignored "-Wsign-compare"
#endif

using namespace pdal;

PointBuffer *makeBuffer()
{
    // create a input
    std::vector<pdal::Dimension> dimensions;
    dimensions.reserve(3);

    pdal::Dimension dimX("X", pdal::dimension::Float, 4,
                         "X coordinate as a float.");
    dimX.setUUID("2ee118d1-119e-4906-99c3-42934203f872");
    dimX.setNamespace("X");
    dimensions.push_back(dimX);

    pdal::Dimension dimY("Y", pdal::dimension::Float, 4,
                         "Y coordinate as a float.");
    dimY.setUUID("87707eee-2f30-4979-9987-8ef747e30275");
    dimY.setNamespace("Y");
    dimensions.push_back(dimY);

    pdal::Dimension dimZ("Z", pdal::dimension::Float, 4,
                         "Z coordinate as a float.");
    dimZ.setUUID("e74b5e41-95e6-4cf2-86ad-e3f5a996da5d");
    dimZ.setNamespace("Z");
    dimensions.push_back(dimZ);

    const pdal::Schema schema(dimensions);

    boost::uint32_t numPoints = 1000;
    pdal::PointBuffer *input(new pdal::PointBuffer(schema, numPoints));

    input->setNumPoints(0);

    pdal::Bounds<double> bounds;
    bool bFirstPoint(true);

    for (boost::uint32_t i=0; i<numPoints; i++)
    {
        input->setField<float>(schema.getDimension("X"), i, 1.0);
        input->setField<float>(schema.getDimension("Y"), i, 2.0);
        input->setField<float>(schema.getDimension("Z"), i, 3.0);

        if (bFirstPoint)
        {
            bounds = pdal::Bounds<double>(1.0, 2.0, 3.0, 1.0, 2.0, 3.0);
            bFirstPoint = false;
        }

        bounds.grow(pdal::Vector<double>(1.0, 2.0, 3.0));
        input->setNumPoints(i+1);
    }

    input->setSpatialBounds(bounds);

    return input;
}

BOOST_AUTO_TEST_SUITE(BufferReaderTest)

BOOST_AUTO_TEST_CASE(test_sequential_iter)
{
    PointBuffer *input = makeBuffer();

    pdal::Option debug("debug", true, "");
    pdal::Option verbose("verbose", 5, "");

    pdal::Options reader_options;
    reader_options.add(debug);
    reader_options.add(verbose);

    pdal::drivers::buffer::Reader reader(reader_options, *input);
    reader.initialize();

    BOOST_CHECK_EQUAL(reader.getDescription(), "Buffer Reader");

    const Schema& schema = reader.getSchema();

    PointBuffer data(schema, 750);

    StageSequentialIterator* iter = reader.createSequentialIterator(data);
    boost::uint32_t numRead = iter->read(data);

    BOOST_CHECK_EQUAL(numRead, 750);

    Schema const& buffer_schema = data.getSchema();
    Dimension const& dimX = buffer_schema.getDimension("X");
    Dimension const& dimY = buffer_schema.getDimension("Y");
    Dimension const& dimZ = buffer_schema.getDimension("Z");

    for (boost::uint32_t i=0; i<numRead; i++)
    {
        float x = data.getField<float>(dimX, i);
        float y = data.getField<float>(dimY, i);
        float z = data.getField<float>(dimZ, i);

        BOOST_CHECK_CLOSE(x, 1.0, 0.00001);
        BOOST_CHECK_CLOSE(y, 2.0, 0.00001);
        BOOST_CHECK_CLOSE(z, 3.0, 0.00001);
    }

    delete iter;

    return;
}

BOOST_AUTO_TEST_CASE(test_iterator_checks)
{
    PointBuffer *input = makeBuffer();

    pdal::Option debug("debug", true, "");
    pdal::Option verbose("verbose", 5, "");

    pdal::Options reader_options;
    reader_options.add(debug);
    reader_options.add(verbose);

    pdal::drivers::buffer::Reader reader(reader_options, *input);
    reader.initialize();

    BOOST_CHECK_EQUAL(reader.supportsIterator(StageIterator_Sequential), true);
    BOOST_CHECK_EQUAL(reader.supportsIterator(StageIterator_Random) , true);

    return;
}

BOOST_AUTO_TEST_CASE(test_random_iter)
{
    PointBuffer *input = makeBuffer();

    pdal::Option debug("debug", true, "");
    pdal::Option verbose("verbose", 5, "");

    pdal::Options reader_options;
    reader_options.add(debug);
    reader_options.add(verbose);

    pdal::drivers::buffer::Reader reader(reader_options, *input);
    reader.initialize();

    BOOST_CHECK_EQUAL(reader.getDescription(), "Buffer Reader");

    const Schema& schema = reader.getSchema();

    PointBuffer data(schema, 10);

    StageRandomIterator* iter = reader.createRandomIterator(data);

    boost::uint32_t numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10u);

    Schema const& buffer_schema = data.getSchema();
    Dimension const& dimX = buffer_schema.getDimension("X");
    Dimension const& dimY = buffer_schema.getDimension("Y");
    Dimension const& dimZ = buffer_schema.getDimension("Z");

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            float x = data.getField<float>(dimX, i);
            float y = data.getField<float>(dimY, i);
            float z = data.getField<float>(dimZ, i);

            BOOST_CHECK_CLOSE(x, 1.0, 0.00001);
            BOOST_CHECK_CLOSE(y, 2.0, 0.00001);
            BOOST_CHECK_CLOSE(z, 3.0, 0.00001);
        }
    }

    numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10u);

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            float x = data.getField<float>(dimX, i);
            float y = data.getField<float>(dimY, i);
            float z = data.getField<float>(dimZ, i);

            BOOST_CHECK_CLOSE(x, 1.0, 0.00001);
            BOOST_CHECK_CLOSE(y, 2.0, 0.00001);
            BOOST_CHECK_CLOSE(z, 3.0, 0.00001);
        }
    }

    boost::uint64_t newPos = iter->seek(99);
    BOOST_CHECK_EQUAL(newPos, 99u);
    numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10u);

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            float x = data.getField<float>(dimX, i);
            float y = data.getField<float>(dimY, i);
            float z = data.getField<float>(dimZ, i);

            BOOST_CHECK_CLOSE(x, 1.0, 0.00001);
            BOOST_CHECK_CLOSE(y, 2.0, 0.00001);
            BOOST_CHECK_CLOSE(z, 3.0, 0.00001);
        }
    }

    newPos = iter->seek(7);
    BOOST_CHECK_EQUAL(newPos, 7u);
    numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10u);

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            float x = data.getField<float>(dimX, i);
            float y = data.getField<float>(dimY, i);
            float z = data.getField<float>(dimZ, i);

            BOOST_CHECK_CLOSE(x, 1.0, 0.00001);
            BOOST_CHECK_CLOSE(y, 2.0, 0.00001);
            BOOST_CHECK_CLOSE(z, 3.0, 0.00001);
        }
    }

    delete iter;

    return;
}

BOOST_AUTO_TEST_CASE(test_iterator_write)
{
    PointBuffer *input = makeBuffer();

    pdal::Option debug("debug", true, "");
    pdal::Option verbose("verbose", 5, "");

    pdal::Options reader_options;
    reader_options.add(debug);
    reader_options.add(verbose);

    pdal::drivers::buffer::Reader reader(reader_options, *input);
    //reader.initialize();

    std::string output("BufferReaderTest-geojson.json");
    pdal::Option out_filename("filename", Support::temppath(output));
    pdal::Option output_type("format", "geojson", "");

    pdal::Options writer_opts;
    writer_opts.add(debug);
    writer_opts.add(verbose);
    writer_opts.add(out_filename);
    writer_opts.add(output_type);

    pdal::drivers::text::Writer writer(reader, writer_opts);
    writer.initialize();
    boost::uint64_t numWritten = writer.write(100);

    BOOST_CHECK_EQUAL(numWritten, 100u);

    return;
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>silence debug output<commit_after>/******************************************************************************
* Copyright (c) 2013, Bradley J Chambers (brad.chambers@gmail.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include <boost/test/unit_test.hpp>
#include <boost/cstdint.hpp>

#include <boost/uuid/uuid_io.hpp>

#include <pdal/PointBuffer.hpp>
#include <pdal/drivers/buffer/Reader.hpp>
#include <pdal/drivers/text/Writer.hpp>

#include <iostream>

#include "Support.hpp"

#ifdef PDAL_COMPILER_GCC
#pragma GCC diagnostic ignored "-Wfloat-equal"
#pragma GCC diagnostic ignored "-Wsign-compare"
#endif

using namespace pdal;

PointBuffer *makeBuffer()
{
    // create a input
    std::vector<pdal::Dimension> dimensions;
    dimensions.reserve(3);

    pdal::Dimension dimX("X", pdal::dimension::Float, 4,
                         "X coordinate as a float.");
    dimX.setUUID("2ee118d1-119e-4906-99c3-42934203f872");
    dimX.setNamespace("X");
    dimensions.push_back(dimX);

    pdal::Dimension dimY("Y", pdal::dimension::Float, 4,
                         "Y coordinate as a float.");
    dimY.setUUID("87707eee-2f30-4979-9987-8ef747e30275");
    dimY.setNamespace("Y");
    dimensions.push_back(dimY);

    pdal::Dimension dimZ("Z", pdal::dimension::Float, 4,
                         "Z coordinate as a float.");
    dimZ.setUUID("e74b5e41-95e6-4cf2-86ad-e3f5a996da5d");
    dimZ.setNamespace("Z");
    dimensions.push_back(dimZ);

    const pdal::Schema schema(dimensions);

    boost::uint32_t numPoints = 1000;
    pdal::PointBuffer *input(new pdal::PointBuffer(schema, numPoints));

    input->setNumPoints(0);

    pdal::Bounds<double> bounds;
    bool bFirstPoint(true);

    for (boost::uint32_t i=0; i<numPoints; i++)
    {
        input->setField<float>(schema.getDimension("X"), i, 1.0);
        input->setField<float>(schema.getDimension("Y"), i, 2.0);
        input->setField<float>(schema.getDimension("Z"), i, 3.0);

        if (bFirstPoint)
        {
            bounds = pdal::Bounds<double>(1.0, 2.0, 3.0, 1.0, 2.0, 3.0);
            bFirstPoint = false;
        }

        bounds.grow(pdal::Vector<double>(1.0, 2.0, 3.0));
        input->setNumPoints(i+1);
    }

    input->setSpatialBounds(bounds);

    return input;
}

BOOST_AUTO_TEST_SUITE(BufferReaderTest)

BOOST_AUTO_TEST_CASE(test_sequential_iter)
{
    PointBuffer *input = makeBuffer();

    pdal::Option debug("debug", true, "");
    pdal::Option verbose("verbose", 5, "");

    pdal::Options reader_options;
    // reader_options.add(debug);
    // reader_options.add(verbose);

    pdal::drivers::buffer::Reader reader(reader_options, *input);
    reader.initialize();

    BOOST_CHECK_EQUAL(reader.getDescription(), "Buffer Reader");

    const Schema& schema = reader.getSchema();

    PointBuffer data(schema, 750);

    StageSequentialIterator* iter = reader.createSequentialIterator(data);
    boost::uint32_t numRead = iter->read(data);

    BOOST_CHECK_EQUAL(numRead, 750);

    Schema const& buffer_schema = data.getSchema();
    Dimension const& dimX = buffer_schema.getDimension("X");
    Dimension const& dimY = buffer_schema.getDimension("Y");
    Dimension const& dimZ = buffer_schema.getDimension("Z");

    for (boost::uint32_t i=0; i<numRead; i++)
    {
        float x = data.getField<float>(dimX, i);
        float y = data.getField<float>(dimY, i);
        float z = data.getField<float>(dimZ, i);

        BOOST_CHECK_CLOSE(x, 1.0, 0.00001);
        BOOST_CHECK_CLOSE(y, 2.0, 0.00001);
        BOOST_CHECK_CLOSE(z, 3.0, 0.00001);
    }

    delete iter;

    return;
}

BOOST_AUTO_TEST_CASE(test_iterator_checks)
{
    PointBuffer *input = makeBuffer();

    pdal::Option debug("debug", true, "");
    pdal::Option verbose("verbose", 5, "");

    pdal::Options reader_options;
    reader_options.add(debug);
    reader_options.add(verbose);

    pdal::drivers::buffer::Reader reader(reader_options, *input);
    reader.initialize();

    BOOST_CHECK_EQUAL(reader.supportsIterator(StageIterator_Sequential), true);
    BOOST_CHECK_EQUAL(reader.supportsIterator(StageIterator_Random) , true);

    return;
}

BOOST_AUTO_TEST_CASE(test_random_iter)
{
    PointBuffer *input = makeBuffer();

    pdal::Option debug("debug", true, "");
    pdal::Option verbose("verbose", 5, "");

    pdal::Options reader_options;
    // reader_options.add(debug);
    // reader_options.add(verbose);

    pdal::drivers::buffer::Reader reader(reader_options, *input);
    reader.initialize();

    BOOST_CHECK_EQUAL(reader.getDescription(), "Buffer Reader");

    const Schema& schema = reader.getSchema();

    PointBuffer data(schema, 10);

    StageRandomIterator* iter = reader.createRandomIterator(data);

    boost::uint32_t numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10u);

    Schema const& buffer_schema = data.getSchema();
    Dimension const& dimX = buffer_schema.getDimension("X");
    Dimension const& dimY = buffer_schema.getDimension("Y");
    Dimension const& dimZ = buffer_schema.getDimension("Z");

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            float x = data.getField<float>(dimX, i);
            float y = data.getField<float>(dimY, i);
            float z = data.getField<float>(dimZ, i);

            BOOST_CHECK_CLOSE(x, 1.0, 0.00001);
            BOOST_CHECK_CLOSE(y, 2.0, 0.00001);
            BOOST_CHECK_CLOSE(z, 3.0, 0.00001);
        }
    }

    numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10u);

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            float x = data.getField<float>(dimX, i);
            float y = data.getField<float>(dimY, i);
            float z = data.getField<float>(dimZ, i);

            BOOST_CHECK_CLOSE(x, 1.0, 0.00001);
            BOOST_CHECK_CLOSE(y, 2.0, 0.00001);
            BOOST_CHECK_CLOSE(z, 3.0, 0.00001);
        }
    }

    boost::uint64_t newPos = iter->seek(99);
    BOOST_CHECK_EQUAL(newPos, 99u);
    numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10u);

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            float x = data.getField<float>(dimX, i);
            float y = data.getField<float>(dimY, i);
            float z = data.getField<float>(dimZ, i);

            BOOST_CHECK_CLOSE(x, 1.0, 0.00001);
            BOOST_CHECK_CLOSE(y, 2.0, 0.00001);
            BOOST_CHECK_CLOSE(z, 3.0, 0.00001);
        }
    }

    newPos = iter->seek(7);
    BOOST_CHECK_EQUAL(newPos, 7u);
    numRead = iter->read(data);
    BOOST_CHECK_EQUAL(numRead, 10u);

    {
        for (boost::uint32_t i=0; i<numRead; i++)
        {
            float x = data.getField<float>(dimX, i);
            float y = data.getField<float>(dimY, i);
            float z = data.getField<float>(dimZ, i);

            BOOST_CHECK_CLOSE(x, 1.0, 0.00001);
            BOOST_CHECK_CLOSE(y, 2.0, 0.00001);
            BOOST_CHECK_CLOSE(z, 3.0, 0.00001);
        }
    }

    delete iter;

    return;
}

BOOST_AUTO_TEST_CASE(test_iterator_write)
{
    PointBuffer *input = makeBuffer();

    pdal::Option debug("debug", true, "");
    pdal::Option verbose("verbose", 5, "");

    pdal::Options reader_options;
    // reader_options.add(debug);
    // reader_options.add(verbose);

    pdal::drivers::buffer::Reader reader(reader_options, *input);
    //reader.initialize();

    std::string output("BufferReaderTest-geojson.json");
    pdal::Option out_filename("filename", Support::temppath(output));
    pdal::Option output_type("format", "geojson", "");

    pdal::Options writer_opts;
    // writer_opts.add(debug);
    // writer_opts.add(verbose);
    writer_opts.add(out_filename);
    writer_opts.add(output_type);

    pdal::drivers::text::Writer writer(reader, writer_opts);
    writer.initialize();
    boost::uint64_t numWritten = writer.write(100);

    BOOST_CHECK_EQUAL(numWritten, 100u);

    return;
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright RTK Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#ifndef __rtkJosephBackProjectionImageFilter_hxx
#define __rtkJosephBackProjectionImageFilter_hxx

#include "rtkHomogeneousMatrix.h"
#include "rtkRayBoxIntersectionFunction.h"

#include <itkImageRegionConstIterator.h>
#include <itkImageRegionIteratorWithIndex.h>
#include <itkIdentityTransform.h>

namespace rtk
{

template <class TInputImage,
          class TOutputImage,
          class TSplatWeightMultiplication>
void
JosephBackProjectionImageFilter<TInputImage,
                                TOutputImage,
                                TSplatWeightMultiplication>
::GenerateData()
{
  const unsigned int Dimension = TInputImage::ImageDimension;
  typename TInputImage::RegionType buffReg = this->GetInput(1)->GetBufferedRegion();
  const unsigned int nPixelPerProj = buffReg.GetSize(0) * buffReg.GetSize(1);
  int offsets[3];
  offsets[0] = 1;
  offsets[1] = this->GetInput(0)->GetBufferedRegion().GetSize()[0];
  offsets[2] = this->GetInput(0)->GetBufferedRegion().GetSize()[0] * this->GetInput(0)->GetBufferedRegion().GetSize()[1];

  GeometryType *geometry = dynamic_cast<GeometryType*>(this->GetGeometry().GetPointer());
  if( !geometry )
    {
    itkGenericExceptionMacro(<< "Error, ThreeDCircularProjectionGeometry expected");
    }

  // Allocate the output image
  this->AllocateOutputs();

  // Initialize output region with input region in case the filter is not in
  // place
  if(this->GetInput() != this->GetOutput() )
    {
    // Iterators on volume input and output
    typedef itk::ImageRegionConstIterator<TInputImage> InputRegionIterator;
    InputRegionIterator itVolIn(this->GetInput(0), this->GetInput()->GetBufferedRegion());

    typedef itk::ImageRegionIteratorWithIndex<TOutputImage> OutputRegionIterator;
    OutputRegionIterator itVolOut(this->GetOutput(), this->GetInput()->GetBufferedRegion());

    while(!itVolIn.IsAtEnd() )
      {
      itVolOut.Set(itVolIn.Get() );
      ++itVolIn;
      ++itVolOut;
      }
    }

  // beginBuffer is pointing at point with index (0,0,0) in memory, even if
  // it is not in the allocated memory
  typename TOutputImage::PixelType *beginBuffer =
      this->GetOutput()->GetBufferPointer() -
      offsets[0] * this->GetOutput()->GetBufferedRegion().GetIndex()[0] -
      offsets[1] * this->GetOutput()->GetBufferedRegion().GetIndex()[1] -
      offsets[2] * this->GetOutput()->GetBufferedRegion().GetIndex()[2];

  // Iterator on projections input
  typedef itk::ImageRegionConstIterator<TInputImage> InputRegionIterator;
  InputRegionIterator itIn(this->GetInput(1), buffReg);

  // Create intersection functions, one for each possible main direction
  typedef rtk::RayBoxIntersectionFunction<CoordRepType, Dimension> RBIFunctionType;
  typename RBIFunctionType::Pointer rbi[Dimension];
  for(unsigned int j=0; j<Dimension; j++)
    {
    rbi[j] = RBIFunctionType::New();
    typename RBIFunctionType::VectorType boxMin, boxMax;
    for(unsigned int i=0; i<Dimension; i++)
      {
      boxMin[i] = this->GetOutput()->GetRequestedRegion().GetIndex()[i];
      boxMax[i] = this->GetOutput()->GetRequestedRegion().GetIndex()[i] +
                  this->GetOutput()->GetRequestedRegion().GetSize()[i] - 1;
      }
    rbi[j]->SetBoxMin(boxMin);
    rbi[j]->SetBoxMax(boxMax);
    }

  // Go over each projection
  for(int iProj=buffReg.GetIndex(2);
          iProj<buffReg.GetIndex(2)+(int)buffReg.GetSize(2);
          iProj++)
    {
    // Account for system rotations
    // volPPToIndex maps the physical 3D coordinates of a point (in mm) to the
    // corresponding 3D volume index
    typename GeometryType::ThreeDHomogeneousMatrixType volPPToIndex;
    volPPToIndex = GetPhysicalPointToIndexMatrix( this->GetOutput() );

    // Set source position in volume indices
    // GetSourcePosition() returns coordinates in mm. Multiplying by
    // volPPToIndex gives the corresponding volume index
    typename GeometryType::HomogeneousVectorType sourcePosition;
    sourcePosition = volPPToIndex * geometry->GetSourcePosition(iProj);
    for(unsigned int i=0; i<Dimension; i++)
      rbi[i]->SetRayOrigin( &(sourcePosition[0]) );

    // Compute matrix to transform projection index to volume index
    // IndexToPhysicalPointMatrix maps the 2D index of a projection's pixel to its 2D position on the detector (in mm)
    // ProjectionCoordinatesToFixedSystemMatrix maps the 2D position of a pixel on the detector to its 3D coordinates in volume's coordinates (still in mm)
    // volPPToIndex maps 3D volume coordinates to a 3D index
    typename GeometryType::ThreeDHomogeneousMatrixType matrixProj, matrixVol;
    matrixProj = geometry->GetProjectionCoordinatesToFixedSystemMatrix(iProj).GetVnlMatrix() *
                 GetIndexToPhysicalPointMatrix( this->GetInput(1) ).GetVnlMatrix();
    matrixVol = volPPToIndex.GetVnlMatrix() *
                geometry->GetRotationMatrices()[iProj].GetInverse();

    // Read detector radius and pre-compute its inverse
    const double R = geometry->GetRadiusCylindricalDetector()[iProj];
    const double invR = 1./R;
    const double sid = geometry->GetSourceToIsocenterDistances()[iProj];

    // Go over each pixel of the projection
    typename RBIFunctionType::VectorType posProj, dirVox, stepMM, dirVoxAbs, np, fp;
    for(unsigned int pix=0; pix<nPixelPerProj; pix++, ++itIn)
      {
      // Compute point coordinate in volume depending on projection index
      for(unsigned int i=0; i<Dimension; i++)
        {
        posProj[i] = matrixProj[i][Dimension];
        for(unsigned int j=0; j<Dimension; j++)
          posProj[i] += matrixProj[i][j] * itIn.GetIndex()[j];
        }

      // Convert cylindrical angle to coordinate
      double a = invR * posProj[0];
      posProj[0] = vcl_sin(a) * R;
      posProj[2] = sid-vcl_cos(a) * R;
      for(unsigned int i=0; i<Dimension; i++)
        {
        // Rotate and convert to voxel coordinates
        dirVox[i] = matrixVol[i][Dimension];
        for(unsigned int j=0; j<Dimension; j++)
          dirVox[i] += matrixVol[i][j] * posProj[j];

        // Direction
        dirVox[i] -= sourcePosition[i];
        }

      // Select main direction
      unsigned int mainDir = 0;
      for(unsigned int i=0; i<Dimension; i++)
        {
        dirVoxAbs[i] = vnl_math_abs( dirVox[i] );
        if(dirVoxAbs[i]>dirVoxAbs[mainDir])
          mainDir = i;
        }

      // Test if there is an intersection
      if( rbi[mainDir]->Evaluate(dirVox) &&
          rbi[mainDir]->GetFarthestDistance()>=0. && // check if detector after the source
          rbi[mainDir]->GetNearestDistance()<=1.)    // check if detector after or in the volume
        {
        // Clip the casting between source and pixel of the detector
        rbi[mainDir]->SetNearestDistance ( std::max(rbi[mainDir]->GetNearestDistance() , 0.) );
        rbi[mainDir]->SetFarthestDistance( std::min(rbi[mainDir]->GetFarthestDistance(), 1.) );

        // Compute and sort intersections: (n)earest and (f)arthest (p)points
        np = rbi[mainDir]->GetNearestPoint();
        fp = rbi[mainDir]->GetFarthestPoint();
        if(np[mainDir]>fp[mainDir])
          std::swap(np, fp);

        // Compute main nearest and farthest slice indices
        const int ns = vnl_math_rnd( np[mainDir]);
        const int fs = vnl_math_rnd( fp[mainDir]);

        // Determine the other two directions
        unsigned int notMainDirInf = (mainDir+1)%Dimension;
        unsigned int notMainDirSup = (mainDir+2)%Dimension;
        if(notMainDirInf>notMainDirSup)
          std::swap(notMainDirInf, notMainDirSup);

        const CoordRepType minx = rbi[mainDir]->GetBoxMin()[notMainDirInf];
        const CoordRepType miny = rbi[mainDir]->GetBoxMin()[notMainDirSup];
        const CoordRepType maxx = rbi[mainDir]->GetBoxMax()[notMainDirInf];
        const CoordRepType maxy = rbi[mainDir]->GetBoxMax()[notMainDirSup];

        // Init data pointers to first pixel of slice ns (i)nferior and (s)uperior (x|y) corner
        const int offsetx = offsets[notMainDirInf];
        const int offsety = offsets[notMainDirSup];
        const int offsetz = offsets[mainDir];
        OutputPixelType *pxiyi, *pxsyi, *pxiys, *pxsys;

        pxiyi = beginBuffer + ns * offsetz;
        pxsyi = pxiyi + offsetx;
        pxiys = pxiyi + offsety;
        pxsys = pxsyi + offsety;

        // Compute step size and go to first voxel
        const CoordRepType residual = ns - np[mainDir];
        const CoordRepType norm = 1/dirVox[mainDir];
        const CoordRepType stepx = dirVox[notMainDirInf] * norm;
        const CoordRepType stepy = dirVox[notMainDirSup] * norm;
        CoordRepType currentx = np[notMainDirInf] + residual * stepx;
        CoordRepType currenty = np[notMainDirSup] + residual * stepy;

        // Compute voxel to millimeters conversion
        stepMM[notMainDirInf] = this->GetInput(0)->GetSpacing()[notMainDirInf] * stepx;
        stepMM[notMainDirSup] = this->GetInput(0)->GetSpacing()[notMainDirSup] * stepy;
        stepMM[mainDir]       = this->GetInput(0)->GetSpacing()[mainDir];

        if (fs == ns) //If the voxel is a corner, we can skip most steps
          {
            BilinearSplatOnBorders(itIn.Get(), fp[mainDir] - np[mainDir], stepMM.GetNorm(),
                                    pxiyi, pxsyi, pxiys, pxsys, currentx, currenty,
                                    offsetx, offsety, minx, miny, maxx, maxy);
          }
        else
          {

          // First step
            BilinearSplatOnBorders(itIn.Get(), residual + 0.5, stepMM.GetNorm(),
                                 pxiyi, pxsyi, pxiys, pxsys, currentx, currenty,
                                 offsetx, offsety, minx, miny, maxx, maxy);

          // Move to next main direction slice
          pxiyi += offsetz;
          pxsyi += offsetz;
          pxiys += offsetz;
          pxsys += offsetz;
          currentx += stepx;
          currenty += stepy;

          // Middle steps
          for(int i=ns+1; i<fs; i++)
            {

            BilinearSplat(itIn.Get(), 1.0, stepMM.GetNorm(), pxiyi, pxsyi, pxiys, pxsys, currentx, currenty, offsetx, offsety);

            // Move to next main direction slice
            pxiyi += offsetz;
            pxsyi += offsetz;
            pxiys += offsetz;
            pxsys += offsetz;
            currentx += stepx;
            currenty += stepy;
            }

          // Last step
          BilinearSplatOnBorders(itIn.Get(), fp[mainDir] - fs + 0.5, stepMM.GetNorm(),
                                 pxiyi, pxsyi, pxiys, pxsys, currentx, currenty,
                                 offsetx, offsety, minx, miny, maxx, maxy);
          }
        }

      }
    }
}

template <class TInputImage,
          class TOutputImage,
          class TSplatWeightMultiplication>
void
JosephBackProjectionImageFilter<TInputImage,
                                   TOutputImage,
                                   TSplatWeightMultiplication>
::BilinearSplat(const InputPixelType rayValue,
                                               const double stepLengthInVoxel,
                                               const double voxelSize,
                                               OutputPixelType *pxiyi,
                                               OutputPixelType *pxsyi,
                                               OutputPixelType *pxiys,
                                               OutputPixelType *pxsys,
                                               const double x,
                                               const double y,
                                               const int ox,
                                               const int oy)
{
  int ix = vnl_math_floor(x);
  int iy = vnl_math_floor(y);
  int idx = ix*ox + iy*oy;
  CoordRepType lx = x - ix;
  CoordRepType ly = y - iy;
  CoordRepType lxc = 1.-lx;
  CoordRepType lyc = 1.-ly;

  pxiyi[idx] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lxc * lyc);
  pxsyi[idx] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lx * lyc);
  pxiys[idx] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lxc * ly);
  pxsys[idx] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lx * ly);

}

template <class TInputImage,
          class TOutputImage,
          class TSplatWeightMultiplication>
void
JosephBackProjectionImageFilter<TInputImage,
                                   TOutputImage,
                                   TSplatWeightMultiplication>
::BilinearSplatOnBorders(const InputPixelType rayValue,
                                               const double stepLengthInVoxel,
                                               const double voxelSize,
                                               OutputPixelType *pxiyi,
                                               OutputPixelType *pxsyi,
                                               OutputPixelType *pxiys,
                                               OutputPixelType *pxsys,
                                               const double x,
                                               const double y,
                                               const int ox,
                                               const int oy,
                                               const CoordRepType minx,
                                               const CoordRepType miny,
                                               const CoordRepType maxx,
                                               const CoordRepType maxy)
{
  int ix = vnl_math_floor(x);
  int iy = vnl_math_floor(y);
  int idx = ix*ox + iy*oy;
  CoordRepType lx = x - ix;
  CoordRepType ly = y - iy;
  CoordRepType lxc = 1.-lx;
  CoordRepType lyc = 1.-ly;

  int offset_xi = 0;
  int offset_yi = 0;
  int offset_xs = 0;
  int offset_ys = 0;

  if(ix < minx) offset_xi = ox;
  if(iy < miny) offset_yi = oy;
  if(ix >= maxx) offset_xs = -ox;
  if(iy >= maxy) offset_ys = -oy;

  pxiyi[idx + offset_xi + offset_yi] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lxc * lyc);
  pxiys[idx + offset_xi + offset_ys] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lxc * ly);
  pxsyi[idx + offset_xs + offset_yi] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lx * lyc);
  pxsys[idx + offset_xs + offset_ys] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lx * ly);

}

} // end namespace rtk

#endif
<commit_msg>Updated Joseph backprojector to perform computation only for non-zero pixels in projections.<commit_after>/*=========================================================================
 *
 *  Copyright RTK Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#ifndef __rtkJosephBackProjectionImageFilter_hxx
#define __rtkJosephBackProjectionImageFilter_hxx

#include "rtkHomogeneousMatrix.h"
#include "rtkRayBoxIntersectionFunction.h"

#include <itkImageRegionConstIterator.h>
#include <itkImageRegionIteratorWithIndex.h>
#include <itkIdentityTransform.h>

namespace rtk
{

template <class TInputImage,
          class TOutputImage,
          class TSplatWeightMultiplication>
void
JosephBackProjectionImageFilter<TInputImage,
                                TOutputImage,
                                TSplatWeightMultiplication>
::GenerateData()
{
  const unsigned int Dimension = TInputImage::ImageDimension;
  typename TInputImage::RegionType buffReg = this->GetInput(1)->GetBufferedRegion();
  const unsigned int nPixelPerProj = buffReg.GetSize(0) * buffReg.GetSize(1);
  int offsets[3];
  offsets[0] = 1;
  offsets[1] = this->GetInput(0)->GetBufferedRegion().GetSize()[0];
  offsets[2] = this->GetInput(0)->GetBufferedRegion().GetSize()[0] * this->GetInput(0)->GetBufferedRegion().GetSize()[1];

  GeometryType *geometry = dynamic_cast<GeometryType*>(this->GetGeometry().GetPointer());
  if( !geometry )
    {
    itkGenericExceptionMacro(<< "Error, ThreeDCircularProjectionGeometry expected");
    }

  // Allocate the output image
  this->AllocateOutputs();

  // Initialize output region with input region in case the filter is not in
  // place
  if(this->GetInput() != this->GetOutput() )
    {
    // Iterators on volume input and output
    typedef itk::ImageRegionConstIterator<TInputImage> InputRegionIterator;
    InputRegionIterator itVolIn(this->GetInput(0), this->GetInput()->GetBufferedRegion());

    typedef itk::ImageRegionIteratorWithIndex<TOutputImage> OutputRegionIterator;
    OutputRegionIterator itVolOut(this->GetOutput(), this->GetInput()->GetBufferedRegion());

    while(!itVolIn.IsAtEnd() )
      {
      itVolOut.Set(itVolIn.Get() );
      ++itVolIn;
      ++itVolOut;
      }
    }

  // beginBuffer is pointing at point with index (0,0,0) in memory, even if
  // it is not in the allocated memory
  typename TOutputImage::PixelType *beginBuffer =
      this->GetOutput()->GetBufferPointer() -
      offsets[0] * this->GetOutput()->GetBufferedRegion().GetIndex()[0] -
      offsets[1] * this->GetOutput()->GetBufferedRegion().GetIndex()[1] -
      offsets[2] * this->GetOutput()->GetBufferedRegion().GetIndex()[2];

  // Iterator on projections input
  typedef itk::ImageRegionConstIterator<TInputImage> InputRegionIterator;
  InputRegionIterator itIn(this->GetInput(1), buffReg);

  // Create intersection functions, one for each possible main direction
  typedef rtk::RayBoxIntersectionFunction<CoordRepType, Dimension> RBIFunctionType;
  typename RBIFunctionType::Pointer rbi[Dimension];
  for(unsigned int j=0; j<Dimension; j++)
    {
    rbi[j] = RBIFunctionType::New();
    typename RBIFunctionType::VectorType boxMin, boxMax;
    for(unsigned int i=0; i<Dimension; i++)
      {
      boxMin[i] = this->GetOutput()->GetRequestedRegion().GetIndex()[i];
      boxMax[i] = this->GetOutput()->GetRequestedRegion().GetIndex()[i] +
                  this->GetOutput()->GetRequestedRegion().GetSize()[i] - 1;
      }
    rbi[j]->SetBoxMin(boxMin);
    rbi[j]->SetBoxMax(boxMax);
    }

  // Go over each projection
  for(int iProj=buffReg.GetIndex(2);
          iProj<buffReg.GetIndex(2)+(int)buffReg.GetSize(2);
          iProj++)
    {
    // Account for system rotations
    // volPPToIndex maps the physical 3D coordinates of a point (in mm) to the
    // corresponding 3D volume index
    typename GeometryType::ThreeDHomogeneousMatrixType volPPToIndex;
    volPPToIndex = GetPhysicalPointToIndexMatrix( this->GetOutput() );

    // Set source position in volume indices
    // GetSourcePosition() returns coordinates in mm. Multiplying by
    // volPPToIndex gives the corresponding volume index
    typename GeometryType::HomogeneousVectorType sourcePosition;
    sourcePosition = volPPToIndex * geometry->GetSourcePosition(iProj);
    for(unsigned int i=0; i<Dimension; i++)
      rbi[i]->SetRayOrigin( &(sourcePosition[0]) );

    // Compute matrix to transform projection index to volume index
    // IndexToPhysicalPointMatrix maps the 2D index of a projection's pixel to its 2D position on the detector (in mm)
    // ProjectionCoordinatesToFixedSystemMatrix maps the 2D position of a pixel on the detector to its 3D coordinates in volume's coordinates (still in mm)
    // volPPToIndex maps 3D volume coordinates to a 3D index
    typename GeometryType::ThreeDHomogeneousMatrixType matrixProj, matrixVol;
    matrixProj = geometry->GetProjectionCoordinatesToFixedSystemMatrix(iProj).GetVnlMatrix() *
                 GetIndexToPhysicalPointMatrix( this->GetInput(1) ).GetVnlMatrix();
    matrixVol = volPPToIndex.GetVnlMatrix() *
                geometry->GetRotationMatrices()[iProj].GetInverse();

    // Read detector radius and pre-compute its inverse
    const double R = geometry->GetRadiusCylindricalDetector()[iProj];
    const double invR = 1./R;
    const double sid = geometry->GetSourceToIsocenterDistances()[iProj];

    // Go over each pixel of the projection
    typename RBIFunctionType::VectorType posProj, dirVox, stepMM, dirVoxAbs, np, fp;
    for(unsigned int pix=0; pix<nPixelPerProj; pix++, ++itIn)
      {
	  // Only perform computation if pixel value is non-zero
	  if (itIn.Get()!=0)
	  {
	      // Compute point coordinate in volume depending on projection index
	      for(unsigned int i=0; i<Dimension; i++)
	      {
		  posProj[i] = matrixProj[i][Dimension];
		  for(unsigned int j=0; j<Dimension; j++)
		      posProj[i] += matrixProj[i][j] * itIn.GetIndex()[j];
	      }

	      // Convert cylindrical angle to coordinate
	      double a = invR * posProj[0];
	      posProj[0] = vcl_sin(a) * R;
	      posProj[2] = sid-vcl_cos(a) * R;
	      for(unsigned int i=0; i<Dimension; i++)
	      {
		  // Rotate and convert to voxel coordinates
		  dirVox[i] = matrixVol[i][Dimension];
		  for(unsigned int j=0; j<Dimension; j++)
		      dirVox[i] += matrixVol[i][j] * posProj[j];

		  // Direction
		  dirVox[i] -= sourcePosition[i];
	      }

	      // Select main direction
	      unsigned int mainDir = 0;
	      for(unsigned int i=0; i<Dimension; i++)
	      {
		  dirVoxAbs[i] = vnl_math_abs( dirVox[i] );
		  if(dirVoxAbs[i]>dirVoxAbs[mainDir])
		      mainDir = i;
	      }

	      // Test if there is an intersection
	      if( rbi[mainDir]->Evaluate(dirVox) &&
		  rbi[mainDir]->GetFarthestDistance()>=0. && // check if detector after the source
		  rbi[mainDir]->GetNearestDistance()<=1.)    // check if detector after or in the volume
	      {
		  // Clip the casting between source and pixel of the detector
		  rbi[mainDir]->SetNearestDistance ( std::max(rbi[mainDir]->GetNearestDistance() , 0.) );
		  rbi[mainDir]->SetFarthestDistance( std::min(rbi[mainDir]->GetFarthestDistance(), 1.) );

		  // Compute and sort intersections: (n)earest and (f)arthest (p)points
		  np = rbi[mainDir]->GetNearestPoint();
		  fp = rbi[mainDir]->GetFarthestPoint();
		  if(np[mainDir]>fp[mainDir])
		      std::swap(np, fp);

		  // Compute main nearest and farthest slice indices
		  const int ns = vnl_math_rnd( np[mainDir]);
		  const int fs = vnl_math_rnd( fp[mainDir]);

		  // Determine the other two directions
		  unsigned int notMainDirInf = (mainDir+1)%Dimension;
		  unsigned int notMainDirSup = (mainDir+2)%Dimension;
		  if(notMainDirInf>notMainDirSup)
		      std::swap(notMainDirInf, notMainDirSup);

		  const CoordRepType minx = rbi[mainDir]->GetBoxMin()[notMainDirInf];
		  const CoordRepType miny = rbi[mainDir]->GetBoxMin()[notMainDirSup];
		  const CoordRepType maxx = rbi[mainDir]->GetBoxMax()[notMainDirInf];
		  const CoordRepType maxy = rbi[mainDir]->GetBoxMax()[notMainDirSup];

		  // Init data pointers to first pixel of slice ns (i)nferior and (s)uperior (x|y) corner
		  const int offsetx = offsets[notMainDirInf];
		  const int offsety = offsets[notMainDirSup];
		  const int offsetz = offsets[mainDir];
		  OutputPixelType *pxiyi, *pxsyi, *pxiys, *pxsys;

		  pxiyi = beginBuffer + ns * offsetz;
		  pxsyi = pxiyi + offsetx;
		  pxiys = pxiyi + offsety;
		  pxsys = pxsyi + offsety;

		  // Compute step size and go to first voxel
		  const CoordRepType residual = ns - np[mainDir];
		  const CoordRepType norm = 1/dirVox[mainDir];
		  const CoordRepType stepx = dirVox[notMainDirInf] * norm;
		  const CoordRepType stepy = dirVox[notMainDirSup] * norm;
		  CoordRepType currentx = np[notMainDirInf] + residual * stepx;
		  CoordRepType currenty = np[notMainDirSup] + residual * stepy;

		  // Compute voxel to millimeters conversion
		  stepMM[notMainDirInf] = this->GetInput(0)->GetSpacing()[notMainDirInf] * stepx;
		  stepMM[notMainDirSup] = this->GetInput(0)->GetSpacing()[notMainDirSup] * stepy;
		  stepMM[mainDir]       = this->GetInput(0)->GetSpacing()[mainDir];

		  if (fs == ns) //If the voxel is a corner, we can skip most steps
		  {
		      BilinearSplatOnBorders(itIn.Get(), fp[mainDir] - np[mainDir], stepMM.GetNorm(),
					     pxiyi, pxsyi, pxiys, pxsys, currentx, currenty,
					     offsetx, offsety, minx, miny, maxx, maxy);
		  }
		  else
		  {

		      // First step
		      BilinearSplatOnBorders(itIn.Get(), residual + 0.5, stepMM.GetNorm(),
					     pxiyi, pxsyi, pxiys, pxsys, currentx, currenty,
					     offsetx, offsety, minx, miny, maxx, maxy);

		      // Move to next main direction slice
		      pxiyi += offsetz;
		      pxsyi += offsetz;
		      pxiys += offsetz;
		      pxsys += offsetz;
		      currentx += stepx;
		      currenty += stepy;

		      // Middle steps
		      for(int i=ns+1; i<fs; i++)
		      {

			  BilinearSplat(itIn.Get(), 1.0, stepMM.GetNorm(), pxiyi, pxsyi, pxiys, pxsys, currentx, currenty, offsetx, offsety);

			  // Move to next main direction slice
			  pxiyi += offsetz;
			  pxsyi += offsetz;
			  pxiys += offsetz;
			  pxsys += offsetz;
			  currentx += stepx;
			  currenty += stepy;
		      }

		      // Last step
		      BilinearSplatOnBorders(itIn.Get(), fp[mainDir] - fs + 0.5, stepMM.GetNorm(),
					     pxiyi, pxsyi, pxiys, pxsys, currentx, currenty,
					     offsetx, offsety, minx, miny, maxx, maxy);
		  }
	      }
	  }
      }
    }
}

template <class TInputImage,
          class TOutputImage,
          class TSplatWeightMultiplication>
void
JosephBackProjectionImageFilter<TInputImage,
                                   TOutputImage,
                                   TSplatWeightMultiplication>
::BilinearSplat(const InputPixelType rayValue,
                                               const double stepLengthInVoxel,
                                               const double voxelSize,
                                               OutputPixelType *pxiyi,
                                               OutputPixelType *pxsyi,
                                               OutputPixelType *pxiys,
                                               OutputPixelType *pxsys,
                                               const double x,
                                               const double y,
                                               const int ox,
                                               const int oy)
{
  int ix = vnl_math_floor(x);
  int iy = vnl_math_floor(y);
  int idx = ix*ox + iy*oy;
  CoordRepType lx = x - ix;
  CoordRepType ly = y - iy;
  CoordRepType lxc = 1.-lx;
  CoordRepType lyc = 1.-ly;

  pxiyi[idx] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lxc * lyc);
  pxsyi[idx] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lx * lyc);
  pxiys[idx] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lxc * ly);
  pxsys[idx] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lx * ly);

}

template <class TInputImage,
          class TOutputImage,
          class TSplatWeightMultiplication>
void
JosephBackProjectionImageFilter<TInputImage,
                                   TOutputImage,
                                   TSplatWeightMultiplication>
::BilinearSplatOnBorders(const InputPixelType rayValue,
                                               const double stepLengthInVoxel,
                                               const double voxelSize,
                                               OutputPixelType *pxiyi,
                                               OutputPixelType *pxsyi,
                                               OutputPixelType *pxiys,
                                               OutputPixelType *pxsys,
                                               const double x,
                                               const double y,
                                               const int ox,
                                               const int oy,
                                               const CoordRepType minx,
                                               const CoordRepType miny,
                                               const CoordRepType maxx,
                                               const CoordRepType maxy)
{
  int ix = vnl_math_floor(x);
  int iy = vnl_math_floor(y);
  int idx = ix*ox + iy*oy;
  CoordRepType lx = x - ix;
  CoordRepType ly = y - iy;
  CoordRepType lxc = 1.-lx;
  CoordRepType lyc = 1.-ly;

  int offset_xi = 0;
  int offset_yi = 0;
  int offset_xs = 0;
  int offset_ys = 0;

  if(ix < minx) offset_xi = ox;
  if(iy < miny) offset_yi = oy;
  if(ix >= maxx) offset_xs = -ox;
  if(iy >= maxy) offset_ys = -oy;

  pxiyi[idx + offset_xi + offset_yi] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lxc * lyc);
  pxiys[idx + offset_xi + offset_ys] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lxc * ly);
  pxsyi[idx + offset_xs + offset_yi] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lx * lyc);
  pxsys[idx + offset_xs + offset_ys] += m_SplatWeightMultiplication(rayValue, stepLengthInVoxel, voxelSize, lx * ly);

}

} // end namespace rtk

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2012 Steinwurf ApS
// All Rights Reserved
//
// Distributed under the "BSD License". See the accompanying LICENSE.rst file.

#include <sak/buffer.hpp>

#include <gtest/gtest.h>

TEST(TestBuffer, construct)
{
    sak::buffer b;
    EXPECT_EQ(0U, b.size());
}

TEST(TestBuffer, resize)
{
    sak::buffer b;
    b.resize(100);
    EXPECT_EQ(100U, b.size());
}

TEST(TestBuffer, resize_and_copy)
{
    sak::buffer b1;
    b1.resize(100);
    EXPECT_EQ(100U, b1.size());

    sak::buffer b2 = b1;
    EXPECT_EQ(100U, b2.size());
}

TEST(TestBuffer, append_to_empty_with_size)
{
    std::vector<uint8_t> data(32);
    EXPECT_EQ(32U, data.size());

    sak::buffer b;
    EXPECT_EQ(0U, b.size());

    b.append(&data[0], static_cast<uint32_t>(data.size()));
    EXPECT_EQ(data.size(), b.size());
}

TEST(TestBuffer, append_to_empty_with_pointers)
{
    std::vector<uint8_t> data(32);
    EXPECT_EQ(32U, data.size());

    sak::buffer b;
    EXPECT_EQ(0U, b.size());

    b.append(&data[0], &data[0] + data.size());
    EXPECT_EQ(data.size(), b.size());
}

TEST(TestBuffer, append_to_empty_with_storage)
{
    std::vector<uint8_t> data(32);
    EXPECT_EQ(32U, data.size());

    sak::buffer b;
    EXPECT_EQ(0U, b.size());

    b.append(sak::storage(data));
    EXPECT_EQ(data.size(), b.size());
}

TEST(TestBuffer, append_to_initialized)
{
    {
        std::vector<uint8_t> data(32, 'x');
        EXPECT_EQ(32U, data.size());

        sak::buffer b(10);
        EXPECT_EQ(0U, b.size());

        b.append(&data[0], static_cast<uint32_t>(data.size()));
        EXPECT_EQ(data.size(), b.size());
    }

    {
        std::vector<uint8_t> data(32, 'x');
        EXPECT_EQ(32U, data.size());

        sak::buffer b(10);
        EXPECT_EQ(0U, b.size());

        b.append(&data[0], &data[0] + data.size());
        EXPECT_EQ(data.size(), b.size());
    }

    {
        std::vector<uint8_t> data(32, 'x');
        EXPECT_EQ(32U, data.size());

        sak::buffer b(10);
        EXPECT_EQ(0U, b.size());

        b.append(sak::storage(data));
        EXPECT_EQ(data.size(), b.size());
    }
}

TEST(TestBuffer, resize_and_clear)
{
    sak::buffer b(100);
    EXPECT_EQ(0U, b.size());
    std::fill_n(b.data(), b.size(), 'x');

    b.resize(10);
    EXPECT_EQ(10U, b.size());
    std::fill_n(b.data(), b.size(), 'x');

    b.resize(101);
    EXPECT_EQ(101U, b.size());
    std::fill_n(b.data(), b.size(), 'x');

    b.clear();
    EXPECT_EQ(0U, b.size());

    b.resize(0);
    EXPECT_EQ(0U, b.size());

    b.resize(102);
    EXPECT_EQ(102U, b.size());
    std::fill_n(b.data(), b.size(), 'x');

    b.resize(0);
    EXPECT_EQ(0U, b.size());

    b.clear();
    EXPECT_EQ(0U, b.size());
}
<commit_msg>Cover buffer::data()<commit_after>// Copyright (c) 2012 Steinwurf ApS
// All Rights Reserved
//
// Distributed under the "BSD License". See the accompanying LICENSE.rst file.

#include <sak/buffer.hpp>

#include <algorithm>

#include <gtest/gtest.h>

TEST(TestBuffer, construct)
{
    sak::buffer b;
    EXPECT_EQ(0U, b.size());
}

TEST(TestBuffer, resize)
{
    sak::buffer b;
    b.resize(100);
    EXPECT_EQ(100U, b.size());
}

TEST(TestBuffer, resize_and_copy)
{
    sak::buffer b1;
    b1.resize(100);
    EXPECT_EQ(100U, b1.size());

    sak::buffer b2 = b1;
    EXPECT_EQ(100U, b2.size());
}

TEST(TestBuffer, append_to_empty_with_size)
{
    std::vector<uint8_t> data(32);
    EXPECT_EQ(32U, data.size());

    sak::buffer b;
    EXPECT_EQ(0U, b.size());

    b.append(&data[0], static_cast<uint32_t>(data.size()));
    EXPECT_EQ(data.size(), b.size());
}

TEST(TestBuffer, append_to_empty_with_pointers)
{
    std::vector<uint8_t> data(32);
    EXPECT_EQ(32U, data.size());

    sak::buffer b;
    EXPECT_EQ(0U, b.size());

    b.append(&data[0], &data[0] + data.size());
    EXPECT_EQ(data.size(), b.size());
}

TEST(TestBuffer, append_to_empty_with_storage)
{
    std::vector<uint8_t> data(32);
    EXPECT_EQ(32U, data.size());

    sak::buffer b;
    EXPECT_EQ(0U, b.size());

    b.append(sak::storage(data));
    EXPECT_EQ(data.size(), b.size());
}

TEST(TestBuffer, append_to_initialized)
{
    {
        std::vector<uint8_t> data(32, 'x');
        EXPECT_EQ(32U, data.size());

        sak::buffer b(10);
        EXPECT_EQ(0U, b.size());

        b.append(&data[0], static_cast<uint32_t>(data.size()));
        EXPECT_EQ(data.size(), b.size());
        EXPECT_TRUE(std::equal(data.begin(), data.end(), b.data()));
    }

    {
        std::vector<uint8_t> data(32, 'x');
        EXPECT_EQ(32U, data.size());

        sak::buffer b(10);
        EXPECT_EQ(0U, b.size());

        b.append(&data[0], &data[0] + data.size());
        EXPECT_EQ(data.size(), b.size());
        EXPECT_TRUE(std::equal(data.begin(), data.end(), b.data()));
    }

    {
        std::vector<uint8_t> data(32, 'x');
        EXPECT_EQ(32U, data.size());

        sak::buffer b(10);
        EXPECT_EQ(0U, b.size());

        b.append(sak::storage(data));
        EXPECT_EQ(data.size(), b.size());
        EXPECT_TRUE(std::equal(data.begin(), data.end(), b.data()));
    }
}

TEST(TestBuffer, resize_and_clear)
{
    sak::buffer b(100);
    EXPECT_EQ(0U, b.size());
    std::fill_n(b.data(), b.size(), 'x');

    b.resize(10);
    EXPECT_EQ(10U, b.size());
    std::fill_n(b.data(), b.size(), 'x');

    b.resize(101);
    EXPECT_EQ(101U, b.size());
    std::fill_n(b.data(), b.size(), 'x');

    b.clear();
    EXPECT_EQ(0U, b.size());

    b.resize(0);
    EXPECT_EQ(0U, b.size());

    b.resize(102);
    EXPECT_EQ(102U, b.size());
    std::fill_n(b.data(), b.size(), 'x');

    b.resize(0);
    EXPECT_EQ(0U, b.size());

    b.clear();
    EXPECT_EQ(0U, b.size());
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include "catch.hpp"

#define DLL_SVM_SUPPORT

#include "dll/dyn_conv_rbm.hpp"
#include "dll/conv_rbm.hpp"
#include "dll/random_layer.hpp"
#include "dll/dbn.hpp"

#include "mnist/mnist_reader.hpp"
#include "mnist/mnist_utils.hpp"

TEST_CASE("unit/cdbn/random/mnist/1", "[cdbn][rectifier][svm][unit]") {
    using dbn_t =
        dll::dbn_desc<dll::dbn_layers<
              dll::conv_rbm_desc_square<1, 28, 20, 12, dll::parallel_mode, dll::momentum, dll::batch_size<10>>::layer_t
            , dll::random_layer_desc::layer_t
            , dll::conv_rbm_desc_square<20, 12, 20, 10, dll::parallel_mode, dll::momentum, dll::batch_size<10>>::layer_t
        >>::dbn_t;

    auto dataset = mnist::read_dataset_direct<std::vector, etl::fast_dyn_matrix<double, 1, 28, 28>>(75);
    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->display();

    dbn->pretrain(dataset.training_images, 5);

    auto result = dbn->svm_train(dataset.training_images, dataset.training_labels);
    REQUIRE(result);

    auto test_error = dll::test_set(dbn, dataset.training_images, dataset.training_labels, dll::svm_predictor());
    std::cout << "test_error:" << test_error << std::endl;
    REQUIRE(test_error < 0.9);
}

TEST_CASE("unit/cdbn/random/mnist/2", "[cdbn][rectifier][svm][unit]") {
    using dbn_t =
        dll::dbn_desc<dll::dbn_layers<
              dll::dyn_conv_rbm_desc<dll::parallel_mode, dll::momentum>::layer_t
            , dll::random_layer_desc::layer_t
            , dll::dyn_conv_rbm_desc<dll::parallel_mode, dll::momentum>::layer_t
        >>::dbn_t;

    auto dataset = mnist::read_dataset_3d<std::vector, etl::dyn_matrix<double, 3>>(75);
    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->template layer_get<0>().init_layer(1, 28, 28, 20, 12, 12);
    dbn->template layer_get<2>().init_layer(20, 12, 12, 20, 10, 10);

    dbn->display();

    dbn->pretrain(dataset.training_images, 5);

    auto result = dbn->svm_train(dataset.training_images, dataset.training_labels);
    REQUIRE(result);

    auto test_error = dll::test_set(dbn, dataset.training_images, dataset.training_labels, dll::svm_predictor());
    std::cout << "test_error:" << test_error << std::endl;
    REQUIRE(test_error < 0.9);
}
<commit_msg>Test the new initialization<commit_after>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include "catch.hpp"

#define DLL_SVM_SUPPORT

#include "dll/dyn_conv_rbm.hpp"
#include "dll/conv_rbm.hpp"
#include "dll/random_layer.hpp"
#include "dll/dbn.hpp"

#include "mnist/mnist_reader.hpp"
#include "mnist/mnist_utils.hpp"

TEST_CASE("unit/cdbn/random/mnist/1", "[cdbn][rectifier][svm][unit]") {
    using dbn_t =
        dll::dbn_desc<dll::dbn_layers<
              dll::conv_rbm_desc_square<1, 28, 20, 12, dll::parallel_mode, dll::momentum, dll::batch_size<10>>::layer_t
            , dll::random_layer_desc::layer_t
            , dll::conv_rbm_desc_square<20, 12, 20, 10, dll::parallel_mode, dll::momentum, dll::batch_size<10>>::layer_t
        >>::dbn_t;

    auto dataset = mnist::read_dataset_direct<std::vector, etl::fast_dyn_matrix<double, 1, 28, 28>>(75);
    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->display();

    dbn->pretrain(dataset.training_images, 5);

    auto result = dbn->svm_train(dataset.training_images, dataset.training_labels);
    REQUIRE(result);

    auto test_error = dll::test_set(dbn, dataset.training_images, dataset.training_labels, dll::svm_predictor());
    std::cout << "test_error:" << test_error << std::endl;
    REQUIRE(test_error < 0.9);
}

TEST_CASE("unit/cdbn/random/mnist/2", "[cdbn][rectifier][svm][unit]") {
    using dbn_t =
        dll::dbn_desc<dll::dbn_layers<
              dll::dyn_conv_rbm_desc<dll::parallel_mode, dll::momentum>::layer_t
            , dll::random_layer_desc::layer_t
            , dll::dyn_conv_rbm_desc<dll::parallel_mode, dll::momentum>::layer_t
        >>::dbn_t;

    auto dataset = mnist::read_dataset_3d<std::vector, etl::dyn_matrix<double, 3>>(75);
    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->template init_layer<0>(1, 28, 28, 20, 12, 12);
    dbn->template init_layer<2>(20, 12, 12, 20, 10, 10);

    dbn->display();

    dbn->pretrain(dataset.training_images, 5);

    auto result = dbn->svm_train(dataset.training_images, dataset.training_labels);
    REQUIRE(result);

    auto test_error = dll::test_set(dbn, dataset.training_images, dataset.training_labels, dll::svm_predictor());
    std::cout << "test_error:" << test_error << std::endl;
    REQUIRE(test_error < 0.9);
}
<|endoftext|>


<commit_before>// FILE: dataperf.cpp
//
// DESCRIPTION:
//
//   Compare relative performance of data types in SystemC
//   by creating long loops and performing operations on the data.
//
// LICENSE:
//
//   Copyright 2014,2015 David C Black
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

#include "require_cxx11.h"
#include <cstdint>
#include <systemc>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <chrono>
#include <ctime>
#include <string>

using namespace std;
using namespace sc_dt;

namespace {
  chrono::time_point<chrono::system_clock> start, current;
  chrono::duration<double> elapsed_seconds;
  size_t loop_count = 1e8;
}

template<typename T>
void truncate(T& val)
{
  val = T(uint32_t(val)); // Truncate to 32 bits
}

template<>
void truncate<sc_bigint<32>>(sc_bigint<32>& val)
{
}

template<typename T>
void arithperf(void)
{
  cout << "Testing arithmetic " << typeid(T).name() << " occupies " << sizeof(T) << " bytes with loop_count=" << loop_count << " " << flush;
  T result =          1;
  T A      = 1103515245; // Linear congruential constants for 32 bit pseudo-random of max length
  T C      =      12345; // result = (A*result + C) & 0xFFFF_FFFF

  start = chrono::system_clock::now();
  for (size_t loop=loop_count; loop!=0; --loop)
  {
    // Compute
    result = A * result + C;
    truncate<T>(result);
  }
  cout << "result=" << fixed << setprecision(0) << result << " " << flush; // Ensure compiler doesn't optimize loop out
  current = chrono::system_clock::now();
  elapsed_seconds = current - start;
  cout << "elapsed time " << setprecision(6) << elapsed_seconds.count() << "s" << endl;
}

template<typename T>
void logicperf(void)
{
  cout << "Testing logic " << typeid(T).name() << " occupies " << sizeof(T) << " bytes with loop_count=" << loop_count << " " << flush;
  size_t tbits = 8*sizeof(T);
  size_t rbits = 17;
  size_t lbits = tbits - rbits;
  T val    =          1;
  T A      = 1103515245; // Linear congruential constants for 32 bit pseudo-random of max length
  T C      =      12345; // val    = (A^ror(val,rbits) ^ C) & 0xFFFF_FFFF
  T rhs, lhs;
  start = chrono::system_clock::now();
  for (size_t loop=loop_count; loop!=0; --loop)
  {
    // Compute
    rhs = (val >> rbits);
    lhs = ((rhs << rbits)^val);
    val = A ^ ((lhs<<lbits)|rhs) ^ C;
  }
  cout << "result=" << fixed << setprecision(0) << val << " " << flush; // Ensure compiler doesn't optimize loop out
  current = chrono::system_clock::now();
  elapsed_seconds = current - start;
  end_time = chrono::system_clock::to_time_t(current);
  cout << "elapsed time " << setprecision(6) << elapsed_seconds.count() << "s" << endl;
}

int sc_main(int argc, char* argv[])
{
  for (int i=1; i<argc; ++i) { // Process command-line
    string arg(argv[i]);
    if (arg.length()>1 and string("-help").find(arg) == 0) {
      cout
        << "SYNOPSIS\n"
        << "  " << argv[0] << " [LOOP_COUNT]\n"
        << "EXAMPLES\n"
        << "  " << argv[0] << "1e7\n"
        << endl
        ;
      return 0;
    } else if (arg.find_first_not_of("0123456789e") == string::npos) {
      istringstream is(arg);
      double d;
      is >> d;
      loop_count = d;
      sc_assert(loop_count != 0);
    }//endif
  }

  arithperf<int32_t>();
  arithperf<sc_int<32>>();
  arithperf<sc_bigint<32>>();
  arithperf<double>();
  arithperf<sc_fixed_fast<32,32>>();
  arithperf<sc_fixed<32,32>>();

  cout << endl;

  logicperf<int32_t>();
  logicperf<sc_int<32>>();
  logicperf<sc_bigint<32>>();
  logicperf<sc_lv<32>>();
  logicperf<sc_bv<32>>();

  cout << "\nCompleted all tests" << endl;
  return 0;
}

//End of file<commit_msg>Remove dependence on C++filt and typeid.name()<commit_after>// FILE: dataperf.cpp
//
// DESCRIPTION:
//
//   Compare relative performance of data types in SystemC
//   by creating long loops and performing operations on the data.
//
// LICENSE:
//
//   Copyright 2014,2015 David C Black
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

#include "require_cxx11.h"
#include <cstdint>
#include <systemc>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <chrono>
#include <ctime>
#include <string>

using namespace std;
using namespace sc_dt;

namespace {
  chrono::time_point<chrono::system_clock> start, current;
  chrono::duration<double> elapsed_seconds;
  size_t loop_count = 1e8;
}

template<typename T>
void truncate(T& val)
{
  val = T(uint32_t(val)); // Truncate to 32 bits
}

template<>
void truncate<sc_bigint<32>>(sc_bigint<32>& val)
{
}

template<typename T>
void arithperf(void)
{
  cout << "Testing arithmetic " << name << " occupies " << sizeof(T) << " bytes with loop_count=" << loop_count << " " << flush;
  T result = 1;
  T A      = 1103515245; // Linear congruential constants for 32 bit pseudo-random of max length
  T C      =      12345; // result = (A*result + C) & 0xFFFF_FFFF

  start = chrono::system_clock::now();
  for (size_t loop=loop_count; loop!=0; --loop)
  {
    // Compute
    result = A * result + C;    truncate<T>(result);
  }
  cout << "result=" << fixed << setprecision(0) << result << " " << flush; // Ensure compiler doesn't optimize loop out
  current = chrono::system_clock::now();
  elapsed_seconds = current - start;
  cout << "elapsed time " << setprecision(6) << elapsed_seconds.count() << "s" << endl;
}

template<typename T>
void logicperf(void)
{
  cout << "Testing logic " << name << " occupies " << sizeof(T) << " bytes with loop_count=" << loop_count << " " << flush;
  size_t tbits = 8*sizeof(T);
  size_t rbits = 17;
  size_t lbits = tbits - rbits;
  T val    =          1;
  T A      = 1103515245; // Linear congruential constants for 32 bit pseudo-random of max length
  T C      =      12345; // val    = (A^ror(val,rbits) ^ C) & 0xFFFF_FFFF
  T rhs, lhs;
  start = chrono::system_clock::now();
  for (size_t loop=loop_count; loop!=0; --loop)
  {
    // Compute
    rhs = (val >> rbits);
    lhs = ((rhs << rbits)^val);
    val = A ^ ((lhs<<lbits)|rhs) ^ C;
  }
  cout << "result=" << fixed << setprecision(0) << val << " " << flush; // Ensure compiler doesn't optimize loop out
  current = chrono::system_clock::now();
  elapsed_seconds = current - start;
  end_time = chrono::system_clock::to_time_t(current);
  cout << "elapsed time " << setprecision(6) << elapsed_seconds.count() << "s" << endl;
}

int sc_main(int argc, char* argv[])
{
  for (int i=1; i<argc; ++i) { // Process command-line
    string arg(argv[i]);
    if (arg.length()>1 and string("-help").find(arg) == 0) {
      cout
        << "SYNOPSIS\n"
        << "  " << argv[0] << " [LOOP_COUNT]\n"
        << "EXAMPLES\n"
        << "  " << argv[0] << "1e7\n"
        << endl
        ;
      return 0;
    } else if (arg.find_first_not_of("0123456789e") == string::npos) {
      istringstream is(arg);
      double d;
      is >> d;
      loop_count = d;
      sc_assert(loop_count != 0);
    }//endif
  }

  arithperf< int32_t              >( "int32_t"              );
  arithperf< sc_int<32>           >( "sc_int<32>"           );
  arithperf< sc_bigint<32>        >( "sc_bigint<32>"        );
  arithperf< double               >( "double"               );
  arithperf< sc_fixed_fast<32,32> >( "sc_fixed_fast<32,32>" );
  arithperf< sc_fixed<32,32>      >( "sc_fixed<32,32>"      );

  cout << endl;

  logicperf< int32_t       >( "int32_t"       );
  logicperf< sc_int<32>    >( "sc_int<32>"    );
  logicperf< sc_bigint<32> >( "sc_bigint<32>" );
  logicperf< sc_lv<32>     >( "sc_lv<32>"     );
  logicperf< sc_bv<32>     >( "sc_bv<32>"     );

  cout << "\nCompleted all tests" << endl;
  return 0;
}

//End of file<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <CppJieba/Limonp/ArgvContext.hpp>
#include <CppJieba/MPSegment.h>
#include <CppJieba/HMMSegment.h>
#include <CppJieba/MixSegment.h>

using namespace CppJieba;

void cut(const ISegment * seg, const char * const filePath)
{
    ifstream ifile(filePath);
    vector<string> res;
    string line;
    while(getline(ifile, line))
    {
        if(!line.empty())
        {
            res.clear();
            seg->cut(line, res);
            cout<<join(res.begin(), res.end(),"/")<<endl;
        }
    }
}

int main(int argc, char ** argv)
{
    //demo
    {
        HMMSegment seg;
        if(!seg.init("../dicts/jieba.dict.utf8"))
        {
            cout<<"seg init failed."<<endl;
            return EXIT_FAILURE;
        }
        cut(&seg, "testlines.utf8");
        seg.dispose();
    }
    {
        MixSegment seg;
        if(!seg.init("../dicts/jieba.dict.utf8", "../dicts/hmm_model.utf8"))
        {
            cout<<"seg init failed."<<endl;
            return EXIT_FAILURE;
        }
        cut(&seg, "testlines.utf8");
        seg.dispose();
    }
    {
        MPSegment seg;
        if(!seg.init("../dicts/jieba.dict.utf8"))
        {
            cout<<"seg init failed."<<endl;
            return false;
        }
        cut(&seg, "testlines.utf8");
        seg.dispose();
    }
    return EXIT_SUCCESS;
}
<commit_msg>modify test/segment.cpp<commit_after>#include <iostream>
#include <fstream>
#include <CppJieba/Limonp/ArgvContext.hpp>
#include <CppJieba/MPSegment.h>
#include <CppJieba/HMMSegment.h>
#include <CppJieba/MixSegment.h>

using namespace CppJieba;

void cut(const ISegment * seg, const char * const filePath)
{
    ifstream ifile(filePath);
    vector<string> res;
    string line;
    while(getline(ifile, line))
    {
        if(!line.empty())
        {
            res.clear();
            seg->cut(line, res);
            cout<<join(res.begin(), res.end(),"/")<<endl;
        }
    }
}

int main(int argc, char ** argv)
{
    //demo
    {
        HMMSegment seg;
        if(!seg.init("../dicts/hmm_model.utf8"))
        {
            cout<<"seg init failed."<<endl;
            return EXIT_FAILURE;
        }
        cut(&seg, "testlines.utf8");
        seg.dispose();
    }
    {
        MixSegment seg;
        if(!seg.init("../dicts/jieba.dict.utf8", "../dicts/hmm_model.utf8"))
        {
            cout<<"seg init failed."<<endl;
            return EXIT_FAILURE;
        }
        cut(&seg, "testlines.utf8");
        seg.dispose();
    }
    {
        MPSegment seg;
        if(!seg.init("../dicts/jieba.dict.utf8"))
        {
            cout<<"seg init failed."<<endl;
            return false;
        }
        cut(&seg, "testlines.utf8");
        seg.dispose();
    }
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "regex.hxx"
#include "pexpand.hxx"
#include "pool.hxx"

#include <inline/compiler.h>

#include <cppunit/CompilerOutputter.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>

#include <glib.h>

#include <string.h>
#include <stdlib.h>

class RegexTest : public CppUnit::TestFixture {
    CPPUNIT_TEST_SUITE(RegexTest);
    CPPUNIT_TEST(TestMatch1);
    CPPUNIT_TEST(TestMatch2);
    CPPUNIT_TEST(TestExpand);
    CPPUNIT_TEST_SUITE_END();

public:
    void TestMatch1() {
        UniqueRegex r;
        CPPUNIT_ASSERT(!r.IsDefined());
        CPPUNIT_ASSERT(r.Compile(".", false, nullptr));
        CPPUNIT_ASSERT(r.IsDefined());
        CPPUNIT_ASSERT(r.Match("a"));
        CPPUNIT_ASSERT(r.Match("abc"));
    }

    void TestMatch2() {
        UniqueRegex r = UniqueRegex();
        CPPUNIT_ASSERT(!r.IsDefined());
        CPPUNIT_ASSERT(r.Compile("..", false, nullptr));
        CPPUNIT_ASSERT(r.IsDefined());
        CPPUNIT_ASSERT(!r.Match("a"));
        CPPUNIT_ASSERT(r.Match("abc"));
    }

    void TestExpand() {
        UniqueRegex r;
        CPPUNIT_ASSERT(!r.IsDefined());
        CPPUNIT_ASSERT(r.Compile("^/foo/(\\w+)/([^/]+)/(.*)$", true, nullptr));
        CPPUNIT_ASSERT(r.IsDefined());

        CPPUNIT_ASSERT(!r.Match("a"));

        auto match_info = r.MatchCapture("/foo/bar/a/b/c.html");
        CPPUNIT_ASSERT(match_info.IsDefined());

        struct pool *pool = pool_new_libc(nullptr, "root");
        auto e = expand_string(pool, "\\1-\\2-\\3-\\\\", match_info, nullptr);
        CPPUNIT_ASSERT(e != nullptr);
        CPPUNIT_ASSERT(strcmp(e, "bar-a-b/c.html-\\") == 0);

        match_info = r.MatchCapture("/foo/bar/a%20b/c%2520.html");
        CPPUNIT_ASSERT(match_info.IsDefined());

        e = expand_string_unescaped(pool, "\\1-\\2-\\3", match_info, nullptr);
        CPPUNIT_ASSERT(e != nullptr);
        CPPUNIT_ASSERT(strcmp(e, "bar-a b-c%20.html") == 0);

        pool_unref(pool);
    }
};

CPPUNIT_TEST_SUITE_REGISTRATION(RegexTest);

int
main(gcc_unused int argc, gcc_unused char **argv)
{
    CppUnit::Test *suite =
        CppUnit::TestFactoryRegistry::getRegistry().makeTest();

    CppUnit::TextUi::TestRunner runner;
    runner.addTest(suite);

    runner.setOutputter(new CppUnit::CompilerOutputter(&runner.result(),
                                                       std::cerr));
    bool success = runner.run();

    return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
<commit_msg>test/t_regex: call pool_recycler_clear()<commit_after>#include "regex.hxx"
#include "pexpand.hxx"
#include "pool.hxx"

#include <inline/compiler.h>

#include <cppunit/CompilerOutputter.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>

#include <glib.h>

#include <string.h>
#include <stdlib.h>

class RegexTest : public CppUnit::TestFixture {
    CPPUNIT_TEST_SUITE(RegexTest);
    CPPUNIT_TEST(TestMatch1);
    CPPUNIT_TEST(TestMatch2);
    CPPUNIT_TEST(TestExpand);
    CPPUNIT_TEST_SUITE_END();

public:
    void TestMatch1() {
        UniqueRegex r;
        CPPUNIT_ASSERT(!r.IsDefined());
        CPPUNIT_ASSERT(r.Compile(".", false, nullptr));
        CPPUNIT_ASSERT(r.IsDefined());
        CPPUNIT_ASSERT(r.Match("a"));
        CPPUNIT_ASSERT(r.Match("abc"));
    }

    void TestMatch2() {
        UniqueRegex r = UniqueRegex();
        CPPUNIT_ASSERT(!r.IsDefined());
        CPPUNIT_ASSERT(r.Compile("..", false, nullptr));
        CPPUNIT_ASSERT(r.IsDefined());
        CPPUNIT_ASSERT(!r.Match("a"));
        CPPUNIT_ASSERT(r.Match("abc"));
    }

    void TestExpand() {
        UniqueRegex r;
        CPPUNIT_ASSERT(!r.IsDefined());
        CPPUNIT_ASSERT(r.Compile("^/foo/(\\w+)/([^/]+)/(.*)$", true, nullptr));
        CPPUNIT_ASSERT(r.IsDefined());

        CPPUNIT_ASSERT(!r.Match("a"));

        auto match_info = r.MatchCapture("/foo/bar/a/b/c.html");
        CPPUNIT_ASSERT(match_info.IsDefined());

        struct pool *pool = pool_new_libc(nullptr, "root");
        auto e = expand_string(pool, "\\1-\\2-\\3-\\\\", match_info, nullptr);
        CPPUNIT_ASSERT(e != nullptr);
        CPPUNIT_ASSERT(strcmp(e, "bar-a-b/c.html-\\") == 0);

        match_info = r.MatchCapture("/foo/bar/a%20b/c%2520.html");
        CPPUNIT_ASSERT(match_info.IsDefined());

        e = expand_string_unescaped(pool, "\\1-\\2-\\3", match_info, nullptr);
        CPPUNIT_ASSERT(e != nullptr);
        CPPUNIT_ASSERT(strcmp(e, "bar-a b-c%20.html") == 0);

        pool_unref(pool);
    }
};

CPPUNIT_TEST_SUITE_REGISTRATION(RegexTest);

int
main(gcc_unused int argc, gcc_unused char **argv)
{
    CppUnit::Test *suite =
        CppUnit::TestFactoryRegistry::getRegistry().makeTest();

    CppUnit::TextUi::TestRunner runner;
    runner.addTest(suite);

    runner.setOutputter(new CppUnit::CompilerOutputter(&runner.result(),
                                                       std::cerr));
    bool success = runner.run();

    pool_recycler_clear();
    return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
<|endoftext|>


<commit_before>
#include <test.hpp>

TEST_CASE("default constructed pbf_reader is okay") {
    protozero::pbf_reader item;

    REQUIRE(item.length() == 0);
    REQUIRE_FALSE(item); // test operator bool()
    REQUIRE_FALSE(item.next());
}

TEST_CASE("empty buffer in pbf_reader is okay") {
    const std::string buffer;
    protozero::pbf_reader item{buffer};

    REQUIRE(item.length() == 0);
    REQUIRE_FALSE(item); // test operator bool()
    REQUIRE_FALSE(item.next());
}

TEST_CASE("check every possible value for single byte in buffer") {
    char buffer;
    for (int i = 0; i <= 255; ++i) {
        buffer = static_cast<char>(i);
        protozero::pbf_reader item{&buffer, 1};

        REQUIRE(item.length() == 1);
        REQUIRE_FALSE(!item); // test operator bool()
        REQUIRE_THROWS((item.next(), item.skip()));
    }
}

TEST_CASE("next() should throw when illegal wire type is encountered") {
    const char buffer = 1u << 3u | 7u;

    protozero::pbf_reader item{&buffer, 1};
    REQUIRE_THROWS_AS(item.next(), const protozero::unknown_pbf_wire_type_exception&);
}

TEST_CASE("next() should throw when illegal tag is encountered") {
    std::string data;

    SECTION("tag 0") {
        protozero::write_varint(std::back_inserter(data), 0u << 3u | 1u);
    }

    SECTION("tag 19000") {
        protozero::write_varint(std::back_inserter(data), 19000u << 3u | 1u);
    }

    SECTION("tag 19001") {
        protozero::write_varint(std::back_inserter(data), 19001u << 3u | 1u);
    }

    SECTION("tag 19999") {
        protozero::write_varint(std::back_inserter(data), 19999u << 3u | 1u);
    }

    protozero::pbf_reader item{data};
    REQUIRE_THROWS_AS(item.next(), const protozero::invalid_tag_exception&);
}

TEST_CASE("next() works when a legal tag is encountered") {
    std::string data;

    SECTION("tag 1") {
        protozero::write_varint(std::back_inserter(data), 1u << 3u | 1u);
    }

    SECTION("tag 18999") {
        protozero::write_varint(std::back_inserter(data), 18999u << 3u | 1u);
    }

    SECTION("tag 20000") {
        protozero::write_varint(std::back_inserter(data), 20000u << 3u | 1u);
    }

    SECTION("tag 1^29 - 1") {
        protozero::write_varint(std::back_inserter(data), ((1u << 29u) - 1u) << 3u | 1u);
    }

    protozero::pbf_reader item{data};
    REQUIRE(item.next());
}

TEST_CASE("pbf_writer asserts on invalid tags") {
    std::string data;
    protozero::pbf_writer writer{data};

    REQUIRE_THROWS_AS(writer.add_int32(0, 123), const assert_error&);
    writer.add_int32(1, 123);
    writer.add_int32(2, 123);
    writer.add_int32(18999, 123);
    REQUIRE_THROWS_AS(writer.add_int32(19000, 123), const assert_error&);
    REQUIRE_THROWS_AS(writer.add_int32(19001, 123), const assert_error&);
    REQUIRE_THROWS_AS(writer.add_int32(19999, 123), const assert_error&);
    writer.add_int32(20000, 123);
    writer.add_int32((1u << 29u) - 1u, 123);
    REQUIRE_THROWS_AS(writer.add_int32(1u << 29u, 123), const assert_error&);
}

<commit_msg>Use TEST_CASEs instead of SECTIOs in some tests.<commit_after>
#include <test.hpp>

TEST_CASE("default constructed pbf_reader is okay") {
    protozero::pbf_reader item;

    REQUIRE(item.length() == 0);
    REQUIRE_FALSE(item); // test operator bool()
    REQUIRE_FALSE(item.next());
}

TEST_CASE("empty buffer in pbf_reader is okay") {
    const std::string buffer;
    protozero::pbf_reader item{buffer};

    REQUIRE(item.length() == 0);
    REQUIRE_FALSE(item); // test operator bool()
    REQUIRE_FALSE(item.next());
}

TEST_CASE("check every possible value for single byte in buffer") {
    char buffer;
    for (int i = 0; i <= 255; ++i) {
        buffer = static_cast<char>(i);
        protozero::pbf_reader item{&buffer, 1};

        REQUIRE(item.length() == 1);
        REQUIRE_FALSE(!item); // test operator bool()
        REQUIRE_THROWS((item.next(), item.skip()));
    }
}

TEST_CASE("next() should throw when illegal wire type is encountered") {
    const char buffer = 1u << 3u | 7u;

    protozero::pbf_reader item{&buffer, 1};
    REQUIRE_THROWS_AS(item.next(), const protozero::unknown_pbf_wire_type_exception&);
}

TEST_CASE("next() should throw when illegal tag 0 is encountered") {
    std::string data;
    protozero::write_varint(std::back_inserter(data), 0u << 3u | 1u);
    protozero::pbf_reader item{data};
    REQUIRE_THROWS_AS(item.next(), const protozero::invalid_tag_exception&);
}

TEST_CASE("next() should throw when illegal tag 19000 is encountered") {
    std::string data;
    protozero::write_varint(std::back_inserter(data), 19000u << 3u | 1u);
    protozero::pbf_reader item{data};
    REQUIRE_THROWS_AS(item.next(), const protozero::invalid_tag_exception&);
}

TEST_CASE("next() should throw when illegal tag 19001 is encountered") {
    std::string data;
    protozero::write_varint(std::back_inserter(data), 19001u << 3u | 1u);
    protozero::pbf_reader item{data};
    REQUIRE_THROWS_AS(item.next(), const protozero::invalid_tag_exception&);
}

TEST_CASE("next() should throw when illegal tag 19999 is encountered") {
    std::string data;
    protozero::write_varint(std::back_inserter(data), 19999u << 3u | 1u);
    protozero::pbf_reader item{data};
    REQUIRE_THROWS_AS(item.next(), const protozero::invalid_tag_exception&);
}

TEST_CASE("next() works when legal tag 1 is encountered") {
    std::string data;
    protozero::write_varint(std::back_inserter(data), 1u << 3u | 1u);
    protozero::pbf_reader item{data};
    REQUIRE(item.next());
}

TEST_CASE("next() works when legal tag 18999 is encountered") {
    std::string data;
    protozero::write_varint(std::back_inserter(data), 18999u << 3u | 1u);
    protozero::pbf_reader item{data};
    REQUIRE(item.next());
}

TEST_CASE("next() works when legal tag 20000 is encountered") {
    std::string data;
    protozero::write_varint(std::back_inserter(data), 20000u << 3u | 1u);
    protozero::pbf_reader item{data};
    REQUIRE(item.next());
}

TEST_CASE("next() works when legal tag 1^29 - 1 is encountered") {
    std::string data;
    protozero::write_varint(std::back_inserter(data), ((1ul << 29u) - 1u) << 3u | 1u);
    protozero::pbf_reader item{data};
    REQUIRE(item.next());
}

TEST_CASE("pbf_writer asserts on invalid tags") {
    std::string data;
    protozero::pbf_writer writer{data};

    REQUIRE_THROWS_AS(writer.add_int32(0, 123), const assert_error&);
    writer.add_int32(1, 123);
    writer.add_int32(2, 123);
    writer.add_int32(18999, 123);
    REQUIRE_THROWS_AS(writer.add_int32(19000, 123), const assert_error&);
    REQUIRE_THROWS_AS(writer.add_int32(19001, 123), const assert_error&);
    REQUIRE_THROWS_AS(writer.add_int32(19999, 123), const assert_error&);
    writer.add_int32(20000, 123);
    writer.add_int32((1u << 29u) - 1u, 123);
    REQUIRE_THROWS_AS(writer.add_int32(1u << 29u, 123), const assert_error&);
}

<|endoftext|>