<commit_before>//
//  refract/JSONSchemaVisitor.cc
//  librefract
//
//  Created by Vilibald Wanča on 09/11/15.
//  Copyright (c) 2015 Apiary Inc. All rights reserved.
//

#include "VisitorUtils.h"
#include "sosJSON.h"
#include <sstream>
#include <iostream>
#include <map>

namespace refract
{

    JSONSchemaVisitor::JSONSchemaVisitor(bool fixit /*= false*/) : fixed(fixit)
    {
        pObj = new ObjectElement;
        pObj->renderType(IElement::rCompact);
    }

    JSONSchemaVisitor::~JSONSchemaVisitor()
    {
        if (NULL != pObj) {
            delete pObj;
        }
    }

    void JSONSchemaVisitor::setFixed(bool fixit)
    {
        fixed = fixit;
    }

    template<>
    void JSONSchemaVisitor::setPrimitiveType(const BooleanElement& e)
    {
        setSchemaType("boolean");
    }

    template<>
    void JSONSchemaVisitor::setPrimitiveType(const StringElement& e)
    {
        setSchemaType("string");
    }

    template<>
    void JSONSchemaVisitor::setPrimitiveType(const NumberElement& e)
    {
        setSchemaType("number");
    }

    void JSONSchemaVisitor::setSchemaType(const std::string& type)
    {
        StringElement *s = new StringElement;

        s->renderType(IElement::rCompact);
        s->set(type);
        addMember("type", s);
    }

    void JSONSchemaVisitor::addMember(const std::string& key, IElement *val)
    {
        MemberElement *m = new MemberElement;

        m->renderType(IElement::rCompact);
        m->set(key, val);
        pObj->push_back(m);
    }

    bool JSONSchemaVisitor::allItemsEmpty(const ArrayElement::ValueType* val)
    {
        for (ArrayElement::ValueType::const_iterator i = val->begin();
             i != val->end();
             ++i) {

            if (!(*i)->empty()) {
                return false;
            }
        }

        return true;
    }

    template<typename T>
    void JSONSchemaVisitor::primitiveType(const T& e)
    {
        const typename T::ValueType *v = GetValue<T>(e);

        if (v) {
            setPrimitiveType(e);

            if (fixed && !e.empty()) {
                ArrayElement *a = new ArrayElement;
                a->push_back(IElement::Create(*v));
                addMember("enum", a);
            }
        }
    }

    void JSONSchemaVisitor::visit(const IElement& e)
    {
        e.content(*this);
    }

    void JSONSchemaVisitor::visit(const MemberElement& e)
    {
        JSONSchemaVisitor renderer;

        if (e.value.second) {
           if (IsTypeAttribute(e, "fixed") || fixed) {
                renderer.setFixed(true);
            }
           renderer.visit(*e.value.second);
        }

        if (StringElement* str = TypeQueryVisitor::as<StringElement>(e.value.first)) {
            IElement *desc = GetDescription(e);

            if (desc) {
                IElement *d = desc->clone();
                d->renderType(IElement::rCompact);
                renderer.addMember("description", d);
            }

            addMember(str->value, renderer.getOwnership());
        }
        else {
            throw std::logic_error("A property's key in the object is not of type string");
        }
    }

    void JSONSchemaVisitor::visit(const ObjectElement& e)
    {
        const ObjectElement::ValueType* val = GetValue<ObjectElement>(e);
        setSchemaType("object");

        if (!val) {
            return;
        }

        ObjectElement *o = new ObjectElement;
        ArrayElement::ValueType reqVals;

        o->renderType(IElement::rCompact);

        for (std::vector<refract::IElement*>::const_iterator it = val->begin();
             it != val->end();
             ++it) {

            if (*it) {
                if (IsTypeAttribute(*(*it), "required") ||
                    IsTypeAttribute(*(*it), "fixed") ||
                    (fixed && !IsTypeAttribute(*(*it), "optional"))) {

                    MemberElement *mr = TypeQueryVisitor::as<MemberElement>(*it);
                    StringElement *n = TypeQueryVisitor::as<StringElement>(mr->value.first);
                    reqVals.push_back(IElement::Create(n->value));
                }

                JSONSchemaVisitor renderer(fixed);
                renderer.visit(*(*it));

                ObjectElement *o1 = TypeQueryVisitor::as<ObjectElement>(renderer.get());
                // the o1->value is never emtpy as the object returned
                // by JSONSchema visitor always has a member, at least a type
                // key for primitive types
                MemberElement *m1 = TypeQueryVisitor::as<MemberElement>(o1->value[0]->clone());

                m1->renderType(IElement::rCompact);
                o->push_back(m1);
            }
        }

        addMember("properties", o);

        if (!reqVals.empty()) {
            ArrayElement *a = new ArrayElement;
            a->renderType(IElement::rCompact);
            a->set(reqVals);
            addMember("required", a);
        }

        if (fixed) {
            addMember("additionalProperties", IElement::Create(false));
        }
    }

    void JSONSchemaVisitor::anyOf(std::map<std::string, std::vector<IElement*> >& types, std::vector<std::string>& typesOrder)
    {
        ArrayElement *a = new ArrayElement;
        a->renderType(IElement::rCompact);

        for (std::vector<std::string>::const_iterator i = typesOrder.begin();
             i != typesOrder.end();
             ++i) {

            const std::vector<IElement*>& items = types[*i];
            JSONSchemaVisitor v;
            IElement *elm = items.front();

            v.visit(*elm);

            if (elm->element() == "enum"){
                v.addMember("enum", elm->clone());
            }
            else if (NULL == TypeQueryVisitor::as<ObjectElement>(elm)) {
                ArrayElement::ValueType enmVals;
                for (std::vector<IElement*>::const_iterator i = items.begin();
                    i != items.end();
                    ++i) {

                    if (!(*i)->empty()) {
                        IElement *e = (*i)->clone();
                        e->renderType(IElement::rCompact);
                        enmVals.push_back(e);
                    }
                }

                if (!enmVals.empty()) {
                    ArrayElement *enm = new ArrayElement;
                    enm->set(enmVals);
                    v.addMember("enum", enm);
                }
            }

            a->push_back(v.getOwnership());
        }
        addMember("anyOf", a);
    }

    void JSONSchemaVisitor::enumElement(const ArrayElement& e, const ArrayElement::ValueType *val)
    {
        std::map<std::string, std::vector<IElement*> > types;
        std::vector<std::string> typesOrder;

        for (ArrayElement::ValueType::const_iterator it = val->begin();
             it != val->end();
             ++it) {

            if (*it) {
                std::vector<IElement*>& items = types[(*it)->element()];

                if (items.empty()) {
                    typesOrder.push_back((*it)->element());
                }

                items.push_back(*it);
            }
        }

        if (types.size() > 1) {
            anyOf(types, typesOrder);
        }
        else {
            if (!e.empty() || DefaultAttribute(e) != NULL) {
                ArrayElement *a = new ArrayElement;
                a->renderType(IElement::rCompact);

                for (ArrayElement::ValueType::const_iterator it = val->begin();
                     it != val->end();
                     ++it) {

                    IElement *e = (*it)->clone();
                    e->renderType(IElement::rCompact);
                    a->push_back(e);
                }

                setSchemaType(types.begin()->first);
                addMember("enum", a);
            }
        }
    }

    void JSONSchemaVisitor::visit(const ArrayElement& e) {
        const ArrayElement::ValueType* val = GetValue<ArrayElement>(e);

        if (!val || val->empty()) {
            return;
        }

        if (e.element() == "enum") {
            enumElement(e, val);
        }
        else {
            JSONSchemaVisitor renderer;
            setSchemaType("array");

            if (fixed) {
                ArrayElement::ValueType av;
                bool allEmpty = allItemsEmpty(val);

                for (ArrayElement::ValueType::const_iterator it = val->begin();
                     it != val->end();
                     ++it) {

                    if (*it) {
                        // if all items are just type items then we
                        // want them in the schema, otherwise skip
                        // empty ones
                        if (allEmpty || !(*it)->empty()) {
                            JSONSchemaVisitor v(true);

                            v.visit(*(*it));
                            av.push_back(v.getOwnership());
                        }
                    }
                }

                if (!av.empty()) {
                    ArrayElement *a = new ArrayElement;
                    a->set(av);
                    addMember("items", a);
                }
            }

            if (IsTypeAttribute(e, "required")) {
                for (ArrayElement::ValueType::const_iterator it = val->begin();
                     it != val->end();
                     ++it) {

                    if (*it && !(*it)->empty()) {
                        renderer.visit(*(*it));
                    }
                }

                addMember("items", renderer.getOwnership());
            }
        }

        IElement *def = DefaultAttribute(e);

        if (def) {
            IElement *d = def->clone();
            d->renderType(IElement::rCompact);

            if (e.element() == "enum") {
                addMember("default", d);
            }
            else {
                ArrayElement *a = new ArrayElement;
                a->push_back(d);
                addMember("default", a);
            }
        }
    }

    void JSONSchemaVisitor::visit(const NullElement& e)
    {
        addMember("type", new NullElement);
    }

    void JSONSchemaVisitor::visit(const StringElement& e)
    {
        primitiveType(e);
    }

    void JSONSchemaVisitor::visit(const NumberElement& e)
    {
        primitiveType(e);
    }

    void JSONSchemaVisitor::visit(const BooleanElement& e)
    {
        primitiveType(e);
    }

    IElement* JSONSchemaVisitor::get()
    {
        return pObj;
    }

    IElement* JSONSchemaVisitor::getOwnership()
    {
        IElement* ret = pObj;
        pObj = NULL;
        return ret;
    }

    std::string JSONSchemaVisitor::getSchema(const IElement& e)
    {
        StringElement *str = new StringElement;

        str->renderType(IElement::rCompact);
        str->set("http://json-schema.org/draft-04/schema#");
        addMember("$schema", str);
        setSchemaType("object");

        visit(e);

        sos::SerializeJSON s;
        std::stringstream ss;
        SerializeCompactVisitor sv;

        pObj->content(sv);
        s.process(sv.value(), ss);

        return ss.str();
    }
}
<commit_msg>Fix crashing tests after rebase<commit_after>//
//  refract/JSONSchemaVisitor.cc
//  librefract
//
//  Created by Vilibald Wanča on 09/11/15.
//  Copyright (c) 2015 Apiary Inc. All rights reserved.
//

