<commit_before>/**
 * Copyright 2013 Da Zheng
 *
 * This file is part of SA-GraphLib.
 *
 * SA-GraphLib is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * SA-GraphLib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with SA-GraphLib.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * This program computes the overlap of each pair of vertices
 * given by the user.
 */

#include <signal.h>
#include <google/profiler.h>

#include <tr1/unordered_set>

#include "graph_engine.h"

enum overlap_stage_t
{
	CONSTRUCT_NEIGHBORS,
	COMP_OVERLAP,
} overlap_stage;

/**
 * This contains all vertices that we want to compute pair-wise overlap.
 */
std::vector<vertex_id_t> overlap_vertices;

template<class InputIterator1, class InputIterator2, class Skipper,
	class Merger, class OutputIterator>
size_t unique_merge(InputIterator1 it1, InputIterator1 last1,
		InputIterator2 it2, InputIterator2 last2, Skipper skip,
		Merger merge, OutputIterator result)
{
	OutputIterator result_begin = result;
	while (it1 != last1 && it2 != last2) {
		if (*it2 < *it1) {
			typename std::iterator_traits<OutputIterator>::value_type v = *it2;
			++it2;
			while (it2 != last2 && v == *it2) {
				v = merge(v, *it2);
				++it2;
			}
			if (!skip(v))
				*(result++) = v;
		}
		else if (*it1 < *it2) {
			typename std::iterator_traits<OutputIterator>::value_type v = *it1;
			++it1;
			while (it1 != last1 && v == *it1) {
				v = merge(v, *it1);
				++it1;
			}
			if (!skip(v))
				*(result++) = v;
		}
		else {
			typename std::iterator_traits<OutputIterator>::value_type v = *it1;
			v = merge(v, *it2);
			++it2;
			while (it2 != last2 && v == *it2) {
				v = merge(v, *it2);
				++it2;
			}
			++it1;
			while (it1 != last1 && v == *it1) {
				v = merge(v, *it1);
				++it1;
			}
			if (!skip(v))
				*(result++) = v;
		}
	}

	while (it1 != last1) {
		typename std::iterator_traits<OutputIterator>::value_type v = *it1;
		++it1;
		while (it1 != last1 && v == *it1) {
			v = merge(v, *it1);
			++it1;
		}
		if (!skip(v))
			*(result++) = v;
	}

	while (it2 != last2) {
		typename std::iterator_traits<OutputIterator>::value_type v = *it2;
		++it2;
		while (it2 != last2 && v == *it2) {
			v = merge(v, *it2);
			++it2;
		}
		if (!skip(v))
			*(result++) = v;
	}
	return result - result_begin;
}

class skip_self
{
	vertex_id_t id;
public:
	skip_self(vertex_id_t id) {
		this->id = id;
	}

	bool operator()(vertex_id_t id) {
		return this->id == id;
	}
};

class merge_edge
{
public:
	vertex_id_t operator()(vertex_id_t e1, vertex_id_t e2) {
		assert(e1 == e2);
		return e1;
	}
};

size_t get_unique_neighbors(const page_vertex &vertex,
		std::vector<vertex_id_t> &neighbors)
{
	neighbors.resize(vertex.get_num_edges(edge_type::BOTH_EDGES));
	size_t num_neighbors = unique_merge(
			vertex.get_neigh_begin(edge_type::IN_EDGE),
			vertex.get_neigh_end(edge_type::IN_EDGE),
			vertex.get_neigh_begin(edge_type::OUT_EDGE),
			vertex.get_neigh_end(edge_type::OUT_EDGE),
			skip_self(vertex.get_id()), merge_edge(),
			neighbors.begin());
	neighbors.resize(num_neighbors);
	return num_neighbors;
}

size_t get_common_vertices(const std::vector<vertex_id_t> &vertices1,
		const std::vector<vertex_id_t> &vertices2)
{
	size_t common = 0;
	size_t i, j;
	// We assume both vectors are sorted in the ascending order.
	// We only need to scan them together to extract the common elements.
	for (i = 0, j = 0; i < vertices1.size() && j < vertices2.size();) {
		if (vertices1[i] == vertices2[j]) {
			common++;
			i++;
			j++;
		}
		else if (vertices1[i] > vertices2[j])
			j++;
		else
			i++;

	}
	return common;
}

size_t get_union_vertices(const std::vector<vertex_id_t> &vertices1,
		const std::vector<vertex_id_t> &vertices2)
{
	std::tr1::unordered_set<vertex_id_t> set(vertices1.begin(),
			vertices1.end());
	set.insert(vertices2.begin(), vertices2.end());
	return set.size();
}

class union_set
{
	std::tr1::unordered_set<vertex_id_t> set;
	pthread_mutex_t lock;
public:
	union_set() {
		pthread_mutex_init(&lock, NULL);
	}

	void add(const std::vector<vertex_id_t> &vec) {
		pthread_mutex_lock(&lock);
		set.insert(vec.begin(), vec.end());
		pthread_mutex_unlock(&lock);
	}

	size_t get_size() const {
		return set.size();
	}
} vertex_union;

class intersection_set
{
	int num_added;
	std::vector<vertex_id_t> set;
	pthread_mutex_t lock;
public:
	intersection_set() {
		num_added = 0;
		pthread_mutex_init(&lock, NULL);
	}

	void add(const std::vector<vertex_id_t> &vec);

	size_t get_size() const {
		return set.size();
	}

	vertex_id_t get(int idx) const {
		return set[idx];
	}
} vertex_intersection;

void intersection_set::add(const std::vector<vertex_id_t> &vec)
{
	std::vector<vertex_id_t> copy(vec);
	std::sort(copy.begin(), copy.end());

	std::vector<vertex_id_t> new_set;
	pthread_mutex_lock(&lock);
	num_added++;
	if (num_added == 1) {
		set = copy;
	}
	else {
		size_t i, j;
		// We assume both vectors are sorted in the ascending order.
		// We only need to scan them together to extract the common elements.
		for (i = 0, j = 0; i < set.size() && j < copy.size();) {
			if (set[i] == copy[j]) {
				new_set.push_back(set[i]);
				i++;
				j++;
			}
			else if (set[i] > copy[j])
				j++;
			else
				i++;

		}
		set = new_set;
	}
	pthread_mutex_unlock(&lock);
}

class overlap_vertex: public compute_vertex
{
	std::vector<vertex_id_t> *neighborhood;
public:
	overlap_vertex() {
		neighborhood = NULL;
	}

	overlap_vertex(vertex_id_t id, const vertex_index *index1): compute_vertex(
			id, index1) {
		neighborhood = NULL;
	}

	void run(graph_engine &graph) {
		switch(overlap_stage) {
			case overlap_stage_t::CONSTRUCT_NEIGHBORS:
				run_stage1(graph);
				break;
			case overlap_stage_t::COMP_OVERLAP:
				run_stage2(graph);
				break;
			default:
				assert(0);
		}
	}

	void run_stage1(graph_engine &graph) {
		vertex_id_t id = get_id();
		graph.request_vertices(*this, &id, 1);
	}

	void run_stage2(graph_engine &graph) {
		BOOST_FOREACH(vertex_id_t id, overlap_vertices) {
			if (id == get_id())
				continue;
			overlap_vertex &neigh = (overlap_vertex &) graph.get_vertex(id);
			size_t common = get_common_vertices(*neighborhood, *neigh.neighborhood);
			size_t vunion = get_union_vertices(*neighborhood, *neigh.neighborhood);
			printf("v%u:v%u, common: %ld, union: %ld, overlap: %f\n",
					get_id(), id, common, vunion,
					((double) common) / vunion);
		}
	}

	void run(graph_engine &graph, const page_vertex &vertex) {
		assert(vertex.get_id() == get_id());
		run_on_itself(graph, vertex);
	}

	void run_on_itself(graph_engine &graph, const page_vertex &vertex) {
		neighborhood = new std::vector<vertex_id_t>();
		get_unique_neighbors(vertex, *neighborhood);
		assert(std::is_sorted(neighborhood->begin(), neighborhood->end()));

		std::vector<vertex_id_t>::iterator it = std::lower_bound(
				neighborhood->begin(), neighborhood->end(), get_id());
		if (it != neighborhood->end())
			assert(*it != get_id());
		neighborhood->insert(it, get_id());
		assert(std::is_sorted(neighborhood->begin(), neighborhood->end()));
	}

	void run_on_messages(graph_engine &,
			const vertex_message *msgs[], int num) {
	}
};

void int_handler(int sig_num)
{
	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
	exit(0);
}

int read_vertices(const std::string &file, std::vector<vertex_id_t> &vertices)
{
	FILE *f = fopen(file.c_str(), "r");
	assert(f);
	ssize_t ret;
	char *line = NULL;
	size_t line_size = 0;
	while ((ret = getline(&line, &line_size, f)) > 0) {
		if (line[ret - 1] == '\n')
			line[ret - 1] = 0;
		vertex_id_t id = atol(line);
		printf("%u\n", id);
		vertices.push_back(id);
	}
	fclose(f);
	return vertices.size();
}

int main(int argc, char *argv[])
{
	std::string output_file;
	std::string confs;

	if (argc < 3) {
		fprintf(stderr,
				"overlap conf_file graph_file index_file vertex_file\n");
		exit(-1);
	}

	std::string conf_file = argv[1];
	std::string graph_file = argv[2];
	std::string index_file = argv[3];
	std::string vertex_file = argv[4];

	read_vertices(vertex_file, overlap_vertices);

	config_map configs(conf_file);
	configs.add_options(confs);
	graph_conf.init(configs);
	graph_conf.print();

	signal(SIGINT, int_handler);
	init_io_system(configs);

	graph_index *index = NUMA_graph_index<overlap_vertex>::create(
			index_file, graph_conf.get_num_threads(), params.get_num_nodes());
	graph_engine *graph = graph_engine::create(
			graph_conf.get_num_threads(), params.get_num_nodes(), graph_file,
			index);
	if (!graph_conf.get_prof_file().empty())
		ProfilerStart(graph_conf.get_prof_file().c_str());

	struct timeval start, end;

	gettimeofday(&start, NULL);
	overlap_stage = overlap_stage_t::CONSTRUCT_NEIGHBORS;
	graph->start(overlap_vertices.data(), overlap_vertices.size());
	graph->wait4complete();
	gettimeofday(&end, NULL);
	printf("It takes %f seconds to construct neighborhoods\n",
			time_diff(start, end));

	gettimeofday(&start, NULL);
	overlap_stage = overlap_stage_t::COMP_OVERLAP;
	graph->start(overlap_vertices.data(), overlap_vertices.size());
	graph->wait4complete();
	gettimeofday(&end, NULL);
	printf("It takes %f seconds to compute overlaps\n", time_diff(start, end));

	printf("All vertices have %ld common neighbors and cover %ld vertices\n",
			vertex_intersection.get_size(), vertex_union.get_size());
	for (size_t i = 0; i < vertex_intersection.get_size(); i++)
		printf("%u\n", vertex_intersection.get(i));

	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
	if (graph_conf.get_print_io_stat())
		print_io_thread_stat();
	graph_engine::destroy(graph);
}
<commit_msg>[Graph]: compute union of two sets more efficiently in overlap.<commit_after>/**
 * Copyright 2013 Da Zheng
 *
 * This file is part of SA-GraphLib.
 *
 * SA-GraphLib is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * SA-GraphLib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with SA-GraphLib.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * This program computes the overlap of each pair of vertices
 * given by the user.
 */

#include <signal.h>
#include <google/profiler.h>

#include <tr1/unordered_set>

#include "graph_engine.h"

enum overlap_stage_t
{
	CONSTRUCT_NEIGHBORS,
	COMP_OVERLAP,
} overlap_stage;

/**
 * This contains all vertices that we want to compute pair-wise overlap.
 */
std::vector<vertex_id_t> overlap_vertices;

template<class InputIterator1, class InputIterator2, class Skipper,
	class Merger, class OutputIterator>
size_t unique_merge(InputIterator1 it1, InputIterator1 last1,
		InputIterator2 it2, InputIterator2 last2, Skipper skip,
		Merger merge, OutputIterator result)
{
	OutputIterator result_begin = result;
	while (it1 != last1 && it2 != last2) {
		if (*it2 < *it1) {
			typename std::iterator_traits<OutputIterator>::value_type v = *it2;
			++it2;
			while (it2 != last2 && v == *it2) {
				v = merge(v, *it2);
				++it2;
			}
			if (!skip(v))
				*(result++) = v;
		}
		else if (*it1 < *it2) {
			typename std::iterator_traits<OutputIterator>::value_type v = *it1;
			++it1;
			while (it1 != last1 && v == *it1) {
				v = merge(v, *it1);
				++it1;
			}
			if (!skip(v))
				*(result++) = v;
		}
		else {
			typename std::iterator_traits<OutputIterator>::value_type v = *it1;
			v = merge(v, *it2);
			++it2;
			while (it2 != last2 && v == *it2) {
				v = merge(v, *it2);
				++it2;
			}
			++it1;
			while (it1 != last1 && v == *it1) {
				v = merge(v, *it1);
				++it1;
			}
			if (!skip(v))
				*(result++) = v;
		}
	}

	while (it1 != last1) {
		typename std::iterator_traits<OutputIterator>::value_type v = *it1;
		++it1;
		while (it1 != last1 && v == *it1) {
			v = merge(v, *it1);
			++it1;
		}
		if (!skip(v))
			*(result++) = v;
	}

	while (it2 != last2) {
		typename std::iterator_traits<OutputIterator>::value_type v = *it2;
		++it2;
		while (it2 != last2 && v == *it2) {
			v = merge(v, *it2);
			++it2;
		}
		if (!skip(v))
			*(result++) = v;
	}
	return result - result_begin;
}

