<commit_before>/*
 * item grouping implementation
 */

#include <string>

#include <sys/uio.h>

#include "node.h"
#include "config.h"
#include "message.h"
#include "convert.h"
#include "array.h"

#include "layout.h"

#include "object.h"

__MPT_NAMESPACE_BEGIN

int Group::typeIdentifier()
{
    static int id = 0;
    if (!id && (id = mpt_valtype_meta_new("group")) < 0) {
        id = mpt_valtype_meta_new(0);
    }
    return id;
}
// object interface for group
int Group::property(struct property *pr) const
{
    if (!pr) {
        return typeIdentifier();
    }
    if (!pr->name || *pr->name) {
        return BadArgument;
    }
    pr->name = "group";
    pr->desc = "mpt item group";
    pr->val.fmt = 0;
    pr->val.ptr = 0;
    return 0;
}
int Group::setProperty(const char *, const metatype *)
{
    return BadOperation;
}
// generic item group
size_t Group::clear(const reference *)
{ return 0; }
Item<metatype> *Group::append(metatype *)
{ return 0; }
const Item<metatype> *Group::item(size_t) const
{ return 0; }
bool Group::bind(const Relation &, logger *)
{ return true; }

bool Group::addItems(node *head, const Relation *relation, logger *out)
{
    const char _func[] = "mpt::Group::addItems";

    for (; head; head = head->next) {
        metatype *from = head->_meta;

        if (from && from->addref()) {
            Reference<metatype> m;
            m.setPointer(from);
            Item<metatype> *it;
            if ((it = append(from))) {
                m.detach();
                it->setName(head->ident.name());
            } else {
                if (out) out->message(_func, out->Warning, "%s %p: %s", MPT_tr("group"), this, MPT_tr("failed to add object"));
            }
            continue;
        }
        // name is property
        const char *name;

        if (!(name = mpt_node_ident(head))) {
            if (out) out->message(_func, out->Error, "%s %p: %s", MPT_tr("node"), head, MPT_tr("bad element name"));
            return false;
        }
        // set property
        value val;
        if (from && (val.ptr = mpt_meta_data(from))) {
            object *obj;
            if ((obj = from->cast<object>())) {
                val.fmt = 0;
                obj->set(name, val, out);
                continue;
            }
            if (out) out->message(_func, out->Warning, "%s (%p): %s", name, from, MPT_tr("parent not an object"));
            continue;
        }
        // get item type
        const char *pos;
        size_t len;
        val.fmt = pos = name;
        name = mpt_convert_key(&pos, 0, &len);
        if (!name || name != val.fmt || !*name) {
            if (out) out->message(_func, out->Warning, "%s: %s", MPT_tr("bad element name"), val.fmt);
            continue;
        }
        // create item
        if (!(from = create(name, len))) {
            if (out) out->message(_func, out->Warning, "%s: %s", MPT_tr("invalid item type"), std::string(name, len).c_str());
            continue;
        }
        // get item name
        name = mpt_convert_key(&pos, ":", &len);

        if (!name || !len) {
            if (out) out->message(_func, out->Warning, "%s", MPT_tr("empty item name"));
            from->unref();
            continue;
        }
        // name conflict on same level
        if (GroupRelation(*this).find(from->type(), name, len)) {
            if (out) out->message(_func, out->Warning, "%s: %s", MPT_tr("conflicting item name"), std::string(name, len).c_str());
            from->unref();
            continue;
        }
        const char *ident = name;
        int ilen = len;

        // find dependant items
        while ((name = mpt_convert_key(&pos, 0, &len))) {
            metatype *curr;
            if (relation) curr = relation->find(from->type(), name, len);
            else curr = GroupRelation(*this).find(from->type(), name, len);
            object *obj, *src;
            if ((src = curr->cast<object>()) && (obj = from->cast<object>())) {
                obj->setProperties(*src, out);
                continue;
            }
            if (out) out->message(_func, out->Error, "%s: %s: %s",
                                  MPT_tr("unable to get inheritance"), head->ident.name(), std::string(name, len).c_str());
            return false;
        }
        // add item to group
        Item<metatype> *ni = append(from);
        if (!ni) {
            from->unref();
            if (out) out->message(_func, out->Error, "%s: %s", MPT_tr("unable add item"), std::string(ident, ilen).c_str());
            continue;
        }
        ni->setName(ident, ilen);

        // set properties and subitems
        if (!head->children) continue;

        // process child items
        Group *ig;
        if ((ig = from->cast<Group>())) {
            if (!relation) {
                if (!(ig->addItems(head->children, relation, out))) return false;
                continue;
            }
            GroupRelation rel(*ig, relation);
            if (!(ig->addItems(head->children, &rel, out))) return false;
            continue;
        }
        object *obj;
        if (!(obj = from->cast<object>())) {
            continue;
        }
        // load item properties
        for (node *sub = head->children; sub; sub = sub->next) {
            metatype *mt;
            const char *data;

            if (!(mt = sub->_meta)) {
                continue;
            }
            // skip invalid name
            if (!(name = mpt_node_ident(sub)) || !*name) {
                continue;
            }
            // try value conversion
            value val;
            if (mt->conv(value::Type, &val) >= 0) {
                if (obj->set(name, val, out)) {
                    continue;
                }
            }
            if (mt->conv('s', &data) >= 0) {
                if (obj->set(name, data, out)) {
                    continue;
                }
            }
            if (out) out->message(_func, out->Warning, "%s: %s: %s", MPT_tr("bad value type"), ni->name(), name);
        }
    }
    return true;
}
metatype *Group::create(const char *type, int nl)
{
    if (!type || !nl) return 0;

    if (nl < 0) {
        nl = strlen(type);
    }

    if (nl == 4 && !memcmp("line", type, nl)) return new Reference<Line>::instance;

    if (nl == 4 && !memcmp("text", type, nl)) return new Reference<Text>::instance;

    if (nl == 5 && !memcmp("world", type, nl)) return new Reference<World>::instance;

    if (nl == 5 && !memcmp("graph", type, nl)) return new Reference<Graph>::instance;

    if (nl == 4 && !memcmp("axis", type, nl)) return new Reference<Axis>::instance;

    class TypedAxis : public Reference<Axis>::instance
    {
    public:
        TypedAxis(int type)
        { format = type & 0x3; }
    };

    if (nl == 5 && !memcmp("xaxis", type, nl)) return new TypedAxis(AxisStyleX);

    if (nl == 5 && !memcmp("yaxis", type, nl)) return new TypedAxis(AxisStyleY);

    if (nl == 5 && !memcmp("zaxis", type, nl)) return new TypedAxis(AxisStyleZ);

    return 0;
}

// group storing elements in RefArray
Collection::~Collection()
{ }

void Collection::unref()
{
    delete this;
}
int Collection::conv(int type, void *ptr) const
{
    int me = Group::typeIdentifier();
    if (me < 0) {
        me = object::Type;
    }
    if (!type) {
        static const char fmt[] = { array::Type };
        if (ptr) *static_cast<const char **>(ptr) = fmt;
        return me;
    }
    if (type == metatype::Type) {
        if (ptr) *static_cast<const metatype **>(ptr) = this;
        return me;
    }
    if (type == object::Type) {
        if (ptr) *static_cast<const metatype **>(ptr) = this;
        return me;
    }
    if (type == me) {
        if (ptr) *static_cast<const Group **>(ptr) = this;
        return array::Type;
    }
    return BadType;
}
Collection *Collection::clone() const
{
    Collection *copy = new Collection;
    copy->_items = _items;
    return copy;
}

const Item<metatype> *Collection::item(size_t pos) const
{
    return _items.get(pos);
}
Item<metatype> *Collection::append(metatype *mt)
{
    return _items.append(mt, 0);
}
size_t Collection::clear(const reference *ref)
{
    long remove = 0;
    if (!ref) {
        remove = _items.length();
        _items = ItemArray<metatype>();
        return remove ? true : false;
    }
    long empty = 0;
    for (auto &it : _items) {
        reference *curr = it.pointer();
        if (!curr) { ++empty; continue; }
        if (curr != ref) continue;
        it.setPointer(nullptr);
        ++remove;
    }
    if ((remove + empty) > _items.length()/2) {
        _items.compact();
    }
    return remove;
}
bool Collection::bind(const Relation &from, logger *out)
{
    for (auto &it : _items) {
        metatype *curr;
        Group *g;
        if (!(curr = it.pointer()) || !(g = curr->cast<Group>())) {
            continue;
        }
        if (!g->bind(GroupRelation(*g, &from), out)) {
            return false;
        }
    }
    return true;
}

// Relation search operations
metatype *GroupRelation::find(int type, const char *name, int nlen) const
{
    const Item<metatype> *c;
    const char *sep;

    if (nlen < 0) nlen = name ? strlen(name) : 0;

    if (_sep && (sep = (char *) memchr(name, _sep, nlen))) {
        size_t plen = sep - name;
        for (int i = 0; (c = _curr.item(i)); ++i) {
            metatype *m = c->pointer();
            if (!m || !c->equal(name, plen)) continue;
            const Group *g;
            if (!(g = m->cast<Group>())) continue;
            if ((m = GroupRelation(*g, this).find(type, sep+1, nlen-plen-1))) {
                return m;
            }
        }
    }
    else {
        for (int i = 0; (c = _curr.item(i)); ++i) {
            metatype *m = c->pointer();
            if (!m || (type && m->type() != type)) continue;
            if (!c->equal(name, nlen)) continue;
            return m;
        }
    }
    return _parent ? _parent->find(type, name, nlen) : 0;
}

metatype *NodeRelation::find(int type, const char *name, int nlen) const
{
    if (!_curr) return 0;

    if (nlen < 0) nlen = name ? strlen(name) : 0;

    for (const node *c = _curr->children; c; c = c->next) {
        metatype *m;
        if (!(m = c->_meta) || !c->ident.equal(name, nlen)) continue;
        if (type && m->type() != type) continue;
        return m;
    }
    return _parent ? _parent->find(type, name, nlen) : 0;
}

__MPT_NAMESPACE_END
<commit_msg>fix: target for group property assignment<commit_after>/*
 * item grouping implementation
 */

#include <string>

#include <sys/uio.h>

