<commit_before>#include "graph.hpp"
#include <cmath>
#include <queue>

#include <iostream>

Graph::Graph() : m_branchId(0)
{
	addNode(Node::ID(300, 300));
	addNode(Node::ID(300, 270));
	forceNewEdge(Node::ID(300, 300), Node::ID(300, 270));

	makePath();
}

Branch const* Graph::getBranch(Branch::ID id) const
{
	auto it = m_branchs.find(id);
	if (it != m_branchs.end())
		return &it->second;
	else
		return nullptr;
}

Branch* Graph::getBranch(Branch::ID id)
{
	auto it = m_branchs.find(id);
	if (it != m_branchs.end())
		return &it->second;
	else
		return nullptr;
}

Node const* Graph::getNode(Node::ID id) const
{
	auto it = m_nodes.find(id);
	if (it != m_nodes.end())
		return &it->second;
	else
		return nullptr;
}

Node* Graph::getNode(Node::ID id)
{
	auto it = m_nodes.find(id);
	if (it != m_nodes.end())
		return &it->second;
	else
		return nullptr;
}

bool Graph::isCulDeSac(Branch::ID b) const
{

	auto it1 = m_neighbours.find(getBranch(b)->getFirstNode());
	auto it2 = m_neighbours.find(getBranch(b)->getSecondNode());
	return (it1 == m_neighbours.end() || it2 == m_neighbours.end() || it1->second.size() < 2 || it2->second.size() < 2);
}

/*
// TODO: pour l’instant, cette fonction ne renvoie que le nombre de nœuds intermédiaires
float Graph::distance(Node::ID n1, Node::ID n2)
{
	if (m_neighbours.find(n1) == m_neighbours.end() || m_neighbours.find(n2) == m_neighbours.end())
		return std::numeric_limits<float>::infinity();

	std::priority_queue<std::pair<float, Node> > q;
	std::set<Node> s;

	q.push(std::make_pair(0., n1));
	while (!q.empty())
	{
		std::pair<float, Node> pair = q.top();
		float d = pair.first;
		Node n = pair.second;
		q.pop();
		if (n == n2)
			return d;

		if (s.find(n) == s.end())
		{
			s.insert(n);
			auto neighbours = m_neighbours.find(n)->second;
			for (auto pair : neighbours)
				q.push(std::make_pair(d+1, pair.first)); // TODO
		}
	}

	return std::numeric_limits<float>::infinity();
}

*/

void Graph::makePath()
{
	int n = m_nodes.size();
	std::vector<std::pair<float, Branch::ID> > ligne(n);
	std::vector<std::vector<std::pair<float, Branch::ID> > > matrix(n, ligne);
	std::map<Node::ID, int> toInt;
	std::map<int, Node::ID> toID;

	int i = 0;
	for (auto pair : m_nodes)
	{
		toInt.insert(std::make_pair(pair.first, i));
		toID.insert(std::make_pair(i++, pair.first));
	}

	i = 0;
	for (auto node_neighbours : m_neighbours)
	{
		Node::ID const& previousNode(sf::Vector2f(std::numeric_limits<float>::infinity(), 0));
		float previousDist(0);

		for (auto node_branch : node_neighbours.second)
		{
			Node::ID const& node2 = node_branch.first;
			Branch::ID branch = node_branch.second;
			float dist = m_branchs.find(branch)->second.getLength();
			if (!(node2 == previousNode) || dist < previousDist)
				matrix[i][toInt[node2]] = std::make_pair(dist, branch);
		}
		i++;
	}

	for (int k = 0 ; k < n ; k++)
	{
		for (i = 0 ; i < n ; i++)
		{
			for (int j = 0 ; j < n ; j++)
			{
				auto &a = matrix[i][j];
				float d = matrix[i][k].first + matrix[k][j].first;
				if (a.first > d)
					a = std::make_pair(d, matrix[i][k].second);
			}
		}
	}

	m_paths.clear();
	for (i = 0 ; i < n ; i++)
		for (int j = 0 ; j < n ; j++)
			m_paths.insert(std::make_pair(std::make_pair(toID.find(i)->second, toID.find(j)->second), matrix[i][j]));
}

Path Graph::getPath(Node::ID n1, Node::ID n2)
{
	Path p;
	auto it = m_paths.find(std::make_pair(n1, n2));
	auto node = n1;
	auto branch = it->second.second;
	auto &realBranch = m_branchs.find(branch)->second;
	while (it != m_paths.end() && !(realBranch.getSecondNode() == n2))
	{
		p.addBranch(node, branch, realBranch.getLength());
		it = m_paths.find(std::make_pair(node, realBranch.getFirstNode()));
		node = realBranch.getFirstNode();
		branch = it->second.second;
		realBranch = m_branchs.find(branch)->second;
	}
	return p;
}

Node::ID Graph::addNode(Node node)
{
	NeighbourHood nh;
	Node::ID ni(node);
	m_neighbours.insert(std::make_pair(ni, nh));
	m_nodes.insert(std::make_pair(ni, node));
	return ni;
}

void Graph::addNode(Node::ID ni)
{
	NeighbourHood nh;
	m_neighbours.insert(std::make_pair(ni, nh));
	m_nodes.emplace(ni, ni);
}
/*
EdgeType Graph::newEdge(Node n1, Node n2)
{
	EdgeType t = NONE;
	sf::Vector2f const& p1 = n1.getPosition(), p2 = n2.getPosition();
	if (isItLeaf(n1, n2))
	{
		if (hasDownEdge(n1) && hasDownEdge(n2))
			t = LEAF;
	}
	else if (n1 < n2 && hasDownEdge(n1) || n2 < n1 && hasDownEdge(n2))
		t = BRANCH;
	auto it1 = m_nodes.find(n1), it2 = m_nodes.find(n2);
	if (it1 != m_nodes.end() && it2 != m_nodes.end() && t != NONE)
	{
		it1->second.insert(std::make_pair(n2, t));
		it2->second.insert(std::make_pair(n1, t));
		return t;
	}
	else
		return NONE;
}

EdgeType Graph::forceNewEdge(Node n1, Node n2)
{
	EdgeType t = NONE;
	sf::Vector2f const& p1 = n1.getPosition(), p2 = n2.getPosition();
	if (isItLeaf(n1, n2))
		t = LEAF;
	else
		t = BRANCH;

	auto it1 = m_nodes.find(n1), it2 = m_nodes.find(n2);
	if (it1 != m_nodes.end() && it2 != m_nodes.end())
	{
		it1->second.insert(std::make_pair(n2, t));
		it2->second.insert(std::make_pair(n1, t));
		return t;
	}
	else
		return NONE;
}
*/

Branch::ID Graph::newEdge(Node::ID n1, Node::ID n2)
{
	auto it1 = m_neighbours.find(n1), it2 = m_neighbours.find(n2);
	if (it1 != m_neighbours.end()
			&& it2 != m_neighbours.end()
			&& m_nodes.find(n1)->second.getType() == Node::Type::RegularNode
			&& m_nodes.find(n2)->second.getType() == Node::Type::RegularNode
			&& ((n1 < n2 && hasDownEdge(n1))
				|| (n2 < n1 && hasDownEdge(n2))
				)
			)
	{
		auto id_n_it = m_branchs.emplace_hint(m_branchs.end(), std::piecewise_construct, std::forward_as_tuple(m_branchId++), std::forward_as_tuple(n1, n2));
		it1->second.insert(std::make_pair(n2, id_n_it->first));
		it2->second.insert(std::make_pair(n1, id_n_it->first));
		return id_n_it->first;
	}
	else
		return Branch::ID(0);
}

Branch::ID Graph::forceNewEdge(Node::ID n1, Node::ID n2)
{
	auto it1 = m_neighbours.find(n1), it2 = m_neighbours.find(n2);
	if (it1 != m_neighbours.end() && it2 != m_neighbours.end())
	{
		auto id_n_it = m_branchs.emplace_hint(m_branchs.end(), std::piecewise_construct, std::forward_as_tuple(m_branchId++), std::forward_as_tuple(n1, n2));
		it1->second.insert(std::make_pair(n2, id_n_it->first));
		it2->second.insert(std::make_pair(n1, id_n_it->first));
		return id_n_it->first;
	}
	else
		return Branch::ID(0);
}

/*
bool Graph::isItLeaf(Node::ID n1, Node::ID n2)
{
	sf::Vector2f const& p1 = n1.getPosition(), p2 = n2.getPosition();
	return std::abs(p2.y - p1.y) <= leafLimit * std::abs(p2.x - p1.x);
}
*/

bool Graph::hasDownEdge(Node::ID n) const
{
	auto it = m_neighbours.find(n);
	if (it == m_neighbours.end())
		return false;
	auto pair = it->second.begin();
	return pair != it->second.end() && pair->first < n;
}

void Graph::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
	for (auto pair : m_branchs)
	{
		pair.second.draw(target, states);
	}

	for (auto pair : m_nodes)
	{
		pair.second.draw(target, states);
	}

}
<commit_msg>Fusion avec la branche test-getPath, et correction de quelques bugs<commit_after>#include "graph.hpp"
#include <cmath>
#include <queue>

#include <iostream>

Graph::Graph() : m_branchId(0)
{
	addNode(Node::ID(300, 300));
	addNode(Node::ID(300, 270));
	forceNewEdge(Node::ID(300, 300), Node::ID(300, 270));

	makePath();
}

Branch const* Graph::getBranch(Branch::ID id) const
{
	auto it = m_branchs.find(id);
	if (it != m_branchs.end())
		return &it->second;
	else
		return nullptr;
}

Branch* Graph::getBranch(Branch::ID id)
{
	auto it = m_branchs.find(id);
	if (it != m_branchs.end())
		return &it->second;
	else
		return nullptr;
}

Node const* Graph::getNode(Node::ID id) const
{
	auto it = m_nodes.find(id);
	if (it != m_nodes.end())
		return &it->second;
	else
		return nullptr;
}

Node* Graph::getNode(Node::ID id)
{
	auto it = m_nodes.find(id);
	if (it != m_nodes.end())
		return &it->second;
	else
		return nullptr;
}

bool Graph::isCulDeSac(Branch::ID b) const
{

	auto it1 = m_neighbours.find(getBranch(b)->getFirstNode());
	auto it2 = m_neighbours.find(getBranch(b)->getSecondNode());
	return (it1 == m_neighbours.end() || it2 == m_neighbours.end() || it1->second.size() < 2 || it2->second.size() < 2);
}

/*
// TODO: pour l’instant, cette fonction ne renvoie que le nombre de nœuds intermédiaires
float Graph::distance(Node::ID n1, Node::ID n2)
{
	if (m_neighbours.find(n1) == m_neighbours.end() || m_neighbours.find(n2) == m_neighbours.end())
		return std::numeric_limits<float>::infinity();

	std::priority_queue<std::pair<float, Node> > q;
	std::set<Node> s;

	q.push(std::make_pair(0., n1));
	while (!q.empty())
	{
		std::pair<float, Node> pair = q.top();
		float d = pair.first;
		Node n = pair.second;
		q.pop();
		if (n == n2)
			return d;

		if (s.find(n) == s.end())
		{
			s.insert(n);
			auto neighbours = m_neighbours.find(n)->second;
			for (auto pair : neighbours)
				q.push(std::make_pair(d+1, pair.first)); // TODO
		}
	}

	return std::numeric_limits<float>::infinity();
}

*/

void Graph::makePath()
{
	int n = m_nodes.size();
	std::vector<std::pair<float, Branch::ID> > ligne(n);
	std::vector<std::vector<std::pair<float, Branch::ID> > > matrix(n, ligne);
	std::map<Node::ID, int> toInt;
	std::map<int, Node::ID> toID;

	int i = 0;
	for (auto pair : m_nodes)
	{
		toInt.insert(std::make_pair(pair.first, i));
		toID.insert(std::make_pair(i++, pair.first));
	}

	i = 0;
	for (auto node_neighbours : m_neighbours)
	{
		Node::ID const& previousNode(sf::Vector2f(std::numeric_limits<float>::infinity(), 0));
		float previousDist(0);

		for (auto node_branch : node_neighbours.second)
		{
			Node::ID const& node2 = node_branch.first;
			Branch::ID branch = node_branch.second;
			float dist = m_branchs.find(branch)->second.getLength();
			if (!(node2 == previousNode) || dist < previousDist)
				matrix[i][toInt[node2]] = std::make_pair(dist, branch);
		}
		i++;
	}

	for (int k = 0 ; k < n ; k++)
	{
		for (i = 0 ; i < n ; i++)
		{
			for (int j = 0 ; j < n ; j++)
			{
				auto &a = matrix[i][j];
				float d = matrix[i][k].first + matrix[k][j].first;
				if (a.first > d)
					a = std::make_pair(d, matrix[i][k].second);
			}
		}
	}

	m_paths.clear();
	for (i = 0 ; i < n ; i++)
		for (int j = 0 ; j < n ; j++)
			m_paths.insert(std::make_pair(std::make_pair(toID.find(i)->second, toID.find(j)->second), matrix[i][j]));
}

