<commit_before>#include <protobuf/LogFrame.pb.h>
#include "InterpolatedPath.hpp"
#include "Utils.hpp"
#include "LogUtils.hpp"
#include <stdexcept>

using namespace std;
using namespace Planning;
using namespace Geometry2d;

#pragma mark InterpolatedPath

Planning::InterpolatedPath::InterpolatedPath(const Geometry2d::Point& p0) {
	points.push_back(p0);
}

Planning::InterpolatedPath::InterpolatedPath(const Geometry2d::Point& p0, const Geometry2d::Point& p1) {
	points.push_back(p0);
	points.push_back(p1);
}

float Planning::InterpolatedPath::length(unsigned int start) const
{
    if (points.empty() || start >= (points.size() - 1))
    {
        return 0;
    }

    float length  = 0;
    for (unsigned int i = start; i < (points.size() - 1); ++i)
    {
        length += (points[i + 1] - points[i]).mag();
    }
    return length;
}

float Planning::InterpolatedPath::length(unsigned int start, unsigned int end) const
{
    if (points.empty() || start >= (points.size() - 1))
    {
        return 0;
    }

    float length  = 0;
    for (unsigned int i = start; i < end; ++i)
    {
        length += (points[i + 1] - points[i]).mag();
    }
    return length;
}

boost::optional<Geometry2d::Point> Planning::InterpolatedPath::start() const
{
		if (points.empty())
			return boost::none;
		else
			return points.front();
}

boost::optional<Geometry2d::Point> Planning::InterpolatedPath::destination() const
{
		if (points.empty())
			return boost::none;
		else
			return points.back();
}

// Returns the index of the point in this path nearest to pt.
int Planning::InterpolatedPath::nearestIndex(const Geometry2d::Point &pt) const
{
	if (points.size() == 0)
	{
		return -1;
	}

	int index = 0;
	float dist = pt.distTo(points[0]);

	for (unsigned int i=1 ; i<points.size(); ++i)
	{
		float d = pt.distTo(points[i]);
		if (d < dist)
		{
			dist = d;
			index = i;
		}
	}

	return index;
}

bool Planning::InterpolatedPath::hit(const Geometry2d::CompositeShape &obstacles, float startTime) const
{
	int start=0;
	for(float t: times) {
		start++;
		if(t>startTime) {
			start--;
			break;
		}
	}

    if (start >= points.size())
    {
        // Empty path or starting beyond end of path
        return false;
    }

    // The set of obstacles the starting point was inside of
    std::set<std::shared_ptr<Geometry2d::Shape> > hit;
    obstacles.hit(points[start], hit);

    for (unsigned int i = start; i < (points.size() - 1); ++i)
    {
        std::set<std::shared_ptr<Geometry2d::Shape> > newHit;
        obstacles.hit(Geometry2d::Segment(points[i], points[i + 1]), newHit);
        try
        {
            set_difference(newHit.begin(), newHit.end(), hit.begin(), hit.end(), ExceptionIterator<std::shared_ptr<Geometry2d::Shape>>());
        } catch (exception& e)
        {
            // Going into a new obstacle
            return true;
        }
    }

    // Didn't hit anything or never left any obstacle
    return obstacles.hit(points.back());
}

float Planning::InterpolatedPath::distanceTo(const Geometry2d::Point &pt) const
{
    int i = nearestIndex(pt);
    if (i < 0)
    {
        return 0;
    }

    float dist = -1;
    for (unsigned int i = 0; i < (points.size() - 1); ++i)
	{
		Geometry2d::Segment s(points[i], points[i+1]);
		const float d = s.distTo(pt);

		if (dist < 0 || d < dist)
		{
			dist = d;
		}
	}

    return dist;
}

Geometry2d::Segment Planning::InterpolatedPath::nearestSegment(const Geometry2d::Point &pt) const
{
	Geometry2d::Segment best;
	float dist = -1;
	if (points.empty())
	{
		return best;
	}

	for (unsigned int i = 0; i < (points.size() - 1); ++i)
    {
		Geometry2d::Segment s(points[i], points[i+1]);
		const float d = s.distTo(pt);

		if (dist < 0 || d < dist)
		{
			best = s;
			dist = d;
		}
	}

	return best;
}

void Planning::InterpolatedPath::startFrom(const Geometry2d::Point& pt, Planning::InterpolatedPath& result) const {

	// path will start at the current robot pose
	result.clear();
	result.points.push_back(pt);

	if (points.empty())
		return;

	// handle simple paths
	if (points.size() == 1) {
		result.points.push_back(points.front());
		return;
	}

	// find where to start the path
	Geometry2d::Segment close_segment;
	float dist = -1;
	unsigned int i = (points.front().nearPoint(pt, 0.02)) ? 1 : 0;
	vector<Geometry2d::Point>::const_iterator path_start = ++points.begin();
	for (; i < (points.size() - 1); ++i)
	{
		Geometry2d::Segment s(points[i], points[i+1]);
		const float d = s.distTo(pt);
		if (dist < 0 || d < dist)
		{
			close_segment = s;
			dist = d;
		}
	}

	// slice path
	// new path will be pt, [closest point on nearest segment], [i+1 to end]
	if (dist > 0.0 && dist < 0.02) {
		Geometry2d::Point intersection_pt = close_segment.nearestPoint(pt);
		result.points.push_back(intersection_pt);
	}

	result.points.insert(result.points.end(), path_start, points.end());

}

float Planning::InterpolatedPath::length(const Geometry2d::Point &pt) const
{
	float dist = -1;
	float length = 0;
	if (points.empty())
	{
		return 0;
	}

	for (unsigned int i = 0; i < (points.size() - 1); ++i)
    {
		Geometry2d::Segment s(points[i], points[i+1]);

		//add the segment length
		length += s.length();

		const float d = s.distTo(pt);

		//if point closer to this segment
		if (dist < 0 || d < dist)
		{
			//closest point on segment
			Geometry2d::Point p = s.nearestPoint(pt);

			//new best distance
			dist = d;

			//reset running length count
			length = 0;
			length += p.distTo(s.pt[1]);
		}
	}

	return length;
}

bool Planning::InterpolatedPath::getPoint(float distance ,Geometry2d::Point &position, Geometry2d::Point &direction) const
{
	if (distance<=0) {
		position = points.front();
		return false;
	}
	if (points.empty())
	{
		return false;
	}
	for (unsigned int i = 0; i < (points.size() - 1); ++i)
    {
    	Geometry2d::Point vector(points[i + 1] - points[i]);
		//Geometry2d::Segment s(points[i], points[i+1]);

		float vectorLength = vector.mag();
		distance -= vectorLength;

		if(distance<=0)
		{
			distance += vectorLength;
			position = points[i] + (vector * (distance / vectorLength));
			direction = vector.normalized();
			return true;
		}
	}
	position = points.back();
	return false;

}
void Planning::InterpolatedPath::draw(SystemState * const state, const QColor &col = Qt::black, const QString &layer = "Motion") const {
	Packet::DebugPath *dbg = state->logFrame->add_debug_paths();
	dbg->set_layer(state->findDebugLayer(layer));
	for (Geometry2d::Point pt : points)
	{
		*dbg->add_points() = pt;
	}
	dbg->set_color(color(col));
	return;
}

bool Planning::InterpolatedPath::evaluate(float t, Geometry2d::Point &targetPosOut, Geometry2d::Point &targetVelOut) const
{
    /*
	float linearPos;
	float linearSpeed;
	bool pathIsValid = TrapezoidalMotion(
        length(),
        maxSpeed,
        maxAcceleration,
        t,
        startSpeed,
        endSpeed,
        linearPos,      //  these are set by reference since C++ can't return multiple values
        linearSpeed);   //

	Geometry2d::Point direction;
	if(!getPoint(linearPos, targetPosOut, direction)) {
		return false;
	}

	targetVelOut = direction * linearSpeed;
	*/
	if (times.size()==0) {
		targetPosOut = Geometry2d::Point(0,0);
		targetVelOut = Geometry2d::Point(0,0);
		return false;
	}
	if (times.size()==1) {
		targetPosOut = points[0];
		targetVelOut = Geometry2d::Point(0,0);
		return false;
	}
	if (t<times[0])
	{
		targetPosOut = points[0];
		targetVelOut = vels[0];
		return false;
	}

    int i=0;
	while (times[i]<=t)
	{
		if (times[i]==t) {
			targetPosOut = points[i];
			targetVelOut = vels[i];
			return true;
		}
		i++;
		if (i==size())
		{
			targetPosOut = points[i-1];
			targetVelOut = vels[i-1];
			return false;
		}
	}
	float deltaT = (times[i] - times[i-1]);
	if (deltaT==0)
	{
		targetPosOut = points[i];
		targetVelOut = vels[i];
		return true;
	}
	float constant = (t-times[i-1])/deltaT;

	targetPosOut = points[i-1]*(1-constant) + points[i]*(constant);
	targetVelOut = vels[i-1]*(1-constant) + vels[i]*(constant);

	return true;
}