#include "node.h"
#include "config.h"
#include "message.h"
#include "convert.h"
#include "array.h"

#include "layout.h"

#include "object.h"

__MPT_NAMESPACE_BEGIN

int Group::typeIdentifier()
{
    static int id = 0;
    if (!id && (id = mpt_valtype_meta_new("group")) < 0) {
        id = mpt_valtype_meta_new(0);
    }
    return id;
}
// object interface for group
int Group::property(struct property *pr) const
{
    if (!pr) {
        return typeIdentifier();
    }
    if (!pr->name || *pr->name) {
        return BadArgument;
    }
    pr->name = "group";
    pr->desc = "mpt item group";
    pr->val.fmt = 0;
    pr->val.ptr = 0;
    return 0;
}
int Group::setProperty(const char *, const metatype *)
{
    return BadOperation;
}
// generic item group
size_t Group::clear(const reference *)
{ return 0; }
Item<metatype> *Group::append(metatype *)
{ return 0; }
const Item<metatype> *Group::item(size_t) const
{ return 0; }
bool Group::bind(const Relation &, logger *)
{ return true; }

bool Group::addItems(node *head, const Relation *relation, logger *out)
{
    const char _func[] = "mpt::Group::addItems";

    for (; head; head = head->next) {
        metatype *from = head->_meta;

        if (from && from->addref()) {
            Reference<metatype> m;
            m.setPointer(from);
            Item<metatype> *it;
            if ((it = append(from))) {
                m.detach();
                it->setName(head->ident.name());
            } else {
                if (out) out->message(_func, out->Warning, "%s %p: %s",
                                      MPT_tr("group"), this, MPT_tr("failed to add object"));
            }
            continue;
        }
        // name is property
        const char *name;

        if (!(name = mpt_node_ident(head))) {
            if (out) out->message(_func, out->Error, "%s %p: %s",
                                  MPT_tr("node"), head, MPT_tr("bad element name"));
            return false;
        }
        // set property
        value val;
        if (from && (val.ptr = mpt_meta_data(from))) {
            if (set(name, val, out)) {
                continue;
            }
            if (out) out->message(_func, out->Warning, "%s (%p): %s",
                                  name, from, MPT_tr("parent not an object"));
            continue;
        }
        // get item type
        const char *pos;
        size_t len;
        val.fmt = pos = name;
        name = mpt_convert_key(&pos, 0, &len);
        if (!name || name != val.fmt || !*name) {
            if (out) out->message(_func, out->Warning, "%s: %s",
                                  MPT_tr("bad element name"), val.fmt);
            continue;
        }
        // create item
        if (!(from = create(name, len))) {
            if (out) out->message(_func, out->Warning, "%s: %s",
                                  MPT_tr("invalid item type"), std::string(name, len).c_str());
            continue;
        }
        // get item name
        name = mpt_convert_key(&pos, ":", &len);

        if (!name || !len) {
            if (out) out->message(_func, out->Warning, "%s",
                                  MPT_tr("empty item name"));
            from->unref();
            continue;
        }
        // name conflict on same level
        if (GroupRelation(*this).find(from->type(), name, len)) {
            if (out) out->message(_func, out->Warning, "%s: %s",
                                  MPT_tr("conflicting item name"), std::string(name, len).c_str());
            from->unref();
            continue;
        }
        const char *ident = name;
        int ilen = len;

        // find dependant items
        while ((name = mpt_convert_key(&pos, 0, &len))) {
            metatype *curr;
            if (relation) curr = relation->find(from->type(), name, len);
            else curr = GroupRelation(*this).find(from->type(), name, len);
            object *obj, *src;
            if ((src = curr->cast<object>()) && (obj = from->cast<object>())) {
                obj->setProperties(*src, out);
                continue;
            }
            from->unref();
            if (out) out->message(_func, out->Error, "%s: %s: %s",
                                  MPT_tr("unable to get inheritance"), head->ident.name(), std::string(name, len).c_str());
            return false;
        }
        // add item to group
        Item<metatype> *ni = append(from);
        if (!ni) {
            from->unref();
            if (out) out->message(_func, out->Error, "%s: %s",
                                  MPT_tr("unable add item"), std::string(ident, ilen).c_str());
            continue;
        }
        ni->setName(ident, ilen);

        // set properties and subitems
        if (!head->children) continue;

        // process child items
        Group *ig;
        if ((ig = from->cast<Group>())) {
            if (!relation) {
                if (!(ig->addItems(head->children, relation, out))) return false;
                continue;
            }
            GroupRelation rel(*ig, relation);
            if (!(ig->addItems(head->children, &rel, out))) return false;
            continue;
        }
        object *obj;
        if (!(obj = from->cast<object>())) {
            continue;
        }
        // load item properties
        for (node *sub = head->children; sub; sub = sub->next) {
            metatype *mt;
            const char *data;

            if (!(mt = sub->_meta)) {
                continue;
            }
            // skip invalid name
            if (!(name = mpt_node_ident(sub)) || !*name) {
                continue;
            }
            // try value conversion
            value val;
            if (mt->conv(value::Type, &val) >= 0) {
                if (obj->set(name, val, out)) {
                    continue;
                }
            }
            if (mt->conv('s', &data) >= 0) {
                if (obj->set(name, data, out)) {
                    continue;
                }
            }
            if (out) out->message(_func, out->Warning, "%s: %s: %s",
                                  MPT_tr("bad value type"), ni->name(), name);
        }
    }
    return true;
}
metatype *Group::create(const char *type, int nl)
{
    if (!type || !nl) return 0;

    if (nl < 0) {
        nl = strlen(type);
    }

    if (nl == 4 && !memcmp("line", type, nl)) return new Reference<Line>::instance;

    if (nl == 4 && !memcmp("text", type, nl)) return new Reference<Text>::instance;

    if (nl == 5 && !memcmp("world", type, nl)) return new Reference<World>::instance;

    if (nl == 5 && !memcmp("graph", type, nl)) return new Reference<Graph>::instance;

    if (nl == 4 && !memcmp("axis", type, nl)) return new Reference<Axis>::instance;

    class TypedAxis : public Reference<Axis>::instance
    {
    public:
        TypedAxis(int type)
        { format = type & 0x3; }
    };

    if (nl == 5 && !memcmp("xaxis", type, nl)) return new TypedAxis(AxisStyleX);

    if (nl == 5 && !memcmp("yaxis", type, nl)) return new TypedAxis(AxisStyleY);

    if (nl == 5 && !memcmp("zaxis", type, nl)) return new TypedAxis(AxisStyleZ);

    return 0;
}

// group storing elements in RefArray
Collection::~Collection()
{ }

void Collection::unref()
{
    delete this;
}
int Collection::conv(int type, void *ptr) const
{
    int me = Group::typeIdentifier();
    if (me < 0) {
        me = object::Type;
    }
    if (!type) {
        static const char fmt[] = { array::Type };
        if (ptr) *static_cast<const char **>(ptr) = fmt;
        return me;
    }
    if (type == metatype::Type) {
        if (ptr) *static_cast<const metatype **>(ptr) = this;
        return me;
    }
    if (type == object::Type) {
        if (ptr) *static_cast<const object **>(ptr) = this;
        return me;
    }
    if (type == me) {
        if (ptr) *static_cast<const Group **>(ptr) = this;
        return array::Type;
    }
    return BadType;
}
Collection *Collection::clone() const
{
    Collection *copy = new Collection;
    copy->_items = _items;
    return copy;
}

const Item<metatype> *Collection::item(size_t pos) const
{
    return _items.get(pos);
}
Item<metatype> *Collection::append(metatype *mt)
{
    return _items.append(mt, 0);
}
size_t Collection::clear(const reference *ref)
{
    long remove = 0;
    if (!ref) {
        remove = _items.length();
        _items = ItemArray<metatype>();
        return remove ? true : false;
    }
    long empty = 0;
    for (auto &it : _items) {
        reference *curr = it.pointer();
        if (!curr) { ++empty; continue; }
        if (curr != ref) continue;
        it.setPointer(nullptr);
        ++remove;
    }
    if ((remove + empty) > _items.length()/2) {
        _items.compact();
    }
    return remove;
}
bool Collection::bind(const Relation &from, logger *out)
{
    for (auto &it : _items) {
        metatype *curr;
        Group *g;
        if (!(curr = it.pointer()) || !(g = curr->cast<Group>())) {
            continue;
        }
        if (!g->bind(GroupRelation(*g, &from), out)) {
            return false;
        }
    }
    return true;
}

// Relation search operations
metatype *GroupRelation::find(int type, const char *name, int nlen) const
{
    const Item<metatype> *c;
    const char *sep;

    if (nlen < 0) nlen = name ? strlen(name) : 0;

    if (_sep && (sep = (char *) memchr(name, _sep, nlen))) {
        size_t plen = sep - name;
        for (int i = 0; (c = _curr.item(i)); ++i) {
            metatype *m = c->pointer();
            if (!m || !c->equal(name, plen)) continue;
            const Group *g;
            if (!(g = m->cast<Group>())) continue;
            if ((m = GroupRelation(*g, this).find(type, sep+1, nlen-plen-1))) {
                return m;
            }
        }
    }
    else {
        for (int i = 0; (c = _curr.item(i)); ++i) {
            metatype *m = c->pointer();
            if (!m || (type && m->type() != type)) continue;
            if (!c->equal(name, nlen)) continue;
            return m;
        }
    }
    return _parent ? _parent->find(type, name, nlen) : 0;
}

metatype *NodeRelation::find(int type, const char *name, int nlen) const
{
    if (!_curr) return 0;

    if (nlen < 0) nlen = name ? strlen(name) : 0;

    for (const node *c = _curr->children; c; c = c->next) {
        metatype *m;
        if (!(m = c->_meta) || !c->ident.equal(name, nlen)) continue;
        if (type && m->type() != type) continue;
        return m;
    }
    return _parent ? _parent->find(type, name, nlen) : 0;
}