Path Graph::getPath(Node::ID n1, Node::ID n2)
{
	Path p;
	auto it = m_paths.find(std::make_pair(n1, n2));
	auto node = n1;
	auto branch = it->second.second;
	auto &realBranch = m_branchs.find(branch)->second;
	while (it != m_paths.end() && !(realBranch.getSecondNode() == n2))
	{
		p.addBranch(node, branch);
		it = m_paths.find(std::make_pair(node, realBranch.getFirstNode()));
		node = realBranch.getFirstNode();
		branch = it->second.second;
		realBranch = m_branchs.find(branch)->second;
	}
	return p;
}

Node::ID Graph::addNode(Node node)
{
	NeighbourHood nh;
	Node::ID ni(node);
	m_neighbours.insert(std::make_pair(ni, nh));
	m_nodes.insert(std::make_pair(ni, node));
	return ni;
}

void Graph::addNode(Node::ID ni)
{
	NeighbourHood nh;
	m_neighbours.insert(std::make_pair(ni, nh));
	m_nodes.emplace(ni, ni);
}
/*
EdgeType Graph::newEdge(Node n1, Node n2)
{
	EdgeType t = NONE;
	sf::Vector2f const& p1 = n1.getPosition(), p2 = n2.getPosition();
	if (isItLeaf(n1, n2))
	{
		if (hasDownEdge(n1) && hasDownEdge(n2))
			t = LEAF;
	}
	else if (n1 < n2 && hasDownEdge(n1) || n2 < n1 && hasDownEdge(n2))
		t = BRANCH;
	auto it1 = m_nodes.find(n1), it2 = m_nodes.find(n2);
	if (it1 != m_nodes.end() && it2 != m_nodes.end() && t != NONE)
	{
		it1->second.insert(std::make_pair(n2, t));
		it2->second.insert(std::make_pair(n1, t));
		return t;
	}
	else
		return NONE;
}

EdgeType Graph::forceNewEdge(Node n1, Node n2)
{
	EdgeType t = NONE;
	sf::Vector2f const& p1 = n1.getPosition(), p2 = n2.getPosition();
	if (isItLeaf(n1, n2))
		t = LEAF;
	else
		t = BRANCH;

	auto it1 = m_nodes.find(n1), it2 = m_nodes.find(n2);
	if (it1 != m_nodes.end() && it2 != m_nodes.end())
	{
		it1->second.insert(std::make_pair(n2, t));
		it2->second.insert(std::make_pair(n1, t));
		return t;
	}
	else
		return NONE;
}
*/

Branch::ID Graph::newEdge(Node::ID n1, Node::ID n2)
{
	auto it1 = m_neighbours.find(n1), it2 = m_neighbours.find(n2);
	if (it1 != m_neighbours.end()
			&& it2 != m_neighbours.end()
			&& m_nodes.find(n1)->second.getType() == Node::Type::RegularNode
			&& m_nodes.find(n2)->second.getType() == Node::Type::RegularNode
			&& ((n1 < n2 && hasDownEdge(n1))
				|| (n2 < n1 && hasDownEdge(n2))
				)
			)
	{
		auto id_n_it = m_branchs.emplace_hint(m_branchs.end(), std::piecewise_construct, std::forward_as_tuple(m_branchId++), std::forward_as_tuple(n1, n2));
		it1->second.insert(std::make_pair(n2, id_n_it->first));
		it2->second.insert(std::make_pair(n1, id_n_it->first));
		return id_n_it->first;
	}
	else
		return Branch::ID(0);
}

Branch::ID Graph::forceNewEdge(Node::ID n1, Node::ID n2)
{
	auto it1 = m_neighbours.find(n1), it2 = m_neighbours.find(n2);
	if (it1 != m_neighbours.end() && it2 != m_neighbours.end())
	{
		auto id_n_it = m_branchs.emplace_hint(m_branchs.end(), std::piecewise_construct, std::forward_as_tuple(m_branchId++), std::forward_as_tuple(n1, n2));
		it1->second.insert(std::make_pair(n2, id_n_it->first));
		it2->second.insert(std::make_pair(n1, id_n_it->first));
		return id_n_it->first;
	}
	else
		return Branch::ID(0);
}

/*
bool Graph::isItLeaf(Node::ID n1, Node::ID n2)
{
	sf::Vector2f const& p1 = n1.getPosition(), p2 = n2.getPosition();
	return std::abs(p2.y - p1.y) <= leafLimit * std::abs(p2.x - p1.x);
}
*/

bool Graph::hasDownEdge(Node::ID n) const
{
	auto it = m_neighbours.find(n);
	if (it == m_neighbours.end())
		return false;
	auto pair = it->second.begin();
	return pair != it->second.end() && pair->first < n;
}

void Graph::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
	for (auto pair : m_branchs)
	{
		pair.second.draw(target, states);
	}

	for (auto pair : m_nodes)
	{
		pair.second.draw(target, states);
	}

}
<|endoftext|>


<commit_before>// Copyright 2016 Dolotov Evgeniy

#include "../include/hello_world.h"

float sum(float a, float b) {
    return a+b;
}
<commit_msg>fix travis<commit_after>// Copyright 2016 Dolotov Evgeniy

#include "../include/hello_world.h"

float sum(float a, float b) {
    return a+b;
}

float mult(float a, float b) {
    return a*b;
}
<|endoftext|>


<commit_before>#include "iOSCFClient.h"

#include "BasicAuth.h"

#include <cstdio>
#include <cstring>
#include <cassert>

#include <CoreFoundation/CoreFoundation.h>
#include <CFNetwork/CFNetwork.h>
#include <CFNetwork/CFHTTPStream.h>

#define _kCFStreamPropertyReadTimeout CFSTR("_kCFStreamPropertyReadTimeout")

using namespace std;

class iOSCFClient : public HTTPClient {
 public:
  iOSCFClient(const std::string & _user_agent, bool _enable_cookies, bool _enable_keepalive)
    : HTTPClient(_user_agent, _enable_cookies, _enable_keepalive) {

  }

  void request(const HTTPRequest & req, const Authorization & auth, HTTPClientInterface & callback) override {
    CFStringRef url_string = CFStringCreateWithCString(NULL, req.getURI().c_str(), kCFStringEncodingUTF8);
    CFURLRef cfUrl = CFURLCreateWithString(kCFAllocatorDefault, url_string, NULL);

    if (!cfUrl) {
      // url_string is needed here, do not release yet
      CFStringRef url_string2 = CFURLCreateStringByAddingPercentEscapes(NULL, url_string, NULL, NULL, kCFStringEncodingUTF8);
      cfUrl = CFURLCreateWithString(kCFAllocatorDefault, url_string2, NULL);
      CFRelease(url_string2);
    }

    CFRelease(url_string);

    if (!cfUrl) {
      callback.handleResultCode(0);
      callback.handleDisconnect();
      return;
    }

    map<string, string> combined_headers;
    combined_headers["User-Agent"] = user_agent;

    string auth_header = auth.createHeader();
    if (!auth_header.empty()) {
      combined_headers[auth.getHeaderName()] = auth_header;
    }

    CFHTTPMessageRef cfHttpReq;
    if (req.getType() == HTTPRequest::POST) {
      cfHttpReq = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("POST"), cfUrl, kCFHTTPVersion1_1);

      combined_headers["Content-Length"] = to_string(req.getContent().size());
      combined_headers["Content-Type"] = req.getContentType();

      CFDataRef body = CFDataCreate(0, (const UInt8 *)req.getContent().data(), (CFIndex)req.getContent().size());
      CFHTTPMessageSetBody(cfHttpReq, body);
      CFRelease(body);
    } else {
      cfHttpReq = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), cfUrl, kCFHTTPVersion1_1);
    }

    for (auto & hd : default_headers) {
      combined_headers[hd.first] = hd.second;
    }
    for (auto & hd : req.getHeaders()) {
      combined_headers[hd.first] = hd.second;
    }
    for (auto & hd : combined_headers) {
      CFStringRef key = CFStringCreateWithCString(NULL, hd.first.c_str(), kCFStringEncodingUTF8);
      CFStringRef value = CFStringCreateWithCString(NULL, hd.second.c_str(), kCFStringEncodingUTF8);
      CFHTTPMessageSetHeaderFieldValue(cfHttpReq, key, value);
      CFRelease(key);
      CFRelease(value);
    }

    CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, cfHttpReq);

    if (req.getReadTimeout()) {
      double timeout = req.getReadTimeout();
      CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &timeout);
      CFReadStreamSetProperty(readStream, _kCFStreamPropertyReadTimeout, number);
      CFRelease(number);
    }

    if (req.getFollowLocation()) {
      CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue);
    }

    if (!CFReadStreamOpen(readStream)) {
      // fail
    }

    bool headersReceived = false;
    bool terminate = false;
    int result_code = 0;
    string redirectUrl;

    while (!terminate) {
      const int nBuffSize = 4096;
      UInt8 buff[nBuffSize];
      CFIndex numBytesRead = CFReadStreamRead(readStream, buff, nBuffSize);

      if (!headersReceived) {
        headersReceived = true;
        CFHTTPMessageRef myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);

        if (myResponse) {
          // CFStringRef myStatusLine = CFHTTPMessageCopyResponseStatusLine(myResponse);
          result_code = (int)CFHTTPMessageGetResponseStatusCode(myResponse);

          callback.handleResultCode(result_code);

          CFDictionaryRef headerFields = CFHTTPMessageCopyAllHeaderFields(myResponse);
          auto size = CFDictionaryGetCount(headerFields);
          if (size > 0) {
            CFTypeRef *keys = (CFTypeRef *)malloc(size * sizeof(CFTypeRef));
            CFStringRef *values = (CFStringRef *)malloc(size * sizeof(CFStringRef));
            CFDictionaryGetKeysAndValues(headerFields, (const void **)keys, (const void **)values);
            for (unsigned int i = 0; i < size; i++) {
              const char * keyStr = CFStringGetCStringPtr((CFStringRef)keys[i], kCFStringEncodingUTF8);
              const char * valStr = CFStringGetCStringPtr((CFStringRef)values[i], kCFStringEncodingUTF8);

              if (keyStr && valStr) {
                callback.handleHeader(keyStr, valStr);

                if (result_code >= 300 && result_code <= 399 && strcasecmp(keyStr, "location") == 0) {
		  redirectUrl = valStr;
		  if (!callback.handleRedirectUrl(redirectUrl)) {
		    terminate = true;
		  }
                }
              }
            }
            free(keys);
            free(values);
          }
	  CFRelease(headerFields);
	  CFRelease(myResponse);
        }
      }

      if (numBytesRead > 0) {
        if (!callback.handleChunk(numBytesRead, (char *)buff)) {
          terminate = true;
        }
      } else if (numBytesRead < 0) {
        CFStreamError error = CFReadStreamGetError(readStream);
        terminate = true;
      } else {
        terminate = true;
      }
    }

    CFReadStreamClose(readStream);

    CFRelease(cfUrl);
    CFRelease(cfHttpReq);
    CFRelease(readStream);

    // cerr << "loaded " << req.getURI().c_str() << " (" << result_code << ", target = " << redirectUrl << ")\n";

#if 0
    const BasicAuth * basic = dynamic_cast<const BasicAuth *>(&auth);
    if (basic) {
      string s = basic->getUsername();
      s += ':';
      s += basic->getPassword();
    }
#endif

    callback.handleDisconnect();
  }

  void clearCookies() override {

  }
};

std::unique_ptr<HTTPClient>
iOSCFClientFactory::createClient2(const std::string & _user_agent, bool _enable_cookies, bool _enable_keepalive) {
  return std::unique_ptr<iOSCFClient>(new iOSCFClient(_user_agent, _enable_cookies, _enable_keepalive));
}
<commit_msg>add keep-alive<commit_after>#include "iOSCFClient.h"