size_t Planning::InterpolatedPath::size() const
{
	 return points.size();
}

bool Planning::InterpolatedPath::valid() const
{
	return !points.empty();
}

float Planning::InterpolatedPath::getTime(int index) const
{
	return times[index];
}

float Planning::InterpolatedPath::getDuration() const
{
	if (times.size()>0) {
		return times.back();
	} else {
		return 0;
	}
}

unique_ptr<Path> Planning::InterpolatedPath::subPath(float startTime, float endTime) const
{
	//Check for valid arguments
	if (startTime<0) {
		throw invalid_argument("InterpolatedPath::subPath(): startTime(" + to_string(startTime) + ") can't be less than zero");
	}

	if (endTime<0) {
		throw invalid_argument("InterpolatedPath::subPath(): endTime(" + to_string(endTime) + ") can't be less than zero");
	}

	if (startTime > endTime) {
		throw invalid_argument("InterpolatedPath::subPath(): startTime(" + to_string(startTime) + ") can't be after endTime(" + to_string(endTime) + ")");
	}

	if (startTime >= getDuration()) {
		debugThrow(invalid_argument("InterpolatedPath::subPath(): startTime(" + to_string(startTime) + ") can't be greater than the duration(" + to_string(getDuration()) + ") of the path"));
		return unique_ptr<Path>(new InterpolatedPath());
	}

	if (startTime == 0 && endTime>=getDuration()) {
		return this->clone();
	}

	InterpolatedPath *path = new InterpolatedPath();

	//Bound the endTime to a reasonable time.
	endTime = min(endTime, getDuration());

	//Find the first point in the vector of points which will be included in the subPath
	size_t start = 0;
	while(times[start]<=startTime) {
		start++;
	}
	start--;

	//Add the first points to the InterpolatedPath
	path->times.push_back(0);
	if (times[start]==startTime) {
		path->points.push_back(points[start]);
		path->vels.push_back(vels[start]);
	} else {
		float deltaT = (times[start+1] - times[start]);
		float constant = (times[start+1]-startTime)/deltaT;
		Point startPos = points[start+1]*(1-constant) + points[start]*(constant);
		Point vi = vels[start+1]*(1-constant) + vels[start]*(constant);
		path->points.push_back(startPos);
		path->vels.push_back(vi);
	}

	//Find the last point in the InterpolatedPath
	Point vf;
	Point endPos;
	size_t end;
	if (endTime >= getDuration()) {
		end = size()-1;
		vf = vels[end];
		endPos = points[end];
	} else {
		end = start + 1;
		while (times[end]<endTime) {
			end++;
		}
		float deltaT = (times[end] - times[end-1]);
		float constant = (times[end] - endTime)/deltaT;
		//endTime = times[end];
		vf = vels[end]*(1-constant) + vels[end-1]*(constant);
		endPos = points[end]*(1-constant) + points[end-1]*(constant);
	}

	//Add all the points in the middle
	size_t i=start + 1;
	while (i<end) {
		path->points.push_back(points[i]);
		path->vels.push_back(vels[i]);
		path->times.push_back(times[i]-startTime);
		i++;
	}

	//Add the last point
	path->points.push_back(endPos);
	path->vels.push_back(vf);
	path->times.push_back(endTime - startTime);

	return unique_ptr<Path>(path);

}

unique_ptr<Path> Planning::InterpolatedPath::clone() const {
	return unique_ptr<Path>(new InterpolatedPath(*this));
}<commit_msg>Remove a commented line of code<commit_after>#include <protobuf/LogFrame.pb.h>
#include "InterpolatedPath.hpp"
#include "Utils.hpp"
#include "LogUtils.hpp"
#include <stdexcept>

using namespace std;
using namespace Planning;
using namespace Geometry2d;

#pragma mark InterpolatedPath

Planning::InterpolatedPath::InterpolatedPath(const Geometry2d::Point& p0) {
	points.push_back(p0);
}

Planning::InterpolatedPath::InterpolatedPath(const Geometry2d::Point& p0, const Geometry2d::Point& p1) {
	points.push_back(p0);
	points.push_back(p1);
}

float Planning::InterpolatedPath::length(unsigned int start) const
{
    if (points.empty() || start >= (points.size() - 1))
    {
        return 0;
    }

    float length  = 0;
    for (unsigned int i = start; i < (points.size() - 1); ++i)
    {
        length += (points[i + 1] - points[i]).mag();
    }
    return length;
}

float Planning::InterpolatedPath::length(unsigned int start, unsigned int end) const
{
    if (points.empty() || start >= (points.size() - 1))
    {
        return 0;
    }

    float length  = 0;
    for (unsigned int i = start; i < end; ++i)
    {
        length += (points[i + 1] - points[i]).mag();
    }
    return length;
}

boost::optional<Geometry2d::Point> Planning::InterpolatedPath::start() const
{
		if (points.empty())
			return boost::none;
		else
			return points.front();
}

boost::optional<Geometry2d::Point> Planning::InterpolatedPath::destination() const
{
		if (points.empty())
			return boost::none;
		else
			return points.back();
}

// Returns the index of the point in this path nearest to pt.
int Planning::InterpolatedPath::nearestIndex(const Geometry2d::Point &pt) const
{
	if (points.size() == 0)
	{
		return -1;
	}

	int index = 0;
	float dist = pt.distTo(points[0]);

	for (unsigned int i=1 ; i<points.size(); ++i)
	{
		float d = pt.distTo(points[i]);
		if (d < dist)
		{
			dist = d;
			index = i;
		}
	}

	return index;
}

bool Planning::InterpolatedPath::hit(const Geometry2d::CompositeShape &obstacles, float startTime) const
{
	int start=0;
	for(float t: times) {
		start++;
		if(t>startTime) {
			start--;
			break;
		}
	}

    if (start >= points.size())
    {
        // Empty path or starting beyond end of path
        return false;
    }

    // The set of obstacles the starting point was inside of
    std::set<std::shared_ptr<Geometry2d::Shape> > hit;
    obstacles.hit(points[start], hit);

    for (unsigned int i = start; i < (points.size() - 1); ++i)
    {
        std::set<std::shared_ptr<Geometry2d::Shape> > newHit;
        obstacles.hit(Geometry2d::Segment(points[i], points[i + 1]), newHit);
        try
        {
            set_difference(newHit.begin(), newHit.end(), hit.begin(), hit.end(), ExceptionIterator<std::shared_ptr<Geometry2d::Shape>>());
        } catch (exception& e)
        {
            // Going into a new obstacle
            return true;
        }
    }

    // Didn't hit anything or never left any obstacle
    return obstacles.hit(points.back());
}

float Planning::InterpolatedPath::distanceTo(const Geometry2d::Point &pt) const
{
    int i = nearestIndex(pt);
    if (i < 0)
    {
        return 0;
    }

    float dist = -1;
    for (unsigned int i = 0; i < (points.size() - 1); ++i)
	{
		Geometry2d::Segment s(points[i], points[i+1]);
		const float d = s.distTo(pt);

		if (dist < 0 || d < dist)
		{
			dist = d;
		}
	}

    return dist;
}

Geometry2d::Segment Planning::InterpolatedPath::nearestSegment(const Geometry2d::Point &pt) const
{
	Geometry2d::Segment best;
	float dist = -1;
	if (points.empty())
	{
		return best;
	}

	for (unsigned int i = 0; i < (points.size() - 1); ++i)
    {
		Geometry2d::Segment s(points[i], points[i+1]);
		const float d = s.distTo(pt);

		if (dist < 0 || d < dist)
		{
			best = s;
			dist = d;
		}
	}

	return best;
}

void Planning::InterpolatedPath::startFrom(const Geometry2d::Point& pt, Planning::InterpolatedPath& result) const {

	// path will start at the current robot pose
	result.clear();
	result.points.push_back(pt);

	if (points.empty())
		return;

	// handle simple paths
	if (points.size() == 1) {
		result.points.push_back(points.front());
		return;
	}

	// find where to start the path
	Geometry2d::Segment close_segment;
	float dist = -1;
	unsigned int i = (points.front().nearPoint(pt, 0.02)) ? 1 : 0;
	vector<Geometry2d::Point>::const_iterator path_start = ++points.begin();
	for (; i < (points.size() - 1); ++i)
	{
		Geometry2d::Segment s(points[i], points[i+1]);
		const float d = s.distTo(pt);
		if (dist < 0 || d < dist)
		{
			close_segment = s;
			dist = d;
		}
	}

	// slice path
	// new path will be pt, [closest point on nearest segment], [i+1 to end]
	if (dist > 0.0 && dist < 0.02) {
		Geometry2d::Point intersection_pt = close_segment.nearestPoint(pt);
		result.points.push_back(intersection_pt);
	}

	result.points.insert(result.points.end(), path_start, points.end());

}

