<commit_before>// Copyright 2014 Alessio Sclocco <a.sclocco@vu.nl>
//
// 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 <iostream>
#include <string>
#include <vector>
#include <exception>
#include <fstream>
#include <iomanip>
#include <limits>

#include <ArgumentList.hpp>
#include <Observation.hpp>
#include <InitializeOpenCL.hpp>
#include <Kernel.hpp>
#include <Shifts.hpp>
#include <Dedispersion.hpp>
#include <utils.hpp>
#include <Timer.hpp>
#include <Stats.hpp>

typedef float dataType;
std::string typeName("float");

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< float > * shifts, cl::Buffer * shifts_d, const unsigned int shifts_size, cl::Buffer * dispersedData_d, const unsigned int dispersedData_size, cl::Buffer * dedispersedData_d, const unsigned int dedispersedData_size);

int main(int argc, char * argv[]) {
  bool localMem = false;
  bool reInit = false;
	unsigned int nrIterations = 0;
	unsigned int clPlatformID = 0;
	unsigned int clDeviceID = 0;
	unsigned int minThreads = 0;
  unsigned int maxThreads = 0;
	unsigned int maxRows = 0;
	unsigned int maxColumns = 0;
  unsigned int threadUnit = 0;
  unsigned int threadIncrement = 0;
  unsigned int maxItems = 0;
  unsigned int maxUnroll = 0;
  unsigned int maxLoopBodySize = 0;
  AstroData::Observation observation;
  cl::Event event;

	try {
    isa::utils::ArgumentList args(argc, argv);

		nrIterations = args.getSwitchArgument< unsigned int >("-iterations");
		clPlatformID = args.getSwitchArgument< unsigned int >("-opencl_platform");
		clDeviceID = args.getSwitchArgument< unsigned int >("-opencl_device");
    localMem = args.getSwitch("-local");
		observation.setPadding(args.getSwitchArgument< unsigned int >("-padding"));
    threadUnit = args.getSwitchArgument< unsigned int >("-thread_unit");
		minThreads = args.getSwitchArgument< unsigned int >("-min_threads");
		maxThreads = args.getSwitchArgument< unsigned int >("-max_threads");
		maxRows = args.getSwitchArgument< unsigned int >("-max_rows");
		maxColumns = args.getSwitchArgument< unsigned int >("-max_columns");
    threadIncrement = args.getSwitchArgument< unsigned int >("-thread_increment");
		maxItems = args.getSwitchArgument< unsigned int >("-max_items");
    maxUnroll = args.getSwitchArgument< unsigned int >("-max_unroll");
    maxLoopBodySize = args.getSwitchArgument< unsigned int >("-max_loopsize");
    observation.setFrequencyRange(args.getSwitchArgument< unsigned int >("-channels"), args.getSwitchArgument< float >("-min_freq"), args.getSwitchArgument< float >("-channel_bandwidth"));
		observation.setNrSamplesPerSecond(args.getSwitchArgument< unsigned int >("-samples"));
    observation.setDMRange(args.getSwitchArgument< unsigned int >("-dms"), args.getSwitchArgument< float >("-dm_first"), args.getSwitchArgument< float >("-dm_step"));
	} catch ( isa::utils::EmptyCommandLine & err ) {
		std::cerr << argv[0] << " -iterations ... -opencl_platform ... -opencl_device ... [-local] -padding ... -thread_unit ... -min_threads ... -max_threads ... -max_items ... -max_unroll ... -max_loopsize ... -max_columns ... -max_rows ... -thread_increment ... -min_freq ... -channel_bandwidth ... -samples ... -channels ... -dms ... -dm_first ... -dm_step ..." << std::endl;
		return 1;
	} catch ( std::exception & err ) {
		std::cerr << err.what() << std::endl;
		return 1;
	}

  // Allocate host memory
  std::vector< float > * shifts = PulsarSearch::getShifts(observation);
  observation.setNrSamplesPerDispersedChannel(observation.getNrSamplesPerSecond() + static_cast< unsigned int >(shifts->at(0) * (observation.getFirstDM() + ((observation.getNrDMs() - 1) * observation.getDMStep()))));

	// Initialize OpenCL
	cl::Context clContext;
	std::vector< cl::Platform > * clPlatforms = new std::vector< cl::Platform >();
	std::vector< cl::Device > * clDevices = new std::vector< cl::Device >();
	std::vector< std::vector< cl::CommandQueue > > * clQueues = new std::vector< std::vector < cl::CommandQueue > >();
  isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, &clContext, clDevices, clQueues);

	// Allocate device memory
  cl::Buffer shifts_d;
  cl::Buffer dispersedData_d;
  cl::Buffer dedispersedData_d;

  initializeDeviceMemory(clContext, &(clQueues->at(clDeviceID)[0]), shifts, &shifts_d, shifts->size(), &dispersedData_d, observation.getNrChannels() * observation.getNrSamplesPerDispersedChannel(), &dedispersedData_d, observation.getNrDMs() * observation.getNrSamplesPerPaddedSecond());

	// Find the parameters
	std::vector< unsigned int > samplesPerBlock;
	for ( unsigned int samples = minThreads; samples <= maxColumns; samples += threadIncrement ) {
		if ( (observation.getNrSamplesPerPaddedSecond() % samples) == 0 ) {
			samplesPerBlock.push_back(samples);
		}
	}
	std::vector< unsigned int > DMsPerBlock;
	for ( unsigned int DMs = 1; DMs <= maxRows; DMs++ ) {
		if ( (observation.getNrDMs() % DMs) == 0 ) {
			DMsPerBlock.push_back(DMs);
		}
	}

	std::cout << std::fixed << std::endl;
	std::cout << "# nrDMs nrChannels nrSamples local samplesPerBlock DMsPerBlock samplesPerThread DMsPerThread unroll GFLOP/s GB/s time stdDeviation COV" << std::endl << std::endl;

	for ( std::vector< unsigned int >::iterator samples = samplesPerBlock.begin(); samples != samplesPerBlock.end(); ++samples ) {
		for ( std::vector< unsigned int >::iterator DMs = DMsPerBlock.begin(); DMs != DMsPerBlock.end(); ++DMs ) {
			if ( ((*samples) * (*DMs)) > maxThreads ) {
				break;
			} else if ( ((*samples) * (*DMs)) % threadUnit != 0 ) {
        continue;
      }

			for ( unsigned int samplesPerThread = 1; samplesPerThread <= maxItems; samplesPerThread++ ) {
				if ( (observation.getNrSamplesPerPaddedSecond() % ((*samples) * samplesPerThread)) != 0 ) {
					continue;
				}

				for ( unsigned int DMsPerThread = 1; DMsPerThread <= maxItems; DMsPerThread++ ) {
					if ( (observation.getNrDMs() % ((*DMs) * DMsPerThread)) != 0 ) {
						continue;
					} else if ( (samplesPerThread * DMsPerThread) + DMsPerThread > maxItems ) {
						break;
					}

          for ( unsigned int unroll = 1; unroll <= maxUnroll; unroll++ ) {
            if ( (observation.getNrChannels() - 1) % unroll != 0 ) {
              continue;
            } else if ( (samplesPerThread * DMsPerThread * unroll) > maxLoopBodySize ) {
              break;
            }
            // Generate kernel
            double gflops = isa::utils::giga(static_cast< long long unsigned int >(observation.getNrDMs()) * observation.getNrChannels() * observation.getNrSamplesPerSecond());
            double gbs = isa::utils::giga(((static_cast< long long unsigned int >(observation.getNrDMs()) * observation.getNrSamplesPerSecond() * (observation.getNrChannels() + 1)) * sizeof(dataType)) + ((observation.getNrDMs() * observation.getNrChannels()) * sizeof(unsigned int)));
            isa::utils::Timer timer;
            cl::Kernel * kernel;
            std::string * code = PulsarSearch::getDedispersionOpenCL(localMem, *samples, *DMs, samplesPerThread, DMsPerThread, unroll, typeName, observation, *shifts);

            if ( reInit ) {
              isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, &clContext, clDevices, clQueues);
              initializeDeviceMemory(clContext, &(clQueues->at(clDeviceID)[0]), shifts, &shifts_d, shifts->size(), &dispersedData_d, observation.getNrChannels() * observation.getNrSamplesPerDispersedChannel(), &dedispersedData_d, observation.getNrDMs() * observation.getNrSamplesPerPaddedSecond());
              reInit = false;
            }
            try {
              kernel = isa::OpenCL::compile("dedispersion", *code, "-cl-mad-enable -Werror", clContext, clDevices->at(clDeviceID));
            } catch ( isa::OpenCL::OpenCLError & err ) {
              std::cerr << err.what() << std::endl;
              continue;
            }
            delete code;

            cl::NDRange global(observation.getNrSamplesPerPaddedSecond() / samplesPerThread, observation.getNrDMs() / DMsPerThread);
            cl::NDRange local(*samples, *DMs);

            kernel->setArg(0, dispersedData_d);
            kernel->setArg(1, dedispersedData_d);
            kernel->setArg(2, shifts_d);

            try {
              // Warm-up run
              clQueues->at(clDeviceID)[0].finish();
              clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &event);
              event.wait();
              // Tuning runs
              for ( unsigned int iteration = 0; iteration < nrIterations; iteration++ ) {
                timer.start();
                clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &event);
                event.wait();
                timer.stop();
              }
            } catch ( cl::Error & err ) {
              std::cerr << "OpenCL error kernel execution (";
              std::cerr << *samples << ", " << *DMs << ", " << samplesPerThread << ", " << DMsPerThread << "): ";
              std::cerr << isa::utils::toString(err.err()) << "." << std::endl;
              delete kernel;
              if ( err.err() == -36 ) {
                reInit = true;
              }
              continue;
            }
            delete kernel;

            std::cout << observation.getNrDMs() << " " << observation.getNrChannels() << " " << observation.getNrSamplesPerSecond() << " " << localMem << " " << *samples << " " << *DMs << " " << samplesPerThread << " " << DMsPerThread << " " << unroll << " ";
            std::cout << std::setprecision(3);
            std::cout << gflops / timer.getAverageTime() << " ";
            std::cout << gbs / timer.getAverageTime() << " ";
            std::cout << std::setprecision(6);
            std::cout << timer.getAverageTime() << " " << timer.getStandardDeviation() << " ";
            std::cout << timer.getCoefficientOfVariation() <<  std::endl;
          }
				}
			}
		}
	}

	std::cout << std::endl;

	return 0;
}

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< float > * shifts, cl::Buffer * shifts_d, const unsigned int shifts_size, cl::Buffer * dispersedData_d, const unsigned int dispersedData_size, cl::Buffer * dedispersedData_d, const unsigned int dedispersedData_size) {
  try {
    *shifts_d = cl::Buffer(clContext, CL_MEM_READ_ONLY, shifts_size * sizeof(float), 0, 0);
    *dispersedData_d = cl::Buffer(clContext, CL_MEM_READ_ONLY, dispersedData_size * sizeof(dataType), 0, 0);
    *dedispersedData_d = cl::Buffer(clContext, CL_MEM_READ_WRITE, dedispersedData_size * sizeof(dataType), 0, 0);
    clQueue->enqueueWriteBuffer(*shifts_d, CL_FALSE, 0, shifts_size * sizeof(float), reinterpret_cast< void * >(shifts->data()));
  } catch ( cl::Error & err ) {
    std::cerr << "OpenCL error: " << isa::utils::toString(err.err()) << "." << std::endl;
  }
}