#include "VisitorUtils.h"
#include "sosJSON.h"
#include <sstream>
#include <iostream>
#include <map>

namespace refract
{

    JSONSchemaVisitor::JSONSchemaVisitor(bool fixit /*= false*/) : fixed(fixit)
    {
        pObj = new ObjectElement;
        pObj->renderType(IElement::rCompact);
    }

    JSONSchemaVisitor::~JSONSchemaVisitor()
    {
        if (NULL != pObj) {
            delete pObj;
        }
    }

    void JSONSchemaVisitor::setFixed(bool fixit)
    {
        fixed = fixit;
    }

    template<>
    void JSONSchemaVisitor::setPrimitiveType(const BooleanElement& e)
    {
        setSchemaType("boolean");
    }

    template<>
    void JSONSchemaVisitor::setPrimitiveType(const StringElement& e)
    {
        setSchemaType("string");
    }

    template<>
    void JSONSchemaVisitor::setPrimitiveType(const NumberElement& e)
    {
        setSchemaType("number");
    }

    void JSONSchemaVisitor::setSchemaType(const std::string& type)
    {
        StringElement *s = new StringElement;

        s->renderType(IElement::rCompact);
        s->set(type);
        addMember("type", s);
    }

    void JSONSchemaVisitor::addMember(const std::string& key, IElement *val)
    {
        MemberElement *m = new MemberElement;

        m->renderType(IElement::rCompact);
        m->set(key, val);
        pObj->push_back(m);
    }

    bool JSONSchemaVisitor::allItemsEmpty(const ArrayElement::ValueType* val)
    {
        for (ArrayElement::ValueType::const_iterator i = val->begin();
             i != val->end();
             ++i) {

            if (!(*i)->empty()) {
                return false;
            }
        }

        return true;
    }

    template<typename T>
    void JSONSchemaVisitor::primitiveType(const T& e)
    {
        const typename T::ValueType *v = GetValue<T>(e);

        if (v) {
            setPrimitiveType(e);

            if (fixed && !e.empty()) {
                ArrayElement *a = new ArrayElement;
                a->push_back(IElement::Create(*v));
                addMember("enum", a);
            }
        }
    }

    void JSONSchemaVisitor::visit(const IElement& e)
    {
        e.content(*this);
    }

    void JSONSchemaVisitor::visit(const MemberElement& e)
    {
        JSONSchemaVisitor renderer;

        if (e.value.second) {
           if (IsTypeAttribute(e, "fixed") || fixed) {
                renderer.setFixed(true);
            }
           renderer.visit(*e.value.second);
        }

        if (StringElement* str = TypeQueryVisitor::as<StringElement>(e.value.first)) {
            IElement *desc = GetDescription(e);

            if (desc) {
                IElement *d = desc->clone();
                d->renderType(IElement::rCompact);
                renderer.addMember("description", d);
            }

            addMember(str->value, renderer.getOwnership());
        }
        else {
            throw std::logic_error("A property's key in the object is not of type string");
        }
    }

    void JSONSchemaVisitor::visit(const ObjectElement& e)
    {
        const ObjectElement::ValueType* val = GetValue<ObjectElement>(e);
        setSchemaType("object");

        if (!val) {
            return;
        }

        ObjectElement *o = new ObjectElement;
        ArrayElement::ValueType reqVals;

        o->renderType(IElement::rCompact);

        for (std::vector<refract::IElement*>::const_iterator it = val->begin();
             it != val->end();
             ++it) {

            if (*it) {
                if (IsTypeAttribute(*(*it), "required") ||
                    IsTypeAttribute(*(*it), "fixed") ||
                    (fixed && !IsTypeAttribute(*(*it), "optional"))) {

                    MemberElement *mr = TypeQueryVisitor::as<MemberElement>(*it);
                    StringElement *n = TypeQueryVisitor::as<StringElement>(mr->value.first);
                    reqVals.push_back(IElement::Create(n->value));
                }

                JSONSchemaVisitor renderer(fixed);
                renderer.visit(*(*it));

                ObjectElement *o1 = TypeQueryVisitor::as<ObjectElement>(renderer.get());
                // the o1->value is never emtpy as the object returned
                // by JSONSchema visitor always has a member, at least a type
                // key for primitive types
                if (!o1->value.empty()) {
                    MemberElement *m1 = TypeQueryVisitor::as<MemberElement>(o1->value[0]->clone());

                    m1->renderType(IElement::rCompact);
                    o->push_back(m1);
                }

            }
        }

        addMember("properties", o);

        if (!reqVals.empty()) {
            ArrayElement *a = new ArrayElement;
            a->renderType(IElement::rCompact);
            a->set(reqVals);
            addMember("required", a);
        }

        if (fixed) {
            addMember("additionalProperties", IElement::Create(false));
        }
    }

    void JSONSchemaVisitor::anyOf(std::map<std::string, std::vector<IElement*> >& types, std::vector<std::string>& typesOrder)
    {
        ArrayElement *a = new ArrayElement;
        a->renderType(IElement::rCompact);

        for (std::vector<std::string>::const_iterator i = typesOrder.begin();
             i != typesOrder.end();
             ++i) {

            const std::vector<IElement*>& items = types[*i];
            JSONSchemaVisitor v;
            IElement *elm = items.front();

            v.visit(*elm);

            if (elm->element() == "enum"){
                v.addMember("enum", elm->clone());
            }
            else if (NULL == TypeQueryVisitor::as<ObjectElement>(elm)) {
                ArrayElement::ValueType enmVals;
                for (std::vector<IElement*>::const_iterator i = items.begin();
                    i != items.end();
                    ++i) {

                    if (!(*i)->empty()) {
                        IElement *e = (*i)->clone();
                        e->renderType(IElement::rCompact);
                        enmVals.push_back(e);
                    }
                }

                if (!enmVals.empty()) {
                    ArrayElement *enm = new ArrayElement;
                    enm->set(enmVals);
                    v.addMember("enum", enm);
                }
            }

            a->push_back(v.getOwnership());
        }
        addMember("anyOf", a);
    }

    void JSONSchemaVisitor::enumElement(const ArrayElement& e, const ArrayElement::ValueType *val)
    {
        std::map<std::string, std::vector<IElement*> > types;
        std::vector<std::string> typesOrder;

        for (ArrayElement::ValueType::const_iterator it = val->begin();
             it != val->end();
             ++it) {

            if (*it) {
                std::vector<IElement*>& items = types[(*it)->element()];

                if (items.empty()) {
                    typesOrder.push_back((*it)->element());
                }

                items.push_back(*it);
            }
        }

        if (types.size() > 1) {
            anyOf(types, typesOrder);
        }
        else {
            if (!e.empty() || DefaultAttribute(e) != NULL) {
                ArrayElement *a = new ArrayElement;
                a->renderType(IElement::rCompact);

                for (ArrayElement::ValueType::const_iterator it = val->begin();
                     it != val->end();
                     ++it) {

                    IElement *e = (*it)->clone();
                    e->renderType(IElement::rCompact);
                    a->push_back(e);
                }

                setSchemaType(types.begin()->first);
                addMember("enum", a);
            }
        }
    }

    void JSONSchemaVisitor::visit(const ArrayElement& e) {
        const ArrayElement::ValueType* val = GetValue<ArrayElement>(e);

        if (!val || val->empty()) {
            return;
        }

        if (e.element() == "enum") {
            enumElement(e, val);
        }
        else {
            JSONSchemaVisitor renderer;
            setSchemaType("array");

            if (fixed) {
                ArrayElement::ValueType av;
                bool allEmpty = allItemsEmpty(val);

                for (ArrayElement::ValueType::const_iterator it = val->begin();
                     it != val->end();
                     ++it) {

                    if (*it) {
                        // if all items are just type items then we
                        // want them in the schema, otherwise skip
                        // empty ones
                        if (allEmpty || !(*it)->empty()) {
                            JSONSchemaVisitor v(true);

                            v.visit(*(*it));
                            av.push_back(v.getOwnership());
                        }
                    }
                }

                if (!av.empty()) {
                    ArrayElement *a = new ArrayElement;
                    a->set(av);
                    addMember("items", a);
                }
            }

            if (IsTypeAttribute(e, "required")) {
                for (ArrayElement::ValueType::const_iterator it = val->begin();
                     it != val->end();
                     ++it) {

                    if (*it && !(*it)->empty()) {
                        renderer.visit(*(*it));
                    }
                }

                addMember("items", renderer.getOwnership());
            }
        }

        IElement *def = DefaultAttribute(e);

        if (def) {
            IElement *d = def->clone();
            d->renderType(IElement::rCompact);

            if (e.element() == "enum") {
                addMember("default", d);
            }
            else {
                ArrayElement *a = new ArrayElement;
                a->push_back(d);
                addMember("default", a);
            }
        }
    }

    void JSONSchemaVisitor::visit(const NullElement& e)
    {
        addMember("type", new NullElement);
    }

    void JSONSchemaVisitor::visit(const StringElement& e)
    {
        primitiveType(e);
    }

    void JSONSchemaVisitor::visit(const NumberElement& e)
    {
        primitiveType(e);
    }

    void JSONSchemaVisitor::visit(const BooleanElement& e)
    {
        primitiveType(e);
    }

    IElement* JSONSchemaVisitor::get()
    {
        return pObj;
    }

    IElement* JSONSchemaVisitor::getOwnership()
    {
        IElement* ret = pObj;
        pObj = NULL;
        return ret;
    }

    std::string JSONSchemaVisitor::getSchema(const IElement& e)
    {
        StringElement *str = new StringElement;

        str->renderType(IElement::rCompact);
        str->set("http://json-schema.org/draft-04/schema#");
        addMember("$schema", str);
        setSchemaType("object");

        visit(e);

        sos::SerializeJSON s;
        std::stringstream ss;
        SerializeCompactVisitor sv;

        pObj->content(sv);
        s.process(sv.value(), ss);

        return ss.str();
    }
}
<|endoftext|>


<commit_before>#include "timestamp.h"
#include "text/textParser.tcc"
#include "exceptions/systemException.h"
#include <math.h>

namespace LightSpeed {