float Planning::InterpolatedPath::length(const Geometry2d::Point &pt) const
{
	float dist = -1;
	float length = 0;
	if (points.empty())
	{
		return 0;
	}

	for (unsigned int i = 0; i < (points.size() - 1); ++i)
    {
		Geometry2d::Segment s(points[i], points[i+1]);

		//add the segment length
		length += s.length();

		const float d = s.distTo(pt);

		//if point closer to this segment
		if (dist < 0 || d < dist)
		{
			//closest point on segment
			Geometry2d::Point p = s.nearestPoint(pt);

			//new best distance
			dist = d;

			//reset running length count
			length = 0;
			length += p.distTo(s.pt[1]);
		}
	}

	return length;
}

bool Planning::InterpolatedPath::getPoint(float distance ,Geometry2d::Point &position, Geometry2d::Point &direction) const
{
	if (distance<=0) {
		position = points.front();
		return false;
	}
	if (points.empty())
	{
		return false;
	}
	for (unsigned int i = 0; i < (points.size() - 1); ++i)
    {
    	Geometry2d::Point vector(points[i + 1] - points[i]);

		float vectorLength = vector.mag();
		distance -= vectorLength;

		if(distance<=0)
		{
			distance += vectorLength;
			position = points[i] + (vector * (distance / vectorLength));
			direction = vector.normalized();
			return true;
		}
	}
	position = points.back();
	return false;

}
void Planning::InterpolatedPath::draw(SystemState * const state, const QColor &col = Qt::black, const QString &layer = "Motion") const {
	Packet::DebugPath *dbg = state->logFrame->add_debug_paths();
	dbg->set_layer(state->findDebugLayer(layer));
	for (Geometry2d::Point pt : points)
	{
		*dbg->add_points() = pt;
	}
	dbg->set_color(color(col));
	return;
}

bool Planning::InterpolatedPath::evaluate(float t, Geometry2d::Point &targetPosOut, Geometry2d::Point &targetVelOut) const
{
    /*
	float linearPos;
	float linearSpeed;
	bool pathIsValid = TrapezoidalMotion(
        length(),
        maxSpeed,
        maxAcceleration,
        t,
        startSpeed,
        endSpeed,
        linearPos,      //  these are set by reference since C++ can't return multiple values
        linearSpeed);   //

	Geometry2d::Point direction;
	if(!getPoint(linearPos, targetPosOut, direction)) {
		return false;
	}

	targetVelOut = direction * linearSpeed;
	*/
	if (times.size()==0) {
		targetPosOut = Geometry2d::Point(0,0);
		targetVelOut = Geometry2d::Point(0,0);
		return false;
	}
	if (times.size()==1) {
		targetPosOut = points[0];
		targetVelOut = Geometry2d::Point(0,0);
		return false;
	}
	if (t<times[0])
	{
		targetPosOut = points[0];
		targetVelOut = vels[0];
		return false;
	}

    int i=0;
	while (times[i]<=t)
	{
		if (times[i]==t) {
			targetPosOut = points[i];
			targetVelOut = vels[i];
			return true;
		}
		i++;
		if (i==size())
		{
			targetPosOut = points[i-1];
			targetVelOut = vels[i-1];
			return false;
		}
	}
	float deltaT = (times[i] - times[i-1]);
	if (deltaT==0)
	{
		targetPosOut = points[i];
		targetVelOut = vels[i];
		return true;
	}
	float constant = (t-times[i-1])/deltaT;

	targetPosOut = points[i-1]*(1-constant) + points[i]*(constant);
	targetVelOut = vels[i-1]*(1-constant) + vels[i]*(constant);

	return true;
}

size_t Planning::InterpolatedPath::size() const
{
	 return points.size();
}

bool Planning::InterpolatedPath::valid() const
{
	return !points.empty();
}

float Planning::InterpolatedPath::getTime(int index) const
{
	return times[index];
}

float Planning::InterpolatedPath::getDuration() const
{
	if (times.size()>0) {
		return times.back();
	} else {
		return 0;
	}
}

unique_ptr<Path> Planning::InterpolatedPath::subPath(float startTime, float endTime) const
{
	//Check for valid arguments
	if (startTime<0) {
		throw invalid_argument("InterpolatedPath::subPath(): startTime(" + to_string(startTime) + ") can't be less than zero");
	}

	if (endTime<0) {
		throw invalid_argument("InterpolatedPath::subPath(): endTime(" + to_string(endTime) + ") can't be less than zero");
	}

	if (startTime > endTime) {
		throw invalid_argument("InterpolatedPath::subPath(): startTime(" + to_string(startTime) + ") can't be after endTime(" + to_string(endTime) + ")");
	}

	if (startTime >= getDuration()) {
		debugThrow(invalid_argument("InterpolatedPath::subPath(): startTime(" + to_string(startTime) + ") can't be greater than the duration(" + to_string(getDuration()) + ") of the path"));
		return unique_ptr<Path>(new InterpolatedPath());
	}

	if (startTime == 0 && endTime>=getDuration()) {
		return this->clone();
	}

	InterpolatedPath *path = new InterpolatedPath();

	//Bound the endTime to a reasonable time.
	endTime = min(endTime, getDuration());

	//Find the first point in the vector of points which will be included in the subPath
	size_t start = 0;
	while(times[start]<=startTime) {
		start++;
	}
	start--;

	//Add the first points to the InterpolatedPath
	path->times.push_back(0);
	if (times[start]==startTime) {
		path->points.push_back(points[start]);
		path->vels.push_back(vels[start]);
	} else {
		float deltaT = (times[start+1] - times[start]);
		float constant = (times[start+1]-startTime)/deltaT;
		Point startPos = points[start+1]*(1-constant) + points[start]*(constant);
		Point vi = vels[start+1]*(1-constant) + vels[start]*(constant);
		path->points.push_back(startPos);
		path->vels.push_back(vi);
	}

	//Find the last point in the InterpolatedPath
	Point vf;
	Point endPos;
	size_t end;
	if (endTime >= getDuration()) {
		end = size()-1;
		vf = vels[end];
		endPos = points[end];
	} else {
		end = start + 1;
		while (times[end]<endTime) {
			end++;
		}
		float deltaT = (times[end] - times[end-1]);
		float constant = (times[end] - endTime)/deltaT;
		//endTime = times[end];
		vf = vels[end]*(1-constant) + vels[end-1]*(constant);
		endPos = points[end]*(1-constant) + points[end-1]*(constant);
	}

	//Add all the points in the middle
	size_t i=start + 1;
	while (i<end) {
		path->points.push_back(points[i]);
		path->vels.push_back(vels[i]);
		path->times.push_back(times[i]-startTime);
		i++;
	}

	//Add the last point
	path->points.push_back(endPos);
	path->vels.push_back(vf);
	path->times.push_back(endTime - startTime);

	return unique_ptr<Path>(path);

}

unique_ptr<Path> Planning::InterpolatedPath::clone() const {
	return unique_ptr<Path>(new InterpolatedPath(*this));
}<|endoftext|>


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

#include "absl/strings/internal/damerau_levenshtein_distance.h"

#include <cstdint>

#include "gmock/gmock.h"
#include "gtest/gtest.h"