<commit_msg>Too many queues were created, fixed.<commit_after>// Copyright 2014 Alessio Sclocco <a.sclocco@vu.nl>
//
// 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 <iostream>
#include <string>
#include <vector>
#include <exception>
#include <fstream>
#include <iomanip>
#include <limits>

#include <ArgumentList.hpp>
#include <Observation.hpp>
#include <InitializeOpenCL.hpp>
#include <Kernel.hpp>
#include <Shifts.hpp>
#include <Dedispersion.hpp>
#include <utils.hpp>
#include <Timer.hpp>
#include <Stats.hpp>

typedef float dataType;
std::string typeName("float");

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< float > * shifts, cl::Buffer * shifts_d, const unsigned int shifts_size, cl::Buffer * dispersedData_d, const unsigned int dispersedData_size, cl::Buffer * dedispersedData_d, const unsigned int dedispersedData_size);

int main(int argc, char * argv[]) {
  bool localMem = false;
  bool reInit = false;
	unsigned int nrIterations = 0;
	unsigned int clPlatformID = 0;
	unsigned int clDeviceID = 0;
	unsigned int minThreads = 0;
  unsigned int maxThreads = 0;
	unsigned int maxRows = 0;
	unsigned int maxColumns = 0;
  unsigned int threadUnit = 0;
  unsigned int threadIncrement = 0;
  unsigned int maxItems = 0;
  unsigned int maxUnroll = 0;
  unsigned int maxLoopBodySize = 0;
  AstroData::Observation observation;
  cl::Event event;

	try {
    isa::utils::ArgumentList args(argc, argv);

		nrIterations = args.getSwitchArgument< unsigned int >("-iterations");
		clPlatformID = args.getSwitchArgument< unsigned int >("-opencl_platform");
		clDeviceID = args.getSwitchArgument< unsigned int >("-opencl_device");
    localMem = args.getSwitch("-local");
		observation.setPadding(args.getSwitchArgument< unsigned int >("-padding"));
    threadUnit = args.getSwitchArgument< unsigned int >("-thread_unit");
		minThreads = args.getSwitchArgument< unsigned int >("-min_threads");
		maxThreads = args.getSwitchArgument< unsigned int >("-max_threads");
		maxRows = args.getSwitchArgument< unsigned int >("-max_rows");
		maxColumns = args.getSwitchArgument< unsigned int >("-max_columns");
    threadIncrement = args.getSwitchArgument< unsigned int >("-thread_increment");
		maxItems = args.getSwitchArgument< unsigned int >("-max_items");
    maxUnroll = args.getSwitchArgument< unsigned int >("-max_unroll");
    maxLoopBodySize = args.getSwitchArgument< unsigned int >("-max_loopsize");
    observation.setFrequencyRange(args.getSwitchArgument< unsigned int >("-channels"), args.getSwitchArgument< float >("-min_freq"), args.getSwitchArgument< float >("-channel_bandwidth"));
		observation.setNrSamplesPerSecond(args.getSwitchArgument< unsigned int >("-samples"));
    observation.setDMRange(args.getSwitchArgument< unsigned int >("-dms"), args.getSwitchArgument< float >("-dm_first"), args.getSwitchArgument< float >("-dm_step"));
	} catch ( isa::utils::EmptyCommandLine & err ) {
		std::cerr << argv[0] << " -iterations ... -opencl_platform ... -opencl_device ... [-local] -padding ... -thread_unit ... -min_threads ... -max_threads ... -max_items ... -max_unroll ... -max_loopsize ... -max_columns ... -max_rows ... -thread_increment ... -min_freq ... -channel_bandwidth ... -samples ... -channels ... -dms ... -dm_first ... -dm_step ..." << std::endl;
		return 1;
	} catch ( std::exception & err ) {
		std::cerr << err.what() << std::endl;
		return 1;
	}

  // Allocate host memory
  std::vector< float > * shifts = PulsarSearch::getShifts(observation);
  observation.setNrSamplesPerDispersedChannel(observation.getNrSamplesPerSecond() + static_cast< unsigned int >(shifts->at(0) * (observation.getFirstDM() + ((observation.getNrDMs() - 1) * observation.getDMStep()))));

	// Initialize OpenCL
	cl::Context clContext;
	std::vector< cl::Platform > * clPlatforms = new std::vector< cl::Platform >();
	std::vector< cl::Device > * clDevices = new std::vector< cl::Device >();
	std::vector< std::vector< cl::CommandQueue > > * clQueues = new std::vector< std::vector < cl::CommandQueue > >();
  isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, &clContext, clDevices, clQueues);

	// Allocate device memory
  cl::Buffer shifts_d;
  cl::Buffer dispersedData_d;
  cl::Buffer dedispersedData_d;

  initializeDeviceMemory(clContext, &(clQueues->at(clDeviceID)[0]), shifts, &shifts_d, shifts->size(), &dispersedData_d, observation.getNrChannels() * observation.getNrSamplesPerDispersedChannel(), &dedispersedData_d, observation.getNrDMs() * observation.getNrSamplesPerPaddedSecond());

	// Find the parameters
	std::vector< unsigned int > samplesPerBlock;
	for ( unsigned int samples = minThreads; samples <= maxColumns; samples += threadIncrement ) {
		if ( (observation.getNrSamplesPerPaddedSecond() % samples) == 0 ) {
			samplesPerBlock.push_back(samples);
		}
	}
	std::vector< unsigned int > DMsPerBlock;
	for ( unsigned int DMs = 1; DMs <= maxRows; DMs++ ) {
		if ( (observation.getNrDMs() % DMs) == 0 ) {
			DMsPerBlock.push_back(DMs);
		}
	}

	std::cout << std::fixed << std::endl;
	std::cout << "# nrDMs nrChannels nrSamples local samplesPerBlock DMsPerBlock samplesPerThread DMsPerThread unroll GFLOP/s GB/s time stdDeviation COV" << std::endl << std::endl;

	for ( std::vector< unsigned int >::iterator samples = samplesPerBlock.begin(); samples != samplesPerBlock.end(); ++samples ) {
		for ( std::vector< unsigned int >::iterator DMs = DMsPerBlock.begin(); DMs != DMsPerBlock.end(); ++DMs ) {
			if ( ((*samples) * (*DMs)) > maxThreads ) {
				break;
			} else if ( ((*samples) * (*DMs)) % threadUnit != 0 ) {
        continue;
      }

			for ( unsigned int samplesPerThread = 1; samplesPerThread <= maxItems; samplesPerThread++ ) {
				if ( (observation.getNrSamplesPerPaddedSecond() % ((*samples) * samplesPerThread)) != 0 ) {
					continue;
				}

				for ( unsigned int DMsPerThread = 1; DMsPerThread <= maxItems; DMsPerThread++ ) {
					if ( (observation.getNrDMs() % ((*DMs) * DMsPerThread)) != 0 ) {
						continue;
					} else if ( (samplesPerThread * DMsPerThread) + DMsPerThread > maxItems ) {
						break;
					}

          for ( unsigned int unroll = 1; unroll <= maxUnroll; unroll++ ) {
            if ( (observation.getNrChannels() - 1) % unroll != 0 ) {
              continue;
            } else if ( (samplesPerThread * DMsPerThread * unroll) > maxLoopBodySize ) {
              break;
            }
            // Generate kernel
            double gflops = isa::utils::giga(static_cast< long long unsigned int >(observation.getNrDMs()) * observation.getNrChannels() * observation.getNrSamplesPerSecond());
            double gbs = isa::utils::giga(((static_cast< long long unsigned int >(observation.getNrDMs()) * observation.getNrSamplesPerSecond() * (observation.getNrChannels() + 1)) * sizeof(dataType)) + ((observation.getNrDMs() * observation.getNrChannels()) * sizeof(unsigned int)));
            isa::utils::Timer timer;
            cl::Kernel * kernel;
            std::string * code = PulsarSearch::getDedispersionOpenCL(localMem, *samples, *DMs, samplesPerThread, DMsPerThread, unroll, typeName, observation, *shifts);

            if ( reInit ) {
              delete clQueues;
              clQueues = new std::vector< std::vector < cl::CommandQueue > >();
              isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, &clContext, clDevices, clQueues);
              initializeDeviceMemory(clContext, &(clQueues->at(clDeviceID)[0]), shifts, &shifts_d, shifts->size(), &dispersedData_d, observation.getNrChannels() * observation.getNrSamplesPerDispersedChannel(), &dedispersedData_d, observation.getNrDMs() * observation.getNrSamplesPerPaddedSecond());
              reInit = false;
            }
            try {
              kernel = isa::OpenCL::compile("dedispersion", *code, "-cl-mad-enable -Werror", clContext, clDevices->at(clDeviceID));
            } catch ( isa::OpenCL::OpenCLError & err ) {
              std::cerr << err.what() << std::endl;
              continue;
            }
            delete code;

            cl::NDRange global(observation.getNrSamplesPerPaddedSecond() / samplesPerThread, observation.getNrDMs() / DMsPerThread);
            cl::NDRange local(*samples, *DMs);

            kernel->setArg(0, dispersedData_d);
            kernel->setArg(1, dedispersedData_d);
            kernel->setArg(2, shifts_d);

            try {
              // Warm-up run
              clQueues->at(clDeviceID)[0].finish();
              clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &event);
              event.wait();
              // Tuning runs
              for ( unsigned int iteration = 0; iteration < nrIterations; iteration++ ) {
                timer.start();
                clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &event);
                event.wait();
                timer.stop();
              }
            } catch ( cl::Error & err ) {
              std::cerr << "OpenCL error kernel execution (";
              std::cerr << *samples << ", " << *DMs << ", " << samplesPerThread << ", " << DMsPerThread << "): ";
              std::cerr << isa::utils::toString(err.err()) << "." << std::endl;
              delete kernel;
              if ( err.err() == -36 ) {
                reInit = true;
              }
              continue;
            }
            delete kernel;

            std::cout << observation.getNrDMs() << " " << observation.getNrChannels() << " " << observation.getNrSamplesPerSecond() << " " << localMem << " " << *samples << " " << *DMs << " " << samplesPerThread << " " << DMsPerThread << " " << unroll << " ";
            std::cout << std::setprecision(3);
            std::cout << gflops / timer.getAverageTime() << " ";
            std::cout << gbs / timer.getAverageTime() << " ";
            std::cout << std::setprecision(6);
            std::cout << timer.getAverageTime() << " " << timer.getStandardDeviation() << " ";
            std::cout << timer.getCoefficientOfVariation() <<  std::endl;
          }
				}
			}
		}
	}

	std::cout << std::endl;

	return 0;
}

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< float > * shifts, cl::Buffer * shifts_d, const unsigned int shifts_size, cl::Buffer * dispersedData_d, const unsigned int dispersedData_size, cl::Buffer * dedispersedData_d, const unsigned int dedispersedData_size) {
  try {
    *shifts_d = cl::Buffer(clContext, CL_MEM_READ_ONLY, shifts_size * sizeof(float), 0, 0);
    *dispersedData_d = cl::Buffer(clContext, CL_MEM_READ_ONLY, dispersedData_size * sizeof(dataType), 0, 0);
    *dedispersedData_d = cl::Buffer(clContext, CL_MEM_READ_WRITE, dedispersedData_size * sizeof(dataType), 0, 0);
    clQueue->enqueueWriteBuffer(*shifts_d, CL_FALSE, 0, shifts_size * sizeof(float), reinterpret_cast< void * >(shifts->data()));
  } catch ( cl::Error & err ) {
    std::cerr << "OpenCL error: " << isa::utils::toString(err.err()) << "." << std::endl;
  }
}