	TimeStamp TimeStamp::fromDBTime(ConstStrA dbdate) {
		using namespace LightSpeed;
		TextParser<char, StaticAlloc<256> > parser;
		if (parser(" %u1-%u2-%u3 %u4:%u5:%u6 ",dbdate)) {
			natural yr = parser[1],
				mh = parser[2],
				dy = parser[3],
				hh = parser[4],
				mn = parser[5],
				sc = parser[6];
			return TimeStamp::fromYMDhms(yr,mh,dy,hh,mn,sc);
		} else if (parser(" %u1-%u2-%u3 " ,dbdate)) {
			natural yr = parser[1],
				mh = parser[2],
				dy = parser[3];
			return TimeStamp::fromYMDhms(yr,mh,dy,0,0,0);
		} else if (parser(" %u1:%u2:%u3 ",dbdate)) {
			natural hh = parser[1],
				mn = parser[2],
				sc = parser[3];
			return TimeStamp::fromYMDhms(0,0,0,hh,mn,sc);
		} else {
			throw InvalidDateTimeFormat(THISLOCATION, dbdate);
		}

	}

	static natural fixShortYear(natural year) {
		if (year <= 50) year+=2000;else year+=1900;
		return year;
	}

	static TimeStamp parse8601date(ConstStrA datePart) {
		TextParser<char, StaticAlloc<50> > parse;
		if (datePart.length() == 4) {
			if (!parse("%u1",datePart)) throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, datePart);
			return TimeStamp::fromYMDhms(parse[1],1,1,0,0,0);
		} else if (datePart.length() == 6) {
			if (!parse("%(2,2)u1%%(2,2)u2%%(2,2)u3",datePart)) throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, datePart);
			return TimeStamp::fromYMDhms(fixShortYear(parse[1]),parse[2],parse[3],0,0,0);
		} else if (datePart.length() == 7) {
			//YYYYWww
			if (parse("%u1W%u2",datePart))  {
				//TODO better implementation of week
				return TimeStamp::fromYMDhms(parse[1],1,(natural)parse[2]*7-6,0,0,0);
			//YYYYDDD
			} else if (parse("%(4,4)u1%%u2",datePart))  {
				return TimeStamp::fromYMDhms(parse[1],1,parse[2],0,0,0);
			//YYYY-MM
			} else if (parse("%u1-%u2",datePart))  {
				return TimeStamp::fromYMDhms(parse[1],parse[2],1,0,0,0);
			} else {
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, datePart);
			}
		} else if (datePart.length() == 8) {
			//YY-MM-DD
			if (parse("%u1-%u2-%u3",datePart))  {
				return TimeStamp::fromYMDhms(fixShortYear(parse[1]),parse[2],parse[3],0,0,0);
			//YYYY-Www
			} else if (parse("%u1-W%u2",datePart))  {
				return TimeStamp::fromYMDhms(parse[1],1,(natural)parse[2]*7-6,0,0,0);
			//YYYY-DDD
			} else if (parse("%u1-%u2",datePart))  {
				return TimeStamp::fromYMDhms(parse[1],1,parse[2],0,0,0);
			//YYYYMMDD
			} else if (parse("%(4,4)u1%%(2,2)u2%%(2,2)u3",datePart))  {
				return TimeStamp::fromYMDhms(parse[1],parse[2],parse[3],0,0,0);
			} else {
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, datePart);
			}
		} else if (datePart.length() == 10) {
			//YYYY-MM-DD
			if (parse("%u1-%u2-%u3",datePart))  {
				return TimeStamp::fromYMDhms(parse[1],parse[2],parse[3],0,0,0);
			} else {
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, datePart);
			}
		} else {
			throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, datePart);
		}
	}

	static TimeStamp parse8601time(ConstStrA timePart) {
		TextParser<char, StaticAlloc<50> > parse;

		natural zonepos = timePart.findOneOf(ConstStrA("Z+-"));
		ConstStrA zonespec;
		if (zonepos != naturalNull) {
			zonespec  = timePart.offset(zonepos);
			timePart = timePart.head(zonepos);
		}

		natural dot = timePart.find('.');
		natural millis = 0;
		if (dot != naturalNull) {
			ConstStrA fract = timePart.offset(dot);
			timePart = timePart.head(dot);
			if (parse("%f1",fract)) {
				float f = parse[1];
				millis = (natural)floor(f*TimeStamp::timeResolution);
			}
		}
		TimeStamp res;
		if (timePart.length() == 2) {
			if (parse("%u1",timePart))
				res = TimeStamp::fromYMDhms(0,0,0,parse[1],0,0);
			else
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, timePart);
		} else if (timePart.length() == 4) {
			if (parse("%u(2,2)u1%%(2,2)u2",timePart))
				res = TimeStamp::fromYMDhms(0,0,0,parse[1],parse[2],0);
			else
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, timePart);

		} else if (timePart.length() == 5) {
			if (parse("%u1:%u2",timePart))
				res = TimeStamp::fromYMDhms(0,0,0,parse[1],parse[2],0);
			else
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, timePart);
		} else if (timePart.length() == 6) {
			if (parse("%u(2,2)u1%%(2,2)u2%%(2,2)u3",timePart))
				res = TimeStamp::fromYMDhms(0,0,0,parse[1],parse[2],parse[3]);
			else
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, timePart);

		} else if (timePart.length() == 8) {
			if (parse("%u1:%u2:%u3",timePart))
				res = TimeStamp::fromYMDhms(0,0,0,parse[1],parse[2],parse[3]);
			else
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, timePart);
		}

		res = res + TimeStamp::intervalMSec(millis);
		if (!zonespec.empty()) {
			if (zonespec != "Z") {
				integer zoneofsmin;
				char zonedir = zonespec[0];
				zonespec = zonespec.offset(1);
				if (parse("%u1",zonespec)) {
					zoneofsmin = (natural)parse[1] * 60;
				} else if (parse("%(2,2)u1%%(2,2)u2",zonespec)) {
					zoneofsmin = (natural)parse[1] * 60+(natural)parse[2];
				} else if (parse("%u1%:%u2",zonespec)) {
					zoneofsmin = (natural)parse[1] * 60+(natural)parse[2];
				} else  {
					throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, zonespec);
				}
				TimeStamp ofs = TimeStamp::intervalMin(zoneofsmin);
				if (zonedir == '-') {
					res = res + ofs;
				} else if (zonedir != '+') {
					res = res - ofs;
				} else {
					throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, zonespec);
				}
			}
		}
		return res;

	}

	LightSpeed::TimeStamp TimeStamp::fromISO8601Time( ConstStrA isotime )
	{
		natural sep = isotime.findOneOf(ConstStrA("T "));
		if (sep == naturalNull) sep = isotime.length();
		ConstStrA datePart = isotime.head(sep);
		ConstStrA timePart = isotime.offset(sep+1);

		try {
		TimeStamp date = parse8601date(datePart);
		TimeStamp time = parse8601time(timePart);
		return date + time;
		} catch (Exception &e) {
			throw InvalidDateTimeFormat(THISLOCATION, isotime) << e;
		}
/*

		ConstStrA::Iterator iter = isotime;
		natural year = 0;
		natural month = 0;
		natural day = 0;
		natural hour = 0;
		natural minute = 0;
		natural second = 0;
		natural houroffset = 0;
		natural minuteoffset = 0;
		char sign;

		char c;
		for (natural i = 0; i < 4; i++) {
			c = iter.getNext();
			if (isdigit(c)) year = year*10 + (c - '0');
			else throw InvalidDateTimeFormat(THISLOCATION,isotime);
		}
		c = iter.peek();
		if (c == '-') iter.skip();
		for (natural i = 0; i < 2; i++) {
			c = iter.getNext();
			if (isdigit(c)) month = month * 10 +(c - '0');
			else throw InvalidDateTimeFormat(THISLOCATION,isotime);
		}
		c = iter.peek();
		if (c == '-') iter.skip();
		for (natural i = 0; i < 2; i++) {
			c = iter.getNext();
			if (isdigit(c)) day = day * 10 +(c - '0');
			else throw InvalidDateTimeFormat(THISLOCATION,isotime);
		}
		if (iter.hasItems()) {
			c = iter.getNext();
			if (c != 'T') throw InvalidDateTimeFormat(THISLOCATION,isotime);
			for (natural i = 0; i < 4; i++) {
				c = iter.getNext();
				if (isdigit(c)) hour = hour*10 + (c - '0');
				else throw InvalidDateTimeFormat(THISLOCATION,isotime);
			}
			c = iter.peek();
			if (c == ':') iter.skip();
			c = iter.peek();
			if (isdigit(c)) {
				for (natural i = 0; i < 2; i++) {
					c = iter.getNext();
					if (isdigit(c)) minute = minute * 10 +(c - '0');
					else throw InvalidDateTimeFormat(THISLOCATION,isotime);
				}
				c = iter.peek();
				if (c == ':') iter.skip();
				c = iter.peek();
				if (isdigit(c)) {
					for (natural i = 0; i < 2; i++) {
						c = iter.getNext();
						if (isdigit(c)) second = second * 10 +(c - '0');
						else throw InvalidDateTimeFormat(THISLOCATION,isotime);
					}
				}
			}
		}
*/
	}

	LightSpeed::StringA LightSpeed::TimeStamp::formatTime(ConstStrA format,natural hintBuffer) const {

		if (hintBuffer == 0) hintBuffer = format.length() * 3;
		AutoArray<char> buffer;
		buffer.resize(hintBuffer);
		ConstStrA res = formatTime(buffer,format);
		if (res.empty()) {
			buffer.resize(hintBuffer * 2);
			res = formatTime(buffer,format);
			if (res.empty()) {
				buffer.resize(hintBuffer * 4);
				res = formatTime(buffer,format);
				if (res.empty()) {
					throw ErrNoWithDescException(THISLOCATION,EFAULT,"Failed to create buffer for formatted date");
				}
			}
		}
		return res;

	}

	const char *TimeStamp::message_InvalidDateTimeFormat = "Invalid date/time: %1";

	static const char *DAY_NAMES[] =
	{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
	static const char *MONTH_NAMES[] =
	{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };

	TimeStamp::RFC1123Time TimeStamp::asRFC1123Time() const {

		CArray<char,30> buf;
		formatTime(buf, "%w--, %d %m- %Y %H:%M:%S GMT");
		memcpy(buf.data(), DAY_NAMES[buf[0] - '0'], 3);
		memcpy(buf.data()+8, MONTH_NAMES[(buf[8] - '0') * 10 + (buf[9] - '0')], 3);

		return buf;

	}

	TimeStamp::DBTime TimeStamp::asDBTime() const {
		CArray<char,20> buf;
		return formatTime(buf,"%Y-%m-%d %H:%M:%S");
	}

	TimeStamp::ISO8601Time TimeStamp::asISO8601Time() const
	{
		CArray<char,21> buf;
		return formatTime(buf,"%Y-%m-%dT%H:%M:%SZ");
	}

}
<commit_msg>fixed bug - index out of range while generating RFC1123 time<commit_after>#include "timestamp.h"
#include "text/textParser.tcc"
#include "exceptions/systemException.h"
#include <math.h>