namespace {

using absl::strings_internal::CappedDamerauLevenshteinDistance;

TEST(Distance, TestDistances) {
  EXPECT_THAT(CappedDamerauLevenshteinDistance("ab", "ab", 6), 0u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance("a", "b", 6), 1u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance("ca", "abc", 6), 3u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abcd", "ad", 6), 2u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abcd", "cadb", 6), 4u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abcd", "bdac", 6), 4u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance("ab", "ab", 0), 0u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance("", "", 0), 0u);
  // combinations for 3-character strings:
  // 1, 2, 3 removals, insertions or replacements and transpositions
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abc", "abc", 6), 0u);
  for (auto res :
       {"", "ca", "efg", "ea", "ce", "ceb", "eca", "cae", "cea", "bea"}) {
    EXPECT_THAT(CappedDamerauLevenshteinDistance("abc", res, 6), 3u);
    EXPECT_THAT(CappedDamerauLevenshteinDistance(res, "abc", 6), 3u);
  }
  for (auto res :
       {"a",   "b",   "c",   "ba",  "cb",  "bca", "cab", "cba", "ace",
        "efc", "ebf", "aef", "ae",  "be",  "eb",  "ec",  "ecb", "bec",
        "bce", "cbe", "ace", "eac", "aeb", "bae", "eab", "eba"}) {
    EXPECT_THAT(CappedDamerauLevenshteinDistance("abc", res, 6), 2u);
    EXPECT_THAT(CappedDamerauLevenshteinDistance(res, "abc", 6), 2u);
  }
  for (auto res : {"ab", "ac", "bc", "acb", "bac", "ebc", "aec", "abe"}) {
    EXPECT_THAT(CappedDamerauLevenshteinDistance("abc", res, 6), 1u);
    EXPECT_THAT(CappedDamerauLevenshteinDistance(res, "abc", 6), 1u);
  }
}

TEST(Distance, TestCutoff) {
  // Returing cutoff + 1 if the value is larger than cutoff or string longer
  // than MAX_SIZE.
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abcd", "a", 3), 3u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abcd", "a", 2), 3u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abcd", "a", 1), 2u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abcdefg", "a", 2), 3u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance("a", "abcde", 2), 3u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(102, 'a'),
                                               std::string(102, 'a'), 105),
              101u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(100, 'a'),
                                               std::string(100, 'a'), 100),
              0u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(100, 'a'),
                                               std::string(100, 'b'), 100),
              100u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(100, 'a'),
                                               std::string(99, 'a'), 2),
              1u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(100, 'a'),
                                               std::string(101, 'a'), 2),
              3u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(100, 'a'),
                                               std::string(101, 'a'), 2),
              3u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(UINT8_MAX + 1, 'a'),
                                               std::string(UINT8_MAX + 1, 'b'),
                                               UINT8_MAX),
              101u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(UINT8_MAX - 1, 'a'),
                                               std::string(UINT8_MAX - 1, 'b'),
                                               UINT8_MAX),
              101u);
  EXPECT_THAT(
      CappedDamerauLevenshteinDistance(std::string(UINT8_MAX, 'a'),
                                       std::string(UINT8_MAX, 'b'), UINT8_MAX),
      101u);
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(UINT8_MAX - 1, 'a'),
                                               std::string(UINT8_MAX - 1, 'a'),
                                               UINT8_MAX),
              101u);
}
}  // namespace
<commit_msg>Fix -Wimplicit-int-conversion.<commit_after>// Copyright 2022 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "absl/strings/internal/damerau_levenshtein_distance.h"

#include <cstdint>

#include "gmock/gmock.h"
#include "gtest/gtest.h"

namespace {

using absl::strings_internal::CappedDamerauLevenshteinDistance;

TEST(Distance, TestDistances) {
  EXPECT_THAT(CappedDamerauLevenshteinDistance("ab", "ab", 6), uint8_t{0});
  EXPECT_THAT(CappedDamerauLevenshteinDistance("a", "b", 6), uint8_t{1});
  EXPECT_THAT(CappedDamerauLevenshteinDistance("ca", "abc", 6), uint8_t{3});
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abcd", "ad", 6), uint8_t{2});
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abcd", "cadb", 6), uint8_t{4});
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abcd", "bdac", 6), uint8_t{4});
  EXPECT_THAT(CappedDamerauLevenshteinDistance("ab", "ab", 0), uint8_t{0});
  EXPECT_THAT(CappedDamerauLevenshteinDistance("", "", 0), uint8_t{0});
  // combinations for 3-character strings:
  // 1, 2, 3 removals, insertions or replacements and transpositions
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abc", "abc", 6), uint8_t{0});
  for (auto res :
       {"", "ca", "efg", "ea", "ce", "ceb", "eca", "cae", "cea", "bea"}) {
    EXPECT_THAT(CappedDamerauLevenshteinDistance("abc", res, 6), uint8_t{3});
    EXPECT_THAT(CappedDamerauLevenshteinDistance(res, "abc", 6), uint8_t{3});
  }
  for (auto res :
       {"a",   "b",   "c",   "ba",  "cb",  "bca", "cab", "cba", "ace",
        "efc", "ebf", "aef", "ae",  "be",  "eb",  "ec",  "ecb", "bec",
        "bce", "cbe", "ace", "eac", "aeb", "bae", "eab", "eba"}) {
    EXPECT_THAT(CappedDamerauLevenshteinDistance("abc", res, 6), uint8_t{2});
    EXPECT_THAT(CappedDamerauLevenshteinDistance(res, "abc", 6), uint8_t{2});
  }
  for (auto res : {"ab", "ac", "bc", "acb", "bac", "ebc", "aec", "abe"}) {
    EXPECT_THAT(CappedDamerauLevenshteinDistance("abc", res, 6), uint8_t{1});
    EXPECT_THAT(CappedDamerauLevenshteinDistance(res, "abc", 6), uint8_t{1});
  }
}

TEST(Distance, TestCutoff) {
  // Returing cutoff + 1 if the value is larger than cutoff or string longer
  // than MAX_SIZE.
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abcd", "a", 3), uint8_t{3});
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abcd", "a", 2), uint8_t{3});
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abcd", "a", 1), uint8_t{2});
  EXPECT_THAT(CappedDamerauLevenshteinDistance("abcdefg", "a", 2), uint8_t{3});
  EXPECT_THAT(CappedDamerauLevenshteinDistance("a", "abcde", 2), uint8_t{3});
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(102, 'a'),
                                               std::string(102, 'a'), 105),
              uint8_t{101});
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(100, 'a'),
                                               std::string(100, 'a'), 100),
              uint8_t{0});
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(100, 'a'),
                                               std::string(100, 'b'), 100),
              uint8_t{100});
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(100, 'a'),
                                               std::string(99, 'a'), 2),
              uint8_t{1});
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(100, 'a'),
                                               std::string(101, 'a'), 2),
              uint8_t{3});
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(100, 'a'),
                                               std::string(101, 'a'), 2),
              uint8_t{3});
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(UINT8_MAX + 1, 'a'),
                                               std::string(UINT8_MAX + 1, 'b'),
                                               UINT8_MAX),
              uint8_t{101});
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(UINT8_MAX - 1, 'a'),
                                               std::string(UINT8_MAX - 1, 'b'),
                                               UINT8_MAX),
              uint8_t{101});
  EXPECT_THAT(
      CappedDamerauLevenshteinDistance(std::string(UINT8_MAX, 'a'),
                                       std::string(UINT8_MAX, 'b'), UINT8_MAX),
      uint8_t{101});
  EXPECT_THAT(CappedDamerauLevenshteinDistance(std::string(UINT8_MAX - 1, 'a'),
                                               std::string(UINT8_MAX - 1, 'a'),
                                               UINT8_MAX),
              uint8_t{101});
}
}  // namespace
<|endoftext|>


<commit_before>/************************************************************************
    filename:   FalProgressBar.cpp
    created:    Sat Jul 2 2005
    author:     Paul D Turner <paul@cegui.org.uk>
*************************************************************************/
/*************************************************************************
    Crazy Eddie's GUI System (http://www.cegui.org.uk)
    Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*************************************************************************/
#include "FalProgressBar.h"
#include "falagard/CEGUIFalWidgetLookManager.h"
#include "falagard/CEGUIFalWidgetLookFeel.h"
#include "elements/CEGUIProgressBar.h"

// Start of CEGUI namespace section
namespace CEGUI
{
    const utf8 FalagardProgressBar::TypeName[] = "Falagard/ProgressBar";
    FalagardProgressBarProperties::VerticalProgress FalagardProgressBar::d_verticalProperty;
    FalagardProgressBarProperties::ReversedProgress FalagardProgressBar::d_reversedProperty;

    FalagardProgressBar::FalagardProgressBar(const String& type) :
        WindowRenderer(type, "ProgressBar"),
        d_vertical(false),
        d_reversed(false)
    {
        registerProperty(&d_verticalProperty);
        registerProperty(&d_reversedProperty);
    }

    void FalagardProgressBar::render()
    {
        const StateImagery* imagery;

        // get WidgetLookFeel for the assigned look.
        const WidgetLookFeel& wlf = getLookNFeel();
        // try and get imagery for our current state
        imagery = &wlf.getStateImagery(d_window->isDisabled() ? "Disabled" : "Enabled");
        // peform the rendering operation.
        imagery->render(*d_window);

        // get imagery for actual progress rendering
        imagery = &wlf.getStateImagery(d_window->isDisabled() ? "DisabledProgress" : "EnabledProgress");

        // get target rect for this imagery
        Rect progressRect(wlf.getNamedArea("ProgressArea").getArea().getPixelRect(*d_window));

        // calculate a clipper according to the current progress.
        Rect progressClipper(progressRect);

        ProgressBar* w = (ProgressBar*)d_window;
        if (d_vertical)
        {
            float height = progressRect.getHeight() * w->getProgress();

            if (d_reversed)
            {
                progressRect.setHeight(height);
            }
            else
            {
                progressClipper.d_top = progressClipper.d_bottom - height;
            }
        }
        else
        {
            float width = progressRect.getWidth() * w->getProgress();

            if (d_reversed)
            {
                progressClipper.d_left = progressClipper.d_right - width;
            }
            else
            {
                progressRect.setWidth(width);
            }
        }

        // peform the rendering operation.
        imagery->render(*d_window, progressRect, 0, &progressClipper);
    }