#include "BasicAuth.h"

#include <cstdio>
#include <cstring>
#include <cassert>

#include <CoreFoundation/CoreFoundation.h>
#include <CFNetwork/CFNetwork.h>
#include <CFNetwork/CFHTTPStream.h>

#define _kCFStreamPropertyReadTimeout CFSTR("_kCFStreamPropertyReadTimeout")

using namespace std;

class iOSCFClient : public HTTPClient {
 public:
  iOSCFClient(const std::string & _user_agent, bool _enable_cookies, bool _enable_keepalive)
    : HTTPClient(_user_agent, _enable_cookies, _enable_keepalive) {

  }

  void request(const HTTPRequest & req, const Authorization & auth, HTTPClientInterface & callback) override {
    CFStringRef url_string = CFStringCreateWithCString(NULL, req.getURI().c_str(), kCFStringEncodingUTF8);
    CFURLRef cfUrl = CFURLCreateWithString(kCFAllocatorDefault, url_string, NULL);

    if (!cfUrl) {
      // url_string is needed here, do not release yet
      CFStringRef url_string2 = CFURLCreateStringByAddingPercentEscapes(NULL, url_string, NULL, NULL, kCFStringEncodingUTF8);
      cfUrl = CFURLCreateWithString(kCFAllocatorDefault, url_string2, NULL);
      CFRelease(url_string2);
    }

    CFRelease(url_string);

    if (!cfUrl) {
      callback.handleResultCode(0);
      callback.handleDisconnect();
      return;
    }

    map<string, string> combined_headers;
    combined_headers["User-Agent"] = user_agent;

    if (enable_keepalive) {
      // combined_headers["Connection"] = "Keep-Alive";
      combined_headers["Keep-Alive"] = "30";
    }

    string auth_header = auth.createHeader();
    if (!auth_header.empty()) {
      combined_headers[auth.getHeaderName()] = auth_header;
    }

    CFHTTPMessageRef cfHttpReq;
    if (req.getType() == HTTPRequest::POST) {
      cfHttpReq = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("POST"), cfUrl, kCFHTTPVersion1_1);

      combined_headers["Content-Length"] = to_string(req.getContent().size());
      combined_headers["Content-Type"] = req.getContentType();

      CFDataRef body = CFDataCreate(0, (const UInt8 *)req.getContent().data(), (CFIndex)req.getContent().size());
      CFHTTPMessageSetBody(cfHttpReq, body);
      CFRelease(body);
    } else {
      cfHttpReq = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), cfUrl, kCFHTTPVersion1_1);
    }

    for (auto & hd : default_headers) {
      combined_headers[hd.first] = hd.second;
    }
    for (auto & hd : req.getHeaders()) {
      combined_headers[hd.first] = hd.second;
    }
    for (auto & hd : combined_headers) {
      CFStringRef key = CFStringCreateWithCString(NULL, hd.first.c_str(), kCFStringEncodingUTF8);
      CFStringRef value = CFStringCreateWithCString(NULL, hd.second.c_str(), kCFStringEncodingUTF8);
      CFHTTPMessageSetHeaderFieldValue(cfHttpReq, key, value);
      CFRelease(key);
      CFRelease(value);
    }

    CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, cfHttpReq);

    CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPAttemptPersistentConnection, enable_keepalive ? kCFBooleanTrue : kCFBooleanFalse);

    if (req.getReadTimeout()) {
      double timeout = req.getReadTimeout();
      CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &timeout);
      CFReadStreamSetProperty(readStream, _kCFStreamPropertyReadTimeout, number);
      CFRelease(number);
    }

    if (req.getFollowLocation()) {
      CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue);
    }

    if (!CFReadStreamOpen(readStream)) {
      // fail
    }

    bool headersReceived = false;
    bool terminate = false;
    int result_code = 0;
    string redirectUrl;

    while (!terminate) {
      const int nBuffSize = 4096;
      UInt8 buff[nBuffSize];
      CFIndex numBytesRead = CFReadStreamRead(readStream, buff, nBuffSize);

      if (!headersReceived) {
        headersReceived = true;
        CFHTTPMessageRef myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);

        if (myResponse) {
          // CFStringRef myStatusLine = CFHTTPMessageCopyResponseStatusLine(myResponse);
          result_code = (int)CFHTTPMessageGetResponseStatusCode(myResponse);

          callback.handleResultCode(result_code);

          CFDictionaryRef headerFields = CFHTTPMessageCopyAllHeaderFields(myResponse);
          auto size = CFDictionaryGetCount(headerFields);
          if (size > 0) {
            CFTypeRef *keys = (CFTypeRef *)malloc(size * sizeof(CFTypeRef));
            CFStringRef *values = (CFStringRef *)malloc(size * sizeof(CFStringRef));
            CFDictionaryGetKeysAndValues(headerFields, (const void **)keys, (const void **)values);
            for (unsigned int i = 0; i < size; i++) {
              const char * keyStr = CFStringGetCStringPtr((CFStringRef)keys[i], kCFStringEncodingUTF8);
              const char * valStr = CFStringGetCStringPtr((CFStringRef)values[i], kCFStringEncodingUTF8);

              if (keyStr && valStr) {
                callback.handleHeader(keyStr, valStr);

                if (result_code >= 300 && result_code <= 399 && strcasecmp(keyStr, "location") == 0) {
		  redirectUrl = valStr;
		  if (!callback.handleRedirectUrl(redirectUrl)) {
		    terminate = true;
		  }
                }
              }
            }
            free(keys);
            free(values);
          }
	  CFRelease(headerFields);
	  CFRelease(myResponse);
        }
      }

      if (numBytesRead > 0) {
        if (!callback.handleChunk(numBytesRead, (char *)buff)) {
          terminate = true;
        }
      } else if (numBytesRead < 0) {
        CFStreamError error = CFReadStreamGetError(readStream);
        terminate = true;
      } else {
        terminate = true;
      }
    }

    CFReadStreamClose(readStream);

    CFRelease(cfUrl);
    CFRelease(cfHttpReq);
    CFRelease(readStream);

    // cerr << "loaded " << req.getURI().c_str() << " (" << result_code << ", target = " << redirectUrl << ")\n";

#if 0
    const BasicAuth * basic = dynamic_cast<const BasicAuth *>(&auth);
    if (basic) {
      string s = basic->getUsername();
      s += ':';
      s += basic->getPassword();
    }
#endif

    callback.handleDisconnect();
  }

  void clearCookies() override {

  }
};