__MPT_NAMESPACE_END
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.1  2002/02/01 22:21:52  peiyongz
 * Initial revision
 *
 * Revision 1.7  2000/10/17 19:25:38  andyh
 * XMLFormatTarget, removed version of writeChars with no length.  Can not be
 * safely used, and obscured other errors.
 *
 * Revision 1.6  2000/10/10 23:54:58  andyh
 * XMLFormatter patch, contributed by Bill Schindler.  Fix problems with
 * output to multi-byte encodings.
 *
 * Revision 1.5  2000/04/07 01:01:56  roddey
 * Fixed an error message so that it indicated the correct radix for the rep
 * token. Get all of the basic output formatting functionality in place for
 * at least ICU and Win32 transcoders.
 *
 * Revision 1.4  2000/04/06 23:50:38  roddey
 * Now the low level formatter handles doing char refs for
 * unrepresentable chars (in addition to the replacement char style
 * already done.)
 *
 * Revision 1.3  2000/04/06 19:09:21  roddey
 * Some more improvements to output formatting. Now it will correctly
 * handle doing the 'replacement char' style of dealing with chars
 * that are unrepresentable.
 *
 * Revision 1.2  2000/04/05 00:20:16  roddey
 * More updates for the low level formatted output support
 *
 * Revision 1.1  2000/03/28 19:43:17  roddey
 * Fixes for signed/unsigned warnings. New work for two way transcoding
 * stuff.
 *
 */

#if !defined(XMLFORMATTER_HPP)
#define XMLFORMATTER_HPP

#include <xercesc/util/XercesDefs.hpp>

class XMLFormatTarget;
class XMLTranscoder;

/**
 *  This class provides the basic formatting capabilities that are required
 *  to turn the Unicode based XML data from the parsers into a form that can
 *  be used on non-Unicode based systems, i.e. into local or generic text
 *  encodings.
 *
 *  A number of flags are provided to control whether various optional
 *  formatting operations are performed.
 */
class XMLPARSER_EXPORT XMLFormatter
{
public:
    // -----------------------------------------------------------------------
    //  Class types
    // -----------------------------------------------------------------------
    enum EscapeFlags
    {
        NoEscapes
        , StdEscapes
        , AttrEscapes
        , CharEscapes

        // Special values, don't use directly
        , EscapeFlags_Count
        , DefaultEscape     = 999
    };

    enum UnRepFlags
    {
        UnRep_Fail
        , UnRep_CharRef
        , UnRep_Replace

        , DefaultUnRep      = 999
    };

    // -----------------------------------------------------------------------
    //  Constructors and Destructor
    // -----------------------------------------------------------------------
    XMLFormatter
    (
        const   XMLCh* const            outEncoding
        ,       XMLFormatTarget* const  target
        , const EscapeFlags             escapeFlags = NoEscapes
        , const UnRepFlags              unrepFlags = UnRep_Fail
    );

    XMLFormatter
    (
        const   char* const             outEncoding
        ,       XMLFormatTarget* const  target
        , const EscapeFlags             escapeFlags = NoEscapes
        , const UnRepFlags              unrepFlags = UnRep_Fail
    );

    ~XMLFormatter();

    // -----------------------------------------------------------------------
    //  Formatting methods
    // -----------------------------------------------------------------------
    void formatBuf
    (
        const   XMLCh* const    toFormat
        , const unsigned int    count
        , const EscapeFlags     escapeFlags = DefaultEscape
        , const UnRepFlags      unrepFlags = DefaultUnRep
    );

    XMLFormatter& operator<<
    (
        const   XMLCh* const    toFormat
    );

    XMLFormatter& operator<<
    (
        const   XMLCh           toFormat
    );

    // -----------------------------------------------------------------------
    //  Getter methods
    // -----------------------------------------------------------------------
    const XMLCh* getEncodingName() const;

    // -----------------------------------------------------------------------
    //  Setter methods
    // -----------------------------------------------------------------------
    void setEscapeFlags
    (
        const   EscapeFlags     newFlags
    );

    void setUnRepFlags
    (
        const   UnRepFlags      newFlags
    );

    XMLFormatter& operator<<
    (
        const   EscapeFlags     newFlags
    );

    XMLFormatter& operator<<
    (
        const   UnRepFlags      newFlags
    );

private :
    // -----------------------------------------------------------------------
    //  Unimplemented constructors and operators
    // -----------------------------------------------------------------------
    XMLFormatter();
    XMLFormatter(const XMLFormatter&);
    void operator=(const XMLFormatter&);

    // -----------------------------------------------------------------------
    //  Private class constants
    // -----------------------------------------------------------------------
    enum Constants
    {
        kTmpBufSize     = 16 * 1024
    };

    // -----------------------------------------------------------------------
    //  Private helper methods
    // -----------------------------------------------------------------------
    const XMLByte* getAposRef(unsigned int & count);
    const XMLByte* getAmpRef(unsigned int & count);
    const XMLByte* getGTRef(unsigned int & count);
    const XMLByte* getLTRef(unsigned int & count);
    const XMLByte* getQuoteRef(unsigned int & count);

    void specialFormat
    (
        const   XMLCh* const    toFormat
        , const unsigned int    count
        , const EscapeFlags     escapeFlags
    );

    // -----------------------------------------------------------------------
    //  Private, non-virtual methods
    //
    //  fEscapeFlags
    //      The escape flags we were told to use in formatting. These are
    //      defaults set in the ctor, which can be overridden on a particular
    //      call.
    //
    //  fOutEncoding
    //      This the name of the output encoding. Saved mainly for meaningful
    //      error messages.
    //
    //  fTarget
    //      This is the target object for the formatting operation.
    //
    //  fUnRepFlags
    //      The unrepresentable flags that indicate how to react when a
    //      character cannot be represented in the target encoding.
    //
    //  fXCoder
    //      This the transcoder that we will use. It is created using the
    //      encoding name we were told to use.
    //
    //  fTmpBuf
    //      An output buffer that we use to transcode chars into before we
    //      send them off to be output.
    //
    //  fAposRef
    //  fAmpRef
    //  fGTRef
    //  fLTRef
    //  fQuoteRef
    //      These are character refs for the standard char refs, in the
    //      output encoding. They are faulted in as required, by transcoding
    //      them from fixed Unicode versions.
    // -----------------------------------------------------------------------
    EscapeFlags                 fEscapeFlags;
    XMLCh*                      fOutEncoding;
    XMLFormatTarget*            fTarget;
    UnRepFlags                  fUnRepFlags;
    XMLTranscoder*              fXCoder;
    XMLByte                     fTmpBuf[kTmpBufSize + 4];

    XMLByte*                    fAposRef;
    unsigned int                fAposLen;
    XMLByte*                    fAmpRef;
    unsigned int                fAmpLen;
    XMLByte*                    fGTRef;
    unsigned int                fGTLen;
    XMLByte*                    fLTRef;
    unsigned int                fLTLen;
    XMLByte*                    fQuoteRef;
    unsigned int                fQuoteLen;
};

class XMLPARSER_EXPORT XMLFormatTarget
{
public:
    // -----------------------------------------------------------------------
    //  Constructors and Destructor
    // -----------------------------------------------------------------------
    virtual ~XMLFormatTarget() {}

    // -----------------------------------------------------------------------
    //  Virtual interface
    // -----------------------------------------------------------------------
    virtual void writeChars
    (
        const   XMLByte* const      toWrite
        , const unsigned int        count
        ,       XMLFormatter* const formatter
    ) = 0;

protected :
    // -----------------------------------------------------------------------
    //  Hidden constructors and operators
    // -----------------------------------------------------------------------
    XMLFormatTarget() {}
    XMLFormatTarget(const XMLFormatTarget&) {}
    void operator=(const XMLFormatTarget&) {}
};

// ---------------------------------------------------------------------------
//  XMLFormatter: Getter methods
// ---------------------------------------------------------------------------
inline const XMLCh* XMLFormatter::getEncodingName() const
{
    return fOutEncoding;
}

// ---------------------------------------------------------------------------
//  XMLFormatter: Setter methods
// ---------------------------------------------------------------------------
inline void XMLFormatter::setEscapeFlags(const EscapeFlags newFlags)
{
    fEscapeFlags = newFlags;
}

inline void XMLFormatter::setUnRepFlags(const UnRepFlags newFlags)
{
    fUnRepFlags = newFlags;
}

inline XMLFormatter& XMLFormatter::operator<<(const EscapeFlags newFlags)
{
    fEscapeFlags = newFlags;
    return *this;
}

inline XMLFormatter& XMLFormatter::operator<<(const UnRepFlags newFlags)
{
    fUnRepFlags = newFlags;
    return *this;
}

#endif
<commit_msg>getTranscoder() added;<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.2  2002/06/21 19:31:23  peiyongz
 * getTranscoder() added;
 *
 * Revision 1.1.1.1  2002/02/01 22:21:52  peiyongz
 * sane_include
 *
 * Revision 1.7  2000/10/17 19:25:38  andyh
 * XMLFormatTarget, removed version of writeChars with no length.  Can not be
 * safely used, and obscured other errors.
 *
 * Revision 1.6  2000/10/10 23:54:58  andyh
 * XMLFormatter patch, contributed by Bill Schindler.  Fix problems with
 * output to multi-byte encodings.
 *
 * Revision 1.5  2000/04/07 01:01:56  roddey
 * Fixed an error message so that it indicated the correct radix for the rep
 * token. Get all of the basic output formatting functionality in place for
 * at least ICU and Win32 transcoders.
 *
 * Revision 1.4  2000/04/06 23:50:38  roddey
 * Now the low level formatter handles doing char refs for
 * unrepresentable chars (in addition to the replacement char style
 * already done.)
 *
 * Revision 1.3  2000/04/06 19:09:21  roddey
 * Some more improvements to output formatting. Now it will correctly
 * handle doing the 'replacement char' style of dealing with chars
 * that are unrepresentable.
 *
 * Revision 1.2  2000/04/05 00:20:16  roddey
 * More updates for the low level formatted output support
 *
 * Revision 1.1  2000/03/28 19:43:17  roddey
 * Fixes for signed/unsigned warnings. New work for two way transcoding
 * stuff.
 *
 */

#if !defined(XMLFORMATTER_HPP)
#define XMLFORMATTER_HPP

#include <xercesc/util/XercesDefs.hpp>

class XMLFormatTarget;
class XMLTranscoder;