    bool FalagardProgressBar::isVertical() const
    {
        return d_vertical;
    }

    bool FalagardProgressBar::isReversed() const
    {
        return d_reversed;
    }

    void FalagardProgressBar::setVertical(bool setting)
    {
        d_vertical = setting;
    }

    void FalagardProgressBar::setReversed(bool setting)
    {
        d_reversed = setting;
    }

} // End of  CEGUI namespace section
<commit_msg>Fixed progressbar WR.<commit_after>/************************************************************************
    filename:   FalProgressBar.cpp
    created:    Sat Jul 2 2005
    author:     Paul D Turner <paul@cegui.org.uk>
*************************************************************************/
/*************************************************************************
    Crazy Eddie's GUI System (http://www.cegui.org.uk)
    Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*************************************************************************/
#include "FalProgressBar.h"
#include "falagard/CEGUIFalWidgetLookManager.h"
#include "falagard/CEGUIFalWidgetLookFeel.h"
#include "elements/CEGUIProgressBar.h"

// Start of CEGUI namespace section
namespace CEGUI
{
    const utf8 FalagardProgressBar::TypeName[] = "Falagard/ProgressBar";
    FalagardProgressBarProperties::VerticalProgress FalagardProgressBar::d_verticalProperty;
    FalagardProgressBarProperties::ReversedProgress FalagardProgressBar::d_reversedProperty;

    FalagardProgressBar::FalagardProgressBar(const String& type) :
        WindowRenderer(type, "ProgressBar"),
        d_vertical(false),
        d_reversed(false)
    {
        registerProperty(&d_verticalProperty);
        registerProperty(&d_reversedProperty);
    }

    void FalagardProgressBar::render()
    {
        const StateImagery* imagery;

        // get WidgetLookFeel for the assigned look.
        const WidgetLookFeel& wlf = getLookNFeel();
        // try and get imagery for our current state
        imagery = &wlf.getStateImagery(d_window->isDisabled() ? "Disabled" : "Enabled");
        // peform the rendering operation.
        imagery->render(*d_window);

        // get imagery for actual progress rendering
        imagery = &wlf.getStateImagery(d_window->isDisabled() ? "DisabledProgress" : "EnabledProgress");

        // get target rect for this imagery
        Rect progressRect(wlf.getNamedArea("ProgressArea").getArea().getPixelRect(*d_window));

        // calculate a clipper according to the current progress.
        Rect progressClipper(progressRect);

        ProgressBar* w = (ProgressBar*)d_window;
        if (d_vertical)
        {
            float height = progressRect.getHeight() * w->getProgress();

            if (d_reversed)
            {
                progressRect.setHeight(height);
            }
            else
            {
                progressRect.d_top = progressRect.d_bottom - height;
            }
        }
        else
        {
            float width = progressRect.getWidth() * w->getProgress();

            if (d_reversed)
            {
                progressRect.d_left = progressRect.d_right - width;
            }
            else
            {
                progressRect.setWidth(width);
            }
        }

        // peform the rendering operation.
        imagery->render(*d_window, progressRect, 0, &progressClipper);
    }

    bool FalagardProgressBar::isVertical() const
    {
        return d_vertical;
    }

    bool FalagardProgressBar::isReversed() const
    {
        return d_reversed;
    }

    void FalagardProgressBar::setVertical(bool setting)
    {
        d_vertical = setting;
    }

    void FalagardProgressBar::setReversed(bool setting)
    {
        d_reversed = setting;
    }

} // End of  CEGUI namespace section
<|endoftext|>


<commit_before>#include "StorageDataPage.h"
#include "StorageFileChunk.h"

StorageDataPage::StorageDataPage(StorageFileChunk* owner_, uint32_t index_)
{
    size = 0;

    buffer.Allocate(STORAGE_DEFAULT_PAGE_GRAN);
    buffer.Zero();

    buffer.AppendLittle32(0); // dummy for size
    buffer.AppendLittle32(0); // dummy for checksum
    buffer.AppendLittle32(0); // dummy for numKeys

    owner = owner_;
    index = index_;
}

StorageDataPage::~StorageDataPage()
{
    StorageFileKeyValue*    kv;

    for (unsigned i = 0; i < GetNumKeys(); i++)
    {
        kv = GetIndexedKeyValue(i);
        delete kv;
    }
}

uint32_t StorageDataPage::GetSize()
{
    return size;
}

StorageKeyValue* StorageDataPage::Get(ReadBuffer& key)
{
    StorageFileKeyValue* it;

    int cmpres;

    if (GetNumKeys() == 0)
        return NULL;

    it = LocateKeyValue(key, cmpres);
    if (cmpres != 0)
        return NULL;

    return it;
}

uint32_t StorageDataPage::GetNumKeys()
{
    return keyValueIndexBuffer.GetLength() / sizeof(StorageFileKeyValue*);
}

uint32_t StorageDataPage::GetLength()
{
    return buffer.GetLength();
}

uint32_t StorageDataPage::GetIncrement(StorageKeyValue* kv)
{
    if (kv->GetType() == STORAGE_KEYVALUE_TYPE_SET)
        return (1 + 2 + kv->GetKey().GetLength() + 4 + kv->GetValue().GetLength());
    else if (kv->GetType() == STORAGE_KEYVALUE_TYPE_DELETE)
        return (1 + 2 + kv->GetKey().GetLength());
    else
        ASSERT_FAIL();

    return 0;
}

void StorageDataPage::Append(StorageKeyValue* kv)
{
    StorageFileKeyValue*    fkv;

    buffer.Append(kv->GetType());                           // 1 byte(s)
    buffer.AppendLittle16(kv->GetKey().GetLength());        // 2 byte(s)
    buffer.Append(kv->GetKey());
    if (kv->GetType() == STORAGE_KEYVALUE_TYPE_SET)
    {
        buffer.AppendLittle32(kv->GetValue().GetLength());  // 4 bytes(s)
        buffer.Append(kv->GetValue());
    }

    fkv = new StorageFileKeyValue;
    if (kv->GetType() == STORAGE_KEYVALUE_TYPE_SET)
        fkv->Set(ReadBuffer(kv->GetKey()), ReadBuffer(kv->GetValue()));
    else
        fkv->Delete(ReadBuffer(kv->GetKey()));

    AppendKeyValue(fkv);
}

void StorageDataPage::Finalize()
{
    uint32_t                div, mod, numKeys, checksum, length, klen, vlen, pos;
    char                    *kpos, *vpos;
    ReadBuffer              dataPart;
    StorageFileKeyValue*    it;

    numKeys = GetNumKeys();
    length = buffer.GetLength();

    div = length / STORAGE_DEFAULT_PAGE_GRAN;
    mod = length % STORAGE_DEFAULT_PAGE_GRAN;
    size = div * STORAGE_DEFAULT_PAGE_GRAN;
    if (mod > 0)
        size += STORAGE_DEFAULT_PAGE_GRAN;

    buffer.Allocate(size);
    buffer.ZeroRest();

    // write numKeys
    buffer.SetLength(8);
    buffer.AppendLittle32(numKeys);

    // compute checksum
//    dataPart.Wrap(buffer.GetBuffer() + 8, size - 8);
//    checksum = dataPart.GetChecksum();
    checksum = 0;

    buffer.SetLength(0);
    buffer.AppendLittle32(size);
    buffer.AppendLittle32(checksum);

    buffer.SetLength(size);

    // set ReadBuffers in tree
    pos = 12;
    for (unsigned i = 0; i < numKeys; i++)
    {
        it = GetIndexedKeyValue(i);

        pos += 1;                                                // type
        if (it->GetType() == STORAGE_KEYVALUE_TYPE_SET)
        {
            klen = it->GetKey().GetLength();
            vlen = it->GetValue().GetLength();

            pos += 2;                                            // keylen
            kpos = buffer.GetBuffer() + pos;
            pos += klen;
            pos += 4;                                            // vlen
            vpos = buffer.GetBuffer() + pos;
            pos += vlen;

            it->Set(ReadBuffer(kpos, klen), ReadBuffer(vpos, vlen));
        }
        else
        {
            klen = it->GetKey().GetLength();

            pos += 2;                                            // keylen
            kpos = buffer.GetBuffer() + pos;
            pos += klen;

            it->Delete(ReadBuffer(kpos, klen));
        }
    }
}