std::unique_ptr<HTTPClient>
iOSCFClientFactory::createClient2(const std::string & _user_agent, bool _enable_cookies, bool _enable_keepalive) {
  return std::unique_ptr<iOSCFClient>(new iOSCFClient(_user_agent, _enable_cookies, _enable_keepalive));
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <cstdlib>
#include <algorithm>
#include <exception>
#include <thread>

#include "settings.h"
#include "grayscale_bitmap.h"
#include "freetype_interface.h"
#include "sdl_interface.h"
#include "image_processor.h"

static void writeThreadsOutputToFile(const std::vector<ImageToTextResult>& thResults,
                                    size_t symbolsInLine) {
    std::ofstream outfile("test.txt");

    size_t symbolsInFile = 0;
    for (const ImageToTextResult& oneThResult : thResults) {
        while (!oneThResult.done.load());

        for (char frameMatch : oneThResult.frameMatches) {
            outfile << frameMatch;

            if (++symbolsInFile % symbolsInLine == 0) {
                outfile << '\n';
            }
        }
    }
}

typedef std::pair<FrameSlider, FrameSlider> img_data_range;
static void assignThreadTasks(  const FramedBitmap& map,
                                std::vector<img_data_range>& tasks,
                                uint_fast8_t threadsNum) {
    size_t framesTotal = map.countFrames();
    size_t framesPerThread = framesTotal % threadsNum == 0
                            ? framesTotal / threadsNum
                            : framesTotal / threadsNum + 1;

    FrameSlider slider  = map.firstFrame();
    FrameSlider imgEnd  = map.lastFrame();
    for (uint_fast8_t threadNum = 0; threadNum < threadsNum; ++threadNum) {
        FrameSlider taskStart = slider;
        for (size_t frame = 0; frame < framesPerThread; ++frame) {
            if (slider == imgEnd) {
                break;
            }

            slider.slide();
        }

        tasks.emplace_back(taskStart, slider);

        if (slider != imgEnd) {
            slider.slide();
        }
    }
}

uint_fast8_t const THREADS_TOTAL = 4;
void imageToText(const Settings settings) {

    setFont(settings.fontPath, settings.fontSize);
    FramedBitmap map = loadGrayscaleImage(settings.imagePath);
    map.setFrameSize(getFontWidth(), getFontHeight());

    ImageToTextResult resDummy(map.countFrames());
    std::vector<ImageToTextResult> threadResults(THREADS_TOTAL, resDummy);
    std::vector<img_data_range> threadTasks;

    assignThreadTasks(map, threadTasks, THREADS_TOTAL);

    for (uint_fast8_t threadNum = 0; threadNum < THREADS_TOTAL; ++threadNum) {
        std::thread(processImagePart,
                    std::ref(threadTasks.at(threadNum).first),
                    std::ref(threadTasks.at(threadNum).second),
                    std::ref(threadResults.at(threadNum))).detach();
    }

    size_t framesInRow = map.columns / map.frameWidth;
    writeThreadsOutputToFile(threadResults, framesInRow);
}

int main(int argc, char* argv[]) {

    try {
        Settings settings = parseArguments(argc, argv);
        imageToText(settings);
    }
    catch (const std::exception& error) {
        std::cerr << error.what() << std::endl;
    }
    catch (...) {
        std::cerr << "Unknown exception caught" << std::endl;
    }

    return 0;
}
<commit_msg>do not pass structs by value #12<commit_after>#include <iostream>
#include <fstream>
#include <cstdlib>
#include <algorithm>
#include <exception>
#include <thread>

#include "settings.h"
#include "grayscale_bitmap.h"
#include "freetype_interface.h"
#include "sdl_interface.h"
#include "image_processor.h"

static void writeThreadsOutputToFile(const std::vector<ImageToTextResult>& thResults,
                                    size_t symbolsInLine) {
    std::ofstream outfile("test.txt");

    size_t symbolsInFile = 0;
    for (const ImageToTextResult& oneThResult : thResults) {
        while (!oneThResult.done.load());

        for (char frameMatch : oneThResult.frameMatches) {
            outfile << frameMatch;

            if (++symbolsInFile % symbolsInLine == 0) {
                outfile << '\n';
            }
        }
    }
}

typedef std::pair<FrameSlider, FrameSlider> img_data_range;
static void assignThreadTasks(  const FramedBitmap& map,
                                std::vector<img_data_range>& tasks,
                                uint_fast8_t threadsNum) {
    size_t framesTotal = map.countFrames();
    size_t framesPerThread = framesTotal % threadsNum == 0
                            ? framesTotal / threadsNum
                            : framesTotal / threadsNum + 1;

    FrameSlider slider  = map.firstFrame();
    FrameSlider imgEnd  = map.lastFrame();
    for (uint_fast8_t threadNum = 0; threadNum < threadsNum; ++threadNum) {
        FrameSlider taskStart = slider;
        for (size_t frame = 0; frame < framesPerThread; ++frame) {
            if (slider == imgEnd) {
                break;
            }

            slider.slide();
        }

        tasks.emplace_back(taskStart, slider);

        if (slider != imgEnd) {
            slider.slide();
        }
    }
}

uint_fast8_t const THREADS_TOTAL = 4;
void imageToText(const Settings& settings) {

    setFont(settings.fontPath, settings.fontSize);
    FramedBitmap map = loadGrayscaleImage(settings.imagePath);
    map.setFrameSize(getFontWidth(), getFontHeight());

    ImageToTextResult resDummy(map.countFrames());
    std::vector<ImageToTextResult> threadResults(THREADS_TOTAL, resDummy);
    std::vector<img_data_range> threadTasks;

    assignThreadTasks(map, threadTasks, THREADS_TOTAL);

    for (uint_fast8_t threadNum = 0; threadNum < THREADS_TOTAL; ++threadNum) {
        std::thread(processImagePart,
                    std::ref(threadTasks.at(threadNum).first),
                    std::ref(threadTasks.at(threadNum).second),
                    std::ref(threadResults.at(threadNum))).detach();
    }

    size_t framesInRow = map.columns / map.frameWidth;
    writeThreadsOutputToFile(threadResults, framesInRow);
}

int main(int argc, char* argv[]) {
    try {
        Settings settings = parseArguments(argc, argv);
        imageToText(settings);
    }
    catch (const std::exception& error) {
        std::cerr << error.what() << std::endl;
    }
    catch (...) {
        std::cerr << "Unknown exception caught" << std::endl;
    }

    return 0;
}
<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include "swissknife_reflog.h"

#include <cassert>

#include <string>
#include <vector>

#include "manifest.h"
#include "object_fetcher.h"
#include "upload_facility.h"

namespace swissknife {

typedef HttpObjectFetcher<> ObjectFetcher;

class RootChainWalker {
 public:
  typedef ObjectFetcher::CatalogTN CatalogTN;
  typedef ObjectFetcher::HistoryTN HistoryTN;

 public:
  RootChainWalker(const manifest::Manifest *manifest,
                  ObjectFetcher            *object_fetcher,
                  manifest::Reflog         *reflog)
    : object_fetcher_(object_fetcher)
    , reflog_(reflog)
    , manifest_(manifest) {}

  void FindObjectsAndPopulateReflog();

 protected:
  typedef std::vector<shash::Any> CatalogList;

 protected:
  CatalogTN* FetchCatalog(const shash::Any catalog_hash);
  HistoryTN* FetchHistory(const shash::Any history_hash);

  void WalkRootCatalogs(const shash::Any &root_catalog_hash);
  void WalkHistories(const shash::Any &history_hash);

  void WalkCatalogsInHistory(const HistoryTN *history);
  void WalkListedCatalogs(const CatalogList &catalog_list);

  template <class DatabaseT>
  DatabaseT* ReturnOrAbort(const ObjectFetcherFailures::Failures  failure,
                           const shash::Any                      &content_hash,
                           DatabaseT                             *database);

 private:
  ObjectFetcher            *object_fetcher_;
  manifest::Reflog         *reflog_;
  const manifest::Manifest *manifest_;
};

ParameterList CommandReconstructReflog::GetParams() const {
  ParameterList r;
  r.push_back(Parameter::Mandatory('r', "repository url"));
  r.push_back(Parameter::Mandatory('u', "spooler definition string"));
  r.push_back(Parameter::Mandatory('n', "fully qualified repository name"));
  r.push_back(Parameter::Mandatory('t', "temporary directory"));
  r.push_back(Parameter::Mandatory('k', "repository keychain"));
  r.push_back(Parameter::Mandatory('R', "path to reflog.chksum file"));
  return r;
}

int CommandReconstructReflog::Main(const ArgumentList &args) {
  const std::string &repo_url           = *args.find('r')->second;
  const std::string &spooler            = *args.find('u')->second;
  const std::string &repo_name          = *args.find('n')->second;
  const std::string &tmp_dir            = *args.find('t')->second;
  const std::string &repo_keys          = *args.find('k')->second;
  const std::string &reflog_chksum_path = *args.find('R')->second;

  const bool follow_redirects = false;
  if (!this->InitDownloadManager(follow_redirects) ||
      !this->InitVerifyingSignatureManager(repo_keys)) {
    LogCvmfs(kLogCvmfs, kLogStderr, "failed to init repo connection");
    return 1;
  }

  ObjectFetcher object_fetcher(repo_name,
                               repo_url,
                               tmp_dir,
                               download_manager(),
                               signature_manager());

  UniquePtr<manifest::Manifest> manifest;
  ObjectFetcher::Failures retval = object_fetcher.FetchManifest(&manifest);
  if (retval != ObjectFetcher::kFailOk) {
    LogCvmfs(kLogCvmfs, kLogStderr, "failed to load repository manifest "
                                    "(%d - %s)",
                                    retval, Code2Ascii(retval));
    return 1;
  }

  const upload::SpoolerDefinition spooler_definition(spooler, shash::kAny);
  UniquePtr<upload::AbstractUploader> uploader(
                       upload::AbstractUploader::Construct(spooler_definition));

  if (!uploader.IsValid()) {
    LogCvmfs(kLogCvmfs, kLogStderr, "failed to initialize spooler for '%s'",
             spooler.c_str());
    return 1;
  }

  UniquePtr<manifest::Reflog> reflog(CreateEmptyReflog(tmp_dir, repo_name));
  reflog->TakeDatabaseFileOwnership();

  reflog->BeginTransaction();
  AddStaticManifestObjects(reflog.weak_ref(), manifest.weak_ref());
  RootChainWalker walker(manifest.weak_ref(),
                         &object_fetcher,
                         reflog.weak_ref());
  walker.FindObjectsAndPopulateReflog();
  reflog->CommitTransaction();

  LogCvmfs(kLogCvmfs, kLogStdout, "found %d entries", reflog->CountEntries());

  reflog->DropDatabaseFileOwnership();
  const std::string reflog_db = reflog->database_file();
  reflog.Destroy();
  uploader->Upload(reflog_db, ".cvmfsreflog");
  shash::Any reflog_hash(manifest->GetHashAlgorithm());
  manifest::Reflog::HashDatabase(reflog_db, &reflog_hash);
  uploader->WaitForUpload();
  unlink(reflog_db.c_str());

  const int errors = uploader->GetNumberOfErrors();
  if (errors > 0) {
    LogCvmfs(kLogCvmfs, kLogStderr, "failed to upload generated Reflog");
  }

  uploader->TearDown();

  manifest::Reflog::WriteChecksum(reflog_chksum_path, reflog_hash);

  return (errors == 0) ? 0 : 1;
}

void CommandReconstructReflog::AddStaticManifestObjects(
                                          manifest::Reflog    *reflog,
                                          manifest::Manifest  *manifest) const {
  const shash::Any certificate = manifest->certificate();
  const shash::Any meta_info   = manifest->meta_info();
  assert(!certificate.IsNull());

  bool success = reflog->AddCertificate(certificate);
  assert(success);
  LogCvmfs(kLogCvmfs, kLogStdout, "Certificate: %s",
           certificate.ToString().c_str());

  if (!meta_info.IsNull()) {
    success = reflog->AddMetainfo(meta_info);
    assert(success);
    LogCvmfs(kLogCvmfs, kLogStdout, "Metainfo: %s",
             meta_info.ToString().c_str());
  }
}

void RootChainWalker::FindObjectsAndPopulateReflog() {
  const shash::Any root_catalog = manifest_->catalog_hash();
  const shash::Any history      = manifest_->history();

  assert(!root_catalog.IsNull());
  WalkRootCatalogs(root_catalog);

  if (!history.IsNull()) {
    WalkHistories(history);
  }
}

void RootChainWalker::WalkRootCatalogs(const shash::Any &root_catalog_hash) {
  shash::Any           current_hash = root_catalog_hash;
  UniquePtr<CatalogTN> current_catalog;

  while (!current_hash.IsNull()                  &&
         !reflog_->ContainsCatalog(current_hash) &&
         (current_catalog = FetchCatalog(current_hash)).IsValid()) {
    LogCvmfs(kLogCvmfs, kLogStdout, "Catalog: %s Revision: %d",
             current_hash.ToString().c_str(), current_catalog->GetRevision());

    const bool success = reflog_->AddCatalog(current_hash);
    assert(success);

    current_hash = current_catalog->GetPreviousRevision();
  }
}

void RootChainWalker::WalkHistories(const shash::Any &history_hash) {
  shash::Any           current_hash = history_hash;
  UniquePtr<HistoryTN> current_history;

  while (!current_hash.IsNull()                  &&
         !reflog_->ContainsHistory(current_hash) &&
         (current_history = FetchHistory(current_hash)).IsValid()) {
    LogCvmfs(kLogCvmfs, kLogStdout, "History: %s",
             current_hash.ToString().c_str());

    WalkCatalogsInHistory(current_history);
    const bool success = reflog_->AddHistory(current_hash);
    assert(success);

    current_hash = current_history->previous_revision();
  }
}

void RootChainWalker::WalkCatalogsInHistory(const HistoryTN *history) {
  CatalogList tag_hashes;
  const bool list_success = history->GetHashes(&tag_hashes);
  assert(list_success);

  CatalogList bin_hashes;
  const bool bin_success = history->ListRecycleBin(&bin_hashes);
  if (!bin_success) {
    LogCvmfs(kLogCvmfs, kLogStderr, "  Warning: 'recycle bin' table missing");
  }

  WalkListedCatalogs(tag_hashes);
  WalkListedCatalogs(bin_hashes);
}

void RootChainWalker::WalkListedCatalogs(
                             const RootChainWalker::CatalogList &catalog_list) {
  CatalogList::const_iterator i    = catalog_list.begin();
  CatalogList::const_iterator iend = catalog_list.end();
  for (; i != iend; ++i) {
    WalkRootCatalogs(*i);
  }
}

RootChainWalker::CatalogTN* RootChainWalker::FetchCatalog(
                                                const shash::Any catalog_hash) {
  CatalogTN *catalog = NULL;
  const char *root_path = "";
  ObjectFetcherFailures::Failures failure =
    object_fetcher_->FetchCatalog(catalog_hash, root_path, &catalog);

  return ReturnOrAbort(failure, catalog_hash, catalog);
}

RootChainWalker::HistoryTN* RootChainWalker::FetchHistory(
                                                const shash::Any history_hash) {
  HistoryTN *history = NULL;
  ObjectFetcherFailures::Failures failure =
    object_fetcher_->FetchHistory(&history, history_hash);

  return ReturnOrAbort(failure, history_hash, history);
}

template <class DatabaseT>
DatabaseT* RootChainWalker::ReturnOrAbort(
                            const ObjectFetcherFailures::Failures  failure,
                            const shash::Any                      &content_hash,
                            DatabaseT                             *database) {
  switch (failure) {
    case ObjectFetcherFailures::kFailOk:
      return database;
    case ObjectFetcherFailures::kFailNotFound:
      return NULL;
    default:
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to load object '%s' (%d - %s)",
                                      content_hash.ToStringWithSuffix().c_str(),
                                      failure, Code2Ascii(failure));
      abort();
  }
}

}  // namespace swissknife
<commit_msg>cancel history iteration on database oddities<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include "swissknife_reflog.h"

#include <cassert>

#include <string>
#include <vector>

#include "manifest.h"
#include "object_fetcher.h"
#include "upload_facility.h"

namespace swissknife {

typedef HttpObjectFetcher<> ObjectFetcher;

class RootChainWalker {
 public:
  typedef ObjectFetcher::CatalogTN CatalogTN;
  typedef ObjectFetcher::HistoryTN HistoryTN;

 public:
  RootChainWalker(const manifest::Manifest *manifest,
                  ObjectFetcher            *object_fetcher,
                  manifest::Reflog         *reflog)
    : object_fetcher_(object_fetcher)
    , reflog_(reflog)
    , manifest_(manifest) {}

  void FindObjectsAndPopulateReflog();

 protected:
  typedef std::vector<shash::Any> CatalogList;

 protected:
  CatalogTN* FetchCatalog(const shash::Any catalog_hash);
  HistoryTN* FetchHistory(const shash::Any history_hash);

  void WalkRootCatalogs(const shash::Any &root_catalog_hash);
  void WalkHistories(const shash::Any &history_hash);

  bool WalkCatalogsInHistory(const HistoryTN *history);
  void WalkListedCatalogs(const CatalogList &catalog_list);

  template <class DatabaseT>
  DatabaseT* ReturnOrAbort(const ObjectFetcherFailures::Failures  failure,
                           const shash::Any                      &content_hash,
                           DatabaseT                             *database);