<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2015 Realm Inc.
//
// 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 "index_set.hpp"

#include <realm/util/assert.hpp>

using namespace realm;

const size_t IndexSet::npos;

IndexSet::IndexSet(std::initializer_list<size_t> values)
{
    for (size_t v : values)
        add(v);
}

bool IndexSet::contains(size_t index) const
{
    auto it = const_cast<IndexSet*>(this)->find(index);
    return it != m_ranges.end() && it->first <= index;
}

size_t IndexSet::count(size_t start_index, size_t end_index) const
{
    auto it = const_cast<IndexSet*>(this)->find(start_index);
    size_t ret = 0;
    for (; end_index > start_index && it != m_ranges.end() && it->first < end_index; ++it) {
        ret += std::min(it->second, end_index) - std::max(it->first, start_index);
        start_index = it->second;
    }
    return ret;
}

IndexSet::iterator IndexSet::find(size_t index)
{
    return find(index, m_ranges.begin());
}

IndexSet::iterator IndexSet::find(size_t index, iterator it)
{
    for (auto end = m_ranges.end(); it != end; ++it) {
        if (it->second > index)
            return it;
    }
    return m_ranges.end();
}

void IndexSet::add(size_t index)
{
    do_add(find(index), index);
}

void IndexSet::add(IndexSet const& other)
{
    auto it = m_ranges.begin();
    for (size_t index : other.as_indexes()) {
        it = do_add(find(index, it), index);
    }
}

size_t IndexSet::add_shifted(size_t index)
{
    auto it = m_ranges.begin();
    for (auto end = m_ranges.end(); it != end && it->first <= index; ++it) {
        index += it->second - it->first;
    }
    do_add(it, index);
    return index;
}

void IndexSet::add_shifted_by(IndexSet const& shifted_by, IndexSet const& values)
{
#ifdef REALM_DEBUG
    size_t expected = std::distance(as_indexes().begin(), as_indexes().end());
    for (auto index : values.as_indexes()) {
        if (!shifted_by.contains(index))
            ++expected;
    }
#endif

    auto it = shifted_by.begin(), end = shifted_by.end();
    size_t shift = 0;
    size_t skip_until = 0;
    for (size_t index : values.as_indexes()) {
        for (; it != end && it->first <= index; ++it) {
            shift += it->second - it->first;
            skip_until = it->second;
        }
        if (index >= skip_until) {
            REALM_ASSERT(index >= shift);
            add_shifted(index - shift);
            ++shift;
        }
    }

    REALM_ASSERT_DEBUG(std::distance(as_indexes().begin(), as_indexes().end()) == expected);
}

void IndexSet::set(size_t len)
{
    m_ranges.clear();
    if (len) {
        m_ranges.push_back({0, len});
    }
}

void IndexSet::insert_at(size_t index, size_t count)
{
    REALM_ASSERT(count > 0);

    auto pos = find(index);
    bool in_existing = false;
    if (pos != m_ranges.end()) {
        if (pos->first <= index)
            in_existing = true;
        else
            pos->first += count;
        pos->second += count;
        for (auto it = pos + 1; it != m_ranges.end(); ++it) {
            it->first += count;
            it->second += count;
        }
    }
    if (!in_existing) {
        for (size_t i = 0; i < count; ++i)
            pos = do_add(pos, index + i) + 1;
    }
}

void IndexSet::insert_at(IndexSet const& positions)
{
    for (auto range : positions) {
        insert_at(range.first, range.second - range.first);
    }
}

void IndexSet::shift_for_insert_at(size_t index, size_t count)
{
    REALM_ASSERT(count > 0);

    auto it = find(index);
    if (it == m_ranges.end())
        return;

    if (it->first < index) {
        // split the range so that we can exclude `index`
        auto old_second = it->second;
        it->second = index;
        it = m_ranges.insert(it + 1, {index, old_second});
    }

    for (; it != m_ranges.end(); ++it) {
        it->first += count;
        it->second += count;
    }
}

void IndexSet::shift_for_insert_at(realm::IndexSet const& values)
{
    for (auto range : values)
        shift_for_insert_at(range.first, range.second - range.first);
}

void IndexSet::erase_at(size_t index)
{
    auto it = find(index);
    if (it != m_ranges.end())
        do_erase(it, index);
}

void IndexSet::erase_at(realm::IndexSet const& values)
{
    size_t shift = 0;
    for (auto index : values.as_indexes())
        erase_at(index - shift++);
}

size_t IndexSet::erase_and_unshift(size_t index)
{
    auto shifted = index;
    auto it = m_ranges.begin(), end = m_ranges.end();
    for (; it != end && it->second <= index; ++it) {
        shifted -= it->second - it->first;
    }
    if (it == end)
        return shifted;

    if (it->first <= index)
        shifted = npos;

    do_erase(it, index);

    return shifted;
}

void IndexSet::do_erase(iterator it, size_t index)
{
    if (it->first <= index) {
        --it->second;
        if (it->first == it->second) {
            it = m_ranges.erase(it);
        }
        else {
            ++it;
        }
    }
    else if (it != m_ranges.begin() && (it - 1)->second + 1 == it->first) {
        (it - 1)->second = it->second - 1;
        it = m_ranges.erase(it);
    }

    for (; it != m_ranges.end(); ++it) {
        --it->first;
        --it->second;
    }
}

IndexSet::iterator IndexSet::do_remove(iterator it, size_t begin, size_t end)
{
    for (it = find(begin, it); it != m_ranges.end() && it->first < end; it = find(begin, it)) {
        // Trim off any part of the range to remove that's before the matching range
        begin = std::max(it->first, begin);

        // If the matching range extends to both sides of the range to remove,
        // split it on the range to remove
        if (it->first < begin && it->second > end) {
            it = m_ranges.insert(it + 1, {end, it->second}) - 1;
            it->second = begin;
        }

        // Range to delete now coverages (at least) one end of the matching range
        if (begin == it->first && end >= it->second)
            it = m_ranges.erase(it);
        else if (begin == it->first)
            it->first = end;
        else
            it->second = begin;
    }
    return it;
}

void IndexSet::remove(size_t index, size_t count)
{
    do_remove(find(index), index, index + count);
}

void IndexSet::remove(realm::IndexSet const& values)
{
    auto it = m_ranges.begin();
    for (auto range : values) {
        it = do_remove(it, range.first, range.second);
        if (it == m_ranges.end())
            return;
    }
}

size_t IndexSet::shift(size_t index) const
{
    for (auto range : m_ranges) {
        if (range.first > index)
            break;
        index += range.second - range.first;
    }
    return index;
}

size_t IndexSet::unshift(size_t index) const
{
    REALM_ASSERT_DEBUG(!contains(index));
    auto shifted = index;
    for (auto range : m_ranges) {
        if (range.first >= index)
            break;
        shifted -= std::min(range.second, index) - range.first;
    }
    return shifted;
}

void IndexSet::clear()
{
    m_ranges.clear();
}

IndexSet::iterator IndexSet::do_add(iterator it, size_t index)
{
    verify();
    bool more_before = it != m_ranges.begin(), valid = it != m_ranges.end();
    REALM_ASSERT(!more_before || index >= (it - 1)->second);
    if (valid && it->first <= index && it->second > index) {
        // index is already in set
        return it;
    }
    if (more_before && (it - 1)->second == index) {
        // index is immediately after an existing range
        ++(it - 1)->second;

        if (valid && (it - 1)->second == it->first) {
            // index joins two existing ranges
            (it - 1)->second = it->second;
            return m_ranges.erase(it) - 1;
        }
        return it - 1;
    }
    if (valid && it->first == index + 1) {
        // index is immediately before an existing range
        --it->first;
        return it;
    }

    // index is not next to an existing range
    return m_ranges.insert(it, {index, index + 1});
}

void IndexSet::verify() const noexcept
{
#ifdef REALM_DEBUG
    size_t prev_end = -1;
    for (auto range : m_ranges) {
        REALM_ASSERT(range.first < range.second);
        REALM_ASSERT(prev_end == size_t(-1) || range.first > prev_end);
        prev_end = range.second;
    }
#endif
}
<commit_msg>Use binary search in IndexSet::find()<commit_after>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2015 Realm Inc.
//
// 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 "index_set.hpp"

#include <realm/util/assert.hpp>

using namespace realm;

const size_t IndexSet::npos;

IndexSet::IndexSet(std::initializer_list<size_t> values)
{
    for (size_t v : values)
        add(v);
}

bool IndexSet::contains(size_t index) const
{
    auto it = const_cast<IndexSet*>(this)->find(index);
    return it != m_ranges.end() && it->first <= index;
}

size_t IndexSet::count(size_t start_index, size_t end_index) const
{
    auto it = const_cast<IndexSet*>(this)->find(start_index);
    size_t ret = 0;
    for (; end_index > start_index && it != m_ranges.end() && it->first < end_index; ++it) {
        ret += std::min(it->second, end_index) - std::max(it->first, start_index);
        start_index = it->second;
    }
    return ret;
}

IndexSet::iterator IndexSet::find(size_t index)
{
    return find(index, m_ranges.begin());
}

IndexSet::iterator IndexSet::find(size_t index, iterator it)
{
    return std::lower_bound(it, m_ranges.end(), std::make_pair(size_t(0), index + 1),
                            [&](auto const& a, auto const& b) { return a.second < b.second; });
}