namespace LightSpeed {

	TimeStamp TimeStamp::fromDBTime(ConstStrA dbdate) {
		using namespace LightSpeed;
		TextParser<char, StaticAlloc<256> > parser;
		if (parser(" %u1-%u2-%u3 %u4:%u5:%u6 ",dbdate)) {
			natural yr = parser[1],
				mh = parser[2],
				dy = parser[3],
				hh = parser[4],
				mn = parser[5],
				sc = parser[6];
			return TimeStamp::fromYMDhms(yr,mh,dy,hh,mn,sc);
		} else if (parser(" %u1-%u2-%u3 " ,dbdate)) {
			natural yr = parser[1],
				mh = parser[2],
				dy = parser[3];
			return TimeStamp::fromYMDhms(yr,mh,dy,0,0,0);
		} else if (parser(" %u1:%u2:%u3 ",dbdate)) {
			natural hh = parser[1],
				mn = parser[2],
				sc = parser[3];
			return TimeStamp::fromYMDhms(0,0,0,hh,mn,sc);
		} else {
			throw InvalidDateTimeFormat(THISLOCATION, dbdate);
		}

	}

	static natural fixShortYear(natural year) {
		if (year <= 50) year+=2000;else year+=1900;
		return year;
	}

	static TimeStamp parse8601date(ConstStrA datePart) {
		TextParser<char, StaticAlloc<50> > parse;
		if (datePart.length() == 4) {
			if (!parse("%u1",datePart)) throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, datePart);
			return TimeStamp::fromYMDhms(parse[1],1,1,0,0,0);
		} else if (datePart.length() == 6) {
			if (!parse("%(2,2)u1%%(2,2)u2%%(2,2)u3",datePart)) throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, datePart);
			return TimeStamp::fromYMDhms(fixShortYear(parse[1]),parse[2],parse[3],0,0,0);
		} else if (datePart.length() == 7) {
			//YYYYWww
			if (parse("%u1W%u2",datePart))  {
				//TODO better implementation of week
				return TimeStamp::fromYMDhms(parse[1],1,(natural)parse[2]*7-6,0,0,0);
			//YYYYDDD
			} else if (parse("%(4,4)u1%%u2",datePart))  {
				return TimeStamp::fromYMDhms(parse[1],1,parse[2],0,0,0);
			//YYYY-MM
			} else if (parse("%u1-%u2",datePart))  {
				return TimeStamp::fromYMDhms(parse[1],parse[2],1,0,0,0);
			} else {
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, datePart);
			}
		} else if (datePart.length() == 8) {
			//YY-MM-DD
			if (parse("%u1-%u2-%u3",datePart))  {
				return TimeStamp::fromYMDhms(fixShortYear(parse[1]),parse[2],parse[3],0,0,0);
			//YYYY-Www
			} else if (parse("%u1-W%u2",datePart))  {
				return TimeStamp::fromYMDhms(parse[1],1,(natural)parse[2]*7-6,0,0,0);
			//YYYY-DDD
			} else if (parse("%u1-%u2",datePart))  {
				return TimeStamp::fromYMDhms(parse[1],1,parse[2],0,0,0);
			//YYYYMMDD
			} else if (parse("%(4,4)u1%%(2,2)u2%%(2,2)u3",datePart))  {
				return TimeStamp::fromYMDhms(parse[1],parse[2],parse[3],0,0,0);
			} else {
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, datePart);
			}
		} else if (datePart.length() == 10) {
			//YYYY-MM-DD
			if (parse("%u1-%u2-%u3",datePart))  {
				return TimeStamp::fromYMDhms(parse[1],parse[2],parse[3],0,0,0);
			} else {
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, datePart);
			}
		} else {
			throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, datePart);
		}
	}

	static TimeStamp parse8601time(ConstStrA timePart) {
		TextParser<char, StaticAlloc<50> > parse;

		natural zonepos = timePart.findOneOf(ConstStrA("Z+-"));
		ConstStrA zonespec;
		if (zonepos != naturalNull) {
			zonespec  = timePart.offset(zonepos);
			timePart = timePart.head(zonepos);
		}

		natural dot = timePart.find('.');
		natural millis = 0;
		if (dot != naturalNull) {
			ConstStrA fract = timePart.offset(dot);
			timePart = timePart.head(dot);
			if (parse("%f1",fract)) {
				float f = parse[1];
				millis = (natural)floor(f*TimeStamp::timeResolution);
			}
		}
		TimeStamp res;
		if (timePart.length() == 2) {
			if (parse("%u1",timePart))
				res = TimeStamp::fromYMDhms(0,0,0,parse[1],0,0);
			else
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, timePart);
		} else if (timePart.length() == 4) {
			if (parse("%u(2,2)u1%%(2,2)u2",timePart))
				res = TimeStamp::fromYMDhms(0,0,0,parse[1],parse[2],0);
			else
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, timePart);

		} else if (timePart.length() == 5) {
			if (parse("%u1:%u2",timePart))
				res = TimeStamp::fromYMDhms(0,0,0,parse[1],parse[2],0);
			else
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, timePart);
		} else if (timePart.length() == 6) {
			if (parse("%u(2,2)u1%%(2,2)u2%%(2,2)u3",timePart))
				res = TimeStamp::fromYMDhms(0,0,0,parse[1],parse[2],parse[3]);
			else
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, timePart);

		} else if (timePart.length() == 8) {
			if (parse("%u1:%u2:%u3",timePart))
				res = TimeStamp::fromYMDhms(0,0,0,parse[1],parse[2],parse[3]);
			else
				throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, timePart);
		}

		res = res + TimeStamp::intervalMSec(millis);
		if (!zonespec.empty()) {
			if (zonespec != "Z") {
				integer zoneofsmin;
				char zonedir = zonespec[0];
				zonespec = zonespec.offset(1);
				if (parse("%u1",zonespec)) {
					zoneofsmin = (natural)parse[1] * 60;
				} else if (parse("%(2,2)u1%%(2,2)u2",zonespec)) {
					zoneofsmin = (natural)parse[1] * 60+(natural)parse[2];
				} else if (parse("%u1%:%u2",zonespec)) {
					zoneofsmin = (natural)parse[1] * 60+(natural)parse[2];
				} else  {
					throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, zonespec);
				}
				TimeStamp ofs = TimeStamp::intervalMin(zoneofsmin);
				if (zonedir == '-') {
					res = res + ofs;
				} else if (zonedir != '+') {
					res = res - ofs;
				} else {
					throw TimeStamp::InvalidDateTimeFormat(THISLOCATION, zonespec);
				}
			}
		}
		return res;

	}

	LightSpeed::TimeStamp TimeStamp::fromISO8601Time( ConstStrA isotime )
	{
		natural sep = isotime.findOneOf(ConstStrA("T "));
		if (sep == naturalNull) sep = isotime.length();
		ConstStrA datePart = isotime.head(sep);
		ConstStrA timePart = isotime.offset(sep+1);

		try {
		TimeStamp date = parse8601date(datePart);
		TimeStamp time = parse8601time(timePart);
		return date + time;
		} catch (Exception &e) {
			throw InvalidDateTimeFormat(THISLOCATION, isotime) << e;
		}
/*

		ConstStrA::Iterator iter = isotime;
		natural year = 0;
		natural month = 0;
		natural day = 0;
		natural hour = 0;
		natural minute = 0;
		natural second = 0;
		natural houroffset = 0;
		natural minuteoffset = 0;
		char sign;

		char c;
		for (natural i = 0; i < 4; i++) {
			c = iter.getNext();
			if (isdigit(c)) year = year*10 + (c - '0');
			else throw InvalidDateTimeFormat(THISLOCATION,isotime);
		}
		c = iter.peek();
		if (c == '-') iter.skip();
		for (natural i = 0; i < 2; i++) {
			c = iter.getNext();
			if (isdigit(c)) month = month * 10 +(c - '0');
			else throw InvalidDateTimeFormat(THISLOCATION,isotime);
		}
		c = iter.peek();
		if (c == '-') iter.skip();
		for (natural i = 0; i < 2; i++) {
			c = iter.getNext();
			if (isdigit(c)) day = day * 10 +(c - '0');
			else throw InvalidDateTimeFormat(THISLOCATION,isotime);
		}
		if (iter.hasItems()) {
			c = iter.getNext();
			if (c != 'T') throw InvalidDateTimeFormat(THISLOCATION,isotime);
			for (natural i = 0; i < 4; i++) {
				c = iter.getNext();
				if (isdigit(c)) hour = hour*10 + (c - '0');
				else throw InvalidDateTimeFormat(THISLOCATION,isotime);
			}
			c = iter.peek();
			if (c == ':') iter.skip();
			c = iter.peek();
			if (isdigit(c)) {
				for (natural i = 0; i < 2; i++) {
					c = iter.getNext();
					if (isdigit(c)) minute = minute * 10 +(c - '0');
					else throw InvalidDateTimeFormat(THISLOCATION,isotime);
				}
				c = iter.peek();
				if (c == ':') iter.skip();
				c = iter.peek();
				if (isdigit(c)) {
					for (natural i = 0; i < 2; i++) {
						c = iter.getNext();
						if (isdigit(c)) second = second * 10 +(c - '0');
						else throw InvalidDateTimeFormat(THISLOCATION,isotime);
					}
				}
			}
		}
*/
	}

	LightSpeed::StringA LightSpeed::TimeStamp::formatTime(ConstStrA format,natural hintBuffer) const {

		if (hintBuffer == 0) hintBuffer = format.length() * 3;
		AutoArray<char> buffer;
		buffer.resize(hintBuffer);
		ConstStrA res = formatTime(buffer,format);
		if (res.empty()) {
			buffer.resize(hintBuffer * 2);
			res = formatTime(buffer,format);
			if (res.empty()) {
				buffer.resize(hintBuffer * 4);
				res = formatTime(buffer,format);
				if (res.empty()) {
					throw ErrNoWithDescException(THISLOCATION,EFAULT,"Failed to create buffer for formatted date");
				}
			}
		}
		return res;

	}

	const char *TimeStamp::message_InvalidDateTimeFormat = "Invalid date/time: %1";

	static const char *DAY_NAMES[] =
	{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
	static const char *MONTH_NAMES[] =
	{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };

	TimeStamp::RFC1123Time TimeStamp::asRFC1123Time() const {

		CArray<char,30> buf;
		formatTime(buf, "%w--, %d %m- %Y %H:%M:%S GMT");
		memcpy(buf.data(), DAY_NAMES[buf[0] - '0'], 3);
		memcpy(buf.data()+8, MONTH_NAMES[(buf[8] - '0') * 10 + (buf[9] - '0') -1 ], 3);

		return buf;

	}

	TimeStamp::DBTime TimeStamp::asDBTime() const {
		CArray<char,20> buf;
		return formatTime(buf,"%Y-%m-%d %H:%M:%S");
	}

	TimeStamp::ISO8601Time TimeStamp::asISO8601Time() const
	{
		CArray<char,21> buf;
		return formatTime(buf,"%Y-%m-%dT%H:%M:%SZ");
	}

}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qgeotiledmapdata.h"
#include "qgeotiledmapdata_p.h"