 private:
  ObjectFetcher            *object_fetcher_;
  manifest::Reflog         *reflog_;
  const manifest::Manifest *manifest_;
};

ParameterList CommandReconstructReflog::GetParams() const {
  ParameterList r;
  r.push_back(Parameter::Mandatory('r', "repository url"));
  r.push_back(Parameter::Mandatory('u', "spooler definition string"));
  r.push_back(Parameter::Mandatory('n', "fully qualified repository name"));
  r.push_back(Parameter::Mandatory('t', "temporary directory"));
  r.push_back(Parameter::Mandatory('k', "repository keychain"));
  r.push_back(Parameter::Mandatory('R', "path to reflog.chksum file"));
  return r;
}

int CommandReconstructReflog::Main(const ArgumentList &args) {
  const std::string &repo_url           = *args.find('r')->second;
  const std::string &spooler            = *args.find('u')->second;
  const std::string &repo_name          = *args.find('n')->second;
  const std::string &tmp_dir            = *args.find('t')->second;
  const std::string &repo_keys          = *args.find('k')->second;
  const std::string &reflog_chksum_path = *args.find('R')->second;

  const bool follow_redirects = false;
  if (!this->InitDownloadManager(follow_redirects) ||
      !this->InitVerifyingSignatureManager(repo_keys)) {
    LogCvmfs(kLogCvmfs, kLogStderr, "failed to init repo connection");
    return 1;
  }

  ObjectFetcher object_fetcher(repo_name,
                               repo_url,
                               tmp_dir,
                               download_manager(),
                               signature_manager());

  UniquePtr<manifest::Manifest> manifest;
  ObjectFetcher::Failures retval = object_fetcher.FetchManifest(&manifest);
  if (retval != ObjectFetcher::kFailOk) {
    LogCvmfs(kLogCvmfs, kLogStderr, "failed to load repository manifest "
                                    "(%d - %s)",
                                    retval, Code2Ascii(retval));
    return 1;
  }

  const upload::SpoolerDefinition spooler_definition(spooler, shash::kAny);
  UniquePtr<upload::AbstractUploader> uploader(
                       upload::AbstractUploader::Construct(spooler_definition));

  if (!uploader.IsValid()) {
    LogCvmfs(kLogCvmfs, kLogStderr, "failed to initialize spooler for '%s'",
             spooler.c_str());
    return 1;
  }

  UniquePtr<manifest::Reflog> reflog(CreateEmptyReflog(tmp_dir, repo_name));
  reflog->TakeDatabaseFileOwnership();

  reflog->BeginTransaction();
  AddStaticManifestObjects(reflog.weak_ref(), manifest.weak_ref());
  RootChainWalker walker(manifest.weak_ref(),
                         &object_fetcher,
                         reflog.weak_ref());
  walker.FindObjectsAndPopulateReflog();
  reflog->CommitTransaction();

  LogCvmfs(kLogCvmfs, kLogStdout, "found %d entries", reflog->CountEntries());

  reflog->DropDatabaseFileOwnership();
  const std::string reflog_db = reflog->database_file();
  reflog.Destroy();
  uploader->Upload(reflog_db, ".cvmfsreflog");
  shash::Any reflog_hash(manifest->GetHashAlgorithm());
  manifest::Reflog::HashDatabase(reflog_db, &reflog_hash);
  uploader->WaitForUpload();
  unlink(reflog_db.c_str());

  const int errors = uploader->GetNumberOfErrors();
  if (errors > 0) {
    LogCvmfs(kLogCvmfs, kLogStderr, "failed to upload generated Reflog");
  }

  uploader->TearDown();

  manifest::Reflog::WriteChecksum(reflog_chksum_path, reflog_hash);

  return (errors == 0) ? 0 : 1;
}

void CommandReconstructReflog::AddStaticManifestObjects(
                                          manifest::Reflog    *reflog,
                                          manifest::Manifest  *manifest) const {
  const shash::Any certificate = manifest->certificate();
  const shash::Any meta_info   = manifest->meta_info();
  assert(!certificate.IsNull());

  bool success = reflog->AddCertificate(certificate);
  assert(success);
  LogCvmfs(kLogCvmfs, kLogStdout, "Certificate: %s",
           certificate.ToString().c_str());

  if (!meta_info.IsNull()) {
    success = reflog->AddMetainfo(meta_info);
    assert(success);
    LogCvmfs(kLogCvmfs, kLogStdout, "Metainfo: %s",
             meta_info.ToString().c_str());
  }
}

void RootChainWalker::FindObjectsAndPopulateReflog() {
  const shash::Any root_catalog = manifest_->catalog_hash();
  const shash::Any history      = manifest_->history();

  assert(!root_catalog.IsNull());
  WalkRootCatalogs(root_catalog);

  if (!history.IsNull()) {
    WalkHistories(history);
  }
}

void RootChainWalker::WalkRootCatalogs(const shash::Any &root_catalog_hash) {
  shash::Any           current_hash = root_catalog_hash;
  UniquePtr<CatalogTN> current_catalog;

  while (!current_hash.IsNull()                  &&
         !reflog_->ContainsCatalog(current_hash) &&
         (current_catalog = FetchCatalog(current_hash)).IsValid()) {
    LogCvmfs(kLogCvmfs, kLogStdout, "Catalog: %s Revision: %d",
             current_hash.ToString().c_str(), current_catalog->GetRevision());

    const bool success = reflog_->AddCatalog(current_hash);
    assert(success);

    current_hash = current_catalog->GetPreviousRevision();
  }
}

void RootChainWalker::WalkHistories(const shash::Any &history_hash) {
  shash::Any           current_hash = history_hash;
  UniquePtr<HistoryTN> current_history;

  while (!current_hash.IsNull()                  &&
         !reflog_->ContainsHistory(current_hash) &&
         (current_history = FetchHistory(current_hash)).IsValid()) {
    LogCvmfs(kLogCvmfs, kLogStdout, "History: %s",
             current_hash.ToString().c_str());

    bool cancel = WalkCatalogsInHistory(current_history);
    const bool success = reflog_->AddHistory(current_hash);
    assert(success);

    if (cancel) {
      current_hash = shash::Any(current_hash.algorithm);
    } else {
      current_hash = current_history->previous_revision();
    }
  }
}

/**
 * If false is returned, it indicates that the history database comes from
 * an early pre-release of the history functionality. The WalkHistory()
 * iteration will subsequently stop. This is necessary, for instance, to
 * handle the cernvm-prod.cern.ch repository.
 */
bool RootChainWalker::WalkCatalogsInHistory(const HistoryTN *history) {
  CatalogList tag_hashes;
  const bool list_success = history->GetHashes(&tag_hashes);
  assert(list_success);

  CatalogList bin_hashes;
  const bool bin_success = history->ListRecycleBin(&bin_hashes);
  if (!bin_success) {
    LogCvmfs(kLogCvmfs, kLogStderr, "  Warning: 'recycle bin' table missing");
  }

  WalkListedCatalogs(tag_hashes);
  WalkListedCatalogs(bin_hashes);

  return !bin_success;
}

void RootChainWalker::WalkListedCatalogs(
                             const RootChainWalker::CatalogList &catalog_list) {
  CatalogList::const_iterator i    = catalog_list.begin();
  CatalogList::const_iterator iend = catalog_list.end();
  for (; i != iend; ++i) {
    WalkRootCatalogs(*i);
  }
}

RootChainWalker::CatalogTN* RootChainWalker::FetchCatalog(
                                                const shash::Any catalog_hash) {
  CatalogTN *catalog = NULL;
  const char *root_path = "";
  ObjectFetcherFailures::Failures failure =
    object_fetcher_->FetchCatalog(catalog_hash, root_path, &catalog);

  return ReturnOrAbort(failure, catalog_hash, catalog);
}

RootChainWalker::HistoryTN* RootChainWalker::FetchHistory(
                                                const shash::Any history_hash) {
  HistoryTN *history = NULL;
  ObjectFetcherFailures::Failures failure =
    object_fetcher_->FetchHistory(&history, history_hash);

  return ReturnOrAbort(failure, history_hash, history);
}

template <class DatabaseT>
DatabaseT* RootChainWalker::ReturnOrAbort(
                            const ObjectFetcherFailures::Failures  failure,
                            const shash::Any                      &content_hash,
                            DatabaseT                             *database) {
  switch (failure) {
    case ObjectFetcherFailures::kFailOk:
      return database;
    case ObjectFetcherFailures::kFailNotFound:
      return NULL;
    default:
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to load object '%s' (%d - %s)",
                                      content_hash.ToStringWithSuffix().c_str(),
                                      failure, Code2Ascii(failure));
      abort();
  }
}

}  // namespace swissknife
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015, Yahoo Inc. All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

#include <algorithm>
#include <cstring>
#include <sstream>

#include "ts.h"
#include "ts-impl.h"