/**
 *  This class provides the basic formatting capabilities that are required
 *  to turn the Unicode based XML data from the parsers into a form that can
 *  be used on non-Unicode based systems, i.e. into local or generic text
 *  encodings.
 *
 *  A number of flags are provided to control whether various optional
 *  formatting operations are performed.
 */
class XMLPARSER_EXPORT XMLFormatter
{
public:
    // -----------------------------------------------------------------------
    //  Class types
    // -----------------------------------------------------------------------
    enum EscapeFlags
    {
        NoEscapes
        , StdEscapes
        , AttrEscapes
        , CharEscapes

        // Special values, don't use directly
        , EscapeFlags_Count
        , DefaultEscape     = 999
    };

    enum UnRepFlags
    {
        UnRep_Fail
        , UnRep_CharRef
        , UnRep_Replace

        , DefaultUnRep      = 999
    };

    // -----------------------------------------------------------------------
    //  Constructors and Destructor
    // -----------------------------------------------------------------------
    XMLFormatter
    (
        const   XMLCh* const            outEncoding
        ,       XMLFormatTarget* const  target
        , const EscapeFlags             escapeFlags = NoEscapes
        , const UnRepFlags              unrepFlags = UnRep_Fail
    );

    XMLFormatter
    (
        const   char* const             outEncoding
        ,       XMLFormatTarget* const  target
        , const EscapeFlags             escapeFlags = NoEscapes
        , const UnRepFlags              unrepFlags = UnRep_Fail
    );

    ~XMLFormatter();

    // -----------------------------------------------------------------------
    //  Formatting methods
    // -----------------------------------------------------------------------
    void formatBuf
    (
        const   XMLCh* const    toFormat
        , const unsigned int    count
        , const EscapeFlags     escapeFlags = DefaultEscape
        , const UnRepFlags      unrepFlags = DefaultUnRep
    );

    XMLFormatter& operator<<
    (
        const   XMLCh* const    toFormat
    );

    XMLFormatter& operator<<
    (
        const   XMLCh           toFormat
    );

    // -----------------------------------------------------------------------
    //  Getter methods
    // -----------------------------------------------------------------------
    const XMLCh* getEncodingName() const;

    inline const XMLTranscoder*   getTranscoder() const;

    // -----------------------------------------------------------------------
    //  Setter methods
    // -----------------------------------------------------------------------
    void setEscapeFlags
    (
        const   EscapeFlags     newFlags
    );

    void setUnRepFlags
    (
        const   UnRepFlags      newFlags
    );

    XMLFormatter& operator<<
    (
        const   EscapeFlags     newFlags
    );

    XMLFormatter& operator<<
    (
        const   UnRepFlags      newFlags
    );

private :
    // -----------------------------------------------------------------------
    //  Unimplemented constructors and operators
    // -----------------------------------------------------------------------
    XMLFormatter();
    XMLFormatter(const XMLFormatter&);
    void operator=(const XMLFormatter&);

    // -----------------------------------------------------------------------
    //  Private class constants
    // -----------------------------------------------------------------------
    enum Constants
    {
        kTmpBufSize     = 16 * 1024
    };

    // -----------------------------------------------------------------------
    //  Private helper methods
    // -----------------------------------------------------------------------
    const XMLByte* getAposRef(unsigned int & count);
    const XMLByte* getAmpRef(unsigned int & count);
    const XMLByte* getGTRef(unsigned int & count);
    const XMLByte* getLTRef(unsigned int & count);
    const XMLByte* getQuoteRef(unsigned int & count);

    void specialFormat
    (
        const   XMLCh* const    toFormat
        , const unsigned int    count
        , const EscapeFlags     escapeFlags
    );

    // -----------------------------------------------------------------------
    //  Private, non-virtual methods
    //
    //  fEscapeFlags
    //      The escape flags we were told to use in formatting. These are
    //      defaults set in the ctor, which can be overridden on a particular
    //      call.
    //
    //  fOutEncoding
    //      This the name of the output encoding. Saved mainly for meaningful
    //      error messages.
    //
    //  fTarget
    //      This is the target object for the formatting operation.
    //
    //  fUnRepFlags
    //      The unrepresentable flags that indicate how to react when a
    //      character cannot be represented in the target encoding.
    //
    //  fXCoder
    //      This the transcoder that we will use. It is created using the
    //      encoding name we were told to use.
    //
    //  fTmpBuf
    //      An output buffer that we use to transcode chars into before we
    //      send them off to be output.
    //
    //  fAposRef
    //  fAmpRef
    //  fGTRef
    //  fLTRef
    //  fQuoteRef
    //      These are character refs for the standard char refs, in the
    //      output encoding. They are faulted in as required, by transcoding
    //      them from fixed Unicode versions.
    // -----------------------------------------------------------------------
    EscapeFlags                 fEscapeFlags;
    XMLCh*                      fOutEncoding;
    XMLFormatTarget*            fTarget;
    UnRepFlags                  fUnRepFlags;
    XMLTranscoder*              fXCoder;
    XMLByte                     fTmpBuf[kTmpBufSize + 4];

    XMLByte*                    fAposRef;
    unsigned int                fAposLen;
    XMLByte*                    fAmpRef;
    unsigned int                fAmpLen;
    XMLByte*                    fGTRef;
    unsigned int                fGTLen;
    XMLByte*                    fLTRef;
    unsigned int                fLTLen;
    XMLByte*                    fQuoteRef;
    unsigned int                fQuoteLen;
};

class XMLPARSER_EXPORT XMLFormatTarget
{
public:
    // -----------------------------------------------------------------------
    //  Constructors and Destructor
    // -----------------------------------------------------------------------
    virtual ~XMLFormatTarget() {}

    // -----------------------------------------------------------------------
    //  Virtual interface
    // -----------------------------------------------------------------------
    virtual void writeChars
    (
        const   XMLByte* const      toWrite
        , const unsigned int        count
        ,       XMLFormatter* const formatter
    ) = 0;

protected :
    // -----------------------------------------------------------------------
    //  Hidden constructors and operators
    // -----------------------------------------------------------------------
    XMLFormatTarget() {}
    XMLFormatTarget(const XMLFormatTarget&) {}
    void operator=(const XMLFormatTarget&) {}
};

// ---------------------------------------------------------------------------
//  XMLFormatter: Getter methods
// ---------------------------------------------------------------------------
inline const XMLCh* XMLFormatter::getEncodingName() const
{
    return fOutEncoding;
}

inline const XMLTranscoder* XMLFormatter::getTranscoder() const
{
    return fXCoder;
}

// ---------------------------------------------------------------------------
//  XMLFormatter: Setter methods
// ---------------------------------------------------------------------------
inline void XMLFormatter::setEscapeFlags(const EscapeFlags newFlags)
{
    fEscapeFlags = newFlags;
}

inline void XMLFormatter::setUnRepFlags(const UnRepFlags newFlags)
{
    fUnRepFlags = newFlags;
}

inline XMLFormatter& XMLFormatter::operator<<(const EscapeFlags newFlags)
{
    fEscapeFlags = newFlags;
    return *this;
}

inline XMLFormatter& XMLFormatter::operator<<(const UnRepFlags newFlags)
{
    fUnRepFlags = newFlags;
    return *this;
}

#endif
<|endoftext|>


<commit_before>#pragma once

#include <atomic>
#include <memory>
#include <mutex>
#include <thread>

namespace Nano
{

class Spin_Mutex
{
    std::atomic_bool locked = { false };

    public:

    inline void lock() noexcept
    {
        do
        {
            while (locked.load(std::memory_order_relaxed))
            {
                std::this_thread::yield();
            }
        }
        while (locked.exchange(true, std::memory_order_acquire));
    }

    inline void unlock() noexcept
    {
        locked.store(false, std::memory_order_release);
    }

    Spin_Mutex() noexcept = default;
    virtual ~Spin_Mutex() noexcept = default;

    // Because all we own is a trivially-copyable atomic_bool, we can manually move/copy
    Spin_Mutex(Spin_Mutex const& other) noexcept : locked{other.locked.load()} {}
    Spin_Mutex& operator= (Spin_Mutex const& other) noexcept
    {
        locked = other.locked.load();
        return *this;
    }

    Spin_Mutex(Spin_Mutex&& other) noexcept : locked{other.locked.load()} {}
    Spin_Mutex& operator= (Spin_Mutex&& other) noexcept
    {
        locked = other.locked.load();
        return *this;
    }
};

//------------------------------------------------------------------------------

// Single Thread Policy
// Use this policy when you DO want performance but NO thread-safety!

class ST_Policy
{
    public:

    template <typename T, typename L>
    inline T const& copy_or_ref(T const& param, L&&) const
    {
        // Return a ref of param
        return param;
    }

    constexpr auto lock_guard() const
    {
        return false;
    }

    protected:

    ST_Policy() noexcept = default;
    ~ST_Policy() noexcept = default;

    ST_Policy(const ST_Policy&) noexcept = default;
    ST_Policy& operator=(const ST_Policy&) noexcept = default;

    ST_Policy(ST_Policy&&) noexcept = default;
    ST_Policy& operator=(ST_Policy&&) noexcept = default;

    using Weak_Ptr = ST_Policy*;

    constexpr auto weak_ptr()
    {
        return this;
    }

    constexpr auto observed(Weak_Ptr) const
    {
        return true;
    }

    constexpr auto visiting(Weak_Ptr observer) const
    {
        return (observer == this ? nullptr : observer);
    }

    constexpr auto unmask(Weak_Ptr observer) const
    {
        return observer;
    }

    constexpr void before_disconnect_all() const
    {

    }
};

//------------------------------------------------------------------------------

// Thread Safe Policy
// Use this policy when you DO want thread-safety but NO reentrancy!

template <typename Mutex = Spin_Mutex>
class TS_Policy
{
    mutable Mutex mutex;

    public:

    template <typename T, typename L>
    inline T const& copy_or_ref(T const& param, L&&) const
    {
        // Return a ref of param
        return param;
    }

    inline auto lock_guard() const
    {
        // All policies must implement the BasicLockable requirement
        return std::lock_guard<TS_Policy>(*const_cast<TS_Policy*>(this));
    }

    inline void lock() const
    {
        mutex.lock();
    }