void IndexSet::add(size_t index)
{
    do_add(find(index), index);
}

void IndexSet::add(IndexSet const& other)
{
    auto it = m_ranges.begin();
    for (size_t index : other.as_indexes()) {
        it = do_add(find(index, it), index);
    }
}

size_t IndexSet::add_shifted(size_t index)
{
    auto it = m_ranges.begin();
    for (auto end = m_ranges.end(); it != end && it->first <= index; ++it) {
        index += it->second - it->first;
    }
    do_add(it, index);
    return index;
}

void IndexSet::add_shifted_by(IndexSet const& shifted_by, IndexSet const& values)
{
#ifdef REALM_DEBUG
    size_t expected = std::distance(as_indexes().begin(), as_indexes().end());
    for (auto index : values.as_indexes()) {
        if (!shifted_by.contains(index))
            ++expected;
    }
#endif

    auto it = shifted_by.begin(), end = shifted_by.end();
    size_t shift = 0;
    size_t skip_until = 0;
    for (size_t index : values.as_indexes()) {
        for (; it != end && it->first <= index; ++it) {
            shift += it->second - it->first;
            skip_until = it->second;
        }
        if (index >= skip_until) {
            REALM_ASSERT(index >= shift);
            add_shifted(index - shift);
            ++shift;
        }
    }

    REALM_ASSERT_DEBUG(std::distance(as_indexes().begin(), as_indexes().end()) == expected);
}

void IndexSet::set(size_t len)
{
    m_ranges.clear();
    if (len) {
        m_ranges.push_back({0, len});
    }
}

void IndexSet::insert_at(size_t index, size_t count)
{
    REALM_ASSERT(count > 0);

    auto pos = find(index);
    bool in_existing = false;
    if (pos != m_ranges.end()) {
        if (pos->first <= index)
            in_existing = true;
        else
            pos->first += count;
        pos->second += count;
        for (auto it = pos + 1; it != m_ranges.end(); ++it) {
            it->first += count;
            it->second += count;
        }
    }
    if (!in_existing) {
        for (size_t i = 0; i < count; ++i)
            pos = do_add(pos, index + i) + 1;
    }
}

void IndexSet::insert_at(IndexSet const& positions)
{
    for (auto range : positions) {
        insert_at(range.first, range.second - range.first);
    }
}

void IndexSet::shift_for_insert_at(size_t index, size_t count)
{
    REALM_ASSERT(count > 0);

    auto it = find(index);
    if (it == m_ranges.end())
        return;

    if (it->first < index) {
        // split the range so that we can exclude `index`
        auto old_second = it->second;
        it->second = index;
        it = m_ranges.insert(it + 1, {index, old_second});
    }

    for (; it != m_ranges.end(); ++it) {
        it->first += count;
        it->second += count;
    }
}

void IndexSet::shift_for_insert_at(realm::IndexSet const& values)
{
    for (auto range : values)
        shift_for_insert_at(range.first, range.second - range.first);
}

void IndexSet::erase_at(size_t index)
{
    auto it = find(index);
    if (it != m_ranges.end())
        do_erase(it, index);
}

void IndexSet::erase_at(realm::IndexSet const& values)
{
    size_t shift = 0;
    for (auto index : values.as_indexes())
        erase_at(index - shift++);
}

size_t IndexSet::erase_and_unshift(size_t index)
{
    auto shifted = index;
    auto it = m_ranges.begin(), end = m_ranges.end();
    for (; it != end && it->second <= index; ++it) {
        shifted -= it->second - it->first;
    }
    if (it == end)
        return shifted;

    if (it->first <= index)
        shifted = npos;

    do_erase(it, index);

    return shifted;
}

void IndexSet::do_erase(iterator it, size_t index)
{
    if (it->first <= index) {
        --it->second;
        if (it->first == it->second) {
            it = m_ranges.erase(it);
        }
        else {
            ++it;
        }
    }
    else if (it != m_ranges.begin() && (it - 1)->second + 1 == it->first) {
        (it - 1)->second = it->second - 1;
        it = m_ranges.erase(it);
    }

    for (; it != m_ranges.end(); ++it) {
        --it->first;
        --it->second;
    }
}

IndexSet::iterator IndexSet::do_remove(iterator it, size_t begin, size_t end)
{
    for (it = find(begin, it); it != m_ranges.end() && it->first < end; it = find(begin, it)) {
        // Trim off any part of the range to remove that's before the matching range
        begin = std::max(it->first, begin);

        // If the matching range extends to both sides of the range to remove,
        // split it on the range to remove
        if (it->first < begin && it->second > end) {
            it = m_ranges.insert(it + 1, {end, it->second}) - 1;
            it->second = begin;
        }

        // Range to delete now coverages (at least) one end of the matching range
        if (begin == it->first && end >= it->second)
            it = m_ranges.erase(it);
        else if (begin == it->first)
            it->first = end;
        else
            it->second = begin;
    }
    return it;
}

void IndexSet::remove(size_t index, size_t count)
{
    do_remove(find(index), index, index + count);
}

void IndexSet::remove(realm::IndexSet const& values)
{
    auto it = m_ranges.begin();
    for (auto range : values) {
        it = do_remove(it, range.first, range.second);
        if (it == m_ranges.end())
            return;
    }
}

size_t IndexSet::shift(size_t index) const
{
    for (auto range : m_ranges) {
        if (range.first > index)
            break;
        index += range.second - range.first;
    }
    return index;
}

size_t IndexSet::unshift(size_t index) const
{
    REALM_ASSERT_DEBUG(!contains(index));
    auto shifted = index;
    for (auto range : m_ranges) {
        if (range.first >= index)
            break;
        shifted -= std::min(range.second, index) - range.first;
    }
    return shifted;
}

void IndexSet::clear()
{
    m_ranges.clear();
}

IndexSet::iterator IndexSet::do_add(iterator it, size_t index)
{
    verify();
    bool more_before = it != m_ranges.begin(), valid = it != m_ranges.end();
    REALM_ASSERT(!more_before || index >= (it - 1)->second);
    if (valid && it->first <= index && it->second > index) {
        // index is already in set
        return it;
    }
    if (more_before && (it - 1)->second == index) {
        // index is immediately after an existing range
        ++(it - 1)->second;

        if (valid && (it - 1)->second == it->first) {
            // index joins two existing ranges
            (it - 1)->second = it->second;
            return m_ranges.erase(it) - 1;
        }
        return it - 1;
    }
    if (valid && it->first == index + 1) {
        // index is immediately before an existing range
        --it->first;
        return it;
    }

    // index is not next to an existing range
    return m_ranges.insert(it, {index, index + 1});
}

void IndexSet::verify() const noexcept
{
#ifdef REALM_DEBUG
    size_t prev_end = -1;
    for (auto range : m_ranges) {
        REALM_ASSERT(range.first < range.second);
        REALM_ASSERT(prev_end == size_t(-1) || range.first > prev_end);
        prev_end = range.second;
    }
#endif
}
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkImageMapToWindowLevelColors.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkImageMapToWindowLevelColors.h"

#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkScalarsToColors.h"
#include "vtkPointData.h"

vtkCxxRevisionMacro(vtkImageMapToWindowLevelColors, "1.22");
vtkStandardNewMacro(vtkImageMapToWindowLevelColors);

// Constructor sets default values
vtkImageMapToWindowLevelColors::vtkImageMapToWindowLevelColors()
{
  this->Window = 255;
  this->Level  = 127.5;
}

vtkImageMapToWindowLevelColors::~vtkImageMapToWindowLevelColors()
{
}

//----------------------------------------------------------------------------
// This method checks to see if we can simply reference the input data
int vtkImageMapToWindowLevelColors::RequestData(
  vtkInformation *request,
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *outInfo = outputVector->GetInformationObject(0);
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);

  vtkImageData *outData = vtkImageData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkImageData *inData = vtkImageData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  // If LookupTable is null and window / level produces no change,
  // then just pass the data
  if (this->LookupTable == NULL &&
      (inData->GetScalarType() == VTK_UNSIGNED_CHAR &&
       this->Window == 255 && this->Level == 127.5))
    {
    vtkDebugMacro("ExecuteData: LookupTable not set, "\
                  "Window / Level at default, "\
                  "passing input to output.");

    outData->SetExtent(inData->GetExtent());
    outData->GetPointData()->PassData(inData->GetPointData());
    this->DataWasPassed = 1;
    }
  else
    // normal behaviour - skip up a level since we don't want to
    // call the superclasses ExecuteData - it would pass the data if there
    // is no lookup table even if there is a window / level - wrong
    // behavior.
    {
    if (this->DataWasPassed)
      {
      outData->GetPointData()->SetScalars(NULL);
      this->DataWasPassed = 0;
      }

    return this->vtkThreadedImageAlgorithm::RequestData(request, inputVector,
                                                        outputVector);
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkImageMapToWindowLevelColors::RequestInformation (
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkInformation *inScalarInfo = vtkDataObject::GetActiveFieldInformation(inInfo,
    vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS);
  if (!inScalarInfo)
    {
    vtkErrorMacro("Missing scalar field on input information!");
    return 0;
    }

  // If LookupTable is null and window / level produces no change,
  // then the data will be passed
  if ( this->LookupTable == NULL &&
    (inScalarInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()) == VTK_UNSIGNED_CHAR &&
          this->Window == 255 && this->Level == 127.5) )
    {
    if (inScalarInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()) != VTK_UNSIGNED_CHAR)
      {
      vtkErrorMacro("ExecuteInformation: No LookupTable was set and input data is not VTK_UNSIGNED_CHAR!");
      }
    else
      {
      // no lookup table, pass the input if it was UNSIGNED_CHAR
      vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_UNSIGNED_CHAR,
        inScalarInfo->Get(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS()));
      }
    }
  else  // the lookup table was set or window / level produces a change
    {
    int numComponents = 4;
    switch (this->OutputFormat)
      {
      case VTK_RGBA:
        numComponents = 4;
        break;
      case VTK_RGB:
        numComponents = 3;
        break;
      case VTK_LUMINANCE_ALPHA:
        numComponents = 2;
        break;
      case VTK_LUMINANCE:
        numComponents = 1;
        break;
      default:
        vtkErrorMacro("ExecuteInformation: Unrecognized color format.");
        break;
      }
    vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_UNSIGNED_CHAR, numComponents);
    }

  return 1;
}

/*
 * This templated routine calculates effective lower and upper limits
 * for a window of values of type T, lower and upper.
 */