void StorageDataPage::Reset()
{
    StorageFileKeyValue*    kv;

    for (unsigned i = 0; i < GetNumKeys(); i++)
    {
        kv = GetIndexedKeyValue(i);
        delete kv;
    }

    keyValueIndexBuffer.Reset();
    buffer.Reset();

    buffer.AppendLittle32(0); // dummy for size
    buffer.AppendLittle32(0); // dummy for checksum
    buffer.AppendLittle32(0); // dummy for numKeys
}

StorageFileKeyValue* StorageDataPage::First()
{
    return GetIndexedKeyValue(0);
}

StorageFileKeyValue* StorageDataPage::Next(StorageFileKeyValue* it)
{
    return GetIndexedKeyValue(it->GetNextIndex());
}

StorageFileKeyValue* StorageDataPage::GetIndexedKeyValue(unsigned index)
{
    if (index >= (keyValueIndexBuffer.GetLength() / sizeof(StorageFileKeyValue*)))
        return NULL;
    return ((StorageFileKeyValue**) keyValueIndexBuffer.GetBuffer())[index];
}

StorageFileKeyValue* StorageDataPage::LocateKeyValue(ReadBuffer& key, int& cmpres)
{
    StorageFileKeyValue**   kvIndex;
    unsigned                first;
    unsigned                last;
    unsigned                numKeys;
    unsigned                mid;

    numKeys = GetNumKeys();
    if (numKeys == 0)
        return NULL;

    kvIndex = (StorageFileKeyValue**) keyValueIndexBuffer.GetBuffer();

    first = 0;
    last = numKeys - 1;
    while (first < last)
    {
        mid = first + ((last - first) / 2);
        cmpres = ReadBuffer::Cmp(key, kvIndex[mid]->GetKey());
        if (cmpres == 0)
            return kvIndex[mid];

        if (cmpres < 0)
            last = mid - 1;
        else
            first = mid + 1;
    }

    // not found
    return NULL;
}

bool StorageDataPage::Read(Buffer& buffer_)
{
    char                    type;
    uint16_t                klen;
    uint32_t                size, checksum, compChecksum, numKeys, vlen, i;
    ReadBuffer              dataPart, parse, key, value;
    StorageFileKeyValue*    fkv;

    assert(GetNumKeys() == 0);

    buffer.Write(buffer_);
    parse.Wrap(buffer);

    // size
    parse.ReadLittle32(size);
    if (size < 12)
        goto Fail;
    if (buffer.GetLength() != size)
        goto Fail;
    parse.Advance(4);

    // checksum
//    parse.ReadLittle32(checksum);
//    dataPart.Wrap(buffer.GetBuffer() + 8, buffer.GetLength() - 8);
//    compChecksum = dataPart.GetChecksum();
//    if (compChecksum != checksum)
//        goto Fail;
    parse.Advance(4);

    // numkeys
    parse.ReadLittle32(numKeys);
    parse.Advance(4);

    // keys
    for (i = 0; i < numKeys; i++)
    {
        // type
        if (!parse.ReadChar(type))
            goto Fail;
        if (type != STORAGE_KEYVALUE_TYPE_SET && type != STORAGE_KEYVALUE_TYPE_DELETE)
            goto Fail;
        parse.Advance(1);

        // klen
        if (!parse.ReadLittle16(klen))
            goto Fail;
        parse.Advance(2);

        // key
        if (parse.GetLength() < klen)
            goto Fail;
        key.Wrap(parse.GetBuffer(), klen);
        parse.Advance(klen);

        if (type == STORAGE_KEYVALUE_TYPE_SET)
        {
            // vlen
            if (!parse.ReadLittle32(vlen))
                goto Fail;
            parse.Advance(4);

            // value
            if (parse.GetLength() < vlen)
                goto Fail;
            value.Wrap(parse.GetBuffer(), vlen);
            parse.Advance(vlen);

            fkv = new StorageFileKeyValue;
            fkv->Set(key, value);
            AppendKeyValue(fkv);
        }
        else
        {
            fkv = new StorageFileKeyValue;
            fkv->Delete(key);
            AppendKeyValue(fkv);
        }
    }

    this->size = size;
    return true;

Fail:
    keyValueIndexBuffer.Reset();
    buffer.Reset();
    return false;
}

void StorageDataPage::Write(Buffer& buffer_)
{
    buffer_.Write(buffer);
}

void StorageDataPage::Unload()
{
    Reset();
    owner->OnDataPageEvicted(index);
}

void StorageDataPage::AppendKeyValue(StorageFileKeyValue* kv)
{
    keyValueIndexBuffer.Append((const char*) &kv, sizeof(StorageFileKeyValue*));
    kv->SetNextIndex(keyValueIndexBuffer.GetLength() / sizeof(StorageFileKeyValue*));
}
<commit_msg>Fixed binary search bug.<commit_after>#include "StorageDataPage.h"
#include "StorageFileChunk.h"

StorageDataPage::StorageDataPage(StorageFileChunk* owner_, uint32_t index_)
{
    size = 0;

    buffer.Allocate(STORAGE_DEFAULT_PAGE_GRAN);
    buffer.Zero();

    buffer.AppendLittle32(0); // dummy for size
    buffer.AppendLittle32(0); // dummy for checksum
    buffer.AppendLittle32(0); // dummy for numKeys

    owner = owner_;
    index = index_;
}

StorageDataPage::~StorageDataPage()
{
    StorageFileKeyValue*    kv;

    for (unsigned i = 0; i < GetNumKeys(); i++)
    {
        kv = GetIndexedKeyValue(i);
        delete kv;
    }
}

uint32_t StorageDataPage::GetSize()
{
    return size;
}

StorageKeyValue* StorageDataPage::Get(ReadBuffer& key)
{
    StorageFileKeyValue* it;

    int cmpres;

    if (GetNumKeys() == 0)
        return NULL;

    it = LocateKeyValue(key, cmpres);
    if (cmpres != 0)
        return NULL;

    return it;
}

uint32_t StorageDataPage::GetNumKeys()
{
    return keyValueIndexBuffer.GetLength() / sizeof(StorageFileKeyValue*);
}

uint32_t StorageDataPage::GetLength()
{
    return buffer.GetLength();
}

uint32_t StorageDataPage::GetIncrement(StorageKeyValue* kv)
{
    if (kv->GetType() == STORAGE_KEYVALUE_TYPE_SET)
        return (1 + 2 + kv->GetKey().GetLength() + 4 + kv->GetValue().GetLength());
    else if (kv->GetType() == STORAGE_KEYVALUE_TYPE_DELETE)
        return (1 + 2 + kv->GetKey().GetLength());
    else
        ASSERT_FAIL();

    return 0;
}

void StorageDataPage::Append(StorageKeyValue* kv)
{
    StorageFileKeyValue*    fkv;

    buffer.Append(kv->GetType());                           // 1 byte(s)
    buffer.AppendLittle16(kv->GetKey().GetLength());        // 2 byte(s)
    buffer.Append(kv->GetKey());
    if (kv->GetType() == STORAGE_KEYVALUE_TYPE_SET)
    {
        buffer.AppendLittle32(kv->GetValue().GetLength());  // 4 bytes(s)
        buffer.Append(kv->GetValue());
    }

    fkv = new StorageFileKeyValue;
    if (kv->GetType() == STORAGE_KEYVALUE_TYPE_SET)
        fkv->Set(ReadBuffer(kv->GetKey()), ReadBuffer(kv->GetValue()));
    else
        fkv->Delete(ReadBuffer(kv->GetKey()));

    AppendKeyValue(fkv);
}

void StorageDataPage::Finalize()
{
    uint32_t                div, mod, numKeys, checksum, length, klen, vlen, pos;
    char                    *kpos, *vpos;
    ReadBuffer              dataPart;
    StorageFileKeyValue*    it;

    numKeys = GetNumKeys();
    length = buffer.GetLength();

    div = length / STORAGE_DEFAULT_PAGE_GRAN;
    mod = length % STORAGE_DEFAULT_PAGE_GRAN;
    size = div * STORAGE_DEFAULT_PAGE_GRAN;
    if (mod > 0)
        size += STORAGE_DEFAULT_PAGE_GRAN;

    buffer.Allocate(size);
    buffer.ZeroRest();

    // write numKeys
    buffer.SetLength(8);
    buffer.AppendLittle32(numKeys);

    // compute checksum
//    dataPart.Wrap(buffer.GetBuffer() + 8, size - 8);
//    checksum = dataPart.GetChecksum();
    checksum = 0;

    buffer.SetLength(0);
    buffer.AppendLittle32(size);
    buffer.AppendLittle32(checksum);

    buffer.SetLength(size);

    // set ReadBuffers in tree
    pos = 12;
    for (unsigned i = 0; i < numKeys; i++)
    {
        it = GetIndexedKeyValue(i);

        pos += 1;                                                // type
        if (it->GetType() == STORAGE_KEYVALUE_TYPE_SET)
        {
            klen = it->GetKey().GetLength();
            vlen = it->GetValue().GetLength();

            pos += 2;                                            // keylen
            kpos = buffer.GetBuffer() + pos;
            pos += klen;
            pos += 4;                                            // vlen
            vpos = buffer.GetBuffer() + pos;
            pos += vlen;

            it->Set(ReadBuffer(kpos, klen), ReadBuffer(vpos, vlen));
        }
        else
        {
            klen = it->GetKey().GetLength();

            pos += 2;                                            // keylen
            kpos = buffer.GetBuffer() + pos;
            pos += klen;

            it->Delete(ReadBuffer(kpos, klen));
        }
    }
}