class skip_self
{
	vertex_id_t id;
public:
	skip_self(vertex_id_t id) {
		this->id = id;
	}

	bool operator()(vertex_id_t id) {
		return this->id == id;
	}
};

class merge_edge
{
public:
	vertex_id_t operator()(vertex_id_t e1, vertex_id_t e2) {
		assert(e1 == e2);
		return e1;
	}
};

size_t get_unique_neighbors(const page_vertex &vertex,
		std::vector<vertex_id_t> &neighbors)
{
	neighbors.resize(vertex.get_num_edges(edge_type::BOTH_EDGES));
	size_t num_neighbors = unique_merge(
			vertex.get_neigh_begin(edge_type::IN_EDGE),
			vertex.get_neigh_end(edge_type::IN_EDGE),
			vertex.get_neigh_begin(edge_type::OUT_EDGE),
			vertex.get_neigh_end(edge_type::OUT_EDGE),
			skip_self(vertex.get_id()), merge_edge(),
			neighbors.begin());
	neighbors.resize(num_neighbors);
	return num_neighbors;
}

size_t get_common_vertices(const std::vector<vertex_id_t> &vertices1,
		const std::vector<vertex_id_t> &vertices2)
{
	size_t common = 0;
	size_t i, j;
	// We assume both vectors are sorted in the ascending order.
	// We only need to scan them together to extract the common elements.
	for (i = 0, j = 0; i < vertices1.size() && j < vertices2.size();) {
		if (vertices1[i] == vertices2[j]) {
			common++;
			i++;
			j++;
		}
		else if (vertices1[i] > vertices2[j])
			j++;
		else
			i++;

	}
	return common;
}

size_t get_union_vertices(const std::vector<vertex_id_t> &vertices1,
		const std::vector<vertex_id_t> &vertices2)
{
	class skip_none {
	public:
		bool operator()(vertex_id_t id) {
			return false;
		}
	};

	class null_iterator: public std::iterator<std::random_access_iterator_tag, vertex_id_t> {
		vertex_id_t id;
		int idx;
	public:
		typedef typename std::iterator<std::random_access_iterator_tag,
				vertex_id_t>::difference_type difference_type;

		null_iterator() {
			idx = 0;
			id = 0;
		}

		vertex_id_t &operator*() {
			return id;
		}

		null_iterator operator++(int) {
			null_iterator it = *this;
			idx++;
			return it;
		}

		difference_type operator-(const null_iterator &it) {
			return idx - it.idx;
		}
	};

	size_t num_eles = unique_merge(vertices1.begin(), vertices1.end(),
			vertices2.begin(), vertices2.end(), skip_none(), merge_edge(),
			null_iterator());
	return num_eles;
}

class union_set
{
	std::tr1::unordered_set<vertex_id_t> set;
	pthread_mutex_t lock;
public:
	union_set() {
		pthread_mutex_init(&lock, NULL);
	}

	void add(const std::vector<vertex_id_t> &vec) {
		pthread_mutex_lock(&lock);
		set.insert(vec.begin(), vec.end());
		pthread_mutex_unlock(&lock);
	}

	size_t get_size() const {
		return set.size();
	}
} vertex_union;

class intersection_set
{
	int num_added;
	std::vector<vertex_id_t> set;
	pthread_mutex_t lock;
public:
	intersection_set() {
		num_added = 0;
		pthread_mutex_init(&lock, NULL);
	}

	void add(const std::vector<vertex_id_t> &vec);

	size_t get_size() const {
		return set.size();
	}

	vertex_id_t get(int idx) const {
		return set[idx];
	}
} vertex_intersection;

void intersection_set::add(const std::vector<vertex_id_t> &vec)
{
	std::vector<vertex_id_t> copy(vec);
	std::sort(copy.begin(), copy.end());

	std::vector<vertex_id_t> new_set;
	pthread_mutex_lock(&lock);
	num_added++;
	if (num_added == 1) {
		set = copy;
	}
	else {
		size_t i, j;
		// We assume both vectors are sorted in the ascending order.
		// We only need to scan them together to extract the common elements.
		for (i = 0, j = 0; i < set.size() && j < copy.size();) {
			if (set[i] == copy[j]) {
				new_set.push_back(set[i]);
				i++;
				j++;
			}
			else if (set[i] > copy[j])
				j++;
			else
				i++;

		}
		set = new_set;
	}
	pthread_mutex_unlock(&lock);
}

class overlap_vertex: public compute_vertex
{
	std::vector<vertex_id_t> *neighborhood;
public:
	overlap_vertex() {
		neighborhood = NULL;
	}

	overlap_vertex(vertex_id_t id, const vertex_index *index1): compute_vertex(
			id, index1) {
		neighborhood = NULL;
	}

	void run(graph_engine &graph) {
		switch(overlap_stage) {
			case overlap_stage_t::CONSTRUCT_NEIGHBORS:
				run_stage1(graph);
				break;
			case overlap_stage_t::COMP_OVERLAP:
				run_stage2(graph);
				break;
			default:
				assert(0);
		}
	}

	void run_stage1(graph_engine &graph) {
		vertex_id_t id = get_id();
		graph.request_vertices(*this, &id, 1);
	}

	void run_stage2(graph_engine &graph) {
		BOOST_FOREACH(vertex_id_t id, overlap_vertices) {
			if (id == get_id())
				continue;
			overlap_vertex &neigh = (overlap_vertex &) graph.get_vertex(id);
			size_t common = get_common_vertices(*neighborhood, *neigh.neighborhood);
			size_t vunion = get_union_vertices(*neighborhood, *neigh.neighborhood);
			printf("v%u:v%u, common: %ld, union: %ld, overlap: %f\n",
					get_id(), id, common, vunion,
					((double) common) / vunion);
		}
	}

	void run(graph_engine &graph, const page_vertex &vertex) {
		assert(vertex.get_id() == get_id());
		run_on_itself(graph, vertex);
	}

	void run_on_itself(graph_engine &graph, const page_vertex &vertex) {
		neighborhood = new std::vector<vertex_id_t>();
		get_unique_neighbors(vertex, *neighborhood);
		assert(std::is_sorted(neighborhood->begin(), neighborhood->end()));

		std::vector<vertex_id_t>::iterator it = std::lower_bound(
				neighborhood->begin(), neighborhood->end(), get_id());
		if (it != neighborhood->end())
			assert(*it != get_id());
		neighborhood->insert(it, get_id());
		assert(std::is_sorted(neighborhood->begin(), neighborhood->end()));
	}

	void run_on_messages(graph_engine &,
			const vertex_message *msgs[], int num) {
	}
};

void int_handler(int sig_num)
{
	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
	exit(0);
}

int read_vertices(const std::string &file, std::vector<vertex_id_t> &vertices)
{
	FILE *f = fopen(file.c_str(), "r");
	assert(f);
	ssize_t ret;
	char *line = NULL;
	size_t line_size = 0;
	while ((ret = getline(&line, &line_size, f)) > 0) {
		if (line[ret - 1] == '\n')
			line[ret - 1] = 0;
		vertex_id_t id = atol(line);
		printf("%u\n", id);
		vertices.push_back(id);
	}
	fclose(f);
	return vertices.size();
}

int main(int argc, char *argv[])
{
	std::string output_file;
	std::string confs;

	if (argc < 3) {
		fprintf(stderr,
				"overlap conf_file graph_file index_file vertex_file\n");
		exit(-1);
	}

	std::string conf_file = argv[1];
	std::string graph_file = argv[2];
	std::string index_file = argv[3];
	std::string vertex_file = argv[4];

	read_vertices(vertex_file, overlap_vertices);

	config_map configs(conf_file);
	configs.add_options(confs);
	graph_conf.init(configs);
	graph_conf.print();

	signal(SIGINT, int_handler);
	init_io_system(configs);

	graph_index *index = NUMA_graph_index<overlap_vertex>::create(
			index_file, graph_conf.get_num_threads(), params.get_num_nodes());
	graph_engine *graph = graph_engine::create(
			graph_conf.get_num_threads(), params.get_num_nodes(), graph_file,
			index);
	if (!graph_conf.get_prof_file().empty())
		ProfilerStart(graph_conf.get_prof_file().c_str());

	struct timeval start, end;

	gettimeofday(&start, NULL);
	overlap_stage = overlap_stage_t::CONSTRUCT_NEIGHBORS;
	graph->start(overlap_vertices.data(), overlap_vertices.size());
	graph->wait4complete();
	gettimeofday(&end, NULL);
	printf("It takes %f seconds to construct neighborhoods\n",
			time_diff(start, end));

	gettimeofday(&start, NULL);
	overlap_stage = overlap_stage_t::COMP_OVERLAP;
	graph->start(overlap_vertices.data(), overlap_vertices.size());
	graph->wait4complete();
	gettimeofday(&end, NULL);
	printf("It takes %f seconds to compute overlaps\n", time_diff(start, end));

	printf("All vertices have %ld common neighbors and cover %ld vertices\n",
			vertex_intersection.get_size(), vertex_union.get_size());
	for (size_t i = 0; i < vertex_intersection.get_size(); i++)
		printf("%u\n", vertex_intersection.get(i));

	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
	if (graph_conf.get_print_io_stat())
		print_io_thread_stat();
	graph_engine::destroy(graph);
}
<|endoftext|>


<commit_before>/**
 * Non-metric Space Library
 *
 * Authors: Bilegsaikhan Naidan (https://github.com/bileg), Leonid Boytsov (http://boytsov.info).
 * With contributions from Lawrence Cayton (http://lcayton.com/) and others.
 *
 * For the complete list of contributors and further details see:
 * https://github.com/searchivarius/NonMetricSpaceLib
 *
 * Copyright (c) 2014
 *
 * This code is released under the
 * Apache License Version 2.0 http://www.apache.org/licenses/.
 *
 */
#include <cstring>
#include <map>
#include <limits>
#include <iostream>
#include <stdexcept>

#include "utils.h"
#include "params_cmdline.h"
#include "params_def.h"
#include "logging.h"
#include "space.h"
#include "cmd_options.h"

#include <cmath>