template <class T>
void vtkImageMapToWindowLevelClamps ( vtkImageData *data, double w,
                                      double l, T& lower, T& upper,
                                      unsigned char &lower_val,
                                      unsigned char &upper_val)
{
  double f_lower, f_upper, f_lower_val, f_upper_val;
  double adjustedLower, adjustedUpper;
  double range[2];

  data->GetPointData()->GetScalars()->GetDataTypeRange( range );

  f_lower = l - fabs(w) / 2.0;
  f_upper = f_lower + fabs(w);

  // Set the correct lower value
  if ( f_lower <= range[1])
    {
    if (f_lower >= range[0])
      {
      lower = (T) f_lower;
      adjustedLower = f_lower;
      }
    else
      {
      lower = (T) range[0];
      adjustedLower = range[0];
      }
    }
  else
    {
    lower = (T) range[1];
    adjustedLower = range[1];
    }

  // Set the correct upper value
  if ( f_upper >= range[0])
    {
    if (f_upper <= range[1])
      {
      upper = (T) f_upper;
      adjustedUpper = f_upper;
      }
    else
      {
      upper = (T) range[1];
      adjustedUpper = range[1];
      }
    }
  else
    {
    upper = (T) range [0];
    adjustedUpper = range [0];
    }

  // now compute the lower and upper values
  if (w >= 0)
    {
    f_lower_val = 255.0*(adjustedLower - f_lower)/w;
    f_upper_val = 255.0*(adjustedUpper - f_lower)/w;
    }
  else
    {
    f_lower_val = 255.0 + 255.0*(adjustedLower - f_lower)/w;
    f_upper_val = 255.0 + 255.0*(adjustedUpper - f_lower)/w;
    }

  if (f_upper_val > 255)
    {
    upper_val = 255;
    }
  else if (f_upper_val < 0)
    {
    upper_val = 0;
    }
  else
    {
    upper_val = (unsigned char)(f_upper_val);
    }

  if (f_lower_val > 255)
    {
    lower_val = 255;
    }
  else if (f_lower_val < 0)
    {
    lower_val = 0;
    }
  else
    {
    lower_val = (unsigned char)(f_lower_val);
    }
}

//----------------------------------------------------------------------------
// This non-templated function executes the filter for any type of data.
template <class T>
void vtkImageMapToWindowLevelColorsExecute(
  vtkImageMapToWindowLevelColors *self,
  vtkImageData *inData, T *inPtr,
  vtkImageData *outData,
  unsigned char *outPtr,
  int outExt[6], int id)
{
  int idxX, idxY, idxZ;
  int extX, extY, extZ;
  vtkIdType inIncX, inIncY, inIncZ;
  vtkIdType outIncX, outIncY, outIncZ;
  unsigned long count = 0;
  unsigned long target;
  int dataType = inData->GetScalarType();
  int numberOfComponents,numberOfOutputComponents,outputFormat;
  int rowLength;
  vtkScalarsToColors *lookupTable = self->GetLookupTable();
  unsigned char *outPtr1;
  T *inPtr1;
  unsigned char *optr;
  T    *iptr;
  double shift =  self->GetWindow() / 2.0 - self->GetLevel();
  double scale = 255.0 / self->GetWindow();

  T   lower, upper;
  unsigned char lower_val, upper_val, result_val;
  unsigned short ushort_val;
  vtkImageMapToWindowLevelClamps( inData, self->GetWindow(),
                                  self->GetLevel(),
                                  lower, upper, lower_val, upper_val );

  // find the region to loop over
  extX = outExt[1] - outExt[0] + 1;
  extY = outExt[3] - outExt[2] + 1;
  extZ = outExt[5] - outExt[4] + 1;

  target = (unsigned long)(extZ*extY/50.0);
  target++;

  // Get increments to march through data
  inData->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ);

  outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ);
  numberOfComponents = inData->GetNumberOfScalarComponents();
  numberOfOutputComponents = outData->GetNumberOfScalarComponents();
  outputFormat = self->GetOutputFormat();

  rowLength = extX*numberOfComponents;

  // Loop through output pixels
  outPtr1 = outPtr;
  inPtr1 = inPtr;
  for (idxZ = 0; idxZ < extZ; idxZ++)
    {
    for (idxY = 0; !self->AbortExecute && idxY < extY; idxY++)
      {
      if (!id)
        {
        if (!(count%target))
          {
          self->UpdateProgress(count/(50.0*target));
          }
        count++;
        }

      iptr = inPtr1;
      optr = outPtr1;

      if ( lookupTable )
        {
        lookupTable->MapScalarsThroughTable2(inPtr1,(unsigned char *)outPtr1,
                                             dataType,extX,numberOfComponents,
                                             outputFormat);

        for (idxX = 0; idxX < extX; idxX++)
          {
          if (*iptr <= lower)
            {
            ushort_val = lower_val;
            }
          else if (*iptr >= upper)
            {
            ushort_val = upper_val;
            }
          else
            {
            ushort_val = (unsigned char) ((*iptr + shift)*scale);
            }
          *optr = (unsigned char)((*optr * ushort_val) >> 8);
          switch (outputFormat)
            {
            case VTK_RGBA:
              *(optr+1) = (unsigned char)((*(optr+1) * ushort_val) >> 8);
              *(optr+2) = (unsigned char)((*(optr+2) * ushort_val) >> 8);
              *(optr+3) = 255;
              break;
            case VTK_RGB:
              *(optr+1) = (unsigned char)((*(optr+1) * ushort_val) >> 8);
              *(optr+2) = (unsigned char)((*(optr+2) * ushort_val) >> 8);
              break;
            case VTK_LUMINANCE_ALPHA:
              *(optr+1) = 255;
              break;
            }
          iptr += numberOfComponents;
          optr += numberOfOutputComponents;
          }
        }
      else
        {
        for (idxX = 0; idxX < extX; idxX++)
          {
          if (*iptr <= lower)
            {
            result_val = lower_val;
            }
          else if (*iptr >= upper)
            {
            result_val = upper_val;
            }
          else
            {
            result_val = (unsigned char) ((*iptr + shift)*scale);
            }
          *optr = result_val;
          switch (outputFormat)
            {
            case VTK_RGBA:
              *(optr+1) = result_val;
              *(optr+2) = result_val;
              *(optr+3) = 255;
              break;
            case VTK_RGB:
              *(optr+1) = result_val;
              *(optr+2) = result_val;
              break;
            case VTK_LUMINANCE_ALPHA:
              *(optr+1) = 255;
              break;
            }
          iptr += numberOfComponents;
          optr += numberOfOutputComponents;
          }
        }
      outPtr1 += outIncY + extX*numberOfOutputComponents;
      inPtr1 += inIncY + rowLength;
      }
    outPtr1 += outIncZ;
    inPtr1 += inIncZ;
    }
}

//----------------------------------------------------------------------------
// This method is passed a input and output data, and executes the filter
// algorithm to fill the output from the input.

void vtkImageMapToWindowLevelColors::ThreadedRequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **vtkNotUsed(inputVector),
  vtkInformationVector *vtkNotUsed(outputVector),
  vtkImageData ***inData,
  vtkImageData **outData,
  int outExt[6], int id)
{
  void *inPtr = inData[0][0]->GetScalarPointerForExtent(outExt);
  void *outPtr = outData[0]->GetScalarPointerForExtent(outExt);

  switch (inData[0][0]->GetScalarType())
    {
    vtkTemplateMacro7(vtkImageMapToWindowLevelColorsExecute, this,
                      inData[0][0], (VTK_TT *)(inPtr),
                      outData[0], (unsigned char *)(outPtr), outExt, id);
    default:
      vtkErrorMacro(<< "Execute: Unknown ScalarType");
      return;
    }
}

void vtkImageMapToWindowLevelColors::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Window: " << this->Window << endl;
  os << indent << "Level: " << this->Level << endl;
}
<commit_msg>BUG: fix bug in passing data through<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageMapToWindowLevelColors.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkImageMapToWindowLevelColors.h"

#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkScalarsToColors.h"
#include "vtkPointData.h"

vtkCxxRevisionMacro(vtkImageMapToWindowLevelColors, "1.23");
vtkStandardNewMacro(vtkImageMapToWindowLevelColors);

// Constructor sets default values
vtkImageMapToWindowLevelColors::vtkImageMapToWindowLevelColors()
{
  this->Window = 255;
  this->Level  = 127.5;
}

vtkImageMapToWindowLevelColors::~vtkImageMapToWindowLevelColors()
{
}

//----------------------------------------------------------------------------
// This method checks to see if we can simply reference the input data
int vtkImageMapToWindowLevelColors::RequestData(
  vtkInformation *request,
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *outInfo = outputVector->GetInformationObject(0);
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);

  vtkImageData *outData = vtkImageData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkImageData *inData = vtkImageData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));

  // If LookupTable is null and window / level produces no change,
  // then just pass the data
  if (this->LookupTable == NULL &&
      (inData->GetScalarType() == VTK_UNSIGNED_CHAR &&
       this->Window == 255 && this->Level == 127.5))
    {
    vtkDebugMacro("ExecuteData: LookupTable not set, "\
                  "Window / Level at default, "\
                  "passing input to output.");

    outData->SetExtent(inData->GetExtent());
    outData->GetPointData()->PassData(inData->GetPointData());
    this->DataWasPassed = 1;
    }
  else
    // normal behaviour - skip up a level since we don't want to
    // call the superclasses ExecuteData - it would pass the data if there
    // is no lookup table even if there is a window / level - wrong
    // behavior.
    {
    if (this->DataWasPassed)
      {
      outData->GetPointData()->SetScalars(NULL);
      this->DataWasPassed = 0;
      }

    return this->vtkThreadedImageAlgorithm::RequestData(request, inputVector,
                                                        outputVector);
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkImageMapToWindowLevelColors::RequestInformation (
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkInformation *inScalarInfo =
    vtkDataObject::GetActiveFieldInformation(inInfo,
    vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS);
  if (!inScalarInfo)
    {
    vtkErrorMacro("Missing scalar field on input information!");
    return 0;
    }

  // If LookupTable is null and window / level produces no change,
  // then the data will be passed
  if ( this->LookupTable == NULL &&
       (inScalarInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()) ==
        VTK_UNSIGNED_CHAR &&
        this->Window == 255 && this->Level == 127.5) )
    {
    if (inScalarInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()) !=
        VTK_UNSIGNED_CHAR)
      {
      vtkErrorMacro("ExecuteInformation: No LookupTable was set and input data is not VTK_UNSIGNED_CHAR!");
      }
    else
      {
      // no lookup table, pass the input if it was UNSIGNED_CHAR
      vtkDataObject::SetPointDataActiveScalarInfo
        (outInfo, VTK_UNSIGNED_CHAR,
         inScalarInfo->Get(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS()));
      }
    }
  else  // the lookup table was set or window / level produces a change
    {
    int numComponents = 4;
    switch (this->OutputFormat)
      {
      case VTK_RGBA:
        numComponents = 4;
        break;
      case VTK_RGB:
        numComponents = 3;
        break;
      case VTK_LUMINANCE_ALPHA:
        numComponents = 2;
        break;
      case VTK_LUMINANCE:
        numComponents = 1;
        break;
      default:
        vtkErrorMacro("ExecuteInformation: Unrecognized color format.");
        break;
      }
    vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_UNSIGNED_CHAR, numComponents);
    }

  return 1;
}