void StorageDataPage::Reset()
{
    StorageFileKeyValue*    kv;

    for (unsigned i = 0; i < GetNumKeys(); i++)
    {
        kv = GetIndexedKeyValue(i);
        delete kv;
    }

    keyValueIndexBuffer.Reset();
    buffer.Reset();

    buffer.AppendLittle32(0); // dummy for size
    buffer.AppendLittle32(0); // dummy for checksum
    buffer.AppendLittle32(0); // dummy for numKeys
}

StorageFileKeyValue* StorageDataPage::First()
{
    return GetIndexedKeyValue(0);
}

StorageFileKeyValue* StorageDataPage::Next(StorageFileKeyValue* it)
{
    return GetIndexedKeyValue(it->GetNextIndex());
}

StorageFileKeyValue* StorageDataPage::GetIndexedKeyValue(unsigned index)
{
    if (index >= (keyValueIndexBuffer.GetLength() / sizeof(StorageFileKeyValue*)))
        return NULL;
    return ((StorageFileKeyValue**) keyValueIndexBuffer.GetBuffer())[index];
}

StorageFileKeyValue* StorageDataPage::LocateKeyValue(ReadBuffer& key, int& cmpres)
{
    StorageFileKeyValue**   kvIndex;
    unsigned                first;
    unsigned                last;
    unsigned                numKeys;
    unsigned                mid;

    numKeys = GetNumKeys();
    if (numKeys == 0)
        return NULL;

    kvIndex = (StorageFileKeyValue**) keyValueIndexBuffer.GetBuffer();

    first = 0;
    last = numKeys - 1;
    while (first <= last)
    {
        mid = first + ((last - first) / 2);
        cmpres = ReadBuffer::Cmp(key, kvIndex[mid]->GetKey());
        if (cmpres == 0)
            return kvIndex[mid];

        if (cmpres < 0)
            last = mid - 1;
        else
            first = mid + 1;
    }

    // not found
    return NULL;
}

bool StorageDataPage::Read(Buffer& buffer_)
{
    char                    type;
    uint16_t                klen;
    uint32_t                size, checksum, compChecksum, numKeys, vlen, i;
    ReadBuffer              dataPart, parse, key, value;
    StorageFileKeyValue*    fkv;

    assert(GetNumKeys() == 0);

    buffer.Write(buffer_);
    parse.Wrap(buffer);

    // size
    parse.ReadLittle32(size);
    if (size < 12)
        goto Fail;
    if (buffer.GetLength() != size)
        goto Fail;
    parse.Advance(4);

    // checksum
//    parse.ReadLittle32(checksum);
//    dataPart.Wrap(buffer.GetBuffer() + 8, buffer.GetLength() - 8);
//    compChecksum = dataPart.GetChecksum();
//    if (compChecksum != checksum)
//        goto Fail;
    parse.Advance(4);

    // numkeys
    parse.ReadLittle32(numKeys);
    parse.Advance(4);

    // keys
    for (i = 0; i < numKeys; i++)
    {
        // type
        if (!parse.ReadChar(type))
            goto Fail;
        if (type != STORAGE_KEYVALUE_TYPE_SET && type != STORAGE_KEYVALUE_TYPE_DELETE)
            goto Fail;
        parse.Advance(1);

        // klen
        if (!parse.ReadLittle16(klen))
            goto Fail;
        parse.Advance(2);

        // key
        if (parse.GetLength() < klen)
            goto Fail;
        key.Wrap(parse.GetBuffer(), klen);
        parse.Advance(klen);

        if (type == STORAGE_KEYVALUE_TYPE_SET)
        {
            // vlen
            if (!parse.ReadLittle32(vlen))
                goto Fail;
            parse.Advance(4);

            // value
            if (parse.GetLength() < vlen)
                goto Fail;
            value.Wrap(parse.GetBuffer(), vlen);
            parse.Advance(vlen);

            fkv = new StorageFileKeyValue;
            fkv->Set(key, value);
            AppendKeyValue(fkv);
        }
        else
        {
            fkv = new StorageFileKeyValue;
            fkv->Delete(key);
            AppendKeyValue(fkv);
        }
    }

    this->size = size;
    return true;

Fail:
    keyValueIndexBuffer.Reset();
    buffer.Reset();
    return false;
}

void StorageDataPage::Write(Buffer& buffer_)
{
    buffer_.Write(buffer);
}

void StorageDataPage::Unload()
{
    Reset();
    owner->OnDataPageEvicted(index);
}

void StorageDataPage::AppendKeyValue(StorageFileKeyValue* kv)
{
    keyValueIndexBuffer.Append((const char*) &kv, sizeof(StorageFileKeyValue*));
    kv->SetNextIndex(keyValueIndexBuffer.GetLength() / sizeof(StorageFileKeyValue*));
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) Jürgen Riegel          (juergen.riegel@web.de) 2010     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
#   include <assert.h>
#endif

/// Here the FreeCAD includes sorted by Base,App,Gui......

#include <Base/Exception.h>
#include <Base/Reader.h>
#include <Base/Writer.h>

#include "Geometry.h"
#include "GeometryPy.h"

#include "PropertyGeometryList.h"
#include "Part2DObject.h"

using namespace App;
using namespace Base;
using namespace std;
using namespace Part;

//**************************************************************************
// PropertyGeometryList
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

TYPESYSTEM_SOURCE(Part::PropertyGeometryList, App::PropertyLists);

//**************************************************************************
// Construction/Destruction

PropertyGeometryList::PropertyGeometryList()
{

}

PropertyGeometryList::~PropertyGeometryList()
{
    for (std::vector<Geometry*>::iterator it = _lValueList.begin(); it != _lValueList.end(); ++it)
        if (*it) delete *it;
}

void PropertyGeometryList::setSize(int newSize)
{
    for (unsigned int i = newSize; i < _lValueList.size(); i++)
        delete _lValueList[i];
    _lValueList.resize(newSize);
}

int PropertyGeometryList::getSize(void) const
{
    return static_cast<int>(_lValueList.size());
}

void PropertyGeometryList::setValue(const Geometry* lValue)
{
    if (lValue) {
        aboutToSetValue();
        Geometry* newVal = lValue->clone();
        for (unsigned int i = 0; i < _lValueList.size(); i++)
            delete _lValueList[i];
        _lValueList.resize(1);
        _lValueList[0] = newVal;
        hasSetValue();
    }
}

void PropertyGeometryList::setValues(const std::vector<Geometry*>& lValue)
{
    aboutToSetValue();
    std::vector<Geometry*> oldVals(_lValueList);
    _lValueList.resize(lValue.size());
    // copy all objects
    for (unsigned int i = 0; i < lValue.size(); i++)
        _lValueList[i] = lValue[i]->clone();
    for (unsigned int i = 0; i < oldVals.size(); i++)
        delete oldVals[i];
    hasSetValue();
}

PyObject *PropertyGeometryList::getPyObject(void)
{
    PyObject* list = PyList_New(getSize());
    for (int i = 0; i < getSize(); i++)
        PyList_SetItem( list, i, _lValueList[i]->getPyObject());
    return list;
}

void PropertyGeometryList::setPyObject(PyObject *value)
{
    // check container of this property to notify about changes
    Part2DObject* part2d = dynamic_cast<Part2DObject*>(this->getContainer());

    if (PySequence_Check(value)) {
        Py_ssize_t nSize = PySequence_Size(value);
        std::vector<Geometry*> values;
        values.resize(nSize);

        for (Py_ssize_t i=0; i < nSize; ++i) {
            PyObject* item = PySequence_GetItem(value, i);
            if (!PyObject_TypeCheck(item, &(GeometryPy::Type))) {
                std::string error = std::string("types in list must be 'Geometry', not ");
                error += item->ob_type->tp_name;
                throw Base::TypeError(error);
            }

            values[i] = static_cast<GeometryPy*>(item)->getGeometryPtr();
        }

        setValues(values);
        if (part2d)
            part2d->acceptGeometry();
    }
    else if (PyObject_TypeCheck(value, &(GeometryPy::Type))) {
        GeometryPy  *pcObject = static_cast<GeometryPy*>(value);
        setValue(pcObject->getGeometryPtr());
        if (part2d)
            part2d->acceptGeometry();
    }
    else {
        std::string error = std::string("type must be 'Geometry' or list of 'Geometry', not ");
        error += value->ob_type->tp_name;
        throw Base::TypeError(error);
    }
}