namespace similarity {

using std::multimap;
using std::string;

void ParseCommandLine(int argc, char* argv[], bool& bPrintProgress,
                      string&                 LogFile,
                      string&                 LoadIndexLoc,
                      string&                 SaveIndexLoc,
                      string&                 DistType,
                      string&                 SpaceType,
                      shared_ptr<AnyParams>&  SpaceParams,
                      unsigned&               ThreadTestQty,
                      bool&                   AppendToResFile,
                      string&                 ResFilePrefix,
                      unsigned&               TestSetQty,
                      string&                 DataFile,
                      string&                 QueryFile,
                      string&                 CacheGSFilePrefix,
                      float&                  maxCacheGSRelativeQty,
                      bool&                   recallOnly,
                      unsigned&               MaxNumData,
                      unsigned&               MaxNumQuery,
                      vector<unsigned>&       knn,
                      float&                  eps,
                      string&                 RangeArg,
                      string&                 MethodName,
                      shared_ptr<AnyParams>&          IndexTimeParams,
                      vector<shared_ptr<AnyParams>>&  QueryTimeParams) {
  knn.clear();
  RangeArg.clear();
  QueryTimeParams.clear();

  string          indexTimeParamStr;
  vector<string>  vQueryTimeParamStr;
  string          spaceParamStr;
  string          knnArg;
  // Conversion to double is due to an Intel's bug with __builtin_signbit being undefined for float
  double          epsTmp;

  bPrintProgress  = true;

  bool bSuppressPrintProgress;

  CmdOptions cmd_options;

  cmd_options.Add(new CmdParam(SPACE_TYPE_PARAM_OPT, SPACE_TYPE_PARAM_MSG,
                               &spaceParamStr, true));
  cmd_options.Add(new CmdParam(DIST_TYPE_PARAM_OPT, DIST_TYPE_PARAM_MSG,
                               &DistType, false, DIST_TYPE_FLOAT));
  cmd_options.Add(new CmdParam(DATA_FILE_PARAM_OPT, DATA_FILE_PARAM_MSG,
                               &DataFile, true));
  cmd_options.Add(new CmdParam(MAX_NUM_DATA_PARAM_OPT, MAX_NUM_QUERY_PARAM_MSG,
                               &MaxNumData, false, MAX_NUM_DATA_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(QUERY_FILE_PARAM_OPT, QUERY_FILE_PARAM_MSG,
                               &QueryFile, false, QUERY_FILE_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(LOAD_INDEX_PARAM_OPT, LOAD_INDEX_PARAM_MSG,
                               &LoadIndexLoc, false, LOAD_INDEX_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(SAVE_INDEX_PARAM_OPT, SAVE_INDEX_PARAM_MSG,
                               &SaveIndexLoc, false, SAVE_INDEX_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(CACHE_PREFIX_GS_PARAM_OPT, CACHE_PREFIX_GS_PARAM_MSG,
                               &CacheGSFilePrefix, false, CACHE_PREFIX_GS_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(MAX_CACHE_GS_QTY_PARAM_OPT, MAX_CACHE_GS_QTY_PARAM_MSG,
                               &maxCacheGSRelativeQty, false, MAX_CACHE_GS_QTY_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(RECALL_ONLY_PARAM_OPT, RECALL_ONLY_PARAM_MSG,
                               &recallOnly, false, RECALL_ONLY_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(LOG_FILE_PARAM_OPT, LOG_FILE_PARAM_MSG,
                               &LogFile, false, LOG_FILE_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(MAX_NUM_QUERY_PARAM_OPT, MAX_NUM_QUERY_PARAM_MSG,
                               &MaxNumQuery, false, MAX_NUM_QUERY_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(TEST_SET_QTY_PARAM_OPT, TEST_SET_QTY_PARAM_MSG,
                               &TestSetQty, false, TEST_SET_QTY_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(KNN_PARAM_OPT, KNN_PARAM_MSG,
                               &knnArg, false));
  cmd_options.Add(new CmdParam(RANGE_PARAM_OPT, RANGE_PARAM_MSG,
                               &RangeArg, false));
  cmd_options.Add(new CmdParam(EPS_PARAM_OPT, EPS_PARAM_MSG,
                               &epsTmp, false, EPS_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(QUERY_TIME_PARAMS_PARAM_OPT, QUERY_TIME_PARAMS_PARAM_MSG,
                               &vQueryTimeParamStr, false));
  cmd_options.Add(new CmdParam(INDEX_TIME_PARAMS_PARAM_OPT, INDEX_TIME_PARAMS_PARAM_MSG,
                               &indexTimeParamStr, false));
  cmd_options.Add(new CmdParam(METHOD_PARAM_OPT, METHOD_PARAM_MSG,
                               &MethodName, false));
  cmd_options.Add(new CmdParam(THREAD_TEST_QTY_PARAM_OPT, THREAD_TEST_QTY_PARAM_MSG,
                               &ThreadTestQty, false, THREAD_TEST_QTY_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(OUT_FILE_PREFIX_PARAM_OPT, OUT_FILE_PREFIX_PARAM_MSG,
                               &ResFilePrefix, false, OUT_FILE_PREFIX_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(APPEND_TO_RES_FILE_PARAM_OPT, APPEND_TO_RES_FILE_PARAM_MSG,
                               &AppendToResFile, false));
  cmd_options.Add(new CmdParam(NO_PROGRESS_PARAM_OPT, NO_PROGRESS_PARAM_MSG,
                               &bSuppressPrintProgress, false));

  try {
    cmd_options.Parse(argc, argv);
  } catch (const CmdParserException& e) {
    cmd_options.ToString();
    std::cout.flush();
    LOG(LIB_FATAL) << e.what();
  } catch (const std::exception& e) {
    cmd_options.ToString();
    std::cout.flush();
    LOG(LIB_FATAL) << e.what();
  } catch (...) {
    cmd_options.ToString();
    std::cout.flush();
    LOG(LIB_FATAL) << "Failed to parse cmd arguments";
  }

  bPrintProgress = !bSuppressPrintProgress;

  eps = epsTmp;

  ToLower(DistType);
  ToLower(spaceParamStr);
  ToLower(MethodName);

  try {
    {
      vector<string>     desc;
      ParseSpaceArg(spaceParamStr, SpaceType, desc);
      SpaceParams = shared_ptr<AnyParams>(new AnyParams(desc));
    }

    {
      vector<string>     desc;
      ParseArg(indexTimeParamStr, desc);
      IndexTimeParams = shared_ptr<AnyParams>(new AnyParams(desc));
    }

    if (vQueryTimeParamStr.empty())
      vQueryTimeParamStr.push_back("");

    for(const auto s: vQueryTimeParamStr) {
      vector<string>  desc;

      ParseArg(s, desc);
      QueryTimeParams.push_back(shared_ptr<AnyParams>(new AnyParams(desc)));
    }

    if (!knnArg.empty() && !SplitStr(knnArg, knn, ',')) {
      LOG(LIB_FATAL) << "Wrong format of the KNN argument: '" << knnArg;
    }

    if (DataFile.empty()) {
      LOG(LIB_FATAL) << "data file is not specified!";
    }

    if (!DoesFileExist(DataFile)) {
      LOG(LIB_FATAL) << "data file " << DataFile << " doesn't exist";
    }

    if (!QueryFile.empty() && !DoesFileExist(QueryFile)) {
      LOG(LIB_FATAL) << "query file " << QueryFile << " doesn't exist";
    }

    if (!MaxNumQuery && QueryFile.empty()) {
      LOG(LIB_FATAL) << "Set a positive # of queries or specify a query file!";
    }

    CHECK_MSG(MaxNumData < MAX_DATASET_QTY, "The maximum number of points should not exceed" + ConvertToString(MAX_DATASET_QTY));
    CHECK_MSG(MaxNumQuery < MAX_DATASET_QTY, "The maximum number of queries should not exceed" + ConvertToString(MAX_DATASET_QTY));
  } catch (const exception& e) {
    LOG(LIB_FATAL) << "Exception: " << e.what();
  }
}

}

<commit_msg>minor fix in param msg<commit_after>/**
 * Non-metric Space Library
 *
 * Authors: Bilegsaikhan Naidan (https://github.com/bileg), Leonid Boytsov (http://boytsov.info).
 * With contributions from Lawrence Cayton (http://lcayton.com/) and others.
 *
 * For the complete list of contributors and further details see:
 * https://github.com/searchivarius/NonMetricSpaceLib
 *
 * Copyright (c) 2014
 *
 * This code is released under the
 * Apache License Version 2.0 http://www.apache.org/licenses/.
 *
 */
#include <cstring>
#include <map>
#include <limits>
#include <iostream>
#include <stdexcept>

#include "utils.h"
#include "params_cmdline.h"
#include "params_def.h"
#include "logging.h"
#include "space.h"
#include "cmd_options.h"

#include <cmath>

namespace similarity {

using std::multimap;
using std::string;

void ParseCommandLine(int argc, char* argv[], bool& bPrintProgress,
                      string&                 LogFile,
                      string&                 LoadIndexLoc,
                      string&                 SaveIndexLoc,
                      string&                 DistType,
                      string&                 SpaceType,
                      shared_ptr<AnyParams>&  SpaceParams,
                      unsigned&               ThreadTestQty,
                      bool&                   AppendToResFile,
                      string&                 ResFilePrefix,
                      unsigned&               TestSetQty,
                      string&                 DataFile,
                      string&                 QueryFile,
                      string&                 CacheGSFilePrefix,
                      float&                  maxCacheGSRelativeQty,
                      bool&                   recallOnly,
                      unsigned&               MaxNumData,
                      unsigned&               MaxNumQuery,
                      vector<unsigned>&       knn,
                      float&                  eps,
                      string&                 RangeArg,
                      string&                 MethodName,
                      shared_ptr<AnyParams>&          IndexTimeParams,
                      vector<shared_ptr<AnyParams>>&  QueryTimeParams) {
  knn.clear();
  RangeArg.clear();
  QueryTimeParams.clear();

  string          indexTimeParamStr;
  vector<string>  vQueryTimeParamStr;
  string          spaceParamStr;
  string          knnArg;
  // Conversion to double is due to an Intel's bug with __builtin_signbit being undefined for float
  double          epsTmp;

  bPrintProgress  = true;

  bool bSuppressPrintProgress;

  CmdOptions cmd_options;

  cmd_options.Add(new CmdParam(SPACE_TYPE_PARAM_OPT, SPACE_TYPE_PARAM_MSG,
                               &spaceParamStr, true));
  cmd_options.Add(new CmdParam(DIST_TYPE_PARAM_OPT, DIST_TYPE_PARAM_MSG,
                               &DistType, false, DIST_TYPE_FLOAT));
  cmd_options.Add(new CmdParam(DATA_FILE_PARAM_OPT, DATA_FILE_PARAM_MSG,
                               &DataFile, true));
  cmd_options.Add(new CmdParam(MAX_NUM_DATA_PARAM_OPT, MAX_NUM_DATA_PARAM_MSG,
                               &MaxNumData, false, MAX_NUM_DATA_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(QUERY_FILE_PARAM_OPT, QUERY_FILE_PARAM_MSG,
                               &QueryFile, false, QUERY_FILE_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(LOAD_INDEX_PARAM_OPT, LOAD_INDEX_PARAM_MSG,
                               &LoadIndexLoc, false, LOAD_INDEX_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(SAVE_INDEX_PARAM_OPT, SAVE_INDEX_PARAM_MSG,
                               &SaveIndexLoc, false, SAVE_INDEX_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(CACHE_PREFIX_GS_PARAM_OPT, CACHE_PREFIX_GS_PARAM_MSG,
                               &CacheGSFilePrefix, false, CACHE_PREFIX_GS_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(MAX_CACHE_GS_QTY_PARAM_OPT, MAX_CACHE_GS_QTY_PARAM_MSG,
                               &maxCacheGSRelativeQty, false, MAX_CACHE_GS_QTY_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(RECALL_ONLY_PARAM_OPT, RECALL_ONLY_PARAM_MSG,
                               &recallOnly, false, RECALL_ONLY_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(LOG_FILE_PARAM_OPT, LOG_FILE_PARAM_MSG,
                               &LogFile, false, LOG_FILE_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(MAX_NUM_QUERY_PARAM_OPT, MAX_NUM_QUERY_PARAM_MSG,
                               &MaxNumQuery, false, MAX_NUM_QUERY_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(TEST_SET_QTY_PARAM_OPT, TEST_SET_QTY_PARAM_MSG,
                               &TestSetQty, false, TEST_SET_QTY_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(KNN_PARAM_OPT, KNN_PARAM_MSG,
                               &knnArg, false));
  cmd_options.Add(new CmdParam(RANGE_PARAM_OPT, RANGE_PARAM_MSG,
                               &RangeArg, false));
  cmd_options.Add(new CmdParam(EPS_PARAM_OPT, EPS_PARAM_MSG,
                               &epsTmp, false, EPS_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(QUERY_TIME_PARAMS_PARAM_OPT, QUERY_TIME_PARAMS_PARAM_MSG,
                               &vQueryTimeParamStr, false));
  cmd_options.Add(new CmdParam(INDEX_TIME_PARAMS_PARAM_OPT, INDEX_TIME_PARAMS_PARAM_MSG,
                               &indexTimeParamStr, false));
  cmd_options.Add(new CmdParam(METHOD_PARAM_OPT, METHOD_PARAM_MSG,
                               &MethodName, false));
  cmd_options.Add(new CmdParam(THREAD_TEST_QTY_PARAM_OPT, THREAD_TEST_QTY_PARAM_MSG,
                               &ThreadTestQty, false, THREAD_TEST_QTY_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(OUT_FILE_PREFIX_PARAM_OPT, OUT_FILE_PREFIX_PARAM_MSG,
                               &ResFilePrefix, false, OUT_FILE_PREFIX_PARAM_DEFAULT));
  cmd_options.Add(new CmdParam(APPEND_TO_RES_FILE_PARAM_OPT, APPEND_TO_RES_FILE_PARAM_MSG,
                               &AppendToResFile, false));
  cmd_options.Add(new CmdParam(NO_PROGRESS_PARAM_OPT, NO_PROGRESS_PARAM_MSG,
                               &bSuppressPrintProgress, false));

  try {
    cmd_options.Parse(argc, argv);
  } catch (const CmdParserException& e) {
    cmd_options.ToString();
    std::cout.flush();
    LOG(LIB_FATAL) << e.what();
  } catch (const std::exception& e) {
    cmd_options.ToString();
    std::cout.flush();
    LOG(LIB_FATAL) << e.what();
  } catch (...) {
    cmd_options.ToString();
    std::cout.flush();
    LOG(LIB_FATAL) << "Failed to parse cmd arguments";
  }

  bPrintProgress = !bSuppressPrintProgress;

  eps = epsTmp;

  ToLower(DistType);
  ToLower(spaceParamStr);
  ToLower(MethodName);

  try {
    {
      vector<string>     desc;
      ParseSpaceArg(spaceParamStr, SpaceType, desc);
      SpaceParams = shared_ptr<AnyParams>(new AnyParams(desc));
    }

    {
      vector<string>     desc;
      ParseArg(indexTimeParamStr, desc);
      IndexTimeParams = shared_ptr<AnyParams>(new AnyParams(desc));
    }

    if (vQueryTimeParamStr.empty())
      vQueryTimeParamStr.push_back("");

    for(const auto s: vQueryTimeParamStr) {
      vector<string>  desc;

      ParseArg(s, desc);
      QueryTimeParams.push_back(shared_ptr<AnyParams>(new AnyParams(desc)));
    }

    if (!knnArg.empty() && !SplitStr(knnArg, knn, ',')) {
      LOG(LIB_FATAL) << "Wrong format of the KNN argument: '" << knnArg;
    }

    if (DataFile.empty()) {
      LOG(LIB_FATAL) << "data file is not specified!";
    }

    if (!DoesFileExist(DataFile)) {
      LOG(LIB_FATAL) << "data file " << DataFile << " doesn't exist";
    }

    if (!QueryFile.empty() && !DoesFileExist(QueryFile)) {
      LOG(LIB_FATAL) << "query file " << QueryFile << " doesn't exist";
    }

    if (!MaxNumQuery && QueryFile.empty()) {
      LOG(LIB_FATAL) << "Set a positive # of queries or specify a query file!";
    }

    CHECK_MSG(MaxNumData < MAX_DATASET_QTY, "The maximum number of points should not exceed" + ConvertToString(MAX_DATASET_QTY));
    CHECK_MSG(MaxNumQuery < MAX_DATASET_QTY, "The maximum number of queries should not exceed" + ConvertToString(MAX_DATASET_QTY));
  } catch (const exception& e) {
    LOG(LIB_FATAL) << "Exception: " << e.what();
  }
}

}

<|endoftext|>


<commit_before>// $Id: haighMallionShiftProcessor.C,v 1.4 2000/09/21 09:46:03 oliver Exp $

#include <BALL/NMR/haighMallionShiftProcessor.h>
#include <BALL/KERNEL/atomIterator.h>
#include <BALL/KERNEL/PTE.h>

namespace BALL
{

	const float HaighMallionShiftProcessor::big_loop_radius_		= 1.39e-10;
	const float HaighMallionShiftProcessor::little_loop_radius_ = 1.182e-10;
	const float HaighMallionShiftProcessor::B_ = 5.455e-6;					//Konstante in IBG(r)

	float getLambda(const Vector3& v1, const Vector3& v2)
	{
		if (v2.x==0)
		{
			if (v2.y==0)
			{
				if (v2.z==0)
				{
					return 0;
				}
				else
				{
					return (v1.z/v2.z);
				}
			}
			else
			{
				return (v1.y/v2.y);
			}
		}
		else
		{
			return (v1.x/v2.x);
		}
	}

	HaighMallionShiftProcessor::HaighMallionShiftProcessor()
		throw()
	{
		asrings_ = new String*[4];

		asrings_[0]=new String[13];

		asrings_[0][0]="TRP";
		asrings_[0][1]="CG";
		asrings_[0][2]="CD2";
		asrings_[0][3]="CE2";
		asrings_[0][4]="NE1";
		asrings_[0][5]="CD1";
		asrings_[0][6]="NULL";
		asrings_[0][7]="CD2";
		asrings_[0][8]="CZ2";
		asrings_[0][9]="CZ3";
		asrings_[0][10]="CE3";
		asrings_[0][11]="CH2";
		asrings_[0][12]="CE2";

		asrings_[1]=new String[7];

		asrings_[1][0]="PHE";
		asrings_[1][1]="CG";
		asrings_[1][2]="CD2";
		asrings_[1][3]="CE2";
		asrings_[1][4]="CZ";
		asrings_[1][5]="CE1";
		asrings_[1][6]="CD1";

		asrings_[2]=new String[7];

		asrings_[2][0]="TYR";
		asrings_[2][1]="CG";
		asrings_[2][2]="CD2";
		asrings_[2][3]="CE2";
		asrings_[2][4]="CZ";
		asrings_[2][5]="CE1";
		asrings_[2][6]="CD1";

		asrings_[3]=new String[7];

		asrings_[3][0]="HIS";
		asrings_[3][1]="CB";
		asrings_[3][2]="CD2";
		asrings_[3][3]="NE2";
		asrings_[3][4]="CE1";
		asrings_[3][5]="ND1";
		asrings_[3][6]="NULL";
	}

	HaighMallionShiftProcessor::~HaighMallionShiftProcessor()
		throw()
	{
	}

	bool HaighMallionShiftProcessor::finish()
		throw()
	{
		// Berechnung des shifts fuer jedes Proton der liste _proton_list

		// hshift bezeichnet den chemicalshift der durch den gerade abgearbeiteten Ring verursacht wird.

		// iteriere ueber alle Protonen
		// fuer jedes Proton iteriere ueber alle Ringe und berechne chemical_shift

		Vector3* vectorField = new Vector3[6];

		Size zaehler, numberOfRings;
		float radius, shift;

		for (list<PDBAtom*>::iterator proton_iter = proton_list_.begin();
				 proton_iter != proton_list_.end(); ++proton_iter)
		{
			for(list<Residue*>::iterator arom_iter = aromat_list_.begin();
					arom_iter != aromat_list_.end(); ++arom_iter)
			{
				const Residue& residue = *(*arom_iter);
				if ((*proton_iter)->getResidue() == &residue)
				{
					continue;
				}

				if (residue.getName()=="TRP")
				{
					zaehler = 0;
					numberOfRings = 2;
					radius = big_loop_radius_;
				}
				if (residue.getName()=="PHE")
				{
					zaehler = 1;
					numberOfRings = 1;
					radius = big_loop_radius_;
				}
				if (residue.getName()=="TYR")
				{
					zaehler = 2;
					numberOfRings = 1;
					radius = little_loop_radius_;
				}
				if (residue.getName()=="HIS")
				{
					zaehler = 3;
					numberOfRings = 1;
					radius = little_loop_radius_;
				}

				Position vzaehler = 0;
				Position hilf = 0;
				while(numberOfRings) // for all rings in the amino acid
				{
					//Aufbau von _vector_feld
					for(Position pos = hilf; pos < hilf + 6; pos++ )
					{
						if (asrings_[zaehler][1 + pos] == "NULL")
						{
							break;
						}

						for(AtomIterator atom_iter = residue.beginAtom();
								+ atom_iter;
								++ atom_iter)
						{
							if(asrings_[zaehler][1 + pos] == (*atom_iter).getName())
							{
								vectorField[vzaehler] = (*atom_iter).getPosition();
								vzaehler++ ;
								break;	// gefunden
							}
						}
					}

					// _vector_feld ist bestimmt und vzaehler zeigt hinter letzten gueltigen vector

					// bestimme den Mittelpunkt

					Vector3 center;

					for (Position pos = 0; pos < vzaehler; pos++)
					{
						center += vectorField[pos];
					}
					center /= vzaehler;

					// bestimme den NormalenVektor der Ringebene

					Vector3 normal;

					for (Position pos = 0; pos < vzaehler; pos++)
					{
						const Vector3& links  = vectorField[(pos + 0) % (vzaehler)];
						const Vector3& mitte  = vectorField[(pos + 1) % (vzaehler)];
						const Vector3& rechts = vectorField[(pos + 2) % (vzaehler)];
						normal += (mitte - links) % (mitte - rechts);
					}

					normal /= vzaehler; // Normalenvektor wurde gemittelt
					normal.normalize(); //Normalenvektor ist jetzt NormalenEinheitsvektor

					// Die Ringebene wurde ermittelt

					// berechne den Flaecheninhalt des Rings
					const Vector3 ein_vector(vectorField[5] - vectorField[1]);
					Vector3 v(vectorField[1] - vectorField[2]);
					float ringSurface = (vectorField[0] - vectorField[1]) * (vectorField[5] - vectorField[1]);
					ringSurface += ein_vector.getLength() * v.getLength();

					// bestimme den chemicalshift des Protons durch diesen Ring
					v = (*proton_iter)->getPosition();

					// berechne Projektion des Protons auf die Ringebene
					float a = normal * v-normal * center;
					Vector3 v_ring;

					if (a < 0)
					{
						v_ring = v - a * normal;
					}
					else
					{
						v_ring= v + a * normal;
					}

					// Schleife ueber alle Bindungen des Rings
					float sum = 0;
					for (Position pos = 0; pos < vzaehler; pos++ )
					{
						const Vector3& eins = vectorField[(pos + 0) % (vzaehler)];
						const Vector3& zwei = vectorField[(pos + 1) % (vzaehler)];

						// berechne Abstand von Proton zu eins und zwei
						Vector3 ein_vector = v - eins;
						float a_eins = (ein_vector.getLength() / radius) * 1e-10;
						ein_vector = v - zwei;
						float a_zwei = (ein_vector.getLength() / radius) * 1e-10;

						// berechne Flaecheninhalt des 3Ecks aus eins,zwei,v_ring
						Vector3 eins_zwei(eins - zwei);

						Vector3 n0 = normal % eins_zwei;
						n0.normalize();

						float h = (n0 * v_ring  -  n0 * zwei);
						if (h < 0)
						{
							h = -h;
						}

						float f = 0.5 * h * eins_zwei.getLength() / ringSurface;

						// bestimme das Vorzeichen der Dreiecksflaeche
						if (getLambda((v_ring - eins) % (v_ring - zwei), normal) > 0)
						{
							f *= -1;
						}

						// addiere gesamtsumme
						sum += f *( (1 / (a_eins * a_eins * a_eins)) + (1 / (a_zwei * a_zwei * a_zwei)) );
					}

					shift += sum * B_; // zaehle aktuellen chemicalshift zum Gesamtwert dazu

					vzaehler = 0;
					numberOfRings--;
					hilf = 6; // fuer den naechsten schleifendurchlauf
				}
			}

			// Setze Property chemicalshift des gerade bearbeiteten Protons auf den entsprechenden Wert.
			float hshift = shift * 1e6;
			shift = (*proton_iter)->getProperty("chemical_shift").getFloat();
			shift += hshift;
			(*proton_iter)->setProperty("chemical_shift", shift);
			(*proton_iter)->setProperty("HM", hshift);
		}

		return true;
	}

	Processor::Result HaighMallionShiftProcessor::operator () (Composite& object)
		throw()
	{
		// Arbeitet als Kollektor :
		// - Alle Ringe werden in _aromat_list gespeichert
		// - Alle Protonen werden in _protonlist gespeichert
		// - die Berechnung erfolgt dann in der Finish Prozedur

		// erganze _aromat_list um aromatische Residues
		if ( RTTI::isKindOf<Residue>(object) )
		{
			Residue* residue = RTTI::castTo<Residue>(object);
			for(Position pos = 0; pos < 4; pos++ )
			{
				if (asrings_[pos][0] == residue->getName())
				{
					aromat_list_.push_back(residue);
					break; // gefunden und schleife hinterher beenden
				}
			}
			return Processor::CONTINUE;
		}

		// erganze proton_list_	um H
		if (RTTI::isKindOf<PDBAtom>(object))
		{
			PDBAtom* atom_ptr = RTTI::castTo<PDBAtom>(object);
			if (atom_ptr->getElement() == PTE[Element::H])
			{
				proton_list_.push_back(atom_ptr);
			}
		}

		return Processor::CONTINUE;
	}

} // namespace BALL
<commit_msg>added: symbolic name for shift property<commit_after>// $Id: haighMallionShiftProcessor.C,v 1.5 2000/09/22 12:09:33 oliver Exp $

#include <BALL/NMR/haighMallionShiftProcessor.h>
#include <BALL/KERNEL/atomIterator.h>
#include <BALL/KERNEL/PTE.h>

namespace BALL
{

  const char* HaighMallionShiftProcessor::PROPERTY__RING_CURRENT_SHIFT = "RingCurrentShift[HM]";

	const float HaighMallionShiftProcessor::big_loop_radius_		= 1.39e-10;
	const float HaighMallionShiftProcessor::little_loop_radius_ = 1.182e-10;
	const float HaighMallionShiftProcessor::B_ = 5.455e-6;					//Konstante in IBG(r)

	float getLambda(const Vector3& v1, const Vector3& v2)
	{
		if (v2.x==0)
		{
			if (v2.y==0)
			{
				if (v2.z==0)
				{
					return 0;
				}
				else
				{
					return (v1.z/v2.z);
				}
			}
			else
			{
				return (v1.y/v2.y);
			}
		}
		else
		{
			return (v1.x/v2.x);
		}
	}

	HaighMallionShiftProcessor::HaighMallionShiftProcessor()
		throw()
	{
		asrings_ = new String*[4];

		asrings_[0]=new String[13];

		asrings_[0][0]="TRP";
		asrings_[0][1]="CG";
		asrings_[0][2]="CD2";
		asrings_[0][3]="CE2";
		asrings_[0][4]="NE1";
		asrings_[0][5]="CD1";
		asrings_[0][6]="NULL";
		asrings_[0][7]="CD2";
		asrings_[0][8]="CZ2";
		asrings_[0][9]="CZ3";
		asrings_[0][10]="CE3";
		asrings_[0][11]="CH2";
		asrings_[0][12]="CE2";

		asrings_[1]=new String[7];

		asrings_[1][0]="PHE";
		asrings_[1][1]="CG";
		asrings_[1][2]="CD2";
		asrings_[1][3]="CE2";
		asrings_[1][4]="CZ";
		asrings_[1][5]="CE1";
		asrings_[1][6]="CD1";

		asrings_[2]=new String[7];

		asrings_[2][0]="TYR";
		asrings_[2][1]="CG";
		asrings_[2][2]="CD2";
		asrings_[2][3]="CE2";
		asrings_[2][4]="CZ";
		asrings_[2][5]="CE1";
		asrings_[2][6]="CD1";

		asrings_[3]=new String[7];

		asrings_[3][0]="HIS";
		asrings_[3][1]="CB";
		asrings_[3][2]="CD2";
		asrings_[3][3]="NE2";
		asrings_[3][4]="CE1";
		asrings_[3][5]="ND1";
		asrings_[3][6]="NULL";
	}

	HaighMallionShiftProcessor::~HaighMallionShiftProcessor()
		throw()
	{
	}

	bool HaighMallionShiftProcessor::finish()
		throw()
	{
		// Berechnung des shifts fuer jedes Proton der liste _proton_list

		// hshift bezeichnet den chemicalshift der durch den gerade abgearbeiteten Ring verursacht wird.

		// iteriere ueber alle Protonen
		// fuer jedes Proton iteriere ueber alle Ringe und berechne chemical_shift

		Vector3* vectorField = new Vector3[6];

		Size zaehler, numberOfRings;
		float radius, shift;

		for (list<PDBAtom*>::iterator proton_iter = proton_list_.begin();
				 proton_iter != proton_list_.end(); ++proton_iter)
		{
			for(list<Residue*>::iterator arom_iter = aromat_list_.begin();
					arom_iter != aromat_list_.end(); ++arom_iter)
			{
				const Residue& residue = *(*arom_iter);
				if ((*proton_iter)->getResidue() == &residue)
				{
					continue;
				}

				if (residue.getName()=="TRP")
				{
					zaehler = 0;
					numberOfRings = 2;
					radius = big_loop_radius_;
				}
				if (residue.getName()=="PHE")
				{
					zaehler = 1;
					numberOfRings = 1;
					radius = big_loop_radius_;
				}
				if (residue.getName()=="TYR")
				{
					zaehler = 2;
					numberOfRings = 1;
					radius = little_loop_radius_;
				}
				if (residue.getName()=="HIS")
				{
					zaehler = 3;
					numberOfRings = 1;
					radius = little_loop_radius_;
				}

				Position vzaehler = 0;
				Position hilf = 0;
				while(numberOfRings) // for all rings in the amino acid
				{
					//Aufbau von _vector_feld
					for(Position pos = hilf; pos < hilf + 6; pos++ )
					{
						if (asrings_[zaehler][1 + pos] == "NULL")
						{
							break;
						}

						for(AtomIterator atom_iter = residue.beginAtom();
								+ atom_iter;
								++ atom_iter)
						{
							if(asrings_[zaehler][1 + pos] == (*atom_iter).getName())
							{
								vectorField[vzaehler] = (*atom_iter).getPosition();
								vzaehler++ ;
								break;	// gefunden
							}
						}
					}

					// _vector_feld ist bestimmt und vzaehler zeigt hinter letzten gueltigen vector

					// bestimme den Mittelpunkt

					Vector3 center;

					for (Position pos = 0; pos < vzaehler; pos++)
					{
						center += vectorField[pos];
					}
					center /= vzaehler;

					// bestimme den NormalenVektor der Ringebene

					Vector3 normal;

					for (Position pos = 0; pos < vzaehler; pos++)
					{
						const Vector3& links  = vectorField[(pos + 0) % (vzaehler)];
						const Vector3& mitte  = vectorField[(pos + 1) % (vzaehler)];
						const Vector3& rechts = vectorField[(pos + 2) % (vzaehler)];
						normal += (mitte - links) % (mitte - rechts);
					}

					normal /= vzaehler; // Normalenvektor wurde gemittelt
					normal.normalize(); //Normalenvektor ist jetzt NormalenEinheitsvektor

					// Die Ringebene wurde ermittelt

					// berechne den Flaecheninhalt des Rings
					const Vector3 ein_vector(vectorField[5] - vectorField[1]);
					Vector3 v(vectorField[1] - vectorField[2]);
					float ringSurface = (vectorField[0] - vectorField[1]) * (vectorField[5] - vectorField[1]);
					ringSurface += ein_vector.getLength() * v.getLength();

					// bestimme den chemicalshift des Protons durch diesen Ring
					v = (*proton_iter)->getPosition();

					// berechne Projektion des Protons auf die Ringebene
					float a = normal * v-normal * center;
					Vector3 v_ring;

					if (a < 0)
					{
						v_ring = v - a * normal;
					}
					else
					{
						v_ring= v + a * normal;
					}

					// Schleife ueber alle Bindungen des Rings
					float sum = 0;
					for (Position pos = 0; pos < vzaehler; pos++ )
					{
						const Vector3& eins = vectorField[(pos + 0) % (vzaehler)];
						const Vector3& zwei = vectorField[(pos + 1) % (vzaehler)];

						// berechne Abstand von Proton zu eins und zwei
						Vector3 ein_vector = v - eins;
						float a_eins = (ein_vector.getLength() / radius) * 1e-10;
						ein_vector = v - zwei;
						float a_zwei = (ein_vector.getLength() / radius) * 1e-10;

						// berechne Flaecheninhalt des 3Ecks aus eins,zwei,v_ring
						Vector3 eins_zwei(eins - zwei);

						Vector3 n0 = normal % eins_zwei;
						n0.normalize();

						float h = (n0 * v_ring  -  n0 * zwei);
						if (h < 0)
						{
							h = -h;
						}

						float f = 0.5 * h * eins_zwei.getLength() / ringSurface;

						// bestimme das Vorzeichen der Dreiecksflaeche
						if (getLambda((v_ring - eins) % (v_ring - zwei), normal) > 0)
						{
							f *= -1;
						}

						// addiere gesamtsumme
						sum += f *( (1 / (a_eins * a_eins * a_eins)) + (1 / (a_zwei * a_zwei * a_zwei)) );
					}

					shift += sum * B_; // zaehle aktuellen chemicalshift zum Gesamtwert dazu

					vzaehler = 0;
					numberOfRings--;
					hilf = 6; // fuer den naechsten schleifendurchlauf
				}
			}

			// Setze Property chemicalshift des gerade bearbeiteten Protons auf den entsprechenden Wert.
			float hshift = shift * 1e6;
			shift = (*proton_iter)->getProperty("chemical_shift").getFloat();
			shift += hshift;
			(*proton_iter)->setProperty("chemical_shift", shift);
			(*proton_iter)->setProperty("HM", hshift);
		}

		return true;
	}

	Processor::Result HaighMallionShiftProcessor::operator () (Composite& object)
		throw()
	{
		// Arbeitet als Kollektor :
		// - Alle Ringe werden in _aromat_list gespeichert
		// - Alle Protonen werden in _protonlist gespeichert
		// - die Berechnung erfolgt dann in der Finish Prozedur

		// erganze _aromat_list um aromatische Residues
		if ( RTTI::isKindOf<Residue>(object) )
		{
			Residue* residue = RTTI::castTo<Residue>(object);
			for(Position pos = 0; pos < 4; pos++ )
			{
				if (asrings_[pos][0] == residue->getName())
				{
					aromat_list_.push_back(residue);
					break; // gefunden und schleife hinterher beenden
				}
			}
			return Processor::CONTINUE;
		}

		// erganze proton_list_	um H
		if (RTTI::isKindOf<PDBAtom>(object))
		{
			PDBAtom* atom_ptr = RTTI::castTo<PDBAtom>(object);
			if (atom_ptr->getElement() == PTE[Element::H])
			{
				proton_list_.push_back(atom_ptr);
			}
		}

		return Processor::CONTINUE;
	}

} // namespace BALL
<|endoftext|>


<commit_before>/*****************************************************************************
 * Copyright (C) 2011-2016 Michael Ira Krufky
 *
 * Author: Michael Ira Krufky <mkrufky@linuxtv.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <inttypes.h>
#include "string.h"

#include "stats.h"
#include "log.h"
#define CLASS_MODULE "stats"

#define DBG 0

#define dPrintf(fmt, arg...) __dPrintf(DBG_STATS, "(%s) " fmt, parent, ##arg)

stats::stats(const char *caller)
  : tei_count(0)
  , __timenow(0)
  , parent(caller)
  , streamtime_cb(NULL)
  , streamtime_priv(NULL)
  , statistics_cb(NULL)
  , statistics_priv(NULL)
{
	dPrintf("(%s)", parent);
}

stats::~stats()
{
	dPrintf("(%s)", parent);
	show(false);
}

#if 0
stats::stats(const stats&)
{
	dPrintf("(%s, copy)", parent);
}

stats& stats::operator= (const stats& cSource)
{
	dPrintf("(%s, operator=)", parent);

	if (this == &cSource)
		return *this;

	return *this;
}
#endif

static void parse_pcr(uint8_t *pcr, uint64_t *pcr_base, unsigned int *pcr_ext)
{
	*pcr_base = ((uint64_t)pcr[0] * 0x2000000) +
		    ((uint64_t)pcr[1] * 0x20000) +
		    ((uint64_t)pcr[2] * 0x200) +
		    ((uint64_t)pcr[3] * 0x02) +
		    ((uint64_t)(pcr[4] & 0x80) >> 7);

	*pcr_ext = ((pcr[4] & 0x01) * 0x100) + pcr[5];

	return;
}

static time_t walltime(void *p) { (void)p; return time(NULL); }

char *stats_scale_unit(char *b, size_t n, uint64_t x)
{
	memset(b, 0, n);

	if (x >= 1000000) {
#if 0
		if ((x % 1000000) < 100)
			snprintf(b, n, "%3" PRIu64 ".%03" PRIu64 " m", x / 1000000, x % 1000000);
		else
#endif
			snprintf(b, n, "%3" PRIu64 ".%03" PRIu64 " m", x / 1000000, x % 1000000);
	} else if (x >= 1000) {
#if 0
		if ((x % 1000) < 100)
			snprintf(b, n, "%3" PRIu64 ".%03" PRIu64 " k", x / 1000, x % 1000);
		else
#endif
			snprintf(b, n, "%3" PRIu64 ".%03" PRIu64 " k", x / 1000, x % 1000);
	} else
		snprintf(b, n, "    %3" PRIu64 "  ", x);
	return b;
}

void stats::show(bool per_sec)
{
	if (statistics_cb) {
		statistics_cb(statistics_priv, statistics, discontinuities, tei_count, per_sec);
		return;
	}
	for (stats_map::const_iterator iter = statistics.begin(); iter != statistics.end(); ++iter) {
		char a[16];
		char b[16];
		__log_printf(stderr, "pid %04x %5" PRIu64 " p%s  %sb%s  %sbit\n",
			     iter->first, iter->second / 188, (per_sec) ? "/s" : "",
			     stats_scale_unit(a, sizeof(a), iter->second), (per_sec) ? "/s" : "",
			     stats_scale_unit(b, sizeof(b), iter->second * 8));
	}
	for (stats_map::const_iterator iter = discontinuities.begin(); iter != discontinuities.end(); ++iter)
		__log_printf(stderr, "pid %04x\t%" PRIu64 " continuity errors (%" PRIu64 "%%)\n", iter->first, iter->second, ((!iter->second) || (!statistics[iter->first])) ? 0 : (!statistics.count(iter->first)) ? 0 : (100 * iter->second / (statistics[iter->first] / 188)));

	if (tei_count) __log_printf(stderr, "tei count: %" PRIu64 " (%" PRIu64 "%%)\n", tei_count, (!statistics[0x2000]) ? 0 : (18800 * tei_count / statistics[0x2000]));
}

void stats::push_pid(int c, const uint16_t pid)
{
	streamtime_callback cb = (streamtime_cb) ? streamtime_cb : &walltime;
	time_t timenow = cb(streamtime_priv);

	if (timenow > __timenow) {
		show();
		clear_stats();
		__timenow = timenow;
	}

	__push_pid(c, pid);
}

pkt_stats_t *stats::parse(const uint8_t *p, pkt_stats_t *pkt_stats)
{
	adaptation_field_t adapt;
	pkt_hdr_t hdr;

	return parse(p, pkt_stats, hdr, adapt);
}

pkt_stats_t *stats::parse(const uint8_t *p, pkt_stats_t *pkt_stats, pkt_hdr_t &hdr, adaptation_field_t &adapt)
{
	if (pkt_stats) {
		memset(pkt_stats, 0, sizeof(pkt_stats_t));

		const uint8_t *q = p;

		memset(&adapt, 0, sizeof(adapt));
		memset(&hdr, 0, sizeof(hdr));

		hdr.sync_byte          = q[0];
		hdr.tei                = (q[1] & 0x80) >> 7;
		hdr.payload_unit_start = (q[1] & 0x40) >> 6;
		hdr.transport_priority = (q[1] & 0x20) >> 5;
		hdr.pid                = ((q[1] & 0x1f) << 8) | q[2];
		hdr.scrambling         = (q[3] & 0xc0) >> 6;
		hdr.adaptation_flags   = (q[3] & 0x30) >> 4;
		hdr.continuity_ctr     = (q[3] & 0x0f);

		if (hdr.adaptation_flags & 0x02) {
			q += 4;
			adapt.field_length   = q[0];
			adapt.discontinuity  = (q[1] & 0x80) >> 7;
			adapt.random_access  = (q[1] & 0x40) >> 6; /* set to 1 if the PES pkt in this TS pkt starts an a/v sequence */
			adapt.es_priority    = (q[1] & 0x20) >> 5;
			adapt.pcr            = (q[1] & 0x10) >> 4;
			adapt.opcr           = (q[1] & 0x08) >> 3;
			adapt.splicing_point = (q[1] & 0x04) >> 2;
			adapt.tp_priv_data   = (q[1] & 0x02) >> 1;
			adapt.field_ext      = (q[1] & 0x01) >> 0;

			if (adapt.pcr) {
				memcpy(adapt.PCR, &q[2], 6);
				q += 6;
			}
			if (adapt.opcr) {
				memcpy(adapt.OPCR, &q[2], 6);
				q += 6;
			}
			if (adapt.splicing_point) {
				adapt.splicing_countdown = q[2];
				q ++;
			}
		}

		pkt_stats->sync_loss = (hdr.sync_byte != 0x47) ? true : false;
		if (!pkt_stats->sync_loss) {
			pkt_stats->tei = (hdr.tei) ? true : false;
			pkt_stats->pid = hdr.pid;
		} else
			pkt_stats->pid = (uint16_t) - 1;
	}
	return pkt_stats;
}

void stats::clear_stats()
{
	statistics.clear();
	discontinuities.clear();
	last_pcr_base.clear();
	tei_count = 0;
}

void stats::push_stats(pkt_stats_t *pkt_stats)
{
	if (pkt_stats->tei) {
		tei_count++;
		push_pid((uint16_t) - 1);
	} else
		push_pid(pkt_stats->pid);
}

void stats::push(const uint8_t *p, pkt_stats_t *pkt_stats)
{
	adaptation_field_t adapt;
	pkt_hdr_t hdr;

	if (!pkt_stats) {
		__push(p);
		return;
	}

	memset(pkt_stats, 0, sizeof(pkt_stats_t));

	parse(p, pkt_stats, hdr, adapt);

	if (hdr.adaptation_flags & 0x01) {// payload present
		if (continuity.count(hdr.pid)) {
			uint8_t next = (continuity[hdr.pid] + 1) & 0x0f;
			if ((next != (hdr.continuity_ctr & 0x0f)) && (hdr.continuity_ctr + continuity[hdr.pid] > 0)) {
				if (!(hdr.adaptation_flags & 0x02) && (adapt.discontinuity)) {
					push_discontinuity(hdr.pid);
#if DBG
					dPrintf("CONTINUITY ERROR pid: %04x cur: 0x%x prev 0x%x", hdr.pid, hdr.continuity_ctr, continuity[hdr.pid]);
#endif
				}
			}
		}
		continuity[hdr.pid] = hdr.continuity_ctr;
	}

	if (hdr.adaptation_flags & 0x02) {
		if (adapt.pcr) {
			uint64_t pcr_base;
			unsigned int pcr_ext;

			parse_pcr(adapt.PCR, &pcr_base, &pcr_ext);
			__log_printf(stderr, "PID: 0x%04x, PCR base: %" PRIu64 ", ext: %d\n", hdr.pid, pcr_base, pcr_ext);

#if DBG
			stats_map::const_iterator iter = last_pcr_base.find(hdr.pid);
			if ((iter != last_pcr_base.end()) && (pcr_base < iter->second))
				__log_printf(stderr, "%s: PID: 0x%04x, %" PRIu64 " < %" PRIu64 " !!!\n",
					__func__, hdr.pid, pcr_base, iter->second);
#endif
			last_pcr_base[hdr.pid] = pcr_base;
		}
		if (adapt.opcr) {
			uint64_t pcr_base;
			unsigned int pcr_ext;

			parse_pcr(adapt.OPCR, &pcr_base, &pcr_ext);
			__log_printf(stderr, "PID: 0x%04x, PCR base: %" PRIu64 ", ext: %d\n", hdr.pid, pcr_base, pcr_ext);
		}
		if (adapt.splicing_point) {
			dPrintf("PID: 0x%04x, splicing countdown: %d", hdr.pid, adapt.splicing_countdown);
		}
	}

	push_stats(pkt_stats);
}
<commit_msg>stats: still too much logging... shut it off!<commit_after>/*****************************************************************************
 * Copyright (C) 2011-2016 Michael Ira Krufky
 *
 * Author: Michael Ira Krufky <mkrufky@linuxtv.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <inttypes.h>
#include "string.h"

#include "stats.h"
#include "log.h"
#define CLASS_MODULE "stats"

#define DBG 0

#define dPrintf(fmt, arg...) __dPrintf(DBG_STATS, "(%s) " fmt, parent, ##arg)

stats::stats(const char *caller)
  : tei_count(0)
  , __timenow(0)
  , parent(caller)
  , streamtime_cb(NULL)
  , streamtime_priv(NULL)
  , statistics_cb(NULL)
  , statistics_priv(NULL)
{
	dPrintf("(%s)", parent);
}

stats::~stats()
{
	dPrintf("(%s)", parent);
	show(false);
}

#if 0
stats::stats(const stats&)
{
	dPrintf("(%s, copy)", parent);
}

stats& stats::operator= (const stats& cSource)
{
	dPrintf("(%s, operator=)", parent);

	if (this == &cSource)
		return *this;

	return *this;
}
#endif

static void parse_pcr(uint8_t *pcr, uint64_t *pcr_base, unsigned int *pcr_ext)
{
	*pcr_base = ((uint64_t)pcr[0] * 0x2000000) +
		    ((uint64_t)pcr[1] * 0x20000) +
		    ((uint64_t)pcr[2] * 0x200) +
		    ((uint64_t)pcr[3] * 0x02) +
		    ((uint64_t)(pcr[4] & 0x80) >> 7);

	*pcr_ext = ((pcr[4] & 0x01) * 0x100) + pcr[5];

	return;
}

static time_t walltime(void *p) { (void)p; return time(NULL); }

char *stats_scale_unit(char *b, size_t n, uint64_t x)
{
	memset(b, 0, n);

	if (x >= 1000000) {
#if 0
		if ((x % 1000000) < 100)
			snprintf(b, n, "%3" PRIu64 ".%03" PRIu64 " m", x / 1000000, x % 1000000);
		else
#endif
			snprintf(b, n, "%3" PRIu64 ".%03" PRIu64 " m", x / 1000000, x % 1000000);
	} else if (x >= 1000) {
#if 0
		if ((x % 1000) < 100)
			snprintf(b, n, "%3" PRIu64 ".%03" PRIu64 " k", x / 1000, x % 1000);
		else
#endif
			snprintf(b, n, "%3" PRIu64 ".%03" PRIu64 " k", x / 1000, x % 1000);
	} else
		snprintf(b, n, "    %3" PRIu64 "  ", x);
	return b;
}

void stats::show(bool per_sec)
{
	if (statistics_cb) {
		statistics_cb(statistics_priv, statistics, discontinuities, tei_count, per_sec);
		return;
	}
	for (stats_map::const_iterator iter = statistics.begin(); iter != statistics.end(); ++iter) {
		char a[16];
		char b[16];
		if (dbg & DBG_STATS) __log_printf(stderr, "pid %04x %5" PRIu64 " p%s  %sb%s  %sbit\n",
			     iter->first, iter->second / 188, (per_sec) ? "/s" : "",
			     stats_scale_unit(a, sizeof(a), iter->second), (per_sec) ? "/s" : "",
			     stats_scale_unit(b, sizeof(b), iter->second * 8));
	}
	for (stats_map::const_iterator iter = discontinuities.begin(); iter != discontinuities.end(); ++iter)
		if (dbg & DBG_STATS) __log_printf(stderr, "pid %04x\t%" PRIu64 " continuity errors (%" PRIu64 "%%)\n", iter->first, iter->second, ((!iter->second) || (!statistics[iter->first])) ? 0 : (!statistics.count(iter->first)) ? 0 : (100 * iter->second / (statistics[iter->first] / 188)));

	if ((tei_count) && (dbg & DBG_STATS)) __log_printf(stderr, "tei count: %" PRIu64 " (%" PRIu64 "%%)\n", tei_count, (!statistics[0x2000]) ? 0 : (18800 * tei_count / statistics[0x2000]));
}

void stats::push_pid(int c, const uint16_t pid)
{
	streamtime_callback cb = (streamtime_cb) ? streamtime_cb : &walltime;
	time_t timenow = cb(streamtime_priv);

	if (timenow > __timenow) {
		show();
		clear_stats();
		__timenow = timenow;
	}

	__push_pid(c, pid);
}

pkt_stats_t *stats::parse(const uint8_t *p, pkt_stats_t *pkt_stats)
{
	adaptation_field_t adapt;
	pkt_hdr_t hdr;

	return parse(p, pkt_stats, hdr, adapt);
}

pkt_stats_t *stats::parse(const uint8_t *p, pkt_stats_t *pkt_stats, pkt_hdr_t &hdr, adaptation_field_t &adapt)
{
	if (pkt_stats) {
		memset(pkt_stats, 0, sizeof(pkt_stats_t));

		const uint8_t *q = p;

		memset(&adapt, 0, sizeof(adapt));
		memset(&hdr, 0, sizeof(hdr));

		hdr.sync_byte          = q[0];
		hdr.tei                = (q[1] & 0x80) >> 7;
		hdr.payload_unit_start = (q[1] & 0x40) >> 6;
		hdr.transport_priority = (q[1] & 0x20) >> 5;
		hdr.pid                = ((q[1] & 0x1f) << 8) | q[2];
		hdr.scrambling         = (q[3] & 0xc0) >> 6;
		hdr.adaptation_flags   = (q[3] & 0x30) >> 4;
		hdr.continuity_ctr     = (q[3] & 0x0f);

		if (hdr.adaptation_flags & 0x02) {
			q += 4;
			adapt.field_length   = q[0];
			adapt.discontinuity  = (q[1] & 0x80) >> 7;
			adapt.random_access  = (q[1] & 0x40) >> 6; /* set to 1 if the PES pkt in this TS pkt starts an a/v sequence */
			adapt.es_priority    = (q[1] & 0x20) >> 5;
			adapt.pcr            = (q[1] & 0x10) >> 4;
			adapt.opcr           = (q[1] & 0x08) >> 3;
			adapt.splicing_point = (q[1] & 0x04) >> 2;
			adapt.tp_priv_data   = (q[1] & 0x02) >> 1;
			adapt.field_ext      = (q[1] & 0x01) >> 0;

			if (adapt.pcr) {
				memcpy(adapt.PCR, &q[2], 6);
				q += 6;
			}
			if (adapt.opcr) {
				memcpy(adapt.OPCR, &q[2], 6);
				q += 6;
			}
			if (adapt.splicing_point) {
				adapt.splicing_countdown = q[2];
				q ++;
			}
		}

		pkt_stats->sync_loss = (hdr.sync_byte != 0x47) ? true : false;
		if (!pkt_stats->sync_loss) {
			pkt_stats->tei = (hdr.tei) ? true : false;
			pkt_stats->pid = hdr.pid;
		} else
			pkt_stats->pid = (uint16_t) - 1;
	}
	return pkt_stats;
}

void stats::clear_stats()
{
	statistics.clear();
	discontinuities.clear();
	last_pcr_base.clear();
	tei_count = 0;
}

void stats::push_stats(pkt_stats_t *pkt_stats)
{
	if (pkt_stats->tei) {
		tei_count++;
		push_pid((uint16_t) - 1);
	} else
		push_pid(pkt_stats->pid);
}

void stats::push(const uint8_t *p, pkt_stats_t *pkt_stats)
{
	adaptation_field_t adapt;
	pkt_hdr_t hdr;

	if (!pkt_stats) {
		__push(p);
		return;
	}

	memset(pkt_stats, 0, sizeof(pkt_stats_t));

	parse(p, pkt_stats, hdr, adapt);

	if (hdr.adaptation_flags & 0x01) {// payload present
		if (continuity.count(hdr.pid)) {
			uint8_t next = (continuity[hdr.pid] + 1) & 0x0f;
			if ((next != (hdr.continuity_ctr & 0x0f)) && (hdr.continuity_ctr + continuity[hdr.pid] > 0)) {
				if (!(hdr.adaptation_flags & 0x02) && (adapt.discontinuity)) {
					push_discontinuity(hdr.pid);
#if DBG
					dPrintf("CONTINUITY ERROR pid: %04x cur: 0x%x prev 0x%x", hdr.pid, hdr.continuity_ctr, continuity[hdr.pid]);
#endif
				}
			}
		}
		continuity[hdr.pid] = hdr.continuity_ctr;
	}

	if (hdr.adaptation_flags & 0x02) {
		if (adapt.pcr) {
			uint64_t pcr_base;
			unsigned int pcr_ext;

			parse_pcr(adapt.PCR, &pcr_base, &pcr_ext);
			if (dbg & DBG_STATS) __log_printf(stderr, "PID: 0x%04x, PCR base: %" PRIu64 ", ext: %d\n", hdr.pid, pcr_base, pcr_ext);

#if DBG
			stats_map::const_iterator iter = last_pcr_base.find(hdr.pid);
			if ((iter != last_pcr_base.end()) && (pcr_base < iter->second))
				__log_printf(stderr, "%s: PID: 0x%04x, %" PRIu64 " < %" PRIu64 " !!!\n",
					__func__, hdr.pid, pcr_base, iter->second);
#endif
			last_pcr_base[hdr.pid] = pcr_base;
		}
		if (adapt.opcr) {
			uint64_t pcr_base;
			unsigned int pcr_ext;

			parse_pcr(adapt.OPCR, &pcr_base, &pcr_ext);
			if (dbg & DBG_STATS) __log_printf(stderr, "PID: 0x%04x, PCR base: %" PRIu64 ", ext: %d\n", hdr.pid, pcr_base, pcr_ext);
		}
		if (adapt.splicing_point) {
			dPrintf("PID: 0x%04x, splicing countdown: %d", hdr.pid, adapt.splicing_countdown);
		}
	}

	push_stats(pkt_stats);
}
<|endoftext|>


<commit_before>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 * Copyright (C) 2005 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************/

#include <geos/geom/Envelope.h>
#include <geos/geom/CoordinateArraySequence.h>
#include <geos/geom/Coordinate.h>
#include <geos/geom/CoordinateFilter.h>

#include <cassert>
#include <algorithm>
#include <vector>

using namespace std;

namespace geos {
namespace geom { // geos::geom

CoordinateArraySequence::CoordinateArraySequence():
	vect(new vector<Coordinate>())
{
}

CoordinateArraySequence::CoordinateArraySequence(size_t n):
	vect(new vector<Coordinate>(n))
{
}

CoordinateArraySequence::CoordinateArraySequence(
	vector<Coordinate> *coords): vect(coords)
{
	if ( ! vect ) vect = new vector<Coordinate>();
}

CoordinateArraySequence::CoordinateArraySequence(
	const CoordinateArraySequence &c)
	:
	CoordinateSequence(c),
	vect(new vector<Coordinate>(*(c.vect)))
{
}

CoordinateSequence *
CoordinateArraySequence::clone() const
{
	return new CoordinateArraySequence(*this);
}

void
CoordinateArraySequence::setPoints(const vector<Coordinate> &v)
{
    assert(0 != vect);
	vect->assign(v.begin(), v.end());
}

const vector<Coordinate>*
CoordinateArraySequence::toVector() const
{
    assert(0 != vect);
	return vect; //new vector<Coordinate>(vect->begin(),vect->end());
}

void
CoordinateArraySequence::toVector(vector<Coordinate>& out) const
{
	assert(0 != vect);
	// TODO: can this be optimized ?
	out.insert(out.end(), vect->begin(), vect->end());
}

bool
CoordinateArraySequence::isEmpty() const
{
    assert(0 != vect);
	return vect->empty();
}

void
CoordinateArraySequence::add(const Coordinate& c)
{
    assert(0 != vect);
	vect->push_back(c);
}

void
CoordinateArraySequence::add(const Coordinate& c, bool allowRepeated)
{
    assert(0 != vect);
	if (!allowRepeated && ! vect->empty() )
	{
		const Coordinate& last=vect->back();
		if (last.equals2D(c)) return;
	}
	vect->push_back(c);
}

/*public*/
void
CoordinateArraySequence::add(size_t i, const Coordinate& coord,
                                       bool allowRepeated)
{
    // don't add duplicate coordinates
    if (! allowRepeated) {
      size_t sz = size();
      if (sz > 0) {
        if (i > 0) {
          const Coordinate& prev = getAt(i - 1);
          if (prev.equals2D(coord)) return;
        }
        if (i < sz) {
          const Coordinate& next = getAt(i);
          if (next.equals2D(coord)) return;
        }
      }
    }

    vect->insert(vect->begin()+i, coord);
}

size_t
CoordinateArraySequence::getSize() const
{
	return vect->size();
}

const Coordinate &
CoordinateArraySequence::getAt(size_t pos) const
{
    assert(0 != vect);
	assert(pos < vect->size());
	return (*vect)[pos];
}

void
CoordinateArraySequence::getAt(size_t pos, Coordinate &c) const
{
    assert(0 != vect);
	assert(pos<vect->size());
	c=(*vect)[pos];
}

void
CoordinateArraySequence::setAt(const Coordinate& c, size_t pos)
{
    assert(0 != vect);
	assert(pos<vect->size());
	(*vect)[pos]=c;
}

void
CoordinateArraySequence::deleteAt(size_t pos)
{
    assert(0 != vect);
	assert(pos<vect->size());
	vect->erase(vect->begin()+pos);
}

string
CoordinateArraySequence::toString() const
{
	string result("(");
	if (getSize()>0) {
		//char buffer[100];
		for (size_t i=0, n=vect->size(); i<n; i++)
		{
			Coordinate& c=(*vect)[i];
			if ( i ) result.append(", ");
			result.append(c.toString());
		}
	}
	result.append(")");

	return result;
}

CoordinateArraySequence::~CoordinateArraySequence()
{
	delete vect;
}

void
CoordinateArraySequence::expandEnvelope(Envelope &env) const
{
    assert(0 != vect);
	size_t size = vect->size();
	for (size_t i=0; i<size; i++) env.expandToInclude((*vect)[i]);
}

double
CoordinateArraySequence::getOrdinate(size_t index, size_t ordinateIndex) const
{
    assert(0 != vect);
	assert(index<vect->size());

	switch (ordinateIndex)
	{
		case CoordinateSequence::X:
			return (*vect)[index].x;
		case CoordinateSequence::Y:
			return (*vect)[index].y;
		case CoordinateSequence::Z:
			return (*vect)[index].z;
		default:
			return DoubleNotANumber;
	}
}

void
CoordinateArraySequence::setOrdinate(size_t index, size_t ordinateIndex,
	double value)
{

    assert(0 != vect);
	assert(index<vect->size());

    assert(ordinateIndex == CoordinateSequence::X
           || ordinateIndex == CoordinateSequence::Y
           || ordinateIndex == CoordinateSequence::Z);

	switch (ordinateIndex)
	{
		case CoordinateSequence::X:
			(*vect)[index].x = value;
			break;
		case CoordinateSequence::Y:
			(*vect)[index].y = value;
			break;
		case CoordinateSequence::Z:
			(*vect)[index].z = value;
			break;
		default:
			break;
	}
}

void
CoordinateArraySequence::apply_rw(const CoordinateFilter *filter)
{
    assert(0 != vect);
	for (vector<Coordinate>::iterator i=vect->begin(), e=vect->end(); i!=e; ++i)
	{
		filter->filter_rw(&(*i));
	}
}

void
CoordinateArraySequence::apply_ro(CoordinateFilter *filter) const
{
    assert(0 != vect);
	for (vector<Coordinate>::const_iterator i=vect->begin(), e=vect->end(); i!=e; ++i)
	{
		filter->filter_ro(&(*i));
	}
}

CoordinateSequence&
CoordinateArraySequence::removeRepeatedPoints()
{
    assert(0 != vect);
	// We use == operator, which is 2D only
	vector<Coordinate>::iterator new_end = \
		std::unique(vect->begin(), vect->end());

	vect->erase(new_end, vect->end());

	return *this;
}

} // namespace geos::geom
} //namespace geos

/**********************************************************************
 * $Log$
 * Revision 1.10  2006/06/12 15:07:47  strk
 * explicitly invoked CoordinateSequence (copy) ctor - suggested by GCC warning.
 *
 * Revision 1.9  2006/06/12 10:10:39  strk
 * Fixed getGeometryN() to take size_t rather then int, changed unsigned int parameters to size_t.
 *
 * Revision 1.8  2006/05/03 08:58:34  strk
 * added new non-static CoordinateSequence::removeRepeatedPoints() mutator.
 *
 * Revision 1.7  2006/03/27 09:00:50  strk
 * Bug #79 - Small fix in CoordinateArraySequence::toString()
 *
 * Revision 1.6  2006/03/22 16:58:34  strk
 * Removed (almost) all inclusions of geom.h.
 * Removed obsoleted .cpp files.
 * Fixed a bug in WKTReader not using the provided CoordinateSequence
 * implementation, optimized out some memory allocations.
 *
 **********************************************************************/

<commit_msg>Drop pointless asserts. We'd abort anyway if vector is null. For the out-of-range case the GNU c++ lib helps debugging with an environment variable <commit_after>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 * Copyright (C) 2005 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************/

#include <geos/geom/Envelope.h>
#include <geos/geom/CoordinateArraySequence.h>
#include <geos/geom/Coordinate.h>
#include <geos/geom/CoordinateFilter.h>

#include <cassert>
#include <algorithm>
#include <vector>

using namespace std;

namespace geos {
namespace geom { // geos::geom

CoordinateArraySequence::CoordinateArraySequence():
	vect(new vector<Coordinate>())
{
}

CoordinateArraySequence::CoordinateArraySequence(size_t n):
	vect(new vector<Coordinate>(n))
{
}

CoordinateArraySequence::CoordinateArraySequence(
	vector<Coordinate> *coords): vect(coords)
{
	if ( ! vect ) vect = new vector<Coordinate>();
}

CoordinateArraySequence::CoordinateArraySequence(
	const CoordinateArraySequence &c)
	:
	CoordinateSequence(c),
	vect(new vector<Coordinate>(*(c.vect)))
{
}

CoordinateSequence *
CoordinateArraySequence::clone() const
{
	return new CoordinateArraySequence(*this);
}

void
CoordinateArraySequence::setPoints(const vector<Coordinate> &v)
{
	vect->assign(v.begin(), v.end());
}

const vector<Coordinate>*
CoordinateArraySequence::toVector() const
{
	return vect; //new vector<Coordinate>(vect->begin(),vect->end());
}

void
CoordinateArraySequence::toVector(vector<Coordinate>& out) const
{
	// TODO: can this be optimized ?
	out.insert(out.end(), vect->begin(), vect->end());
}

bool
CoordinateArraySequence::isEmpty() const
{
	return vect->empty();
}

void
CoordinateArraySequence::add(const Coordinate& c)
{
	vect->push_back(c);
}

void
CoordinateArraySequence::add(const Coordinate& c, bool allowRepeated)
{
	if (!allowRepeated && ! vect->empty() )
	{
		const Coordinate& last=vect->back();
		if (last.equals2D(c)) return;
	}
	vect->push_back(c);
}

/*public*/
void
CoordinateArraySequence::add(size_t i, const Coordinate& coord,
                                       bool allowRepeated)
{
    // don't add duplicate coordinates
    if (! allowRepeated) {
      size_t sz = size();
      if (sz > 0) {
        if (i > 0) {
          const Coordinate& prev = getAt(i - 1);
          if (prev.equals2D(coord)) return;
        }
        if (i < sz) {
          const Coordinate& next = getAt(i);
          if (next.equals2D(coord)) return;
        }
      }
    }

    vect->insert(vect->begin()+i, coord);
}

size_t
CoordinateArraySequence::getSize() const
{
	return vect->size();
}

const Coordinate &
CoordinateArraySequence::getAt(size_t pos) const
{
	return (*vect)[pos];
}

void
CoordinateArraySequence::getAt(size_t pos, Coordinate &c) const
{
	c=(*vect)[pos];
}

void
CoordinateArraySequence::setAt(const Coordinate& c, size_t pos)
{
	(*vect)[pos]=c;
}

void
CoordinateArraySequence::deleteAt(size_t pos)
{
	vect->erase(vect->begin()+pos);
}

string
CoordinateArraySequence::toString() const
{
	string result("(");
	if (getSize()>0) {
		//char buffer[100];
		for (size_t i=0, n=vect->size(); i<n; i++)
		{
			Coordinate& c=(*vect)[i];
			if ( i ) result.append(", ");
			result.append(c.toString());
		}
	}
	result.append(")");

	return result;
}

CoordinateArraySequence::~CoordinateArraySequence()
{
	delete vect;
}

void
CoordinateArraySequence::expandEnvelope(Envelope &env) const
{
	for (size_t i=0, n=vect->size(); i<n; ++i)
		env.expandToInclude((*vect)[i]);
}

double
CoordinateArraySequence::getOrdinate(size_t index, size_t ordinateIndex) const
{
	switch (ordinateIndex)
	{
		case CoordinateSequence::X:
			return (*vect)[index].x;
		case CoordinateSequence::Y:
			return (*vect)[index].y;
		case CoordinateSequence::Z:
			return (*vect)[index].z;
		default:
			return DoubleNotANumber;
	}
}

void
CoordinateArraySequence::setOrdinate(size_t index, size_t ordinateIndex,
	double value)
{
	switch (ordinateIndex)
	{
		case CoordinateSequence::X:
			(*vect)[index].x = value;
			break;
		case CoordinateSequence::Y:
			(*vect)[index].y = value;
			break;
		case CoordinateSequence::Z:
			(*vect)[index].z = value;
			break;
		default:
			assert(0);
			break;
	}
}

void
CoordinateArraySequence::apply_rw(const CoordinateFilter *filter)
{
	for (vector<Coordinate>::iterator i=vect->begin(), e=vect->end(); i!=e; ++i)
	{
		filter->filter_rw(&(*i));
	}
}

void
CoordinateArraySequence::apply_ro(CoordinateFilter *filter) const
{
	for (vector<Coordinate>::const_iterator i=vect->begin(), e=vect->end(); i!=e; ++i)
	{
		filter->filter_ro(&(*i));
	}
}

CoordinateSequence&
CoordinateArraySequence::removeRepeatedPoints()
{
	// We use == operator, which is 2D only
	vector<Coordinate>::iterator new_end = \
		std::unique(vect->begin(), vect->end());

	vect->erase(new_end, vect->end());

	return *this;
}

} // namespace geos::geom
} //namespace geos

/**********************************************************************
 * $Log$
 * Revision 1.10  2006/06/12 15:07:47  strk
 * explicitly invoked CoordinateSequence (copy) ctor - suggested by GCC warning.
 *
 * Revision 1.9  2006/06/12 10:10:39  strk
 * Fixed getGeometryN() to take size_t rather then int, changed unsigned int parameters to size_t.
 *
 * Revision 1.8  2006/05/03 08:58:34  strk
 * added new non-static CoordinateSequence::removeRepeatedPoints() mutator.
 *
 * Revision 1.7  2006/03/27 09:00:50  strk
 * Bug #79 - Small fix in CoordinateArraySequence::toString()
 *
 * Revision 1.6  2006/03/22 16:58:34  strk
 * Removed (almost) all inclusions of geom.h.
 * Removed obsoleted .cpp files.
 * Fixed a bug in WKTReader not using the provided CoordinateSequence
 * implementation, optimized out some memory allocations.
 *
 **********************************************************************/

<|endoftext|>


<commit_before>/***************************Copyright-DO-NOT-REMOVE-THIS-LINE**
 * CONDOR Copyright Notice
 *
 * See LICENSE.TXT for additional notices and disclaimers.
 *
 * Copyright (c)1990-1998 CONDOR Team, Computer Sciences Department,
 * University of Wisconsin-Madison, Madison, WI.  All Rights Reserved.
 * No use of the CONDOR Software Program Source Code is authorized
 * without the express consent of the CONDOR Team.  For more information
 * contact: CONDOR Team, Attention: Professor Miron Livny,
 * 7367 Computer Sciences, 1210 W. Dayton St., Madison, WI 53706-1685,
 * (608) 262-0856 or miron@cs.wisc.edu.
 *
 * U.S. Government Rights Restrictions: Use, duplication, or disclosure
 * by the U.S. Government is subject to restrictions as set forth in
 * subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer
 * Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and
 * (2) of Commercial Computer Software-Restricted Rights at 48 CFR
 * 52.227-19, as applicable, CONDOR Team, Attention: Professor Miron
 * Livny, 7367 Computer Sciences, 1210 W. Dayton St., Madison,
 * WI 53706-1685, (608) 262-0856 or miron@cs.wisc.edu.
****************************Copyright-DO-NOT-REMOVE-THIS-LINE**/

///////////////////////////////////////////////////////////////////////////////
// Get the ip address and port number of a schedd from the collector.
///////////////////////////////////////////////////////////////////////////////

#include "condor_common.h"
#include "condor_query.h"
#include "condor_config.h"
#include "my_hostname.h"
#include "get_full_hostname.h"
#include "daemon_types.h"

extern "C" {

// Return the host portion of a daemon name string.  Either the name
// includes an "@" sign, in which case we return whatever is after it,
// or it doesn't, in which case we just return what we got passed.
const char*
get_host_part( const char* name )
{
	char* tmp;
	if (name == NULL) return NULL;
	tmp = strchr( name, '@' );
	if( tmp ) {
		return ++tmp;
	} else {
		return name;
	}
}

// Return a pointer to a static buffer that contains the valid daemon
// name that corresponds with the given name.  Basically, see if
// there's an '@'.  If so, resolve everything after it as a hostname.
// If not, resolve what we were passed as a hostname.
char*
get_daemon_name( const char* name )
{
	char *tmp, *fullname, *tmpname;
	static char daemon_name[256];
	daemon_name[0] = '\0';
	tmpname= strdup( name );
	int had_error = 0;

		// First, check for a '@' in the name.
	tmp = strchr( tmpname, '@' );
	if( tmp ) {
			// There's a '@'.
		*tmp = '\0';
		tmp++;
		if( *tmp ) {
				// There was something after the @, try to resolve it
				// as a full hostname:
			fullname = get_full_hostname( tmp );
		} else {
				// There was nothing after the @, use localhost:
			fullname = my_full_hostname();
		}
		if( fullname ) {
			sprintf( daemon_name, "%s@%s", tmpname, fullname );
		} else {
			had_error = 1;
		}
	} else {
			// There's no '@', just try to resolve the hostname.
		if( (fullname = get_full_hostname(tmpname)) ) {
			sprintf( daemon_name, "%s", fullname );
		} else {
			had_error = 1;
		}
	}
	free( tmpname );
	if( had_error ) {
		return NULL;
	} else {
		return daemon_name;
	}
}

// Given some name, create a valid name for ourself with our full
// hostname.  If the name contains an '@', strip off everything after
// it and append my_full_hostname().  If there's no '@', try to
// resolve what we have and see if it's my_full_hostname.  If so, use
// it, otherwise, use name@my_full_hostname().
char*
build_valid_daemon_name( char* name )
{
	char *tmp;
	static char daemonName[100];

	if( name && *name ) {
		tmp = strchr( name, '@' );
		if( tmp ) {
				// name we were passed has an '@'
			*tmp = '\0';
			sprintf( daemonName, "%s@%s", name, my_full_hostname() );
		} else {
				// no '@', see if what we have is our hostname
			if( !strcmp(get_full_hostname(name), my_full_hostname()) ) {
				sprintf( daemonName, "%s", my_full_hostname() );
			} else {
				sprintf( daemonName, "%s@%s", name, my_full_hostname() );
			}
		}
	} else {
		sprintf( daemonName, "%s", my_full_hostname() );
	}
	return daemonName;
}

// Return a pointer to a static buffer which contains the name of the
// given daemon (specified by subsys string) as configured on the
// local host.
char*
my_daemon_name( const char* subsys )
{
	static char my_name[100];
	char line [100], *tmp;
	sprintf( line, "%s_NAME", subsys );
	tmp = param( line );
	if( tmp ) {
		sprintf( my_name, "%s", build_valid_daemon_name(tmp) );
		free( tmp );
	} else {
		sprintf( my_name, "%s", my_full_hostname() );
	}
	return my_name;
}

char*
real_get_daemon_addr( const char* constraint_attr,
				 const char* name, AdTypes adtype,
				 const char* attribute, const char* subsys,
				 const char* pool )
{

	static char			daemonAddr[100];
	char				constraint[500];
	char				*fullname = NULL, *addr_file, *tmp, *my_name;
	FILE				*addr_fp;
	int					is_local = 0;

	daemonAddr[0] = '\0';
	my_name = my_daemon_name( subsys );

		// Figure out if we want to find a local daemon or not.
	if( name && *name ) {
		fullname = (char*)name;
		if( !strcmp( fullname, my_name ) ) {
			is_local = 1;
		}
	} else {
		fullname = my_name;
		is_local = 1;
	}

	if( is_local ) {
		sprintf( constraint, "%s_ADDRESS_FILE", subsys );
		addr_file = param( constraint );
		if( addr_file ) {
			if( (addr_fp = fopen(addr_file, "r")) ) {
					// Read out the sinful string.
				fgets( daemonAddr, 100, addr_fp );
					// chop off the newline
				tmp = strchr( daemonAddr, '\n' );
				if( tmp ) {
					*tmp = '\0';
				}
				fclose( addr_fp );
			}
			free( addr_file );
		}
		if( daemonAddr[0] == '<' ) {
				// We found something reasonable.
			return daemonAddr;
		}
	}

	CondorQuery			query(adtype);
	ClassAd*			scan;
	ClassAdList			ads;

	sprintf(constraint, "%s == \"%s\"", constraint_attr, fullname );
	query.addConstraint(constraint);
	query.fetchAds(ads, pool);
	ads.Open();
	scan = ads.Next();
	if(!scan)
	{
		return NULL;
	}
	if(scan->EvalString(attribute, NULL, daemonAddr) == FALSE)
	{
		return NULL;
	}
	return daemonAddr;
}

char*
get_schedd_addr(const char* name, const char* pool)
{
	return real_get_daemon_addr( ATTR_NAME, name, SCHEDD_AD,
								 ATTR_SCHEDD_IP_ADDR, "SCHEDD", pool );
}

char*
get_startd_addr(const char* name, const char* pool)
{
	return real_get_daemon_addr( ATTR_MACHINE, get_host_part(name), STARTD_AD,
								 ATTR_STARTD_IP_ADDR, "STARTD", pool );
}

char*
get_master_addr(const char* name, const char* pool)
{
	return real_get_daemon_addr( ATTR_NAME, name, MASTER_AD,
								 ATTR_MASTER_IP_ADDR, "MASTER", pool );
}

char*
get_cm_addr( const char* name, char* config_name, int port )
{
	static char addr[30];
	struct hostent* hostp;
	char* tmp = NULL;

	if( name && *name ) {
		tmp = strdup( name );
	} else {
		tmp = param( config_name );
	}
	if( ! tmp ) {
		return NULL;
	}
	hostp = gethostbyname( tmp );
	free( tmp );
	if( ! hostp ) {
		return NULL;
	}
	sprintf( addr, "<%s:%d>",
			 inet_ntoa( *(struct in_addr*)(hostp->h_addr_list[0]) ),
			 port );
	return addr;
}

char*
get_negotiator_addr(const char* name)
{
	return get_cm_addr( name, "NEGOTIATOR_HOST", NEGOTIATOR_PORT );
}

char*
get_collector_addr(const char* name)
{
	return get_cm_addr( name, "COLLECTOR_HOST", COLLECTOR_PORT );
}

char*
get_daemon_addr( daemon_t dt, const char* name, const char* pool )
{
	switch( dt ) {
	case DT_MASTER:
		return get_master_addr( name, pool );
	case DT_STARTD:
		return get_startd_addr( name, pool );
	case DT_SCHEDD:
		return get_schedd_addr( name, pool );
	case DT_NEGOTIATOR:
		return get_negotiator_addr( name );
	case DT_COLLECTOR:
		return get_collector_addr( name );
	default:
		return NULL;
	}
	return NULL;
}

int
is_valid_sinful( char *sinful )
{
	char* tmp;
	if( !sinful ) return FALSE;
	if( !(sinful[0] == '<') ) return FALSE;
	if( !(tmp = strchr(sinful, ':')) ) return FALSE;
	if( !(tmp = strrchr(sinful, '>')) ) return FALSE;
	return TRUE;
}

} /* extern "C" */
<commit_msg>+ All of the get_*_addr() functions are now trivially implemented with   the new Daemon class.  Therefore, a lot of the code has been ripped   out of here, reworked, and can now be found in daemon.C. + Converted get_daemon_name(), build_valid_daemon_name(), and   my_daemon_name() to all return strnewp()'d strings, instead of   pointers into static buffers to a) prevent errors and b) make things   more thread-safe.<commit_after>/***************************Copyright-DO-NOT-REMOVE-THIS-LINE**
 * CONDOR Copyright Notice
 *
 * See LICENSE.TXT for additional notices and disclaimers.
 *
 * Copyright (c)1990-1998 CONDOR Team, Computer Sciences Department,
 * University of Wisconsin-Madison, Madison, WI.  All Rights Reserved.
 * No use of the CONDOR Software Program Source Code is authorized
 * without the express consent of the CONDOR Team.  For more information
 * contact: CONDOR Team, Attention: Professor Miron Livny,
 * 7367 Computer Sciences, 1210 W. Dayton St., Madison, WI 53706-1685,
 * (608) 262-0856 or miron@cs.wisc.edu.
 *
 * U.S. Government Rights Restrictions: Use, duplication, or disclosure
 * by the U.S. Government is subject to restrictions as set forth in
 * subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer
 * Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and
 * (2) of Commercial Computer Software-Restricted Rights at 48 CFR
 * 52.227-19, as applicable, CONDOR Team, Attention: Professor Miron
 * Livny, 7367 Computer Sciences, 1210 W. Dayton St., Madison,
 * WI 53706-1685, (608) 262-0856 or miron@cs.wisc.edu.
****************************Copyright-DO-NOT-REMOVE-THIS-LINE**/

///////////////////////////////////////////////////////////////////////////////
// Get the ip address and port number of a schedd from the collector.
///////////////////////////////////////////////////////////////////////////////

#include "condor_common.h"
#include "condor_config.h"
#include "condor_string.h"
#include "daemon.h"
#include "get_full_hostname.h"
#include "my_hostname.h"
#include "daemon_types.h"

extern "C" {

// Return the host portion of a daemon name string.  Either the name
// includes an "@" sign, in which case we return whatever is after it,
// or it doesn't, in which case we just return what we got passed.
const char*
get_host_part( const char* name )
{
	char* tmp;
	if (name == NULL) return NULL;
	tmp = strchr( name, '@' );
	if( tmp ) {
		return ++tmp;
	} else {
		return name;
	}
}

// Return a pointer to a static buffer that contains the valid daemon
// name that corresponds with the given name.  Basically, see if
// there's an '@'.  If so, resolve everything after it as a hostname.
// If not, resolve what we were passed as a hostname.
char*
get_daemon_name( const char* name )
{
	char *tmp, *fullname, *tmpname;
	char daemon_name[256];
	daemon_name[0] = '\0';
	tmpname= strdup( name );
	int had_error = 0;

		// First, check for a '@' in the name.
	tmp = strchr( tmpname, '@' );
	if( tmp ) {
			// There's a '@'.
		*tmp = '\0';
		tmp++;
		if( *tmp ) {
				// There was something after the @, try to resolve it
				// as a full hostname:
			fullname = get_full_hostname( tmp );
		} else {
				// There was nothing after the @, use localhost:
			fullname = my_full_hostname();
		}
		if( fullname ) {
			sprintf( daemon_name, "%s@%s", tmpname, fullname );
		} else {
			had_error = 1;
		}
	} else {
			// There's no '@', just try to resolve the hostname.
		if( (fullname = get_full_hostname(tmpname)) ) {
			sprintf( daemon_name, "%s", fullname );
		} else {
			had_error = 1;
		}
	}
	free( tmpname );
	if( had_error ) {
		return NULL;
	} else {
		return strnewp( daemon_name );
	}
}

// Given some name, create a valid name for ourself with our full
// hostname.  If the name contains an '@', strip off everything after
// it and append my_full_hostname().  If there's no '@', try to
// resolve what we have and see if it's my_full_hostname.  If so, use
// it, otherwise, use name@my_full_hostname().  We return the answer
// in a newly allocated string which should be deallocated w/ delete.
char*
build_valid_daemon_name( char* name )
{
	char *tmp;
	char daemonName[100];

	if( name && *name ) {
		tmp = strchr( name, '@' );
		if( tmp ) {
				// name we were passed has an '@'
			*tmp = '\0';
			sprintf( daemonName, "%s@%s", name, my_full_hostname() );
		} else {
				// no '@', see if what we have is our hostname
			if( !strcmp(get_full_hostname(name), my_full_hostname()) ) {
				sprintf( daemonName, "%s", my_full_hostname() );
			} else {
				sprintf( daemonName, "%s@%s", name, my_full_hostname() );
			}
		}
	} else {
		sprintf( daemonName, "%s", my_full_hostname() );
	}
	return strnewp( daemonName );
}

// Return a newly allocated string which contains the name of the
// given daemon (specified by subsys string) as configured on the
// local host.  This string should be deallocated with delete [].
char*
my_daemon_name( const char* subsys )
{
	char line [100], *tmp, *my_name;
	sprintf( line, "%s_NAME", subsys );
	tmp = param( line );
	if( tmp ) {
		my_name = build_valid_daemon_name(tmp);
		free( tmp );
	} else {
		my_name = strnewp( my_full_hostname() );
	}
	return my_name;
}

char*
get_schedd_addr(const char* name, const char* pool)
{
	static char addr[100];
	Daemon d( DT_SCHEDD, name, pool );
	sprintf( addr, "%s", d.addr() );
	return addr;
}

char*
get_startd_addr(const char* name, const char* pool)
{
	static char addr[100];
	Daemon d( DT_STARTD, name, pool );
	sprintf( addr, "%s", d.addr() );
	return addr;
}

char*
get_master_addr(const char* name, const char* pool)
{
	static char addr[100];
	Daemon d( DT_MASTER, name, pool );
	sprintf( addr, "%s", d.addr() );
	return addr;
}

char*
get_negotiator_addr(const char* name)
{
	static char addr[100];
	Daemon d( DT_COLLECTOR, name );
	sprintf( addr, "%s", d.addr() );
	return addr;
}

char*
get_collector_addr(const char* name)
{
	static char addr[100];
	Daemon d( DT_COLLECTOR, name );
	sprintf( addr, "%s", d.addr() );
	return addr;
}

char*
get_daemon_addr( daemon_t dt, const char* name, const char* pool )
{
	switch( dt ) {
	case DT_MASTER:
		return get_master_addr( name, pool );
	case DT_STARTD:
		return get_startd_addr( name, pool );
	case DT_SCHEDD:
		return get_schedd_addr( name, pool );
	case DT_NEGOTIATOR:
		return get_negotiator_addr( name );
	case DT_COLLECTOR:
		return get_collector_addr( name );
	default:
		return NULL;
	}
	return NULL;
}

int
is_valid_sinful( char *sinful )
{
	char* tmp;
	if( !sinful ) return FALSE;
	if( !(sinful[0] == '<') ) return FALSE;
	if( !(tmp = strchr(sinful, ':')) ) return FALSE;
	if( !(tmp = strrchr(sinful, '>')) ) return FALSE;
	return TRUE;
}

} /* extern "C" */
<|endoftext|>