namespace http {
namespace filters {

struct Contains {
  const char * const p;
  const size_t s;
  Contains(const char * const p, const size_t s) :
    p(p), s(s) {
    ASSERT(p != NULL);
    ASSERT(s <= strlen(p));
  }
  template < class I >
  bool operator () (const I & i) const {
    const char * const begin = i->pointer,
          * const end = begin + i->length;
    return std::search(begin, end, p, p + s) != end;
  }
};

struct Equal {
  const char * const p;
  const size_t s;
  Equal(const char * const p, const size_t s) :
    p(p), s(s) {
    ASSERT(p != NULL);
    ASSERT(s <= strlen(p));
  }
  template < class I >
  bool operator () (const I & i) const {
    return s == i->length && memcmp(p, i->pointer, s) == 0;
  }
};

template < class T >
struct GreaterThan {
  const T t;
  GreaterThan(const T & t) : t(t) { }
  template < class I >
  bool operator () (const I & i) const {
    std::istringstream ss(i->str());
    int64_t c;
    ss >> c;
    return ! ss.fail() && c > t;
  }
};

template < class T >
struct GreaterThanAfter {
  const char * const p;
  const size_t s;
  const T t;
  GreaterThanAfter(const char * const p, const size_t s,
      const T & t) : p(p), s(s), t(t) {
    ASSERT(s <= strlen(p));
  }
  template < class I >
  bool operator () (const I & i) const {
    const char * const begin = i->pointer,
          * const end = begin + i->length,
          * iterator = std::search(begin, end, p, p + s);
    while (iterator != end) {
      iterator += s;
      ASSERT(iterator <= end);
      std::istringstream ss(std::string(iterator, end - iterator));
      int64_t c;
      ss >> c;
      if ( ! ss.fail() && c > t) {
        return true;
      }
      iterator = std::search(iterator, end, p, p + s);
    }
    return false;
  }
};

template < class T >
struct LessThan {
  const T t;
  LessThan(const T & t) : t(t) { }
  template < class I >
  bool operator () (const I & i) const {
    std::istringstream ss(i->str());
    int64_t c;
    ss >> c;
    return ! ss.fail() && c < t;
  }
};

template < class T >
struct LessThanAfter{
  const char * const p;
  const size_t s;
  const T t;
  LessThanAfter(const char * const p, const size_t s,
      const T & t) : p(p), s(s), t(t) {
    ASSERT(s <= strlen(p));
  }
  template < class I >
  bool operator () (const I & i) const {
    const char * const begin = i->pointer,
          * const end = begin + i->length,
          * iterator = std::search(begin, end, p, p + s);
    while (iterator != end) {
      iterator += s;
      ASSERT(iterator <= end);
      std::istringstream ss(std::string(iterator, end - iterator));
      int64_t c;
      ss >> c;
      if ( ! ss.fail() && c < t) {
        return true;
      }
      iterator = std::search(iterator, end, p, p + s);
    }
    return false;
  }
};

struct StartsWith {
  const char * const p;
  const size_t s;
  const size_t o;
  StartsWith(const char * const p, const size_t s, const size_t o) :
    p(p), s(s), o(o) {
    ASSERT(p != NULL);
    ASSERT(s <= strlen(p));
  }
  template < class I >
  bool operator () (const I & i) const {
    const char * const begin = i->pointer,
          * const end = begin + i->length;
    return std::search(begin, end, p, p + s) == begin + o;
  }
};

template < class T, class U >
bool Loop(const typename T::Result & r, const U & u) {
  typedef typename T::Values::const_iterator Iterator;
  if ( ! r.second) {
    return false;
  }
  ASSERT(r.first != NULL);
  const Iterator end = r.first->end();
  Iterator it = r.first->begin();
  for (; it != end; ++it) {
    ASSERT(it->pointer != NULL);
    ASSERT(it->length > 0);
    if (u(it)) {
      return true;
    }
  }
  return false;
}

bool TSImplementation::ContainsHeader(
    const char * const a, const char * const b) {
  return Loop< Headers >(headers()[a], Contains(b, strlen(b)));
}

bool TSImplementation::EqualHeader(
    const char * const a, const char * const b) {
  return Loop< Headers >(headers()[a], Equal(b, strlen(b)));
}

bool TSImplementation::GreaterThanHeader(
    const char * const a, const int64_t b) {
  return Loop< Headers >(headers()[a], GreaterThan< int64_t >(b));
}

bool TSImplementation::GreaterThanAfterHeader(const char * const a,
    const char * const b, const int64_t c) {
  return Loop< Headers >(headers()[a],
      GreaterThanAfter< int64_t >(b, strlen(b), c));
}

bool TSImplementation::LessThanHeader(
    const char * const a, const int64_t b) {
  return Loop< Headers >(headers()[a], LessThan< int64_t >(b));
}

bool TSImplementation::LessThanAfterHeader(const char * const a,
    const char * const b, const int64_t c) {
  return Loop< Headers >(headers()[a],
      LessThanAfter< int64_t >(b, strlen(b), c));
}

bool TSImplementation::StartsWithHeader(
    const char * const a, const char * const b, const uint32_t c) {
  return Loop< Headers >(headers()[a], StartsWith(b, strlen(b), c));
}

bool TSImplementation::IsScheme(
    const char * const a, const uint32_t b) {
  ASSERT(a != NULL);
  ASSERT(strlen(a) == b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const m = TSUrlSchemeGet(buffer_, url(), &l);
  return b == static_cast< uint32_t >(l) && memcmp(m, a, b) == 0;
}

bool TSImplementation::IsMethod(
    const char * const a, const uint32_t b) const {
  ASSERT(a != NULL);
  ASSERT(strlen(a) == b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const m = TSHttpHdrMethodGet(buffer_, location_, &l);
  return b == static_cast< uint32_t >(l) && memcmp(m, a, b) == 0;
}

bool TSImplementation::ContainsDomain(
    const char * const a, const uint32_t b) {
  ASSERT(a != NULL);
  ASSERT(strlen(a) >= b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const begin = TSUrlHostGet(buffer_, url(), &l),
        * const end = begin + l;
  return std::search(begin, end, a, a + b) != end;
}

bool TSImplementation::EqualDomain(
    const char * const a, const uint32_t b) {
  ASSERT(a != NULL);
  ASSERT(strlen(a) >= b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const m = TSUrlHostGet(buffer_, url(), &l);
  return b == static_cast< uint32_t >(l) && memcmp(m, a, b) == 0;
}

bool TSImplementation::StartsWithDomain(
    const char * const a, const uint32_t b, const uint32_t c) {
  ASSERT(a != NULL);
  ASSERT(strlen(a) >= b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const begin = TSUrlHostGet(buffer_, url(), &l),
        * const end = begin + l;
  return std::search(begin, end, a, a + b) == begin + c;
}

bool TSImplementation::ContainsPath(
    const char * const a, const uint32_t b) {
  ASSERT(a != NULL);
  ASSERT(strlen(a) >= b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const begin = TSUrlPathGet(buffer_, url(), &l),
        * const end = begin + l;
  return std::search(begin, end, a, a + b) != end;
}

bool TSImplementation::EqualPath(
    const char * const a, const uint32_t b) {
  ASSERT(a != NULL);
  ASSERT(strlen(a) >= b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const m = TSUrlPathGet(buffer_, url(), &l);
  return b == static_cast< uint32_t >(l) && memcmp(m, a, b) == 0;
}

bool TSImplementation::StartsWithPath(
    const char * const a, const uint32_t b, const uint32_t c) {
  ASSERT(a != NULL);
  ASSERT(strlen(a) >= b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const begin = TSUrlPathGet(buffer_, url(), &l),
        * const end = begin + l;
  return std::search(begin, end, a, a + b) == begin + c;
}

bool TSImplementation::ContainsQueryParameter(
    const char * const a, const char * const b) {
  return Loop< QueryParameters >(queryParameters()[a], Contains(b, strlen(b)));
}

bool TSImplementation::EqualQueryParameter(
    const char * const a, const char * const b) {
  return Loop< QueryParameters >(queryParameters()[a], Equal(b, strlen(b)));
}

bool TSImplementation::GreaterThanQueryParameter(
    const char * const a, const int64_t b) {
  return Loop< QueryParameters >(queryParameters()[a], GreaterThan< int64_t >(b));
}

bool TSImplementation::GreaterThanAfterQueryParameter(const char * const a,
    const char * const b, const int64_t c) {
  return Loop< QueryParameters >(queryParameters()[a],
      GreaterThanAfter< int64_t >(b, strlen(b), c));
}

bool TSImplementation::LessThanQueryParameter(
    const char * const a, const int64_t b) {
  return Loop< QueryParameters >(queryParameters()[a], LessThan< int64_t >(b));
}

bool TSImplementation::LessThanAfterQueryParameter(const char * const a,
    const char * const b, const int64_t c) {
  return Loop< QueryParameters >(queryParameters()[a],
      LessThanAfter< int64_t >(b, strlen(b), c));
}

bool TSImplementation::StartsWithQueryParameter(
    const char * const a, const char * const b, const uint32_t c) {
  return Loop< QueryParameters >(queryParameters()[a], StartsWith(b, strlen(b), c));
}

bool TSImplementation::ContainsCookie(
    const char * const a, const char * const b) {
  return Loop< Cookies >(cookies()[a], Contains(b, strlen(b)));
}

bool TSImplementation::EqualCookie(
    const char * const a, const char * const b) {
  return Loop< Cookies >(cookies()[a], Equal(b, strlen(b)));
}

bool TSImplementation::GreaterThanCookie(
    const char * const a, const int64_t b) {
  return Loop< Cookies >(cookies()[a], GreaterThan< int64_t >(b));
}

bool TSImplementation::GreaterThanAfterCookie(const char * const a,
    const char * const b, const int64_t c) {
  return Loop< Cookies >(cookies()[a],
      GreaterThanAfter< int64_t >(b, strlen(b), c));
}

bool TSImplementation::LessThanCookie(
    const char * const a, const int64_t b) {
  return Loop< Cookies >(cookies()[a], LessThan< int64_t >(b));
}

bool TSImplementation::LessThanAfterCookie(const char * const a,
    const char * const b, const int64_t c) {
  return Loop< Cookies >(cookies()[a],
      LessThanAfter< int64_t >(b, strlen(b), c));
}

} //end of filters namespace
} //end of http namespace
<commit_msg>fixing searching into empty string, no point into searching on it<commit_after>/*
 * Copyright (c) 2015, Yahoo Inc. All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

#include <algorithm>
#include <cstring>
#include <sstream>

#include "ts.h"
#include "ts-impl.h"

namespace http {
namespace filters {

struct Contains {
  const char * const p;
  const size_t s;
  Contains(const char * const p, const size_t s) :
    p(p), s(s) {
    ASSERT(p != NULL);
    ASSERT(s <= strlen(p));
  }
  template < class I >
  bool operator () (const I & i) const {
    const char * const begin = i->pointer,
          * const end = begin + i->length;
    return std::search(begin, end, p, p + s) != end;
  }
};

struct Equal {
  const char * const p;
  const size_t s;
  Equal(const char * const p, const size_t s) :
    p(p), s(s) {
    ASSERT(p != NULL);
    ASSERT(s <= strlen(p));
  }
  template < class I >
  bool operator () (const I & i) const {
    return s == i->length && memcmp(p, i->pointer, s) == 0;
  }
};

template < class T >
struct GreaterThan {
  const T t;
  GreaterThan(const T & t) : t(t) { }
  template < class I >
  bool operator () (const I & i) const {
    std::istringstream ss(i->str());
    int64_t c;
    ss >> c;
    return ! ss.fail() && c > t;
  }
};

template < class T >
struct GreaterThanAfter {
  const char * const p;
  const size_t s;
  const T t;
  GreaterThanAfter(const char * const p, const size_t s,
      const T & t) : p(p), s(s), t(t) {
    ASSERT(s <= strlen(p));
  }
  template < class I >
  bool operator () (const I & i) const {
    const char * const begin = i->pointer,
          * const end = begin + i->length,
          * iterator = std::search(begin, end, p, p + s);
    while (iterator != end) {
      iterator += s;
      ASSERT(iterator <= end);
      std::istringstream ss(std::string(iterator, end - iterator));
      int64_t c;
      ss >> c;
      if ( ! ss.fail() && c > t) {
        return true;
      }
      iterator = std::search(iterator, end, p, p + s);
    }
    return false;
  }
};

template < class T >
struct LessThan {
  const T t;
  LessThan(const T & t) : t(t) { }
  template < class I >
  bool operator () (const I & i) const {
    std::istringstream ss(i->str());
    int64_t c;
    ss >> c;
    return ! ss.fail() && c < t;
  }
};

template < class T >
struct LessThanAfter{
  const char * const p;
  const size_t s;
  const T t;
  LessThanAfter(const char * const p, const size_t s,
      const T & t) : p(p), s(s), t(t) {
    ASSERT(s <= strlen(p));
  }
  template < class I >
  bool operator () (const I & i) const {
    const char * const begin = i->pointer,
          * const end = begin + i->length,
          * iterator = std::search(begin, end, p, p + s);
    while (iterator != end) {
      iterator += s;
      ASSERT(iterator <= end);
      std::istringstream ss(std::string(iterator, end - iterator));
      int64_t c;
      ss >> c;
      if ( ! ss.fail() && c < t) {
        return true;
      }
      iterator = std::search(iterator, end, p, p + s);
    }
    return false;
  }
};

struct StartsWith {
  const char * const p;
  const size_t s;
  const size_t o;
  StartsWith(const char * const p, const size_t s, const size_t o) :
    p(p), s(s), o(o) {
    ASSERT(p != NULL);
    ASSERT(s <= strlen(p));
  }
  template < class I >
  bool operator () (const I & i) const {
    const char * const begin = i->pointer,
          * const end = begin + i->length;
    return begin != end
      && std::search(begin, end, p, p + s) == begin + o;
  }
};

template < class T, class U >
bool Loop(const typename T::Result & r, const U & u) {
  typedef typename T::Values::const_iterator Iterator;
  if ( ! r.second) {
    return false;
  }
  ASSERT(r.first != NULL);
  const Iterator end = r.first->end();
  Iterator it = r.first->begin();
  for (; it != end; ++it) {
    ASSERT(it->pointer != NULL);
    ASSERT(it->length > 0);
    if (u(it)) {
      return true;
    }
  }
  return false;
}

bool TSImplementation::ContainsHeader(
    const char * const a, const char * const b) {
  return Loop< Headers >(headers()[a], Contains(b, strlen(b)));
}

bool TSImplementation::EqualHeader(
    const char * const a, const char * const b) {
  return Loop< Headers >(headers()[a], Equal(b, strlen(b)));
}

bool TSImplementation::GreaterThanHeader(
    const char * const a, const int64_t b) {
  return Loop< Headers >(headers()[a], GreaterThan< int64_t >(b));
}

bool TSImplementation::GreaterThanAfterHeader(const char * const a,
    const char * const b, const int64_t c) {
  return Loop< Headers >(headers()[a],
      GreaterThanAfter< int64_t >(b, strlen(b), c));
}

bool TSImplementation::LessThanHeader(
    const char * const a, const int64_t b) {
  return Loop< Headers >(headers()[a], LessThan< int64_t >(b));
}

bool TSImplementation::LessThanAfterHeader(const char * const a,
    const char * const b, const int64_t c) {
  return Loop< Headers >(headers()[a],
      LessThanAfter< int64_t >(b, strlen(b), c));
}

bool TSImplementation::StartsWithHeader(
    const char * const a, const char * const b, const uint32_t c) {
  return Loop< Headers >(headers()[a], StartsWith(b, strlen(b), c));
}

bool TSImplementation::IsScheme(
    const char * const a, const uint32_t b) {
  ASSERT(a != NULL);
  ASSERT(strlen(a) == b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const m = TSUrlSchemeGet(buffer_, url(), &l);
  return b == static_cast< uint32_t >(l) && memcmp(m, a, b) == 0;
}

bool TSImplementation::IsMethod(
    const char * const a, const uint32_t b) const {
  ASSERT(a != NULL);
  ASSERT(strlen(a) == b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const m = TSHttpHdrMethodGet(buffer_, location_, &l);
  return b == static_cast< uint32_t >(l) && memcmp(m, a, b) == 0;
}

bool TSImplementation::ContainsDomain(
    const char * const a, const uint32_t b) {
  ASSERT(a != NULL);
  ASSERT(strlen(a) >= b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const begin = TSUrlHostGet(buffer_, url(), &l),
        * const end = begin + l;
  return std::search(begin, end, a, a + b) != end;
}

bool TSImplementation::EqualDomain(
    const char * const a, const uint32_t b) {
  ASSERT(a != NULL);
  ASSERT(strlen(a) >= b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const m = TSUrlHostGet(buffer_, url(), &l);
  return b == static_cast< uint32_t >(l) && memcmp(m, a, b) == 0;
}

bool TSImplementation::StartsWithDomain(
    const char * const a, const uint32_t b, const uint32_t c) {
  ASSERT(a != NULL);
  ASSERT(strlen(a) >= b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const begin = TSUrlHostGet(buffer_, url(), &l),
        * const end = begin + l;
  return begin != end
    && std::search(begin, end, a, a + b) == begin + c;
}

bool TSImplementation::ContainsPath(
    const char * const a, const uint32_t b) {
  ASSERT(a != NULL);
  ASSERT(strlen(a) >= b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const begin = TSUrlPathGet(buffer_, url(), &l),
        * const end = begin + l;
  return std::search(begin, end, a, a + b) != end;
}

bool TSImplementation::EqualPath(
    const char * const a, const uint32_t b) {
  ASSERT(a != NULL);
  ASSERT(strlen(a) >= b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const m = TSUrlPathGet(buffer_, url(), &l);
  return b == static_cast< uint32_t >(l) && memcmp(m, a, b) == 0;
}

bool TSImplementation::StartsWithPath(
    const char * const a, const uint32_t b, const uint32_t c) {
  ASSERT(a != NULL);
  ASSERT(strlen(a) >= b);
  ASSERT(buffer_ != NULL);
  ASSERT(location_ != NULL);
  int l = 0;
  const char * const begin = TSUrlPathGet(buffer_, url(), &l),
        * const end = begin + l;
  return begin != end
    && std::search(begin, end, a, a + b) == begin + c;
}

bool TSImplementation::ContainsQueryParameter(
    const char * const a, const char * const b) {
  return Loop< QueryParameters >(queryParameters()[a], Contains(b, strlen(b)));
}

bool TSImplementation::EqualQueryParameter(
    const char * const a, const char * const b) {
  return Loop< QueryParameters >(queryParameters()[a], Equal(b, strlen(b)));
}

bool TSImplementation::GreaterThanQueryParameter(
    const char * const a, const int64_t b) {
  return Loop< QueryParameters >(queryParameters()[a], GreaterThan< int64_t >(b));
}

bool TSImplementation::GreaterThanAfterQueryParameter(const char * const a,
    const char * const b, const int64_t c) {
  return Loop< QueryParameters >(queryParameters()[a],
      GreaterThanAfter< int64_t >(b, strlen(b), c));
}

bool TSImplementation::LessThanQueryParameter(
    const char * const a, const int64_t b) {
  return Loop< QueryParameters >(queryParameters()[a], LessThan< int64_t >(b));
}

bool TSImplementation::LessThanAfterQueryParameter(const char * const a,
    const char * const b, const int64_t c) {
  return Loop< QueryParameters >(queryParameters()[a],
      LessThanAfter< int64_t >(b, strlen(b), c));
}

bool TSImplementation::StartsWithQueryParameter(
    const char * const a, const char * const b, const uint32_t c) {
  return Loop< QueryParameters >(queryParameters()[a], StartsWith(b, strlen(b), c));
}

bool TSImplementation::ContainsCookie(
    const char * const a, const char * const b) {
  return Loop< Cookies >(cookies()[a], Contains(b, strlen(b)));
}

bool TSImplementation::EqualCookie(
    const char * const a, const char * const b) {
  return Loop< Cookies >(cookies()[a], Equal(b, strlen(b)));
}

bool TSImplementation::GreaterThanCookie(
    const char * const a, const int64_t b) {
  return Loop< Cookies >(cookies()[a], GreaterThan< int64_t >(b));
}

bool TSImplementation::GreaterThanAfterCookie(const char * const a,
    const char * const b, const int64_t c) {
  return Loop< Cookies >(cookies()[a],
      GreaterThanAfter< int64_t >(b, strlen(b), c));
}

bool TSImplementation::LessThanCookie(
    const char * const a, const int64_t b) {
  return Loop< Cookies >(cookies()[a], LessThan< int64_t >(b));
}

bool TSImplementation::LessThanAfterCookie(const char * const a,
    const char * const b, const int64_t c) {
  return Loop< Cookies >(cookies()[a],
      LessThanAfter< int64_t >(b, strlen(b), c));
}

} //end of filters namespace
} //end of http namespace
<|endoftext|>


<commit_before>/*
  Copyright (c) 2013 Matthew Stump

  This file is part of libprz.

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

  libprz 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 Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <boost/bind.hpp>
#include <stdint.h>
#include <boost/lexical_cast.hpp>

#include "encode.hpp"
#include "index_reader.hpp"
#include "index_writer.hpp"

#include "index_slice.hpp"

inline void
get_address(prz::index_address_t    position,
            prz::index_address_t*   bucket,
            prz::index_partition_t* bucket_index,
            prz::index_partition_t* bit_offset)
{
    *bucket = position >> 8; // div by 256
    prz::index_partition_t bucket_offset = position & 0xFF; // mod by 256
    *bucket_index = bucket_offset >> 6; // div by 64
    *bit_offset = bucket_offset & 0x3F; // mod by 64
}

inline void
set_bit(prz::index_segment_ptr input,
        prz::index_partition_t bucket_index,
        prz::index_partition_t bit_offset,
        bool                   val)
{
    input[bucket_index] |= (val ? 1 : 0) << bit_offset;
}

inline void
segment_union(prz::index_segment_ptr a,
              prz::index_segment_ptr b,
              prz::index_segment_ptr o)
{
    for (int i = 0; i < PRZ_INDEX_SEGMENT_LENGTH; ++i) {
        o[i] = a[i] | b[i];
    }
}

inline void
segment_intersection(prz::index_segment_ptr a,
                     prz::index_segment_ptr b,
                     prz::index_segment_ptr o)
{
    for (int i = 0; i < PRZ_INDEX_SEGMENT_LENGTH; ++i) {
        o[i] = a[i] & b[i];
    }
}

inline prz::index_slice_t::iterator
find_insertion_point(prz::index_slice_t::iterator begin,
                     prz::index_slice_t::iterator end,
                     prz::index_address_t   bucket)
{
    return std::find_if(begin,
                        end,
                        boost::bind(&prz::index_slice_t::index_node_t::offset, _1 ) >= bucket);
}

inline prz::index_slice_t::iterator
get_output_node(prz::index_slice_t&          output,
                prz::index_slice_t::iterator output_iter,
                prz::index_address_t   offset)
{
    output_iter = find_insertion_point(output_iter, output.end(), offset);
    if (output_iter == output.end()) {
        return output.insert(output_iter, new prz::index_slice_t::index_node_t(offset));
    }
    return output_iter;
}

inline prz::status_t
union_behavior(prz::index_slice_t& a_index,
               prz::index_slice_t& b_index,
               prz::index_slice_t& output)
{

    prz::index_slice_t::iterator a_iter = a_index.begin();
    prz::index_slice_t::iterator b_iter = b_index.begin();
    prz::index_slice_t::iterator output_iter = output.begin();

    for (;;) {
        if (a_iter == a_index.end() && b_iter == b_index.end()) {
            break;
        }
        else if (a_iter == a_index.end()) {
            if (&output == &b_index) {
                break;
            }
            output_iter = get_output_node(output, output_iter, b_iter->offset);
            memcpy(output_iter->segment, b_iter->segment, PRZ_INDEX_SEGMENT_SIZE);
            ++b_iter;
        }
        else if (a_iter->offset < b_iter->offset) {
            output_iter = get_output_node(output, output_iter, a_iter->offset);
            memcpy(output_iter->segment, a_iter->segment, PRZ_INDEX_SEGMENT_SIZE);
            ++a_iter;
        }
        else if (a_iter->offset > b_iter->offset) {
            output_iter = get_output_node(output, output_iter, b_iter->offset);
            memcpy(output_iter->segment, b_iter->segment, PRZ_INDEX_SEGMENT_SIZE);
            ++b_iter;
        }
        else if (a_iter->offset == b_iter->offset) {
            output_iter = get_output_node(output, output_iter, b_iter->offset);
            segment_union(a_iter->segment, b_iter->segment, output_iter->segment);
            ++a_iter;
            ++b_iter;
        }
        else {
            return prz::status_t(PRZ_ERROR_INDEX_OPERATION,
                                "shit's gone crazy in index union: "
                                + boost::lexical_cast<std::string>(a_iter->offset)
                                + ":" + boost::lexical_cast<std::string>(b_iter->offset)
                                + ":" + boost::lexical_cast<std::string>(output_iter->offset));
        }
    }
    return prz::status_t();
}

inline prz::status_t
intersection_behavior(prz::index_slice_t& a_index,
                      prz::index_slice_t& b_index,
                      prz::index_slice_t& output)
{
    prz::index_slice_t::iterator a_iter = a_index.begin();
    prz::index_slice_t::iterator b_iter = b_index.begin();
    prz::index_slice_t::iterator output_iter = output.begin();

    for (;;) {
        if (b_iter == b_index.end() || a_iter == a_index.end()) {
            output.erase(output_iter, output.end());
            break;
        }
        else if (a_iter->offset < b_iter->offset) {
            ++a_iter;
        }
        else if (a_iter->offset > b_iter->offset) {
            ++b_iter;
        }
        else if (a_iter->offset == b_iter->offset) {
            prz::index_slice_t::iterator new_output_iter = get_output_node(output, output_iter, b_iter->offset);
            if (output_iter != output.end() && new_output_iter != output_iter) {
                output.erase(output_iter, new_output_iter);
            }
            output_iter = new_output_iter;
            segment_intersection(a_iter->segment, b_iter->segment, output_iter->segment);
            ++a_iter;
            ++b_iter;
            ++output_iter;
        }
        else {
            return prz::status_t(PRZ_ERROR_INDEX_OPERATION,
                                "shit's gone crazy in index intersection: "
                                + boost::lexical_cast<std::string>(a_iter->offset)
                                + ":" + boost::lexical_cast<std::string>(b_iter->offset)
                                + ":" + boost::lexical_cast<std::string>(output_iter->offset));
        }
    }
    return prz::status_t();
}

prz::index_slice_t::index_node_t::index_node_t(const index_node_t& node) :
    offset(node.offset)
{
    memcpy(segment, node.segment, PRZ_INDEX_SEGMENT_SIZE);
}

prz::index_slice_t::index_node_t::index_node_t(prz::index_address_t offset) :
    offset(offset)
{}

prz::index_slice_t::index_node_t::index_node_t(prz::index_address_t offset,
                                         const index_segment_ptr data) :
    offset(offset)
{
    memcpy(segment, data, PRZ_INDEX_SEGMENT_SIZE);
}

void
prz::index_slice_t::index_node_t::zero()
{
    memset(segment, 0, PRZ_INDEX_SEGMENT_SIZE);
}

prz::index_slice_t::index_slice_t(prz::index_partition_t partition,
                      const char*            field,
                      size_t                 field_size,
                      prz::index_address_t   value) :
    _partition(partition),
    _field(field, field + field_size),
    _value(value)
{}

prz::index_slice_t::index_slice_t(prz::index_partition_t partition,
                      const prz::byte_t*     field,
                      size_t                 field_size,
                      prz::index_address_t   value) :
    _partition(partition),
    _field(field, field + field_size),
    _value(value)
{}

prz::status_t
prz::index_slice_t::execute(index_operation_enum operation,
                      prz::index_slice_t&        a_index,
                      prz::index_slice_t&        b_index,
                      prz::index_slice_t&        output)
{
    if (operation == PRZ_INDEX_OP_INTERSECTION) {
        return intersection_behavior(a_index, b_index, output);
    }
    else if (operation == PRZ_INDEX_OP_UNION) {
        return union_behavior(a_index, b_index, output);
    }
    return prz::status_t(PRZ_ERROR_INDEX_OPERATION, "unkown/unsupported index operation");
}

prz::status_t
prz::index_slice_t::execute(prz::index_operation_enum operation,
                      prz::index_reader_t*      reader,
                      prz::index_partition_t    partition,
                      const prz::byte_t*        field,
                      size_t                    field_size,
                      prz::index_address_t      value,
                      prz::index_slice_t&             output)
{
    prz::status_t status = reader->read_index_slice(partition, field, field_size, value, &output);
    if (status) {
        status = execute(operation, *this, output, output);
    }
    return status;
}

prz::status_t
prz::index_slice_t::execute(prz::index_operation_enum operation,
                      prz::index_reader_t*      reader,
                      prz::index_partition_t    partition,
                      const prz::byte_t*        field,
                      size_t                    field_size,
                      prz::index_address_t      value)
{
    prz::index_slice_t other_index(partition, field, field_size, value);
    prz::status_t status = reader->read_index_slice(partition, field, field_size, value, &other_index);
    if (status) {
        status = execute(operation, *this, other_index, *this);
    }
    return status;
}

prz::status_t
prz::index_slice_t::bit(prz::index_reader_t* reader,
                  prz::index_writer_t* writer,
                  prz::index_address_t bit,
                  bool                 state)
{
    prz::index_address_t   offset       = 0;
    prz::index_partition_t offset_index = 0;
    prz::index_partition_t bit_offset   = 0;
    get_address(bit, &offset, &offset_index, &bit_offset);

    prz::index_slice_t::iterator it = find_insertion_point(begin(), end(), offset);

    prz::status_t status;
    if (it->offset != offset) {
        it = prz::index_slice_t::iterator(_index.insert(it.base(), new index_node_t(offset)));
        status = reader->read_segment(_partition, &_field[0], _field.size(), _value, offset, it->segment);
    }

    if (status) {
        set_bit(it->segment, offset_index, bit_offset, state);
        status = writer->write_segment(_partition, &_field[0], _field.size(), _value, offset, it->segment);
    }
    return status;
}

bool
prz::index_slice_t::bit(index_address_t      bit)
{
    prz::index_address_t        bucket       = 0;
    prz::index_partition_t      bucket_index = 0;
    prz::index_partition_t      bit_offset   = 0;
    get_address(bit, &bucket, &bucket_index, &bit_offset);

    prz::index_slice_t::iterator it = find_insertion_point(begin(), end(), bucket);

    if (it->offset != bucket) {
        return false;
    }
    return (it->segment[bucket_index] & 1 << bit_offset);
}

prz::index_partition_t
prz::index_slice_t::partition() const
{
    return _partition;
}

const prz::byte_t*
prz::index_slice_t::field() const
{
    return &_field[0];
}

prz::index_address_t
prz::index_slice_t::value() const
{
    return _value;
}
<commit_msg>fixed formatting in index_slice.cpp<commit_after>/*
  Copyright (c) 2013 Matthew Stump

  This file is part of libprz.

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

  libprz 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 Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <boost/bind.hpp>
#include <stdint.h>
#include <boost/lexical_cast.hpp>

#include "encode.hpp"
#include "index_reader.hpp"
#include "index_writer.hpp"

#include "index_slice.hpp"

inline void
get_address(prz::index_address_t    position,
            prz::index_address_t*   bucket,
            prz::index_partition_t* bucket_index,
            prz::index_partition_t* bit_offset)
{
    *bucket = position >> 8; // div by 256
    prz::index_partition_t bucket_offset = position & 0xFF; // mod by 256
    *bucket_index = bucket_offset >> 6; // div by 64
    *bit_offset = bucket_offset & 0x3F; // mod by 64
}

inline void
set_bit(prz::index_segment_ptr input,
        prz::index_partition_t bucket_index,
        prz::index_partition_t bit_offset,
        bool                   val)
{
    input[bucket_index] |= (val ? 1 : 0) << bit_offset;
}

inline void
segment_union(prz::index_segment_ptr a,
              prz::index_segment_ptr b,
              prz::index_segment_ptr o)
{
    for (int i = 0; i < PRZ_INDEX_SEGMENT_LENGTH; ++i) {
        o[i] = a[i] | b[i];
    }
}

inline void
segment_intersection(prz::index_segment_ptr a,
                     prz::index_segment_ptr b,
                     prz::index_segment_ptr o)
{
    for (int i = 0; i < PRZ_INDEX_SEGMENT_LENGTH; ++i) {
        o[i] = a[i] & b[i];
    }
}

inline prz::index_slice_t::iterator
find_insertion_point(prz::index_slice_t::iterator begin,
                     prz::index_slice_t::iterator end,
                     prz::index_address_t         bucket)
{
    return std::find_if(begin,
                        end,
                        boost::bind(&prz::index_slice_t::index_node_t::offset, _1 ) >= bucket);
}

inline prz::index_slice_t::iterator
get_output_node(prz::index_slice_t&          output,
                prz::index_slice_t::iterator output_iter,
                prz::index_address_t         offset)
{
    output_iter = find_insertion_point(output_iter, output.end(), offset);
    if (output_iter == output.end()) {
        return output.insert(output_iter, new prz::index_slice_t::index_node_t(offset));
    }
    return output_iter;
}

inline prz::status_t
union_behavior(prz::index_slice_t& a_index,
               prz::index_slice_t& b_index,
               prz::index_slice_t& output)
{

    prz::index_slice_t::iterator a_iter = a_index.begin();
    prz::index_slice_t::iterator b_iter = b_index.begin();
    prz::index_slice_t::iterator output_iter = output.begin();

    for (;;) {
        if (a_iter == a_index.end() && b_iter == b_index.end()) {
            break;
        }
        else if (a_iter == a_index.end()) {
            if (&output == &b_index) {
                break;
            }
            output_iter = get_output_node(output, output_iter, b_iter->offset);
            memcpy(output_iter->segment, b_iter->segment, PRZ_INDEX_SEGMENT_SIZE);
            ++b_iter;
        }
        else if (a_iter->offset < b_iter->offset) {
            output_iter = get_output_node(output, output_iter, a_iter->offset);
            memcpy(output_iter->segment, a_iter->segment, PRZ_INDEX_SEGMENT_SIZE);
            ++a_iter;
        }
        else if (a_iter->offset > b_iter->offset) {
            output_iter = get_output_node(output, output_iter, b_iter->offset);
            memcpy(output_iter->segment, b_iter->segment, PRZ_INDEX_SEGMENT_SIZE);
            ++b_iter;
        }
        else if (a_iter->offset == b_iter->offset) {
            output_iter = get_output_node(output, output_iter, b_iter->offset);
            segment_union(a_iter->segment, b_iter->segment, output_iter->segment);
            ++a_iter;
            ++b_iter;
        }
        else {
            return prz::status_t(PRZ_ERROR_INDEX_OPERATION,
                                 "shit's gone crazy in index union: "
                                 + boost::lexical_cast<std::string>(a_iter->offset)
                                 + ":" + boost::lexical_cast<std::string>(b_iter->offset)
                                 + ":" + boost::lexical_cast<std::string>(output_iter->offset));
        }
    }
    return prz::status_t();
}

inline prz::status_t
intersection_behavior(prz::index_slice_t& a_index,
                      prz::index_slice_t& b_index,
                      prz::index_slice_t& output)
{
    prz::index_slice_t::iterator a_iter = a_index.begin();
    prz::index_slice_t::iterator b_iter = b_index.begin();
    prz::index_slice_t::iterator output_iter = output.begin();

    for (;;) {
        if (b_iter == b_index.end() || a_iter == a_index.end()) {
            output.erase(output_iter, output.end());
            break;
        }
        else if (a_iter->offset < b_iter->offset) {
            ++a_iter;
        }
        else if (a_iter->offset > b_iter->offset) {
            ++b_iter;
        }
        else if (a_iter->offset == b_iter->offset) {
            prz::index_slice_t::iterator new_output_iter = get_output_node(output, output_iter, b_iter->offset);
            if (output_iter != output.end() && new_output_iter != output_iter) {
                output.erase(output_iter, new_output_iter);
            }
            output_iter = new_output_iter;
            segment_intersection(a_iter->segment, b_iter->segment, output_iter->segment);
            ++a_iter;
            ++b_iter;
            ++output_iter;
        }
        else {
            return prz::status_t(PRZ_ERROR_INDEX_OPERATION,
                                 "shit's gone crazy in index intersection: "
                                 + boost::lexical_cast<std::string>(a_iter->offset)
                                 + ":" + boost::lexical_cast<std::string>(b_iter->offset)
                                 + ":" + boost::lexical_cast<std::string>(output_iter->offset));
        }
    }
    return prz::status_t();
}

prz::index_slice_t::index_node_t::index_node_t(const index_node_t& node) :
    offset(node.offset)
{
    memcpy(segment, node.segment, PRZ_INDEX_SEGMENT_SIZE);
}

prz::index_slice_t::index_node_t::index_node_t(prz::index_address_t offset) :
    offset(offset)
{}

prz::index_slice_t::index_node_t::index_node_t(prz::index_address_t offset,
                                               const index_segment_ptr data) :
    offset(offset)
{
    memcpy(segment, data, PRZ_INDEX_SEGMENT_SIZE);
}

void
prz::index_slice_t::index_node_t::zero()
{
    memset(segment, 0, PRZ_INDEX_SEGMENT_SIZE);
}

prz::index_slice_t::index_slice_t(prz::index_partition_t partition,
                                  const char*            field,
                                  size_t                 field_size,
                                  prz::index_address_t   value) :
    _partition(partition),
    _field(field, field + field_size),
    _value(value)
{}

prz::index_slice_t::index_slice_t(prz::index_partition_t partition,
                                  const prz::byte_t*     field,
                                  size_t                 field_size,
                                  prz::index_address_t   value) :
    _partition(partition),
    _field(field, field + field_size),
    _value(value)
{}

prz::status_t
prz::index_slice_t::execute(index_operation_enum operation,
                            prz::index_slice_t&  a_index,
                            prz::index_slice_t&  b_index,
                            prz::index_slice_t&  output)
{
    if (operation == PRZ_INDEX_OP_INTERSECTION) {
        return intersection_behavior(a_index, b_index, output);
    }
    else if (operation == PRZ_INDEX_OP_UNION) {
        return union_behavior(a_index, b_index, output);
    }
    return prz::status_t(PRZ_ERROR_INDEX_OPERATION, "unkown/unsupported index operation");
}

prz::status_t
prz::index_slice_t::execute(prz::index_operation_enum operation,
                            prz::index_reader_t*      reader,
                            prz::index_partition_t    partition,
                            const prz::byte_t*        field,
                            size_t                    field_size,
                            prz::index_address_t      value,
                            prz::index_slice_t&       output)
{
    prz::status_t status = reader->read_index_slice(partition, field, field_size, value, &output);
    if (status) {
        status = execute(operation, *this, output, output);
    }
    return status;
}

prz::status_t
prz::index_slice_t::execute(prz::index_operation_enum operation,
                            prz::index_reader_t*      reader,
                            prz::index_partition_t    partition,
                            const prz::byte_t*        field,
                            size_t                    field_size,
                            prz::index_address_t      value)
{
    prz::index_slice_t other_index(partition, field, field_size, value);
    prz::status_t status = reader->read_index_slice(partition, field, field_size, value, &other_index);
    if (status) {
        status = execute(operation, *this, other_index, *this);
    }
    return status;
}

prz::status_t
prz::index_slice_t::bit(prz::index_reader_t* reader,
                        prz::index_writer_t* writer,
                        prz::index_address_t bit,
                        bool                 state)
{
    prz::index_address_t   offset       = 0;
    prz::index_partition_t offset_index = 0;
    prz::index_partition_t bit_offset   = 0;
    get_address(bit, &offset, &offset_index, &bit_offset);

    prz::index_slice_t::iterator it = find_insertion_point(begin(), end(), offset);

    prz::status_t status;
    if (it->offset != offset) {
        it = prz::index_slice_t::iterator(_index.insert(it.base(), new index_node_t(offset)));
        status = reader->read_segment(_partition, &_field[0], _field.size(), _value, offset, it->segment);
    }

    if (status) {
        set_bit(it->segment, offset_index, bit_offset, state);
        status = writer->write_segment(_partition, &_field[0], _field.size(), _value, offset, it->segment);
    }
    return status;
}

bool
prz::index_slice_t::bit(index_address_t      bit)
{
    prz::index_address_t        bucket       = 0;
    prz::index_partition_t      bucket_index = 0;
    prz::index_partition_t      bit_offset   = 0;
    get_address(bit, &bucket, &bucket_index, &bit_offset);

    prz::index_slice_t::iterator it = find_insertion_point(begin(), end(), bucket);

    if (it->offset != bucket) {
        return false;
    }
    return (it->segment[bucket_index] & 1 << bit_offset);
}

prz::index_partition_t
prz::index_slice_t::partition() const
{
    return _partition;
}

const prz::byte_t*
prz::index_slice_t::field() const
{
    return &_field[0];
}

prz::index_address_t
prz::index_slice_t::value() const
{
    return _value;
}
<|endoftext|>