    inline void unlock() noexcept
    {
        mutex.unlock();
    }

    protected:

    TS_Policy() noexcept = default;
    ~TS_Policy() noexcept = default;

    TS_Policy(TS_Policy const&) noexcept = default;
    TS_Policy& operator= (TS_Policy const&) noexcept = default;

    TS_Policy(TS_Policy&&) noexcept = default;
    TS_Policy& operator= (TS_Policy&&) noexcept = default;

    using Weak_Ptr = TS_Policy*;

    constexpr auto weak_ptr()
    {
        return this;
    }

    constexpr auto observed(Weak_Ptr) const
    {
        return true;
    }

    constexpr auto visiting(Weak_Ptr observer) const
    {
        return (observer == this ? nullptr : observer);
    }

    constexpr auto unmask(Weak_Ptr observer) const
    {
        return observer;
    }

    constexpr void before_disconnect_all() const
    {

    }
};

//------------------------------------------------------------------------------

// Single Thread Policy "Safe"
// Use this policy when you DO want reentrancy but NO thread-safety!

class ST_Policy_Safe
{
    public:

    template <typename T, typename L>
    inline T copy_or_ref(T const& param, L&&) const
    {
        // Return a copy of param
        return param;
    }

    constexpr auto lock_guard() const
    {
        return false;
    }

    protected:

    ST_Policy_Safe() noexcept = default;
    ~ST_Policy_Safe() noexcept = default;

    ST_Policy_Safe(ST_Policy_Safe const&) noexcept = default;
    ST_Policy_Safe& operator= (ST_Policy_Safe const&) noexcept = default;

    ST_Policy_Safe(ST_Policy_Safe&&) noexcept = default;
    ST_Policy_Safe& operator= (ST_Policy_Safe&&) noexcept = default;

    using Weak_Ptr = ST_Policy_Safe*;

    constexpr auto weak_ptr()
    {
        return this;
    }

    constexpr auto observed(Weak_Ptr) const
    {
        return true;
    }

    constexpr auto visiting(Weak_Ptr observer) const
    {
        return (observer == this ? nullptr : observer);
    }

    constexpr auto unmask(Weak_Ptr observer) const
    {
        return observer;
    }

    constexpr void before_disconnect_all() const
    {

    }
};

//------------------------------------------------------------------------------

// Thread Safe Policy "Safe"
// Use this policy when you DO want thread-safety AND reentrancy!

template <typename Mutex = Spin_Mutex>
class TS_Policy_Safe
{
    using Shared_Ptr = std::shared_ptr<TS_Policy_Safe>;

    Shared_Ptr tracker { this, [](...){} };
    mutable Mutex mutex;

    public:

    template <typename T, typename L>
    inline T copy_or_ref(T const& param, L&& lock) const
    {
        std::unique_lock<TS_Policy_Safe> unlock_after_copy = std::move(lock);
        // Return a copy of param and then unlock the now "sunk" lock
        return param;
    }

    inline auto lock_guard() const
    {
        // Unique_lock must be used in order to "sink" the lock into copy_or_ref
        return std::unique_lock<TS_Policy_Safe>(*const_cast<TS_Policy_Safe*>(this));
    }

    inline void lock() const
    {
        mutex.lock();
    }

    inline void unlock() noexcept
    {
        mutex.unlock();
    }

    protected:

    TS_Policy_Safe() noexcept = default;
    ~TS_Policy_Safe() noexcept = default;

    TS_Policy_Safe(TS_Policy_Safe const&) noexcept = default;
    TS_Policy_Safe& operator= (TS_Policy_Safe const&) noexcept = default;

    TS_Policy_Safe(TS_Policy_Safe&&) noexcept = default;
    TS_Policy_Safe& operator= (TS_Policy_Safe&&) noexcept = default;

    using Weak_Ptr = std::weak_ptr<TS_Policy_Safe>;

    inline Weak_Ptr weak_ptr() const
    {
        return tracker;
    }

    inline Shared_Ptr observed(Weak_Ptr const& observer) const
    {
        return std::move(observer.lock());
    }

    inline Shared_Ptr visiting(Weak_Ptr const& observer) const
    {
        // Lock the observer if the observer isn't tracker
        return observer.owner_before(tracker)
            || tracker.owner_before(observer) ? std::move(observer.lock()) : nullptr;
    }

    inline auto unmask(Shared_Ptr& observer) const
    {
        return observer.get();
    }

    inline void before_disconnect_all()
    {
        // Immediately create a weak ptr so we can "ping" for expiration
        auto ping = weak_ptr();
        // Reset the tracker and then ping for any lingering refs
        tracker.reset();
        // Wait for all visitors to finish their emissions
        do
        {
            while (!ping.expired())
            {
                std::this_thread::yield();
            }
        }
        while (ping.lock());
    }
};

} // namespace Nano ------------------------------------------------------------
<commit_msg>Make Spin_Mutex final<commit_after>#pragma once

#include <atomic>
#include <memory>
#include <mutex>
#include <thread>

namespace Nano
{

class Spin_Mutex final
{
    std::atomic_bool locked = { false };

    public:

    inline void lock() noexcept
    {
        do
        {
            while (locked.load(std::memory_order_relaxed))
            {
                std::this_thread::yield();
            }
        }
        while (locked.exchange(true, std::memory_order_acquire));
    }

    inline void unlock() noexcept
    {
        locked.store(false, std::memory_order_release);
    }

    Spin_Mutex() noexcept = default;
    ~Spin_Mutex() noexcept = default;

    // Because all we own is a trivially-copyable atomic_bool, we can manually move/copy
    Spin_Mutex(Spin_Mutex const& other) noexcept : locked{other.locked.load()} {}
    Spin_Mutex& operator= (Spin_Mutex const& other) noexcept
    {
        locked = other.locked.load();
        return *this;
    }

    Spin_Mutex(Spin_Mutex&& other) noexcept : locked{other.locked.load()} {}
    Spin_Mutex& operator= (Spin_Mutex&& other) noexcept
    {
        locked = other.locked.load();
        return *this;
    }
};

//------------------------------------------------------------------------------

// Single Thread Policy
// Use this policy when you DO want performance but NO thread-safety!

class ST_Policy
{
    public:

    template <typename T, typename L>
    inline T const& copy_or_ref(T const& param, L&&) const
    {
        // Return a ref of param
        return param;
    }

    constexpr auto lock_guard() const
    {
        return false;
    }

    protected:

    ST_Policy() noexcept = default;
    ~ST_Policy() noexcept = default;

    ST_Policy(const ST_Policy&) noexcept = default;
    ST_Policy& operator=(const ST_Policy&) noexcept = default;

    ST_Policy(ST_Policy&&) noexcept = default;
    ST_Policy& operator=(ST_Policy&&) noexcept = default;

    using Weak_Ptr = ST_Policy*;

    constexpr auto weak_ptr()
    {
        return this;
    }

    constexpr auto observed(Weak_Ptr) const
    {
        return true;
    }

    constexpr auto visiting(Weak_Ptr observer) const
    {
        return (observer == this ? nullptr : observer);
    }

    constexpr auto unmask(Weak_Ptr observer) const
    {
        return observer;
    }

    constexpr void before_disconnect_all() const
    {

    }
};

//------------------------------------------------------------------------------

// Thread Safe Policy
// Use this policy when you DO want thread-safety but NO reentrancy!

template <typename Mutex = Spin_Mutex>
class TS_Policy
{
    mutable Mutex mutex;

    public:

    template <typename T, typename L>
    inline T const& copy_or_ref(T const& param, L&&) const
    {
        // Return a ref of param
        return param;
    }

    inline auto lock_guard() const
    {
        // All policies must implement the BasicLockable requirement
        return std::lock_guard<TS_Policy>(*const_cast<TS_Policy*>(this));
    }

    inline void lock() const
    {
        mutex.lock();
    }

    inline void unlock() noexcept
    {
        mutex.unlock();
    }

    protected:

    TS_Policy() noexcept = default;
    ~TS_Policy() noexcept = default;

    TS_Policy(TS_Policy const&) noexcept = default;
    TS_Policy& operator= (TS_Policy const&) noexcept = default;

    TS_Policy(TS_Policy&&) noexcept = default;
    TS_Policy& operator= (TS_Policy&&) noexcept = default;

    using Weak_Ptr = TS_Policy*;

    constexpr auto weak_ptr()
    {
        return this;
    }

    constexpr auto observed(Weak_Ptr) const
    {
        return true;
    }

    constexpr auto visiting(Weak_Ptr observer) const
    {
        return (observer == this ? nullptr : observer);
    }

    constexpr auto unmask(Weak_Ptr observer) const
    {
        return observer;
    }

    constexpr void before_disconnect_all() const
    {

    }
};

//------------------------------------------------------------------------------

// Single Thread Policy "Safe"
// Use this policy when you DO want reentrancy but NO thread-safety!

class ST_Policy_Safe
{
    public:

    template <typename T, typename L>
    inline T copy_or_ref(T const& param, L&&) const
    {
        // Return a copy of param
        return param;
    }

    constexpr auto lock_guard() const
    {
        return false;
    }

    protected:

    ST_Policy_Safe() noexcept = default;
    ~ST_Policy_Safe() noexcept = default;

    ST_Policy_Safe(ST_Policy_Safe const&) noexcept = default;
    ST_Policy_Safe& operator= (ST_Policy_Safe const&) noexcept = default;

    ST_Policy_Safe(ST_Policy_Safe&&) noexcept = default;
    ST_Policy_Safe& operator= (ST_Policy_Safe&&) noexcept = default;

    using Weak_Ptr = ST_Policy_Safe*;

    constexpr auto weak_ptr()
    {
        return this;
    }

    constexpr auto observed(Weak_Ptr) const
    {
        return true;
    }

    constexpr auto visiting(Weak_Ptr observer) const
    {
        return (observer == this ? nullptr : observer);
    }

    constexpr auto unmask(Weak_Ptr observer) const
    {
        return observer;
    }

    constexpr void before_disconnect_all() const
    {

    }
};

//------------------------------------------------------------------------------

// Thread Safe Policy "Safe"
// Use this policy when you DO want thread-safety AND reentrancy!

template <typename Mutex = Spin_Mutex>
class TS_Policy_Safe
{
    using Shared_Ptr = std::shared_ptr<TS_Policy_Safe>;