#include "qgeotiledmappingmanagerengine.h"
#include "qgeocoordinate.h"

#include <QDebug>

#define DEFAULT_ZOOMLEVEL 8
#define PI 3.14159265
#include <math.h>

QTM_BEGIN_NAMESPACE

QGeoTiledMapData::QGeoTiledMapData(QGeoMappingManagerEngine *engine, QGeoMapWidget *widget)
        : QGeoMapData(engine, widget),
        d_ptr(new QGeoTiledMapDataPrivate())
{
    QGeoTiledMappingManagerEngine *tileEngine = static_cast<QGeoTiledMappingManagerEngine *>(QGeoMapData::engine());
    QGeoMapData::setZoomLevel(DEFAULT_ZOOMLEVEL);
    d_ptr->width = (1 << DEFAULT_ZOOMLEVEL) * tileEngine->tileSize().width();
    d_ptr->height = (1 << DEFAULT_ZOOMLEVEL) * tileEngine->tileSize().height();
}

QGeoTiledMapData::~QGeoTiledMapData()
{
}

QPointF QGeoTiledMapData::coordinateToScreenPosition(const QGeoCoordinate &coordinate) const
{
    qulonglong worldX;
    qulonglong worldY;

    coordinateToWorldPixel(coordinate, &worldX, &worldY);
    QPointF pos(worldX, worldY);
    pos -= d_ptr->screenRect.topLeft();
    return pos;
}

QGeoCoordinate QGeoTiledMapData::screenPositionToCoordinate(const QPointF &screenPosition) const
{
    qulonglong worldX = static_cast<qulonglong>(d_ptr->screenRect.left() + screenPosition.x()) % d_ptr->width;
    qulonglong worldY = static_cast<qulonglong>(d_ptr->screenRect.top() + screenPosition.y()) % d_ptr->height;

    return worldPixelToCoordinate(worldX, worldY);
}

/*!
    Returns the (row,col) index of the tile that \a screenPosition lies on.
    The screen position (0,0) represents the top-left corner of the current map view.
*/
QPoint QGeoTiledMapData::screenPositionToTileIndices(const QPointF &screenPosition) const
{
    //TODO: add some type checking
    QGeoTiledMappingManagerEngine *tileEngine = static_cast<QGeoTiledMappingManagerEngine *>(QGeoMapData::engine());
    QPointF pos = d_ptr->screenRect.topLeft() + screenPosition;

    int tileX = pos.x() / tileEngine->tileSize().width();
    int tileY = pos.y() / tileEngine->tileSize().height();

    return QPoint(tileX, tileY);
}

void QGeoTiledMapData::coordinateToWorldPixel(const QGeoCoordinate &coordinate, qulonglong *x, qulonglong *y) const
{
    double lng = coordinate.longitude(); //x
    double lat = coordinate.latitude(); //y

    lng = lng / 360.0 + 0.5;

    lat = 0.5 - (log(tan((PI / 4.0) + (PI / 2.0) * lat / 180.0)) / PI) / 2.0;
    lat = qMax(0.0, lat);
    lat = qMin(1.0, lat);

    *x = qRound64(lng * qreal(d_ptr->width));
    *y = qRound64(lat * qreal(d_ptr->height));
}

qreal rmod(const qreal a, const qreal b)
{
    quint64 div = static_cast<quint64>(a / b);
    return a - static_cast<qreal>(div) * b;
}

QGeoCoordinate QGeoTiledMapData::worldPixelToCoordinate(qulonglong x, qulonglong y) const
{
    qreal fx = qreal(x) / qreal(d_ptr->width);
    qreal fy = qreal(y) / qreal(d_ptr->height);

    if (fy < 0.0f)
        fy = 0.0f;
    else if (fy > 1.0f)
        fy = 1.0f;

    qreal lat;

    if (fy == 0.0f)
        lat = 90.0f;
    else if (fy == 1.0f)
        lat = -90.0f;
    else
        lat = (180.0f / PI) * (2.0f * atan(exp(PI * (1.0f - 2.0f * fy))) - (PI / 2.0f));

    qreal lng;
    if (fx >= 0) {
        lng = rmod(fx, 1.0f);
    } else {
        lng = rmod(1.0f - rmod(-1.0f * fx, 1.0f), 1.0f);
    }

    lng = lng * 360.0f - 180.0f;

    return QGeoCoordinate(lat, lng);
}

void QGeoTiledMapData::setCenter(const QGeoCoordinate &center)
{
    d_ptr->protectRegion = QRectF();
    qulonglong x;
    qulonglong y;
    coordinateToWorldPixel(center, &x, &y);
    d_ptr->screenRect.moveCenter(QPointF(x, y));
    d_ptr->screenRect.moveLeft(qRound64(d_ptr->screenRect.left()));
    d_ptr->screenRect.moveTop(qRound64(d_ptr->screenRect.top()));
}

QGeoCoordinate QGeoTiledMapData::center() const
{
    QPointF center = d_ptr->screenRect.center();
    return worldPixelToCoordinate(center.x(), center.y());
}

void QGeoTiledMapData::setZoomLevel(qreal zoomLevel)
{
    qreal oldZoomLevel = QGeoMapData::zoomLevel();

    QGeoMapData::setZoomLevel(zoomLevel);

    // QGeoMapData::setZoomLevel clips the zoom level to be
    // in between the minimum and maximum zoom levels
    zoomLevel = QGeoMapData::zoomLevel();

    int zoomDiff = qRound(zoomLevel - oldZoomLevel);

    if (zoomDiff == 0)
        return;

    d_ptr->protectRegion = QRectF();

    //compute new screenRect
    qreal ratioX = d_ptr->screenRect.center().x() / d_ptr->width;
    qreal ratioY = d_ptr->screenRect.center().y() / d_ptr->height;
    //TODO: add some type checking
    QGeoTiledMappingManagerEngine *tileEngine = static_cast<QGeoTiledMappingManagerEngine *>(QGeoMapData::engine());
    d_ptr->width = (1 << static_cast<int>(zoomLevel)) * tileEngine->tileSize().width();
    d_ptr->height = (1 << static_cast<int>(zoomLevel)) * tileEngine->tileSize().height();
    QPointF newCenter(qRound(ratioX * d_ptr->width), qRound(ratioY * d_ptr->height));
    d_ptr->screenRect.moveCenter(newCenter);

    //scale old image
    QRectF target = QGeoMapData::mapImage().rect();
    qreal width = target.width() / (1 << qAbs(zoomDiff));
    qreal height = target.width() / (1 << qAbs(zoomDiff));
    qreal x = target.x() + ((target.width() - width) / 2.0);
    qreal y = target.y() + ((target.height() - height) / 2.0);
    QRectF source = QRectF(x, y, width, height);

    QPixmap pm(QGeoMapData::mapImage().size());
    QPainter painter(&pm);

    if (zoomDiff < 0) {
        painter.drawPixmap(source, QGeoMapData::mapImage(), target);
    } else {
        painter.drawPixmap(target, QGeoMapData::mapImage(), source);
    }

    setMapImage(pm);
}

void QGeoTiledMapData::setViewportSize(const QSizeF &size)
{
    d_ptr->protectRegion = d_ptr->screenRect;
    d_ptr->screenRect.setSize(size);
    QGeoMapData::setViewportSize(size);

    QPixmap pm(size.toSize());
    QPainter p(&pm);
    if (!QGeoMapData::mapImage().isNull())
        p.drawPixmap(QGeoMapData::mapImage().rect(), QGeoMapData::mapImage(), QGeoMapData::mapImage().rect());
    setMapImage(pm);
}

void QGeoTiledMapData::pan(int dx, int dy)
{
    QRectF oldScreenRect(d_ptr->screenRect);
    d_ptr->screenRect.translate(dx, dy);

    //Have we crossed the dateline from east-->west (i.e. "left edge")
    while (d_ptr->screenRect.left() < 0) {
        d_ptr->screenRect.translate(d_ptr->width, 0);
    }

    //Have we crossed the dateline from west-->east (i.e. "right edge")
    if (d_ptr->screenRect.left()>= d_ptr->width) {
        d_ptr->screenRect.moveLeft(static_cast<qulonglong>(d_ptr->screenRect.left()) % d_ptr->width);
    }

    qreal deltaX = oldScreenRect.left() - d_ptr->screenRect.left();
    qreal deltaY = oldScreenRect.top() - d_ptr->screenRect.top();
    qreal sx;
    qreal sy;
    qreal tx;
    qreal ty;

    //TODO: make this work in case we wrapped around the date line
    if (deltaX >= 0) {
        sx = 0.0;
        tx = deltaX;
    } else {
        sx = qAbs(deltaX);
        tx = 0.0;
    }

    if (deltaY >= 0) {
        sy = 0.0;
        ty = deltaY;
    } else {
        sy = qAbs(deltaY);
        ty = 0.0;
    }

    QRectF source = QRectF(sx, sy, QGeoMapData::mapImage().width(), QGeoMapData::mapImage().height());
    QRectF target = QRectF(tx, ty, QGeoMapData::mapImage().width(), QGeoMapData::mapImage().height());

    QPixmap pm(QGeoMapData::mapImage().size());
    QPainter p(&pm);
    if (!QGeoMapData::mapImage().isNull()) {
        p.drawPixmap(target, QGeoMapData::mapImage(), source);
        //TODO: is this correct?
        d_ptr->protectRegion = target.translated(d_ptr->screenRect.topLeft());
        setMapImage(pm);
    }
}