void PropertyGeometryList::Save(Writer &writer) const
{
    writer.Stream() << writer.ind() << "<GeometryList count=\"" << getSize() <<"\">" << endl;
    writer.incInd();
    for (int i = 0; i < getSize(); i++) {
        writer.Stream() << writer.ind() << "<Geometry  type=\""
                        << _lValueList[i]->getTypeId().getName() << "\">" << endl;;
        writer.incInd();
        _lValueList[i]->Save(writer);
        writer.decInd();
        writer.Stream() << writer.ind() << "</Geometry>" << endl;
    }
    writer.decInd();
    writer.Stream() << writer.ind() << "</GeometryList>" << endl ;
}

void PropertyGeometryList::Restore(Base::XMLReader &reader)
{
    // read my element
    reader.readElement("GeometryList");
    // get the value of my attribute
    int count = reader.getAttributeAsInteger("count");

    std::vector<Geometry*> values;
    values.reserve(count);
    for (int i = 0; i < count; i++) {
        reader.readElement("Geometry");
        const char* TypeName = reader.getAttribute("type");
        Geometry *newG = (Geometry *)Base::Type::fromName(TypeName).createInstance();
        newG->Restore(reader);
        values.push_back(newG);
        reader.readEndElement("Geometry");
    }

    reader.readEndElement("GeometryList");

    // assignment
    setValues(values);
}

App::Property *PropertyGeometryList::Copy(void) const
{
    PropertyGeometryList *p = new PropertyGeometryList();
    p->setValues(_lValueList);
    return p;
}

void PropertyGeometryList::Paste(const Property &from)
{
    const PropertyGeometryList& FromList = dynamic_cast<const PropertyGeometryList&>(from);
    setValues(FromList._lValueList);
}

unsigned int PropertyGeometryList::getMemSize(void) const
{
    int size = sizeof(PropertyGeometryList);
    for (int i = 0; i < getSize(); i++)
        size += _lValueList[i]->getMemSize();
    return size;
}
<commit_msg>PropertyGeometryList: enable a partial recover on certain errors<commit_after>/***************************************************************************
 *   Copyright (c) Jürgen Riegel          (juergen.riegel@web.de) 2010     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
#   include <assert.h>
#endif

/// Here the FreeCAD includes sorted by Base,App,Gui......

#include <Base/Exception.h>
#include <Base/Reader.h>
#include <Base/Writer.h>

#include "Geometry.h"
#include "GeometryPy.h"

#include "PropertyGeometryList.h"
#include "Part2DObject.h"

using namespace App;
using namespace Base;
using namespace std;
using namespace Part;

//**************************************************************************
// PropertyGeometryList
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

TYPESYSTEM_SOURCE(Part::PropertyGeometryList, App::PropertyLists);

//**************************************************************************
// Construction/Destruction

PropertyGeometryList::PropertyGeometryList()
{

}

PropertyGeometryList::~PropertyGeometryList()
{
    for (std::vector<Geometry*>::iterator it = _lValueList.begin(); it != _lValueList.end(); ++it)
        if (*it) delete *it;
}

void PropertyGeometryList::setSize(int newSize)
{
    for (unsigned int i = newSize; i < _lValueList.size(); i++)
        delete _lValueList[i];
    _lValueList.resize(newSize);
}

int PropertyGeometryList::getSize(void) const
{
    return static_cast<int>(_lValueList.size());
}

void PropertyGeometryList::setValue(const Geometry* lValue)
{
    if (lValue) {
        aboutToSetValue();
        Geometry* newVal = lValue->clone();
        for (unsigned int i = 0; i < _lValueList.size(); i++)
            delete _lValueList[i];
        _lValueList.resize(1);
        _lValueList[0] = newVal;
        hasSetValue();
    }
}

void PropertyGeometryList::setValues(const std::vector<Geometry*>& lValue)
{
    aboutToSetValue();
    std::vector<Geometry*> oldVals(_lValueList);
    _lValueList.resize(lValue.size());
    // copy all objects
    for (unsigned int i = 0; i < lValue.size(); i++)
        _lValueList[i] = lValue[i]->clone();
    for (unsigned int i = 0; i < oldVals.size(); i++)
        delete oldVals[i];
    hasSetValue();
}

PyObject *PropertyGeometryList::getPyObject(void)
{
    PyObject* list = PyList_New(getSize());
    for (int i = 0; i < getSize(); i++)
        PyList_SetItem( list, i, _lValueList[i]->getPyObject());
    return list;
}

void PropertyGeometryList::setPyObject(PyObject *value)
{
    // check container of this property to notify about changes
    Part2DObject* part2d = dynamic_cast<Part2DObject*>(this->getContainer());

    if (PySequence_Check(value)) {
        Py_ssize_t nSize = PySequence_Size(value);
        std::vector<Geometry*> values;
        values.resize(nSize);

        for (Py_ssize_t i=0; i < nSize; ++i) {
            PyObject* item = PySequence_GetItem(value, i);
            if (!PyObject_TypeCheck(item, &(GeometryPy::Type))) {
                std::string error = std::string("types in list must be 'Geometry', not ");
                error += item->ob_type->tp_name;
                throw Base::TypeError(error);
            }

            values[i] = static_cast<GeometryPy*>(item)->getGeometryPtr();
        }

        setValues(values);
        if (part2d)
            part2d->acceptGeometry();
    }
    else if (PyObject_TypeCheck(value, &(GeometryPy::Type))) {
        GeometryPy  *pcObject = static_cast<GeometryPy*>(value);
        setValue(pcObject->getGeometryPtr());
        if (part2d)
            part2d->acceptGeometry();
    }
    else {
        std::string error = std::string("type must be 'Geometry' or list of 'Geometry', not ");
        error += value->ob_type->tp_name;
        throw Base::TypeError(error);
    }
}

void PropertyGeometryList::Save(Writer &writer) const
{
    writer.Stream() << writer.ind() << "<GeometryList count=\"" << getSize() <<"\">" << endl;
    writer.incInd();
    for (int i = 0; i < getSize(); i++) {
        writer.Stream() << writer.ind() << "<Geometry  type=\""
                        << _lValueList[i]->getTypeId().getName() << "\">" << endl;;
        writer.incInd();
        _lValueList[i]->Save(writer);
        writer.decInd();
        writer.Stream() << writer.ind() << "</Geometry>" << endl;
    }
    writer.decInd();
    writer.Stream() << writer.ind() << "</GeometryList>" << endl ;
}

void PropertyGeometryList::Restore(Base::XMLReader &reader)
{
    bool partialrestore = false;

    // read my element
    reader.readElement("GeometryList");
    // get the value of my attribute
    int count = reader.getAttributeAsInteger("count");

    std::vector<Geometry*> values;
    values.reserve(count);
    for (int i = 0; i < count; i++) {
        reader.readElement("Geometry");
        const char* TypeName = reader.getAttribute("type");
        Geometry *newG = (Geometry *)Base::Type::fromName(TypeName).createInstance();

        try {
            newG->Restore(reader);
            values.push_back(newG);
            reader.readEndElement("Geometry");
        }
        catch(Base::RestoreError e) {

            e.ReportException();

            if(isOrderRelevant) {
                // Pushes the best try by the Geometry class
                values.push_back(newG);
            }
            else {
                delete newG;
            }

            reader.readEndElement("Geometry");

            partialrestore = true;

            continue;
        }

    }

    reader.readEndElement("GeometryList");

    // assignment
    setValues(values);

    /*if(partialrestore)
        THROWMT(Base::RestoreError, QT_TRANSLATE_NOOP("Exceptions","There were errors during the restoring process. Some geometry objects may not correspond to the version that was saved or might have been deleted."));*/
}

App::Property *PropertyGeometryList::Copy(void) const
{
    PropertyGeometryList *p = new PropertyGeometryList();
    p->setValues(_lValueList);
    return p;
}

void PropertyGeometryList::Paste(const Property &from)
{
    const PropertyGeometryList& FromList = dynamic_cast<const PropertyGeometryList&>(from);
    setValues(FromList._lValueList);
}

unsigned int PropertyGeometryList::getMemSize(void) const
{
    int size = sizeof(PropertyGeometryList);
    for (int i = 0; i < getSize(); i++)
        size += _lValueList[i]->getMemSize();
    return size;
}
<|endoftext|>