    Shared_Ptr tracker { this, [](...){} };
    mutable Mutex mutex;

    public:

    template <typename T, typename L>
    inline T copy_or_ref(T const& param, L&& lock) const
    {
        std::unique_lock<TS_Policy_Safe> unlock_after_copy = std::move(lock);
        // Return a copy of param and then unlock the now "sunk" lock
        return param;
    }

    inline auto lock_guard() const
    {
        // Unique_lock must be used in order to "sink" the lock into copy_or_ref
        return std::unique_lock<TS_Policy_Safe>(*const_cast<TS_Policy_Safe*>(this));
    }

    inline void lock() const
    {
        mutex.lock();
    }

    inline void unlock() noexcept
    {
        mutex.unlock();
    }

    protected:

    TS_Policy_Safe() noexcept = default;
    ~TS_Policy_Safe() noexcept = default;

    TS_Policy_Safe(TS_Policy_Safe const&) noexcept = default;
    TS_Policy_Safe& operator= (TS_Policy_Safe const&) noexcept = default;

    TS_Policy_Safe(TS_Policy_Safe&&) noexcept = default;
    TS_Policy_Safe& operator= (TS_Policy_Safe&&) noexcept = default;

    using Weak_Ptr = std::weak_ptr<TS_Policy_Safe>;

    inline Weak_Ptr weak_ptr() const
    {
        return tracker;
    }

    inline Shared_Ptr observed(Weak_Ptr const& observer) const
    {
        return std::move(observer.lock());
    }

    inline Shared_Ptr visiting(Weak_Ptr const& observer) const
    {
        // Lock the observer if the observer isn't tracker
        return observer.owner_before(tracker)
            || tracker.owner_before(observer) ? std::move(observer.lock()) : nullptr;
    }

    inline auto unmask(Shared_Ptr& observer) const
    {
        return observer.get();
    }

    inline void before_disconnect_all()
    {
        // Immediately create a weak ptr so we can "ping" for expiration
        auto ping = weak_ptr();
        // Reset the tracker and then ping for any lingering refs
        tracker.reset();
        // Wait for all visitors to finish their emissions
        do
        {
            while (!ping.expired())
            {
                std::this_thread::yield();
            }
        }
        while (ping.lock());
    }
};

} // namespace Nano ------------------------------------------------------------
<|endoftext|>


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

  This file is part of the elastix software.

  Copyright (c) University Medical Center Utrecht. All rights reserved.
  See src/CopyrightElastix.txt or http://elastix.isi.uu.nl/legal.php for
  details.

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

======================================================================*/
#ifndef __itkMissingStructurePenalty_hxx
#define __itkMissingStructurePenalty_hxx

#include "itkMissingStructurePenalty.h"

namespace itk
{

/**
 * ******************* Constructor *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::MissingVolumeMeshPenalty()
{
  this->m_MappedMeshContainer = MappedMeshContainerType::New();
} // end Constructor

/**
 * ******************* Destructor *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet  >
::~MissingVolumeMeshPenalty()
{} // end Destructor

/**
 * *********************** Initialize *****************************
 */

template< class TFixedPointSet, class TMovingPointSet  >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::Initialize( void ) throw ( ExceptionObject )
{
  /** Call the initialize of the superclass. */
  //this->Superclass::Initialize();

  if( !this->m_Transform )
  {
    itkExceptionMacro( << "Transform is not present" );
  }

  if( !this->m_FixedMeshContainer )
  {
    itkExceptionMacro( << "FixedMeshContainer is not present" );
  }

  const FixedMeshContainerElementIdentifier numberOfMeshes = this->m_FixedMeshContainer->Size();
  this->m_MappedMeshContainer->Reserve( numberOfMeshes );

  for( FixedMeshContainerElementIdentifier meshId = 0; meshId < numberOfMeshes; ++meshId )
  {
    FixedMeshConstPointer           fixedMesh      = this->m_FixedMeshContainer->ElementAt( meshId );
    MeshPointsContainerConstPointer fixedPoints    = fixedMesh->GetPoints();
    const unsigned int              numberOfPoints = fixedPoints->Size();

    typename MeshPointsContainerType::Pointer mappedPoints =  MeshPointsContainerType::New();
    mappedPoints->Reserve( numberOfPoints );

    typename FixedMeshType::Pointer mappedMesh = FixedMeshType::New();
    mappedMesh->SetPoints( mappedPoints );

    // mappedMesh was constructed with a Cellscontainer and CellDatacontainer of size 0.
    // We use a null pointer to set them to undefined, which is also the default behavior of the MeshReader.
    // "Write result mesh" checks the null pointer and writes a mesh with the remaining data filled in from the fixed mesh.
    mappedMesh->SetPointData( NULL );
    mappedMesh->SetCells( NULL );
    mappedMesh->SetCellData( NULL );

    this->m_MappedMeshContainer->SetElement( meshId, mappedMesh );

  }
} // end Initialize()

/**
 * ******************* GetValue *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
typename MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >::MeasureType
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::GetValue( const TransformParametersType & parameters ) const
{
  /** Sanity checks. */
  FixedMeshContainerConstPointer fixedMeshContainer = this->GetFixedMeshContainer();
  if( !fixedMeshContainer )
  {
    itkExceptionMacro( << "FixedMeshContainer mesh has not been assigned" );
  }

  /** Initialize some variables */
  MeasureType value = NumericTraits< MeasureType >::Zero;

  //OutputPointType fixedPoint;
  /** Get the current corresponding points. */

  /** Make sure the transform parameters are up to date. */
  this->SetTransformParameters( parameters );

  DerivativeType dummyDerivative;
  this->GetValueAndDerivative( parameters, value, dummyDerivative );

  return value;

} // end GetValue()

/**
 * ******************* GetDerivative *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::GetDerivative( const TransformParametersType & parameters,
  DerivativeType & derivative ) const
{
  /** When the derivative is calculated, all information for calculating
  * the metric value is available. It does not cost anything to calculate
  * the metric value now. Therefore, we have chosen to only implement the
  * GetValueAndDerivative(), supplying it with a dummy value variable.
  */
  MeasureType dummyvalue = NumericTraits< MeasureType >::Zero;
  this->GetValueAndDerivative( parameters, dummyvalue, derivative );

} // end GetDerivative()