QRectF QGeoTiledMapData::screenRect() const
{
    return d_ptr->screenRect;
}

QRectF QGeoTiledMapData::protectedRegion() const
{
    return d_ptr->protectRegion;
}

void QGeoTiledMapData::clearProtectedRegion()
{
    d_ptr->protectRegion = QRectF();
}

QList<QGeoMapObject*> QGeoTiledMapData::visibleMapObjects()
{
    return QList<QGeoMapObject*>();
}

QList<QGeoMapObject*> QGeoTiledMapData::mapObjectsAtScreenPosition(const QPointF &screenPosition, int radius)
{
    return QList<QGeoMapObject*>();
}

QList<QGeoMapObject*> QGeoTiledMapData::mapObjectsInScreenRect(const QRectF &screenRect)
{
    return QList<QGeoMapObject*>();
}

/*******************************************************************************
*******************************************************************************/

QGeoTiledMapDataPrivate::QGeoTiledMapDataPrivate() {}

QGeoTiledMapDataPrivate::QGeoTiledMapDataPrivate(const QGeoTiledMapDataPrivate &other)
        : width(other.width),
        height(other.height),
        protectRegion(other.protectRegion),
        screenRect(other.screenRect) {}

QGeoTiledMapDataPrivate::~QGeoTiledMapDataPrivate() {}

QGeoTiledMapDataPrivate& QGeoTiledMapDataPrivate::operator= (const QGeoTiledMapDataPrivate & other)
{
    width = other.width;
    height = other.height;
    protectRegion = other.protectRegion;
    screenRect = other.screenRect;

    return *this;
}

QTM_END_NAMESPACE
<commit_msg>Fixed scrambled line issue after zoomLevel change<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qgeotiledmapdata.h"
#include "qgeotiledmapdata_p.h"

#include "qgeotiledmappingmanagerengine.h"
#include "qgeocoordinate.h"

#include <QDebug>

#define DEFAULT_ZOOMLEVEL 8
#define PI 3.14159265
#include <math.h>

QTM_BEGIN_NAMESPACE

QGeoTiledMapData::QGeoTiledMapData(QGeoMappingManagerEngine *engine, QGeoMapWidget *widget)
        : QGeoMapData(engine, widget),
        d_ptr(new QGeoTiledMapDataPrivate())
{
    QGeoTiledMappingManagerEngine *tileEngine = static_cast<QGeoTiledMappingManagerEngine *>(QGeoMapData::engine());
    QGeoMapData::setZoomLevel(DEFAULT_ZOOMLEVEL);
    d_ptr->width = (1 << DEFAULT_ZOOMLEVEL) * tileEngine->tileSize().width();
    d_ptr->height = (1 << DEFAULT_ZOOMLEVEL) * tileEngine->tileSize().height();
}

QGeoTiledMapData::~QGeoTiledMapData()
{
}

QPointF QGeoTiledMapData::coordinateToScreenPosition(const QGeoCoordinate &coordinate) const
{
    qulonglong worldX;
    qulonglong worldY;

    coordinateToWorldPixel(coordinate, &worldX, &worldY);
    QPointF pos(worldX, worldY);
    pos -= d_ptr->screenRect.topLeft();
    return pos;
}

QGeoCoordinate QGeoTiledMapData::screenPositionToCoordinate(const QPointF &screenPosition) const
{
    qulonglong worldX = static_cast<qulonglong>(d_ptr->screenRect.left() + screenPosition.x()) % d_ptr->width;
    qulonglong worldY = static_cast<qulonglong>(d_ptr->screenRect.top() + screenPosition.y()) % d_ptr->height;

    return worldPixelToCoordinate(worldX, worldY);
}

/*!
    Returns the (row,col) index of the tile that \a screenPosition lies on.
    The screen position (0,0) represents the top-left corner of the current map view.
*/
QPoint QGeoTiledMapData::screenPositionToTileIndices(const QPointF &screenPosition) const
{
    //TODO: add some type checking
    QGeoTiledMappingManagerEngine *tileEngine = static_cast<QGeoTiledMappingManagerEngine *>(QGeoMapData::engine());
    QPointF pos = d_ptr->screenRect.topLeft() + screenPosition;

    int tileX = pos.x() / tileEngine->tileSize().width();
    int tileY = pos.y() / tileEngine->tileSize().height();

    return QPoint(tileX, tileY);
}

void QGeoTiledMapData::coordinateToWorldPixel(const QGeoCoordinate &coordinate, qulonglong *x, qulonglong *y) const
{
    double lng = coordinate.longitude(); //x
    double lat = coordinate.latitude(); //y

    lng = lng / 360.0 + 0.5;

    lat = 0.5 - (log(tan((PI / 4.0) + (PI / 2.0) * lat / 180.0)) / PI) / 2.0;
    lat = qMax(0.0, lat);
    lat = qMin(1.0, lat);

    *x = qRound64(lng * qreal(d_ptr->width));
    *y = qRound64(lat * qreal(d_ptr->height));
}

qreal rmod(const qreal a, const qreal b)
{
    quint64 div = static_cast<quint64>(a / b);
    return a - static_cast<qreal>(div) * b;
}

QGeoCoordinate QGeoTiledMapData::worldPixelToCoordinate(qulonglong x, qulonglong y) const
{
    qreal fx = qreal(x) / qreal(d_ptr->width);
    qreal fy = qreal(y) / qreal(d_ptr->height);

    if (fy < 0.0f)
        fy = 0.0f;
    else if (fy > 1.0f)
        fy = 1.0f;

    qreal lat;

    if (fy == 0.0f)
        lat = 90.0f;
    else if (fy == 1.0f)
        lat = -90.0f;
    else
        lat = (180.0f / PI) * (2.0f * atan(exp(PI * (1.0f - 2.0f * fy))) - (PI / 2.0f));

    qreal lng;
    if (fx >= 0) {
        lng = rmod(fx, 1.0f);
    } else {
        lng = rmod(1.0f - rmod(-1.0f * fx, 1.0f), 1.0f);
    }

    lng = lng * 360.0f - 180.0f;

    return QGeoCoordinate(lat, lng);
}

void QGeoTiledMapData::setCenter(const QGeoCoordinate &center)
{
    d_ptr->protectRegion = QRectF();
    qulonglong x;
    qulonglong y;
    coordinateToWorldPixel(center, &x, &y);
    d_ptr->screenRect.moveCenter(QPointF(x, y));
    d_ptr->screenRect.moveLeft(qRound64(d_ptr->screenRect.left()));
    d_ptr->screenRect.moveTop(qRound64(d_ptr->screenRect.top()));
}

QGeoCoordinate QGeoTiledMapData::center() const
{
    QPointF center = d_ptr->screenRect.center();
    return worldPixelToCoordinate(center.x(), center.y());
}

void QGeoTiledMapData::setZoomLevel(qreal zoomLevel)
{
    qreal oldZoomLevel = QGeoMapData::zoomLevel();

    QGeoMapData::setZoomLevel(zoomLevel);

    // QGeoMapData::setZoomLevel clips the zoom level to be
    // in between the minimum and maximum zoom levels
    zoomLevel = QGeoMapData::zoomLevel();

    int zoomDiff = qRound(zoomLevel - oldZoomLevel);

    if (zoomDiff == 0)
        return;

    d_ptr->protectRegion = QRectF();

    QGeoCoordinate currCenter = center();
    //TODO: add some type checking
    QGeoTiledMappingManagerEngine *tileEngine = static_cast<QGeoTiledMappingManagerEngine *>(QGeoMapData::engine());
    d_ptr->width = (1 << static_cast<int>(zoomLevel)) * tileEngine->tileSize().width();
    d_ptr->height = (1 << static_cast<int>(zoomLevel)) * tileEngine->tileSize().height();

    setCenter(currCenter);

    //scale old image
    QRectF target = QGeoMapData::mapImage().rect();
    qreal width = target.width() / (1 << qAbs(zoomDiff));
    qreal height = target.width() / (1 << qAbs(zoomDiff));
    qreal x = target.x() + ((target.width() - width) / 2.0);
    qreal y = target.y() + ((target.height() - height) / 2.0);
    QRectF source = QRectF(x, y, width, height);

    QPixmap pm(QGeoMapData::mapImage().size());
    QPainter painter(&pm);

    if (zoomDiff < 0) {
        painter.drawPixmap(source, QGeoMapData::mapImage(), target);
    } else {
        painter.drawPixmap(target, QGeoMapData::mapImage(), source);
    }

    setMapImage(pm);
}

void QGeoTiledMapData::setViewportSize(const QSizeF &size)
{
    d_ptr->protectRegion = d_ptr->screenRect;
    d_ptr->screenRect.setSize(size);
    QGeoMapData::setViewportSize(size);

    QPixmap pm(size.toSize());
    QPainter p(&pm);
    if (!QGeoMapData::mapImage().isNull())
        p.drawPixmap(QGeoMapData::mapImage().rect(), QGeoMapData::mapImage(), QGeoMapData::mapImage().rect());
    setMapImage(pm);
}