/*
 * This templated routine calculates effective lower and upper limits
 * for a window of values of type T, lower and upper.
 */
template <class T>
void vtkImageMapToWindowLevelClamps ( vtkImageData *data, double w,
                                      double l, T& lower, T& upper,
                                      unsigned char &lower_val,
                                      unsigned char &upper_val)
{
  double f_lower, f_upper, f_lower_val, f_upper_val;
  double adjustedLower, adjustedUpper;
  double range[2];

  data->GetPointData()->GetScalars()->GetDataTypeRange( range );

  f_lower = l - fabs(w) / 2.0;
  f_upper = f_lower + fabs(w);

  // Set the correct lower value
  if ( f_lower <= range[1])
    {
    if (f_lower >= range[0])
      {
      lower = (T) f_lower;
      adjustedLower = f_lower;
      }
    else
      {
      lower = (T) range[0];
      adjustedLower = range[0];
      }
    }
  else
    {
    lower = (T) range[1];
    adjustedLower = range[1];
    }

  // Set the correct upper value
  if ( f_upper >= range[0])
    {
    if (f_upper <= range[1])
      {
      upper = (T) f_upper;
      adjustedUpper = f_upper;
      }
    else
      {
      upper = (T) range[1];
      adjustedUpper = range[1];
      }
    }
  else
    {
    upper = (T) range [0];
    adjustedUpper = range [0];
    }

  // now compute the lower and upper values
  if (w >= 0)
    {
    f_lower_val = 255.0*(adjustedLower - f_lower)/w;
    f_upper_val = 255.0*(adjustedUpper - f_lower)/w;
    }
  else
    {
    f_lower_val = 255.0 + 255.0*(adjustedLower - f_lower)/w;
    f_upper_val = 255.0 + 255.0*(adjustedUpper - f_lower)/w;
    }

  if (f_upper_val > 255)
    {
    upper_val = 255;
    }
  else if (f_upper_val < 0)
    {
    upper_val = 0;
    }
  else
    {
    upper_val = (unsigned char)(f_upper_val);
    }

  if (f_lower_val > 255)
    {
    lower_val = 255;
    }
  else if (f_lower_val < 0)
    {
    lower_val = 0;
    }
  else
    {
    lower_val = (unsigned char)(f_lower_val);
    }
}

//----------------------------------------------------------------------------
// This non-templated function executes the filter for any type of data.
template <class T>
void vtkImageMapToWindowLevelColorsExecute(
  vtkImageMapToWindowLevelColors *self,
  vtkImageData *inData, T *inPtr,
  vtkImageData *outData,
  unsigned char *outPtr,
  int outExt[6], int id)
{
  int idxX, idxY, idxZ;
  int extX, extY, extZ;
  vtkIdType inIncX, inIncY, inIncZ;
  vtkIdType outIncX, outIncY, outIncZ;
  unsigned long count = 0;
  unsigned long target;
  int dataType = inData->GetScalarType();
  int numberOfComponents,numberOfOutputComponents,outputFormat;
  int rowLength;
  vtkScalarsToColors *lookupTable = self->GetLookupTable();
  unsigned char *outPtr1;
  T *inPtr1;
  unsigned char *optr;
  T    *iptr;
  double shift =  self->GetWindow() / 2.0 - self->GetLevel();
  double scale = 255.0 / self->GetWindow();

  T   lower, upper;
  unsigned char lower_val, upper_val, result_val;
  unsigned short ushort_val;
  vtkImageMapToWindowLevelClamps( inData, self->GetWindow(),
                                  self->GetLevel(),
                                  lower, upper, lower_val, upper_val );

  // find the region to loop over
  extX = outExt[1] - outExt[0] + 1;
  extY = outExt[3] - outExt[2] + 1;
  extZ = outExt[5] - outExt[4] + 1;

  target = (unsigned long)(extZ*extY/50.0);
  target++;

  // Get increments to march through data
  inData->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ);

  outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ);
  numberOfComponents = inData->GetNumberOfScalarComponents();
  numberOfOutputComponents = outData->GetNumberOfScalarComponents();
  outputFormat = self->GetOutputFormat();

  rowLength = extX*numberOfComponents;

  // Loop through output pixels
  outPtr1 = outPtr;
  inPtr1 = inPtr;
  for (idxZ = 0; idxZ < extZ; idxZ++)
    {
    for (idxY = 0; !self->AbortExecute && idxY < extY; idxY++)
      {
      if (!id)
        {
        if (!(count%target))
          {
          self->UpdateProgress(count/(50.0*target));
          }
        count++;
        }

      iptr = inPtr1;
      optr = outPtr1;

      if ( lookupTable )
        {
        lookupTable->MapScalarsThroughTable2(inPtr1,(unsigned char *)outPtr1,
                                             dataType,extX,numberOfComponents,
                                             outputFormat);

        for (idxX = 0; idxX < extX; idxX++)
          {
          if (*iptr <= lower)
            {
            ushort_val = lower_val;
            }
          else if (*iptr >= upper)
            {
            ushort_val = upper_val;
            }
          else
            {
            ushort_val = (unsigned char) ((*iptr + shift)*scale);
            }
          *optr = (unsigned char)((*optr * ushort_val) >> 8);
          switch (outputFormat)
            {
            case VTK_RGBA:
              *(optr+1) = (unsigned char)((*(optr+1) * ushort_val) >> 8);
              *(optr+2) = (unsigned char)((*(optr+2) * ushort_val) >> 8);
              *(optr+3) = 255;
              break;
            case VTK_RGB:
              *(optr+1) = (unsigned char)((*(optr+1) * ushort_val) >> 8);
              *(optr+2) = (unsigned char)((*(optr+2) * ushort_val) >> 8);
              break;
            case VTK_LUMINANCE_ALPHA:
              *(optr+1) = 255;
              break;
            }
          iptr += numberOfComponents;
          optr += numberOfOutputComponents;
          }
        }
      else
        {
        for (idxX = 0; idxX < extX; idxX++)
          {
          if (*iptr <= lower)
            {
            result_val = lower_val;
            }
          else if (*iptr >= upper)
            {
            result_val = upper_val;
            }
          else
            {
            result_val = (unsigned char) ((*iptr + shift)*scale);
            }
          *optr = result_val;
          switch (outputFormat)
            {
            case VTK_RGBA:
              *(optr+1) = result_val;
              *(optr+2) = result_val;
              *(optr+3) = 255;
              break;
            case VTK_RGB:
              *(optr+1) = result_val;
              *(optr+2) = result_val;
              break;
            case VTK_LUMINANCE_ALPHA:
              *(optr+1) = 255;
              break;
            }
          iptr += numberOfComponents;
          optr += numberOfOutputComponents;
          }
        }
      outPtr1 += outIncY + extX*numberOfOutputComponents;
      inPtr1 += inIncY + rowLength;
      }
    outPtr1 += outIncZ;
    inPtr1 += inIncZ;
    }
}

//----------------------------------------------------------------------------
// This method is passed a input and output data, and executes the filter
// algorithm to fill the output from the input.

void vtkImageMapToWindowLevelColors::ThreadedRequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **vtkNotUsed(inputVector),
  vtkInformationVector *vtkNotUsed(outputVector),
  vtkImageData ***inData,
  vtkImageData **outData,
  int outExt[6], int id)
{
  void *inPtr = inData[0][0]->GetScalarPointerForExtent(outExt);
  void *outPtr = outData[0]->GetScalarPointerForExtent(outExt);

  switch (inData[0][0]->GetScalarType())
    {
    vtkTemplateMacro7(vtkImageMapToWindowLevelColorsExecute, this,
                      inData[0][0], (VTK_TT *)(inPtr),
                      outData[0], (unsigned char *)(outPtr), outExt, id);
    default:
      vtkErrorMacro(<< "Execute: Unknown ScalarType");
      return;
    }
}

void vtkImageMapToWindowLevelColors::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Window: " << this->Window << endl;
  os << indent << "Level: " << this->Level << endl;
}
<|endoftext|>


<commit_before>#ifndef SOLAIRE_COMPRESSED_VECTOR_HPP
#define SOLAIRE_COMPRESSED_VECTOR_HPP

//Copyright 2015 Adam Smith
//
//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.

// Contact :
// Email             : solairelibrary@mail.com
// GitHub repository : https://github.com/SolaireLibrary/SolaireCPP

/*!
	\file CompressedVector.hpp
	\brief Contains code for an N dimentional vector class with typedefs for commonly used vector types.
	\author
	Created			: Adam Smith
	Last modified	: Adam Smith
	\date
	Created			: 13th January 2016
	Last Modified	: 13th January 2016
*/

#include <cmath>
#include <cstdint>
#include <limits>
#include "Solaire/Core/BinaryBlock.hpp"

namespace Solaire { namespace Test {

    static constexpr bool isByteAligned(const uint32_t aBits) throw() {
        return (static_cast<float>(aBits) / 8.f) == static_cast<float>(aBits / 8);
    }

    static constexpr uint64_t MASKS[33] = {
        0x00,
        0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF,                         // 8 bit
        0x01F, 0x03F, 0x07F, 0x0FF, 0x1FF, 0x3FF, 0x7F, 0xFFF,                  // 16 bit
        0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FF, 0xFFFF,          // 32 bit
        0x01FFF, 0x03FFF, 0x07FFF, 0x0FFFF, 0x1FFFF, 0x3FFFF, 0x7FFF, 0xFFFFF,  // 64 bit
    };

    ////

    template<class T, const bool SIGN, typename ENABLE = void>
    struct BiggerIntegerStruct {
        typedef void Type;
    };

    #define SOLAIRE_BIGGER_INTEGER_STRUCT(aType, aSignedType, aUnsignedType)\
    template<class T, const bool SIGN>\
    struct BiggerIntegerStruct<T, SIGN, typename std::enable_if<std::is_same<T, aType>::value && ! SIGN>::type> {\
        typedef aUnsignedType Type;\
    };\
    template<class T, const bool SIGN>\
    struct BiggerIntegerStruct<T, SIGN, typename std::enable_if<std::is_same<T, aType>::value && SIGN>::type> {\
        typedef aSignedType Type;\
    };