/**
 * ******************* GetValueAndDerivative *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::GetValueAndDerivative( const TransformParametersType & parameters,
  MeasureType & value, DerivativeType & derivative ) const
{
  /** Sanity checks. */
  FixedMeshContainerConstPointer fixedMeshContainer = this->GetFixedMeshContainer();
  if( !fixedMeshContainer )
  {
    itkExceptionMacro( << "FixedMeshContainer mesh has not been assigned" );
  }

  /** Initialize some variables */
  value = NumericTraits< MeasureType >::Zero;

  /** Make sure the transform parameters are up to date. */
  this->SetTransformParameters( parameters );

  derivative = DerivativeType( this->GetNumberOfParameters() );
  derivative.Fill( NumericTraits< DerivativeValueType >::Zero );

  NonZeroJacobianIndicesType nzji( this->m_Transform->GetNumberOfNonZeroJacobianIndices() );
  TransformJacobianType      jacobian;

  const FixedMeshContainerElementIdentifier numberOfMeshes = this->m_FixedMeshContainer->Size();

  typedef typename FixedMeshType::PointType FixedMeshPointType;

  FixedMeshPointType zeroPoint = typename FixedMeshPointType::Point();
  zeroPoint.Fill( 0.0 );

  typename MeshPointsContainerType::Pointer pointCentroids = FixedMeshType::PointsContainer::New();
  pointCentroids->resize( numberOfMeshes, typename FixedMeshPointType::Point( zeroPoint ) );

  for( FixedMeshContainerElementIdentifier meshId = 0; meshId < numberOfMeshes; ++meshId ) // loop over all meshes in container
  {
    const FixedMeshConstPointer           fixedMesh      = fixedMeshContainer->ElementAt( meshId );
    const MeshPointsContainerConstPointer fixedPoints    = fixedMesh->GetPoints();
    const unsigned int                    numberOfPoints = fixedPoints->Size();

    const FixedMeshPointer           mappedMesh   = this->m_MappedMeshContainer->ElementAt( meshId );
    const MeshPointsContainerPointer mappedPoints = mappedMesh->GetPoints();

    typename FixedMeshType::PointType &              pointCentroid = pointCentroids->ElementAt( meshId );
    typedef typename FixedMeshType::PointsContainer FixedMeshPointsContainerType;
    typename FixedMeshType::PointsContainer::Pointer derivPoints   = FixedMeshPointsContainerType::New();

    derivPoints->resize( numberOfPoints, typename FixedMeshPointType::Point( zeroPoint ) );

    MeshPointsContainerConstIteratorType fixedPointIt  = fixedPoints->Begin();
    MeshPointsContainerIteratorType      mappedPointIt = mappedPoints->Begin();
    MeshPointsContainerConstIteratorType fixedPointEnd = fixedPoints->End();

    for( ; fixedPointIt != fixedPointEnd; ++fixedPointIt, ++mappedPointIt )
    {
      const OutputPointType mappedPoint = this->m_Transform->TransformPoint( fixedPointIt->Value() );
      mappedPointIt.Value()         = mappedPoint;
      pointCentroid.GetVnlVector() += mappedPoint.GetVnlVector();
    }
    pointCentroid.GetVnlVector() /= numberOfPoints;

    typename FixedMeshType::CellsContainerConstIterator cellBegin = fixedMesh->GetCells()->Begin();
    typename FixedMeshType::CellsContainerConstIterator cellEnd   = fixedMesh->GetCells()->End();

    typename CellInterfaceType::PointIdIterator beginpointer;
    float                              sumSignedVolume = 0.0;
    float                              sumAbsVolume    = 0.0;

    const float eps = 0.00001;

    for( ; cellBegin != cellEnd; ++cellBegin )
    {
      beginpointer = cellBegin->Value()->PointIdsBegin();
      float signedVolume;  // = vnl_determinant(fullMatrix.GetVnlMatrix());

      //const VectorType::const_pointer p1,p2,p3,p4;
      switch( FixedPointSetDimension )
      {
        case 2:
        {
          const FixedMeshPointIdentifier p1Id = *beginpointer;
          ++beginpointer;
          const VectorType p1   = mappedPoints->GetElement( p1Id ) - pointCentroid;
          const FixedMeshPointIdentifier p2Id = *beginpointer;
          ++beginpointer;
          const VectorType p2 = mappedPoints->GetElement( p2Id ) - pointCentroid;

          signedVolume = vnl_determinant( p1.GetDataPointer(), p2.GetDataPointer() );

          const int sign = ( signedVolume > eps ) - ( signedVolume < -eps );
          if( sign != 0 )
          {
            derivPoints->at( p1Id )[ 0 ] += sign * p2[ 1 ];
            derivPoints->at( p1Id )[ 1 ] -= sign * p2[ 0 ];
            derivPoints->at( p2Id )[ 0 ] -= sign * p1[ 1 ];
            derivPoints->at( p2Id )[ 1 ] += sign * p1[ 0 ];
          }

        }
        break;
        case 3:
        {
          const FixedMeshPointIdentifier p1Id = *beginpointer;
          ++beginpointer;
          const VectorType p1   = mappedPoints->GetElement( p1Id ) - pointCentroid;
          const FixedMeshPointIdentifier p2Id = *beginpointer;
          ++beginpointer;
          const VectorType p2   = mappedPoints->GetElement( p2Id ) - pointCentroid;
          const FixedMeshPointIdentifier p3Id = *beginpointer;
          ++beginpointer;
          const VectorType p3 = mappedPoints->GetElement( p3Id ) - pointCentroid;

          signedVolume = vnl_determinant( p1.GetDataPointer(), p2.GetDataPointer(), p3.GetDataPointer() );

          const int sign = ( ( signedVolume > eps ) - ( signedVolume < -eps ) );

          if( sign != 0 )
          {
            derivPoints->at( p1Id )[ 0 ] += sign * ( p2[ 1 ] * p3[ 2 ] - p2[ 2 ] * p3[ 1 ] );
            derivPoints->at( p1Id )[ 1 ] += sign * ( p2[ 2 ] * p3[ 0 ] - p2[ 0 ] * p3[ 2 ] );
            derivPoints->at( p1Id )[ 2 ] += sign * ( p2[ 0 ] * p3[ 1 ] - p2[ 1 ] * p3[ 0 ] );

            derivPoints->at( p2Id )[ 0 ] += sign * ( p1[ 2 ] * p3[ 1 ] - p1[ 1 ] * p3[ 2 ] );
            derivPoints->at( p2Id )[ 1 ] += sign * ( p1[ 0 ] * p3[ 2 ] - p1[ 2 ] * p3[ 0 ] );
            derivPoints->at( p2Id )[ 2 ] += sign * ( p1[ 1 ] * p3[ 0 ] - p1[ 0 ] * p3[ 1 ] );

            derivPoints->at( p3Id )[ 0 ] += sign * ( p1[ 1 ] * p2[ 2 ] - p1[ 2 ] * p2[ 1 ] );
            derivPoints->at( p3Id )[ 1 ] += sign * ( p1[ 2 ] * p2[ 0 ] - p1[ 0 ] * p2[ 2 ] );
            derivPoints->at( p3Id )[ 2 ] += sign * ( p1[ 0 ] * p2[ 1 ] - p1[ 1 ] * p2[ 0 ] );

          }
        }

        break;
        case 4:
        {
          const VectorConstPointer p1 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          const VectorConstPointer p2 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          const VectorConstPointer p3 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          const VectorConstPointer p4 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          signedVolume = vnl_determinant( p1, p2, p3, p4 );
        }
        break;
        default:
          std::cout << "no dimensions higher than 4"  << std::endl;
      }

      sumSignedVolume +=  signedVolume;
      sumAbsVolume    += abs( signedVolume );
    }

    /** Create iterators. */
    fixedPointIt = fixedPoints->Begin();
    unsigned int pointIndex;
    /** Loop over points. */
    for( pointIndex = 0; fixedPointIt != fixedPointEnd; ++fixedPointIt, ++pointIndex )
    {
      /** Get the TransformJacobian dT/dmu. */
      this->m_Transform->GetJacobian( fixedPointIt.Value(), jacobian, nzji );
      if( nzji.size() == this->GetNumberOfParameters() )
      {
        /** Loop over all Jacobians. */
        derivative += derivPoints->at( pointIndex ).GetVnlVector() * jacobian; //* sumAbsVolumeEps;
      }
      else
      {
        /** Only pick the nonzero Jacobians. */
        for( unsigned int i = 0; i < nzji.size(); ++i )
        {
          const unsigned int index  = nzji[ i ];
          VnlVectorType      column = jacobian.get_column( i );
          derivative[ index ] += dot_product( derivPoints->at( pointIndex ).GetVnlVector(), column ); // *sumAbsVolumeEps;
        }
      }

    }   // end loop over all corresponding points

    /** Check if enough samples were valid. */

    /** Copy the measure to value. */
    value += sumAbsVolume;

  } // end loop over all meshes in container
} // end GetValueAndDerivative()

/**
 * ******************* SubVector *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::SubVector( const VectorType & fullVector,  SubVectorType & subVector, const unsigned int leaveOutIndex )  const
{
  //SubVectorType subVector = SubVectorType::Vector();

  typename VectorType::ConstIterator    fullVectorIt  = fullVector.Begin();
  typename VectorType::ConstIterator    fullVectorEnd = fullVector.End();
  typename SubVectorType::Iterator      subVectorIt   = subVector.Begin();
  typename SubVectorType::ConstIterator subVectorEnd  = subVector.End();
  unsigned int                 fullIndex     = 0;
  for( ; subVectorIt != subVectorEnd; ++fullVectorIt, ++subVectorIt, ++fullIndex )
  {
    if( fullIndex == leaveOutIndex )
    {
      ++fullVectorIt;
    }
    *subVectorIt = *fullVectorIt;
  }

} // end SubVector()

} // end itk namespace

#endif // end #ifndef __itkMissingStructurePenalty_hxx

<commit_msg>COMP: case value not in enumerated type<commit_after>/*======================================================================

  This file is part of the elastix software.

  Copyright (c) University Medical Center Utrecht. All rights reserved.
  See src/CopyrightElastix.txt or http://elastix.isi.uu.nl/legal.php for
  details.

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

======================================================================*/
#ifndef __itkMissingStructurePenalty_hxx
#define __itkMissingStructurePenalty_hxx

#include "itkMissingStructurePenalty.h"

namespace itk
{

/**
 * ******************* Constructor *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::MissingVolumeMeshPenalty()
{
  this->m_MappedMeshContainer = MappedMeshContainerType::New();
} // end Constructor

/**
 * ******************* Destructor *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet  >
::~MissingVolumeMeshPenalty()
{} // end Destructor

/**
 * *********************** Initialize *****************************
 */

template< class TFixedPointSet, class TMovingPointSet  >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::Initialize( void ) throw ( ExceptionObject )
{
  /** Call the initialize of the superclass. */
  //this->Superclass::Initialize();

  if( !this->m_Transform )
  {
    itkExceptionMacro( << "Transform is not present" );
  }

  if( !this->m_FixedMeshContainer )
  {
    itkExceptionMacro( << "FixedMeshContainer is not present" );
  }

  const FixedMeshContainerElementIdentifier numberOfMeshes = this->m_FixedMeshContainer->Size();
  this->m_MappedMeshContainer->Reserve( numberOfMeshes );

  for( FixedMeshContainerElementIdentifier meshId = 0; meshId < numberOfMeshes; ++meshId )
  {
    FixedMeshConstPointer           fixedMesh      = this->m_FixedMeshContainer->ElementAt( meshId );
    MeshPointsContainerConstPointer fixedPoints    = fixedMesh->GetPoints();
    const unsigned int              numberOfPoints = fixedPoints->Size();

    typename MeshPointsContainerType::Pointer mappedPoints =  MeshPointsContainerType::New();
    mappedPoints->Reserve( numberOfPoints );

    typename FixedMeshType::Pointer mappedMesh = FixedMeshType::New();
    mappedMesh->SetPoints( mappedPoints );

    // mappedMesh was constructed with a Cellscontainer and CellDatacontainer of size 0.
    // We use a null pointer to set them to undefined, which is also the default behavior of the MeshReader.
    // "Write result mesh" checks the null pointer and writes a mesh with the remaining data filled in from the fixed mesh.
    mappedMesh->SetPointData( NULL );
    mappedMesh->SetCells( NULL );
    mappedMesh->SetCellData( NULL );

    this->m_MappedMeshContainer->SetElement( meshId, mappedMesh );

  }
} // end Initialize()

/**
 * ******************* GetValue *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
typename MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >::MeasureType
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::GetValue( const TransformParametersType & parameters ) const
{
  /** Sanity checks. */
  FixedMeshContainerConstPointer fixedMeshContainer = this->GetFixedMeshContainer();
  if( !fixedMeshContainer )
  {
    itkExceptionMacro( << "FixedMeshContainer mesh has not been assigned" );
  }

  /** Initialize some variables */
  MeasureType value = NumericTraits< MeasureType >::Zero;

  //OutputPointType fixedPoint;
  /** Get the current corresponding points. */

  /** Make sure the transform parameters are up to date. */
  this->SetTransformParameters( parameters );

  DerivativeType dummyDerivative;
  this->GetValueAndDerivative( parameters, value, dummyDerivative );

  return value;

} // end GetValue()

/**
 * ******************* GetDerivative *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::GetDerivative( const TransformParametersType & parameters,
  DerivativeType & derivative ) const
{
  /** When the derivative is calculated, all information for calculating
  * the metric value is available. It does not cost anything to calculate
  * the metric value now. Therefore, we have chosen to only implement the
  * GetValueAndDerivative(), supplying it with a dummy value variable.
  */
  MeasureType dummyvalue = NumericTraits< MeasureType >::Zero;
  this->GetValueAndDerivative( parameters, dummyvalue, derivative );

} // end GetDerivative()