void QGeoTiledMapData::pan(int dx, int dy)
{
    QRectF oldScreenRect(d_ptr->screenRect);
    d_ptr->screenRect.translate(dx, dy);

    //Have we crossed the dateline from east-->west (i.e. "left edge")
    while (d_ptr->screenRect.left() < 0) {
        d_ptr->screenRect.translate(d_ptr->width, 0);
    }

    //Have we crossed the dateline from west-->east (i.e. "right edge")
    if (d_ptr->screenRect.left()>= d_ptr->width) {
        d_ptr->screenRect.moveLeft(static_cast<qulonglong>(d_ptr->screenRect.left()) % d_ptr->width);
    }

    qreal deltaX = oldScreenRect.left() - d_ptr->screenRect.left();
    qreal deltaY = oldScreenRect.top() - d_ptr->screenRect.top();
    qreal sx;
    qreal sy;
    qreal tx;
    qreal ty;

    //TODO: make this work in case we wrapped around the date line
    if (deltaX >= 0) {
        sx = 0.0;
        tx = deltaX;
    } else {
        sx = qAbs(deltaX);
        tx = 0.0;
    }

    if (deltaY >= 0) {
        sy = 0.0;
        ty = deltaY;
    } else {
        sy = qAbs(deltaY);
        ty = 0.0;
    }

    QRectF source = QRectF(sx, sy, QGeoMapData::mapImage().width(), QGeoMapData::mapImage().height());
    QRectF target = QRectF(tx, ty, QGeoMapData::mapImage().width(), QGeoMapData::mapImage().height());

    QPixmap pm(QGeoMapData::mapImage().size());
    QPainter p(&pm);
    if (!QGeoMapData::mapImage().isNull()) {
        p.drawPixmap(target, QGeoMapData::mapImage(), source);
        //TODO: is this correct?
        d_ptr->protectRegion = target.translated(d_ptr->screenRect.topLeft());
        setMapImage(pm);
    }
}

QRectF QGeoTiledMapData::screenRect() const
{
    return d_ptr->screenRect;
}

QRectF QGeoTiledMapData::protectedRegion() const
{
    return d_ptr->protectRegion;
}

void QGeoTiledMapData::clearProtectedRegion()
{
    d_ptr->protectRegion = QRectF();
}

QList<QGeoMapObject*> QGeoTiledMapData::visibleMapObjects()
{
    return QList<QGeoMapObject*>();
}

QList<QGeoMapObject*> QGeoTiledMapData::mapObjectsAtScreenPosition(const QPointF &screenPosition, int radius)
{
    return QList<QGeoMapObject*>();
}

QList<QGeoMapObject*> QGeoTiledMapData::mapObjectsInScreenRect(const QRectF &screenRect)
{
    return QList<QGeoMapObject*>();
}

/*******************************************************************************
*******************************************************************************/

QGeoTiledMapDataPrivate::QGeoTiledMapDataPrivate() {}

QGeoTiledMapDataPrivate::QGeoTiledMapDataPrivate(const QGeoTiledMapDataPrivate &other)
        : width(other.width),
        height(other.height),
        protectRegion(other.protectRegion),
        screenRect(other.screenRect) {}

QGeoTiledMapDataPrivate::~QGeoTiledMapDataPrivate() {}

QGeoTiledMapDataPrivate& QGeoTiledMapDataPrivate::operator= (const QGeoTiledMapDataPrivate & other)
{
    width = other.width;
    height = other.height;
    protectRegion = other.protectRegion;
    screenRect = other.screenRect;

    return *this;
}

QTM_END_NAMESPACE
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011-2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "VisitorUtils.hpp"

#include "ltac/Statement.hpp"
#include "ltac/PseudoRegister.hpp"
#include "ltac/PseudoFloatRegister.hpp"
#include "ltac/LiveRegistersProblem.hpp"

using namespace eddic;

typedef ltac::LiveRegistersProblem::ProblemDomain ProblemDomain;

void ltac::LiveRegisterValues::insert(ltac::PseudoRegister reg){
    registers.insert(reg);
}

void ltac::LiveRegisterValues::insert(ltac::PseudoFloatRegister reg){
    float_registers.insert(reg);
}

void ltac::LiveRegisterValues::erase(ltac::PseudoRegister reg){
    registers.erase(reg);
}

void ltac::LiveRegisterValues::erase(ltac::PseudoFloatRegister reg){
    float_registers.erase(reg);
}

std::size_t ltac::LiveRegisterValues::size(){
    return (static_cast<std::size_t>(std::numeric_limits<unsigned short>::max()) + 1) * registers.size() + float_registers.size();
}

std::ostream& ltac::operator<<(std::ostream& stream, ltac::LiveRegisterValues& value){
    stream << "set{";

    for(auto& v : value.registers){
        stream << v << ", ";
    }

    for(auto& v : value.float_registers){
        stream << v << ", ";
    }

    return stream << "}";
}

ProblemDomain ltac::LiveRegistersProblem::Boundary(mtac::function_p /*function*/){
    auto value = default_element();
    return value;
}

ProblemDomain ltac::LiveRegistersProblem::Init(mtac::function_p /*function*/){
    auto value = default_element();
    return value;
}

ProblemDomain ltac::LiveRegistersProblem::meet(ProblemDomain& in, ProblemDomain& out){
    if(out.top()){
        return in;
    } else if(in.top()){
        return out;
    }

    typename ProblemDomain::Values values;
    ProblemDomain result(values);

    for(auto& value : in.values().registers){
        result.values().insert(value);
    }

    for(auto& value : in.values().float_registers){
        result.values().insert(value);
    }

    for(auto& value : out.values().registers){
        result.values().insert(value);
    }

    for(auto& value : out.values().float_registers){
        result.values().insert(value);
    }

    return result;
}

namespace {

struct LivenessCollector : public boost::static_visitor<> {
    ProblemDomain& in;

    LivenessCollector(ProblemDomain& in) : in(in) {}

    template<typename Arg>
    inline void set_live(Arg& arg){
        if(auto* ptr = boost::get<ltac::PseudoRegister>(&arg)){
            in.values().insert(*ptr);
        } else if(auto* ptr = boost::get<ltac::PseudoFloatRegister>(&arg)){
            in.values().insert(*ptr);
        } else if(auto* ptr = boost::get<ltac::Address>(&arg)){
            set_live_opt(ptr->base_register);
            set_live_opt(ptr->scaled_register);
        }
    }

    template<typename Arg>
    inline void set_dead(Arg& arg){
        if(auto* ptr = boost::get<ltac::PseudoRegister>(&arg)){
            in.values().erase(*ptr);
        } else if(auto* ptr = boost::get<ltac::PseudoFloatRegister>(&arg)){
            in.values().erase(*ptr);
        }
    }

    template<typename Arg>
    inline void set_live_opt(Arg& arg){
        if(arg){
            set_live(*arg);
        }
    }

    void operator()(std::shared_ptr<ltac::Instruction> instruction){
        if(instruction->op != ltac::Operator::NOP){
            if(ltac::erase_result_complete(instruction->op)){
                set_dead(*instruction->arg1);
            } else {
                set_live_opt(instruction->arg1);
            }

            set_live_opt(instruction->arg2);
            set_live_opt(instruction->arg3);
        }

        for(auto& reg : instruction->uses){
            in.values().insert(reg);
        }

        for(auto& reg : instruction->float_uses){
            in.values().insert(reg);
        }
    }

    void operator()(std::shared_ptr<ltac::Jump> instruction){
        for(auto& reg : instruction->uses){
            in.values().insert(reg);
        }

        for(auto& reg : instruction->float_uses){
            in.values().insert(reg);
        }

        for(auto& reg : instruction->kills){
            in.values().erase(reg);
        }

        for(auto& reg : instruction->float_kills){
            in.values().erase(reg);
        }
    }

    template<typename T>
    void operator()(T&){
        //Nothing to do
    }
};

} //End of anonymous namespace

ProblemDomain ltac::LiveRegistersProblem::transfer(mtac::basic_block_p /*basic_block*/, ltac::Statement& statement, ProblemDomain& in){
    auto out = in;

    LivenessCollector collector(out);
    visit(collector, statement);

    return out;
}

bool ltac::LiveRegistersProblem::optimize(ltac::Statement& /*statement*/, std::shared_ptr<mtac::DataFlowResults<ProblemDomain>> /*results*/){
    //This analysis is only made to gather information, not to optimize anything
    throw "Unimplemented";
}
<commit_msg>An operation erasing the result, does not erase it if it an address<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011-2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "VisitorUtils.hpp"

#include "ltac/Statement.hpp"
#include "ltac/PseudoRegister.hpp"
#include "ltac/PseudoFloatRegister.hpp"
#include "ltac/LiveRegistersProblem.hpp"

using namespace eddic;

typedef ltac::LiveRegistersProblem::ProblemDomain ProblemDomain;

void ltac::LiveRegisterValues::insert(ltac::PseudoRegister reg){
    registers.insert(reg);
}

void ltac::LiveRegisterValues::insert(ltac::PseudoFloatRegister reg){
    float_registers.insert(reg);
}

void ltac::LiveRegisterValues::erase(ltac::PseudoRegister reg){
    registers.erase(reg);
}

void ltac::LiveRegisterValues::erase(ltac::PseudoFloatRegister reg){
    float_registers.erase(reg);
}

std::size_t ltac::LiveRegisterValues::size(){
    return (static_cast<std::size_t>(std::numeric_limits<unsigned short>::max()) + 1) * registers.size() + float_registers.size();
}

std::ostream& ltac::operator<<(std::ostream& stream, ltac::LiveRegisterValues& value){
    stream << "set{";

    for(auto& v : value.registers){
        stream << v << ", ";
    }

    for(auto& v : value.float_registers){
        stream << v << ", ";
    }

    return stream << "}";
}

ProblemDomain ltac::LiveRegistersProblem::Boundary(mtac::function_p /*function*/){
    auto value = default_element();
    return value;
}

ProblemDomain ltac::LiveRegistersProblem::Init(mtac::function_p /*function*/){
    auto value = default_element();
    return value;
}

ProblemDomain ltac::LiveRegistersProblem::meet(ProblemDomain& in, ProblemDomain& out){
    if(out.top()){
        return in;
    } else if(in.top()){
        return out;
    }

    typename ProblemDomain::Values values;
    ProblemDomain result(values);

    for(auto& value : in.values().registers){
        result.values().insert(value);
    }

    for(auto& value : in.values().float_registers){
        result.values().insert(value);
    }

    for(auto& value : out.values().registers){
        result.values().insert(value);
    }

    for(auto& value : out.values().float_registers){
        result.values().insert(value);
    }

    return result;
}