    SOLAIRE_BIGGER_INTEGER_STRUCT(uint8_t,  uint16_t,   int16_t);
    SOLAIRE_BIGGER_INTEGER_STRUCT(uint16_t, uint32_t,   int32_t);
    SOLAIRE_BIGGER_INTEGER_STRUCT(uint32_t, uint64_t,   int64_t);
    SOLAIRE_BIGGER_INTEGER_STRUCT(uint64_t, uint64_t,   int64_t);
    SOLAIRE_BIGGER_INTEGER_STRUCT(int8_t,   uint8_t,    int16_t);
    SOLAIRE_BIGGER_INTEGER_STRUCT(int16_t,  uint16_t,   int32_t);
    SOLAIRE_BIGGER_INTEGER_STRUCT(int32_t,  uint32_t,   int64_t);
    SOLAIRE_BIGGER_INTEGER_STRUCT(int64_t,  uint64_t,   int64_t);

    template<class T, const bool SIGN>
    using BiggerInteger = typename BiggerIntegerStruct<T, SIGN>::Type;

    template<class A, class B>
    static constexpr bool canIntegerContain() {
        static_assert(std::is_integral<A>::value, "SolaireCPP : canIntegerContain<A> must be integer type");
        static_assert(std::is_integral<B>::value, "SolaireCPP : canIntegerContain<B> must be integer type");
        return
            (std::numeric_limits<A>::min() <= std::numeric_limits<B>::min()) &&
            (std::numeric_limits<A>::max() >= std::numeric_limits<B>::max());
    }

    template<class A, class B, typename ENABLE = void>
    struct IntegerContainerStruct {
        typedef void Type;
    };

    template<class A, class B>
    struct IntegerContainerStruct<A, B, typename std::enable_if<canIntegerContain<A,B>()>::type> {
        typedef A Type;
    };

    template<class A, class B>
    struct IntegerContainerStruct<A, B, typename std::enable_if<canIntegerContain<B,A>() && ! canIntegerContain<A,B>()>::type> {
        typedef B Type;
    };

    template<class A, class B>
    struct IntegerContainerStruct<A, B, typename std::enable_if<
        ((! canIntegerContain<A,B>()) && (! canIntegerContain<B,A>())) &&
        (
            canIntegerContain<BiggerInteger<A, std::is_signed<A>::value>, A>() &&
            canIntegerContain<BiggerInteger<A, std::is_signed<A>::value>, B>()
         )
    >::type> {
        typedef BiggerInteger<A, std::is_signed<A>::value> Type;
    };

    template<class A, class B>
    struct IntegerContainerStruct<A, B, typename std::enable_if<
        ((! canIntegerContain<A,B>()) && (! canIntegerContain<B,A>())) &&
        (
            canIntegerContain<BiggerInteger<B, std::is_signed<B>::value>, A>() &&
            canIntegerContain<BiggerInteger<B, std::is_signed<B>::value>, B>()
         )
    >::type> {
        typedef BiggerInteger<B, std::is_signed<B>::value> Type;
    };

    template<class A, class B>
    using IntegerContainer2 = typename IntegerContainerStruct<A, B>::Type;

    template<class A, class B, class C>
    using IntegerContainer3 = typename IntegerContainerStruct<IntegerContainer2<A, B>, C>::Type;

    template<class A, class B, class C, class D>
    using IntegerContainer4 = IntegerContainer2<IntegerContainer2<A, B>, IntegerContainer2<C, D>>;

    ////

    template<const uint8_t BITS, const bool SIGN>
    struct ElementInfo {
        enum : uint64_t {
            Bits = BITS,
            Signed = SIGN
        };
        typedef BinaryBlock<BITS, Signed> Type;

        enum : Type {
            Min = Signed ? (static_cast<int64_t>(MASKS[Bits] / 2) - 1) * -1 : 0,
            Max = Signed ? MASKS[Bits] / 2 : (MASKS[Bits] + 1)
        };

        static constexpr float scale(const Type aValue) {
            return static_cast<float>(aValue) / static_cast<float>(Max);
        }
    };

    template<
        const uint8_t XBITS, const uint8_t YBITS, const uint8_t ZBITS, const uint8_t WBITS,
        const bool XSIGN = false, const bool YSIGN = false, const bool ZSIGN = false, const bool WSIGN = false
    >
    class CompressedVector {
    public:
        enum {
            TotalBits = XBITS + YBITS + ZBITS + WBITS,
            IsByteAligned = isByteAligned(TotalBits),
            Size = (XBITS == 0 ? 0 : 1) + (YBITS == 0 ? 0 : 1) + (ZBITS == 0 ? 0 : 1) + (WBITS == 0 ? 0 : 1)
        };

        typedef ElementInfo<XBITS, XSIGN> XInfo;
        typedef ElementInfo<YBITS, YSIGN> YInfo;
        typedef ElementInfo<ZBITS, ZSIGN> ZInfo;
        typedef ElementInfo<WBITS, WSIGN> WInfo;

        typedef IntegerContainer4<typename XInfo::Type, typename YInfo::Type, typename ZInfo::Type, typename WInfo::Type> Scalar;

        typedef CompressedVector<
            XBITS, YBITS, ZBITS, WBITS,
            XSIGN, YSIGN, ZSIGN, WSIGN
        > Self;
    public:
        typename XInfo::Type X : XBITS;
        typename YInfo::Type Y : YBITS;
        typename ZInfo::Type Z : ZBITS;
        typename WInfo::Type W : WBITS;

        // Constructors

        CompressedVector() :
            X(0),
            Y(0),
            Z(0),
            W(0)
        {}

        CompressedVector(const Scalar aX, const Scalar aY) :
            X(aX),
            Y(aY),
            Z(0),
            W(0)
        {}

        CompressedVector(const Scalar aX, const Scalar aY, const Scalar aZ) :
            X(aX),
            Y(aY),
            Z(aZ),
            W(0)
        {}

        CompressedVector(const Scalar aX, const Scalar aY, const Scalar aZ, const Scalar aW) :
            X(aX),
            Y(aY),
            Z(aZ),
            W(aW)
        {}

        // C++ operators

        /*!
            \brief Access an element of this vector.
            \param aIndex The element to access.
            \return A copy of the scalar element.
        */
	    Scalar operator[](const uint32_t aIndex) const throw() {
	        switch(aIndex) {
            case 0  : return X;
            case 1  : return Y;
            case 2  : return Z;
            case 3  : return W;
            default : return 0;
	        }
	    }

        /*!
            \brief Compare this vector to another.
            \param aOther The second vector.
            \return True if this vector is equal to \a aOther.
        */
		bool operator==(const Self aOther) const throw() {
			return std::memcmp(this, &aOther, sizeof(Self)) == 0;
		}

        /*!
            \brief Compare this vector to another.
            \param aOther The second vector.
            \return True if this vector is not equal to \a aOther.
        */
		bool operator!=(const Self aOther) const throw() {
			return std::memcmp(this, &aOther, sizeof(Self)) != 0;
		}

        /*!
            \brief Compare this vector to another.
            \detail This is implemented using the (squared) magnitude.
            \param aOther The second vector.
            \return True if this vector is less than \a aOther.
        */
		bool operator<(const Self aOther) const throw() {
			return magnitudeSquared() < aOther.magnitudeSquared();
		}

        /*!
            \brief Compare this vector to another.
            \detail This is implemented using the (squared) magnitude.
            \param aOther The second vector.
            \return True if this vector is greater than \a aOther.
        */
		bool operator>(const Self aOther) const throw() {
			return magnitudeSquared() > aOther.magnitudeSquared();
		}

        /*!
            \brief Compare this vector to another.
            \detail This is implemented using the (squared) magnitude.
            \param aOther The second vector.
            \return True if this vector is less than, or equal to \a aOther.
        */
		bool operator<=(const Self aOther) const throw() {
			return magnitudeSquared() <= aOther.magnitudeSquared();
		}

        /*!
            \brief Compare this vector to another.
            \detail This is implemented using the (squared) magnitude.
            \param aOther The second vector.
            \return True if this vector is greater than, or equal to \a aOther.
        */
		bool operator>=(const Self aOther) const throw() {
			return magnitudeSquared() >= aOther.magnitudeSquared();
		}

        // Misc

        /*!
            \brief Calculate the sum of all elements in the vector.
            \return The sum.
        */
		Scalar sum() const throw() {
			return X + Y + Z + W;
		}

        /*!
            \brief Calculate the mean element in the vector.
            \return The mean element.
        */
		Scalar average() const throw() {
			return sum() / Size;
		}

        /*!
            \brief Compute square of the magnitude of this vector.
            \detail This is faster than Magnitude().
            \return The square of the magnitude.
            \see Magnitude
        */
       Scalar magnitudeSquared() const throw() {
			return (X * X) + (Y * Y) + (Z * Z) + (W * W);
		}

        /*!
            \brief Compute magnitude of this vector.
            \return The magnitude.
            \see MagnitudeSquared
        */
		Scalar magnitude() const throw() {
			return static_cast<Scalar>(std::sqrt(static_cast<double>(magnitudeSquared())));
		}

        /*!
            \brief Compute normalised form of this vector.
            \return The normalised unit vector.
        */
		Self normalise() const throw() {
			return Self(*this) / magnitude();
		}

        /*!
            \brief Compute the dot product of two vectors.
            \param aOther The second vector.
            \return The dot product.
        */
		Scalar dotProduct(const Self aOther) const throw() {
			return (X * aOther.X) + (Y * aOther.Y) + (Z * aOther.Z) + (W * aOther.W);
		}

        /*!
            \brief Compute the cross product of two vectors.
            \param aOther The second vector.
            \return The cross product.
        */
		Self crossProduct(const Self aOther) const throw() {
		    return Self(
                (Y * aOther.Z) - (Z * aOther.Y),
                (Z * aOther.Z) - (X * aOther.Z),
                (X * aOther.Y) - (Y * aOther.Z),
                0
		    );
		}

        /*!
            \brief Perform linear interpolation between two vectors.
            \param aOther The other vector.
            \param aWeight The weighting bias for this vector.
            \return The interpolated vector.
        */
		Self lerp(const Self aOther, const double aWeight) const throw() {
			return Self(
               static_cast<Scalar>((1.0 - aWeight) * static_cast<double>(X) + aWeight * static_cast<double>(aOther.X)),
               static_cast<Scalar>((1.0 - aWeight) * static_cast<double>(Y) + aWeight * static_cast<double>(aOther.Y)),
               static_cast<Scalar>((1.0 - aWeight) * static_cast<double>(Z) + aWeight * static_cast<double>(aOther.Z)),
               static_cast<Scalar>((1.0 - aWeight) * static_cast<double>(W) + aWeight * static_cast<double>(aOther.W))
            );
		}

		//! \todo Swizzle
    };

    template<class T>
    static void PrintElementInfo(const char aElement) {
        std::cout << "Info - Element " << aElement << std::endl;
        std::cout << "Bits\t: " << T::Bits << std::endl;
        std::cout << "Signed\t: " << T::Signed << std::endl;
        std::cout << "Type\t: " << sizeof(typename T::Type) << " bytes" << std::endl;
        std::cout << "Min\t: " << T::Min << std::endl;
        std::cout << "Max\t: " << T::Max << std::endl;

    }