/**
 * ******************* GetValueAndDerivative *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::GetValueAndDerivative( const TransformParametersType & parameters,
  MeasureType & value, DerivativeType & derivative ) const
{
  /** Sanity checks. */
  FixedMeshContainerConstPointer fixedMeshContainer = this->GetFixedMeshContainer();
  if( !fixedMeshContainer )
  {
    itkExceptionMacro( << "FixedMeshContainer mesh has not been assigned" );
  }

  /** Initialize some variables */
  value = NumericTraits< MeasureType >::Zero;

  /** Make sure the transform parameters are up to date. */
  this->SetTransformParameters( parameters );

  derivative = DerivativeType( this->GetNumberOfParameters() );
  derivative.Fill( NumericTraits< DerivativeValueType >::Zero );

  NonZeroJacobianIndicesType nzji( this->m_Transform->GetNumberOfNonZeroJacobianIndices() );
  TransformJacobianType      jacobian;

  const FixedMeshContainerElementIdentifier numberOfMeshes = this->m_FixedMeshContainer->Size();

  typedef typename FixedMeshType::PointType FixedMeshPointType;

  FixedMeshPointType zeroPoint = typename FixedMeshPointType::Point();
  zeroPoint.Fill( 0.0 );

  typename MeshPointsContainerType::Pointer pointCentroids = FixedMeshType::PointsContainer::New();
  pointCentroids->resize( numberOfMeshes, typename FixedMeshPointType::Point( zeroPoint ) );

  for( FixedMeshContainerElementIdentifier meshId = 0; meshId < numberOfMeshes; ++meshId ) // loop over all meshes in container
  {
    const FixedMeshConstPointer           fixedMesh      = fixedMeshContainer->ElementAt( meshId );
    const MeshPointsContainerConstPointer fixedPoints    = fixedMesh->GetPoints();
    const unsigned int                    numberOfPoints = fixedPoints->Size();

    const FixedMeshPointer           mappedMesh   = this->m_MappedMeshContainer->ElementAt( meshId );
    const MeshPointsContainerPointer mappedPoints = mappedMesh->GetPoints();

    typename FixedMeshType::PointType &              pointCentroid = pointCentroids->ElementAt( meshId );
    typedef typename FixedMeshType::PointsContainer FixedMeshPointsContainerType;
    typename FixedMeshType::PointsContainer::Pointer derivPoints   = FixedMeshPointsContainerType::New();

    derivPoints->resize( numberOfPoints, typename FixedMeshPointType::Point( zeroPoint ) );

    MeshPointsContainerConstIteratorType fixedPointIt  = fixedPoints->Begin();
    MeshPointsContainerIteratorType      mappedPointIt = mappedPoints->Begin();
    MeshPointsContainerConstIteratorType fixedPointEnd = fixedPoints->End();

    for( ; fixedPointIt != fixedPointEnd; ++fixedPointIt, ++mappedPointIt )
    {
      const OutputPointType mappedPoint = this->m_Transform->TransformPoint( fixedPointIt->Value() );
      mappedPointIt.Value()         = mappedPoint;
      pointCentroid.GetVnlVector() += mappedPoint.GetVnlVector();
    }
    pointCentroid.GetVnlVector() /= numberOfPoints;

    typename FixedMeshType::CellsContainerConstIterator cellBegin = fixedMesh->GetCells()->Begin();
    typename FixedMeshType::CellsContainerConstIterator cellEnd   = fixedMesh->GetCells()->End();

    typename CellInterfaceType::PointIdIterator beginpointer;
    float                              sumSignedVolume = 0.0;
    float                              sumAbsVolume    = 0.0;

    const float eps = 0.00001;

    for( ; cellBegin != cellEnd; ++cellBegin )
    {
      beginpointer = cellBegin->Value()->PointIdsBegin();
      float signedVolume;  // = vnl_determinant(fullMatrix.GetVnlMatrix());

      //const VectorType::const_pointer p1,p2,p3,p4;
      switch( static_cast<unsigned int>( FixedPointSetDimension ) )
      {
        case 2:
        {
          const FixedMeshPointIdentifier p1Id = *beginpointer;
          ++beginpointer;
          const VectorType p1   = mappedPoints->GetElement( p1Id ) - pointCentroid;
          const FixedMeshPointIdentifier p2Id = *beginpointer;
          ++beginpointer;
          const VectorType p2 = mappedPoints->GetElement( p2Id ) - pointCentroid;

          signedVolume = vnl_determinant( p1.GetDataPointer(), p2.GetDataPointer() );

          const int sign = ( signedVolume > eps ) - ( signedVolume < -eps );
          if( sign != 0 )
          {
            derivPoints->at( p1Id )[ 0 ] += sign * p2[ 1 ];
            derivPoints->at( p1Id )[ 1 ] -= sign * p2[ 0 ];
            derivPoints->at( p2Id )[ 0 ] -= sign * p1[ 1 ];
            derivPoints->at( p2Id )[ 1 ] += sign * p1[ 0 ];
          }

        }
        break;
        case 3:
        {
          const FixedMeshPointIdentifier p1Id = *beginpointer;
          ++beginpointer;
          const VectorType p1   = mappedPoints->GetElement( p1Id ) - pointCentroid;
          const FixedMeshPointIdentifier p2Id = *beginpointer;
          ++beginpointer;
          const VectorType p2   = mappedPoints->GetElement( p2Id ) - pointCentroid;
          const FixedMeshPointIdentifier p3Id = *beginpointer;
          ++beginpointer;
          const VectorType p3 = mappedPoints->GetElement( p3Id ) - pointCentroid;

          signedVolume = vnl_determinant( p1.GetDataPointer(), p2.GetDataPointer(), p3.GetDataPointer() );

          const int sign = ( ( signedVolume > eps ) - ( signedVolume < -eps ) );

          if( sign != 0 )
          {
            derivPoints->at( p1Id )[ 0 ] += sign * ( p2[ 1 ] * p3[ 2 ] - p2[ 2 ] * p3[ 1 ] );
            derivPoints->at( p1Id )[ 1 ] += sign * ( p2[ 2 ] * p3[ 0 ] - p2[ 0 ] * p3[ 2 ] );
            derivPoints->at( p1Id )[ 2 ] += sign * ( p2[ 0 ] * p3[ 1 ] - p2[ 1 ] * p3[ 0 ] );

            derivPoints->at( p2Id )[ 0 ] += sign * ( p1[ 2 ] * p3[ 1 ] - p1[ 1 ] * p3[ 2 ] );
            derivPoints->at( p2Id )[ 1 ] += sign * ( p1[ 0 ] * p3[ 2 ] - p1[ 2 ] * p3[ 0 ] );
            derivPoints->at( p2Id )[ 2 ] += sign * ( p1[ 1 ] * p3[ 0 ] - p1[ 0 ] * p3[ 1 ] );

            derivPoints->at( p3Id )[ 0 ] += sign * ( p1[ 1 ] * p2[ 2 ] - p1[ 2 ] * p2[ 1 ] );
            derivPoints->at( p3Id )[ 1 ] += sign * ( p1[ 2 ] * p2[ 0 ] - p1[ 0 ] * p2[ 2 ] );
            derivPoints->at( p3Id )[ 2 ] += sign * ( p1[ 0 ] * p2[ 1 ] - p1[ 1 ] * p2[ 0 ] );

          }
        }

        break;
        case 4:
        {
          const VectorConstPointer p1 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          const VectorConstPointer p2 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          const VectorConstPointer p3 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          const VectorConstPointer p4 = mappedPoints->GetElement( *beginpointer++ ).GetDataPointer();
          signedVolume = vnl_determinant( p1, p2, p3, p4 );
        }
        break;
        default:
          std::cout << "no dimensions higher than 4"  << std::endl;
      }

      sumSignedVolume +=  signedVolume;
      sumAbsVolume    += abs( signedVolume );
    }

    /** Create iterators. */
    fixedPointIt = fixedPoints->Begin();
    unsigned int pointIndex;
    /** Loop over points. */
    for( pointIndex = 0; fixedPointIt != fixedPointEnd; ++fixedPointIt, ++pointIndex )
    {
      /** Get the TransformJacobian dT/dmu. */
      this->m_Transform->GetJacobian( fixedPointIt.Value(), jacobian, nzji );
      if( nzji.size() == this->GetNumberOfParameters() )
      {
        /** Loop over all Jacobians. */
        derivative += derivPoints->at( pointIndex ).GetVnlVector() * jacobian; //* sumAbsVolumeEps;
      }
      else
      {
        /** Only pick the nonzero Jacobians. */
        for( unsigned int i = 0; i < nzji.size(); ++i )
        {
          const unsigned int index  = nzji[ i ];
          VnlVectorType      column = jacobian.get_column( i );
          derivative[ index ] += dot_product( derivPoints->at( pointIndex ).GetVnlVector(), column ); // *sumAbsVolumeEps;
        }
      }

    }   // end loop over all corresponding points

    /** Check if enough samples were valid. */

    /** Copy the measure to value. */
    value += sumAbsVolume;

  } // end loop over all meshes in container
} // end GetValueAndDerivative()

/**
 * ******************* SubVector *******************
 */

template< class TFixedPointSet, class TMovingPointSet >
void
MissingVolumeMeshPenalty< TFixedPointSet, TMovingPointSet >
::SubVector( const VectorType & fullVector,  SubVectorType & subVector, const unsigned int leaveOutIndex )  const
{
  //SubVectorType subVector = SubVectorType::Vector();

  typename VectorType::ConstIterator    fullVectorIt  = fullVector.Begin();
  typename VectorType::ConstIterator    fullVectorEnd = fullVector.End();
  typename SubVectorType::Iterator      subVectorIt   = subVector.Begin();
  typename SubVectorType::ConstIterator subVectorEnd  = subVector.End();
  unsigned int                 fullIndex     = 0;
  for( ; subVectorIt != subVectorEnd; ++fullVectorIt, ++subVectorIt, ++fullIndex )
  {
    if( fullIndex == leaveOutIndex )
    {
      ++fullVectorIt;
    }
    *subVectorIt = *fullVectorIt;
  }

} // end SubVector()

} // end itk namespace

#endif // end #ifndef __itkMissingStructurePenalty_hxx

<|endoftext|>