namespace {

struct LivenessCollector : public boost::static_visitor<> {
    ProblemDomain& in;

    LivenessCollector(ProblemDomain& in) : in(in) {}

    template<typename Arg>
    inline void set_live(Arg& arg){
        if(auto* ptr = boost::get<ltac::PseudoRegister>(&arg)){
            in.values().insert(*ptr);
        } else if(auto* ptr = boost::get<ltac::PseudoFloatRegister>(&arg)){
            in.values().insert(*ptr);
        } else if(auto* ptr = boost::get<ltac::Address>(&arg)){
            set_live_opt(ptr->base_register);
            set_live_opt(ptr->scaled_register);
        }
    }

    template<typename Arg>
    inline void set_dead(Arg& arg){
        if(auto* ptr = boost::get<ltac::PseudoRegister>(&arg)){
            in.values().erase(*ptr);
        } else if(auto* ptr = boost::get<ltac::PseudoFloatRegister>(&arg)){
            in.values().erase(*ptr);
        }
    }

    template<typename Arg>
    inline void set_live_opt(Arg& arg){
        if(arg){
            set_live(*arg);
        }
    }

    void operator()(std::shared_ptr<ltac::Instruction> instruction){
        if(instruction->op != ltac::Operator::NOP){
            if(ltac::erase_result_complete(instruction->op)){
                if(auto* ptr = boost::get<ltac::Address>(&*instruction->arg1)){
                    set_live_opt(ptr->base_register);
                    set_live_opt(ptr->scaled_register);
                } else {
                    set_dead(*instruction->arg1);
                }
            } else {
                set_live_opt(instruction->arg1);
            }

            set_live_opt(instruction->arg2);
            set_live_opt(instruction->arg3);
        }

        for(auto& reg : instruction->uses){
            in.values().insert(reg);
        }

        for(auto& reg : instruction->float_uses){
            in.values().insert(reg);
        }
    }

    void operator()(std::shared_ptr<ltac::Jump> instruction){
        for(auto& reg : instruction->uses){
            in.values().insert(reg);
        }

        for(auto& reg : instruction->float_uses){
            in.values().insert(reg);
        }

        for(auto& reg : instruction->kills){
            in.values().erase(reg);
        }

        for(auto& reg : instruction->float_kills){
            in.values().erase(reg);
        }
    }

    template<typename T>
    void operator()(T&){
        //Nothing to do
    }
};

} //End of anonymous namespace

ProblemDomain ltac::LiveRegistersProblem::transfer(mtac::basic_block_p /*basic_block*/, ltac::Statement& statement, ProblemDomain& in){
    auto out = in;

    LivenessCollector collector(out);
    visit(collector, statement);

    return out;
}

bool ltac::LiveRegistersProblem::optimize(ltac::Statement& /*statement*/, std::shared_ptr<mtac::DataFlowResults<ProblemDomain>> /*results*/){
    //This analysis is only made to gather information, not to optimize anything
    throw "Unimplemented";
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <stdio.h>
#include "Exception.h"
#include <decaf/util/logging/LoggerDefines.h>
#include <decaf/internal/AprPool.h>

#include <sstream>
#include <apr_strings.h>

using namespace std;
using namespace decaf;
using namespace decaf::internal;
using namespace decaf::lang;
using namespace decaf::util::logging;

////////////////////////////////////////////////////////////////////////////////
Exception::Exception() throw(){
}

////////////////////////////////////////////////////////////////////////////////
Exception::Exception( const Exception& ex ) throw() : Throwable() {
    *this = ex;
}

////////////////////////////////////////////////////////////////////////////////
Exception::Exception( const char* file, const int lineNumber,
                      const char* msg, ... ) throw() {
    va_list vargs;
    va_start( vargs, msg ) ;
    buildMessage( msg, vargs );

    // Set the first mark for this exception.
    setMark( file, lineNumber );
}

////////////////////////////////////////////////////////////////////////////////
Exception::~Exception() throw(){
}

////////////////////////////////////////////////////////////////////////////////
void Exception::setMessage( const char* msg, ... ){
    va_list vargs;
    va_start( vargs, msg );
    buildMessage( msg, vargs );
    va_end( vargs );
}

////////////////////////////////////////////////////////////////////////////////
void Exception::buildMessage( const char* format, va_list& vargs ) {

    // Allocate buffer with a guess of it's size
    AprPool pool;

    // Allocate a buffer of the specified size.
    char* buffer = apr_pvsprintf( pool.getAprPool(), format, vargs );

    // Guessed size was enough. Assign the string.
    message.assign( buffer, strlen( buffer ) );
}

////////////////////////////////////////////////////////////////////////////////
void Exception::setMark( const char* file, const int lineNumber ) {

    // Add this mark to the end of the stack trace.
    stackTrace.push_back( std::make_pair( (std::string)file, (int)lineNumber ) );

    std::ostringstream stream;
    stream << "\tFILE: " << stackTrace[stackTrace.size()-1].first;
    stream << ", LINE: " << stackTrace[stackTrace.size()-1].second;

    //decaf::util::logger::SimpleLogger logger("com.yadda2");
    //logger.log( stream.str() );
}

////////////////////////////////////////////////////////////////////////////////
Exception* Exception::clone() const {
    return new Exception( *this );
}

////////////////////////////////////////////////////////////////////////////////
std::vector< std::pair< std::string, int> > Exception::getStackTrace() const {
    return stackTrace;
}

////////////////////////////////////////////////////////////////////////////////
void Exception::setStackTrace(
    const std::vector< std::pair< std::string, int> >& trace ) {

    this->stackTrace = trace;
}

////////////////////////////////////////////////////////////////////////////////
void Exception::printStackTrace() const {
    printStackTrace( std::cerr );
}

////////////////////////////////////////////////////////////////////////////////
void Exception::printStackTrace( std::ostream& stream ) const {
    stream << getStackTraceString();
}

////////////////////////////////////////////////////////////////////////////////
std::string Exception::getStackTraceString() const {

    // Create the output stream.
    std::ostringstream stream;

    // Write the message and each stack entry.
    stream << message << std::endl;
    for( unsigned int ix=0; ix<stackTrace.size(); ++ix ){
        stream << "\tFILE: " << stackTrace[ix].first;
        stream << ", LINE: " << stackTrace[ix].second;
        stream << std::endl;
    }

    // Return the string from the output stream.
    return stream.str();
}

////////////////////////////////////////////////////////////////////////////////
Exception& Exception::operator =( const Exception& ex ){
    this->message = ex.message;
    this->stackTrace = ex.stackTrace;
    return *this;
}
<commit_msg>Adding in missing call to va_end()<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <stdio.h>
#include "Exception.h"
#include <decaf/util/logging/LoggerDefines.h>
#include <decaf/internal/AprPool.h>

#include <sstream>
#include <apr_strings.h>

using namespace std;
using namespace decaf;
using namespace decaf::internal;
using namespace decaf::lang;
using namespace decaf::util::logging;

////////////////////////////////////////////////////////////////////////////////
Exception::Exception() throw(){
}

////////////////////////////////////////////////////////////////////////////////
Exception::Exception( const Exception& ex ) throw() : Throwable() {
    *this = ex;
}

////////////////////////////////////////////////////////////////////////////////
Exception::Exception( const char* file, const int lineNumber,
                      const char* msg, ... ) throw() {
    va_list vargs;
    va_start( vargs, msg ) ;
    buildMessage( msg, vargs );
    va_end( vargs );

    // Set the first mark for this exception.
    setMark( file, lineNumber );
}

////////////////////////////////////////////////////////////////////////////////
Exception::~Exception() throw(){
}

////////////////////////////////////////////////////////////////////////////////
void Exception::setMessage( const char* msg, ... ){
    va_list vargs;
    va_start( vargs, msg );
    buildMessage( msg, vargs );
    va_end( vargs );
}

////////////////////////////////////////////////////////////////////////////////
void Exception::buildMessage( const char* format, va_list& vargs ) {

    // Allocate buffer with a guess of it's size
    AprPool pool;

    // Allocate a buffer of the specified size.
    char* buffer = apr_pvsprintf( pool.getAprPool(), format, vargs );

    // Guessed size was enough. Assign the string.
    message.assign( buffer, strlen( buffer ) );
}

////////////////////////////////////////////////////////////////////////////////
void Exception::setMark( const char* file, const int lineNumber ) {

    // Add this mark to the end of the stack trace.
    stackTrace.push_back( std::make_pair( (std::string)file, (int)lineNumber ) );

    std::ostringstream stream;
    stream << "\tFILE: " << stackTrace[stackTrace.size()-1].first;
    stream << ", LINE: " << stackTrace[stackTrace.size()-1].second;

    //decaf::util::logger::SimpleLogger logger("com.yadda2");
    //logger.log( stream.str() );
}

////////////////////////////////////////////////////////////////////////////////
Exception* Exception::clone() const {
    return new Exception( *this );
}

////////////////////////////////////////////////////////////////////////////////
std::vector< std::pair< std::string, int> > Exception::getStackTrace() const {
    return stackTrace;
}

////////////////////////////////////////////////////////////////////////////////
void Exception::setStackTrace(
    const std::vector< std::pair< std::string, int> >& trace ) {

    this->stackTrace = trace;
}

////////////////////////////////////////////////////////////////////////////////
void Exception::printStackTrace() const {
    printStackTrace( std::cerr );
}

////////////////////////////////////////////////////////////////////////////////
void Exception::printStackTrace( std::ostream& stream ) const {
    stream << getStackTraceString();
}

////////////////////////////////////////////////////////////////////////////////
std::string Exception::getStackTraceString() const {

    // Create the output stream.
    std::ostringstream stream;

    // Write the message and each stack entry.
    stream << message << std::endl;
    for( unsigned int ix=0; ix<stackTrace.size(); ++ix ){
        stream << "\tFILE: " << stackTrace[ix].first;
        stream << ", LINE: " << stackTrace[ix].second;
        stream << std::endl;
    }

    // Return the string from the output stream.
    return stream.str();
}

////////////////////////////////////////////////////////////////////////////////
Exception& Exception::operator =( const Exception& ex ){
    this->message = ex.message;
    this->stackTrace = ex.stackTrace;
    return *this;
}
<|endoftext|>