    template<class T>
    static void PrintVectorInfo() {
        std::cout << "Info - Vector" << std::endl;
        std::cout << "TotalBits\t: " << T::TotalBits << std::endl;
        std::cout << "IsByteAligned\t: " << T::IsByteAligned << std::endl;
        std::cout << std::endl;
        PrintElementInfo<typename T::XInfo>('X');
        std::cout << std::endl;
        PrintElementInfo<typename T::YInfo>('Y');
        std::cout << std::endl;
        PrintElementInfo<typename T::ZInfo>('Z');
        std::cout << std::endl;
        PrintElementInfo<typename T::WInfo>('W');
    }

}}

#endif
<commit_msg>Moved IntegerContainer to Core module<commit_after>#ifndef SOLAIRE_COMPRESSED_VECTOR_HPP
#define SOLAIRE_COMPRESSED_VECTOR_HPP

//Copyright 2015 Adam Smith
//
//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.

// Contact :
// Email             : solairelibrary@mail.com
// GitHub repository : https://github.com/SolaireLibrary/SolaireCPP

/*!
	\file CompressedVector.hpp
	\brief Contains code for an N dimentional vector class with typedefs for commonly used vector types.
	\author
	Created			: Adam Smith
	Last modified	: Adam Smith
	\date
	Created			: 13th January 2016
	Last Modified	: 13th January 2016
*/

#include <cmath>
#include <cstdint>
#include <limits>
#include "Solaire/Core/BinaryBlock.hpp"
#include "Solaire/Core/IntegerContainer.hpp"

namespace Solaire { namespace Test {

    static constexpr bool isByteAligned(const uint32_t aBits) throw() {
        return (static_cast<float>(aBits) / 8.f) == static_cast<float>(aBits / 8);
    }

    static constexpr uint64_t MASKS[33] = {
        0x00,
        0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF,                         // 8 bit
        0x01F, 0x03F, 0x07F, 0x0FF, 0x1FF, 0x3FF, 0x7F, 0xFFF,                  // 16 bit
        0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FF, 0xFFFF,          // 32 bit
        0x01FFF, 0x03FFF, 0x07FFF, 0x0FFFF, 0x1FFFF, 0x3FFFF, 0x7FFF, 0xFFFFF,  // 64 bit
    };

    ////

    template<const uint8_t BITS, const bool SIGN>
    struct ElementInfo {
        enum : uint64_t {
            Bits = BITS,
            Signed = SIGN
        };
        typedef BinaryBlock<BITS, Signed> Type;

        enum : Type {
            Min = Signed ? (static_cast<int64_t>(MASKS[Bits] / 2) - 1) * -1 : 0,
            Max = Signed ? MASKS[Bits] / 2 : (MASKS[Bits] + 1)
        };

        static constexpr float scale(const Type aValue) {
            return static_cast<float>(aValue) / static_cast<float>(Max);
        }
    };

    template<
        const uint8_t XBITS, const uint8_t YBITS, const uint8_t ZBITS, const uint8_t WBITS,
        const bool XSIGN = false, const bool YSIGN = false, const bool ZSIGN = false, const bool WSIGN = false
    >
    class CompressedVector {
    public:
        enum {
            TotalBits = XBITS + YBITS + ZBITS + WBITS,
            IsByteAligned = isByteAligned(TotalBits),
            Size = (XBITS == 0 ? 0 : 1) + (YBITS == 0 ? 0 : 1) + (ZBITS == 0 ? 0 : 1) + (WBITS == 0 ? 0 : 1)
        };

        typedef ElementInfo<XBITS, XSIGN> XInfo;
        typedef ElementInfo<YBITS, YSIGN> YInfo;
        typedef ElementInfo<ZBITS, ZSIGN> ZInfo;
        typedef ElementInfo<WBITS, WSIGN> WInfo;

        typedef IntegerContainer4<typename XInfo::Type, typename YInfo::Type, typename ZInfo::Type, typename WInfo::Type> Scalar;

        typedef CompressedVector<
            XBITS, YBITS, ZBITS, WBITS,
            XSIGN, YSIGN, ZSIGN, WSIGN
        > Self;
    public:
        typename XInfo::Type X : XBITS;
        typename YInfo::Type Y : YBITS;
        typename ZInfo::Type Z : ZBITS;
        typename WInfo::Type W : WBITS;

        // Constructors

        CompressedVector() :
            X(0),
            Y(0),
            Z(0),
            W(0)
        {}

        CompressedVector(const Scalar aX, const Scalar aY) :
            X(aX),
            Y(aY),
            Z(0),
            W(0)
        {}

        CompressedVector(const Scalar aX, const Scalar aY, const Scalar aZ) :
            X(aX),
            Y(aY),
            Z(aZ),
            W(0)
        {}

        CompressedVector(const Scalar aX, const Scalar aY, const Scalar aZ, const Scalar aW) :
            X(aX),
            Y(aY),
            Z(aZ),
            W(aW)
        {}

        // C++ operators

        /*!
            \brief Access an element of this vector.
            \param aIndex The element to access.
            \return A copy of the scalar element.
        */
	    Scalar operator[](const uint32_t aIndex) const throw() {
	        switch(aIndex) {
            case 0  : return X;
            case 1  : return Y;
            case 2  : return Z;
            case 3  : return W;
            default : return 0;
	        }
	    }

        /*!
            \brief Compare this vector to another.
            \param aOther The second vector.
            \return True if this vector is equal to \a aOther.
        */
		bool operator==(const Self aOther) const throw() {
			return std::memcmp(this, &aOther, sizeof(Self)) == 0;
		}

        /*!
            \brief Compare this vector to another.
            \param aOther The second vector.
            \return True if this vector is not equal to \a aOther.
        */
		bool operator!=(const Self aOther) const throw() {
			return std::memcmp(this, &aOther, sizeof(Self)) != 0;
		}

        /*!
            \brief Compare this vector to another.
            \detail This is implemented using the (squared) magnitude.
            \param aOther The second vector.
            \return True if this vector is less than \a aOther.
        */
		bool operator<(const Self aOther) const throw() {
			return magnitudeSquared() < aOther.magnitudeSquared();
		}

        /*!
            \brief Compare this vector to another.
            \detail This is implemented using the (squared) magnitude.
            \param aOther The second vector.
            \return True if this vector is greater than \a aOther.
        */
		bool operator>(const Self aOther) const throw() {
			return magnitudeSquared() > aOther.magnitudeSquared();
		}

        /*!
            \brief Compare this vector to another.
            \detail This is implemented using the (squared) magnitude.
            \param aOther The second vector.
            \return True if this vector is less than, or equal to \a aOther.
        */
		bool operator<=(const Self aOther) const throw() {
			return magnitudeSquared() <= aOther.magnitudeSquared();
		}

        /*!
            \brief Compare this vector to another.
            \detail This is implemented using the (squared) magnitude.
            \param aOther The second vector.
            \return True if this vector is greater than, or equal to \a aOther.
        */
		bool operator>=(const Self aOther) const throw() {
			return magnitudeSquared() >= aOther.magnitudeSquared();
		}

        // Misc

        /*!
            \brief Calculate the sum of all elements in the vector.
            \return The sum.
        */
		Scalar sum() const throw() {
			return X + Y + Z + W;
		}

        /*!
            \brief Calculate the mean element in the vector.
            \return The mean element.
        */
		Scalar average() const throw() {
			return sum() / Size;
		}

        /*!
            \brief Compute square of the magnitude of this vector.
            \detail This is faster than Magnitude().
            \return The square of the magnitude.
            \see Magnitude
        */
       Scalar magnitudeSquared() const throw() {
			return (X * X) + (Y * Y) + (Z * Z) + (W * W);
		}

        /*!
            \brief Compute magnitude of this vector.
            \return The magnitude.
            \see MagnitudeSquared
        */
		Scalar magnitude() const throw() {
			return static_cast<Scalar>(std::sqrt(static_cast<double>(magnitudeSquared())));
		}

        /*!
            \brief Compute normalised form of this vector.
            \return The normalised unit vector.
        */
		Self normalise() const throw() {
			return Self(*this) / magnitude();
		}

        /*!
            \brief Compute the dot product of two vectors.
            \param aOther The second vector.
            \return The dot product.
        */
		Scalar dotProduct(const Self aOther) const throw() {
			return (X * aOther.X) + (Y * aOther.Y) + (Z * aOther.Z) + (W * aOther.W);
		}

        /*!
            \brief Compute the cross product of two vectors.
            \param aOther The second vector.
            \return The cross product.
        */
		Self crossProduct(const Self aOther) const throw() {
		    return Self(
                (Y * aOther.Z) - (Z * aOther.Y),
                (Z * aOther.Z) - (X * aOther.Z),
                (X * aOther.Y) - (Y * aOther.Z),
                0
		    );
		}

        /*!
            \brief Perform linear interpolation between two vectors.
            \param aOther The other vector.
            \param aWeight The weighting bias for this vector.
            \return The interpolated vector.
        */
		Self lerp(const Self aOther, const double aWeight) const throw() {
			return Self(
               static_cast<Scalar>((1.0 - aWeight) * static_cast<double>(X) + aWeight * static_cast<double>(aOther.X)),
               static_cast<Scalar>((1.0 - aWeight) * static_cast<double>(Y) + aWeight * static_cast<double>(aOther.Y)),
               static_cast<Scalar>((1.0 - aWeight) * static_cast<double>(Z) + aWeight * static_cast<double>(aOther.Z)),
               static_cast<Scalar>((1.0 - aWeight) * static_cast<double>(W) + aWeight * static_cast<double>(aOther.W))
            );
		}

		//! \todo Swizzle
    };

    template<class T>
    static void PrintElementInfo(const char aElement) {
        std::cout << "Info - Element " << aElement << std::endl;
        std::cout << "Bits\t: " << T::Bits << std::endl;
        std::cout << "Signed\t: " << T::Signed << std::endl;
        std::cout << "Type\t: " << sizeof(typename T::Type) << " bytes" << std::endl;
        std::cout << "Min\t: " << T::Min << std::endl;
        std::cout << "Max\t: " << T::Max << std::endl;

    }

    template<class T>
    static void PrintVectorInfo() {
        std::cout << "Info - Vector" << std::endl;
        std::cout << "TotalBits\t: " << T::TotalBits << std::endl;
        std::cout << "IsByteAligned\t: " << T::IsByteAligned << std::endl;
        std::cout << std::endl;
        PrintElementInfo<typename T::XInfo>('X');
        std::cout << std::endl;
        PrintElementInfo<typename T::YInfo>('Y');
        std::cout << std::endl;
        PrintElementInfo<typename T::ZInfo>('Z');
        std::cout << std::endl;
        PrintElementInfo<typename T::WInfo>('W');
    }

}}

#endif
<|endoftext|>